2001-03-11 01:29:38 +01:00
|
|
|
/*
|
|
|
|
|
* Copyright (c) 2001 Stephen Williams (steve@icarus.com)
|
|
|
|
|
*
|
|
|
|
|
* This source code is free software; you can redistribute it
|
|
|
|
|
* and/or modify it in source code form under the terms of the GNU
|
|
|
|
|
* General Public License as published by the Free Software
|
|
|
|
|
* Foundation; either version 2 of the License, or (at your option)
|
|
|
|
|
* any later version.
|
|
|
|
|
*
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
|
|
|
|
*/
|
|
|
|
|
#if !defined(WINNT)
|
2001-03-29 05:46:36 +02:00
|
|
|
#ident "$Id: vthread.cc,v 1.13 2001/03/29 03:46:36 steve Exp $"
|
2001-03-11 01:29:38 +01:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
# include "vthread.h"
|
|
|
|
|
# include "codes.h"
|
|
|
|
|
# include "schedule.h"
|
2001-03-11 23:42:11 +01:00
|
|
|
# include "functor.h"
|
2001-03-16 02:44:34 +01:00
|
|
|
# include "vpi_priv.h"
|
2001-03-22 06:08:00 +01:00
|
|
|
# include <malloc.h>
|
2001-03-23 02:11:06 +01:00
|
|
|
# include <string.h>
|
2001-03-11 23:42:11 +01:00
|
|
|
# include <assert.h>
|
2001-03-11 01:29:38 +01:00
|
|
|
|
|
|
|
|
struct vthread_s {
|
|
|
|
|
/* This is the program counter. */
|
|
|
|
|
unsigned long pc;
|
2001-03-22 06:08:00 +01:00
|
|
|
unsigned char *bits;
|
|
|
|
|
unsigned short nbits;
|
2001-03-26 06:00:39 +02:00
|
|
|
/* This is used for keeping wait queues. */
|
|
|
|
|
struct vthread_s*next;
|
2001-03-11 01:29:38 +01:00
|
|
|
};
|
|
|
|
|
|
2001-03-23 02:11:06 +01:00
|
|
|
static void thr_check_addr(struct vthread_s*thr, unsigned addr)
|
|
|
|
|
{
|
|
|
|
|
if (addr < thr->nbits)
|
|
|
|
|
return;
|
|
|
|
|
assert(addr < 0x10000);
|
|
|
|
|
while (thr->nbits <= addr) {
|
|
|
|
|
thr->bits = (unsigned char*)realloc(thr->bits, thr->nbits/4 + 16);
|
|
|
|
|
memset(thr->bits + thr->nbits/4, 0xaa, 16);
|
|
|
|
|
thr->nbits += 16*4;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2001-03-22 06:08:00 +01:00
|
|
|
static inline unsigned thr_get_bit(struct vthread_s*thr, unsigned addr)
|
|
|
|
|
{
|
|
|
|
|
assert(addr < thr->nbits);
|
|
|
|
|
unsigned idx = addr % 4;
|
|
|
|
|
addr /= 4;
|
|
|
|
|
return (thr->bits[addr] >> (idx*2)) & 3;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline void thr_put_bit(struct vthread_s*thr,
|
|
|
|
|
unsigned addr, unsigned val)
|
|
|
|
|
{
|
2001-03-23 02:11:06 +01:00
|
|
|
thr_check_addr(thr, addr);
|
2001-03-22 06:08:00 +01:00
|
|
|
unsigned idx = addr % 4;
|
|
|
|
|
addr /= 4;
|
|
|
|
|
unsigned mask = 3 << (idx*2);
|
|
|
|
|
|
|
|
|
|
thr->bits[addr] = (thr->bits[addr] & ~mask) | (val << (idx*2));
|
|
|
|
|
}
|
|
|
|
|
|
2001-03-11 01:29:38 +01:00
|
|
|
/*
|
|
|
|
|
* Create a new thread with the given start address.
|
|
|
|
|
*/
|
|
|
|
|
vthread_t v_newthread(unsigned long pc)
|
|
|
|
|
{
|
|
|
|
|
vthread_t thr = new struct vthread_s;
|
|
|
|
|
thr->pc = pc;
|
2001-03-22 06:08:00 +01:00
|
|
|
thr->bits = (unsigned char*)malloc(16);
|
|
|
|
|
thr->nbits = 16*4;
|
2001-03-26 06:00:39 +02:00
|
|
|
thr->next = 0;
|
2001-03-11 01:29:38 +01:00
|
|
|
|
2001-03-22 06:08:00 +01:00
|
|
|
thr_put_bit(thr, 0, 0);
|
|
|
|
|
thr_put_bit(thr, 1, 1);
|
|
|
|
|
thr_put_bit(thr, 2, 2);
|
|
|
|
|
thr_put_bit(thr, 3, 3);
|
2001-03-11 01:29:38 +01:00
|
|
|
return thr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* This function runs a thread by fetching an instruction,
|
|
|
|
|
* incrementing the PC, and executing the instruction.
|
|
|
|
|
*/
|
|
|
|
|
void vthread_run(vthread_t thr)
|
|
|
|
|
{
|
|
|
|
|
for (;;) {
|
|
|
|
|
vvp_code_t cp = codespace_index(thr->pc);
|
|
|
|
|
thr->pc += 1;
|
|
|
|
|
|
2001-03-16 02:44:34 +01:00
|
|
|
assert(cp->opcode);
|
2001-03-19 02:55:38 +01:00
|
|
|
|
|
|
|
|
/* Run the opcode implementation. If the execution of
|
|
|
|
|
the opcode returns false, then the thread is meant to
|
|
|
|
|
be paused, so break out of the loop. */
|
2001-03-11 01:29:38 +01:00
|
|
|
bool rc = (cp->opcode)(thr, cp);
|
|
|
|
|
if (rc == false)
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2001-03-26 06:00:39 +02:00
|
|
|
void vthread_schedule_list(vthread_t thr)
|
|
|
|
|
{
|
|
|
|
|
while (thr) {
|
|
|
|
|
vthread_t tmp = thr;
|
|
|
|
|
thr = thr->next;
|
|
|
|
|
schedule_vthread(tmp, 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2001-03-11 01:29:38 +01:00
|
|
|
bool of_ASSIGN(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
2001-03-23 02:53:46 +01:00
|
|
|
unsigned char bit_val = thr_get_bit(thr, cp->bit_idx2);
|
2001-03-12 00:06:49 +01:00
|
|
|
schedule_assign(cp->iptr, bit_val, cp->bit_idx1);
|
2001-03-11 01:29:38 +01:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2001-03-22 06:08:00 +01:00
|
|
|
bool of_CMPU(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
|
|
|
|
unsigned eq = 1;
|
|
|
|
|
unsigned eeq = 1;
|
|
|
|
|
unsigned lt = 2;
|
|
|
|
|
|
2001-03-23 02:11:06 +01:00
|
|
|
unsigned idx1 = cp->bit_idx1;
|
|
|
|
|
unsigned idx2 = cp->bit_idx2;
|
|
|
|
|
|
2001-03-22 06:08:00 +01:00
|
|
|
for (unsigned idx = 0 ; idx < cp->number ; idx += 1) {
|
2001-03-23 02:11:06 +01:00
|
|
|
unsigned lv = thr_get_bit(thr, idx1);
|
|
|
|
|
unsigned rv = thr_get_bit(thr, idx2);
|
2001-03-22 06:08:00 +01:00
|
|
|
|
|
|
|
|
if (lv != rv)
|
|
|
|
|
eeq = 0;
|
2001-03-23 05:56:03 +01:00
|
|
|
if (eq != 2) {
|
|
|
|
|
if ((lv == 0) && (rv != 0))
|
|
|
|
|
eq = 0;
|
|
|
|
|
if ((lv == 1) && (rv != 1))
|
|
|
|
|
eq = 0;
|
|
|
|
|
if ((lv | rv) >= 2)
|
|
|
|
|
eq = 2;
|
|
|
|
|
}
|
2001-03-23 02:11:06 +01:00
|
|
|
|
|
|
|
|
if (idx1 >= 4) idx1 += 1;
|
|
|
|
|
if (idx2 >= 4) idx2 += 1;
|
2001-03-22 06:08:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
thr_put_bit(thr, 4, eq);
|
|
|
|
|
thr_put_bit(thr, 5, lt);
|
|
|
|
|
thr_put_bit(thr, 6, eeq);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2001-03-11 01:29:38 +01:00
|
|
|
bool of_DELAY(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
2001-03-19 02:55:38 +01:00
|
|
|
//printf("thread %p: %%delay %lu\n", thr, cp->number);
|
2001-03-11 01:29:38 +01:00
|
|
|
schedule_vthread(thr, cp->number);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool of_END(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
2001-03-19 02:55:38 +01:00
|
|
|
//printf("thread %p: %%end\n", thr);
|
2001-03-11 01:29:38 +01:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2001-03-22 06:08:00 +01:00
|
|
|
bool of_INV(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
|
|
|
|
assert(cp->bit_idx1 >= 4);
|
|
|
|
|
for (unsigned idx = 0 ; idx < cp->bit_idx2 ; idx += 1) {
|
|
|
|
|
unsigned val = thr_get_bit(thr, cp->bit_idx1+idx);
|
|
|
|
|
switch (val) {
|
|
|
|
|
case 0:
|
|
|
|
|
val = 1;
|
|
|
|
|
break;
|
|
|
|
|
case 1:
|
|
|
|
|
val = 0;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
val = 2;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
thr_put_bit(thr, cp->bit_idx1+idx, val);
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2001-03-20 07:16:23 +01:00
|
|
|
bool of_JMP(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
|
|
|
|
thr->pc = cp->cptr;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2001-03-22 06:08:00 +01:00
|
|
|
bool of_JMP0(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
|
|
|
|
if (thr_get_bit(thr, cp->bit_idx1) == 0)
|
|
|
|
|
thr->pc = cp->cptr;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2001-03-25 05:54:26 +02:00
|
|
|
bool of_JMP0XZ(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
|
|
|
|
if (thr_get_bit(thr, cp->bit_idx1) != 1)
|
|
|
|
|
thr->pc = cp->cptr;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2001-03-22 06:08:00 +01:00
|
|
|
bool of_LOAD(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
|
|
|
|
assert(cp->bit_idx1 >= 4);
|
|
|
|
|
thr_put_bit(thr, cp->bit_idx1, functor_get(cp->iptr));
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool of_MOV(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
|
|
|
|
assert(cp->bit_idx1 >= 4);
|
|
|
|
|
|
|
|
|
|
if (cp->bit_idx2 >= 4) {
|
|
|
|
|
for (unsigned idx = 0 ; idx < cp->number ; idx += 1)
|
|
|
|
|
thr_put_bit(thr,
|
|
|
|
|
cp->bit_idx1+idx,
|
|
|
|
|
thr_get_bit(thr, cp->bit_idx2+idx));
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
for (unsigned idx = 0 ; idx < cp->number ; idx += 1)
|
|
|
|
|
thr_put_bit(thr,
|
|
|
|
|
cp->bit_idx1+idx,
|
|
|
|
|
thr_get_bit(thr, cp->bit_idx2));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2001-03-11 01:29:38 +01:00
|
|
|
bool of_NOOP(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool of_SET(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
2001-03-23 02:53:46 +01:00
|
|
|
unsigned char bit_val = thr_get_bit(thr, cp->bit_idx1);
|
2001-03-11 23:42:11 +01:00
|
|
|
functor_set(cp->iptr, bit_val);
|
|
|
|
|
|
2001-03-11 01:29:38 +01:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2001-03-16 02:44:34 +01:00
|
|
|
bool of_VPI_CALL(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
2001-03-19 02:55:38 +01:00
|
|
|
// printf("thread %p: %%vpi_call\n", thr);
|
2001-03-16 02:44:34 +01:00
|
|
|
vpip_execute_vpi_call(cp->handle);
|
2001-03-19 02:55:38 +01:00
|
|
|
return schedule_finished()? false : true;
|
2001-03-16 02:44:34 +01:00
|
|
|
}
|
|
|
|
|
|
2001-03-26 06:00:39 +02:00
|
|
|
/*
|
|
|
|
|
* Implement the wait by locating the functor for the event, and
|
|
|
|
|
* adding this thread to the threads list for the event.
|
|
|
|
|
*/
|
|
|
|
|
bool of_WAIT(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
|
|
|
|
functor_t fp = functor_index(cp->iptr);
|
2001-03-29 05:46:36 +02:00
|
|
|
assert((fp->mode == 1) || (fp->mode == 2));
|
2001-03-26 06:00:39 +02:00
|
|
|
vvp_event_t ep = fp->event;
|
|
|
|
|
thr->next = ep->threads;
|
|
|
|
|
ep->threads = thr;
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2001-03-11 01:29:38 +01:00
|
|
|
/*
|
|
|
|
|
* $Log: vthread.cc,v $
|
2001-03-29 05:46:36 +02:00
|
|
|
* Revision 1.13 2001/03/29 03:46:36 steve
|
|
|
|
|
* Support named events as mode 2 functors.
|
|
|
|
|
*
|
2001-03-26 06:00:39 +02:00
|
|
|
* Revision 1.12 2001/03/26 04:00:39 steve
|
|
|
|
|
* Add the .event statement and the %wait instruction.
|
|
|
|
|
*
|
2001-03-25 05:54:26 +02:00
|
|
|
* Revision 1.11 2001/03/25 03:54:26 steve
|
|
|
|
|
* Add JMP0XZ and postpone net inputs when needed.
|
|
|
|
|
*
|
2001-03-23 05:56:03 +01:00
|
|
|
* Revision 1.10 2001/03/23 04:56:03 steve
|
|
|
|
|
* eq is x if either value of cmp/u has x or z.
|
|
|
|
|
*
|
2001-03-23 02:53:46 +01:00
|
|
|
* Revision 1.9 2001/03/23 01:53:46 steve
|
|
|
|
|
* Support set of functors from thread bits.
|
|
|
|
|
*
|
2001-03-23 02:11:06 +01:00
|
|
|
* Revision 1.8 2001/03/23 01:11:06 steve
|
|
|
|
|
* Handle vectors pulled out of a constant bit.
|
|
|
|
|
*
|
2001-03-22 06:08:00 +01:00
|
|
|
* Revision 1.7 2001/03/22 05:08:00 steve
|
|
|
|
|
* implement %load, %inv, %jum/0 and %cmp/u
|
|
|
|
|
*
|
2001-03-20 07:16:23 +01:00
|
|
|
* Revision 1.6 2001/03/20 06:16:24 steve
|
|
|
|
|
* Add support for variable vectors.
|
|
|
|
|
*
|
2001-03-19 02:55:38 +01:00
|
|
|
* Revision 1.5 2001/03/19 01:55:38 steve
|
|
|
|
|
* Add support for the vpiReset sim control.
|
|
|
|
|
*
|
2001-03-16 02:44:34 +01:00
|
|
|
* Revision 1.4 2001/03/16 01:44:34 steve
|
|
|
|
|
* Add structures for VPI support, and all the %vpi_call
|
|
|
|
|
* instruction. Get linking of VPI modules to work.
|
|
|
|
|
*
|
2001-03-12 00:06:49 +01:00
|
|
|
* Revision 1.3 2001/03/11 23:06:49 steve
|
|
|
|
|
* Compact the vvp_code_s structure.
|
|
|
|
|
*
|
2001-03-11 23:42:11 +01:00
|
|
|
* Revision 1.2 2001/03/11 22:42:11 steve
|
|
|
|
|
* Functor values and propagation.
|
|
|
|
|
*
|
2001-03-11 01:29:38 +01:00
|
|
|
* Revision 1.1 2001/03/11 00:29:39 steve
|
|
|
|
|
* Add the vvp engine to cvs.
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
|