/****************************************************************************
    Copyright (C) 1987-2005 by Jeffery P. Hansen

    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., 675 Mass Ave, Cambridge, MA 02139, USA.

    Last edit by hansen on Mon Dec  8 13:45:47 2003
****************************************************************************/
#include <stdlib.h>
#include <string.h>
#include "tkgate.h"

static iconDimensions ram_iconDims[] = {
  {0, 0, 34, 49, 17, 23},
};
static int ram_iconBoldOffset = 50;


#define RAM_A 0
#define RAM_D 1
#define RAM_WE 2
#define RAM_OE 3
#define RAM_CS 4

struct locate ram_A_loc[] = {{-18,-1,-18,-1,D_LEFT}};
struct locate ram_D_loc[] = {{17,-1,17,-1,D_RIGHT}};
struct locate ram_we_loc[] = {{0,-24,0,-24,D_UP}};
struct locate ram_cs_loc[] = {{-7,26,-7,26,D_DOWN}};
struct locate ram_oe_loc[] = {{7,26,7,26,D_DOWN}};

GCElement *RamRom_Make(EditState **es,GModuleDef *env,int GType,
		    int x,int y,int r,const char *Name,int noWires,const char **options,int nOptions);
void RamRom_EditProps(GCElement *g,int isLoadDialog);
void RamRom_SetProp(GCElement*,const char*,const void*);
void RamRom_SimHitFunc(EditState *es,GCElement *g);
void RamRom_VerSave(FILE *f,GCElement *g);

static char *psRam[] = {
  "%",
  "% x y r ram",
  "%",
  "/psram {",
  "  startgate",
  "  -17.5 23.5 moveto",
  "  16.5 23.5 lineto",
  "  16.5 -25.5 lineto",
  "  -17.5 -25.5 lineto",
  "  closepath stroke",
  "  8 rfont",
  "  -15 -2 moveto (A) show",
  "  5 -2 moveto (D) show",
  "  6 rfont",
  "  (_cs) -11 -23 prshow",
  "  (_oe) 4 -23 prshow",
  "  (_we) -4 16 prshow",
  "  grestore",
  "} def",
  0
};

GGateInfo gate_ram_info = {
  0,
  "RAM",
  "ram",0x0,
  "psram",psRam,

  {{"R",	{"gmmem",5},		{"gmram",0,"mem",100},	"gat_make ram"},
   {0}},


  ram_iconDims,

  5,{{"A",IN,8,1,ram_A_loc},
       {"D",TRI,8,1,ram_D_loc},
       {"WE",IN,1,1,ram_we_loc},
       {"OE",IN,1,1,ram_oe_loc},
       {"CS",IN,1,1,ram_cs_loc}},
  {{5,-30,LJ},{5,-30,LJ},{5,-30,LJ},{5,-30,LJ}},
  {0},

  {"OE-D","CS-D","A-D","addr_setup","data_setup","addr_hold","data_hold",0},
  
  RamRom_Make,
  Generic_Init,
  Generic_Delete,
  Generic_GetExtents,
  Generic_HitDistance,
  Generic_Draw,
  Generic_Move,
  Generic_Replicate,
  Err_AddInput,
  Err_AddOutput,
  Err_AddInOut,
  Err_ChangePin,
  Nop_SimStateFunc,
  RamRom_SimHitFunc,
  Generic_PSWrite,
  Generic_EditProps,
  RamRom_VerSave
};

GCElement *RamRom_Make(EditState **es,GModuleDef *env,int GType,
		    int x,int y,int r,const char *Name,int noWires,const char **options,int nOptions)
{
  GCElement *g;
  const char *DefV;

  if (!(g = Generic_Make(es,env,GType,x,y,r,Name,noWires,options,nOptions)))
    return NULL;

  DefV = seekOption("-memfile",options,nOptions);

  ob_touch(g);

  if (!DefV)
    g->u.mem.memfile = 0;
  else
    g->u.mem.memfile = ob_strdup(DefV);

  return g;
}


void RamRom_EditProps(GCElement *g,int isLoadDialog)
{
  Tcl_Interp *tcl = XGate.tcl;

  Generic_EditProps(g,isLoadDialog);
  if (isLoadDialog) {
    DoTcl("set edgat_memFile \"%s\"",g->u.mem.memfile ? g->u.mem.memfile : "");
  } else {
    const char *p;

    ob_touch(g);
    if (g->u.mem.memfile) ob_free(g->u.mem.memfile);
    g->u.mem.memfile = 0;

    if ((p = Tcl_GetVar(tcl,"edgat_memFile",TCL_GLOBAL_ONLY))) {
      if (strspn(p," ") != strlen(p))
	g->u.mem.memfile = ob_strdup(p);
    }
  }
}

void RamRom_SetProp(GCElement *g,const char *name,const void *value)
{
  if (strcmp(name,"/mem") == 0) {
    ob_touch(g);
    if (g->u.mem.memfile) ob_free(g->u.mem.memfile);
    g->u.mem.memfile = ob_strdup(value);
  }
}

void RamRom_SimHitFunc(EditState *es,GCElement *g)
{
  selectGate(es,XGate.ed->tx,XGate.ed->ty);
}

void RamRom_VerSave(FILE *f,GCElement *g)
{
  VerilogBasicGateCall(f,g);
  VerilogBasicGateParmList(f,g);
  VerilogBasicGateComment(f,g,1);
  if (g->u.mem.memfile)
    fprintf(f," /mem:\"%s\"",g->u.mem.memfile);
  fprintf(f,"\n");
}


void init_ram()
{
  Pixmap P;

  P = Pixmap_registerFromFile("ram","ram.b");
  gateinfo_1iconInit(&gate_ram_info,P,ram_iconDims,ram_iconBoldOffset);
  RegisterGate(&gate_ram_info);
}

