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 Feb  2 13:45:47 2009
19 ****************************************************************************/
20 #include "thyme.h"
21 
22 #ifndef DEBUG
23 #define DEBUG 0
24 #endif
25 
26 /*****************************************************************************
27  *
28  * Create a new CodeBlock
29  *
30  * Returns:		Newly created and initialized CodeBlock.
31  *
32  *****************************************************************************/
new_CodeBlock(ModuleInst * mi)33 CodeBlock *new_CodeBlock(ModuleInst *mi)
34 {
35   CodeBlock *cb = (CodeBlock *) malloc(sizeof(CodeBlock));
36   CodeBlock_init(cb,mi);
37   return cb;
38 }
39 
40 /*****************************************************************************
41  *
42  * Delete a CodeBlock
43  *
44  * Parameters:
45  *     cb		CodeBlock to be deleted.
46  *
47  *****************************************************************************/
delete_CodeBlock(CodeBlock * cb)48 void delete_CodeBlock(CodeBlock *cb)
49 {
50   CodeBlock_uninit(cb);
51   free(cb);
52 }
53 
54 /*****************************************************************************
55  *
56  * Initialize a CodeBlock
57  *
58  * Parameters:
59  *     cb		CodeBlock to be initialized.
60  *
61  *****************************************************************************/
CodeBlock_init(CodeBlock * cb,ModuleInst * mi)62 void CodeBlock_init(CodeBlock *cb,ModuleInst *mi)
63 {
64   cb->cb_length =  0;
65   cb->cb_nalloced = BCODE_BLOCKSIZE;
66   cb->cb_module = mi;
67   cb->cb_instructions = (ByteCode*) malloc(sizeof(ByteCode)*BCODE_BLOCKSIZE);
68 }
69 
70 /*****************************************************************************
71  *
72  * Resize a codeblock to use the minimum number of bytes.
73  *
74  *****************************************************************************/
CodeBlock_close(CodeBlock * cb)75 void CodeBlock_close(CodeBlock *cb)
76 {
77   ByteCode *oldBC = cb->cb_instructions;
78 
79   cb->cb_nalloced = cb->cb_length;
80   cb->cb_instructions = (ByteCode*) malloc(sizeof(ByteCode)*cb->cb_nalloced);
81   memcpy(cb->cb_instructions, oldBC, sizeof(ByteCode)*cb->cb_nalloced);
82   free(oldBC);
83 }
84 
85 /*****************************************************************************
86  *
87  * Uninitialize a CodeBlock
88  *
89  * Parameters:
90  *     cb		CodeBlock to be uninitialized.
91  *
92  *****************************************************************************/
CodeBlock_uninit(CodeBlock * cb)93 void CodeBlock_uninit(CodeBlock *cb)
94 {
95   free(cb->cb_instructions);
96 }
97 
98 /*****************************************************************************
99  *
100  * Allocate and return the next empty ByteCode in a CodeBlock
101  *
102  * Paramaters:
103  *     cb		CodeBlock to use.
104  *
105  * Returns:		Next unused ByteCode in cb.
106  *
107  *****************************************************************************/
CodeBlock_nextEmpty(CodeBlock * cb)108 ByteCode *CodeBlock_nextEmpty(CodeBlock *cb)
109 {
110   if (cb->cb_length >= cb->cb_nalloced) {
111     cb->cb_nalloced += BCODE_BLOCKSIZE;
112     cb->cb_instructions = (ByteCode*) realloc(cb->cb_instructions,sizeof(ByteCode)*cb->cb_nalloced);
113   }
114 
115   return cb->cb_instructions + cb->cb_length++;
116 }
117 
CodeBlock_copy(CodeBlock * dst,unsigned dpos,CodeBlock * src,unsigned start,unsigned stop)118 void CodeBlock_copy(CodeBlock *dst,unsigned dpos,CodeBlock *src,unsigned start,unsigned stop)
119 {
120   if (stop >= src->cb_length)
121     stop = src->cb_length -1;
122   unsigned copySize = (stop-start+1);
123   unsigned reqLen = dpos + copySize;		/* Required length */
124 
125   if (reqLen >= dst->cb_nalloced) {
126     dst->cb_nalloced = reqLen;
127     dst->cb_instructions = (ByteCode*) realloc(dst->cb_instructions,sizeof(ByteCode)*dst->cb_nalloced);
128   }
129 
130   memcpy(CodeBlock_get(dst,dpos),CodeBlock_get(src,start),sizeof(ByteCode)*copySize);
131 #if 0
132   {
133     int i;
134     unsigned *ptr = (unsigned*) CodeBlock_get(dst,dpos);
135     int n = sizeof(ByteCode)*(stop-start+1)/sizeof(unsigned);
136 
137     printf("copy %d <- %d..%d  n=%d\n",dpos,start,stop,n);
138     printf("  dst:");
139     for (i = 0;i <= n;i++) {
140       printf("%08x",ptr[i]);
141     }
142     printf("\n");
143 
144     ptr = (unsigned*) CodeBlock_get(src,start);
145     printf("  src:");
146     for (i = 0;i <= n;i++) {
147       printf("%08x",ptr[i]);
148     }
149     printf("\n");
150   }
151 #endif
152 }
153 
154 
155 
156 /*****************************************************************************
157  *
158  * BCEnd initialization function
159  *
160  * Parameters:
161  *     bc		ByteCode object to initialize
162  *
163  *****************************************************************************/
BCEnd_init(ByteCode * bc)164 void BCEnd_init(ByteCode *bc)
165 {
166   bc->bc_func = (BCfunc*) BCEnd_exec;
167 }
168 
169 
170 /*****************************************************************************
171  *
172  * Execute BCEnd instruction
173  *
174  * Parameters:
175  *     bc		ByteCode object to execute
176  *     t		Thread that is executing instruction
177  *
178  *****************************************************************************/
BCEnd_exec(BCEnd * bc,VGThread * t)179 void BCEnd_exec(BCEnd *bc,VGThread *t)
180 {
181 #if DEBUG
182   vgio_echo("%p: BCEnd\n",t);
183 #endif
184   VGThread_kill(t);
185   if (t->t_parent)
186     VGThread_childEndNotify(t->t_parent);
187 }
188 
189 /*****************************************************************************
190  *
191  * BCNoop initialization function
192  *
193  * Parameters:
194  *     bc		ByteCode object to initialize as an BCNoop
195  *
196  *****************************************************************************/
BCNoop_init(ByteCode * bc)197 void BCNoop_init(ByteCode *bc)
198 {
199   bc->bc_func = (BCfunc*) BCNoop_exec;
200 }
201 
202 /*****************************************************************************
203  *
204  * Execute BCNoop instruction
205  *
206  * Parameters:
207  *     bc		ByteCode object to execute
208  *     t		Thread that is executing instruction
209  *
210  *****************************************************************************/
BCNoop_exec(BCNoop * bc,VGThread * t)211 void BCNoop_exec(BCNoop *bc,VGThread *t)
212 {
213 #if DEBUG
214   vgio_echo("%p: BCNoop\n",t);
215 #endif
216   t->t_pc++;
217 }
218 
219 /*****************************************************************************
220  *
221  * BCOpr initialization function
222  *
223  * Parameters:
224  *     bc		ByteCode object to initialize
225  *     func		Value function to execute
226  *     r		Destination Value
227  *     a,b,c		Source Value objects
228  *
229  *****************************************************************************/
BCOpr_init(ByteCode * bc,valueop_f * func,Value * r,Value * a,Value * b,Value * c)230 void BCOpr_init(ByteCode *bc,valueop_f *func,Value*r,Value*a,Value*b,Value*c)
231 {
232   if (!func)
233     abort();
234 
235   bc->bc_func = (BCfunc*) BCOpr_exec;
236   bc->bc_opr.o_op =  func;
237   bc->bc_opr.o_dest = r;
238   bc->bc_opr.o_opr[0] = a;
239   bc->bc_opr.o_opr[1] = b;
240   bc->bc_opr.o_opr[2] = c;
241 }
242 
243 /*****************************************************************************
244  *
245  * Execute BCOpr instruction
246  *
247  * Parameters:
248  *     bc		ByteCode object to execute
249  *     t		Thread that is executing instruction
250  *
251  *****************************************************************************/
BCOpr_exec(BCOpr * bc,VGThread * t)252 void BCOpr_exec(BCOpr *bc,VGThread *t)
253 {
254   (*bc->o_op)(bc->o_dest,bc->o_opr[0],bc->o_opr[1],bc->o_opr[2]);
255   t->t_pc++;
256 #if DEBUG
257   {
258     OpDesc *od = OpDesc_findFunc(bc->o_op);
259     const char *op = "[?]\0[?]";
260 
261     if (od) op = od->od_text;
262 
263     vgio_echo("%p: BCOpr: ",t);
264     Value_print(bc->o_dest,stdout);
265     vgio_echo(" = ");
266     if (bc->o_opr[0]) Value_print(bc->o_opr[0],stdout);
267     if (bc->o_opr[1]) {
268       vgio_echo(" %s ",op);
269       Value_print(bc->o_opr[1],stdout);
270     }
271     if (bc->o_opr[2]) {
272       op = strend((char*)op) + 1;
273       vgio_echo(" %s ",op);
274       Value_print(bc->o_opr[2],stdout);
275     }
276 
277 
278     vgio_echo("\n");
279   }
280 #endif
281 }
282 
283 /*****************************************************************************
284  *
285  * BCGoto initialization function
286  *
287  * Parameters:
288  *     bc		ByteCode object to initialize
289  *     cond		Condition value (or null for unconditional branch)
290  *     neg		If non-zero, branch condition is revered
291  *     cb		CodeBlock in which destination is contained
292  *     offset		Offset into CodeBlock to branch to.
293  *
294  *****************************************************************************/
BCGoto_init(ByteCode * bc,Value * cond,int neg,CodeBlock * cb,unsigned offset)295 void BCGoto_init(ByteCode *bc, Value *cond,int neg,CodeBlock *cb,unsigned offset)
296 {
297   BCGoto *g = (BCGoto*)bc;
298 
299   g->g_func = (BCfunc*) BCGoto_exec;
300   g->g_cond = cond;
301   g->g_block = cb;
302   g->g_offset = offset;
303   g->g_neg = neg;
304 }
305 
306 /*****************************************************************************
307  *
308  * Execute BCGoto instruction
309  *
310  * Parameters:
311  *     bc		ByteCode object to execute
312  *     t		Thread that is executing instruction
313  *
314  *****************************************************************************/
BCGoto_exec(BCGoto * g,VGThread * t)315 void BCGoto_exec(BCGoto *g,VGThread *t)
316 {
317   int doskip = (g->g_cond && (Value_isZero(g->g_cond)||!Value_isLogic(g->g_cond)));
318 
319   if (g->g_neg) doskip = !doskip;
320   if (doskip) {
321 #if DEBUG
322     vgio_echo("%p: BCGoto: nojump\n",t);
323 #endif
324     t->t_pc++;
325   } else {
326 #if DEBUG
327     vgio_echo("%p: BCGoto: jump %p:%x\n",t,g->g_block,g->g_offset);
328 #endif
329     t->t_pc = CodeBlock_first(g->g_block) + g->g_offset;
330   }
331 }
332 
333 /*****************************************************************************
334  *
335  * BCTask initialization function
336  *
337  * Parameters:
338  *     bc		ByteCode object to initialize
339  *     func		System task function pointer
340  *     context		Optional task context used by delayed execution tasks.
341  *     numArgs		Number of arguments
342  *     args		Array of values
343  *
344  *****************************************************************************/
BCTask_init(ByteCode * bc,systask_f * func,TaskContext * context,Value * rval,int numArgs,void ** args)345 void BCTask_init(ByteCode *bc,systask_f *func,TaskContext *context,Value *rval,int numArgs,void **args)
346 {
347   BCTask *t = (BCTask*)bc;
348 
349   t->t_func = (BCfunc*) BCTask_exec;
350   t->t_context = context;
351   t->t_task = func;
352   t->t_rvalue = rval;
353   t->t_numArgs = numArgs;
354   t->t_args = args;
355 
356 }
357 
358 /*****************************************************************************
359  *
360  * Execute BCTask instruction
361  *
362  * Parameters:
363  *     bc		ByteCode object to execute
364  *     t		Thread that is executing instruction
365  *
366  *****************************************************************************/
BCTask_exec(BCTask * t,VGThread * th)367 void BCTask_exec(BCTask *t,VGThread *th)
368 {
369 #if DEBUG
370   vgio_echo("%p: BCTask(%s) in %s\n",t,SysTask_findName(t->t_task),th->t_modCtx->mc_path);
371 #endif
372   (*t->t_task)(th,t->t_rvalue,t->t_numArgs,t->t_args,t->t_context);
373   th->t_pc++;
374 }
375 
376 /*****************************************************************************
377  *
378  * BCDelay initialization function
379  *
380  * Parameters:
381  *     bc		ByteCode object to initialize
382  *     t		Amount of delay
383  *
384  *****************************************************************************/
BCDelay_init(ByteCode * bc,deltatime_t t)385 void BCDelay_init(ByteCode *bc,deltatime_t t)
386 {
387   BCDelay *d = (BCDelay*)bc;
388 
389   d->d_func = (BCfunc*) BCDelay_exec;
390   d->d_delay = t;
391 }
392 
393 /*****************************************************************************
394  *
395  * Execute BCDelay instruction
396  *
397  * Parameters:
398  *     bc		ByteCode object to execute
399  *     t		Thread that is executing instruction
400  *
401  *****************************************************************************/
BCDelay_exec(BCDelay * d,VGThread * t)402 void BCDelay_exec(BCDelay *d,VGThread *t)
403 {
404   if (d->d_delay == 0)
405     VGThread_delayToEnd(t);
406   else
407     VGThread_delay(t,d->d_delay);
408 #if DEBUG
409   vgio_echo("%p: BCDelay %d\n",t,d->d_delay);
410 #endif
411   t->t_pc++;
412 }
413 
414 /*****************************************************************************
415  *
416  * BCTrigger initialization function
417  *
418  * Parameters:
419  *     bct		ByteCode object to initialize
420  *     t		Triggering event
421  *
422  *****************************************************************************/
BCTrigger_init(ByteCode * bc,Trigger * t)423 void BCTrigger_init(ByteCode *bc,Trigger *t)
424 {
425   BCTrigger *bct = (BCTrigger*)bc;
426 
427   bct->t_func = (BCfunc*) BCTrigger_exec;
428   bct->t_trigger = t;
429 }
430 
431 /*****************************************************************************
432  *
433  * Execute BCTrigger instruction
434  *
435  * Parameters:
436  *     bc		ByteCode object to execute
437  *     t		Thread that is executing instruction
438  *
439  *****************************************************************************/
BCTrigger_exec(BCTrigger * bct,VGThread * t)440 void BCTrigger_exec(BCTrigger *bct,VGThread *t)
441 {
442 #if DEBUG
443   char buf[STRMAX],*p;
444   ListElem *le;
445 
446   p = buf;
447   for (le = List_first(bct->t_trigger->t_posedges);le;le = List_next(bct->t_trigger->t_posedges,le)) {
448     Net *n = ListElem_obj(le);
449     p += sprintf(p," %s",Net_getName(n));
450   }
451   vgio_echo("%p: BCTrigger on %s\n",t,buf);
452 #endif
453   VGThread_eventWait(t,bct->t_trigger);
454   t->t_pc++;
455 }
456 
457 /*****************************************************************************
458  *
459  * BCLock initialization function
460  *
461  * Parameters:
462  *     bct		ByteCode object to initialize
463  *     t		Triggering event
464  *     value		Semephore variable
465  *
466  *****************************************************************************/
BCLock_init(ByteCode * bc,Trigger * t,Value * value)467 void BCLock_init(ByteCode *bc,Trigger *t, Value *value)
468 {
469   BCLock *bcl = (BCLock*)bc;
470 
471   bcl->l_func = (BCfunc*) BCLock_exec;
472   bcl->l_trigger = t;
473   bcl->l_value = value;
474 }
475 
476 /*****************************************************************************
477  *
478  * Execute BCLock instruction
479  *
480  * Parameters:
481  *     bc		ByteCode object to execute
482  *     t		Thread that is executing instruction
483  *
484  * If the semephore variable is zero, we set it to one and advance the PC.  Otherwise
485  * we wait for a change in the semephore value and reexecute ourself.
486  *
487  *****************************************************************************/
BCLock_exec(BCLock * bcl,VGThread * t)488 void BCLock_exec(BCLock *bcl,VGThread *t)
489 {
490 #if DEBUG
491   char buf[STRMAX],*p;
492   ListElem *le;
493 
494   p = buf;
495   for (le = List_first(bcl->l_trigger->t_posedges);le;le = List_next(bct->t_trigger->t_posedges,le)) {
496     Net *n = ListElem_obj(le);
497     p += sprintf(p," %s",Net_getName(n));
498   }
499   vgio_echo("%p: BCLock on %s\n",t,buf);
500 #endif
501 
502   if (Value_isZero(bcl->l_value)) {
503     Value_one(bcl->l_value);
504     t->t_pc++;
505   } else
506     VGThread_eventWait(t,bcl->l_trigger);
507 }
508 
509 /*****************************************************************************
510  *
511  * BCCopy initialization function
512  *
513  * Parameters:
514  *     bc		ByteCode object to initialize
515  *     dst		Destination Value for copy
516  *     src		Source Value for copy
517  *
518  *****************************************************************************/
BCCopy_init(ByteCode * bc,Value * dst,Value * src)519 void BCCopy_init(ByteCode *bc, Value*dst, Value*src)
520 {
521   BCCopy *c = (BCCopy*)bc;
522 
523   c->c_func = (BCfunc*) BCCopy_exec;
524   c->c_dst = dst;
525   c->c_src = src;
526 }
527 
528 /*****************************************************************************
529  *
530  * Execute BCCopy instruction
531  *
532  * Parameters:
533  *     bc		ByteCode object to execute
534  *     t		Thread that is executing instruction
535  *
536  *****************************************************************************/
BCCopy_exec(BCCopy * c,VGThread * t)537 void BCCopy_exec(BCCopy *c, VGThread *t)
538 {
539   int nd = Value_nbits(c->c_dst);
540   int ns = Value_nbits(c->c_src);
541 
542   if (nd == ns)
543     Value_copy(c->c_dst,c->c_src);
544   else if (nd < ns)
545     Value_copyRange(c->c_dst,0,c->c_src,ns-1,0);
546   else {
547     Value_zero(c->c_dst);
548     Value_copyRange(c->c_dst,0,c->c_src,ns-1,0);
549   }
550 
551 #if DEBUG
552   vgio_echo("%p: BCCopy: ",t);
553   Value_print(c->c_dst,stdout);
554   vgio_echo(" = ");
555   Value_print(c->c_src,stdout);
556   vgio_echo("\n");
557 #endif
558 
559   t->t_pc++;
560 }
561 
562 /*****************************************************************************
563  *
564  * BCCopyRange initialization function
565  *
566  * Parameters:
567  *     bc		ByteCode object to initialize
568  *     dst		Destination Value for copy
569  *     dLsb		LSB in destination
570  *     src		Source Value for copy
571  *     sLSB		LSB in source
572  *     width		Bits to copy
573  *
574  *****************************************************************************/
BCCopyRange_init(ByteCode * bc,Value * dst,unsigned dLsb,Value * src,Value * sLsb,unsigned width)575 void BCCopyRange_init(ByteCode *bc, Value *dst, unsigned dLsb,Value *src,Value *sLsb, unsigned width)
576 {
577   BCCopyRange *r = (BCCopyRange*)bc;
578 
579   r->r_func = (BCfunc*) BCCopyRange_exec;
580   r->r_dst = dst;
581   r->r_dLsb = dLsb;
582   r->r_src = src;
583   r->r_sLsb = sLsb;
584   r->r_width = width;
585 }
586 
BCCopyRange_exec(BCCopyRange * r,VGThread * t)587 void BCCopyRange_exec(BCCopyRange *r, VGThread *t)
588 {
589   unsigned sLsb;
590 
591   if (!r->r_sLsb)
592     sLsb = 0;
593   else if (Value_toInt(r->r_sLsb,&sLsb) < 0) {
594     /*
595      * Source bit is unknown.
596      */
597     Value *x = new_Value(r->r_width);
598     Value_unknown(x);
599     Value_copyRange(r->r_dst, r->r_dLsb, x,r->r_width-1,0);
600     delete_Value(x);
601     t->t_pc++;
602 
603 #if DEBUG
604   vgio_echo("%p: BCCopyRange(",t);
605   Value_print(r->r_dst, stdout);
606   vgio_echo(", %d, ",r->r_dLsb);
607   Value_print(r->r_src, stdout);
608   vgio_echo(", [? +: %d])\n",r->r_width-1);
609 #endif
610 
611     return;
612   }
613 
614   /*
615    * Normal case
616    */
617   Value_copyRange(r->r_dst, r->r_dLsb, r->r_src,sLsb+r->r_width-1,sLsb);
618   t->t_pc++;
619 
620 #if DEBUG
621   vgio_echo("%p: BCCopyRange(",t);
622   Value_print(r->r_dst, stdout);
623   vgio_echo(", %d, ",r->r_dLsb);
624   Value_print(r->r_src, stdout);
625   vgio_echo(", [%d:%d])\n",sLsb+r->r_width-1,sLsb);
626 #endif
627 }
628 
629 /*****************************************************************************
630  *
631  * Initialize a BCMemFetch instruction
632  *
633  *****************************************************************************/
BCMemFetch_init(ByteCode * bc,Net * n,Value * addr,Value * data)634 void BCMemFetch_init(ByteCode *bc,Net *n, Value *addr, Value *data)
635 {
636   BCMemFetch *m = (BCMemFetch*)bc;
637 
638   m->m_func = (BCfunc*) BCMemFetch_exec;
639   m->m_net = n;
640   m->m_addr = addr;
641   m->m_data = data;
642 }
643 
644 /*****************************************************************************
645  *
646  * Executete a BCMemFetch instruction
647  *
648  *****************************************************************************/
BCMemFetch_exec(BCMemFetch * bmo,VGThread * t)649 void BCMemFetch_exec(BCMemFetch *bmo,VGThread *t)
650 {
651   Memory *m  = &bmo->m_net->n_data.memory;
652   unsigned addr;
653 
654   if (Value_toInt(bmo->m_addr,&addr) < 0) {
655     Value_unknown(bmo->m_data);
656 #if DEBUG
657   vgio_echo("%p: BCMemFetch: %s[?]=?",t,Net_getName(bmo->m_net));
658 #endif
659   } else {
660     Memory_setFlags(m, MF_INITIALIZED);
661     Memory_get(m, addr, bmo->m_data);
662     Memory_accessNotify(m, addr, 0);
663 #if DEBUG
664     vgio_echo("%p: BCMemFetch: %s[%x]=",t,Net_getName(bmo->m_net), addr);
665     Value_print(bmo->m_data, stdout);
666     vgio_printf("\n");
667 #endif
668   }
669 
670   t->t_pc++;
671 }
672 
673 /*****************************************************************************
674  *
675  * Initialize a BCNbMemPut instruction
676  *
677  *****************************************************************************/
BCNbMemPutD_init(ByteCode * bc,Net * n,Value * addr,Value * netLsb,Value * data,unsigned valLsb,unsigned width,deltatime_t delay)678 void BCNbMemPutD_init(ByteCode *bc,Net *n, Value *addr, Value *netLsb, Value *data,
679 		     unsigned valLsb,unsigned width,deltatime_t delay)
680 {
681   BCNbMemPutD *m = (BCNbMemPutD*)bc;
682 
683   m->m_func = (BCfunc*) BCNbMemPutD_exec;
684   m->m_net = n;
685   m->m_addr = addr;
686   m->m_netLsb = netLsb;
687   m->m_data = data;
688   m->m_valLsb = valLsb;
689   m->m_width = width;
690   m->m_delay = delay;
691 }
692 
693 /*****************************************************************************
694  *
695  * Executete a BCNbMemPut instruction
696  *
697  *****************************************************************************/
BCNbMemPutD_exec(BCNbMemPutD * mpd,VGThread * thread)698 void BCNbMemPutD_exec(BCNbMemPutD *mpd,VGThread *thread)
699 {
700   unsigned netLsb = 0;
701   EvQueue *Q = VGThread_getQueue(thread);
702   Event *e;
703 
704 #if DEBUG
705   vgio_echo("%p: BCNbMemPutD(%p) #%d\n",thread,mpd,mpd->m_delay);
706 #endif
707 
708   if (mpd->m_netLsb) {
709     if (Value_toInt(mpd->m_netLsb,&netLsb) < 0) {
710       /*
711        * An LSB was specified but it contains unknown bits
712        */
713       Value *xs = new_Value(Value_nbits(mpd->m_data));
714       Value_unknown(xs);
715       e = new_EvMem(mpd->m_net, mpd->m_addr, netLsb, xs, mpd->m_valLsb+mpd->m_width-1,mpd->m_valLsb);
716       EvQueue_enqueueAfter(Q,e,mpd->m_delay);
717       delete_Value(xs);
718       thread->t_pc++;
719       return;
720     }
721   } else
722     netLsb = 0;
723 
724   e = new_EvMem(mpd->m_net, mpd->m_addr, netLsb, mpd->m_data, mpd->m_valLsb+mpd->m_width-1,mpd->m_valLsb);
725   EvQueue_enqueueAfter(Q,e,mpd->m_delay);
726   thread->t_pc++;
727 }
728 
729 /*****************************************************************************
730  *
731  * Initialize a BCNbMemPut instruction
732  *
733  *****************************************************************************/
BCNbMemPutE_init(ByteCode * bc,Net * n,Value * addr,Value * netLsb,Value * data,unsigned valLsb,unsigned width,Trigger * trigger)734 void BCNbMemPutE_init(ByteCode *bc,Net *n, Value *addr, Value *netLsb, Value *data,
735 		     unsigned valLsb,unsigned width,Trigger *trigger)
736 {
737   BCNbMemPutE *m = (BCNbMemPutE*)bc;
738 
739   m->m_func = (BCfunc*) BCNbMemPutE_exec;
740   m->m_net = n;
741   m->m_addr = addr;
742   m->m_netLsb = netLsb;
743   m->m_data = data;
744   m->m_valLsb = valLsb;
745   m->m_width = width;
746   m->m_trigger = trigger;
747 }
748 
749 /*****************************************************************************
750  *
751  * Executete a BCNbMemPut instruction
752  *
753  *****************************************************************************/
BCNbMemPutE_exec(BCNbMemPutE * mpe,VGThread * thread)754 void BCNbMemPutE_exec(BCNbMemPutE *mpe,VGThread *thread)
755 {
756   unsigned netLsb = 0;
757   /** @TODO to remove */
758   /* EvQueue *Q = VGThread_getQueue(thread); */
759   Event *e;
760 
761 #if DEBUG
762   vgio_echo("%p: BCNbMemPutE(%p)\n",thread,mpe);
763 #endif
764 
765   if (mpe->m_netLsb) {
766     if (Value_toInt(mpe->m_netLsb,&netLsb) < 0) {
767       /*
768        * An LSB was specified but it contains unknown bits
769        */
770       Value *xs = new_Value(Value_nbits(mpe->m_data));
771       Value_unknown(xs);
772       e = new_EvMem(mpe->m_net, mpe->m_addr, netLsb, xs, mpe->m_valLsb+mpe->m_width-1,mpe->m_valLsb);
773       Trigger_enqueue(mpe->m_trigger, e);
774       delete_Value(xs);
775       thread->t_pc++;
776       return;
777     }
778   } else
779     netLsb = 0;
780 
781   e = new_EvMem(mpe->m_net, mpe->m_addr, netLsb, mpe->m_data, mpe->m_valLsb+mpe->m_width-1,mpe->m_valLsb);
782   Trigger_enqueue(mpe->m_trigger, e);
783   thread->t_pc++;
784 }
785 
786 /*****************************************************************************
787  *
788  * Initialize a BCMemPut instruction
789  *
790  *****************************************************************************/
BCMemPut_init(ByteCode * bc,Net * n,Value * addr,Value * netLsb,Value * data,unsigned valLsb,unsigned width)791 void BCMemPut_init(ByteCode *bc,Net *n, Value *addr, Value *netLsb, Value *data,unsigned valLsb,unsigned width)
792 {
793   BCMemPut *m = (BCMemPut*)bc;
794 
795   m->m_func = (BCfunc*) BCMemPut_exec;
796   m->m_net = n;
797   m->m_addr = addr;
798   m->m_netLsb = netLsb;
799   m->m_data = data;
800   m->m_valLsb = valLsb;
801   m->m_width = width;
802 }
803 
804 /*****************************************************************************
805  *
806  * Executete a BCMemPut instruction
807  *
808  *****************************************************************************/
BCMemPut_exec(BCMemPut * bmo,VGThread * t)809 void BCMemPut_exec(BCMemPut *bmo,VGThread *t)
810 {
811   Memory *m  = &bmo->m_net->n_data.memory;
812   unsigned addr;
813   unsigned netLsb = 0;
814 
815   if (Value_toInt(bmo->m_addr,&addr) < 0) {
816 #if DEBUG
817     vgio_echo("%p: BCMemPut: %s[?]=?",t,Net_getName(bmo->m_net));
818 #endif
819     if ((Memory_getFlags(m) & MF_INITIALIZED))
820       errorRun(ERR_MEMADDR,Net_getName(bmo->m_net));
821     goto done;
822   } else {
823     Memory_setFlags(m, MF_INITIALIZED);
824     if (bmo->m_netLsb && Value_toInt(bmo->m_netLsb,&netLsb) < 0) {
825       errorRun(ERR_MEMBITS,Net_getName(bmo->m_net));
826       goto done;
827     } else if (Net_nbits(bmo->m_net) == bmo->m_width) {
828       Net_memSet(bmo->m_net, addr, bmo->m_data);
829     } else
830       Net_memSetRange(bmo->m_net, addr, netLsb, bmo->m_data, bmo->m_valLsb+bmo->m_width-1, bmo->m_valLsb);
831   }
832 
833 #if DEBUG
834   vgio_echo("%p: BCMemPut: %s[%x][%d:%d]=",t,Net_getName(bmo->m_net), addr,bmo->m_width+netLsb-1,netLsb);
835   Value_print(bmo->m_data, stdout);
836   vgio_printf("[%d:%d]\n",bmo->m_width+bmo->m_valLsb-1,bmo->m_valLsb);
837 #endif
838  done:
839   t->t_pc++;
840 }
841 
842 /*****************************************************************************
843  *
844  * BCRaise initialization function
845  *
846  * Parameters:
847  *     bc		ByteCode object to initialize
848  *     net		Destination Net for assignment
849  *
850  *****************************************************************************/
BCRaise_init(ByteCode * bc,Net * net)851 void BCRaise_init(ByteCode *bc, Net *net)
852 {
853   BCRaise *r = (BCRaise*)bc;
854 
855   r->r_func = (BCfunc*) BCRaise_exec;
856   r->r_net = net;
857 }
858 
859 /*****************************************************************************
860  *
861  * Execute BCRaise instruction
862  *
863  * Parameters:
864  *     bc		ByteCode object to execute
865  *     t		Thread that is executing instruction
866  *
867  *****************************************************************************/
BCRaise_exec(BCRaise * r,VGThread * t)868 void BCRaise_exec(BCRaise *r, VGThread *t)
869 {
870   Net_set(r->r_net, 0);
871 
872 #if DEBUG
873   vgio_echo("%p: BCRaise: %s\n",t,r->r_net->n_name);
874 #endif
875 
876   t->t_pc++;
877 }
878 
879 /*****************************************************************************
880  *
881  * BCAsgn initialization function
882  *
883  * Parameters:
884  *     bc		ByteCode object to initialize
885  *     net		Destination Net for assignment
886  *     netLsb		Least significant bit in assignment
887  *     value		Value to assign
888  *     valLsb		Least significant bit in value
889  *     width		Width of value to copy
890  *
891  *****************************************************************************/
BCAsgn_init(ByteCode * bc,Net * net,Value * netLsb,Value * value,unsigned valLsb,unsigned width)892 void BCAsgn_init(ByteCode *bc, Net *net, Value *netLsb, Value *value, unsigned valLsb, unsigned width)
893 {
894   BCAsgn *a = (BCAsgn*)bc;
895 
896   a->a_func = (BCfunc*) BCAsgn_exec;
897   a->a_net = net;
898   a->a_netLsb = netLsb;
899   a->a_value = value;
900   a->a_valLsb = valLsb;
901   a->a_width = width;
902 }
903 
904 /*****************************************************************************
905  *
906  * Execute BCAsgn instruction
907  *
908  * Parameters:
909  *     bc		ByteCode object to execute
910  *     t		Thread that is executing instruction
911  *
912  *****************************************************************************/
BCAsgn_exec(BCAsgn * a,VGThread * t)913 void BCAsgn_exec(BCAsgn *a, VGThread *t)
914 {
915   int nd = Net_nbits(a->a_net);
916   int ns = Value_nbits(a->a_value);
917   unsigned netLsb = 0;
918 
919   if (nd == a->a_width && ns == a->a_width) {
920     Net_set(a->a_net, a->a_value);
921   } else {
922 
923     /*
924      * If an lsb is specified but it is unknown, set the target net to unknown
925      * since we do not know where we are writing the value.
926      */
927     if (a->a_netLsb) {
928       if (Value_toInt(a->a_netLsb,&netLsb) < 0) {
929 	Net_makeUnknown(a->a_net);
930 	return;
931       }
932     } else
933       netLsb = 0;
934 
935     Net_setRange(a->a_net, netLsb,a->a_value,a->a_valLsb+a->a_width-1,a->a_valLsb);
936   }
937 
938 #if DEBUG
939   vgio_echo("%p: BCAsgn: %s[%d:%d] = ",t,a->a_net->n_name,netLsb+a->a_width-1,netLsb);
940   Value_print(a->a_value,stdout);
941   vgio_echo("[%d:%d]\n",a->a_valLsb+a->a_width-1,a->a_valLsb);
942 #endif
943 
944   t->t_pc++;
945 }
946 
947 /*****************************************************************************
948  *
949  * BCNbAsgnD initialization function
950  *
951  * Parameters:
952  *     bc		ByteCode object to initialize
953  *     net		Destination Net for assignment
954  *     netLsb		Least significant bit in assignment
955  *     value		Value to assign
956  *     valLsb		Least significant bit in value
957  *     width		Width of value to copy
958  *     delay		Delay after which to queue assignment.
959  *
960  *****************************************************************************/
BCNbAsgnD_init(ByteCode * bc,Net * net,Value * netLsb,Value * value,unsigned valLsb,unsigned width,deltatime_t delay)961 void BCNbAsgnD_init(ByteCode *bc, Net *net, Value *netLsb, Value *value,
962 		    unsigned valLsb, unsigned width,deltatime_t delay)
963 {
964   BCNbAsgnD *a = (BCNbAsgnD*)bc;
965 
966   a->a_func = (BCfunc*) BCNbAsgnD_exec;
967   a->a_net = net;
968   a->a_netLsb = netLsb;
969   a->a_value = value;
970   a->a_valLsb = valLsb;
971   a->a_width = width;
972   a->a_delay = delay;
973 }
974 
975 /*****************************************************************************
976  *
977  * Execute BCNbAsgnD instruction
978  *
979  * Parameters:
980  *     bc		ByteCode object to execute
981  *     t		Thread that is executing instruction
982  *
983  *****************************************************************************/
BCNbAsgnD_exec(BCNbAsgnD * a,VGThread * thread)984 void BCNbAsgnD_exec(BCNbAsgnD *a, VGThread *thread)
985 {
986   unsigned netLsb = 0;
987   EvQueue *Q = VGThread_getQueue(thread);
988   Event *e;
989 
990 #if DEBUG
991   vgio_echo("%p: BCNbAsgnD(%p) #%d\n",thread,a,a->a_delay);
992 #endif
993 
994   if (a->a_netLsb) {
995     if (Value_toInt(a->a_netLsb,&netLsb) < 0) {
996       /*
997        * An LSB was specified but it contains unknown bits
998        */
999       Value *xs = new_Value(Value_nbits(a->a_value));
1000       Value_unknown(xs);
1001       e = new_EvNet(a->a_net, netLsb, xs, a->a_valLsb+a->a_width-1,a->a_valLsb);
1002       EvQueue_enqueueAfter(Q,e,a->a_delay);
1003       delete_Value(xs);
1004       thread->t_pc++;
1005       return;
1006     }
1007   } else
1008     netLsb = 0;
1009 
1010   e = new_EvNet(a->a_net, netLsb, a->a_value, a->a_valLsb+a->a_width-1,a->a_valLsb);
1011   EvQueue_enqueueAfter(Q,e,a->a_delay);
1012   thread->t_pc++;
1013 }
1014 
1015 
1016 /*****************************************************************************
1017  *
1018  * BCNbAsgnE initialization function
1019  *
1020  * Parameters:
1021  *     bc		ByteCode object to initialize
1022  *     net		Destination Net for assignment
1023  *     netLsb		Least significant bit in assignment
1024  *     value		Value to assign
1025  *     valLsb		Least significant bit in value
1026  *     width		Width of value to copy
1027  *     trigger		Triggering event for assigment.
1028  *
1029  *****************************************************************************/
BCNbAsgnE_init(ByteCode * bc,Net * net,Value * netLsb,Value * value,unsigned valLsb,unsigned width,Trigger * trigger)1030 void BCNbAsgnE_init(ByteCode *bc, Net *net, Value *netLsb, Value *value, unsigned valLsb, unsigned width,Trigger *trigger)
1031 {
1032   BCNbAsgnE *a = (BCNbAsgnE*)bc;
1033 
1034   a->a_func = (BCfunc*) BCNbAsgnE_exec;
1035   a->a_net = net;
1036   a->a_netLsb = netLsb;
1037   a->a_value = value;
1038   a->a_valLsb = valLsb;
1039   a->a_width = width;
1040   a->a_trigger = trigger;
1041 }
1042 
1043 /*****************************************************************************
1044  *
1045  * Execute BCNbAsgnE instruction
1046  *
1047  * Parameters:
1048  *     bc		ByteCode object to execute
1049  *     t		Thread that is executing instruction
1050  *
1051  *****************************************************************************/
BCNbAsgnE_exec(BCNbAsgnE * a,VGThread * thread)1052 void BCNbAsgnE_exec(BCNbAsgnE *a, VGThread *thread)
1053 {
1054   unsigned netLsb = 0;
1055   Event *e;
1056 
1057 #if DEBUG
1058   vgio_echo("%p: BCNbAsgnE\n",thread);
1059 #endif
1060 
1061   if (a->a_netLsb) {
1062     if (Value_toInt(a->a_netLsb,&netLsb) < 0) {
1063       /*
1064        * An LSB was specified but it contains unknown bits
1065        */
1066       Value *xs = new_Value(Value_nbits(a->a_value));
1067       Value_unknown(xs);
1068       e = new_EvNet(a->a_net, netLsb, xs, a->a_valLsb+a->a_width-1,a->a_valLsb);
1069       Trigger_enqueue(a->a_trigger ,e);
1070       delete_Value(xs);
1071       thread->t_pc++;
1072       return;
1073     }
1074   } else
1075     netLsb = 0;
1076 
1077   e = new_EvNet(a->a_net, netLsb, a->a_value, a->a_valLsb+a->a_width-1,a->a_valLsb);
1078   Trigger_enqueue(a->a_trigger ,e);
1079   thread->t_pc++;
1080 }
1081 
1082 /*****************************************************************************
1083  *
1084  * BCWireAsgnD initialization function
1085  *
1086  * Parameters:
1087  *     bc		ByteCode object to initialize
1088  *     net		Destination Net for assignment
1089  *     netLsb		Least significant bit in assignment
1090  *     value		Value to assign
1091  *     valLsb		Least significant bit in value
1092  *     width		Width of value to copy
1093  *     delay		Delay after which to queue assignment.
1094  *
1095  *****************************************************************************/
BCWireAsgnD_init(ByteCode * bc,Net * net,int id,Value * netLsb,Value * value,unsigned valLsb,unsigned width,deltatime_t delay)1096 void BCWireAsgnD_init(ByteCode *bc, Net *net, int id, Value *netLsb, Value *value,
1097 		    unsigned valLsb, unsigned width,deltatime_t delay)
1098 {
1099   BCWireAsgnD *a = (BCWireAsgnD*)bc;
1100 
1101   a->a_func = (BCfunc*) BCWireAsgnD_exec;
1102   a->a_net = net;
1103   a->a_id = id;
1104   a->a_netLsb = netLsb;
1105   a->a_value = value;
1106   a->a_valLsb = valLsb;
1107   a->a_width = width;
1108   a->a_delay = delay;
1109 }
1110 
1111 /*****************************************************************************
1112  *
1113  * Execute BCWireAsgnD instruction
1114  *
1115  * Parameters:
1116  *     bc		ByteCode object to execute
1117  *     t		Thread that is executing instruction
1118  *
1119  *****************************************************************************/
BCWireAsgnD_exec(BCWireAsgnD * a,VGThread * thread)1120 void BCWireAsgnD_exec(BCWireAsgnD *a, VGThread *thread)
1121 {
1122   unsigned netLsb = 0;
1123   EvQueue *Q = VGThread_getQueue(thread);
1124   Event *e;
1125 
1126   if (a->a_netLsb) {
1127     if (Value_toInt(a->a_netLsb,&netLsb) < 0) {
1128       Value *xs = new_Value(Value_nbits(a->a_value));
1129       Value_unknown(xs);
1130       e = new_EvNet(a->a_net, netLsb, xs, a->a_valLsb+a->a_width-1,a->a_valLsb);
1131       EvQueue_enqueueAfter(Q,e,a->a_delay);
1132 
1133 #if DEBUG
1134       vgio_echo("%p: BCWireAsgnD: #%d %s[%d:%d] = ",thread,a->a_delay,Net_getName(a->a_net),a->a_valLsb+a->a_width-1);
1135       Value_print(xs,stdout);
1136       vgio_echo("\n");
1137 #endif
1138 
1139       delete_Value(xs);
1140       thread->t_pc++;
1141       return;
1142     }
1143   } else {
1144     netLsb = 0;
1145   }
1146 
1147   e = new_EvDriver(a->a_net, a->a_id, netLsb, a->a_value, a->a_valLsb+a->a_width-1,a->a_valLsb);
1148   EvQueue_enqueueAfter(Q,e,a->a_delay);
1149 
1150 #if DEBUG
1151   vgio_echo("%p: BCWireAsgnD: #%d %s = ",thread,a->a_delay,Net_getName(a->a_net));
1152   Value_print(a->a_value,stdout);
1153   vgio_echo("\n");
1154 #endif
1155 
1156   thread->t_pc++;
1157 }
1158 
1159 /*****************************************************************************
1160  *
1161  * Initialize a BCSpawn instruction.
1162  *
1163  *****************************************************************************/
BCSpawn_init(ByteCode * bc,CodeBlock * cb,unsigned offset)1164 void BCSpawn_init(ByteCode *bc,CodeBlock *cb,unsigned offset)
1165 {
1166   BCSpawn *s = (BCSpawn*)bc;
1167 
1168   s->s_func = (BCfunc*) BCSpawn_exec;
1169   s->s_block = cb;
1170   s->s_offset = offset;
1171 }
1172 
1173 /*****************************************************************************
1174  *
1175  * Execute a BCSpawn instruction.
1176  *
1177  *****************************************************************************/
BCSpawn_exec(BCSpawn * s,VGThread * thread)1178 void BCSpawn_exec(BCSpawn *s,VGThread *thread)
1179 {
1180   VGThread *child = VGThread_spawn(thread,s->s_block,s->s_offset);
1181   VGThread_start(child);
1182   VGThread_delay(child,0);
1183   thread->t_pc++;
1184 
1185 #if DEBUG
1186   vgio_echo("%p: BCSpawn(%u) -> %p\n",thread,s->s_offset,child);
1187 #endif
1188 }
1189 
1190 /*****************************************************************************
1191  *
1192  * Initialize a BCWait instruction.
1193  *
1194  *****************************************************************************/
BCWait_init(ByteCode * bc)1195 void BCWait_init(ByteCode *bc)
1196 {
1197   BCWait *w = (BCWait*)bc;
1198 
1199   w->w_func = (BCfunc*) BCWait_exec;
1200 }
1201 
1202 /*****************************************************************************
1203  *
1204  * Execute a BCWait instruction.
1205  *
1206  *****************************************************************************/
BCWait_exec(BCWait * w,VGThread * thread)1207 void BCWait_exec(BCWait *w,VGThread *thread)
1208 {
1209   VGThread_suspend(thread);
1210   thread->t_pc++;
1211 #if DEBUG
1212   vgio_echo("%p: BCWait()\n",thread);
1213 #endif
1214 }
1215 
1216 /*****************************************************************************
1217  *
1218  * Initialize a BCSubr instruction
1219  *
1220  *****************************************************************************/
BCSubr_init(ByteCode * bc,CodeBlock * block,unsigned offset)1221 void BCSubr_init(ByteCode *bc,CodeBlock *block,unsigned offset)
1222 {
1223   BCSubr *s = (BCSubr*)bc;
1224 
1225   s->s_func = (BCfunc*) BCSubr_exec;
1226   s->s_block = block;
1227   s->s_offset = offset;
1228 }
1229 
1230 /*****************************************************************************
1231  *
1232  * Execute a BCSubr instruction
1233  *
1234  *****************************************************************************/
BCSubr_exec(BCSubr * s,VGThread * t)1235 void BCSubr_exec(BCSubr *s,VGThread *t)
1236 {
1237 #if DEBUG
1238   vgio_echo("%p: BCSubr: jump %p:%x\n",t,s->s_block,s->s_offset);
1239 #endif
1240   t->t_callStack = new_VGFrame(t->t_pc+1, t->t_callStack);
1241   t->t_pc = CodeBlock_first(s->s_block) + s->s_offset;
1242 }
1243 
1244 /*****************************************************************************
1245  *
1246  * Initialize a BCReturn instruction
1247  *
1248  *****************************************************************************/
BCReturn_init(ByteCode * bc)1249 void BCReturn_init(ByteCode *bc)
1250 {
1251   BCReturn *r = (BCReturn*)bc;
1252 
1253   r->r_func = (BCfunc*) BCReturn_exec;
1254 }
1255 
1256 /*****************************************************************************
1257  *
1258  * Execute a BCReturn instruction
1259  *
1260  *****************************************************************************/
BCReturn_exec(BCReturn * r,VGThread * t)1261 void BCReturn_exec(BCReturn *r,VGThread *t)
1262 {
1263   VGFrame *vgf = t->t_callStack;
1264 
1265 #if DEBUG
1266   vgio_echo("%p: BCReturn\n",t);
1267 #endif
1268 
1269   if (!vgf) {
1270     errorRun(ERR_IE_RETURN);
1271 
1272     VGThread_kill(t);
1273     if (t->t_parent)
1274       VGThread_childEndNotify(t->t_parent);
1275     return;
1276   }
1277 
1278   t->t_callStack = vgf->f_next;
1279   t->t_pc = vgf->f_pc;
1280   delete_VGFrame(vgf);
1281 }
1282 
1283 /*****************************************************************************
1284  *
1285  * Initialize a BCDebugPrint instruction
1286  *
1287  *****************************************************************************/
BCDebugPrint_init(ByteCode * bc,char * msg,...)1288 void BCDebugPrint_init(ByteCode *bc,char *msg,...)
1289 {
1290   BCDebugPrint *dp = (BCDebugPrint*)bc;
1291   char buf[STRMAX];
1292   va_list ap;
1293 
1294   va_start(ap, msg);
1295   vsprintf(buf,msg,ap);
1296   va_end(ap);
1297 
1298   dp->dp_func = (BCfunc*) BCDebugPrint_exec;
1299   dp->dp_message = strdup(buf);
1300 
1301 }
1302 
1303 /*****************************************************************************
1304  *
1305  * Execute a BCDebugPrint instruction
1306  *
1307  *****************************************************************************/
BCDebugPrint_exec(BCDebugPrint * dp,VGThread * t)1308 void BCDebugPrint_exec(BCDebugPrint *dp,VGThread *t)
1309 {
1310 #if DEBUG
1311   vgio_echo("%p: BCDebugPrint()\n",t);
1312 #endif
1313   printf("%s",dp->dp_message);
1314   t->t_pc++;
1315 }
1316 
1317 
1318 
1319 /*****************************************************************************
1320  *
1321  * Create a new VGThread object.
1322  *
1323  * Parameters:
1324  *     cb		Codeblock in which to begin execution
1325  *     pc		Thread program counter
1326  *     modCtx		Module context in which thread was declared.
1327  *     mitem		Module item this thread manages if applicable
1328  *
1329  *****************************************************************************/
new_VGThread(CodeBlock * cb,unsigned pc,ModuleInst * modCtx,ModuleItem * mitem)1330 VGThread *new_VGThread(CodeBlock *cb,unsigned pc,ModuleInst *modCtx,ModuleItem *mitem)
1331 {
1332   VGThread *thread = (VGThread *) malloc(sizeof(VGThread));
1333 
1334   VGThread_init(thread,cb,pc,modCtx,mitem);
1335 
1336   return thread;
1337 }
1338 
1339 /*****************************************************************************
1340  *
1341  * Destroy a VGThread object.
1342  *
1343  * Parameters:
1344  *     thread		VGThread object to be destroyed.
1345  *
1346  *****************************************************************************/
delete_VGThread(VGThread * thread)1347 void delete_VGThread(VGThread *thread)
1348 {
1349   VGThread_uninit(thread);
1350   free(thread);
1351 }
1352 
1353 /*****************************************************************************
1354  *
1355  * Constructor for VGThread objects.
1356  *
1357  * Parameters:
1358  *     thread		Thread to be constructed.
1359  *     cb		Codeblock in which to begin execution
1360  *     pc		Thread program counter
1361  *     modCtx		Module context in which thread was declared.
1362  *     mitem		Module item this thread manages if applicable
1363  *
1364  *****************************************************************************/
VGThread_init(VGThread * thread,CodeBlock * cb,unsigned pc,ModuleInst * modCtx,ModuleItem * mitem)1365 void VGThread_init(VGThread *thread,CodeBlock *cb,unsigned pc, ModuleInst *modCtx,ModuleItem *mitem)
1366 {
1367   thread->t_pending = 0;
1368   thread->t_state = TS_ACTIVE;
1369   thread->t_isLive = 1;
1370   thread->t_wait = 0;
1371   thread->t_start_block = cb;
1372   thread->t_start_pc = pc;
1373   thread->t_pc = 0;
1374   thread->t_modCtx = modCtx;
1375   thread->t_mitem = mitem;
1376   thread->t_next = 0;
1377   thread->t_numChild = 0;
1378   thread->t_parent = 0;
1379   thread->t_callStack = 0;
1380 }
1381 
VGThread_start(VGThread * thread)1382 void VGThread_start(VGThread *thread)
1383 {
1384   thread->t_pc = CodeBlock_first(thread->t_start_block) + thread->t_start_pc;
1385 }
1386 
VGThread_kill(VGThread * t)1387 void VGThread_kill(VGThread *t)
1388 {
1389   /*  vgio_echo("killing thread %p.\n",t);*/
1390   t->t_pending = 0;
1391   t->t_state = TS_BLOCKED;
1392   t->t_isLive = 0;
1393 
1394   if (t->t_mitem)
1395     ModuleItem_killNotify(t->t_mitem);
1396 }
1397 
1398 
1399 /*****************************************************************************
1400  *
1401  * Spawn a child thread.
1402  *
1403  * Parameters:
1404  *     parent		Parent thread initiating the spawn
1405  *     cb		Codeblock to execute in
1406  *     offset		Offset of starting address.
1407  *
1408  *****************************************************************************/
VGThread_spawn(VGThread * parent,CodeBlock * cb,unsigned offset)1409 VGThread *VGThread_spawn(VGThread *parent,CodeBlock *cb,unsigned offset)
1410 {
1411   VGThread *child = new_VGThread(cb, offset, parent->t_modCtx, parent->t_mitem);
1412 
1413   child->t_parent = parent;
1414   parent->t_numChild++;
1415 
1416   return child;
1417 }
1418 
1419 /*****************************************************************************
1420  *
1421  * Receive notification that a child thread has terminated.
1422  *
1423  *****************************************************************************/
VGThread_childEndNotify(VGThread * thread)1424 void VGThread_childEndNotify(VGThread *thread)
1425 {
1426   if (--thread->t_numChild == 0 && !VGThread_isActive(thread)) {
1427     VGThread_delay(thread,0);
1428   }
1429 }
1430 
1431 /*****************************************************************************
1432  *
1433  * Uninitialize a VGThread object.
1434  *
1435  * Parameters:
1436  *     thread		VGThread object to be destroyed.
1437  *
1438  *****************************************************************************/
VGThread_uninit(VGThread * thread)1439 void VGThread_uninit(VGThread *thread)
1440 {
1441   /* nothing to do now - placeholder for future use. */
1442 }
1443 
VGThread_goto(VGThread * thread,CodeBlock * codeBlock,unsigned offset)1444 void VGThread_goto(VGThread *thread,CodeBlock *codeBlock,unsigned offset)
1445 {
1446   thread->t_pc = CodeBlock_get(codeBlock,offset);
1447 }
1448 
1449 
1450 /*****************************************************************************
1451  *
1452  * Execute a thread until it is suspended.
1453  *
1454  * Parameters:
1455  *     thread		Thread to execute.
1456  *
1457  *****************************************************************************/
VGThread_exec(VGThread * thread)1458 void VGThread_exec(VGThread *thread)
1459 {
1460   VGThread_resume(thread);
1461   while (VGThread_isActive(thread)) {
1462     if (do_input_check) {
1463       EvQueue *Q = VGThread_getQueue(thread);
1464       VGThread_suspend(thread);
1465       EvQueue_enqueueAtHead(Q,new_EvThread(thread));
1466     } else
1467       VGThread_doNextInsruction(thread);
1468   }
1469 }
1470 
1471 /*****************************************************************************
1472  *
1473  * Suspend execution of a thread for t time units.
1474  *
1475  * Parameters:
1476  *     thread		Thread to be suspended.
1477  *     delay		Number of epochs to wait before resuming thread.
1478  *
1479  *****************************************************************************/
VGThread_delay(VGThread * thread,deltatime_t delay)1480 void VGThread_delay(VGThread *thread,deltatime_t delay)
1481 {
1482   EvQueue *Q = VGThread_getQueue(thread);
1483 
1484   VGThread_suspend(thread);
1485   EvQueue_enqueueAfter(Q,new_EvThread(thread), delay);
1486 }
1487 
1488 /*****************************************************************************
1489  *
1490  * Suspend execution of a thread until end of epoch .
1491  *
1492  * Parameters:
1493  *     thread		Thread to be suspended.
1494  *
1495  *****************************************************************************/
VGThread_delayToEnd(VGThread * thread)1496 void VGThread_delayToEnd(VGThread *thread)
1497 {
1498   EvQueue *Q = VGThread_getQueue(thread);
1499 
1500   VGThread_suspend(thread);
1501   EvQueue_enqueueInactive(Q,new_EvThread(thread));
1502 }
1503 
1504 /*****************************************************************************
1505  *
1506  * Suspend execution of a thread until a triggering event occurs.
1507  *
1508  * Parameters:
1509  *     thread		Thread to be suspended
1510  *     trigger		Trigger on which to wait.
1511  *
1512  *****************************************************************************/
VGThread_eventWait(VGThread * thread,Trigger * trigger)1513 void VGThread_eventWait(VGThread *thread,Trigger *trigger)
1514 {
1515   VGThread_suspend(thread);
1516   Trigger_enqueue(trigger,new_EvThread(thread));
1517 }
1518 
1519 /*****************************************************************************
1520  *
1521  * Create a thread stack frame object
1522  *
1523  * Parameters:
1524  *     bc		Stack frame address
1525  *     next		Next element on stack frame
1526  *
1527  *****************************************************************************/
new_VGFrame(ByteCode * bc,VGFrame * next)1528 VGFrame *new_VGFrame(ByteCode *bc,VGFrame *next)
1529 {
1530   VGFrame *vgf = (VGFrame *) malloc(sizeof(VGFrame));
1531 
1532   vgf->f_pc = bc;
1533   vgf->f_next = next;
1534 
1535   return vgf;
1536 }
1537 
1538 /*****************************************************************************
1539  *
1540  * Destroy a thread stack frame object
1541  *
1542  *****************************************************************************/
delete_VGFrame(VGFrame * vgf)1543 void delete_VGFrame(VGFrame *vgf)
1544 {
1545   free(vgf);
1546 }
1547