/*
   Copyright (C) 2000 T. Scott Dattalo

This file is part of gpsim.

gpsim 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, or (at your option)
any later version.

gpsim 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 gpsim; see the file COPYING.  If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.  */

/*
  Logic.cc

This is an example module library for interfacing with gpsim.

In here you'll find some simple logic devices:

  AND2Gate - A 2-input AND gate
  OR2Gate - A 2-input OR gate

*/

/* IN_MODULE should be defined for modules */
#define IN_MODULE

#include "../config.h"    // get the definition for HAVE_GUI

#ifdef HAVE_GUI

/* XPM */
static char * and2_pixmap[] = {
"32 32 3 1",
" 	c black",
".	c None",
"X	c white",
"                    ............",
"                        ........",
"  XXXXXXXXXXXXXXXXXX    ........",
"  XXXXXXXXXXXXXXXXXXXXXX  ......",
"  XXXXXXXXXXXXXXXXXXXXXX  ......",
"  XXXXXXXXXXXXXXXXXXXXXXXX  ....",
"  XXXXXXXXXXXXXXXXXXXXXXXX   ...",
"  XXXXXXXXXXXXXXXXXXXXXXXXX  ...",
"  XXXXXXXXXXXXXXXXXXXXXXXXXXX  .",
"  XXXXXXXXXXXXXXXXXXXXXXXXXXX  .",
"  XXXXXXXXXXXXXXXXXXXXXXXXXXX  .",
"  XXXXXX XXX XXX X    XXXXXXX  .",
"  XXXXX X XX  XX XX XX XXXXXX  .",
"  XXXX XXX X  XX XX XX XXXXXXX  ",
"  XXXX XXX X X X XX XX XXXXXXX  ",
"  XXXX XXX X X X XX XX XXXXXXX  ",
"  XXXX     X XX  XX XX XXXXXXX  ",
"  XXXX XXX X XX  XX XX XXXXXXX  ",
"  XXXX XXX X XXX XX XX XXXXXXX  ",
"  XXXX XXX X XXX X    XXXXXXX  .",
"  XXXXXXXXXXXXXXXXXXXXXXXXXXX  .",
"  XXXXXXXXXXXXXXXXXXXXXXXXXXX  .",
"  XXXXXXXXXXXXXXXXXXXXXXXXXXX  .",
"  XXXXXXXXXXXXXXXXXXXXXXXXXXX  .",
"  XXXXXXXXXXXXXXXXXXXXXXXXX  ...",
"  XXXXXXXXXXXXXXXXXXXXXXXX   ...",
"  XXXXXXXXXXXXXXXXXXXXXXXX  ....",
"  XXXXXXXXXXXXXXXXXXXXXX  ......",
"  XXXXXXXXXXXXXXXXXXXXXX  ......",
"  XXXXXXXXXXXXXXXXXX    ........",
"                        ........",
"                    ............"};

/* XPM */
static char * or2_pixmap[] = {
"32 32 3 1",
" 	c black",
".	c None",
"X	c white",
"                    ............",
"                        ........",
"  XXXXXXXXXXXXXXXXXX    ........",
"  XXXXXXXXXXXXXXXXXXXXXX  ......",
"  XXXXXXXXXXXXXXXXXXXXXX  ......",
".  XXXXXXXXXXXXXXXXXXXXXXX  ....",
".  XXXXXXXXXXXXXXXXXXXXXXX   ...",
".  XXXXXXXXXXXXXXXXXXXXXXXX  ...",
"..  XXXXXXXXXXXXXXXXXXXXXXXXX  .",
"..  XXXXXXXXXXXXXXXXXXXXXXXXX  .",
"..  XXXXXXXXXXXXXXXXXXXXXXXXX  .",
"..  XXXXXXX   XX    XXXXXXXXX  .",
"...  XXXXX XXX X XXX XXXXXXXX  .",
"...  XXXXX XXX X XXX XXXXXXXXX  ",
"...  XXXXX XXX X XXX XXXXXXXXX  ",
"...  XXXXX XXX X    XXXXXXXXXX  ",
"...  XXXXX XXX X X XXXXXXXXXXX  ",
"...  XXXXX XXX X XX XXXXXXXXXX  ",
"...  XXXXX XXX X XXX XXXXXXXXX  ",
"...  XXXXXX   XX XXX XXXXXXXX  .",
"..  XXXXXXXXXXXXXXXXXXXXXXXXX  .",
"..  XXXXXXXXXXXXXXXXXXXXXXXXX  .",
"..  XXXXXXXXXXXXXXXXXXXXXXXXX  .",
"..  XXXXXXXXXXXXXXXXXXXXXXXXX  .",
".  XXXXXXXXXXXXXXXXXXXXXXXX  ...",
".  XXXXXXXXXXXXXXXXXXXXXXX   ...",
".  XXXXXXXXXXXXXXXXXXXXXXX  ....",
"  XXXXXXXXXXXXXXXXXXXXXX  ......",
"  XXXXXXXXXXXXXXXXXXXXXX  ......",
"  XXXXXXXXXXXXXXXXXX    ........",
"                        ........",
"                    ............"};

