1 /****************************************************************************
2     Copyright (C) 1987-2015 by Jeffery P. Hansen
3 
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8 
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13 
14     You should have received a copy of the GNU General Public License along
15     with this program; if not, write to the Free Software Foundation, Inc.,
16     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 
18     Last edit by hansen on Tue Feb  3 15:33:02 2009
19 ****************************************************************************/
20 
21 #include "tkgate.h"
22 #include "print.h"
23 
24 static void FF_WriteCellDef(FILE *f,GCellSpec *gcs);
25 static GCElement *FF_Make(EditState **es,GModuleDef *env,int GType,
26 		   int x,int y,int r,const char *Name,int noWires,const char **options,int nOptions);
27 static void FF_Draw(GCElement *g,int md);
28 static int FF_EditProps(GCElement *g,int isLoadDialog);
29 static void FF_VerSave(FILE *f,GCElement *g);
30 static GCElement *FF_Copy(GModuleDef *M,GCElement *g,int x,int y,unsigned);
31 static void FF_SetProp(GCElement *g,const char *prop,const void *value);
32 static void FF_PSWrite(GPrint *gp,GModLayout*,GCElement *g);
33 static GWireNode *FF_wireSnap(GCElement *g,GWire *w,int *mod,int retry);
34 static void FF_Rotate(GCElement *g, int centX, int centY,int rdir);
35 
36 static iconDimensions ff_iconDims[] = {
37   {0,  0, 31, 31, 15, 15},
38   {32, 0, 31, 31, 15, 15},
39   {32, 32, 31, 31, 15, 15},
40   {0,  32, 31, 31, 15, 15},
41 };
42 static int ff_iconBoldOffset = 64;
43 
44 GPadLoc ff_in_loc[] = {
45 	{-16,0,-16,0,D_LEFT},
46 	{0,16,0,16,D_DOWN},
47 	{16,0,16,0,D_RIGHT},
48 	{0,-16,0,-16,D_UP},
49 };
50 
51 GPadLoc ff_out_loc[] = {
52 	{16,-5,16,-5,D_RIGHT},
53 	{-5,-16,-5,-16,D_UP},
54 	{-16,5,-16,5,D_LEFT},
55 	{5,16,5,16,D_DOWN},
56 };
57 
58 GPadLoc ff_nout_loc[] = {
59 	{16,5,16,5,D_RIGHT},
60 	{5,-16,5,-16,D_UP},
61 	{-16,-5,-16,-5,D_LEFT},
62 	{-5,16,-5,16,D_DOWN},
63 };
64 
65 GPadLoc ff_ck_loc[] = {
66 	{0,16,0,16,D_DOWN},
67 	{16,0,16,0,D_RIGHT},
68 	{0,-16,0,-16,D_UP},
69 	{-16,0,-16,0,D_LEFT},
70 };
71 
72 GPadLoc ff_en_loc[] = {
73 	{5,-16,5,-16,D_UP},
74 	{-16,-5,-16,-5,D_LEFT},
75 	{-5,16,-5,16,D_DOWN},
76 	{16,5,16,5,D_RIGHT},
77 };
78 
79 GPadLoc ff_clr_loc[] = {
80 	{-5,-16,-5,-16,D_UP},
81 	{-16,5,-16,5,D_LEFT},
82 	{5,16,5,16,D_DOWN},
83 	{16,-5,16,-5,D_RIGHT},
84 };
85 
86 /***************************************************************************************/
87 /* Reverse locations */
88 /***************************************************************************************/
89 struct locate rff_in_loc[] = {
90 	{16,0,16,0,D_RIGHT},
91 	{0,-16,0,-16,D_UP},
92 	{-16,0,-16,0,D_LEFT},
93 	{0,16,0,16,D_DOWN},
94 };
95 
96 struct locate rff_out_loc[] = {
97 	{-16,-5,-16,-5,D_LEFT},
98 	{-5,16,-5,16,D_DOWN},
99 	{16,5,16,5,D_RIGHT},
100 	{5,-16,5,-16,D_UP},
101 };
102 
103 struct locate rff_nout_loc[] = {
104 	{-16,5,-16,5,D_LEFT},
105 	{5,16,5,16,D_DOWN},
106 	{16,-5,16,-5,D_RIGHT},
107 	{-5,-16,-5,-16,D_UP},
108 };
109 
110 static char *psFlipFlop[] = {
111   "%",
112   "% A flip-flop",
113   "/psflipflop {",
114   "  [[0 0][0 0][0 0][0 0]] adjstartgate",
115   "  -15.5 -15.5 moveto",
116   "  -15.5 15.5 lineto",
117   "  15.5 15.5 lineto",
118   "  15.5 -15.5 lineto",
119   "  closepath stroke",
120   "  -5 -15.5 moveto",
121   "  0 -10.5 lineto",
122   "  5 -15.5 lineto",
123   "  stroke",
124   "  7 rfont",
125   "  (_C) -8 6 prshow",
126   "  (_E) 2 6 prshow",
127   "  {",
128   "    (Q) -14 2 prshow",
129   "    (_Q) -14 -8 prshow",
130   "    (D) 8 -3 prshow",
131   "  } {",
132   "    (Q) 8 2 prshow",
133   "    (_Q) 8 -8 prshow",
134   "    (D) -14 -3 prshow",
135   "  } ifelse",
136   "  grestore",
137   "} def",
138   0
139 };
140 
141 GGateInfo gate_ff_info = {
142   GC_FLIPFLOP,
143   "FF",
144   "ff",0x0,
145   "psflipflop",psFlipFlop,
146   -1,0,
147 
148   {{"f",	{"gm.mem",5},		{"gm.mem.ff",0,0,100},	"gat_make FF"},
149    {"q",	{"gm.mem",5},		{"gm.mem.rff",0,0,100},	"gat_make FF -reverse 1"},
150 
151    {0}},
152 
153 
154   ff_iconDims,
155 
156   6,{{"Q",OUT,1,1,ff_out_loc},
157      {"_Q",OUT,1,1,ff_nout_loc},
158      {"D",IN,1,1,ff_in_loc},
159      {"EN",IN,1,1,ff_en_loc},
160      {"CLR",IN,1,1,ff_clr_loc},
161      {"CK",IN,1,1,ff_ck_loc}},
162   {{-17,15,RJ},{17,15,LJ},{17,15,LJ},{-17,15,RJ}},
163   {1},
164 
165   {"Dsetup","Dhold","Dck_q",0},
166 
167   FF_Make,
168   FF_WriteCellDef,
169   Generic_Init,
170   Generic_Delete,
171   Generic_GetExtents,
172   Generic_HitDistance,
173   FF_Draw,
174   Generic_Move,
175   FF_Copy,
176   Err_AddInput,
177   Err_AddOutput,
178   Err_AddInOut,
179   FF_Rotate,
180   Err_RemovePort,
181   Err_ChangePin,
182   Nop_SimInitFunc,
183   Nop_SimHitFunc,
184   FF_PSWrite,
185   FF_EditProps,
186   FF_VerSave,
187   FF_SetProp,
188   0,
189   FF_wireSnap
190 };
191 
192 /*****************************************************************************
193  *
194  * Make the GGateInfo structure reflect a normal flip-flop
195  *
196  *****************************************************************************/
FF_normal_gateinfo()197 static void FF_normal_gateinfo()
198 {
199   gate_ff_info.Pad[0].Loc = ff_out_loc;
200   gate_ff_info.Pad[1].Loc = ff_nout_loc;
201   gate_ff_info.Pad[2].Loc = ff_in_loc;
202 }
203 
204 /*****************************************************************************
205  *
206  * Make the GGateInfo structure reflect a mirror flip-flop
207  *
208  *****************************************************************************/
FF_reverse_gateinfo()209 static void FF_reverse_gateinfo()
210 {
211   gate_ff_info.Pad[0].Loc = rff_out_loc;
212   gate_ff_info.Pad[1].Loc = rff_nout_loc;
213   gate_ff_info.Pad[2].Loc = rff_in_loc;
214 }
215 
FF_Make(EditState ** es,GModuleDef * env,int GType,int x,int y,int r,const char * Name,int noWires,const char ** options,int nOptions)216 static GCElement *FF_Make(EditState **es,GModuleDef *env,int GType,
217 			int x,int y,int r,const char *Name,int noWires,const char **options,int nOptions)
218 {
219   GCElement *g;
220   const char *revOpt;
221   int isMirror = 0;
222 
223   revOpt = seekOption("-reverse",options,nOptions);
224   if (revOpt && *revOpt == '1')
225     isMirror = 1;
226 
227   if (isMirror)
228     FF_reverse_gateinfo();
229 
230   g = Generic_Make(es,env,GType,x,y,r,Name,noWires,options,nOptions);
231   ob_touch(g);
232   g->u.ff.mirror = isMirror;
233 
234   if (isMirror)
235     FF_normal_gateinfo();
236 
237   return g;
238 }
239 
FF_Draw(GCElement * g,int md)240 static void FF_Draw(GCElement *g,int md)
241 {
242   int x = g->xpos;
243   int y = g->ypos;
244   GGateInfo *gi = g->typeinfo;
245   int idx = g->orient;
246   int selected = g->selected;
247 
248   if (selected) idx += 4;
249 
250   if (g->u.ff.mirror)
251     Icon_draw(TkGate.D,TkGate.W,TkGate.instGC,ctow_x(x),ctow_y(y),gi->altIcon[idx]);
252   else
253     Icon_draw(TkGate.D,TkGate.W,TkGate.instGC,ctow_x(x),ctow_y(y),gi->icon[idx]);
254 
255   gate_drawWires(g,md);
256 
257   if (g->ename && g->show_name)
258     gate_drawgatename(g,g->ename);
259 }
260 
FF_EditProps(GCElement * g,int isLoadDialog)261 static int FF_EditProps(GCElement *g,int isLoadDialog)
262 {
263   Tcl_Interp *tcl = TkGate.tcl;
264 
265   Generic_EditProps(g,isLoadDialog);
266   if (isLoadDialog) {
267     DoTcl("set ::edgat_ffmirror %d",g->u.ff.mirror);
268   } else {
269     const char *p;
270     int mirror = g->u.ff.mirror;
271 
272     if ((p = Tcl_GetVar(tcl,"edgat_ffmirror",TCL_GLOBAL_ONLY)))
273       sscanf(p,"%d",&mirror);
274 
275     if (g->u.ff.mirror != mirror) {
276       int p;
277 
278       g->u.ff.mirror = mirror;
279 
280       if (mirror)
281 	FF_reverse_gateinfo();
282 
283       for (p = 0;p < 3;p++) {
284 	GPadLoc *pd = &g->typeinfo->Pad[p].Loc[g->orient];
285 
286 	wire_rePort(g->wires[p],g->xpos+pd->x2,g->ypos+pd->y2,pd->dir);
287       }
288 
289       if (mirror)
290 	FF_normal_gateinfo();
291     }
292 
293     ob_touch(g);
294   }
295 
296   return 0;
297 }
298 
FF_Rotate(GCElement * g,int centX,int centY,int rdir)299 static void FF_Rotate(GCElement *g, int centX, int centY,int rdir)
300 {
301   if (g->u.ff.mirror)
302     FF_reverse_gateinfo();
303 
304   Generic_Rotate(g,centX,centY,rdir);
305 
306   if (g->u.ff.mirror)
307     FF_normal_gateinfo();
308 }
309 
310 
FF_VerSave(FILE * f,GCElement * g)311 static void FF_VerSave(FILE *f,GCElement *g)
312 {
313   VerilogBasicGateCall(f,g);
314   VerilogBasicGateParmList(f,g);
315   VerilogBasicGateComment(f,g,1);
316   fprintf(f," /mi:%d",g->u.ff.mirror);
317   fprintf(f,"\n");
318 }
319 
FF_Copy(GModuleDef * M,GCElement * g,int x,int y,unsigned flags)320 static GCElement *FF_Copy(GModuleDef *M,GCElement *g,int x,int y,unsigned flags)
321 {
322   GCElement *ng;
323 
324   if (g->u.ff.mirror)
325     FF_reverse_gateinfo();
326 
327   ng = Generic_Copy(M,g,x,y,flags);
328   ob_touch(ng);
329   ng->u.ff.mirror = g->u.ff.mirror;
330 
331   if (g->u.ff.mirror)
332     FF_normal_gateinfo();
333 
334   return ng;
335 }
336 
FF_SetProp(GCElement * g,const char * prop,const void * value)337 static void FF_SetProp(GCElement *g,const char *prop,const void *value)
338 {
339   int i;
340 
341   if (strcmp(prop,"/mi") == 0) g->u.ff.mirror = *((int*)value);
342 
343   if (g->u.ff.mirror) {
344     for (i = 0;i < 3;i++) {
345       if (g->wires[i])
346 	g->wires[i]->orient = (g->wires[i]->orient + 2) % 4;
347     }
348   }
349 }
350 
FF_PSWrite(GPrint * gp,GModLayout * mli,GCElement * g)351 static void FF_PSWrite(GPrint *gp,GModLayout *mli,GCElement *g)
352 {
353   Generic_PSLabels(gp,g);
354 
355   fprintf(gp->p_f,"%s %d %d %d %s\n",
356 	  g->u.ff.mirror ? "true" : "false",
357 	  g->xpos,g->ypos,-g->orient*90,
358 	  g->typeinfo->psprint);
359 }
360 
FF_wireSnap(GCElement * g,GWire * w,int * mod,int retry)361 static GWireNode *FF_wireSnap(GCElement *g,GWire *w,int *mod,int retry)
362 {
363   int p,n;
364 
365   if (posongate(w,w->gate,&p,&n) == 0) {
366     GPadLoc *pd;
367 
368     if (g->u.ff.mirror)
369       FF_reverse_gateinfo();
370 
371     pd = &g->typeinfo->Pad[p].Loc[g->orient];
372 
373     if (g->u.ff.mirror)
374       FF_normal_gateinfo();
375 
376 
377     *mod = wire_force(w,pd->dir,retry);
378   }
379   return w->nodes;
380 }
381 
382 /*****************************************************************************
383  *
384  * Generate primitive cell definition for flip-flops.
385  *
386  * Parameters:
387  *    f			File to write cell to.
388  *    name		Name of cell to write.
389  *
390  *****************************************************************************/
FF_WriteCellDef(FILE * f,GCellSpec * gcs)391 static void FF_WriteCellDef(FILE *f,GCellSpec *gcs)
392 {
393   int numBit = gcs->gc_numBits;
394   const char *invSpec = gcs->gc_invSpec;
395   int invQ = 0, invNQ = 1;
396   PrimParm primParm;
397 
398   if (*invSpec) {
399     if (*invSpec == 'N')
400       invQ = 1;
401     if (!invSpec[1] || invSpec[1] == 'N')
402       invNQ = 0;
403   }
404 
405   PrimParm_init(&primParm);
406   PrimParm_rangeSet(&primParm,"DQ_RANGE",numBit);
407   PrimParm_intSet(&primParm,"DQ_BITS",numBit);
408   PrimParm_invSet(&primParm,"invQ",invQ);
409   PrimParm_invSet(&primParm,"invNQ",invNQ);
410   Primitive_write(f,"flipflop",gcs,&primParm);
411 }
412 
init_ff()413 void init_ff()
414 {
415   Pixmap P;
416 
417   P = Pixmap_registerFromFile("flipflop","flipflop.b");
418   gateinfo_iconInit(&gate_ff_info,P,ff_iconDims,ff_iconBoldOffset);
419 
420   P = Pixmap_registerFromFile("rflipflop","rflipflop.b");
421   gateinfo_altIconInit(&gate_ff_info,P,ff_iconDims,ff_iconBoldOffset);
422 
423   RegisterGate(&gate_ff_info);
424 }
425