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 Mon Jan 19 23:41:17 2009
19 ****************************************************************************/
20 
21 #include "tkgate.h"
22 #include "print.h"
23 
24 #define REV_PADS	4		/* First four pads subject to mirror */
25 #define JKFF_Q		0
26 #define JKFF_NQ		1
27 #define JKFF_J		2
28 #define JKFF_K		3
29 #define JKFF_PRE	4
30 #define JKFF_CLR	5
31 #define JKFF_CK		6
32 
33 static void JKFF_WriteCellDef(FILE *f,GCellSpec *gcs);
34 static GCElement *JKFF_Make(EditState **es,GModuleDef *env,int GType,
35 		   int x,int y,int r,const char *Name,int noWires,const char **options,int nOptions);
36 static void JKFF_Draw(GCElement *g,int md);
37 static int JKFF_EditProps(GCElement *g,int isLoadDialog);
38 static void JKFF_VerSave(FILE *f,GCElement *g);
39 static GCElement *JKFF_Copy(GModuleDef *M,GCElement *g,int x,int y,unsigned);
40 static void JKFF_SetProp(GCElement *g,const char *prop,const void *value);
41 static void JKFF_PSWrite(GPrint *gp,GModLayout*,GCElement *g);
42 static GWireNode *JKFF_wireSnap(GCElement *g,GWire *w,int *mod,int retry);
43 static void JKFF_Rotate(GCElement *g, int centX, int centY,int rdir);
44 
45 static iconDimensions jkff_iconDims[] = {
46   {0,  0, 31, 31, 15, 15},
47   {32, 0, 31, 31, 15, 15},
48   {32, 32, 31, 31, 15, 15},
49   {0,  32, 31, 31, 15, 15},
50 };
51 static int jkff_iconBoldOffset = 64;
52 
53 GPadLoc jkff_j_loc[] = {
54 	{-16,-5,-16,-5,D_LEFT},
55 	{-5,16,-5,16,D_DOWN},
56 	{16,5,16,5,D_RIGHT},
57 	{5,-16,5,-16,D_UP},
58 };
59 
60 GPadLoc jkff_k_loc[] = {
61 	{-16,5,-16,5,D_LEFT},
62 	{5,16,5,16,D_DOWN},
63 	{16,-5,16,-5,D_RIGHT},
64 	{-5,-16,-5,-16,D_UP},
65 };
66 
67 GPadLoc jkff_out_loc[] = {
68 	{16,-5,16,-5,D_RIGHT},
69 	{-5,-16,-5,-16,D_UP},
70 	{-16,5,-16,5,D_LEFT},
71 	{5,16,5,16,D_DOWN},
72 };
73 
74 GPadLoc jkff_nout_loc[] = {
75 	{16,5,16,5,D_RIGHT},
76 	{5,-16,5,-16,D_UP},
77 	{-16,-5,-16,-5,D_LEFT},
78 	{-5,16,-5,16,D_DOWN},
79 };
80 
81 GPadLoc jkff_ck_loc[] = {
82 	{0,16,0,16,D_DOWN},
83 	{16,0,16,0,D_RIGHT},
84 	{0,-16,0,-16,D_UP},
85 	{-16,0,-16,0,D_LEFT},
86 };
87 
88 GPadLoc jkff_clr_loc[] = {
89 	{5,-16,5,-16,D_UP},
90 	{-16,-5,-16,-5,D_LEFT},
91 	{-5,16,-5,16,D_DOWN},
92 	{16,5,16,5,D_RIGHT},
93 };
94 
95 GPadLoc jkff_pre_loc[] = {
96 	{-5,-16,-5,-16,D_UP},
97 	{-16,5,-16,5,D_LEFT},
98 	{5,16,5,16,D_DOWN},
99 	{16,-5,16,-5,D_RIGHT},
100 };
101 
102 /***************************************************************************************/
103 /* Reverse locations */
104 /***************************************************************************************/
105 struct locate rjkff_j_loc[] = {
106 	{16,-5,16,-5,D_RIGHT},
107 	{-5,-16,-5,-16,D_UP},
108 	{-16,5,-16,5,D_LEFT},
109 	{5,16,5,16,D_DOWN},
110 };
111 
112 struct locate rjkff_k_loc[] = {
113 	{16,5,16,5,D_RIGHT},
114 	{5,-16,5,-16,D_UP},
115 	{-16,-5,-16,-5,D_LEFT},
116 	{-5,16,-5,16,D_DOWN},
117 };
118 
119 struct locate rjkff_out_loc[] = {
120 	{-16,-5,-16,-5,D_LEFT},
121 	{-5,16,-5,16,D_DOWN},
122 	{16,5,16,5,D_RIGHT},
123 	{5,-16,5,-16,D_UP},
124 };
125 
126 struct locate rjkff_nout_loc[] = {
127 	{-16,5,-16,5,D_LEFT},
128 	{5,16,5,16,D_DOWN},
129 	{16,-5,16,-5,D_RIGHT},
130 	{-5,-16,-5,-16,D_UP},
131 };
132 
133 static char *psJKFF[] = {
134   "%",
135   "% A JK flip-flop",
136   "/psjkff {",
137   "  [[0 0][0 0][0 0][0 0]] adjstartgate",
138   "  -15.5 -15.5 moveto",
139   "  -15.5 15.5 lineto",
140   "  15.5 15.5 lineto",
141   "  15.5 -15.5 lineto",
142   "  closepath stroke",
143   "  -5 -15.5 moveto",
144   "  0 -10.5 lineto",
145   "  5 -15.5 lineto",
146   "  stroke",
147   "  7 rfont",
148   "  (_C) -8 6 prshow",
149   "  (_P) 2 6 prshow",
150   "  {",
151   "    (Q) -14 2 prshow",
152   "    (_Q) -14 -8 prshow",
153   "    (J) 8 2 prshow",
154   "    (K) 8 -8 prshow",
155   "  } {",
156   "    (Q) 8 2 prshow",
157   "    (_Q) 8 -8 prshow",
158   "    (J) -14 2 prshow",
159   "    (K) -14 -8 prshow",
160   "  } ifelse",
161   "  grestore",
162   "} def",
163   0
164 };
165 
166 GGateInfo gate_jkff_info = {
167   0,
168   "JKFF",
169   "jkff",0x0,
170   "psjkff",psJKFF,
171   -1,0,
172 
173   {{"j",	{"gm.mem",5},		{"gm.mem.jkff",0,0,200},	"gat_make JKFF"},
174    {"J",	{"gm.mem",5},		{"gm.mem.rjkff",0,0,200},	"gat_make JKFF -reverse 1"},
175 
176    {0}},
177 
178 
179   jkff_iconDims,
180 
181   7,{{"Q",OUT,1,1,jkff_out_loc},
182      {"_Q",OUT,1,1,jkff_nout_loc},
183      {"J",IN,1,1,jkff_j_loc},
184      {"K",IN,1,1,jkff_k_loc},
185      {"PRE",IN,1,1,jkff_pre_loc},
186      {"CLR",IN,1,1,jkff_clr_loc},
187      {"CK",IN,1,1,jkff_ck_loc}},
188   {{-17,15,RJ},{17,15,LJ},{17,15,LJ},{-17,15,RJ}},
189   {1},
190 
191   {"Dsetup","Dhold","Dck_q",0},
192 
193   JKFF_Make,
194   JKFF_WriteCellDef,
195   Generic_Init,
196   Generic_Delete,
197   Generic_GetExtents,
198   Generic_HitDistance,
199   JKFF_Draw,
200   Generic_Move,
201   JKFF_Copy,
202   Err_AddInput,
203   Err_AddOutput,
204   Err_AddInOut,
205   JKFF_Rotate,
206   Err_RemovePort,
207   Err_ChangePin,
208   Nop_SimInitFunc,
209   Nop_SimHitFunc,
210   JKFF_PSWrite,
211   JKFF_EditProps,
212   JKFF_VerSave,
213   JKFF_SetProp,
214   0,
215   JKFF_wireSnap
216 };
217 
218 /*****************************************************************************
219  *
220  * Make the GGateInfo structure reflect a normal flip-flop
221  *
222  *****************************************************************************/
JKFF_normal_gateinfo()223 static void JKFF_normal_gateinfo()
224 {
225   gate_jkff_info.Pad[JKFF_Q].Loc = jkff_out_loc;
226   gate_jkff_info.Pad[JKFF_NQ].Loc = jkff_nout_loc;
227   gate_jkff_info.Pad[JKFF_J].Loc = jkff_j_loc;
228   gate_jkff_info.Pad[JKFF_K].Loc = jkff_k_loc;
229 }
230 
231 /*****************************************************************************
232  *
233  * Make the GGateInfo structure reflect a mirror flip-flop
234  *
235  *****************************************************************************/
JKFF_reverse_gateinfo()236 static void JKFF_reverse_gateinfo()
237 {
238   gate_jkff_info.Pad[JKFF_Q].Loc = rjkff_out_loc;
239   gate_jkff_info.Pad[JKFF_NQ].Loc = rjkff_nout_loc;
240   gate_jkff_info.Pad[JKFF_J].Loc = rjkff_j_loc;
241   gate_jkff_info.Pad[JKFF_K].Loc = rjkff_k_loc;
242 }
243 
JKFF_Make(EditState ** es,GModuleDef * env,int GType,int x,int y,int r,const char * Name,int noWires,const char ** options,int nOptions)244 static GCElement *JKFF_Make(EditState **es,GModuleDef *env,int GType,
245 			    int x,int y,int r,const char *Name,int noWires,
246 			    const char **options,int nOptions)
247 {
248   GCElement *g;
249   const char *revOpt;
250   int isMirror = 0;
251 
252   revOpt = seekOption("-reverse",options,nOptions);
253   if (revOpt && *revOpt == '1')
254     isMirror = 1;
255 
256   if (isMirror)
257     JKFF_reverse_gateinfo();
258 
259   g = Generic_Make(es,env,GType,x,y,r,Name,noWires,options,nOptions);
260   ob_touch(g);
261   g->u.ff.mirror = isMirror;
262 
263   if (isMirror)
264     JKFF_normal_gateinfo();
265 
266   return g;
267 }
268 
JKFF_Draw(GCElement * g,int md)269 static void JKFF_Draw(GCElement *g,int md)
270 {
271   int x = g->xpos;
272   int y = g->ypos;
273   GGateInfo *gi = g->typeinfo;
274   int idx = g->orient;
275   int selected = g->selected;
276 
277   if (selected) idx += 4;
278 
279   if (g->u.ff.mirror)
280     Icon_draw(TkGate.D,TkGate.W,TkGate.instGC,ctow_x(x),ctow_y(y),gi->altIcon[idx]);
281   else
282     Icon_draw(TkGate.D,TkGate.W,TkGate.instGC,ctow_x(x),ctow_y(y),gi->icon[idx]);
283 
284   gate_drawWires(g,md);
285 
286   if (g->ename && g->show_name)
287     gate_drawgatename(g,g->ename);
288 }
289 
JKFF_EditProps(GCElement * g,int isLoadDialog)290 static int JKFF_EditProps(GCElement *g,int isLoadDialog)
291 {
292   Tcl_Interp *tcl = TkGate.tcl;
293 
294   Generic_EditProps(g,isLoadDialog);
295   if (isLoadDialog) {
296     DoTcl("set ::edgat_ffmirror %d",g->u.ff.mirror);
297   } else {
298     const char *p;
299     int mirror = g->u.ff.mirror;
300 
301     if ((p = Tcl_GetVar(tcl,"edgat_ffmirror",TCL_GLOBAL_ONLY)))
302       sscanf(p,"%d",&mirror);
303 
304     if (g->u.ff.mirror != mirror) {
305       int p;
306 
307       g->u.ff.mirror = mirror;
308 
309       if (mirror)
310 	JKFF_reverse_gateinfo();
311 
312       for (p = 0;p < REV_PADS;p++) {
313 	GPadLoc *pd = &g->typeinfo->Pad[p].Loc[g->orient];
314 
315 	wire_rePort(g->wires[p],g->xpos+pd->x2,g->ypos+pd->y2,pd->dir);
316       }
317 
318       if (mirror)
319 	JKFF_normal_gateinfo();
320     }
321 
322     ob_touch(g);
323   }
324 
325   return 0;
326 }
327 
JKFF_Rotate(GCElement * g,int centX,int centY,int rdir)328 static void JKFF_Rotate(GCElement *g, int centX, int centY,int rdir)
329 {
330   if (g->u.ff.mirror)
331     JKFF_reverse_gateinfo();
332 
333   Generic_Rotate(g,centX,centY,rdir);
334 
335   if (g->u.ff.mirror)
336     JKFF_normal_gateinfo();
337 }
338 
339 
JKFF_VerSave(FILE * f,GCElement * g)340 static void JKFF_VerSave(FILE *f,GCElement *g)
341 {
342   VerilogBasicGateCall(f,g);
343   VerilogBasicGateParmList(f,g);
344   VerilogBasicGateComment(f,g,1);
345   fprintf(f," /mi:%d",g->u.ff.mirror);
346   fprintf(f,"\n");
347 }
348 
JKFF_Copy(GModuleDef * M,GCElement * g,int x,int y,unsigned flags)349 static GCElement *JKFF_Copy(GModuleDef *M,GCElement *g,int x,int y,unsigned flags)
350 {
351   GCElement *ng;
352 
353   if (g->u.ff.mirror)
354     JKFF_reverse_gateinfo();
355 
356   ng = Generic_Copy(M,g,x,y,flags);
357   ob_touch(ng);
358   ng->u.ff.mirror = g->u.ff.mirror;
359 
360   if (g->u.ff.mirror)
361     JKFF_normal_gateinfo();
362 
363   return ng;
364 }
365 
JKFF_SetProp(GCElement * g,const char * prop,const void * value)366 static void JKFF_SetProp(GCElement *g,const char *prop,const void *value)
367 {
368   int i;
369 
370   if (strcmp(prop,"/mi") == 0) g->u.ff.mirror = *((int*)value);
371 
372   if (g->u.ff.mirror) {
373     for (i = 0;i < REV_PADS;i++) {
374       if (g->wires[i])
375 	g->wires[i]->orient = (g->wires[i]->orient + 2) % 4;
376     }
377   }
378 }
379 
JKFF_PSWrite(GPrint * gp,GModLayout * mli,GCElement * g)380 static void JKFF_PSWrite(GPrint *gp,GModLayout *mli,GCElement *g)
381 {
382   Generic_PSLabels(gp,g);
383 
384   fprintf(gp->p_f,"%s %d %d %d %s\n",
385 	  g->u.ff.mirror ? "true" : "false",
386 	  g->xpos,g->ypos,-g->orient*90,
387 	  g->typeinfo->psprint);
388 }
389 
JKFF_wireSnap(GCElement * g,GWire * w,int * mod,int retry)390 static GWireNode *JKFF_wireSnap(GCElement *g,GWire *w,int *mod,int retry)
391 {
392   int p,n;
393 
394   if (posongate(w,w->gate,&p,&n) == 0) {
395     GPadLoc *pd;
396 
397     if (g->u.ff.mirror)
398       JKFF_reverse_gateinfo();
399 
400     pd = &g->typeinfo->Pad[p].Loc[g->orient];
401 
402     if (g->u.ff.mirror)
403       JKFF_normal_gateinfo();
404 
405 
406     *mod = wire_force(w,pd->dir,retry);
407   }
408   return w->nodes;
409 }
410 
411 /*****************************************************************************
412  *
413  * Generate primitive cell definition for flip-flops.
414  *
415  * Parameters:
416  *    f			File to write cell to.
417  *    name		Name of cell to write.
418  *
419  *****************************************************************************/
JKFF_WriteCellDef(FILE * f,GCellSpec * gcs)420 static void JKFF_WriteCellDef(FILE *f,GCellSpec *gcs)
421 {
422   int numBit = gcs->gc_numBits;
423   const char *invSpec = gcs->gc_invSpec;
424   int invQ = 0, invNQ = 1;
425   PrimParm primParm;
426 
427   if (*invSpec) {
428     if (*invSpec == 'N')
429       invQ = 1;
430     if (!invSpec[1] || invSpec[1] == 'N')
431       invNQ = 0;
432   }
433 
434   PrimParm_init(&primParm);
435   PrimParm_rangeSet(&primParm,"JK_RANGE",numBit);
436   PrimParm_intSet(&primParm,"JK_BITS",numBit);
437   PrimParm_invSet(&primParm,"invQ",invQ);
438   PrimParm_invSet(&primParm,"invNQ",invNQ);
439   Primitive_write(f,"jkff",gcs,&primParm);
440 }
441 
init_jkff()442 void init_jkff()
443 {
444   Pixmap P;
445 
446   P = Pixmap_registerFromFile("jkff","jkff.b");
447   gateinfo_iconInit(&gate_jkff_info,P,jkff_iconDims,jkff_iconBoldOffset);
448 
449   P = Pixmap_registerFromFile("rjkff","rjkff.b");
450   gateinfo_altIconInit(&gate_jkff_info,P,jkff_iconDims,jkff_iconBoldOffset);
451 
452   RegisterGate(&gate_jkff_info);
453 }
454