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 18:14:05 2009
19 ****************************************************************************/
20 
21 #include "tkgate.h"
22 
23 #include "print.h"
24 
25 #define CLOCK_OUT 0
26 #define CLOCKPARAMXOFFSET 0
27 #define CLOCKPARAMYOFFSET 20
28 
29 /* Defines local to this file */
30 #define F_PW 0x1
31 #define F_PHI 0x2
32 #define F_DW 0x4
33 
34 /* Default clock parameters */
35 #define CLOCK_OMEGA	100
36 #define CLOCK_PHI    	0
37 #define CLOCK_DUTY	50
38 
39 static void Clock_WriteCellDef(FILE *f,GCellSpec *gcs);
40 
41 static iconDimensions clock_iconDims[] = {
42   {0, 0, 27, 25, 13, 12},
43   {27, 0, 25, 26, 12, 14},
44   {26, 27, 27, 25, 12, 13},
45   {0, 26, 25, 26, 15, 14},
46 };
47 static int clock_iconBoldOffset = 53;
48 
49 GCElement *Clock_Make(EditState **es,GModuleDef *env,int GType,
50 		      int x,int y,int r,const char *Name,int noWire,const char**,int);
51 void Clock_Draw(GCElement *g,int md);
52 GCElement *Clock_Copy(GModuleDef *M,GCElement *g,int x,int y,unsigned flags);
53 int Clock_EditProps(GCElement *g,int isLoadDialog);
54 void Clock_PSWrite(GPrint *P,GModLayout*,GCElement *g);
55 void Clock_VerSave(FILE*,GCElement*);
56 void Clock_SetProp(GCElement*,const char*,const void*);
57 
58 GPadLoc clock_out_loc[] = {
59 	{13,0,13,0,D_RIGHT},
60 	{0,-15,0,-15,D_UP},
61 	{-13,-1,-13,-1,D_LEFT},
62 	{-3,12,-3,12,D_DOWN}};
63 
64 static char *psClock[] = {
65   "%",
66   "% dw phi pw x y r clockgate",
67   "%",
68   "/psclock_base {",
69   "  [[-1 0][0 0][1 -1][-3 -2]] adjstartgate",
70   "  -8 -12 moveto",
71   "  16 0 lineto",
72   "  -8 12 lineto",
73   "  closepath",
74   "  stroke",
75   "  -6 -4 moveto",
76   "  -4 -4 lineto",
77   "  -4 4 lineto",
78   "  0 4 lineto",
79   "  0 -4 lineto",
80   "  2 -4 lineto",
81   "  stroke",
82   "  grestore",
83   "} def",
84   "/psclock {",
85   "  3 copy psclock_base",
86   "  startnorotgate",
87   "  0 -20 translate",
88   "  0 0 moveto",
89   "  8 rfont",
90   "  (P = ) show",
91   "  20 string cvs show",
92   "  ( ) show",
93   "  8 syfont",
94   "  (f) show ",
95   "  8 rfont",
96   "  ( = ) show",
97   "  20 string cvs show",
98   "  ( D = ) show",
99   "  20 string cvs show",
100   "  grestore",
101   "} bind def",
102   0
103 };
104 
105 GGateInfo gate_clock_info = {
106   GC_CLOCK,
107   "CLOCK",
108   "clock",0x0,
109   "psclock",psClock,
110   -1,-1,
111 
112   {{"c",	{"gm.io",0},		{"gm.io.clock",0,"x",100},	"gat_make CLOCK"},
113    {0}},
114 
115   clock_iconDims,
116 
117   1,{{"Z",OUT,1,1,clock_out_loc}},
118   {{0,-17,CT},{17,0,LJ},{0,-17,CT},{17,0,LJ}},
119   {1},
120 
121   {0},
122 
123   Clock_Make,
124   Clock_WriteCellDef,
125   Generic_Init,
126   Generic_Delete,
127   Generic_GetExtents,
128   Generic_HitDistance,
129   Clock_Draw,
130   Generic_Move,
131   Clock_Copy,
132   Err_AddInput,
133   Err_AddOutput,
134   Err_AddInOut,
135   Generic_Rotate,
136   Err_RemovePort,
137   Err_ChangePin,
138   Nop_SimInitFunc,
139   Nop_SimHitFunc,
140   Clock_PSWrite,
141   Clock_EditProps,
142   Clock_VerSave,
143   Clock_SetProp
144 };
145 
gate_drawclockparams(GCElement * g)146 void gate_drawclockparams(GCElement *g)
147 {
148   char b[STRMAX];
149   int x,y;
150 
151   x = g->xpos + CLOCKPARAMXOFFSET;
152   y = g->ypos + CLOCKPARAMYOFFSET;
153 
154   if (g->selected)
155     XSetFont(TkGate.D,TkGate.instGC,TkGate.stextbXF[TkGate.circuit->zoom_factor]->fid);
156   else
157     XSetFont(TkGate.D,TkGate.instGC,TkGate.stextXF[TkGate.circuit->zoom_factor]->fid);
158 
159   sprintf(b,"f=%d ",g->u.clock.omega);
160   x = RelPosDrawString(TkGate.painterW,TkGate.stextXF[TkGate.circuit->zoom_factor],TkGate.instGC,x,y,b,AtLeft);
161 
162   sprintf(b,"p=%d ",g->u.clock.phi);
163   x = RelPosDrawString(TkGate.painterW,TkGate.stextXF[TkGate.circuit->zoom_factor],TkGate.instGC,x,y,b,AtLeft);
164 
165   sprintf(b,"dw=%d ",g->u.clock.duty);
166   x = RelPosDrawString(TkGate.painterW,TkGate.stextXF[TkGate.circuit->zoom_factor],TkGate.instGC,x,y,b,AtLeft);
167 }
168 
Clock_Make(EditState ** es,GModuleDef * env,int GType,int x,int y,int r,const char * Name,int noWire,const char ** options,int nOptions)169 GCElement *Clock_Make(EditState **es,GModuleDef *env,int GType,
170 		      int x,int y,int r,const char *Name,int noWire,const char **options,int nOptions)
171 {
172   GCElement *g;
173   const char *LPW,*LPhi,*LDW;
174 
175   if (!(g = Generic_Make(es,env,GType,x,y,r,Name,noWire,options,nOptions)))
176     return NULL;
177 
178   LPW  = seekOption("-pw",options,nOptions);
179   LPhi = seekOption("-phi",options,nOptions);
180   LDW  = seekOption("-dw",options,nOptions);
181 
182   if (!LPW || sscanf(LPW,"%hd",&g->u.clock.omega) != 1)
183     g->u.clock.omega = CLOCK_OMEGA;
184 
185   if (!LPhi || sscanf(LPhi,"%hd",&g->u.clock.phi) != 1)
186     g->u.clock.phi = CLOCK_PHI;
187 
188   if (!LDW || sscanf(LDW,"%hd",&g->u.clock.duty) != 1)
189     g->u.clock.duty = CLOCK_DUTY;
190 
191   return g;
192 }
193 
194 
Clock_Draw(GCElement * g,int md)195 void Clock_Draw(GCElement *g,int md)
196 {
197   Generic_Draw(g,md);
198   gate_drawclockparams(g);
199 }
200 
Clock_Copy(GModuleDef * M,GCElement * g,int x,int y,unsigned flags)201 GCElement *Clock_Copy(GModuleDef *M,GCElement *g,int x,int y,unsigned flags)
202 {
203   GCElement *ng;
204 
205   ng = Generic_Copy(M,g,x,y,flags);
206 
207   ng->u.clock.omega = g->u.clock.omega;
208   ng->u.clock.phi = g->u.clock.phi;
209   ng->u.clock.duty = g->u.clock.duty;
210 
211   return ng;
212 }
213 
Clock_PSWrite(GPrint * P,GModLayout * L,GCElement * g)214 void Clock_PSWrite(GPrint *P,GModLayout *L,GCElement *g)
215 {
216   Generic_PSLabels(P,g);
217 
218   fprintf(P->p_f,"%d %d %d %d %d %d %s\n",
219 	  g->u.clock.duty,g->u.clock.phi,g->u.clock.omega,
220 	  g->xpos,g->ypos,-g->orient*90,g->typeinfo->psprint);
221 }
222 
Clock_EditProps(GCElement * g,int isLoadDialog)223 int Clock_EditProps(GCElement *g,int isLoadDialog)
224 {
225   Tcl_Interp *tcl = TkGate.tcl;
226 
227   Generic_EditProps(g,isLoadDialog);
228   if (isLoadDialog) {
229     DoTcl("set ::ecpOmega %d",g->u.clock.omega);
230     DoTcl("set ::ecpPhi %d",g->u.clock.phi);
231     DoTcl("set ::ecpDuty %d",g->u.clock.duty);
232   } else {
233     const char *p;
234     if ((p = Tcl_GetVar(tcl,"ecpOmega",TCL_GLOBAL_ONLY)))
235       sscanf(p,"%hd",&g->u.clock.omega);
236     if ((p = Tcl_GetVar(tcl,"ecpPhi",TCL_GLOBAL_ONLY)))
237       sscanf(p,"%hd",&g->u.clock.phi);
238     if ((p = Tcl_GetVar(tcl,"ecpDuty",TCL_GLOBAL_ONLY)))
239       sscanf(p,"%hd",&g->u.clock.duty);
240   }
241 
242   return 0;
243 }
244 
Clock_VerSave(FILE * f,GCElement * g)245 void Clock_VerSave(FILE *f,GCElement *g)
246 {
247   VerilogBasicGateCall(f,g);
248   VerilogBasicGateParmList(f,g);
249   VerilogBasicGateComment(f,g,1);
250   fprintf(f," /omega:%d /phi:%d /duty:%d",g->u.clock.omega,g->u.clock.phi,g->u.clock.duty);
251   fprintf(f,"\n");
252 }
253 
Clock_SetProp(GCElement * g,const char * prop,const void * value)254 void Clock_SetProp(GCElement *g,const char *prop,const void *value)
255 {
256   if (strcmp(prop,"/omega") == 0) {
257     int n = *((int*)value);
258     g->u.clock.omega = n;
259   } else if (strcmp(prop,"/phi") == 0) {
260     int n = *((int*)value);
261     g->u.clock.phi = n;
262   } else if (strcmp(prop,"/duty") == 0) {
263     int n = *((int*)value);
264     g->u.clock.duty = n;
265   }
266 }
267 
Clock_WriteCellDef(FILE * f,GCellSpec * gcs)268 static void Clock_WriteCellDef(FILE *f,GCellSpec *gcs)
269 {
270   const char *invSpec = gcs->gc_invSpec;
271   int period = gcs->gc_parms[0];
272   int shift  = gcs->gc_parms[1]*period/100;
273   int duty   = gcs->gc_parms[2];
274   int on_time, off_time;
275   /** @TODO to remove */
276   /*
277   int on_value = 1;
278   */
279   int start_value;
280   int phase_wait;
281   PrimParm primParm;
282 
283   if (period < 2) period = 2;
284   if (duty <= 0 || duty >= 100) duty = 50;
285   if (shift < 0) shift = 0;
286   off_time = period*duty/100;
287   on_time = period - off_time;
288   shift %= period;
289   if (on_time <= 0) {
290     on_time = 1;
291     off_time--;
292   }
293   if (off_time <= 0) {
294     off_time = 1;
295     on_time--;
296   }
297 
298   if (shift < off_time) {
299     start_value = 0;
300     phase_wait = off_time-shift;
301   } else {
302     start_value = 1;
303     phase_wait = period-shift;
304   }
305 
306 
307   PrimParm_init(&primParm);
308   PrimParm_intSet(&primParm,"INITIAL",start_value);
309   PrimParm_intSet(&primParm,"PHASE",phase_wait);
310   PrimParm_intSet(&primParm,"OFF_TIME",off_time);
311   PrimParm_intSet(&primParm,"ON_TIME",on_time);
312   PrimParm_invSet(&primParm,"invZ",(*invSpec == 'N'));
313   Primitive_write(f,"clock",gcs,&primParm);
314 }
315 
init_clock()316 void init_clock()
317 {
318   Pixmap P;
319 
320   P = Pixmap_registerFromFile("clock","clock.b");
321   gateinfo_iconInit(&gate_clock_info,P,clock_iconDims,clock_iconBoldOffset);
322   RegisterGate(&gate_clock_info);
323 }
324