static char * xor2_pixmap[] = {
"40 32 3 1",
" 	c None",
".	c black",
"X	c white",
"        ....................            ",
"  ..    ....................            ",
" ....   ........................        ",
"  ...   ..XXXXXXXXXXXXXXXXXX....        ",
"  ...   ..XXXXXXXXXXXXXXXXXXXXXX..      ",
"   ...  ..XXXXXXXXXXXXXXXXXXXXXX..      ",
"   ....  ..XXXXXXXXXXXXXXXXXXXXXXX..    ",
"    ...  ..XXXXXXXXXXXXXXXXXXXXXXX...   ",
"    ...  ..XXXXXXXXXXXXXXXXXXXXXXXX..   ",
"    ...   ..XXXXXXXXXXXXXXXXXXXXXXXXX.. ",
"    ....  ..XXXXXXXXXXXXXXXXXXXXXXXXX.. ",
"     ...  ..XXXXXXXXXXXXXXXXXXXXXXXXX.. ",
"     ...  ..XXXX.XXX.XX...XX....XXXXX.. ",
"      ..   ..XXX.XXX.X.XXX.X.XXX.XXXX.. ",
"      ..   ..XXXX.X.XX.XXX.X.XXX.XXXXX..",
"      ..   ..XXXX.X.XX.XXX.X.XXX.XXXXX..",
"      ...  ..XXXXX.XXX.XXX.X....XXXXXX..",
"      ...  ..XXXX.X.XX.XXX.X.X.XXXXXXX..",
"      ...  ..XXXX.X.XX.XXX.X.XX.XXXXXX..",
"      ...  ..XXX.XXX.X.XXX.X.XXX.XXXXX..",
"      ...  ..XXX.XXX.XX...XX.XXX.XXXX.. ",
"      ... ..XXXXXXXXXXXXXXXXXXXXXXXXX.. ",
"      ..  ..XXXXXXXXXXXXXXXXXXXXXXXXX.. ",
"     ...  ..XXXXXXXXXXXXXXXXXXXXXXXXX.. ",
"     ...  ..XXXXXXXXXXXXXXXXXXXXXXXXX.. ",
"    ...  ..XXXXXXXXXXXXXXXXXXXXXXXX..   ",
"    ...  ..XXXXXXXXXXXXXXXXXXXXXXX...   ",
"    ...  ..XXXXXXXXXXXXXXXXXXXXXXX..    ",
"   .... ..XXXXXXXXXXXXXXXXXXXXXX..      ",
"  ..... ..XXXXXXXXXXXXXXXXXXXXXX..      ",
" ....   ..XXXXXXXXXXXXXXXXXX....        ",
"  ..    ........................        "};

static char * not_pixmap[] = {
"32 32 3 1",
" 	c black",
".	c None",
"X	c white",
" ...............................",
"   .............................",
"     ...........................",
"  X   ..........................",
"  XXX   ........................",
"  XXXX    ......................",
"  XXXXXX    ....................",
"  XXXXXXXX   ...................",
"  XXXXXXXXXX   .................",
"  XXXXXXXXXXX    ...............",
"  XXXXXXXXXXXXX   ..............",
"  XXXXXXXXXXXXXXX   ............",
"  XXXXXXXXXXXXXXXX    .....   ..",
"  XXXXXXXXXXXXXXXXXX    .. XXX .",
"  XXXXXXXXXXXXXXXXXXXX    XXXXX ",
"  XXXXXXXXXXXXXXXXXXXXXX  XXXXX ",
"  XXXXXXXXXXXXXXXXXXXX    XXXXX ",
"  XXXXXXXXXXXXXXXXXXX   .. XXX .",
"  XXXXXXXXXXXXXXXXX   .....   ..",
"  XXXXXXXXXXXXXXX    ...........",
"  XXXXXXXXXXXXXX   .............",
"  XXXXXXXXXXXX   ...............",
"  XXXXXXXXXXX   ................",
"  XXXXXXXXX   ..................",
"  XXXXXXX    ...................",
"  XXXXXX   .....................",
"  XXXX   .......................",
"  XXX   ........................",
"  X   ..........................",
"     ...........................",
"   .............................",
" ..............................."};

