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