#include <gtk/gtk.h>

#endif

#include <errno.h>
#include <stdlib.h>
#include <string>


#include "logic.h"
#include "../src/packages.h"
#include "../src/gpsim_interface.h"
#include "../src/attributes.h"

//--------------------------------------------------------------
// Led_Input
//   This class is a minor extension of a normal IO_input. I may
// remove it later, but for now it does serve a simple purpose.
// Specifically, this derivation will intercept when a stimulus
// is being changed. 

void Logic_Input::setDrivenState( bool new_state)
{

  if(0)
    cout << name()<< " setDrivenState= " 
	 << (new_state ? "high" : "low") << endl;

  if(new_state != getDrivenState()) {

    bDrivingState = new_state;
    bDrivenState  = new_state;

    if(LGParent) {
      LGParent->update_input_pin(m_iobit, new_state);
      LGParent->update_state();
    }
  }
}


/*************************************************************
*
*  LogicGate class
*/

LogicGate::LogicGate(void)
{
#ifdef HAVE_GUI
  pixmap=0;
#endif
}

LogicGate::~LogicGate(void)
{
}

//--------------------------------------------------------------
void LogicGate::update_input_pin(unsigned int pin, bool bValue)
{
  unsigned int mask = 1<<pin;
  input_state &= ~mask;
  input_state |= bValue ? mask : 0;
}

//--------------------------------------------------------------
// create_iopin_map 
//
//  This is where the information for the Module's package is defined.
// Specifically, the I/O pins of the module are created.

void LogicGate::create_iopin_map(void)
{
  int i;

  // Define the physical package.
  //   The Package class, which is a parent of all of the modules,
  //   is responsible for allocating memory for the I/O pins.
  //

  create_pkg(number_of_pins);


  // Define the I/O pins and assign them to the package.
  //   There are two things happening here. First, there is
  //   a new I/O pin that is being created. For the binary 
  //   indicator, both pins are inputs. The second thing is
  //   that the pins are "assigned" to the package. If we
  //   need to reference these newly created I/O pins (like
  //   below) then we can call the member function 'get_pin'.

  // all logic gates have one or more inputs, but only one
  // output. The output is arbitrarily assigned to position
  // 0 on the I/O port while the inputs go to positions 1 and above


#define OUTPUT_BITPOSITION 0
#define INPUT_FIRST_BITPOSITION (OUTPUT_BITPOSITION + 1)

  // Here, we name the port `pin'. So in gpsim, we will reference
  //   the bit positions as U1.pin0, U1.pin1, ..., where U1 is the
  //   name of the logic gate (which is assigned by the user and
  //   obtained with the name() member function call).

  string outname = name() + ".out";

  pOutputPin = new Logic_Output(this, OUTPUT_BITPOSITION, outname.c_str());
  pOutputPin->update_direction(1,true);  // make the bidirectional an output

  // Position pin on middle right side of package
  package->set_pin_position(1,2.5);
  assign_pin(OUTPUT_BITPOSITION + 1, pOutputPin);

  Logic_Input *LIP;

  int j;


  pInputPins = (IOPIN **) new char[sizeof (IOPIN *) * (number_of_pins-1)];

  string inname;
  for(i=j=INPUT_FIRST_BITPOSITION; i<number_of_pins; i++) {
    char pin_number = i-j +'0';
    inname = name() + ".in" + pin_number;
    //p[2] = i-j +'0';
    LIP = new Logic_Input(this, i-INPUT_FIRST_BITPOSITION,inname.c_str());
    pInputPins[i-INPUT_FIRST_BITPOSITION] = LIP;

    if(number_of_pins==2)
      package->set_pin_position(i+1, 0.5); // Left side of package
    else
      package->set_pin_position(i+1, (float)((i-INPUT_FIRST_BITPOSITION)*0.9999)); // Left side of package
    assign_pin(i+1, LIP );       //  Pin numbers begin at 1
  }

  // Form the logic gate bit masks
  input_bit_mask = (1<< (number_of_pins-1)) - 1;

  initializeAttributes();

}

#ifdef HAVE_GUI
static gboolean expose(GtkWidget *widget,
		GdkEventExpose *event,
		LogicGate *lg)
{
	if(lg->pixmap==0)
	{
		puts("LogicGate has no pixmap");
		return 0;
	}

	gdk_draw_pixmap(widget->window,
			widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
			lg->pixmap,
			event->area.x, event->area.y,
			event->area.x, event->area.y,
			event->area.width, event->area.height);
	
	return 0;
}

GtkWidget *LogicGate::create_pixmap(char **pixmap_data)
{
    GtkStyle *style;
    GdkBitmap *mask;
    GtkWidget *da;
    int width,height;

    style = gtk_style_new();
    
    pixmap = gdk_pixmap_colormap_create_from_xpm_d(NULL,
						   gdk_colormap_get_system(),
						   &mask,
						   &style->bg[GTK_STATE_NORMAL],
						   pixmap_data);
#if GTK_MAJOR_VERSION >= 2
    gdk_drawable_get_size(pixmap,&width,&height);
#else
    gdk_window_get_size(pixmap,&width,&height);
#endif
    da = gtk_drawing_area_new();
    gtk_drawing_area_size(GTK_DRAWING_AREA(da),width,height);
    gtk_signal_connect(GTK_OBJECT(da),"expose_event",
    		(GtkSignalFunc) expose,this);
    return da;
}
#endif

//--------------------------------------------------------------
// construct

Module * AND2Gate::construct(const char *_new_name)
{


  AND2Gate *a2gP = new AND2Gate ;

  a2gP->new_name(_new_name);
  a2gP->set_number_of_pins(3);
  a2gP->create_iopin_map();

  return a2gP;

}

AND2Gate::AND2Gate(void)
{
#ifdef HAVE_GUI
  if(get_interface().bUsingGUI())
    set_widget(create_pixmap(and2_pixmap));
#endif

}
AND2Gate::~AND2Gate(void)
{
}


void ANDGate::update_state(void)
{
  pOutputPin->putState((input_state & input_bit_mask) == input_bit_mask);
  if (pOutputPin->snode)
    pOutputPin->snode->update();
}

//--------------------------------------------------------------
// construct


OR2Gate::OR2Gate(void)
{
#ifdef HAVE_GUI

  if(get_interface().bUsingGUI())
    set_widget(create_pixmap(or2_pixmap));
#endif
}
OR2Gate::~OR2Gate(void)
{

}

Module * OR2Gate::construct(const char *_new_name)
{


  OR2Gate *o2gP = new OR2Gate ;

  o2gP->new_name(_new_name);
  o2gP->set_number_of_pins(3);
  o2gP->create_iopin_map();

  return o2gP;

}

void ORGate::update_state(void)
{
  pOutputPin->putState((input_state & input_bit_mask) != 0);

}


//--------------------------------------------------------------
// construct NOT
Module * NOTGate::construct(const char *_new_name)
{

  NOTGate *a2gP = new NOTGate ;

  a2gP->new_name(_new_name);
  a2gP->set_number_of_pins(2);
  a2gP->create_iopin_map();

  return a2gP;

}

NOTGate::NOTGate(void)
{
#ifdef HAVE_GUI

  if(get_interface().bUsingGUI())
    set_widget(create_pixmap(not_pixmap));
#endif
}
NOTGate::~NOTGate(void)
{

}

void NOTGate::update_state(void)
{
  pOutputPin->putState((input_state & input_bit_mask) == 0);

}

//--------------------------------------------------------------
// construct


XOR2Gate::XOR2Gate(void)
{
#ifdef HAVE_GUI

  if(get_interface().bUsingGUI())
    set_widget(create_pixmap(xor2_pixmap));
#endif
}
XOR2Gate::~XOR2Gate(void)
{
}

Module * XOR2Gate::construct(const char *_new_name)
{

  XOR2Gate *o2gP = new XOR2Gate ;

  o2gP->new_name(_new_name);
  o2gP->set_number_of_pins(3);
  o2gP->create_iopin_map();

  return o2gP;

}

void XORGate::update_state(void)
{
  bool bNewOutputState=false;

  unsigned int mask=input_bit_mask;
  while(mask) {
    unsigned int lsb = (~mask + 1) & mask;
    mask ^= lsb;
    bNewOutputState ^= (lsb & input_state) ? true : false;
  }

  pOutputPin->putState(bNewOutputState);
}



syntax highlighted by Code2HTML, v. 0.9.1