2001-03-11 01:29:38 +01:00
|
|
|
/*
|
2004-06-19 17:52:53 +02:00
|
|
|
* Copyright (c) 2001-2004 Stephen Williams (steve@icarus.com)
|
2001-03-11 01:29:38 +01:00
|
|
|
*
|
|
|
|
|
* 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
|
|
|
|
|
*/
|
2002-08-12 03:34:58 +02:00
|
|
|
#ifdef HAVE_CVS_IDENT
|
2006-02-02 03:43:57 +01:00
|
|
|
#ident "$Id: vthread.cc,v 1.151 2006/02/02 02:44:00 steve Exp $"
|
2001-03-11 01:29:38 +01:00
|
|
|
#endif
|
|
|
|
|
|
2003-11-10 21:19:32 +01:00
|
|
|
# include "config.h"
|
2001-03-11 01:29:38 +01:00
|
|
|
# include "vthread.h"
|
|
|
|
|
# include "codes.h"
|
|
|
|
|
# include "schedule.h"
|
2002-03-18 01:19:34 +01:00
|
|
|
# include "ufunc.h"
|
2001-11-06 04:07:21 +01:00
|
|
|
# include "event.h"
|
2001-03-16 02:44:34 +01:00
|
|
|
# include "vpi_priv.h"
|
2001-09-15 20:27:04 +02:00
|
|
|
#ifdef HAVE_MALLOC_H
|
2001-03-22 06:08:00 +01:00
|
|
|
# include <malloc.h>
|
2001-09-15 20:27:04 +02:00
|
|
|
#endif
|
|
|
|
|
# include <stdlib.h>
|
2002-05-31 06:09:58 +02:00
|
|
|
# include <limits.h>
|
2001-03-23 02:11:06 +01:00
|
|
|
# include <string.h>
|
2003-01-26 00:48:05 +01:00
|
|
|
# include <math.h>
|
2001-03-11 23:42:11 +01:00
|
|
|
# include <assert.h>
|
2001-03-11 01:29:38 +01:00
|
|
|
|
2005-05-17 22:51:06 +02:00
|
|
|
# include <iostream>
|
2001-06-23 20:26:26 +02:00
|
|
|
#include <stdio.h>
|
2002-05-31 02:05:49 +02:00
|
|
|
|
|
|
|
|
/* This is the size of an unsigned long in bits. This is just a
|
|
|
|
|
convenience macro. */
|
|
|
|
|
# define CPU_WORD_BITS (8*sizeof(unsigned long))
|
|
|
|
|
# define TOP_BIT (1UL << (CPU_WORD_BITS-1))
|
|
|
|
|
|
2001-04-13 05:55:18 +02:00
|
|
|
/*
|
|
|
|
|
* This vhtread_s structure describes all there is to know about a
|
|
|
|
|
* thread, including its program counter, all the private bits it
|
|
|
|
|
* holds, and its place in other lists.
|
|
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
* ** Notes On The Interactions of %fork/%join/%end:
|
|
|
|
|
*
|
|
|
|
|
* The %fork instruction creates a new thread and pushes that onto the
|
|
|
|
|
* stack of children for the thread. This new thread, then, becomes
|
2003-02-10 00:33:26 +01:00
|
|
|
* the new direct descendant of the thread. This new thread is
|
2001-04-13 05:55:18 +02:00
|
|
|
* therefore also the first thread to be reaped when the parent does a
|
|
|
|
|
* %join.
|
|
|
|
|
*
|
|
|
|
|
* It is a programming error for a thread that created threads to not
|
|
|
|
|
* %join as many as it created before it %ends. The linear stack for
|
|
|
|
|
* tracking thread relationships will create a mess otherwise. For
|
|
|
|
|
* example, if A creates B then C, the stack is:
|
|
|
|
|
*
|
|
|
|
|
* A --> C --> B
|
|
|
|
|
*
|
|
|
|
|
* If C then %forks X, the stack is:
|
|
|
|
|
*
|
|
|
|
|
* A --> C --> X --> B
|
|
|
|
|
*
|
|
|
|
|
* If C %ends without a join, then the stack is:
|
|
|
|
|
*
|
|
|
|
|
* A --> C(zombie) --> X --> B
|
|
|
|
|
*
|
2002-09-21 06:55:00 +02:00
|
|
|
* If A then executes 2 %joins, it will reap C and X (when it ends)
|
2001-04-13 05:55:18 +02:00
|
|
|
* leaving B in purgatory. What's worse, A will block on the schedules
|
|
|
|
|
* of X and C instead of C and B, possibly creating incorrect timing.
|
2001-04-14 07:10:05 +02:00
|
|
|
*
|
|
|
|
|
* The schedule_parent_on_end flag is used by threads to tell their
|
|
|
|
|
* children that they are waiting for it to end. It is set by a %join
|
|
|
|
|
* instruction if the child is not already done. The thread that
|
|
|
|
|
* executes a %join instruction sets the flag in its child.
|
|
|
|
|
*
|
|
|
|
|
* The i_have_ended flag, on the other hand, is used by threads to
|
|
|
|
|
* tell their parents that they are already dead. A thread that
|
|
|
|
|
* executes %end will set its own i_have_ended flag and let its parent
|
|
|
|
|
* reap it when the parent does the %join. If a thread has its
|
|
|
|
|
* schedule_parent_on_end flag set already when it %ends, then it
|
|
|
|
|
* reaps itself and simply schedules its parent. If a child has its
|
|
|
|
|
* i_have_ended flag set when a thread executes %join, then it is free
|
|
|
|
|
* to reap the child immediately.
|
2001-04-13 05:55:18 +02:00
|
|
|
*/
|
|
|
|
|
|
2001-03-11 01:29:38 +01:00
|
|
|
struct vthread_s {
|
|
|
|
|
/* This is the program counter. */
|
2003-07-03 22:03:36 +02:00
|
|
|
vvp_code_t pc;
|
2001-04-13 05:55:18 +02:00
|
|
|
/* These hold the private thread bits. */
|
2005-08-27 04:34:42 +02:00
|
|
|
vvp_vector4_t bits4;
|
2003-01-26 00:48:05 +01:00
|
|
|
|
|
|
|
|
/* These are the word registers. */
|
|
|
|
|
union {
|
2005-09-14 04:50:07 +02:00
|
|
|
int64_t w_int;
|
|
|
|
|
uint64_t w_uint;
|
|
|
|
|
double w_real;
|
2003-01-26 00:48:05 +01:00
|
|
|
} words[16];
|
|
|
|
|
|
2001-04-13 05:55:18 +02:00
|
|
|
/* My parent sets this when it wants me to wake it up. */
|
|
|
|
|
unsigned schedule_parent_on_end :1;
|
2001-04-18 06:21:23 +02:00
|
|
|
unsigned i_have_ended :1;
|
2001-04-13 05:55:18 +02:00
|
|
|
unsigned waiting_for_event :1;
|
2001-04-21 02:34:39 +02:00
|
|
|
unsigned is_scheduled :1;
|
2002-09-21 06:55:00 +02:00
|
|
|
unsigned fork_count :8;
|
2001-04-13 05:55:18 +02:00
|
|
|
/* This points to the sole child of the thread. */
|
2001-03-30 06:55:22 +02:00
|
|
|
struct vthread_s*child;
|
2001-04-13 05:55:18 +02:00
|
|
|
/* This points to my parent, if I have one. */
|
|
|
|
|
struct vthread_s*parent;
|
2001-03-26 06:00:39 +02:00
|
|
|
/* This is used for keeping wait queues. */
|
2001-04-18 06:21:23 +02:00
|
|
|
struct vthread_s*wait_next;
|
|
|
|
|
/* These are used to keep the thread in a scope. */
|
|
|
|
|
struct vthread_s*scope_next, *scope_prev;
|
2001-03-11 01:29:38 +01:00
|
|
|
};
|
|
|
|
|
|
2002-05-31 02:05:49 +02:00
|
|
|
|
2005-08-27 04:34:42 +02:00
|
|
|
static inline void thr_check_addr(struct vthread_s*thr, unsigned addr)
|
2001-03-23 02:11:06 +01:00
|
|
|
{
|
2005-08-27 04:34:42 +02:00
|
|
|
if (thr->bits4.size() <= addr)
|
|
|
|
|
thr->bits4.resize(addr + CPU_WORD_BITS);
|
2001-03-23 02:11:06 +01:00
|
|
|
}
|
|
|
|
|
|
2004-12-11 03:31:25 +01:00
|
|
|
static inline vvp_bit4_t thr_get_bit(struct vthread_s*thr, unsigned addr)
|
2001-03-22 06:08:00 +01:00
|
|
|
{
|
2005-08-27 04:34:42 +02:00
|
|
|
assert(addr < thr->bits4.size());
|
|
|
|
|
return thr->bits4.value(addr);
|
2001-03-22 06:08:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline void thr_put_bit(struct vthread_s*thr,
|
2005-08-27 04:34:42 +02:00
|
|
|
unsigned addr, vvp_bit4_t val)
|
2001-03-22 06:08:00 +01:00
|
|
|
{
|
2005-08-27 04:34:42 +02:00
|
|
|
thr_check_addr(thr, addr);
|
|
|
|
|
thr->bits4.set_bit(addr, val);
|
2002-05-31 02:05:49 +02:00
|
|
|
}
|
|
|
|
|
|
2005-08-27 04:34:42 +02:00
|
|
|
// REMOVE ME
|
2002-05-31 02:05:49 +02:00
|
|
|
static inline void thr_clr_bit_(struct vthread_s*thr, unsigned addr)
|
|
|
|
|
{
|
2005-08-27 04:34:42 +02:00
|
|
|
thr->bits4.set_bit(addr, BIT4_0);
|
2001-03-22 06:08:00 +01:00
|
|
|
}
|
|
|
|
|
|
2005-08-27 04:34:42 +02:00
|
|
|
vvp_bit4_t vthread_get_bit(struct vthread_s*thr, unsigned addr)
|
2001-05-10 02:26:53 +02:00
|
|
|
{
|
|
|
|
|
return thr_get_bit(thr, addr);
|
|
|
|
|
}
|
|
|
|
|
|
2005-08-27 04:34:42 +02:00
|
|
|
void vthread_put_bit(struct vthread_s*thr, unsigned addr, vvp_bit4_t bit)
|
2001-05-10 02:26:53 +02:00
|
|
|
{
|
|
|
|
|
thr_put_bit(thr, addr, bit);
|
|
|
|
|
}
|
|
|
|
|
|
2003-01-26 19:16:22 +01:00
|
|
|
double vthread_get_real(struct vthread_s*thr, unsigned addr)
|
|
|
|
|
{
|
|
|
|
|
return thr->words[addr].w_real;
|
|
|
|
|
}
|
|
|
|
|
|
2003-01-27 01:14:37 +01:00
|
|
|
void vthread_put_real(struct vthread_s*thr, unsigned addr, double val)
|
|
|
|
|
{
|
|
|
|
|
thr->words[addr].w_real = val;
|
|
|
|
|
}
|
|
|
|
|
|
2001-07-04 06:57:10 +02:00
|
|
|
static unsigned long* vector_to_array(struct vthread_s*thr,
|
|
|
|
|
unsigned addr, unsigned wid)
|
|
|
|
|
{
|
2002-05-31 02:05:49 +02:00
|
|
|
unsigned awid = (wid + CPU_WORD_BITS - 1) / (CPU_WORD_BITS);
|
2001-07-04 06:57:10 +02:00
|
|
|
|
|
|
|
|
|
2005-08-27 04:34:42 +02:00
|
|
|
if (addr == 0) {
|
|
|
|
|
unsigned long*val = new unsigned long[awid];
|
|
|
|
|
for (unsigned idx = 0 ; idx < awid ; idx += 1)
|
|
|
|
|
val[idx] = 0;
|
|
|
|
|
return val;
|
|
|
|
|
}
|
|
|
|
|
if (addr == 1) {
|
|
|
|
|
unsigned long*val = new unsigned long[awid];
|
|
|
|
|
for (unsigned idx = 0 ; idx < awid ; idx += 1)
|
|
|
|
|
val[idx] = -1UL;
|
|
|
|
|
return val;
|
2001-07-04 06:57:10 +02:00
|
|
|
}
|
|
|
|
|
|
2005-08-27 04:34:42 +02:00
|
|
|
if (addr < 4)
|
|
|
|
|
return 0;
|
2001-07-04 06:57:10 +02:00
|
|
|
|
2005-08-27 04:34:42 +02:00
|
|
|
return thr->bits4.subarray(addr, wid);
|
2001-07-04 06:57:10 +02:00
|
|
|
}
|
|
|
|
|
|
2004-12-11 03:31:25 +01:00
|
|
|
/*
|
|
|
|
|
* This function gets from the thread a vector of bits starting from
|
|
|
|
|
* the addressed location and for the specified width.
|
|
|
|
|
*/
|
|
|
|
|
static vvp_vector4_t vthread_bits_to_vector(struct vthread_s*thr,
|
|
|
|
|
unsigned bit, unsigned wid)
|
|
|
|
|
{
|
|
|
|
|
/* Make a vector of the desired width. */
|
|
|
|
|
|
|
|
|
|
if (bit >= 4) {
|
2005-08-27 04:34:42 +02:00
|
|
|
return vvp_vector4_t(thr->bits4, bit, wid);
|
|
|
|
|
|
2004-12-11 03:31:25 +01:00
|
|
|
} else {
|
2005-08-27 04:34:42 +02:00
|
|
|
vvp_vector4_t value(wid);
|
2004-12-11 03:31:25 +01:00
|
|
|
vvp_bit4_t bit_val = (vvp_bit4_t)bit;
|
2005-06-26 03:57:22 +02:00
|
|
|
for (unsigned idx = 0; idx < wid; idx +=1) {
|
2004-12-11 03:31:25 +01:00
|
|
|
value.set_bit(idx, bit_val);
|
|
|
|
|
}
|
2005-08-27 04:34:42 +02:00
|
|
|
return value;
|
2004-12-11 03:31:25 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2001-05-10 02:26:53 +02:00
|
|
|
|
2001-03-11 01:29:38 +01:00
|
|
|
/*
|
|
|
|
|
* Create a new thread with the given start address.
|
|
|
|
|
*/
|
2003-07-03 22:03:36 +02:00
|
|
|
vthread_t vthread_new(vvp_code_t pc, struct __vpiScope*scope)
|
2001-03-11 01:29:38 +01:00
|
|
|
{
|
|
|
|
|
vthread_t thr = new struct vthread_s;
|
2001-04-13 05:55:18 +02:00
|
|
|
thr->pc = pc;
|
2005-08-27 04:34:42 +02:00
|
|
|
thr->bits4 = vvp_vector4_t(32);
|
2001-04-13 05:55:18 +02:00
|
|
|
thr->child = 0;
|
|
|
|
|
thr->parent = 0;
|
2002-09-21 06:55:00 +02:00
|
|
|
thr->wait_next = 0;
|
2001-04-18 06:21:23 +02:00
|
|
|
|
|
|
|
|
/* If the target scope never held a thread, then create a
|
|
|
|
|
header cell for it. This is a stub to make circular lists
|
|
|
|
|
easier to work with. */
|
|
|
|
|
if (scope->threads == 0) {
|
|
|
|
|
scope->threads = new struct vthread_s;
|
2003-07-03 22:03:36 +02:00
|
|
|
scope->threads->pc = codespace_null();
|
2005-08-27 04:34:42 +02:00
|
|
|
scope->threads->bits4 = vvp_vector4_t();
|
2001-04-18 06:21:23 +02:00
|
|
|
scope->threads->child = 0;
|
|
|
|
|
scope->threads->parent = 0;
|
|
|
|
|
scope->threads->scope_prev = scope->threads;
|
|
|
|
|
scope->threads->scope_next = scope->threads;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{ vthread_t tmp = scope->threads;
|
|
|
|
|
thr->scope_next = tmp->scope_next;
|
|
|
|
|
thr->scope_prev = tmp;
|
|
|
|
|
thr->scope_next->scope_prev = thr;
|
|
|
|
|
thr->scope_prev->scope_next = thr;
|
|
|
|
|
}
|
2001-04-13 05:55:18 +02:00
|
|
|
|
|
|
|
|
thr->schedule_parent_on_end = 0;
|
2001-05-02 03:37:38 +02:00
|
|
|
thr->is_scheduled = 0;
|
2001-04-13 05:55:18 +02:00
|
|
|
thr->i_have_ended = 0;
|
2001-04-14 07:10:05 +02:00
|
|
|
thr->waiting_for_event = 0;
|
2001-05-03 01:16:50 +02:00
|
|
|
thr->is_scheduled = 0;
|
2002-09-21 06:55:00 +02:00
|
|
|
thr->fork_count = 0;
|
2001-03-11 01:29:38 +01:00
|
|
|
|
2005-08-27 04:34:42 +02:00
|
|
|
thr_put_bit(thr, 0, BIT4_0);
|
|
|
|
|
thr_put_bit(thr, 1, BIT4_1);
|
|
|
|
|
thr_put_bit(thr, 2, BIT4_X);
|
|
|
|
|
thr_put_bit(thr, 3, BIT4_Z);
|
2001-04-18 06:21:23 +02:00
|
|
|
|
2001-03-11 01:29:38 +01:00
|
|
|
return thr;
|
|
|
|
|
}
|
|
|
|
|
|
2001-07-20 06:57:00 +02:00
|
|
|
/*
|
|
|
|
|
* Reaping pulls the thread out of the stack of threads. If I have a
|
|
|
|
|
* child, then hand it over to my parent.
|
|
|
|
|
*/
|
2001-03-30 06:55:22 +02:00
|
|
|
static void vthread_reap(vthread_t thr)
|
|
|
|
|
{
|
2005-08-27 04:34:42 +02:00
|
|
|
thr->bits4 = vvp_vector4_t();
|
2001-04-13 05:55:18 +02:00
|
|
|
|
2002-09-21 06:55:00 +02:00
|
|
|
if (thr->child) {
|
|
|
|
|
assert(thr->child->parent == thr);
|
2001-04-13 05:55:18 +02:00
|
|
|
thr->child->parent = thr->parent;
|
2002-09-21 06:55:00 +02:00
|
|
|
}
|
|
|
|
|
if (thr->parent) {
|
|
|
|
|
assert(thr->parent->child == thr);
|
2001-04-13 05:55:18 +02:00
|
|
|
thr->parent->child = thr->child;
|
2002-09-21 06:55:00 +02:00
|
|
|
}
|
2001-04-13 05:55:18 +02:00
|
|
|
|
2001-04-18 06:21:23 +02:00
|
|
|
thr->child = 0;
|
|
|
|
|
thr->parent = 0;
|
|
|
|
|
|
|
|
|
|
thr->scope_next->scope_prev = thr->scope_prev;
|
|
|
|
|
thr->scope_prev->scope_next = thr->scope_next;
|
|
|
|
|
|
2003-07-03 22:03:36 +02:00
|
|
|
thr->pc = codespace_null();
|
2001-04-21 02:34:39 +02:00
|
|
|
|
|
|
|
|
/* If this thread is not scheduled, then is it safe to delete
|
|
|
|
|
it now. Otherwise, let the schedule event (which will
|
|
|
|
|
execute the thread at of_ZOMBIE) delete the object. */
|
2002-09-21 06:55:00 +02:00
|
|
|
if ((thr->is_scheduled == 0) && (thr->waiting_for_event == 0)) {
|
|
|
|
|
assert(thr->fork_count == 0);
|
2002-09-22 01:47:30 +02:00
|
|
|
assert(thr->wait_next == 0);
|
2001-04-21 02:34:39 +02:00
|
|
|
delete thr;
|
2002-09-21 06:55:00 +02:00
|
|
|
}
|
2001-03-30 06:55:22 +02:00
|
|
|
}
|
|
|
|
|
|
2001-04-21 02:34:39 +02:00
|
|
|
void vthread_mark_scheduled(vthread_t thr)
|
|
|
|
|
{
|
2003-01-07 00:57:26 +01:00
|
|
|
while (thr != 0) {
|
|
|
|
|
assert(thr->is_scheduled == 0);
|
|
|
|
|
thr->is_scheduled = 1;
|
|
|
|
|
thr = thr->wait_next;
|
|
|
|
|
}
|
2001-04-21 02:34:39 +02:00
|
|
|
}
|
2001-03-11 01:29:38 +01:00
|
|
|
|
|
|
|
|
/*
|
2003-01-07 00:57:26 +01:00
|
|
|
* This function runs each thread by fetching an instruction,
|
|
|
|
|
* incrementing the PC, and executing the instruction. The thread may
|
|
|
|
|
* be the head of a list, so each thread is run so far as possible.
|
2001-03-11 01:29:38 +01:00
|
|
|
*/
|
|
|
|
|
void vthread_run(vthread_t thr)
|
|
|
|
|
{
|
2003-01-07 00:57:26 +01:00
|
|
|
while (thr != 0) {
|
|
|
|
|
vthread_t tmp = thr->wait_next;
|
|
|
|
|
thr->wait_next = 0;
|
2001-04-21 02:34:39 +02:00
|
|
|
|
2003-01-07 00:57:26 +01:00
|
|
|
assert(thr->is_scheduled);
|
|
|
|
|
thr->is_scheduled = 0;
|
2001-03-11 01:29:38 +01:00
|
|
|
|
2003-01-07 00:57:26 +01:00
|
|
|
for (;;) {
|
2003-07-03 22:03:36 +02:00
|
|
|
vvp_code_t cp = thr->pc;
|
2003-01-07 00:57:26 +01:00
|
|
|
thr->pc += 1;
|
2001-03-19 02:55:38 +01:00
|
|
|
|
2003-01-07 00:57:26 +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. */
|
|
|
|
|
bool rc = (cp->opcode)(thr, cp);
|
|
|
|
|
if (rc == false)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
thr = tmp;
|
2001-03-11 01:29:38 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2003-07-03 22:03:36 +02:00
|
|
|
/*
|
|
|
|
|
* The CHUNK_LINK instruction is a specla next pointer for linking
|
|
|
|
|
* chunks of code space. It's like a simplified %jmp.
|
|
|
|
|
*/
|
|
|
|
|
bool of_CHUNK_LINK(vthread_t thr, vvp_code_t code)
|
|
|
|
|
{
|
|
|
|
|
assert(code->cptr);
|
|
|
|
|
thr->pc = code->cptr;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2001-04-13 05:55:18 +02:00
|
|
|
/*
|
2001-04-18 06:21:23 +02:00
|
|
|
* This is called by an event functor to wake up all the threads on
|
2001-04-13 05:55:18 +02:00
|
|
|
* its list. I in fact created that list in the %wait instruction, and
|
|
|
|
|
* I also am certain that the waiting_for_event flag is set.
|
|
|
|
|
*/
|
2001-03-26 06:00:39 +02:00
|
|
|
void vthread_schedule_list(vthread_t thr)
|
|
|
|
|
{
|
2003-01-07 00:57:26 +01:00
|
|
|
for (vthread_t cur = thr ; cur ; cur = cur->wait_next) {
|
|
|
|
|
assert(cur->waiting_for_event);
|
|
|
|
|
cur->waiting_for_event = 0;
|
2001-03-26 06:00:39 +02:00
|
|
|
}
|
2003-01-07 00:57:26 +01:00
|
|
|
|
|
|
|
|
schedule_vthread(thr, 0);
|
2001-03-26 06:00:39 +02:00
|
|
|
}
|
|
|
|
|
|
2001-04-13 05:55:18 +02:00
|
|
|
|
2001-04-01 08:12:13 +02:00
|
|
|
bool of_AND(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
2001-11-01 04:00:19 +01:00
|
|
|
assert(cp->bit_idx[0] >= 4);
|
2001-04-01 08:12:13 +02:00
|
|
|
|
2001-11-01 04:00:19 +01:00
|
|
|
unsigned idx1 = cp->bit_idx[0];
|
|
|
|
|
unsigned idx2 = cp->bit_idx[1];
|
2001-04-01 08:12:13 +02:00
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < cp->number ; idx += 1) {
|
|
|
|
|
|
2005-08-27 04:34:42 +02:00
|
|
|
vvp_bit4_t lb = thr_get_bit(thr, idx1);
|
|
|
|
|
vvp_bit4_t rb = thr_get_bit(thr, idx2);
|
2001-04-01 08:12:13 +02:00
|
|
|
|
2005-08-27 05:28:57 +02:00
|
|
|
thr_put_bit(thr, idx1, lb & rb);
|
2001-04-01 08:12:13 +02:00
|
|
|
|
|
|
|
|
idx1 += 1;
|
|
|
|
|
if (idx2 >= 4)
|
|
|
|
|
idx2 += 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2001-06-22 02:03:05 +02:00
|
|
|
|
2001-03-31 03:59:58 +02:00
|
|
|
bool of_ADD(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
2001-11-01 04:00:19 +01:00
|
|
|
assert(cp->bit_idx[0] >= 4);
|
2001-03-31 03:59:58 +02:00
|
|
|
|
2001-11-01 04:00:19 +01:00
|
|
|
unsigned long*lva = vector_to_array(thr, cp->bit_idx[0], cp->number);
|
|
|
|
|
unsigned long*lvb = vector_to_array(thr, cp->bit_idx[1], cp->number);
|
2001-07-04 06:57:10 +02:00
|
|
|
if (lva == 0 || lvb == 0)
|
|
|
|
|
goto x_out;
|
2001-03-31 03:59:58 +02:00
|
|
|
|
|
|
|
|
|
2001-06-22 02:03:05 +02:00
|
|
|
unsigned long carry;
|
|
|
|
|
carry = 0;
|
2002-05-31 02:05:49 +02:00
|
|
|
for (unsigned idx = 0 ; (idx*CPU_WORD_BITS) < cp->number ; idx += 1) {
|
2001-10-23 05:49:13 +02:00
|
|
|
|
|
|
|
|
unsigned long tmp = lvb[idx] + carry;
|
|
|
|
|
unsigned long sum = lva[idx] + tmp;
|
|
|
|
|
carry = 0;
|
|
|
|
|
if (tmp < lvb[idx])
|
|
|
|
|
carry = 1;
|
|
|
|
|
if (sum < tmp)
|
|
|
|
|
carry = 1;
|
|
|
|
|
if (sum < lva[idx])
|
|
|
|
|
carry = 1;
|
|
|
|
|
lva[idx] = sum;
|
2001-06-22 02:03:05 +02:00
|
|
|
}
|
2001-03-31 03:59:58 +02:00
|
|
|
|
2005-08-27 04:34:42 +02:00
|
|
|
/* We know from the vector_to_array that the address is valid
|
|
|
|
|
in the thr->bitr4 vector, so just do the set bit. */
|
|
|
|
|
|
2001-03-31 03:59:58 +02:00
|
|
|
for (unsigned idx = 0 ; idx < cp->number ; idx += 1) {
|
2002-05-31 02:05:49 +02:00
|
|
|
unsigned bit = lva[idx/CPU_WORD_BITS] >> (idx % CPU_WORD_BITS);
|
2005-08-27 04:34:42 +02:00
|
|
|
thr->bits4.set_bit(cp->bit_idx[0]+idx, (bit&1) ? BIT4_1 : BIT4_0);
|
2001-03-31 03:59:58 +02:00
|
|
|
}
|
|
|
|
|
|
2001-06-22 02:03:05 +02:00
|
|
|
delete[]lva;
|
2001-07-04 06:57:10 +02:00
|
|
|
delete[]lvb;
|
2001-06-22 02:03:05 +02:00
|
|
|
|
2001-03-31 03:59:58 +02:00
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
x_out:
|
2001-06-22 02:03:05 +02:00
|
|
|
delete[]lva;
|
2001-07-04 06:57:10 +02:00
|
|
|
delete[]lvb;
|
2001-06-22 02:03:05 +02:00
|
|
|
|
2005-08-27 04:34:42 +02:00
|
|
|
vvp_vector4_t tmp(cp->number, BIT4_X);
|
|
|
|
|
thr->bits4.set_vec(cp->bit_idx[0], tmp);
|
2001-03-31 03:59:58 +02:00
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2003-01-26 00:48:05 +01:00
|
|
|
bool of_ADD_WR(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
|
|
|
|
double l = thr->words[cp->bit_idx[0]].w_real;
|
|
|
|
|
double r = thr->words[cp->bit_idx[1]].w_real;
|
|
|
|
|
thr->words[cp->bit_idx[0]].w_real = l + r;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2002-05-29 18:29:34 +02:00
|
|
|
/*
|
|
|
|
|
* This is %addi, add-immediate. The first value is a vector, the
|
|
|
|
|
* second value is the immediate value in the bin_idx[1] position. The
|
|
|
|
|
* immediate value can be up to 16 bits, which are then padded to the
|
|
|
|
|
* width of the vector with zero.
|
|
|
|
|
*/
|
|
|
|
|
bool of_ADDI(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
|
|
|
|
assert(cp->bit_idx[0] >= 4);
|
|
|
|
|
|
2002-05-31 02:05:49 +02:00
|
|
|
unsigned word_count = (cp->number+CPU_WORD_BITS-1)/CPU_WORD_BITS;
|
2002-05-29 18:29:34 +02:00
|
|
|
|
|
|
|
|
unsigned long*lva = vector_to_array(thr, cp->bit_idx[0], cp->number);
|
2005-08-27 04:34:42 +02:00
|
|
|
unsigned long*lvb = 0;
|
2002-05-29 18:29:34 +02:00
|
|
|
if (lva == 0)
|
|
|
|
|
goto x_out;
|
|
|
|
|
|
|
|
|
|
lvb = new unsigned long[word_count];
|
|
|
|
|
|
|
|
|
|
lvb[0] = cp->bit_idx[1];
|
|
|
|
|
for (unsigned idx = 1 ; idx < word_count ; idx += 1)
|
|
|
|
|
lvb[idx] = 0;
|
|
|
|
|
|
|
|
|
|
unsigned long carry;
|
|
|
|
|
carry = 0;
|
2002-05-31 02:05:49 +02:00
|
|
|
for (unsigned idx = 0 ; (idx*CPU_WORD_BITS) < cp->number ; idx += 1) {
|
2002-05-29 18:29:34 +02:00
|
|
|
|
|
|
|
|
unsigned long tmp = lvb[idx] + carry;
|
|
|
|
|
unsigned long sum = lva[idx] + tmp;
|
|
|
|
|
carry = 0;
|
|
|
|
|
if (tmp < lvb[idx])
|
|
|
|
|
carry = 1;
|
|
|
|
|
if (sum < tmp)
|
|
|
|
|
carry = 1;
|
|
|
|
|
if (sum < lva[idx])
|
|
|
|
|
carry = 1;
|
|
|
|
|
lva[idx] = sum;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < cp->number ; idx += 1) {
|
2005-08-29 06:46:13 +02:00
|
|
|
unsigned long bit = lva[idx/CPU_WORD_BITS] >> (idx%CPU_WORD_BITS);
|
|
|
|
|
thr->bits4.set_bit(cp->bit_idx[0]+idx, (bit&1UL) ? BIT4_1:BIT4_0);
|
2002-05-29 18:29:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
delete[]lva;
|
|
|
|
|
delete[]lvb;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
x_out:
|
|
|
|
|
delete[]lva;
|
|
|
|
|
|
2005-08-27 04:34:42 +02:00
|
|
|
vvp_vector4_t tmp (cp->number, BIT4_X);
|
|
|
|
|
thr->bits4.set_vec(cp->bit_idx[0], tmp);
|
2002-05-29 18:29:34 +02:00
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2002-11-08 05:59:57 +01:00
|
|
|
/*
|
|
|
|
|
* This is %assign/v0 <label>, <delay>, <bit>
|
|
|
|
|
* Index register 0 contains a vector width.
|
|
|
|
|
*/
|
|
|
|
|
bool of_ASSIGN_V0(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
2003-01-26 00:48:05 +01:00
|
|
|
unsigned wid = thr->words[0].w_int;
|
2002-11-08 05:59:57 +01:00
|
|
|
assert(wid > 0);
|
|
|
|
|
unsigned delay = cp->bit_idx[0];
|
|
|
|
|
unsigned bit = cp->bit_idx[1];
|
|
|
|
|
|
2004-12-11 03:31:25 +01:00
|
|
|
vvp_vector4_t value = vthread_bits_to_vector(thr, bit, wid);
|
2002-11-08 05:59:57 +01:00
|
|
|
|
2004-12-11 03:31:25 +01:00
|
|
|
vvp_net_ptr_t ptr (cp->net, 0);
|
|
|
|
|
schedule_assign_vector(ptr, value, delay);
|
2002-11-08 05:59:57 +01:00
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2005-06-14 03:44:09 +02:00
|
|
|
/*
|
|
|
|
|
* This is %assign/v0/d <label>, <delay_idx>, <bit>
|
|
|
|
|
* Index register 0 contains a vector width, and the named index
|
|
|
|
|
* register contains the delay.
|
|
|
|
|
*/
|
|
|
|
|
bool of_ASSIGN_V0D(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
|
|
|
|
unsigned wid = thr->words[0].w_int;
|
|
|
|
|
assert(wid > 0);
|
|
|
|
|
|
|
|
|
|
unsigned long delay = thr->words[cp->bit_idx[0]].w_int;
|
|
|
|
|
unsigned bit = cp->bit_idx[1];
|
|
|
|
|
|
|
|
|
|
vvp_vector4_t value = vthread_bits_to_vector(thr, bit, wid);
|
|
|
|
|
|
|
|
|
|
vvp_net_ptr_t ptr (cp->net, 0);
|
|
|
|
|
schedule_assign_vector(ptr, value, delay);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2005-05-07 05:15:42 +02:00
|
|
|
/*
|
|
|
|
|
* This is %assign/v0/x1 <label>, <delay>, <bit>
|
|
|
|
|
* Index register 0 contains a vector part width.
|
|
|
|
|
* Index register 1 contains the offset into the destination vector.
|
|
|
|
|
*/
|
|
|
|
|
bool of_ASSIGN_V0X1(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
|
|
|
|
unsigned wid = thr->words[0].w_int;
|
|
|
|
|
unsigned off = thr->words[1].w_int;
|
|
|
|
|
unsigned delay = cp->bit_idx[0];
|
|
|
|
|
unsigned bit = cp->bit_idx[1];
|
|
|
|
|
|
2005-11-25 18:55:26 +01:00
|
|
|
vvp_fun_signal_vec*sig
|
|
|
|
|
= reinterpret_cast<vvp_fun_signal_vec*> (cp->net->fun);
|
2005-05-07 05:15:42 +02:00
|
|
|
assert(sig);
|
|
|
|
|
assert(wid > 0);
|
|
|
|
|
|
|
|
|
|
if (off >= sig->size())
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
vvp_vector4_t value = vthread_bits_to_vector(thr, bit, wid);
|
|
|
|
|
|
|
|
|
|
vvp_net_ptr_t ptr (cp->net, 0);
|
|
|
|
|
schedule_assign_vector(ptr, off, sig->size(), value, delay);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2004-05-19 05:26:24 +02:00
|
|
|
/*
|
|
|
|
|
* This is %assign/wr <vpi-label>, <delay>, <index>
|
|
|
|
|
*
|
|
|
|
|
* This assigns (after a delay) a value to a real variable. Use the
|
|
|
|
|
* vpi_put_value function to do the assign, with the delay written
|
|
|
|
|
* into the vpiInertialDelay carrying the desired delay.
|
|
|
|
|
*/
|
|
|
|
|
bool of_ASSIGN_WR(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
|
|
|
|
unsigned delay = cp->bit_idx[0];
|
|
|
|
|
s_vpi_time del;
|
|
|
|
|
|
|
|
|
|
del.type = vpiSimTime;
|
|
|
|
|
vpip_time_to_timestruct(&del, schedule_simtime() + delay);
|
|
|
|
|
|
|
|
|
|
struct __vpiHandle*tmp = cp->handle;
|
|
|
|
|
|
|
|
|
|
t_vpi_value val;
|
|
|
|
|
val.format = vpiRealVal;
|
|
|
|
|
val.value.real = thr->words[cp->bit_idx[1]].w_real;
|
|
|
|
|
vpi_put_value(tmp, &val, &del, vpiInertialDelay);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2001-08-27 00:59:32 +02:00
|
|
|
bool of_ASSIGN_X0(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
2004-12-11 03:31:25 +01:00
|
|
|
#if 0
|
2001-11-01 04:00:19 +01:00
|
|
|
unsigned char bit_val = thr_get_bit(thr, cp->bit_idx[1]);
|
2003-01-26 00:48:05 +01:00
|
|
|
vvp_ipoint_t itmp = ipoint_index(cp->iptr, thr->words[0].w_int);
|
2001-11-01 04:00:19 +01:00
|
|
|
schedule_assign(itmp, bit_val, cp->bit_idx[0]);
|
2004-12-11 03:31:25 +01:00
|
|
|
#else
|
|
|
|
|
fprintf(stderr, "XXXX forgot how to implement %%assign/x0\n");
|
|
|
|
|
#endif
|
2001-08-27 00:59:32 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2005-03-06 18:07:48 +01:00
|
|
|
/* %assign/mv <memory>, <delay>, <bit>
|
|
|
|
|
* This generates an assignment event to a memory. Index register 0
|
|
|
|
|
* contains the width of the vector (and the word) and index register
|
2005-09-19 23:45:35 +02:00
|
|
|
* 3 contains the canonical address of the word in memory.
|
2005-03-06 18:07:48 +01:00
|
|
|
*/
|
2005-03-03 05:33:10 +01:00
|
|
|
bool of_ASSIGN_MV(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
2005-03-06 18:07:48 +01:00
|
|
|
unsigned wid = thr->words[0].w_int;
|
2006-02-02 03:43:57 +01:00
|
|
|
unsigned off = thr->words[1].w_int;
|
2005-03-06 18:07:48 +01:00
|
|
|
unsigned adr = thr->words[3].w_int;
|
|
|
|
|
|
|
|
|
|
assert(wid > 0);
|
|
|
|
|
|
|
|
|
|
unsigned delay = cp->bit_idx[0];
|
|
|
|
|
unsigned bit = cp->bit_idx[1];
|
|
|
|
|
|
|
|
|
|
vvp_vector4_t value = vthread_bits_to_vector(thr, bit, wid);
|
|
|
|
|
|
2006-02-02 03:43:57 +01:00
|
|
|
schedule_assign_memory_word(cp->mem, adr, off, value, delay);
|
2001-05-01 03:09:39 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2002-08-22 05:38:40 +02:00
|
|
|
bool of_BLEND(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
|
|
|
|
assert(cp->bit_idx[0] >= 4);
|
|
|
|
|
|
|
|
|
|
unsigned idx1 = cp->bit_idx[0];
|
|
|
|
|
unsigned idx2 = cp->bit_idx[1];
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < cp->number ; idx += 1) {
|
2005-08-27 04:34:42 +02:00
|
|
|
vvp_bit4_t lb = thr_get_bit(thr, idx1);
|
|
|
|
|
vvp_bit4_t rb = thr_get_bit(thr, idx2);
|
2002-08-22 05:38:40 +02:00
|
|
|
|
|
|
|
|
if (lb != rb)
|
2005-08-27 04:34:42 +02:00
|
|
|
thr_put_bit(thr, idx1, BIT4_X);
|
2002-08-22 05:38:40 +02:00
|
|
|
|
|
|
|
|
idx1 += 1;
|
|
|
|
|
if (idx2 >= 4)
|
|
|
|
|
idx2 += 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2001-05-06 01:55:46 +02:00
|
|
|
bool of_BREAKPOINT(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2005-05-02 00:05:21 +02:00
|
|
|
/*
|
|
|
|
|
* the %cassign/link instruction connects a source node to a
|
|
|
|
|
* destination node. The destination node must be a signal, as it is
|
|
|
|
|
* marked with the source of the cassign so that it may later be
|
|
|
|
|
* unlinked without specifically knowing the source that this
|
|
|
|
|
* instruction used.
|
|
|
|
|
*/
|
|
|
|
|
bool of_CASSIGN_LINK(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
|
|
|
|
vvp_net_t*dst = cp->net;
|
|
|
|
|
vvp_net_t*src = cp->net2;
|
|
|
|
|
|
|
|
|
|
/* For now, assert that the destination continuous assign
|
|
|
|
|
input is empty. That should be so as you can have only one
|
|
|
|
|
continuous assignment active for the destination. */
|
|
|
|
|
assert(dst->port[1].nil());
|
|
|
|
|
|
|
|
|
|
/* Link the output of the src to the port[1] (the cassign
|
|
|
|
|
port) of the destination. */
|
|
|
|
|
vvp_net_ptr_t dst_ptr (dst, 1);
|
|
|
|
|
dst->port[1] = src->out;
|
|
|
|
|
src->out = dst_ptr;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2004-12-11 03:31:25 +01:00
|
|
|
/*
|
|
|
|
|
* the %cassign/v instruction invokes a continuous assign of a
|
|
|
|
|
* constant value to a signal. The instruction arguments are:
|
|
|
|
|
*
|
|
|
|
|
* %cassign/v <net>, <base>, <wid> ;
|
|
|
|
|
*
|
|
|
|
|
* Where the <net> is the net label assembled into a vvp_net pointer,
|
|
|
|
|
* and the <base> and <wid> are stashed in the bit_idx array.
|
|
|
|
|
*
|
|
|
|
|
* This instruction writes vvp_vector4_t values to port-1 of the
|
|
|
|
|
* target signal.
|
|
|
|
|
*/
|
|
|
|
|
bool of_CASSIGN_V(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
|
|
|
|
vvp_net_t*net = cp->net;
|
|
|
|
|
unsigned base = cp->bit_idx[0];
|
|
|
|
|
unsigned wid = cp->bit_idx[1];
|
|
|
|
|
|
|
|
|
|
/* Collect the thread bits into a vector4 item. */
|
|
|
|
|
vvp_vector4_t value = vthread_bits_to_vector(thr, base, wid);
|
|
|
|
|
|
|
|
|
|
/* set the value into port 1 of the destination. */
|
|
|
|
|
vvp_net_ptr_t ptr (net, 1);
|
|
|
|
|
vvp_send_vec4(ptr, value);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2001-04-05 03:12:27 +02:00
|
|
|
bool of_CMPS(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
2005-08-27 04:34:42 +02:00
|
|
|
vvp_bit4_t eq = BIT4_1;
|
|
|
|
|
vvp_bit4_t eeq = BIT4_1;
|
|
|
|
|
vvp_bit4_t lt = BIT4_0;
|
2001-04-05 03:12:27 +02:00
|
|
|
|
2001-11-01 04:00:19 +01:00
|
|
|
unsigned idx1 = cp->bit_idx[0];
|
|
|
|
|
unsigned idx2 = cp->bit_idx[1];
|
2001-04-05 03:12:27 +02:00
|
|
|
|
2005-08-27 04:34:42 +02:00
|
|
|
const unsigned end1 = (idx1 < 4)? idx1 : idx1 + cp->number - 1;
|
|
|
|
|
const unsigned end2 = (idx2 < 4)? idx2 : idx2 + cp->number - 1;
|
|
|
|
|
|
|
|
|
|
if (end1 > end2)
|
|
|
|
|
thr_check_addr(thr, end1);
|
|
|
|
|
else
|
|
|
|
|
thr_check_addr(thr, end2);
|
2001-12-31 01:01:16 +01:00
|
|
|
|
2005-08-27 04:34:42 +02:00
|
|
|
const vvp_bit4_t sig1 = thr_get_bit(thr, end1);
|
|
|
|
|
const vvp_bit4_t sig2 = thr_get_bit(thr, end2);
|
2001-04-05 03:12:27 +02:00
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < cp->number ; idx += 1) {
|
2005-08-27 04:34:42 +02:00
|
|
|
vvp_bit4_t lv = thr_get_bit(thr, idx1);
|
|
|
|
|
vvp_bit4_t rv = thr_get_bit(thr, idx2);
|
2001-04-05 03:12:27 +02:00
|
|
|
|
|
|
|
|
if (lv > rv) {
|
2005-08-27 04:34:42 +02:00
|
|
|
lt = BIT4_0;
|
|
|
|
|
eeq = BIT4_0;
|
2001-04-05 03:12:27 +02:00
|
|
|
} else if (lv < rv) {
|
2005-08-27 04:34:42 +02:00
|
|
|
lt = BIT4_1;
|
|
|
|
|
eeq = BIT4_0;
|
2001-04-05 03:12:27 +02:00
|
|
|
}
|
2005-08-27 04:34:42 +02:00
|
|
|
if (eq != BIT4_X) {
|
|
|
|
|
if ((lv == BIT4_0) && (rv != BIT4_0))
|
|
|
|
|
eq = BIT4_0;
|
|
|
|
|
if ((lv == BIT4_1) && (rv != BIT4_1))
|
|
|
|
|
eq = BIT4_0;
|
|
|
|
|
if (bit4_is_xz(lv) || bit4_is_xz(rv))
|
|
|
|
|
eq = BIT4_X;
|
2001-04-05 03:12:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (idx1 >= 4) idx1 += 1;
|
|
|
|
|
if (idx2 >= 4) idx2 += 1;
|
|
|
|
|
}
|
|
|
|
|
|
2005-08-27 04:34:42 +02:00
|
|
|
if (eq == BIT4_X)
|
|
|
|
|
lt = BIT4_X;
|
|
|
|
|
else if ((sig1 == BIT4_1) && (sig2 == BIT4_0))
|
|
|
|
|
lt = BIT4_1;
|
|
|
|
|
else if ((sig1 == BIT4_0) && (sig2 == BIT4_1))
|
|
|
|
|
lt = BIT4_0;
|
2001-04-05 03:12:27 +02:00
|
|
|
|
2001-12-31 01:01:16 +01:00
|
|
|
/* Correct the lt bit to account for the sign of the parameters. */
|
2005-08-27 04:34:42 +02:00
|
|
|
if (lt != BIT4_X) {
|
2001-12-31 01:01:16 +01:00
|
|
|
|
|
|
|
|
/* If both numbers are negative, then switch the
|
|
|
|
|
direction of the lt. */
|
2005-08-27 04:34:42 +02:00
|
|
|
if ((sig1 == BIT4_1) && (sig2 == BIT4_1) && (eq != BIT4_0))
|
|
|
|
|
lt = ~lt;
|
2001-12-31 01:01:16 +01:00
|
|
|
|
|
|
|
|
/* If the first is negative and the last positive, then
|
|
|
|
|
a < b for certain. */
|
2005-08-27 04:34:42 +02:00
|
|
|
if ((sig1 == BIT4_1) && (sig2 == BIT4_0))
|
|
|
|
|
lt = BIT4_1;
|
2001-12-31 01:01:16 +01:00
|
|
|
|
|
|
|
|
/* If the first is positive and the last negative, then
|
|
|
|
|
a > b for certain. */
|
2005-08-27 04:34:42 +02:00
|
|
|
if ((sig1 == BIT4_0) && (sig2 == BIT4_1))
|
|
|
|
|
lt = BIT4_0;
|
2001-12-31 01:01:16 +01:00
|
|
|
}
|
|
|
|
|
|
2001-04-05 03:12:27 +02:00
|
|
|
thr_put_bit(thr, 4, eq);
|
|
|
|
|
thr_put_bit(thr, 5, lt);
|
|
|
|
|
thr_put_bit(thr, 6, eeq);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2002-06-02 20:55:58 +02:00
|
|
|
bool of_CMPIU(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
2005-08-27 04:34:42 +02:00
|
|
|
vvp_bit4_t eq = BIT4_1;
|
|
|
|
|
vvp_bit4_t eeq = BIT4_1;
|
|
|
|
|
vvp_bit4_t lt = BIT4_0;
|
2002-06-02 20:55:58 +02:00
|
|
|
|
|
|
|
|
unsigned idx1 = cp->bit_idx[0];
|
|
|
|
|
unsigned imm = cp->bit_idx[1];
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < cp->number ; idx += 1) {
|
2005-08-27 04:34:42 +02:00
|
|
|
vvp_bit4_t lv = thr_get_bit(thr, idx1);
|
|
|
|
|
vvp_bit4_t rv = (imm & 1)? BIT4_1 : BIT4_0;
|
2002-06-02 20:55:58 +02:00
|
|
|
imm >>= 1;
|
|
|
|
|
|
|
|
|
|
if (lv > rv) {
|
2005-08-27 04:34:42 +02:00
|
|
|
lt = BIT4_0;
|
|
|
|
|
eeq = BIT4_0;
|
2002-06-02 20:55:58 +02:00
|
|
|
} else if (lv < rv) {
|
2005-08-27 04:34:42 +02:00
|
|
|
lt = BIT4_1;
|
|
|
|
|
eeq = BIT4_0;
|
2002-06-02 20:55:58 +02:00
|
|
|
}
|
2005-08-27 04:34:42 +02:00
|
|
|
if (eq != BIT4_X) {
|
|
|
|
|
if ((lv == BIT4_0) && (rv != BIT4_0))
|
|
|
|
|
eq = BIT4_0;
|
|
|
|
|
if ((lv == BIT4_1) && (rv != BIT4_1))
|
|
|
|
|
eq = BIT4_0;
|
|
|
|
|
if (bit4_is_xz(lv) || bit4_is_xz(rv))
|
|
|
|
|
eq = BIT4_X;
|
2002-06-02 20:55:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (idx1 >= 4) idx1 += 1;
|
|
|
|
|
}
|
|
|
|
|
|
2005-08-27 04:34:42 +02:00
|
|
|
if (eq == BIT4_X)
|
|
|
|
|
lt = BIT4_X;
|
2002-06-02 20:55:58 +02:00
|
|
|
|
|
|
|
|
thr_put_bit(thr, 4, eq);
|
|
|
|
|
thr_put_bit(thr, 5, lt);
|
|
|
|
|
thr_put_bit(thr, 6, eeq);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2001-03-22 06:08:00 +01:00
|
|
|
bool of_CMPU(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
2005-08-27 04:34:42 +02:00
|
|
|
vvp_bit4_t eq = BIT4_1;
|
|
|
|
|
vvp_bit4_t eeq = BIT4_1;
|
|
|
|
|
vvp_bit4_t lt = BIT4_0;
|
2001-03-22 06:08:00 +01:00
|
|
|
|
2001-11-01 04:00:19 +01:00
|
|
|
unsigned idx1 = cp->bit_idx[0];
|
|
|
|
|
unsigned idx2 = cp->bit_idx[1];
|
2001-03-23 02:11:06 +01:00
|
|
|
|
2001-03-22 06:08:00 +01:00
|
|
|
for (unsigned idx = 0 ; idx < cp->number ; idx += 1) {
|
2005-08-27 04:34:42 +02:00
|
|
|
vvp_bit4_t lv = thr_get_bit(thr, idx1);
|
|
|
|
|
vvp_bit4_t rv = thr_get_bit(thr, idx2);
|
2001-03-22 06:08:00 +01:00
|
|
|
|
2001-04-01 09:22:08 +02:00
|
|
|
if (lv > rv) {
|
2005-08-27 04:34:42 +02:00
|
|
|
lt = BIT4_0;
|
|
|
|
|
eeq = BIT4_0;
|
2001-04-01 09:22:08 +02:00
|
|
|
} else if (lv < rv) {
|
2005-08-27 04:34:42 +02:00
|
|
|
lt = BIT4_1;
|
|
|
|
|
eeq = BIT4_0;
|
2001-04-01 09:22:08 +02:00
|
|
|
}
|
2005-08-27 04:34:42 +02:00
|
|
|
if (eq != BIT4_X) {
|
|
|
|
|
if ((lv == BIT4_0) && (rv != BIT4_0))
|
|
|
|
|
eq = BIT4_0;
|
|
|
|
|
if ((lv == BIT4_1) && (rv != BIT4_1))
|
|
|
|
|
eq = BIT4_0;
|
|
|
|
|
if (bit4_is_xz(lv) || bit4_is_xz(rv))
|
|
|
|
|
eq = BIT4_X;
|
2001-03-23 05:56:03 +01:00
|
|
|
}
|
2001-03-23 02:11:06 +01:00
|
|
|
|
|
|
|
|
if (idx1 >= 4) idx1 += 1;
|
|
|
|
|
if (idx2 >= 4) idx2 += 1;
|
2005-08-27 05:28:57 +02:00
|
|
|
|
2001-03-22 06:08:00 +01:00
|
|
|
}
|
|
|
|
|
|
2005-08-27 04:34:42 +02:00
|
|
|
if (eq == BIT4_X)
|
|
|
|
|
lt = BIT4_X;
|
2001-04-01 09:22:08 +02:00
|
|
|
|
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-04-01 06:34:28 +02:00
|
|
|
bool of_CMPX(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
2005-08-27 04:34:42 +02:00
|
|
|
vvp_bit4_t eq = BIT4_1;
|
2001-04-01 06:34:28 +02:00
|
|
|
|
2001-11-01 04:00:19 +01:00
|
|
|
unsigned idx1 = cp->bit_idx[0];
|
|
|
|
|
unsigned idx2 = cp->bit_idx[1];
|
2001-04-01 06:34:28 +02:00
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < cp->number ; idx += 1) {
|
2005-08-27 04:34:42 +02:00
|
|
|
vvp_bit4_t lv = thr_get_bit(thr, idx1);
|
|
|
|
|
vvp_bit4_t rv = thr_get_bit(thr, idx2);
|
2001-04-01 06:34:28 +02:00
|
|
|
|
2005-08-27 04:34:42 +02:00
|
|
|
if ((lv != rv) && !bit4_is_xz(lv) && !bit4_is_xz(rv)) {
|
|
|
|
|
eq = BIT4_0;
|
2001-04-01 06:34:28 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (idx1 >= 4) idx1 += 1;
|
|
|
|
|
if (idx2 >= 4) idx2 += 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
thr_put_bit(thr, 4, eq);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2003-01-26 00:48:05 +01:00
|
|
|
bool of_CMPWR(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
|
|
|
|
double l = thr->words[cp->bit_idx[0]].w_real;
|
|
|
|
|
double r = thr->words[cp->bit_idx[1]].w_real;
|
|
|
|
|
|
2005-08-27 04:34:42 +02:00
|
|
|
vvp_bit4_t eq = (l == r)? BIT4_1 : BIT4_0;
|
|
|
|
|
vvp_bit4_t lt = (l < r)? BIT4_1 : BIT4_0;
|
2003-01-26 00:48:05 +01:00
|
|
|
|
|
|
|
|
thr_put_bit(thr, 4, eq);
|
|
|
|
|
thr_put_bit(thr, 5, lt);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2005-09-14 04:50:07 +02:00
|
|
|
bool of_CMPWS(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
|
|
|
|
int64_t l = thr->words[cp->bit_idx[0]].w_int;
|
|
|
|
|
int64_t r = thr->words[cp->bit_idx[1]].w_int;
|
|
|
|
|
|
|
|
|
|
vvp_bit4_t eq = (l == r)? BIT4_1 : BIT4_0;
|
|
|
|
|
vvp_bit4_t lt = (l < r)? BIT4_1 : BIT4_0;
|
|
|
|
|
|
|
|
|
|
thr_put_bit(thr, 4, eq);
|
|
|
|
|
thr_put_bit(thr, 5, lt);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool of_CMPWU(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
|
|
|
|
uint64_t l = thr->words[cp->bit_idx[0]].w_uint;
|
|
|
|
|
uint64_t r = thr->words[cp->bit_idx[1]].w_uint;
|
|
|
|
|
|
|
|
|
|
vvp_bit4_t eq = (l == r)? BIT4_1 : BIT4_0;
|
|
|
|
|
vvp_bit4_t lt = (l < r)? BIT4_1 : BIT4_0;
|
|
|
|
|
|
|
|
|
|
thr_put_bit(thr, 4, eq);
|
|
|
|
|
thr_put_bit(thr, 5, lt);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2001-04-01 06:34:28 +02:00
|
|
|
bool of_CMPZ(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
2005-08-27 04:34:42 +02:00
|
|
|
vvp_bit4_t eq = BIT4_1;
|
2001-04-01 06:34:28 +02:00
|
|
|
|
2001-11-01 04:00:19 +01:00
|
|
|
unsigned idx1 = cp->bit_idx[0];
|
|
|
|
|
unsigned idx2 = cp->bit_idx[1];
|
2001-04-01 06:34:28 +02:00
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < cp->number ; idx += 1) {
|
2005-08-27 04:34:42 +02:00
|
|
|
vvp_bit4_t lv = thr_get_bit(thr, idx1);
|
|
|
|
|
vvp_bit4_t rv = thr_get_bit(thr, idx2);
|
2001-04-01 06:34:28 +02:00
|
|
|
|
2005-08-27 04:34:42 +02:00
|
|
|
if ((lv != BIT4_Z) && (rv != BIT4_Z) && (lv != rv)) {
|
|
|
|
|
eq = BIT4_0;
|
2001-04-01 06:34:28 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (idx1 >= 4) idx1 += 1;
|
|
|
|
|
if (idx2 >= 4) idx2 += 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
thr_put_bit(thr, 4, eq);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2003-01-26 19:16:22 +01:00
|
|
|
bool of_CVT_IR(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
|
|
|
|
double r = thr->words[cp->bit_idx[1]].w_real;
|
|
|
|
|
thr->words[cp->bit_idx[0]].w_int = (long)(r);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool of_CVT_RI(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
|
|
|
|
long r = thr->words[cp->bit_idx[1]].w_int;
|
|
|
|
|
thr->words[cp->bit_idx[0]].w_real = (double)(r);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2003-02-27 21:36:29 +01:00
|
|
|
bool of_CVT_VR(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
|
|
|
|
double r = thr->words[cp->bit_idx[1]].w_real;
|
|
|
|
|
long rl = (long)r;
|
|
|
|
|
unsigned base = cp->bit_idx[0];
|
|
|
|
|
unsigned wid = cp->number;
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < wid ; idx += 1) {
|
2005-08-27 04:34:42 +02:00
|
|
|
thr_put_bit(thr, base+idx, (rl&1)? BIT4_1 : BIT4_0);
|
2003-02-27 21:36:29 +01:00
|
|
|
rl >>= 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2004-12-11 03:31:25 +01:00
|
|
|
/*
|
|
|
|
|
* This implements the %deassign instruction. All we do is write a
|
|
|
|
|
* long(1) to port-3 of the addressed net. This turns off an active
|
|
|
|
|
* continuous assign activated by %cassign/v
|
2005-05-02 00:05:21 +02:00
|
|
|
*
|
|
|
|
|
* FIXME: This does not remove a linked %cassign/link. It should.
|
2004-12-11 03:31:25 +01:00
|
|
|
*/
|
|
|
|
|
bool of_DEASSIGN(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
|
|
|
|
vvp_net_t*net = cp->net;
|
|
|
|
|
|
|
|
|
|
vvp_net_ptr_t ptr (net, 3);
|
|
|
|
|
vvp_send_long(ptr, 1);
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2001-07-19 06:40:55 +02:00
|
|
|
bool of_DELAYX(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
|
|
|
|
unsigned long delay;
|
|
|
|
|
|
|
|
|
|
assert(cp->number < 4);
|
2003-01-26 00:48:05 +01:00
|
|
|
delay = thr->words[cp->number].w_int;
|
2001-07-19 06:40:55 +02:00
|
|
|
schedule_vthread(thr, delay);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2002-09-21 06:55:00 +02:00
|
|
|
static bool do_disable(vthread_t thr, vthread_t match)
|
|
|
|
|
{
|
|
|
|
|
bool flag = false;
|
|
|
|
|
|
|
|
|
|
/* Pull the target thread out of its scope. */
|
|
|
|
|
thr->scope_next->scope_prev = thr->scope_prev;
|
|
|
|
|
thr->scope_prev->scope_next = thr->scope_next;
|
|
|
|
|
|
|
|
|
|
/* Turn the thread off by setting is program counter to
|
|
|
|
|
zero and setting an OFF bit. */
|
2003-07-03 22:03:36 +02:00
|
|
|
thr->pc = codespace_null();
|
2002-09-21 06:55:00 +02:00
|
|
|
thr->i_have_ended = 1;
|
|
|
|
|
|
|
|
|
|
/* Turn off all the children of the thread. Simulate a %join
|
|
|
|
|
for as many times as needed to clear the results of all the
|
|
|
|
|
%forks that this thread has done. */
|
|
|
|
|
while (thr->fork_count > 0) {
|
|
|
|
|
|
|
|
|
|
vthread_t tmp = thr->child;
|
|
|
|
|
assert(tmp);
|
|
|
|
|
assert(tmp->parent == thr);
|
|
|
|
|
tmp->schedule_parent_on_end = 0;
|
|
|
|
|
if (do_disable(tmp, match))
|
|
|
|
|
flag = true;
|
|
|
|
|
|
|
|
|
|
thr->fork_count -= 1;
|
|
|
|
|
|
|
|
|
|
vthread_reap(tmp);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (thr->schedule_parent_on_end) {
|
|
|
|
|
/* If a parent is waiting in a %join, wake it up. */
|
|
|
|
|
assert(thr->parent);
|
|
|
|
|
assert(thr->parent->fork_count > 0);
|
|
|
|
|
|
|
|
|
|
thr->parent->fork_count -= 1;
|
|
|
|
|
schedule_vthread(thr->parent, 0, true);
|
|
|
|
|
vthread_reap(thr);
|
|
|
|
|
|
|
|
|
|
} else if (thr->parent) {
|
|
|
|
|
/* If the parent is yet to %join me, let its %join
|
|
|
|
|
do the reaping. */
|
|
|
|
|
//assert(tmp->is_scheduled == 0);
|
|
|
|
|
|
|
|
|
|
} else {
|
2003-02-10 00:33:26 +01:00
|
|
|
/* No parent at all. Goodbye. */
|
2002-09-21 06:55:00 +02:00
|
|
|
vthread_reap(thr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return flag || (thr == match);
|
|
|
|
|
}
|
|
|
|
|
|
2001-04-18 06:21:23 +02:00
|
|
|
/*
|
|
|
|
|
* Implement the %disable instruction by scanning the target scope for
|
|
|
|
|
* all the target threads. Kill the target threads and wake up a
|
|
|
|
|
* parent that is attempting a %join.
|
|
|
|
|
*/
|
|
|
|
|
bool of_DISABLE(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
|
|
|
|
struct __vpiScope*scope = (struct __vpiScope*)cp->handle;
|
|
|
|
|
if (scope->threads == 0)
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
struct vthread_s*head = scope->threads;
|
|
|
|
|
|
2002-05-27 02:53:10 +02:00
|
|
|
bool disabled_myself_flag = false;
|
|
|
|
|
|
2001-04-18 06:21:23 +02:00
|
|
|
while (head->scope_next != head) {
|
|
|
|
|
vthread_t tmp = head->scope_next;
|
|
|
|
|
|
2002-05-27 02:53:10 +02:00
|
|
|
/* If I am disabling myself, that remember that fact so
|
|
|
|
|
that I can finish this statement differently. */
|
|
|
|
|
if (tmp == thr)
|
|
|
|
|
disabled_myself_flag = true;
|
|
|
|
|
|
2001-04-21 02:34:39 +02:00
|
|
|
|
2002-09-21 06:55:00 +02:00
|
|
|
if (do_disable(tmp, thr))
|
|
|
|
|
disabled_myself_flag = true;
|
2001-04-18 06:21:23 +02:00
|
|
|
}
|
|
|
|
|
|
2002-05-27 02:53:10 +02:00
|
|
|
return ! disabled_myself_flag;
|
2001-04-18 06:21:23 +02:00
|
|
|
}
|
|
|
|
|
|
2002-04-14 20:41:34 +02:00
|
|
|
static void divide_bits(unsigned len, unsigned char*lbits,
|
|
|
|
|
const unsigned char*rbits)
|
|
|
|
|
{
|
|
|
|
|
unsigned char *a, *b, *z, *t;
|
|
|
|
|
a = new unsigned char[len+1];
|
|
|
|
|
b = new unsigned char[len+1];
|
|
|
|
|
z = new unsigned char[len+1];
|
|
|
|
|
t = new unsigned char[len+1];
|
|
|
|
|
|
|
|
|
|
unsigned char carry;
|
|
|
|
|
unsigned char temp;
|
|
|
|
|
|
|
|
|
|
int mxa = -1, mxz = -1;
|
|
|
|
|
int i;
|
|
|
|
|
int current, copylen;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < len ; idx += 1) {
|
|
|
|
|
unsigned lb = lbits[idx];
|
|
|
|
|
unsigned rb = rbits[idx];
|
|
|
|
|
|
|
|
|
|
z[idx]=lb;
|
|
|
|
|
a[idx]=1-rb; // for 2s complement add..
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
z[len]=0;
|
|
|
|
|
a[len]=1;
|
|
|
|
|
|
|
|
|
|
for(i=0;i<(int)len+1;i++) {
|
|
|
|
|
b[i]=0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for(i=len-1;i>=0;i--) {
|
|
|
|
|
if(!a[i]) {
|
|
|
|
|
mxa=i;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2004-10-04 03:10:51 +02:00
|
|
|
|
2002-04-14 20:41:34 +02:00
|
|
|
for(i=len-1;i>=0;i--) {
|
|
|
|
|
if(z[i]) {
|
|
|
|
|
mxz=i;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if((mxa>mxz)||(mxa==-1)) {
|
|
|
|
|
if(mxa==-1) {
|
|
|
|
|
fprintf(stderr, "Division By Zero error, exiting.\n");
|
|
|
|
|
exit(255);
|
|
|
|
|
}
|
2004-10-04 03:10:51 +02:00
|
|
|
|
2002-04-14 20:41:34 +02:00
|
|
|
goto tally;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
copylen = mxa + 2;
|
2004-10-04 03:10:51 +02:00
|
|
|
current = mxz - mxa;
|
|
|
|
|
|
2002-04-14 20:41:34 +02:00
|
|
|
while(current > -1) {
|
|
|
|
|
carry = 1;
|
|
|
|
|
for(i=0;i<copylen;i++) {
|
|
|
|
|
temp = z[i+current] + a[i] + carry;
|
|
|
|
|
t[i] = (temp&1);
|
|
|
|
|
carry = (temp>>1);
|
|
|
|
|
}
|
2004-10-04 03:10:51 +02:00
|
|
|
|
2002-04-14 20:41:34 +02:00
|
|
|
if(carry) {
|
|
|
|
|
for(i=0;i<copylen;i++) {
|
|
|
|
|
z[i+current] = t[i];
|
|
|
|
|
}
|
|
|
|
|
b[current] = 1;
|
|
|
|
|
}
|
2004-10-04 03:10:51 +02:00
|
|
|
|
2002-04-14 20:41:34 +02:00
|
|
|
current--;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tally:
|
|
|
|
|
for (unsigned idx = 0 ; idx < len ; idx += 1) {
|
|
|
|
|
// n.b., z[] has the remainder...
|
|
|
|
|
lbits[idx] = b[idx];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
delete []t;
|
|
|
|
|
delete []z;
|
|
|
|
|
delete []b;
|
|
|
|
|
delete []a;
|
|
|
|
|
}
|
|
|
|
|
|
2001-10-16 03:26:54 +02:00
|
|
|
bool of_DIV(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
2001-11-01 04:00:19 +01:00
|
|
|
assert(cp->bit_idx[0] >= 4);
|
2001-10-16 03:26:54 +02:00
|
|
|
|
|
|
|
|
if(cp->number <= 8*sizeof(unsigned long)) {
|
2001-11-01 04:00:19 +01:00
|
|
|
unsigned idx1 = cp->bit_idx[0];
|
|
|
|
|
unsigned idx2 = cp->bit_idx[1];
|
2001-10-16 03:26:54 +02:00
|
|
|
unsigned long lv = 0, rv = 0;
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < cp->number ; idx += 1) {
|
2005-08-27 04:34:42 +02:00
|
|
|
vvp_bit4_t lb = thr_get_bit(thr, idx1);
|
|
|
|
|
vvp_bit4_t rb = thr_get_bit(thr, idx2);
|
2001-10-16 03:26:54 +02:00
|
|
|
|
2005-08-27 04:34:42 +02:00
|
|
|
if (bit4_is_xz(lb) || bit4_is_xz(rb))
|
2001-10-16 03:26:54 +02:00
|
|
|
goto x_out;
|
|
|
|
|
|
|
|
|
|
lv |= lb << idx;
|
|
|
|
|
rv |= rb << idx;
|
|
|
|
|
|
|
|
|
|
idx1 += 1;
|
|
|
|
|
if (idx2 >= 4)
|
|
|
|
|
idx2 += 1;
|
|
|
|
|
}
|
|
|
|
|
|
2005-08-27 04:34:42 +02:00
|
|
|
if (rv == BIT4_0)
|
2001-10-21 01:20:32 +02:00
|
|
|
goto x_out;
|
|
|
|
|
|
2001-10-16 03:26:54 +02:00
|
|
|
lv /= rv;
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < cp->number ; idx += 1) {
|
2005-08-27 04:34:42 +02:00
|
|
|
thr_put_bit(thr, cp->bit_idx[0]+idx, (lv&1) ? BIT4_1 : BIT4_0);
|
2001-10-16 03:26:54 +02:00
|
|
|
lv >>= 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
2002-04-14 20:41:34 +02:00
|
|
|
/* Make a string of the bits of the numbers to be
|
|
|
|
|
divided. Then divide them, and write the results into
|
|
|
|
|
the thread. */
|
|
|
|
|
unsigned char*lbits = new unsigned char[cp->number];
|
|
|
|
|
unsigned char*rbits = new unsigned char[cp->number];
|
|
|
|
|
unsigned idx1 = cp->bit_idx[0];
|
|
|
|
|
unsigned idx2 = cp->bit_idx[1];
|
2002-05-24 06:55:13 +02:00
|
|
|
bool rval_is_zero = true;
|
2002-04-14 20:41:34 +02:00
|
|
|
for (unsigned idx = 0 ; idx < cp->number ; idx += 1) {
|
|
|
|
|
lbits[idx] = thr_get_bit(thr, idx1);
|
|
|
|
|
rbits[idx] = thr_get_bit(thr, idx2);
|
|
|
|
|
if ((lbits[idx] | rbits[idx]) > 1) {
|
|
|
|
|
delete[]lbits;
|
|
|
|
|
delete[]rbits;
|
|
|
|
|
goto x_out;
|
|
|
|
|
}
|
|
|
|
|
|
2002-05-24 06:55:13 +02:00
|
|
|
if (rbits[idx] != 0)
|
|
|
|
|
rval_is_zero = false;
|
|
|
|
|
|
2002-04-14 20:41:34 +02:00
|
|
|
idx1 += 1;
|
|
|
|
|
if (idx2 >= 4)
|
|
|
|
|
idx2 += 1;
|
|
|
|
|
}
|
|
|
|
|
|
2002-05-24 06:55:13 +02:00
|
|
|
/* Notice the special case of divide by 0. */
|
|
|
|
|
if (rval_is_zero) {
|
|
|
|
|
delete[]lbits;
|
|
|
|
|
delete[]rbits;
|
|
|
|
|
goto x_out;
|
|
|
|
|
}
|
|
|
|
|
|
2002-04-14 20:41:34 +02:00
|
|
|
divide_bits(cp->number, lbits, rbits);
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < cp->number ; idx += 1) {
|
2005-08-27 04:34:42 +02:00
|
|
|
thr_put_bit(thr, cp->bit_idx[0]+idx, lbits[idx]?BIT4_1:BIT4_0);
|
2002-04-14 20:41:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
delete[]lbits;
|
|
|
|
|
delete[]rbits;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2001-10-16 03:26:54 +02:00
|
|
|
|
2002-04-14 20:41:34 +02:00
|
|
|
x_out:
|
|
|
|
|
for (unsigned idx = 0 ; idx < cp->number ; idx += 1)
|
2005-08-27 04:34:42 +02:00
|
|
|
thr_put_bit(thr, cp->bit_idx[0]+idx, BIT4_X);
|
2001-10-16 03:26:54 +02:00
|
|
|
|
2002-04-14 20:41:34 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
2001-10-16 03:26:54 +02:00
|
|
|
|
2002-04-14 20:41:34 +02:00
|
|
|
static void negate_bits(unsigned len, unsigned char*bits)
|
|
|
|
|
{
|
|
|
|
|
unsigned char carry = 1;
|
|
|
|
|
for (unsigned idx = 0 ; idx < len ; idx += 1) {
|
|
|
|
|
carry += bits[idx]? 0 : 1;
|
|
|
|
|
bits[idx] = carry & 1;
|
|
|
|
|
carry >>= 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool of_DIV_S(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
|
|
|
|
assert(cp->bit_idx[0] >= 4);
|
|
|
|
|
|
|
|
|
|
if(cp->number <= 8*sizeof(long)) {
|
2001-11-01 04:00:19 +01:00
|
|
|
unsigned idx1 = cp->bit_idx[0];
|
|
|
|
|
unsigned idx2 = cp->bit_idx[1];
|
2002-04-14 20:41:34 +02:00
|
|
|
long lv = 0, rv = 0;
|
2001-10-16 03:26:54 +02:00
|
|
|
|
2002-04-14 20:41:34 +02:00
|
|
|
unsigned lb = 0;
|
|
|
|
|
unsigned rb = 0;
|
2001-10-16 03:26:54 +02:00
|
|
|
for (unsigned idx = 0 ; idx < cp->number ; idx += 1) {
|
2002-04-14 20:41:34 +02:00
|
|
|
lb = thr_get_bit(thr, idx1);
|
|
|
|
|
rb = thr_get_bit(thr, idx2);
|
2001-10-16 03:26:54 +02:00
|
|
|
|
2002-04-14 20:41:34 +02:00
|
|
|
if ((lb | rb) & 2)
|
2001-10-16 03:26:54 +02:00
|
|
|
goto x_out;
|
|
|
|
|
|
2002-04-14 20:41:34 +02:00
|
|
|
lv |= (long)lb << idx;
|
|
|
|
|
rv |= (long)rb << idx;
|
2001-10-16 03:26:54 +02:00
|
|
|
|
|
|
|
|
idx1 += 1;
|
|
|
|
|
if (idx2 >= 4)
|
|
|
|
|
idx2 += 1;
|
|
|
|
|
}
|
|
|
|
|
|
2002-04-14 20:41:34 +02:00
|
|
|
/* Extend the sign to fill the native long. */
|
|
|
|
|
for (unsigned idx = cp->number; idx < (8*sizeof lv); idx += 1) {
|
|
|
|
|
lv |= (long)lb << idx;
|
|
|
|
|
rv |= (long)rb << idx;
|
2001-10-16 03:26:54 +02:00
|
|
|
}
|
|
|
|
|
|
2002-04-14 20:41:34 +02:00
|
|
|
if (rv == 0)
|
|
|
|
|
goto x_out;
|
|
|
|
|
|
|
|
|
|
lv /= rv;
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < cp->number ; idx += 1) {
|
2005-08-27 04:34:42 +02:00
|
|
|
thr_put_bit(thr, cp->bit_idx[0]+idx, (lv&1)?BIT4_1:BIT4_0);
|
2002-04-14 20:41:34 +02:00
|
|
|
lv >>= 1;
|
2001-10-16 03:26:54 +02:00
|
|
|
}
|
2002-04-14 20:41:34 +02:00
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
unsigned char*lbits = new unsigned char[cp->number];
|
|
|
|
|
unsigned char*rbits = new unsigned char[cp->number];
|
|
|
|
|
unsigned idx1 = cp->bit_idx[0];
|
|
|
|
|
unsigned idx2 = cp->bit_idx[1];
|
2002-05-24 06:55:13 +02:00
|
|
|
bool rval_is_zero = true;
|
2002-04-14 20:41:34 +02:00
|
|
|
for (unsigned idx = 0 ; idx < cp->number ; idx += 1) {
|
|
|
|
|
lbits[idx] = thr_get_bit(thr, idx1);
|
|
|
|
|
rbits[idx] = thr_get_bit(thr, idx2);
|
|
|
|
|
if ((lbits[idx] | rbits[idx]) > 1) {
|
|
|
|
|
delete[]lbits;
|
|
|
|
|
delete[]rbits;
|
|
|
|
|
goto x_out;
|
2001-10-16 03:26:54 +02:00
|
|
|
}
|
2002-04-14 20:41:34 +02:00
|
|
|
|
2002-05-24 06:55:13 +02:00
|
|
|
if (rbits[idx] != 0)
|
|
|
|
|
rval_is_zero = false;
|
|
|
|
|
|
2002-04-14 20:41:34 +02:00
|
|
|
idx1 += 1;
|
|
|
|
|
if (idx2 >= 4)
|
|
|
|
|
idx2 += 1;
|
2001-10-16 03:26:54 +02:00
|
|
|
}
|
|
|
|
|
|
2002-05-24 06:55:13 +02:00
|
|
|
/* Notice the special case of divide by 0. */
|
|
|
|
|
if (rval_is_zero) {
|
|
|
|
|
delete[]lbits;
|
|
|
|
|
delete[]rbits;
|
|
|
|
|
goto x_out;
|
|
|
|
|
}
|
|
|
|
|
|
2002-04-14 20:41:34 +02:00
|
|
|
/* Signed division is unsigned division on the absolute
|
|
|
|
|
values of the operands, then corrected for the number
|
|
|
|
|
of signs. */
|
|
|
|
|
unsigned sign_flag = 0;
|
|
|
|
|
if (lbits[cp->number-1]) {
|
|
|
|
|
sign_flag += 1;
|
|
|
|
|
negate_bits(cp->number, lbits);
|
|
|
|
|
}
|
|
|
|
|
if (rbits[cp->number-1]) {
|
|
|
|
|
sign_flag += 1;
|
|
|
|
|
negate_bits(cp->number, rbits);
|
2001-10-16 03:26:54 +02:00
|
|
|
}
|
|
|
|
|
|
2002-04-14 20:41:34 +02:00
|
|
|
divide_bits(cp->number, lbits, rbits);
|
|
|
|
|
|
|
|
|
|
if (sign_flag & 1) {
|
|
|
|
|
negate_bits(cp->number, lbits);
|
2001-10-16 03:26:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < cp->number ; idx += 1) {
|
2005-08-27 04:34:42 +02:00
|
|
|
thr_put_bit(thr, cp->bit_idx[0]+idx, lbits[idx]?BIT4_1:BIT4_0);
|
2001-10-16 03:26:54 +02:00
|
|
|
}
|
|
|
|
|
|
2002-04-14 20:41:34 +02:00
|
|
|
delete[]lbits;
|
|
|
|
|
delete[]rbits;
|
2001-10-16 03:26:54 +02:00
|
|
|
}
|
|
|
|
|
|
2002-04-14 20:41:34 +02:00
|
|
|
return true;
|
|
|
|
|
|
2001-10-16 03:26:54 +02:00
|
|
|
x_out:
|
|
|
|
|
for (unsigned idx = 0 ; idx < cp->number ; idx += 1)
|
2005-08-27 04:34:42 +02:00
|
|
|
thr_put_bit(thr, cp->bit_idx[0]+idx, BIT4_X);
|
2001-10-16 03:26:54 +02:00
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2003-03-28 03:33:56 +01:00
|
|
|
bool of_DIV_WR(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
|
|
|
|
double l = thr->words[cp->bit_idx[0]].w_real;
|
|
|
|
|
double r = thr->words[cp->bit_idx[1]].w_real;
|
|
|
|
|
thr->words[cp->bit_idx[0]].w_real = l / r;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2001-04-13 05:55:18 +02:00
|
|
|
/*
|
|
|
|
|
* This terminates the current thread. If there is a parent who is
|
|
|
|
|
* waiting for me to die, then I schedule it. At any rate, I mark
|
|
|
|
|
* myself as a zombie by setting my pc to 0.
|
2001-07-20 06:57:00 +02:00
|
|
|
*
|
|
|
|
|
* It is possible for this thread to have children at this %end. This
|
|
|
|
|
* means that my child is really my sibling created by my parent, and
|
|
|
|
|
* my parent will do the proper %joins in due course. For example:
|
|
|
|
|
*
|
|
|
|
|
* %fork child_1, test;
|
|
|
|
|
* %fork child_2, test;
|
|
|
|
|
* ... parent code ...
|
|
|
|
|
* %join;
|
|
|
|
|
* %join;
|
|
|
|
|
* %end;
|
|
|
|
|
*
|
|
|
|
|
* child_1 ;
|
|
|
|
|
* %end;
|
|
|
|
|
* child_2 ;
|
|
|
|
|
* %end;
|
|
|
|
|
*
|
|
|
|
|
* In this example, the main thread creates threads child_1 and
|
|
|
|
|
* child_2. It is possible that this thread is child_2, so there is a
|
|
|
|
|
* parent pointer and a child pointer, even though I did no
|
|
|
|
|
* %forks or %joins. This means that I have a ->child pointer and a
|
|
|
|
|
* ->parent pointer.
|
|
|
|
|
*
|
|
|
|
|
* If the main thread has executed the first %join, then it is waiting
|
|
|
|
|
* for me, and I will be reaped right away.
|
|
|
|
|
*
|
|
|
|
|
* If the main thread has not executed a %join yet, then this thread
|
|
|
|
|
* becomes a zombie. The main thread executes its %join eventually,
|
|
|
|
|
* reaping me at that time.
|
|
|
|
|
*
|
|
|
|
|
* It does not matter the order that child_1 and child_2 threads call
|
|
|
|
|
* %end -- child_2 will be reaped by the first %join, and child_1 will
|
|
|
|
|
* be reaped by the second %join.
|
2001-04-13 05:55:18 +02:00
|
|
|
*/
|
2001-04-18 06:21:23 +02:00
|
|
|
bool of_END(vthread_t thr, vvp_code_t)
|
2001-03-11 01:29:38 +01:00
|
|
|
{
|
2001-04-13 05:55:18 +02:00
|
|
|
assert(! thr->waiting_for_event);
|
2002-09-21 06:55:00 +02:00
|
|
|
assert( thr->fork_count == 0 );
|
2001-04-13 05:55:18 +02:00
|
|
|
thr->i_have_ended = 1;
|
2003-07-03 22:03:36 +02:00
|
|
|
thr->pc = codespace_null();
|
2001-04-13 05:55:18 +02:00
|
|
|
|
|
|
|
|
/* If I have a parent who is waiting for me, then mark that I
|
2001-04-18 07:04:19 +02:00
|
|
|
have ended, and schedule that parent. Also, finish the
|
|
|
|
|
%join for the parent. */
|
2001-04-13 05:55:18 +02:00
|
|
|
if (thr->schedule_parent_on_end) {
|
|
|
|
|
assert(thr->parent);
|
2002-09-21 06:55:00 +02:00
|
|
|
assert(thr->parent->fork_count > 0);
|
|
|
|
|
|
|
|
|
|
thr->parent->fork_count -= 1;
|
2002-05-13 01:44:41 +02:00
|
|
|
schedule_vthread(thr->parent, 0, true);
|
2001-04-18 07:04:19 +02:00
|
|
|
vthread_reap(thr);
|
2001-04-13 05:55:18 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If I have no parents, then no one can %join me and there is
|
|
|
|
|
no reason to stick around. This can happen, for example if
|
2001-07-20 06:57:00 +02:00
|
|
|
I am an ``initial'' thread.
|
|
|
|
|
|
|
|
|
|
If I have children at this point, then I must have been the
|
|
|
|
|
main thread (there is no other parent) and an error (not
|
|
|
|
|
enough %joins) has been detected. */
|
2001-04-13 05:55:18 +02:00
|
|
|
if (thr->parent == 0) {
|
2001-07-20 06:57:00 +02:00
|
|
|
assert(thr->child == 0);
|
2001-04-13 05:55:18 +02:00
|
|
|
vthread_reap(thr);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If I make it this far, then I have a parent who may wish
|
|
|
|
|
to %join me. Remain a zombie so that it can. */
|
|
|
|
|
|
2001-03-11 01:29:38 +01:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2005-06-02 18:02:11 +02:00
|
|
|
/*
|
|
|
|
|
* the %force/link instruction connects a source node to a
|
|
|
|
|
* destination node. The destination node must be a signal, as it is
|
|
|
|
|
* marked with the source of the force so that it may later be
|
|
|
|
|
* unlinked without specifically knowing the source that this
|
|
|
|
|
* instruction used.
|
|
|
|
|
*/
|
|
|
|
|
bool of_FORCE_LINK(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
|
|
|
|
vvp_net_t*dst = cp->net;
|
|
|
|
|
vvp_net_t*src = cp->net2;
|
|
|
|
|
|
2005-11-25 18:55:26 +01:00
|
|
|
vvp_fun_signal_base*sig
|
|
|
|
|
= reinterpret_cast<vvp_fun_signal_base*>(dst->fun);
|
2005-06-02 18:02:11 +02:00
|
|
|
assert(sig);
|
|
|
|
|
|
|
|
|
|
/* Detect the special case that we are already forced the
|
|
|
|
|
source onto the destination. */
|
|
|
|
|
if (sig->force_link == src)
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
/* FIXME: Don't yet support changing the force. */
|
|
|
|
|
assert(sig->force_link == 0);
|
|
|
|
|
sig->force_link = src;
|
|
|
|
|
|
|
|
|
|
/* Link the output of the src to the port[2] (the force
|
|
|
|
|
port) of the destination. */
|
|
|
|
|
vvp_net_ptr_t dst_ptr (dst, 2);
|
|
|
|
|
dst->port[2] = src->out;
|
|
|
|
|
src->out = dst_ptr;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2004-12-15 18:17:42 +01:00
|
|
|
/*
|
|
|
|
|
* The %force/v instruction invokes a force assign of a constant value
|
|
|
|
|
* to a signal. The instruction arguments are:
|
|
|
|
|
*
|
|
|
|
|
* %force/v <net>, <base>, <wid> ;
|
|
|
|
|
*
|
|
|
|
|
* where the <net> is the net label assembled into a vvp_net pointer,
|
|
|
|
|
* and the <base> and <wid> are stashed in the bit_idx array.
|
|
|
|
|
*
|
|
|
|
|
* The instruction writes a vvp_vector4_t value to port-2 of the
|
|
|
|
|
* target signal.
|
|
|
|
|
*/
|
|
|
|
|
bool of_FORCE_V(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
|
|
|
|
vvp_net_t*net = cp->net;
|
|
|
|
|
unsigned base = cp->bit_idx[0];
|
|
|
|
|
unsigned wid = cp->bit_idx[1];
|
|
|
|
|
|
|
|
|
|
/* Collect the thread bits into a vector4 item. */
|
|
|
|
|
vvp_vector4_t value = vthread_bits_to_vector(thr, base, wid);
|
|
|
|
|
|
|
|
|
|
/* set the value into port 1 of the destination. */
|
|
|
|
|
vvp_net_ptr_t ptr (net, 2);
|
|
|
|
|
vvp_send_vec4(ptr, value);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2005-11-26 18:16:05 +01:00
|
|
|
bool of_FORCE_X0(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
|
|
|
|
vvp_net_t*net = cp->net;
|
|
|
|
|
unsigned bit = cp->bit_idx[0];
|
|
|
|
|
unsigned wid = cp->bit_idx[1];
|
|
|
|
|
|
|
|
|
|
// Implicitly, we get the base into the target vector from the
|
|
|
|
|
// X0 register.
|
|
|
|
|
long index = thr->words[0].w_int;
|
|
|
|
|
|
|
|
|
|
vvp_fun_signal_vec*sig = dynamic_cast<vvp_fun_signal_vec*> (net->fun);
|
|
|
|
|
|
|
|
|
|
if (index < 0 && (wid <= (unsigned)-index))
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
if (index >= (long)sig->size())
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
if (index < 0) {
|
|
|
|
|
wid -= (unsigned) -index;
|
|
|
|
|
index = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (index+wid > sig->size())
|
|
|
|
|
wid = sig->size() - index;
|
|
|
|
|
|
|
|
|
|
vvp_vector4_t bit_vec(wid);
|
|
|
|
|
for (unsigned idx = 0 ; idx < wid ; idx += 1) {
|
|
|
|
|
vvp_bit4_t bit_val = thr_get_bit(thr, bit);
|
|
|
|
|
bit_vec.set_bit(idx, bit_val);
|
|
|
|
|
if (bit >= 4)
|
|
|
|
|
bit += 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vvp_net_ptr_t ptr (net, 2);
|
|
|
|
|
vvp_send_vec4_pv(ptr, bit_vec, index, wid, sig->size());
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2001-04-13 05:55:18 +02:00
|
|
|
/*
|
|
|
|
|
* The %fork instruction causes a new child to be created and pushed
|
|
|
|
|
* in front of any existing child. This causes the new child to be the
|
|
|
|
|
* parent of any previous children, and for me to be the parent of the
|
|
|
|
|
* new child.
|
|
|
|
|
*/
|
2001-03-30 06:55:22 +02:00
|
|
|
bool of_FORK(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
2001-11-01 04:00:19 +01:00
|
|
|
vthread_t child = vthread_new(cp->cptr2, cp->scope);
|
2001-04-13 05:55:18 +02:00
|
|
|
|
|
|
|
|
child->child = thr->child;
|
|
|
|
|
child->parent = thr;
|
2001-03-30 06:55:22 +02:00
|
|
|
thr->child = child;
|
2001-04-13 05:55:18 +02:00
|
|
|
if (child->child) {
|
|
|
|
|
assert(child->child->parent == thr);
|
|
|
|
|
child->child->parent = child;
|
|
|
|
|
}
|
2002-09-21 06:55:00 +02:00
|
|
|
|
|
|
|
|
thr->fork_count += 1;
|
|
|
|
|
|
2002-05-13 01:44:41 +02:00
|
|
|
schedule_vthread(child, 0, true);
|
2001-03-30 06:55:22 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2001-03-22 06:08:00 +01:00
|
|
|
bool of_INV(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
2001-11-01 04:00:19 +01:00
|
|
|
assert(cp->bit_idx[0] >= 4);
|
|
|
|
|
for (unsigned idx = 0 ; idx < cp->bit_idx[1] ; idx += 1) {
|
2005-02-12 07:13:22 +01:00
|
|
|
vvp_bit4_t val = thr_get_bit(thr, cp->bit_idx[0]+idx);
|
2001-03-22 06:08:00 +01:00
|
|
|
switch (val) {
|
2005-02-12 07:13:22 +01:00
|
|
|
case BIT4_0:
|
|
|
|
|
val = BIT4_1;
|
2001-03-22 06:08:00 +01:00
|
|
|
break;
|
2005-02-12 07:13:22 +01:00
|
|
|
case BIT4_1:
|
|
|
|
|
val = BIT4_0;
|
2001-03-22 06:08:00 +01:00
|
|
|
break;
|
|
|
|
|
default:
|
2005-02-12 07:13:22 +01:00
|
|
|
val = BIT4_X;
|
2001-03-22 06:08:00 +01:00
|
|
|
break;
|
|
|
|
|
}
|
2001-11-01 04:00:19 +01:00
|
|
|
thr_put_bit(thr, cp->bit_idx[0]+idx, val);
|
2001-03-22 06:08:00 +01:00
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2001-05-01 03:09:39 +02:00
|
|
|
|
|
|
|
|
/*
|
2001-05-03 01:16:50 +02:00
|
|
|
** Index registers, unsigned arithmetic.
|
2001-05-01 03:09:39 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
bool of_IX_ADD(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
2003-01-26 00:48:05 +01:00
|
|
|
thr->words[cp->bit_idx[0] & 3].w_int += cp->number;
|
2001-05-03 01:16:50 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool of_IX_SUB(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
2003-01-26 00:48:05 +01:00
|
|
|
thr->words[cp->bit_idx[0] & 3].w_int -= cp->number;
|
2001-05-01 03:09:39 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool of_IX_MUL(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
2003-01-26 00:48:05 +01:00
|
|
|
thr->words[cp->bit_idx[0] & 3].w_int *= cp->number;
|
2001-05-01 03:09:39 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool of_IX_LOAD(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
2003-01-26 00:48:05 +01:00
|
|
|
thr->words[cp->bit_idx[0] & 3].w_int = cp->number;
|
2001-05-01 07:00:02 +02:00
|
|
|
return true;
|
2001-05-01 03:09:39 +02:00
|
|
|
}
|
|
|
|
|
|
2002-08-18 03:05:50 +02:00
|
|
|
/*
|
|
|
|
|
* Load a vector into an index register. The format of the
|
|
|
|
|
* opcode is:
|
|
|
|
|
*
|
|
|
|
|
* %ix/get <ix>, <base>, <wid>
|
|
|
|
|
*
|
|
|
|
|
* where <ix> is the index register, <base> is the base of the
|
|
|
|
|
* vector and <wid> is the width in bits.
|
|
|
|
|
*
|
|
|
|
|
* Index registers only hold binary values, so if any of the
|
2002-08-27 07:39:57 +02:00
|
|
|
* bits of the vector are x or z, then set the value to 0,
|
|
|
|
|
* set bit[4] to 1, and give up.
|
2002-08-18 03:05:50 +02:00
|
|
|
*/
|
2001-05-06 19:42:22 +02:00
|
|
|
bool of_IX_GET(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
2005-01-28 06:34:25 +01:00
|
|
|
unsigned index = cp->bit_idx[0];
|
|
|
|
|
unsigned base = cp->bit_idx[1];
|
|
|
|
|
unsigned width = cp->number;
|
|
|
|
|
|
2001-05-06 19:42:22 +02:00
|
|
|
unsigned long v = 0;
|
2002-08-27 07:39:57 +02:00
|
|
|
bool unknown_flag = false;
|
|
|
|
|
|
2005-01-28 06:34:25 +01:00
|
|
|
for (unsigned i = 0 ; i<width ; i += 1) {
|
2005-08-27 04:34:42 +02:00
|
|
|
vvp_bit4_t vv = thr_get_bit(thr, base);
|
|
|
|
|
if (bit4_is_xz(vv)) {
|
2002-08-18 03:05:50 +02:00
|
|
|
v = 0UL;
|
2002-08-27 07:39:57 +02:00
|
|
|
unknown_flag = true;
|
2001-05-06 19:42:22 +02:00
|
|
|
break;
|
|
|
|
|
}
|
2005-01-28 06:34:25 +01:00
|
|
|
|
2001-05-06 19:42:22 +02:00
|
|
|
v |= vv << i;
|
2005-01-28 06:34:25 +01:00
|
|
|
|
|
|
|
|
if (base >= 4)
|
|
|
|
|
base += 1;
|
2001-05-06 19:42:22 +02:00
|
|
|
}
|
2005-01-28 06:34:25 +01:00
|
|
|
thr->words[index].w_int = v;
|
|
|
|
|
|
2002-08-27 07:39:57 +02:00
|
|
|
/* Set bit 4 as a flag if the input is unknown. */
|
2005-08-27 04:34:42 +02:00
|
|
|
thr_put_bit(thr, 4, unknown_flag? BIT4_1 : BIT4_0);
|
2005-01-28 06:34:25 +01:00
|
|
|
|
2001-05-06 19:42:22 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2001-05-01 03:09:39 +02:00
|
|
|
|
2001-04-13 05:55:18 +02:00
|
|
|
/*
|
|
|
|
|
* The various JMP instruction work simply by pulling the new program
|
|
|
|
|
* counter from the instruction and resuming. If the jump is
|
|
|
|
|
* conditional, then test the bit for the expected value first.
|
|
|
|
|
*/
|
2001-03-20 07:16:23 +01:00
|
|
|
bool of_JMP(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
|
|
|
|
thr->pc = cp->cptr;
|
2003-02-22 03:52:06 +01:00
|
|
|
|
|
|
|
|
/* Normally, this returns true so that the processor just
|
|
|
|
|
keeps going to the next instruction. However, if there was
|
|
|
|
|
a $stop or vpiStop, returning false here can break the
|
|
|
|
|
simulation out of a hung loop. */
|
2003-02-22 07:26:58 +01:00
|
|
|
if (schedule_stopped()) {
|
|
|
|
|
schedule_vthread(thr, 0, false);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
2001-03-20 07:16:23 +01:00
|
|
|
}
|
|
|
|
|
|
2001-03-22 06:08:00 +01:00
|
|
|
bool of_JMP0(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
2001-11-01 04:00:19 +01:00
|
|
|
if (thr_get_bit(thr, cp->bit_idx[0]) == 0)
|
2001-03-22 06:08:00 +01:00
|
|
|
thr->pc = cp->cptr;
|
2003-02-22 03:52:06 +01:00
|
|
|
|
|
|
|
|
/* Normally, this returns true so that the processor just
|
|
|
|
|
keeps going to the next instruction. However, if there was
|
|
|
|
|
a $stop or vpiStop, returning false here can break the
|
|
|
|
|
simulation out of a hung loop. */
|
2003-02-22 07:26:58 +01:00
|
|
|
if (schedule_stopped()) {
|
|
|
|
|
schedule_vthread(thr, 0, false);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
2001-03-22 06:08:00 +01:00
|
|
|
}
|
|
|
|
|
|
2001-03-25 05:54:26 +02:00
|
|
|
bool of_JMP0XZ(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
2005-08-27 05:28:57 +02:00
|
|
|
if (thr_get_bit(thr, cp->bit_idx[0]) != BIT4_1)
|
2001-03-25 05:54:26 +02:00
|
|
|
thr->pc = cp->cptr;
|
2003-02-22 03:52:06 +01:00
|
|
|
|
|
|
|
|
/* Normally, this returns true so that the processor just
|
|
|
|
|
keeps going to the next instruction. However, if there was
|
|
|
|
|
a $stop or vpiStop, returning false here can break the
|
|
|
|
|
simulation out of a hung loop. */
|
2003-02-22 07:26:58 +01:00
|
|
|
if (schedule_stopped()) {
|
|
|
|
|
schedule_vthread(thr, 0, false);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
2001-03-25 05:54:26 +02:00
|
|
|
}
|
|
|
|
|
|
2001-03-31 19:36:02 +02:00
|
|
|
bool of_JMP1(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
2001-11-01 04:00:19 +01:00
|
|
|
if (thr_get_bit(thr, cp->bit_idx[0]) == 1)
|
2001-03-31 19:36:02 +02:00
|
|
|
thr->pc = cp->cptr;
|
2003-02-22 03:52:06 +01:00
|
|
|
|
|
|
|
|
/* Normally, this returns true so that the processor just
|
|
|
|
|
keeps going to the next instruction. However, if there was
|
|
|
|
|
a $stop or vpiStop, returning false here can break the
|
|
|
|
|
simulation out of a hung loop. */
|
2003-02-22 07:26:58 +01:00
|
|
|
if (schedule_stopped()) {
|
|
|
|
|
schedule_vthread(thr, 0, false);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
2001-03-31 19:36:02 +02:00
|
|
|
}
|
|
|
|
|
|
2001-04-13 05:55:18 +02:00
|
|
|
/*
|
|
|
|
|
* The %join instruction causes the thread to wait for the one and
|
|
|
|
|
* only child to die. If it is already dead (and a zombie) then I
|
|
|
|
|
* reap it and go on. Otherwise, I tell the child that I am ready for
|
|
|
|
|
* it to die, and it will reschedule me when it does.
|
|
|
|
|
*/
|
2001-03-30 06:55:22 +02:00
|
|
|
bool of_JOIN(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
|
|
|
|
assert(thr->child);
|
2001-04-13 05:55:18 +02:00
|
|
|
assert(thr->child->parent == thr);
|
2001-04-18 06:21:23 +02:00
|
|
|
|
2002-09-21 06:55:00 +02:00
|
|
|
assert(thr->fork_count > 0);
|
|
|
|
|
|
|
|
|
|
|
2001-04-18 06:21:23 +02:00
|
|
|
/* If the child has already ended, reap it now. */
|
2001-04-13 05:55:18 +02:00
|
|
|
if (thr->child->i_have_ended) {
|
2002-09-21 06:55:00 +02:00
|
|
|
thr->fork_count -= 1;
|
2001-03-30 06:55:22 +02:00
|
|
|
vthread_reap(thr->child);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2001-04-18 06:21:23 +02:00
|
|
|
/* Otherwise, I get to start waiting. */
|
2001-04-13 05:55:18 +02:00
|
|
|
thr->child->schedule_parent_on_end = 1;
|
2001-03-30 06:55:22 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2001-05-01 03:09:39 +02:00
|
|
|
bool of_LOAD_MEM(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
2005-03-03 05:33:10 +01:00
|
|
|
#if 0
|
2001-11-01 04:00:19 +01:00
|
|
|
assert(cp->bit_idx[0] >= 4);
|
2003-01-26 00:48:05 +01:00
|
|
|
unsigned char val = memory_get(cp->mem, thr->words[3].w_int);
|
2001-11-01 04:00:19 +01:00
|
|
|
thr_put_bit(thr, cp->bit_idx[0], val);
|
2005-03-03 05:33:10 +01:00
|
|
|
#else
|
|
|
|
|
fprintf(stderr, "XXXX %%load/m is obsolete\n");
|
|
|
|
|
#endif
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* %load/mv <bit>, <mem-label>, <wid> ;
|
|
|
|
|
*
|
|
|
|
|
* <bit> is the thread bit address for the result
|
|
|
|
|
* <mem-label> is the memory device to access, and
|
|
|
|
|
* <wid> is the width of the word to read.
|
|
|
|
|
*
|
|
|
|
|
* The address of the word in the memory is in index register 3.
|
|
|
|
|
*/
|
|
|
|
|
bool of_LOAD_MV(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
|
|
|
|
unsigned bit = cp->bit_idx[0];
|
|
|
|
|
unsigned wid = cp->bit_idx[1];
|
|
|
|
|
unsigned adr = thr->words[3].w_int;
|
|
|
|
|
|
|
|
|
|
vvp_vector4_t word = memory_get_word(cp->mem, adr);
|
|
|
|
|
|
2005-03-05 06:45:18 +01:00
|
|
|
if (word.size() != wid) {
|
|
|
|
|
fprintf(stderr, "internal error: mem width=%u, word.size()=%u, wid=%u\n",
|
|
|
|
|
memory_word_width(cp->mem), word.size(), wid);
|
|
|
|
|
}
|
2005-03-03 05:33:10 +01:00
|
|
|
assert(word.size() == wid);
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < wid ; idx += 1, bit += 1) {
|
|
|
|
|
vvp_bit4_t val = word.value(idx);
|
|
|
|
|
thr_put_bit(thr, bit, val);
|
|
|
|
|
}
|
|
|
|
|
|
2001-05-01 03:09:39 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2005-03-03 05:33:10 +01:00
|
|
|
|
2002-08-28 19:15:06 +02:00
|
|
|
/*
|
2004-12-11 03:31:25 +01:00
|
|
|
* %load/nx <bit>, <vpi-label>, <idx> ; Load net/indexed.
|
|
|
|
|
*
|
|
|
|
|
* cp->bit_idx[0] contains the <bit> value, an index into the thread
|
|
|
|
|
* bit register.
|
|
|
|
|
*
|
|
|
|
|
* cp->bin_idx[1] is the <idx> value from the words array.
|
|
|
|
|
*
|
|
|
|
|
* cp->handle is the linked reference to the __vpiSignal that we are
|
|
|
|
|
* to read from.
|
2002-08-28 19:15:06 +02:00
|
|
|
*/
|
|
|
|
|
bool of_LOAD_NX(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
|
|
|
|
assert(cp->bit_idx[0] >= 4);
|
|
|
|
|
assert(cp->bit_idx[1] < 4);
|
|
|
|
|
assert(cp->handle->vpi_type->type_code == vpiNet);
|
|
|
|
|
|
|
|
|
|
struct __vpiSignal*sig =
|
|
|
|
|
reinterpret_cast<struct __vpiSignal*>(cp->handle);
|
|
|
|
|
|
2003-01-26 00:48:05 +01:00
|
|
|
unsigned idx = thr->words[cp->bit_idx[1]].w_int;
|
2002-08-28 19:15:06 +02:00
|
|
|
|
2005-11-25 18:55:26 +01:00
|
|
|
vvp_fun_signal_vec*fun = dynamic_cast<vvp_fun_signal_vec*>(sig->node->fun);
|
2004-12-11 03:31:25 +01:00
|
|
|
assert(sig != 0);
|
|
|
|
|
|
|
|
|
|
vvp_bit4_t val = fun->value(idx);
|
|
|
|
|
thr_put_bit(thr, cp->bit_idx[0], val);
|
|
|
|
|
|
2002-08-28 19:15:06 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2004-12-11 03:31:25 +01:00
|
|
|
/* %load/v <bit>, <label>, <wid>
|
|
|
|
|
*
|
|
|
|
|
* Implement the %load/v instruction. Load the vector value of the
|
|
|
|
|
* requested width from the <label> functor starting in the thread bit
|
|
|
|
|
* <bit>.
|
|
|
|
|
*
|
|
|
|
|
* The <bit> value is the destination in the thread vector store, and
|
|
|
|
|
* is in cp->bit_idx[0].
|
|
|
|
|
*
|
|
|
|
|
* The <wid> value is the expected with of the vector, and is in
|
|
|
|
|
* cp->bit_idx[1].
|
|
|
|
|
*
|
|
|
|
|
* The functor to read from is the vvp_net_t object pointed to by the
|
|
|
|
|
* cp->net pointer.
|
|
|
|
|
*/
|
2002-11-07 03:32:39 +01:00
|
|
|
bool of_LOAD_VEC(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
|
|
|
|
assert(cp->bit_idx[0] >= 4);
|
|
|
|
|
assert(cp->bit_idx[1] > 0);
|
|
|
|
|
|
|
|
|
|
unsigned bit = cp->bit_idx[0];
|
2004-12-11 03:31:25 +01:00
|
|
|
unsigned wid = cp->bit_idx[1];
|
|
|
|
|
vvp_net_t*net = cp->net;
|
|
|
|
|
|
|
|
|
|
/* For the %load to work, the functor must actually be a
|
|
|
|
|
signal functor. Only signals save their vector value. */
|
2005-11-25 18:55:26 +01:00
|
|
|
vvp_fun_signal_vec*sig = dynamic_cast<vvp_fun_signal_vec*> (net->fun);
|
2004-12-11 03:31:25 +01:00
|
|
|
assert(sig);
|
2002-11-07 03:32:39 +01:00
|
|
|
|
2005-06-19 20:42:00 +02:00
|
|
|
vvp_vector4_t sig_value = sig->vec4_value();
|
2005-08-27 04:34:42 +02:00
|
|
|
sig_value.resize(wid);
|
2005-06-19 20:42:00 +02:00
|
|
|
|
2005-08-27 04:34:42 +02:00
|
|
|
/* Check the address once, before we scan the vector. */
|
|
|
|
|
thr_check_addr(thr, bit+wid-1);
|
|
|
|
|
|
|
|
|
|
/* Copy the vector bits into the bits4 vector. Do the copy
|
|
|
|
|
directly to skip the excess calls to thr_check_addr. */
|
|
|
|
|
thr->bits4.set_vec(bit, sig_value);
|
2002-11-07 03:32:39 +01:00
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2003-01-26 00:48:05 +01:00
|
|
|
bool of_LOAD_WR(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
|
|
|
|
struct __vpiHandle*tmp = cp->handle;
|
|
|
|
|
t_vpi_value val;
|
|
|
|
|
|
|
|
|
|
val.format = vpiRealVal;
|
|
|
|
|
vpi_get_value(tmp, &val);
|
|
|
|
|
|
|
|
|
|
thr->words[cp->bit_idx[0]].w_real = val.value.real;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2005-01-22 01:58:22 +01:00
|
|
|
/*
|
|
|
|
|
* %load/x <bit>, <functor>, <index>
|
|
|
|
|
*
|
|
|
|
|
* <bit> is the destination thread bit and must be >= 4.
|
|
|
|
|
*/
|
2001-07-22 02:04:50 +02:00
|
|
|
bool of_LOAD_X(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
2005-01-22 01:58:22 +01:00
|
|
|
// <bit> is the thread bit to load
|
2001-11-01 04:00:19 +01:00
|
|
|
assert(cp->bit_idx[0] >= 4);
|
2005-01-22 01:58:22 +01:00
|
|
|
unsigned bit = cp->bit_idx[0];
|
|
|
|
|
|
|
|
|
|
// <index> is the index register to use. The actual index into
|
|
|
|
|
// the vector is the value of the index register.
|
|
|
|
|
unsigned index_idx = cp->bit_idx[1];
|
|
|
|
|
unsigned index = thr->words[index_idx].w_int;
|
|
|
|
|
|
|
|
|
|
// <functor> is converted to a vvp_net_t pointer from which we
|
|
|
|
|
// read our value.
|
|
|
|
|
vvp_net_t*net = cp->net;
|
|
|
|
|
|
|
|
|
|
// For the %load to work, the functor must actually be a
|
|
|
|
|
// signal functor. Only signals save their vector value.
|
2005-11-25 18:55:26 +01:00
|
|
|
vvp_fun_signal_vec*sig = dynamic_cast<vvp_fun_signal_vec*> (net->fun);
|
2005-01-22 01:58:22 +01:00
|
|
|
assert(sig);
|
|
|
|
|
|
|
|
|
|
vvp_bit4_t val = index >= sig->size()? BIT4_X : sig->value(index);
|
|
|
|
|
thr_put_bit(thr, bit, val);
|
2001-07-22 02:04:50 +02:00
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2005-09-17 06:01:01 +02:00
|
|
|
bool of_LOAD_XP(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
|
|
|
|
// First do the normal handling of the %load/x
|
|
|
|
|
of_LOAD_X(thr, cp);
|
|
|
|
|
|
|
|
|
|
// Now do the post-increment
|
|
|
|
|
unsigned index_idx = cp->bit_idx[1];
|
|
|
|
|
thr->words[index_idx].w_int += 1;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2003-01-26 00:48:05 +01:00
|
|
|
bool of_LOADI_WR(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
|
|
|
|
unsigned idx = cp->bit_idx[0];
|
|
|
|
|
double mant = cp->number;
|
|
|
|
|
int exp = cp->bit_idx[1];
|
2004-06-05 01:26:34 +02:00
|
|
|
double sign = (exp & 0x4000)? -1.0 : 1.0;
|
2003-01-26 00:48:05 +01:00
|
|
|
|
|
|
|
|
exp &= 0x1fff;
|
|
|
|
|
|
|
|
|
|
mant = sign * ldexp(mant, exp - 0x1000);
|
|
|
|
|
thr->words[idx].w_real = mant;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2004-06-19 17:52:53 +02:00
|
|
|
static void do_verylong_mod(vthread_t thr, vvp_code_t cp,
|
|
|
|
|
bool left_is_neg, bool right_is_neg)
|
2001-05-24 06:20:10 +02:00
|
|
|
{
|
2004-06-19 17:52:53 +02:00
|
|
|
bool out_is_neg = left_is_neg != right_is_neg;
|
|
|
|
|
int len=cp->number;
|
|
|
|
|
unsigned char *a, *z, *t;
|
|
|
|
|
a = new unsigned char[len+1];
|
|
|
|
|
z = new unsigned char[len+1];
|
|
|
|
|
t = new unsigned char[len+1];
|
|
|
|
|
|
|
|
|
|
unsigned char carry;
|
|
|
|
|
unsigned char temp;
|
|
|
|
|
|
|
|
|
|
int mxa = -1, mxz = -1;
|
|
|
|
|
int i;
|
|
|
|
|
int current, copylen;
|
2001-05-24 06:20:10 +02:00
|
|
|
|
2001-11-01 04:00:19 +01:00
|
|
|
unsigned idx1 = cp->bit_idx[0];
|
|
|
|
|
unsigned idx2 = cp->bit_idx[1];
|
2001-05-24 06:20:10 +02:00
|
|
|
|
2004-06-19 17:52:53 +02:00
|
|
|
unsigned lb_carry = left_is_neg? 1 : 0;
|
|
|
|
|
unsigned rb_carry = right_is_neg? 1 : 0;
|
2001-05-24 06:20:10 +02:00
|
|
|
for (unsigned idx = 0 ; idx < cp->number ; idx += 1) {
|
|
|
|
|
unsigned lb = thr_get_bit(thr, idx1);
|
|
|
|
|
unsigned rb = thr_get_bit(thr, idx2);
|
|
|
|
|
|
2004-06-19 17:52:53 +02:00
|
|
|
if ((lb | rb) & 2) {
|
|
|
|
|
delete []t;
|
|
|
|
|
delete []z;
|
|
|
|
|
delete []a;
|
2001-05-24 06:20:10 +02:00
|
|
|
goto x_out;
|
2004-06-19 17:52:53 +02:00
|
|
|
}
|
2001-05-24 06:20:10 +02:00
|
|
|
|
2004-06-19 17:52:53 +02:00
|
|
|
if (left_is_neg) {
|
|
|
|
|
lb = (1-lb) + lb_carry;
|
|
|
|
|
lb_carry = (lb & ~1)? 1 : 0;
|
|
|
|
|
lb &= 1;
|
|
|
|
|
}
|
|
|
|
|
if (right_is_neg) {
|
|
|
|
|
rb = (1-rb) + rb_carry;
|
|
|
|
|
rb_carry = (rb & ~1)? 1 : 0;
|
|
|
|
|
rb &= 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
z[idx]=lb;
|
|
|
|
|
a[idx]=1-rb; // for 2s complement add..
|
2001-05-24 06:20:10 +02:00
|
|
|
|
|
|
|
|
idx1 += 1;
|
|
|
|
|
if (idx2 >= 4)
|
|
|
|
|
idx2 += 1;
|
|
|
|
|
}
|
|
|
|
|
|
2004-06-19 17:52:53 +02:00
|
|
|
z[len]=0;
|
|
|
|
|
a[len]=1;
|
2001-10-21 01:20:32 +02:00
|
|
|
|
2004-06-19 17:52:53 +02:00
|
|
|
for(i=len-1;i>=0;i--) {
|
|
|
|
|
if(!a[i]) {
|
|
|
|
|
mxa=i;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2001-05-24 06:20:10 +02:00
|
|
|
|
2004-06-19 17:52:53 +02:00
|
|
|
for(i=len-1;i>=0;i--) {
|
|
|
|
|
if(z[i]) {
|
|
|
|
|
mxz=i;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2001-05-24 06:20:10 +02:00
|
|
|
}
|
|
|
|
|
|
2004-06-19 17:52:53 +02:00
|
|
|
if((mxa>mxz)||(mxa==-1)) {
|
|
|
|
|
if(mxa==-1) {
|
|
|
|
|
delete []t;
|
|
|
|
|
delete []z;
|
|
|
|
|
delete []a;
|
|
|
|
|
goto x_out;
|
|
|
|
|
}
|
2001-05-24 06:20:10 +02:00
|
|
|
|
2004-06-19 17:52:53 +02:00
|
|
|
goto tally;
|
|
|
|
|
}
|
2001-10-16 03:26:54 +02:00
|
|
|
|
2004-06-19 17:52:53 +02:00
|
|
|
copylen = mxa + 2;
|
2004-10-04 03:10:51 +02:00
|
|
|
current = mxz - mxa;
|
2001-10-16 03:26:54 +02:00
|
|
|
|
2004-06-19 17:52:53 +02:00
|
|
|
while(current > -1) {
|
|
|
|
|
carry = 1;
|
|
|
|
|
for(i=0;i<copylen;i++) {
|
|
|
|
|
temp = z[i+current] + a[i] + carry;
|
|
|
|
|
t[i] = (temp&1);
|
|
|
|
|
carry = (temp>>1);
|
2004-10-04 03:10:51 +02:00
|
|
|
}
|
2001-10-16 03:26:54 +02:00
|
|
|
|
2004-06-19 17:52:53 +02:00
|
|
|
if(carry) {
|
|
|
|
|
for(i=0;i<copylen;i++) {
|
|
|
|
|
z[i+current] = t[i];
|
|
|
|
|
}
|
|
|
|
|
}
|
2001-10-16 03:26:54 +02:00
|
|
|
|
2004-06-19 17:52:53 +02:00
|
|
|
current--;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tally:
|
2001-10-16 03:26:54 +02:00
|
|
|
|
2004-06-19 17:52:53 +02:00
|
|
|
carry = out_is_neg? 1 : 0;
|
2001-10-16 03:26:54 +02:00
|
|
|
for (unsigned idx = 0 ; idx < cp->number ; idx += 1) {
|
2004-06-19 17:52:53 +02:00
|
|
|
unsigned ob = z[idx];
|
|
|
|
|
if (out_is_neg) {
|
|
|
|
|
ob = (1-ob) + carry;
|
|
|
|
|
carry = (ob & ~1)? 1 : 0;
|
|
|
|
|
ob = ob & 1;
|
|
|
|
|
}
|
2005-08-27 04:34:42 +02:00
|
|
|
thr_put_bit(thr, cp->bit_idx[0]+idx, ob?BIT4_1:BIT4_0);
|
2004-06-19 17:52:53 +02:00
|
|
|
}
|
2001-10-16 03:26:54 +02:00
|
|
|
|
2004-06-19 17:52:53 +02:00
|
|
|
delete []t;
|
|
|
|
|
delete []z;
|
|
|
|
|
delete []a;
|
|
|
|
|
return;
|
2001-10-16 03:26:54 +02:00
|
|
|
|
2004-06-19 17:52:53 +02:00
|
|
|
x_out:
|
|
|
|
|
for (unsigned idx = 0 ; idx < cp->number ; idx += 1)
|
2005-08-27 04:34:42 +02:00
|
|
|
thr_put_bit(thr, cp->bit_idx[0]+idx, BIT4_X);
|
2001-10-16 03:26:54 +02:00
|
|
|
|
2004-06-19 17:52:53 +02:00
|
|
|
return;
|
|
|
|
|
}
|
2001-10-16 03:26:54 +02:00
|
|
|
|
2004-06-19 17:52:53 +02:00
|
|
|
bool of_MOD(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
|
|
|
|
assert(cp->bit_idx[0] >= 4);
|
2001-10-16 03:26:54 +02:00
|
|
|
|
2004-06-19 17:52:53 +02:00
|
|
|
if(cp->number <= 8*sizeof(unsigned long long)) {
|
|
|
|
|
unsigned idx1 = cp->bit_idx[0];
|
|
|
|
|
unsigned idx2 = cp->bit_idx[1];
|
|
|
|
|
unsigned long long lv = 0, rv = 0;
|
2001-10-16 03:26:54 +02:00
|
|
|
|
2004-06-19 17:52:53 +02:00
|
|
|
for (unsigned idx = 0 ; idx < cp->number ; idx += 1) {
|
|
|
|
|
unsigned long long lb = thr_get_bit(thr, idx1);
|
|
|
|
|
unsigned long long rb = thr_get_bit(thr, idx2);
|
|
|
|
|
|
|
|
|
|
if ((lb | rb) & 2)
|
|
|
|
|
goto x_out;
|
|
|
|
|
|
|
|
|
|
lv |= lb << idx;
|
|
|
|
|
rv |= rb << idx;
|
|
|
|
|
|
|
|
|
|
idx1 += 1;
|
|
|
|
|
if (idx2 >= 4)
|
|
|
|
|
idx2 += 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (rv == 0)
|
|
|
|
|
goto x_out;
|
|
|
|
|
|
|
|
|
|
lv %= rv;
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < cp->number ; idx += 1) {
|
2005-08-27 04:34:42 +02:00
|
|
|
thr_put_bit(thr, cp->bit_idx[0]+idx, (lv&1)?BIT4_1 : BIT4_0);
|
2004-06-19 17:52:53 +02:00
|
|
|
lv >>= 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
do_verylong_mod(thr, cp, false, false);
|
|
|
|
|
return true;
|
2001-10-16 03:26:54 +02:00
|
|
|
}
|
|
|
|
|
|
2004-06-19 17:52:53 +02:00
|
|
|
x_out:
|
|
|
|
|
for (unsigned idx = 0 ; idx < cp->number ; idx += 1)
|
2005-08-27 04:34:42 +02:00
|
|
|
thr_put_bit(thr, cp->bit_idx[0]+idx, BIT4_X);
|
2004-06-19 17:52:53 +02:00
|
|
|
|
2001-10-16 03:26:54 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2004-06-19 17:52:53 +02:00
|
|
|
bool of_MOD_S(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
|
|
|
|
assert(cp->bit_idx[0] >= 4);
|
|
|
|
|
|
|
|
|
|
/* Handle the case that we can fit the bits into a long-long
|
|
|
|
|
variable. We cause use native % to do the work. */
|
|
|
|
|
if(cp->number <= 8*sizeof(long long)) {
|
|
|
|
|
unsigned idx1 = cp->bit_idx[0];
|
|
|
|
|
unsigned idx2 = cp->bit_idx[1];
|
|
|
|
|
long long lv = 0, rv = 0;
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < cp->number ; idx += 1) {
|
|
|
|
|
long long lb = thr_get_bit(thr, idx1);
|
|
|
|
|
long long rb = thr_get_bit(thr, idx2);
|
|
|
|
|
|
|
|
|
|
if ((lb | rb) & 2)
|
|
|
|
|
goto x_out;
|
|
|
|
|
|
|
|
|
|
lv |= lb << idx;
|
|
|
|
|
rv |= rb << idx;
|
|
|
|
|
|
|
|
|
|
idx1 += 1;
|
|
|
|
|
if (idx2 >= 4)
|
|
|
|
|
idx2 += 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (rv == 0)
|
|
|
|
|
goto x_out;
|
|
|
|
|
|
|
|
|
|
/* Sign extend the signed operands. */
|
2004-06-19 18:17:02 +02:00
|
|
|
if (lv & (1LL << (cp->number-1)))
|
2004-06-19 17:52:53 +02:00
|
|
|
lv |= -1LL << cp->number;
|
2004-06-19 18:17:02 +02:00
|
|
|
if (rv & (1LL << (cp->number-1)))
|
2004-06-19 17:52:53 +02:00
|
|
|
rv |= -1LL << cp->number;
|
|
|
|
|
|
|
|
|
|
lv %= rv;
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < cp->number ; idx += 1) {
|
2005-08-27 04:34:42 +02:00
|
|
|
thr_put_bit(thr, cp->bit_idx[0]+idx, (lv&1)?BIT4_1:BIT4_0);
|
2004-06-19 17:52:53 +02:00
|
|
|
lv >>= 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
bool left_is_neg
|
|
|
|
|
= thr_get_bit(thr,cp->bit_idx[0]+cp->number-1) == 1;
|
|
|
|
|
bool right_is_neg
|
|
|
|
|
= thr_get_bit(thr,cp->bit_idx[1]+cp->number-1) == 1;
|
|
|
|
|
do_verylong_mod(thr, cp, left_is_neg, right_is_neg);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2001-05-24 06:20:10 +02:00
|
|
|
x_out:
|
|
|
|
|
for (unsigned idx = 0 ; idx < cp->number ; idx += 1)
|
2005-08-27 04:34:42 +02:00
|
|
|
thr_put_bit(thr, cp->bit_idx[0]+idx, BIT4_X);
|
2001-05-24 06:20:10 +02:00
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2002-05-31 06:09:58 +02:00
|
|
|
/*
|
|
|
|
|
* %mov <dest>, <src>, <wid>
|
|
|
|
|
* This instruction is implemented by the of_MOV function
|
2003-02-10 00:33:26 +01:00
|
|
|
* below. However, during runtime vvp might notice that the
|
2002-05-31 06:09:58 +02:00
|
|
|
* parameters have certain properties that make it possible to
|
|
|
|
|
* replace the of_MOV opcode with a more specific instruction that
|
|
|
|
|
* more directly does the job. All the of_MOV*_ functions are
|
|
|
|
|
* functions that of_MOV might use to replace itself.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
static bool of_MOV1XZ_(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
2005-08-30 02:49:21 +02:00
|
|
|
thr_check_addr(thr, cp->bit_idx[0]+cp->number-1);
|
2005-08-27 04:34:42 +02:00
|
|
|
vvp_vector4_t tmp (cp->number, (vvp_bit4_t)cp->bit_idx[1]);
|
|
|
|
|
thr->bits4.set_vec(cp->bit_idx[0], tmp);
|
2002-05-31 06:09:58 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool of_MOV_(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
2005-08-27 04:34:42 +02:00
|
|
|
/* This variant implements the general case that we know
|
|
|
|
|
neither the source nor the destination to be <4. Otherwise,
|
|
|
|
|
we copy all the bits manually. */
|
|
|
|
|
|
|
|
|
|
thr_check_addr(thr, cp->bit_idx[0]+cp->number);
|
|
|
|
|
thr_check_addr(thr, cp->bit_idx[1]+cp->number);
|
|
|
|
|
// Read the source vector out
|
|
|
|
|
vvp_vector4_t tmp (thr->bits4, cp->bit_idx[1], cp->number);
|
|
|
|
|
// Write it in the new place.
|
|
|
|
|
thr->bits4.set_vec(cp->bit_idx[0], tmp);
|
|
|
|
|
|
2002-05-31 06:09:58 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2001-03-22 06:08:00 +01:00
|
|
|
bool of_MOV(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
2001-11-01 04:00:19 +01:00
|
|
|
assert(cp->bit_idx[0] >= 4);
|
2001-03-22 06:08:00 +01:00
|
|
|
|
2001-11-01 04:00:19 +01:00
|
|
|
if (cp->bit_idx[1] >= 4) {
|
2002-05-31 06:09:58 +02:00
|
|
|
cp->opcode = &of_MOV_;
|
|
|
|
|
return cp->opcode(thr, cp);
|
2001-03-22 06:08:00 +01:00
|
|
|
|
|
|
|
|
} else {
|
2002-05-31 06:09:58 +02:00
|
|
|
cp->opcode = &of_MOV1XZ_;
|
|
|
|
|
return cp->opcode(thr, cp);
|
2001-03-22 06:08:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2001-06-17 01:45:05 +02:00
|
|
|
bool of_MUL(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
2001-11-01 04:00:19 +01:00
|
|
|
assert(cp->bit_idx[0] >= 4);
|
2001-10-14 18:36:43 +02:00
|
|
|
if(cp->number <= 8*sizeof(unsigned long)) {
|
2001-06-17 01:45:05 +02:00
|
|
|
|
2001-11-01 04:00:19 +01:00
|
|
|
unsigned idx1 = cp->bit_idx[0];
|
|
|
|
|
unsigned idx2 = cp->bit_idx[1];
|
2001-06-17 01:45:05 +02:00
|
|
|
unsigned long lv = 0, rv = 0;
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < cp->number ; idx += 1) {
|
2005-08-27 04:34:42 +02:00
|
|
|
vvp_bit4_t lb = thr_get_bit(thr, idx1);
|
|
|
|
|
vvp_bit4_t rb = thr_get_bit(thr, idx2);
|
2001-06-17 01:45:05 +02:00
|
|
|
|
2005-08-27 04:34:42 +02:00
|
|
|
if (bit4_is_xz(lb) || bit4_is_xz(rb))
|
2001-06-17 01:45:05 +02:00
|
|
|
goto x_out;
|
|
|
|
|
|
2005-08-27 04:34:42 +02:00
|
|
|
lv |= ((unsigned long)lb) << idx;
|
|
|
|
|
rv |= ((unsigned long)rb) << idx;
|
2001-06-17 01:45:05 +02:00
|
|
|
|
|
|
|
|
idx1 += 1;
|
|
|
|
|
if (idx2 >= 4)
|
|
|
|
|
idx2 += 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
lv *= rv;
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < cp->number ; idx += 1) {
|
2005-08-27 04:34:42 +02:00
|
|
|
thr_put_bit(thr, cp->bit_idx[0]+idx, (lv&1) ? BIT4_1 : BIT4_0);
|
2001-06-17 01:45:05 +02:00
|
|
|
lv >>= 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
2001-10-14 18:36:43 +02:00
|
|
|
} else {
|
2001-11-01 04:00:19 +01:00
|
|
|
unsigned idx1 = cp->bit_idx[0];
|
|
|
|
|
unsigned idx2 = cp->bit_idx[1];
|
2001-10-14 18:36:43 +02:00
|
|
|
|
|
|
|
|
unsigned char *a, *b, *sum;
|
|
|
|
|
a = new unsigned char[cp->number];
|
|
|
|
|
b = new unsigned char[cp->number];
|
|
|
|
|
sum = new unsigned char[cp->number];
|
|
|
|
|
|
|
|
|
|
int mxa = -1;
|
|
|
|
|
int mxb = -1;
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < cp->number ; idx += 1) {
|
2005-08-27 04:34:42 +02:00
|
|
|
vvp_bit4_t lb = thr_get_bit(thr, idx1);
|
|
|
|
|
vvp_bit4_t rb = thr_get_bit(thr, idx2);
|
2001-10-14 18:36:43 +02:00
|
|
|
|
2005-08-27 04:34:42 +02:00
|
|
|
if (bit4_is_xz(lb) || bit4_is_xz(rb))
|
2001-10-14 18:36:43 +02:00
|
|
|
{
|
|
|
|
|
delete[]sum;
|
|
|
|
|
delete[]b;
|
|
|
|
|
delete[]a;
|
|
|
|
|
goto x_out;
|
|
|
|
|
}
|
|
|
|
|
|
2001-10-14 19:36:18 +02:00
|
|
|
if((a[idx] = lb)) mxa=idx+1;
|
2001-10-14 18:36:43 +02:00
|
|
|
if((b[idx] = rb)) mxb=idx;
|
|
|
|
|
sum[idx]=0;
|
|
|
|
|
|
|
|
|
|
idx1 += 1;
|
|
|
|
|
if (idx2 >= 4)
|
|
|
|
|
idx2 += 1;
|
|
|
|
|
}
|
|
|
|
|
|
2004-10-04 03:10:51 +02:00
|
|
|
// do "unsigned ZZ sum = a * b" the hard way..
|
2001-10-14 18:36:43 +02:00
|
|
|
for(int i=0;i<=mxb;i++)
|
|
|
|
|
{
|
|
|
|
|
if(b[i])
|
|
|
|
|
{
|
|
|
|
|
unsigned char carry=0;
|
|
|
|
|
unsigned char temp;
|
|
|
|
|
|
|
|
|
|
for(int j=0;j<=mxa;j++)
|
|
|
|
|
{
|
|
|
|
|
if(i+j>=(int)cp->number) break;
|
|
|
|
|
temp=sum[i+j]+a[j]+carry;
|
|
|
|
|
sum[i+j]=(temp&1);
|
|
|
|
|
carry=(temp>>1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < cp->number ; idx += 1) {
|
2005-08-27 04:34:42 +02:00
|
|
|
thr_put_bit(thr, cp->bit_idx[0]+idx, sum[idx]?BIT4_1:BIT4_0);
|
2001-10-14 18:36:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
delete[]sum;
|
|
|
|
|
delete[]b;
|
|
|
|
|
delete[]a;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2001-06-17 01:45:05 +02:00
|
|
|
|
|
|
|
|
x_out:
|
|
|
|
|
for (unsigned idx = 0 ; idx < cp->number ; idx += 1)
|
2005-08-27 04:34:42 +02:00
|
|
|
thr_put_bit(thr, cp->bit_idx[0]+idx, BIT4_X);
|
2001-06-17 01:45:05 +02:00
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2003-01-26 00:48:05 +01:00
|
|
|
bool of_MUL_WR(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
|
|
|
|
double l = thr->words[cp->bit_idx[0]].w_real;
|
|
|
|
|
double r = thr->words[cp->bit_idx[1]].w_real;
|
|
|
|
|
thr->words[cp->bit_idx[0]].w_real = l * r;
|
2003-01-26 19:16:22 +01:00
|
|
|
|
2003-01-26 00:48:05 +01:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2002-05-31 22:04:22 +02:00
|
|
|
bool of_MULI(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
|
|
|
|
assert(cp->bit_idx[0] >= 4);
|
|
|
|
|
|
|
|
|
|
/* If the value fits into a native unsigned long, then make an
|
|
|
|
|
unsigned long variable with the numbers, to a native
|
|
|
|
|
multiply, and work with that. */
|
|
|
|
|
|
|
|
|
|
if(cp->number <= 8*sizeof(unsigned long)) {
|
|
|
|
|
unsigned idx1 = cp->bit_idx[0];
|
|
|
|
|
unsigned long lv = 0, rv = cp->bit_idx[1];
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < cp->number ; idx += 1) {
|
2005-08-27 04:34:42 +02:00
|
|
|
vvp_bit4_t lb = thr_get_bit(thr, idx1);
|
2002-05-31 22:04:22 +02:00
|
|
|
|
2005-08-27 04:34:42 +02:00
|
|
|
if (bit4_is_xz(lb))
|
2002-05-31 22:04:22 +02:00
|
|
|
goto x_out;
|
|
|
|
|
|
|
|
|
|
lv |= lb << idx;
|
|
|
|
|
|
|
|
|
|
idx1 += 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
lv *= rv;
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < cp->number ; idx += 1) {
|
2005-08-27 04:34:42 +02:00
|
|
|
thr_put_bit(thr, cp->bit_idx[0]+idx, (lv&1)? BIT4_1 : BIT4_0);
|
2002-05-31 22:04:22 +02:00
|
|
|
lv >>= 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* number is too large for local long, so do bitwise
|
|
|
|
|
multiply. */
|
|
|
|
|
|
|
|
|
|
unsigned idx1; idx1 = cp->bit_idx[0];
|
|
|
|
|
unsigned imm; imm = cp->bit_idx[1];
|
|
|
|
|
|
|
|
|
|
unsigned char *a, *b, *sum;
|
|
|
|
|
a = new unsigned char[cp->number];
|
|
|
|
|
b = new unsigned char[cp->number];
|
|
|
|
|
sum = new unsigned char[cp->number];
|
|
|
|
|
|
|
|
|
|
int mxa; mxa = -1;
|
|
|
|
|
int mxb; mxb = -1;
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < cp->number ; idx += 1) {
|
2005-08-27 04:34:42 +02:00
|
|
|
vvp_bit4_t lb = thr_get_bit(thr, idx1);
|
|
|
|
|
vvp_bit4_t rb = (imm & 1)? BIT4_1 : BIT4_0;
|
2002-05-31 22:04:22 +02:00
|
|
|
|
|
|
|
|
imm >>= 1;
|
|
|
|
|
|
2005-08-27 04:34:42 +02:00
|
|
|
if (bit4_is_xz(lb)) {
|
2002-05-31 22:04:22 +02:00
|
|
|
delete[]sum;
|
|
|
|
|
delete[]b;
|
|
|
|
|
delete[]a;
|
|
|
|
|
goto x_out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if((a[idx] = lb)) mxa=idx+1;
|
|
|
|
|
if((b[idx] = rb)) mxb=idx;
|
|
|
|
|
sum[idx]=0;
|
|
|
|
|
|
|
|
|
|
idx1 += 1;
|
|
|
|
|
}
|
|
|
|
|
|
2004-10-04 03:10:51 +02:00
|
|
|
// do "unsigned ZZ sum = a * b" the hard way..
|
2002-05-31 22:04:22 +02:00
|
|
|
for(int i=0;i<=mxb;i++) {
|
|
|
|
|
if(b[i]) {
|
|
|
|
|
unsigned char carry=0;
|
|
|
|
|
unsigned char temp;
|
|
|
|
|
|
|
|
|
|
for(int j=0;j<=mxa;j++) {
|
|
|
|
|
if(i+j>=(int)cp->number) break;
|
|
|
|
|
temp=sum[i+j]+a[j]+carry;
|
|
|
|
|
sum[i+j]=(temp&1);
|
|
|
|
|
carry=(temp>>1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < cp->number ; idx += 1) {
|
2005-08-27 04:34:42 +02:00
|
|
|
thr_put_bit(thr, cp->bit_idx[0]+idx, sum[idx]?BIT4_1:BIT4_0);
|
2002-05-31 22:04:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
delete[]sum;
|
|
|
|
|
delete[]b;
|
|
|
|
|
delete[]a;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
x_out:
|
|
|
|
|
for (unsigned idx = 0 ; idx < cp->number ; idx += 1)
|
2005-08-27 04:34:42 +02:00
|
|
|
thr_put_bit(thr, cp->bit_idx[0]+idx, BIT4_X);
|
2002-05-31 22:04:22 +02:00
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2002-09-12 17:49:43 +02:00
|
|
|
bool of_NAND(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
|
|
|
|
assert(cp->bit_idx[0] >= 4);
|
|
|
|
|
|
|
|
|
|
unsigned idx1 = cp->bit_idx[0];
|
|
|
|
|
unsigned idx2 = cp->bit_idx[1];
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < cp->number ; idx += 1) {
|
|
|
|
|
|
2005-08-27 04:34:42 +02:00
|
|
|
vvp_bit4_t lb = thr_get_bit(thr, idx1);
|
|
|
|
|
vvp_bit4_t rb = thr_get_bit(thr, idx2);
|
2002-09-12 17:49:43 +02:00
|
|
|
|
2005-08-27 04:34:42 +02:00
|
|
|
if ((lb == BIT4_0) || (rb == BIT4_0)) {
|
|
|
|
|
thr_put_bit(thr, idx1, BIT4_1);
|
2002-09-12 17:49:43 +02:00
|
|
|
|
2005-08-27 04:34:42 +02:00
|
|
|
} else if ((lb == BIT4_1) && (rb == BIT4_1)) {
|
|
|
|
|
thr_put_bit(thr, idx1, BIT4_0);
|
2002-09-12 17:49:43 +02:00
|
|
|
|
|
|
|
|
} else {
|
2005-08-27 04:34:42 +02:00
|
|
|
thr_put_bit(thr, idx1, BIT4_X);
|
2002-09-12 17:49:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
idx1 += 1;
|
|
|
|
|
if (idx2 >= 4)
|
|
|
|
|
idx2 += 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2001-03-11 01:29:38 +01:00
|
|
|
bool of_NOOP(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2001-04-02 00:25:33 +02:00
|
|
|
bool of_NORR(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
2001-11-01 04:00:19 +01:00
|
|
|
assert(cp->bit_idx[0] >= 4);
|
2001-04-02 00:25:33 +02:00
|
|
|
|
2005-05-17 22:51:06 +02:00
|
|
|
vvp_bit4_t lb = BIT4_1;
|
2001-11-01 04:00:19 +01:00
|
|
|
unsigned idx2 = cp->bit_idx[1];
|
2001-06-18 03:09:32 +02:00
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < cp->number ; idx += 1) {
|
|
|
|
|
|
2005-05-17 22:51:06 +02:00
|
|
|
vvp_bit4_t rb = thr_get_bit(thr, idx2+idx);
|
|
|
|
|
if (rb == BIT4_1) {
|
|
|
|
|
lb = BIT4_0;
|
2001-06-18 03:09:32 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2005-05-17 22:51:06 +02:00
|
|
|
if (rb != BIT4_0)
|
|
|
|
|
lb = BIT4_X;
|
2001-06-18 03:09:32 +02:00
|
|
|
}
|
|
|
|
|
|
2001-11-01 04:00:19 +01:00
|
|
|
thr_put_bit(thr, cp->bit_idx[0], lb);
|
2001-06-18 03:09:32 +02:00
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool of_ANDR(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
2001-11-01 04:00:19 +01:00
|
|
|
assert(cp->bit_idx[0] >= 4);
|
2001-06-18 03:09:32 +02:00
|
|
|
|
2005-08-27 04:34:42 +02:00
|
|
|
vvp_bit4_t lb = BIT4_1;
|
2001-11-01 04:00:19 +01:00
|
|
|
unsigned idx2 = cp->bit_idx[1];
|
2001-06-18 03:09:32 +02:00
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < cp->number ; idx += 1) {
|
|
|
|
|
|
2005-08-27 04:34:42 +02:00
|
|
|
vvp_bit4_t rb = thr_get_bit(thr, idx2+idx);
|
|
|
|
|
if (rb == BIT4_0) {
|
|
|
|
|
lb = BIT4_0;
|
2001-06-18 03:09:32 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2005-08-27 04:34:42 +02:00
|
|
|
if (rb != BIT4_1)
|
|
|
|
|
lb = BIT4_X;
|
2001-06-18 03:09:32 +02:00
|
|
|
}
|
|
|
|
|
|
2001-11-01 04:00:19 +01:00
|
|
|
thr_put_bit(thr, cp->bit_idx[0], lb);
|
2001-06-18 03:09:32 +02:00
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool of_NANDR(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
2001-11-01 04:00:19 +01:00
|
|
|
assert(cp->bit_idx[0] >= 4);
|
2001-06-18 03:09:32 +02:00
|
|
|
|
2005-08-27 04:34:42 +02:00
|
|
|
vvp_bit4_t lb = BIT4_0;
|
2001-11-01 04:00:19 +01:00
|
|
|
unsigned idx2 = cp->bit_idx[1];
|
2001-04-02 00:25:33 +02:00
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < cp->number ; idx += 1) {
|
|
|
|
|
|
2005-08-27 04:34:42 +02:00
|
|
|
vvp_bit4_t rb = thr_get_bit(thr, idx2+idx);
|
|
|
|
|
if (rb == BIT4_0) {
|
|
|
|
|
lb = BIT4_1;
|
2001-06-18 03:09:32 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2005-08-27 04:34:42 +02:00
|
|
|
if (rb != BIT4_1)
|
|
|
|
|
lb = BIT4_X;
|
2001-06-18 03:09:32 +02:00
|
|
|
}
|
|
|
|
|
|
2001-11-01 04:00:19 +01:00
|
|
|
thr_put_bit(thr, cp->bit_idx[0], lb);
|
2001-06-18 03:09:32 +02:00
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool of_ORR(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
2001-11-01 04:00:19 +01:00
|
|
|
assert(cp->bit_idx[0] >= 4);
|
2001-06-18 03:09:32 +02:00
|
|
|
|
2005-08-27 04:34:42 +02:00
|
|
|
vvp_bit4_t lb = BIT4_0;
|
2001-11-01 04:00:19 +01:00
|
|
|
unsigned idx2 = cp->bit_idx[1];
|
2001-06-18 03:09:32 +02:00
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < cp->number ; idx += 1) {
|
|
|
|
|
|
2005-08-27 04:34:42 +02:00
|
|
|
vvp_bit4_t rb = thr_get_bit(thr, idx2+idx);
|
|
|
|
|
if (rb == BIT4_1) {
|
|
|
|
|
lb = BIT4_1;
|
2001-04-02 00:25:33 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2005-08-27 04:34:42 +02:00
|
|
|
if (rb != BIT4_0)
|
|
|
|
|
lb = BIT4_X;
|
2001-04-02 00:25:33 +02:00
|
|
|
}
|
|
|
|
|
|
2001-11-01 04:00:19 +01:00
|
|
|
thr_put_bit(thr, cp->bit_idx[0], lb);
|
2001-04-02 00:25:33 +02:00
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2001-06-18 03:09:32 +02:00
|
|
|
bool of_XORR(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
2001-11-01 04:00:19 +01:00
|
|
|
assert(cp->bit_idx[0] >= 4);
|
2001-06-18 03:09:32 +02:00
|
|
|
|
2005-08-27 04:34:42 +02:00
|
|
|
vvp_bit4_t lb = BIT4_0;
|
2001-11-01 04:00:19 +01:00
|
|
|
unsigned idx2 = cp->bit_idx[1];
|
2001-06-18 03:09:32 +02:00
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < cp->number ; idx += 1) {
|
|
|
|
|
|
2005-08-27 04:34:42 +02:00
|
|
|
vvp_bit4_t rb = thr_get_bit(thr, idx2+idx);
|
|
|
|
|
if (rb == BIT4_1)
|
|
|
|
|
lb = ~lb;
|
|
|
|
|
else if (rb != BIT4_0) {
|
|
|
|
|
lb = BIT4_X;
|
2001-06-18 03:09:32 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2004-10-04 03:10:51 +02:00
|
|
|
|
2001-11-01 04:00:19 +01:00
|
|
|
thr_put_bit(thr, cp->bit_idx[0], lb);
|
2004-10-04 03:10:51 +02:00
|
|
|
|
2001-06-18 03:09:32 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool of_XNORR(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
2001-11-01 04:00:19 +01:00
|
|
|
assert(cp->bit_idx[0] >= 4);
|
2001-06-18 03:09:32 +02:00
|
|
|
|
2005-08-27 04:34:42 +02:00
|
|
|
vvp_bit4_t lb = BIT4_1;
|
2001-11-01 04:00:19 +01:00
|
|
|
unsigned idx2 = cp->bit_idx[1];
|
2001-06-18 03:09:32 +02:00
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < cp->number ; idx += 1) {
|
|
|
|
|
|
2005-08-27 04:34:42 +02:00
|
|
|
vvp_bit4_t rb = thr_get_bit(thr, idx2+idx);
|
|
|
|
|
if (rb == BIT4_1)
|
|
|
|
|
lb = ~lb;
|
|
|
|
|
else if (rb != BIT4_0) {
|
|
|
|
|
lb = BIT4_X;
|
2001-06-18 03:09:32 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2004-10-04 03:10:51 +02:00
|
|
|
|
2001-11-01 04:00:19 +01:00
|
|
|
thr_put_bit(thr, cp->bit_idx[0], lb);
|
2004-10-04 03:10:51 +02:00
|
|
|
|
2001-06-18 03:09:32 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2001-04-01 09:22:08 +02:00
|
|
|
bool of_OR(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
2001-11-01 04:00:19 +01:00
|
|
|
assert(cp->bit_idx[0] >= 4);
|
2001-04-01 09:22:08 +02:00
|
|
|
|
2001-11-01 04:00:19 +01:00
|
|
|
unsigned idx1 = cp->bit_idx[0];
|
|
|
|
|
unsigned idx2 = cp->bit_idx[1];
|
2001-04-01 09:22:08 +02:00
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < cp->number ; idx += 1) {
|
|
|
|
|
|
2005-05-17 22:51:06 +02:00
|
|
|
vvp_bit4_t lb = thr_get_bit(thr, idx1);
|
|
|
|
|
vvp_bit4_t rb = thr_get_bit(thr, idx2);
|
2001-04-01 09:22:08 +02:00
|
|
|
|
2005-05-17 22:51:06 +02:00
|
|
|
if ((lb == BIT4_1) || (rb == BIT4_1)) {
|
|
|
|
|
thr_put_bit(thr, idx1, BIT4_1);
|
2001-04-01 09:22:08 +02:00
|
|
|
|
2005-05-17 22:51:06 +02:00
|
|
|
} else if ((lb == BIT4_0) && (rb == BIT4_0)) {
|
|
|
|
|
thr_put_bit(thr, idx1, BIT4_0);
|
2001-04-01 09:22:08 +02:00
|
|
|
|
|
|
|
|
} else {
|
2005-05-17 22:51:06 +02:00
|
|
|
thr_put_bit(thr, idx1, BIT4_X);
|
2001-04-01 09:22:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
idx1 += 1;
|
|
|
|
|
if (idx2 >= 4)
|
|
|
|
|
idx2 += 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2002-09-18 06:29:55 +02:00
|
|
|
bool of_NOR(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
|
|
|
|
assert(cp->bit_idx[0] >= 4);
|
|
|
|
|
|
|
|
|
|
unsigned idx1 = cp->bit_idx[0];
|
|
|
|
|
unsigned idx2 = cp->bit_idx[1];
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < cp->number ; idx += 1) {
|
|
|
|
|
|
2005-08-27 04:34:42 +02:00
|
|
|
vvp_bit4_t lb = thr_get_bit(thr, idx1);
|
|
|
|
|
vvp_bit4_t rb = thr_get_bit(thr, idx2);
|
2002-09-18 06:29:55 +02:00
|
|
|
|
2005-08-27 04:34:42 +02:00
|
|
|
if ((lb == BIT4_1) || (rb == BIT4_1)) {
|
|
|
|
|
thr_put_bit(thr, idx1, BIT4_0);
|
2002-09-18 06:29:55 +02:00
|
|
|
|
2005-08-27 04:34:42 +02:00
|
|
|
} else if ((lb == BIT4_0) && (rb == BIT4_0)) {
|
|
|
|
|
thr_put_bit(thr, idx1, BIT4_1);
|
2002-09-18 06:29:55 +02:00
|
|
|
|
|
|
|
|
} else {
|
2005-08-27 04:34:42 +02:00
|
|
|
thr_put_bit(thr, idx1, BIT4_X);
|
2002-09-18 06:29:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
idx1 += 1;
|
|
|
|
|
if (idx2 >= 4)
|
|
|
|
|
idx2 += 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2004-12-17 05:47:47 +01:00
|
|
|
/*
|
|
|
|
|
* These implement the %release/net and %release/reg instructions. The
|
|
|
|
|
* %release/net instruction applies to a net kind of functor by
|
|
|
|
|
* sending the release/net command to the command port. (See vvp_net.h
|
|
|
|
|
* for details.) The %release/reg instruction is the same, but sends
|
|
|
|
|
* the release/reg command instead. These are very similar to the
|
|
|
|
|
* %deassign instruction.
|
|
|
|
|
*/
|
|
|
|
|
bool of_RELEASE_NET(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
|
|
|
|
vvp_net_t*net = cp->net;
|
|
|
|
|
|
2005-11-25 18:55:26 +01:00
|
|
|
vvp_fun_signal_base*sig = reinterpret_cast<vvp_fun_signal_base*>(net->fun);
|
2005-06-02 18:02:11 +02:00
|
|
|
assert(sig);
|
|
|
|
|
|
|
|
|
|
/* XXXX Release for %force/link not yet implemented. */
|
|
|
|
|
assert(sig->force_link == 0);
|
|
|
|
|
|
2004-12-17 05:47:47 +01:00
|
|
|
vvp_net_ptr_t ptr (net, 3);
|
|
|
|
|
vvp_send_long(ptr, 2);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool of_RELEASE_REG(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
|
|
|
|
vvp_net_t*net = cp->net;
|
|
|
|
|
|
2005-11-25 18:55:26 +01:00
|
|
|
vvp_fun_signal_base*sig = reinterpret_cast<vvp_fun_signal_base*>(net->fun);
|
2005-06-02 18:02:11 +02:00
|
|
|
assert(sig);
|
|
|
|
|
|
|
|
|
|
/* XXXX Release for %force/link not yet implemented. */
|
|
|
|
|
assert(sig->force_link == 0);
|
|
|
|
|
|
2004-12-17 05:47:47 +01:00
|
|
|
vvp_net_ptr_t ptr (net, 3);
|
|
|
|
|
vvp_send_long(ptr, 3);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2001-05-30 05:02:35 +02:00
|
|
|
|
2005-03-03 05:33:10 +01:00
|
|
|
/*
|
|
|
|
|
* This implements the "%set/mv <label>, <bit>, <wid>" instruction. In
|
|
|
|
|
* this case, the <label> is a memory label, and the <bit> and <wid>
|
|
|
|
|
* are the thread vector of a value to be written in.
|
|
|
|
|
*/
|
|
|
|
|
bool of_SET_MV(vthread_t thr, vvp_code_t cp)
|
2001-05-01 03:09:39 +02:00
|
|
|
{
|
2005-03-03 05:33:10 +01:00
|
|
|
unsigned bit = cp->bit_idx[0];
|
|
|
|
|
unsigned wid = cp->bit_idx[1];
|
2006-02-02 03:43:57 +01:00
|
|
|
unsigned off = thr->words[1].w_int;
|
2005-03-03 05:33:10 +01:00
|
|
|
unsigned adr = thr->words[3].w_int;
|
2001-05-01 03:09:39 +02:00
|
|
|
|
2005-03-03 05:33:10 +01:00
|
|
|
/* Make a vector of the desired width. */
|
|
|
|
|
vvp_vector4_t value = vthread_bits_to_vector(thr, bit, wid);
|
|
|
|
|
|
2006-02-02 03:43:57 +01:00
|
|
|
memory_set_word(cp->mem, adr, off, value);
|
2001-05-01 03:09:39 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2005-03-03 05:33:10 +01:00
|
|
|
|
2004-12-11 03:31:25 +01:00
|
|
|
/*
|
|
|
|
|
* This implements the "%set/v <label>, <bit>, <wid>" instruction.
|
|
|
|
|
*
|
|
|
|
|
* The <label> is a reference to a vvp_net_t object, and it is in
|
|
|
|
|
* cp->net.
|
|
|
|
|
*
|
|
|
|
|
* The <bit> is the thread bit address, and is in cp->bin_idx[0].
|
|
|
|
|
*
|
|
|
|
|
* The <wid> is the width of the vector I'm to make, and is in
|
|
|
|
|
* cp->bin_idx[1].
|
|
|
|
|
*/
|
2002-11-07 03:32:39 +01:00
|
|
|
bool of_SET_VEC(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
|
|
|
|
assert(cp->bit_idx[1] > 0);
|
|
|
|
|
unsigned bit = cp->bit_idx[0];
|
2004-12-11 03:31:25 +01:00
|
|
|
unsigned wid = cp->bit_idx[1];
|
2002-11-07 03:32:39 +01:00
|
|
|
|
2004-12-11 03:31:25 +01:00
|
|
|
/* set the value into port 0 of the destination. */
|
|
|
|
|
vvp_net_ptr_t ptr (cp->net, 0);
|
2005-08-27 04:34:42 +02:00
|
|
|
|
|
|
|
|
if (bit >= 4) {
|
2005-08-29 06:46:13 +02:00
|
|
|
vvp_vector4_t value(thr->bits4,bit,wid);
|
|
|
|
|
vvp_send_vec4(ptr, value);
|
2005-08-27 04:34:42 +02:00
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
/* Make a vector of the desired width. */
|
|
|
|
|
vvp_bit4_t bit_val = (vvp_bit4_t)bit;
|
|
|
|
|
vvp_vector4_t value(wid, bit_val);
|
|
|
|
|
|
|
|
|
|
vvp_send_vec4(ptr, value);
|
|
|
|
|
}
|
2002-11-07 03:32:39 +01:00
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2003-01-26 00:48:05 +01:00
|
|
|
bool of_SET_WORDR(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
|
|
|
|
struct __vpiHandle*tmp = cp->handle;
|
|
|
|
|
t_vpi_value val;
|
|
|
|
|
|
|
|
|
|
val.format = vpiRealVal;
|
|
|
|
|
val.value.real = thr->words[cp->bit_idx[0]].w_real;
|
|
|
|
|
vpi_put_value(tmp, &val, 0, vpiNoDelay);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2002-01-26 03:08:07 +01:00
|
|
|
/*
|
|
|
|
|
* Implement the %set/x instruction:
|
|
|
|
|
*
|
2005-03-22 06:18:34 +01:00
|
|
|
* %set/x <functor>, <bit>, <wid>
|
2002-01-26 03:08:07 +01:00
|
|
|
*
|
2005-03-22 06:18:34 +01:00
|
|
|
* The bit value of a vector go into the addressed functor. Do not
|
|
|
|
|
* transfer bits that are outside the signal range. Get the target
|
|
|
|
|
* vector dimensions from the vvp_fun_signal addressed by the vvp_net
|
|
|
|
|
* pointer.
|
2002-01-26 03:08:07 +01:00
|
|
|
*/
|
2002-11-21 23:43:13 +01:00
|
|
|
bool of_SET_X0(vthread_t thr, vvp_code_t cp)
|
2001-08-27 00:59:32 +02:00
|
|
|
{
|
2005-02-14 02:50:23 +01:00
|
|
|
vvp_net_t*net = cp->net;
|
2005-03-22 06:18:34 +01:00
|
|
|
unsigned bit = cp->bit_idx[0];
|
|
|
|
|
unsigned wid = cp->bit_idx[1];
|
2001-08-27 00:59:32 +02:00
|
|
|
|
2005-02-14 02:50:23 +01:00
|
|
|
// Implicitly, we get the base into the target vector from the
|
|
|
|
|
// X0 register.
|
2005-03-22 06:18:34 +01:00
|
|
|
long index = thr->words[0].w_int;
|
2005-02-14 02:50:23 +01:00
|
|
|
|
2005-11-26 18:16:05 +01:00
|
|
|
vvp_fun_signal_vec*sig = dynamic_cast<vvp_fun_signal_vec*> (net->fun);
|
2003-05-26 06:44:54 +02:00
|
|
|
|
2005-03-22 06:18:34 +01:00
|
|
|
if (index < 0 && (wid <= (unsigned)-index))
|
2003-05-26 06:44:54 +02:00
|
|
|
return true;
|
|
|
|
|
|
2005-03-22 06:18:34 +01:00
|
|
|
if (index >= (long)sig->size())
|
2003-05-26 06:44:54 +02:00
|
|
|
return true;
|
|
|
|
|
|
2005-03-22 06:18:34 +01:00
|
|
|
if (index < 0) {
|
|
|
|
|
wid -= (unsigned) -index;
|
|
|
|
|
index = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (index+wid > sig->size())
|
|
|
|
|
wid = sig->size() - index;
|
|
|
|
|
|
|
|
|
|
vvp_vector4_t bit_vec(wid);
|
|
|
|
|
for (unsigned idx = 0 ; idx < wid ; idx += 1) {
|
|
|
|
|
vvp_bit4_t bit_val = thr_get_bit(thr, bit);
|
|
|
|
|
bit_vec.set_bit(idx, bit_val);
|
|
|
|
|
if (bit >= 4)
|
|
|
|
|
bit += 1;
|
|
|
|
|
}
|
2003-05-26 06:44:54 +02:00
|
|
|
|
2005-02-14 02:50:23 +01:00
|
|
|
vvp_net_ptr_t ptr (net, 0);
|
2005-03-22 06:18:34 +01:00
|
|
|
vvp_send_vec4_pv(ptr, bit_vec, index, wid, sig->size());
|
2003-05-26 06:44:54 +02:00
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2001-06-23 20:26:26 +02:00
|
|
|
bool of_SHIFTL_I0(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
2001-11-01 04:00:19 +01:00
|
|
|
unsigned base = cp->bit_idx[0];
|
2001-06-23 20:26:26 +02:00
|
|
|
unsigned wid = cp->number;
|
2003-01-26 00:48:05 +01:00
|
|
|
unsigned long shift = thr->words[0].w_int;
|
2001-06-23 20:26:26 +02:00
|
|
|
|
2002-11-22 01:01:50 +01:00
|
|
|
assert(base >= 4);
|
2005-08-27 04:34:42 +02:00
|
|
|
thr_check_addr(thr, base+wid-1);
|
2002-11-22 01:01:50 +01:00
|
|
|
|
2001-06-23 20:26:26 +02:00
|
|
|
if (shift >= wid) {
|
2005-08-27 04:34:42 +02:00
|
|
|
// Shift is so far that all value is shifted out. Write
|
|
|
|
|
// in a constant 0 result.
|
|
|
|
|
vvp_vector4_t tmp (wid, BIT4_0);
|
|
|
|
|
thr->bits4.set_vec(base, tmp);
|
2001-06-23 20:26:26 +02:00
|
|
|
|
|
|
|
|
} else if (shift > 0) {
|
2005-08-27 04:34:42 +02:00
|
|
|
vvp_vector4_t tmp (thr->bits4, base, wid-shift);
|
|
|
|
|
thr->bits4.set_vec(base+shift, tmp);
|
|
|
|
|
|
|
|
|
|
// Fill zeros on the bottom
|
|
|
|
|
vvp_vector4_t fil (shift, BIT4_0);
|
|
|
|
|
thr->bits4.set_vec(base, fil);
|
2001-06-23 20:26:26 +02:00
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2001-06-30 23:07:26 +02:00
|
|
|
/*
|
2005-01-28 06:34:25 +01:00
|
|
|
* This is an unsigned right shift:
|
|
|
|
|
*
|
|
|
|
|
* %shiftr/i0 <bit>, <wid>
|
|
|
|
|
*
|
|
|
|
|
* The vector at address <bit> with width <wid> is shifted right a
|
|
|
|
|
* number of bits stored in index/word register 0.
|
2001-06-30 23:07:26 +02:00
|
|
|
*/
|
|
|
|
|
bool of_SHIFTR_I0(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
2001-11-01 04:00:19 +01:00
|
|
|
unsigned base = cp->bit_idx[0];
|
2001-06-30 23:07:26 +02:00
|
|
|
unsigned wid = cp->number;
|
2003-01-26 00:48:05 +01:00
|
|
|
unsigned long shift = thr->words[0].w_int;
|
2001-06-30 23:07:26 +02:00
|
|
|
|
2005-05-17 22:51:06 +02:00
|
|
|
if (shift > 0) {
|
|
|
|
|
unsigned idx;
|
|
|
|
|
for (idx = 0 ; (idx+shift) < wid ; idx += 1) {
|
2001-06-30 23:07:26 +02:00
|
|
|
unsigned src = base + idx + shift;
|
|
|
|
|
unsigned dst = base + idx;
|
|
|
|
|
thr_put_bit(thr, dst, thr_get_bit(thr, src));
|
|
|
|
|
}
|
2005-05-17 22:51:06 +02:00
|
|
|
for ( ; idx < wid ; idx += 1)
|
2005-08-27 04:34:42 +02:00
|
|
|
thr_put_bit(thr, base+idx, BIT4_0);
|
2001-06-30 23:07:26 +02:00
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2003-06-18 05:55:18 +02:00
|
|
|
bool of_SHIFTR_S_I0(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
|
|
|
|
unsigned base = cp->bit_idx[0];
|
|
|
|
|
unsigned wid = cp->number;
|
|
|
|
|
unsigned long shift = thr->words[0].w_int;
|
2005-08-27 04:34:42 +02:00
|
|
|
vvp_bit4_t sign = thr_get_bit(thr, base+wid-1);
|
2003-06-18 05:55:18 +02:00
|
|
|
|
|
|
|
|
if (shift >= wid) {
|
|
|
|
|
for (unsigned idx = 0 ; idx < wid ; idx += 1)
|
|
|
|
|
thr_put_bit(thr, base+idx, sign);
|
|
|
|
|
|
|
|
|
|
} else if (shift > 0) {
|
|
|
|
|
for (unsigned idx = 0 ; idx < (wid-shift) ; idx += 1) {
|
|
|
|
|
unsigned src = base + idx + shift;
|
|
|
|
|
unsigned dst = base + idx;
|
|
|
|
|
thr_put_bit(thr, dst, thr_get_bit(thr, src));
|
|
|
|
|
}
|
|
|
|
|
for (unsigned idx = (wid-shift) ; idx < wid ; idx += 1)
|
|
|
|
|
thr_put_bit(thr, base+idx, sign);
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2001-05-02 03:57:25 +02:00
|
|
|
bool of_SUB(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
2001-11-01 04:00:19 +01:00
|
|
|
assert(cp->bit_idx[0] >= 4);
|
2001-05-02 03:57:25 +02:00
|
|
|
|
2001-11-01 04:00:19 +01:00
|
|
|
unsigned long*lva = vector_to_array(thr, cp->bit_idx[0], cp->number);
|
|
|
|
|
unsigned long*lvb = vector_to_array(thr, cp->bit_idx[1], cp->number);
|
2001-07-04 06:57:10 +02:00
|
|
|
if (lva == 0 || lvb == 0)
|
|
|
|
|
goto x_out;
|
2001-05-02 03:57:25 +02:00
|
|
|
|
|
|
|
|
|
2001-09-08 01:29:28 +02:00
|
|
|
unsigned carry;
|
2001-07-04 06:57:10 +02:00
|
|
|
carry = 1;
|
2001-05-02 03:57:25 +02:00
|
|
|
for (unsigned idx = 0 ; idx < cp->number ; idx += 1) {
|
2001-09-08 01:29:28 +02:00
|
|
|
unsigned long tmp;
|
|
|
|
|
unsigned sum = carry;
|
|
|
|
|
|
2002-05-31 02:05:49 +02:00
|
|
|
tmp = lva[idx/CPU_WORD_BITS];
|
|
|
|
|
sum += 1 & (tmp >> (idx%CPU_WORD_BITS));
|
2001-09-08 01:29:28 +02:00
|
|
|
|
2002-05-31 02:05:49 +02:00
|
|
|
tmp = lvb[idx/CPU_WORD_BITS];
|
|
|
|
|
sum += 1 & ~(tmp >> (idx%CPU_WORD_BITS));
|
2001-09-08 01:29:28 +02:00
|
|
|
|
|
|
|
|
carry = sum / 2;
|
2005-08-27 04:34:42 +02:00
|
|
|
thr_put_bit(thr, cp->bit_idx[0]+idx, (sum&1) ? BIT4_1 : BIT4_0);
|
2001-05-02 03:57:25 +02:00
|
|
|
}
|
|
|
|
|
|
2001-07-04 06:57:10 +02:00
|
|
|
delete[]lva;
|
|
|
|
|
delete[]lvb;
|
|
|
|
|
|
2001-05-02 03:57:25 +02:00
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
x_out:
|
2001-07-04 06:57:10 +02:00
|
|
|
delete[]lva;
|
|
|
|
|
delete[]lvb;
|
|
|
|
|
|
2001-05-02 03:57:25 +02:00
|
|
|
for (unsigned idx = 0 ; idx < cp->number ; idx += 1)
|
2005-08-27 04:34:42 +02:00
|
|
|
thr_put_bit(thr, cp->bit_idx[0]+idx, BIT4_X);
|
2001-05-02 03:57:25 +02:00
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2003-02-06 18:41:47 +01:00
|
|
|
bool of_SUB_WR(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
|
|
|
|
double l = thr->words[cp->bit_idx[0]].w_real;
|
|
|
|
|
double r = thr->words[cp->bit_idx[1]].w_real;
|
|
|
|
|
thr->words[cp->bit_idx[0]].w_real = l - r;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2002-08-28 20:38:07 +02:00
|
|
|
bool of_SUBI(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
|
|
|
|
assert(cp->bit_idx[0] >= 4);
|
|
|
|
|
|
|
|
|
|
unsigned word_count = (cp->number+CPU_WORD_BITS-1)/CPU_WORD_BITS;
|
|
|
|
|
|
|
|
|
|
unsigned long*lva = vector_to_array(thr, cp->bit_idx[0], cp->number);
|
|
|
|
|
unsigned long*lvb;
|
|
|
|
|
if (lva == 0)
|
|
|
|
|
goto x_out;
|
|
|
|
|
|
|
|
|
|
lvb = new unsigned long[word_count];
|
|
|
|
|
|
2003-09-01 06:03:38 +02:00
|
|
|
|
|
|
|
|
lvb[0] = cp->bit_idx[1];
|
|
|
|
|
lvb[0] = ~lvb[0];
|
2002-08-28 20:38:07 +02:00
|
|
|
for (unsigned idx = 1 ; idx < word_count ; idx += 1)
|
2003-09-01 06:03:38 +02:00
|
|
|
lvb[idx] = ~0UL;
|
2002-08-28 20:38:07 +02:00
|
|
|
|
|
|
|
|
unsigned long carry;
|
|
|
|
|
carry = 1;
|
|
|
|
|
for (unsigned idx = 0 ; (idx*CPU_WORD_BITS) < cp->number ; idx += 1) {
|
|
|
|
|
|
|
|
|
|
unsigned long tmp = lvb[idx] + carry;
|
|
|
|
|
unsigned long sum = lva[idx] + tmp;
|
2003-09-01 06:03:38 +02:00
|
|
|
carry = 0UL;
|
2002-08-28 20:38:07 +02:00
|
|
|
if (tmp < lvb[idx])
|
|
|
|
|
carry = 1;
|
|
|
|
|
if (sum < tmp)
|
|
|
|
|
carry = 1;
|
|
|
|
|
if (sum < lva[idx])
|
|
|
|
|
carry = 1;
|
|
|
|
|
lva[idx] = sum;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < cp->number ; idx += 1) {
|
|
|
|
|
unsigned bit = lva[idx/CPU_WORD_BITS] >> (idx % CPU_WORD_BITS);
|
2005-05-17 22:51:06 +02:00
|
|
|
thr_put_bit(thr, cp->bit_idx[0]+idx, (bit&1) ? BIT4_1 : BIT4_0);
|
2002-08-28 20:38:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
delete[]lva;
|
|
|
|
|
delete[]lvb;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
x_out:
|
|
|
|
|
delete[]lva;
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < cp->number ; idx += 1)
|
2005-08-27 04:34:42 +02:00
|
|
|
thr_put_bit(thr, cp->bit_idx[0]+idx, BIT4_X);
|
2002-08-28 20:38:07 +02: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-05-10 02:26:53 +02:00
|
|
|
vpip_execute_vpi_call(thr, cp->handle);
|
2003-02-22 07:26:58 +01:00
|
|
|
|
|
|
|
|
if (schedule_stopped()) {
|
|
|
|
|
if (! schedule_finished())
|
|
|
|
|
schedule_vthread(thr, 0, false);
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return schedule_finished()? false : true;
|
2001-03-16 02:44:34 +01:00
|
|
|
}
|
|
|
|
|
|
2004-12-11 03:31:25 +01:00
|
|
|
/* %wait <label>;
|
|
|
|
|
* Implement the wait by locating the vvp_net_T for the event, and
|
|
|
|
|
* adding this thread to the threads list for the event. The some
|
|
|
|
|
* argument is the reference to the functor to wait for. This must be
|
|
|
|
|
* an event object of some sort.
|
2001-03-26 06:00:39 +02:00
|
|
|
*/
|
|
|
|
|
bool of_WAIT(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
2001-04-13 05:55:18 +02:00
|
|
|
assert(! thr->waiting_for_event);
|
|
|
|
|
thr->waiting_for_event = 1;
|
2004-12-11 03:31:25 +01:00
|
|
|
|
|
|
|
|
vvp_net_t*net = cp->net;
|
|
|
|
|
/* Get the functor as a waitable_hooks_s object. */
|
|
|
|
|
waitable_hooks_s*ep = dynamic_cast<waitable_hooks_s*> (net->fun);
|
2001-10-31 05:27:46 +01:00
|
|
|
assert(ep);
|
2004-12-11 03:31:25 +01:00
|
|
|
/* Add this thread to the list in the event. */
|
2001-04-18 06:21:23 +02:00
|
|
|
thr->wait_next = ep->threads;
|
2001-03-26 06:00:39 +02:00
|
|
|
ep->threads = thr;
|
2004-12-11 03:31:25 +01:00
|
|
|
/* Return false to suspend this thread. */
|
2001-03-26 06:00:39 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2001-04-13 05:55:18 +02:00
|
|
|
|
2001-04-15 06:07:56 +02:00
|
|
|
bool of_XNOR(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
2001-11-01 04:00:19 +01:00
|
|
|
assert(cp->bit_idx[0] >= 4);
|
2001-04-15 06:07:56 +02:00
|
|
|
|
2001-11-01 04:00:19 +01:00
|
|
|
unsigned idx1 = cp->bit_idx[0];
|
|
|
|
|
unsigned idx2 = cp->bit_idx[1];
|
2001-04-15 06:07:56 +02:00
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < cp->number ; idx += 1) {
|
|
|
|
|
|
2005-08-27 04:34:42 +02:00
|
|
|
vvp_bit4_t lb = thr_get_bit(thr, idx1);
|
|
|
|
|
vvp_bit4_t rb = thr_get_bit(thr, idx2);
|
|
|
|
|
thr_put_bit(thr, idx1, ~(lb ^ rb));
|
2001-04-15 06:07:56 +02:00
|
|
|
|
|
|
|
|
idx1 += 1;
|
|
|
|
|
if (idx2 >= 4)
|
|
|
|
|
idx2 += 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2001-04-15 18:37:48 +02:00
|
|
|
bool of_XOR(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
2001-11-01 04:00:19 +01:00
|
|
|
assert(cp->bit_idx[0] >= 4);
|
2001-04-15 18:37:48 +02:00
|
|
|
|
2001-11-01 04:00:19 +01:00
|
|
|
unsigned idx1 = cp->bit_idx[0];
|
|
|
|
|
unsigned idx2 = cp->bit_idx[1];
|
2001-04-15 18:37:48 +02:00
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < cp->number ; idx += 1) {
|
|
|
|
|
|
2005-05-17 22:51:06 +02:00
|
|
|
vvp_bit4_t lb = thr_get_bit(thr, idx1);
|
|
|
|
|
vvp_bit4_t rb = thr_get_bit(thr, idx2);
|
2001-04-15 18:37:48 +02:00
|
|
|
|
2005-05-17 22:51:06 +02:00
|
|
|
if ((lb == BIT4_1) && (rb == BIT4_1)) {
|
|
|
|
|
thr_put_bit(thr, idx1, BIT4_0);
|
2001-04-15 18:37:48 +02:00
|
|
|
|
2005-05-17 22:51:06 +02:00
|
|
|
} else if ((lb == BIT4_0) && (rb == BIT4_0)) {
|
|
|
|
|
thr_put_bit(thr, idx1, BIT4_0);
|
2001-04-15 18:37:48 +02:00
|
|
|
|
2005-05-17 22:51:06 +02:00
|
|
|
} else if ((lb == BIT4_1) && (rb == BIT4_0)) {
|
|
|
|
|
thr_put_bit(thr, idx1, BIT4_1);
|
2001-04-15 18:37:48 +02:00
|
|
|
|
2005-05-17 22:51:06 +02:00
|
|
|
} else if ((lb == BIT4_0) && (rb == BIT4_1)) {
|
|
|
|
|
thr_put_bit(thr, idx1, BIT4_1);
|
2001-04-15 18:37:48 +02:00
|
|
|
|
|
|
|
|
} else {
|
2005-05-17 22:51:06 +02:00
|
|
|
thr_put_bit(thr, idx1, BIT4_X);
|
2001-04-15 18:37:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
idx1 += 1;
|
|
|
|
|
if (idx2 >= 4)
|
|
|
|
|
idx2 += 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2001-04-18 06:21:23 +02:00
|
|
|
bool of_ZOMBIE(vthread_t thr, vvp_code_t)
|
2001-04-13 05:55:18 +02:00
|
|
|
{
|
2003-07-03 22:03:36 +02:00
|
|
|
thr->pc = codespace_null();
|
2001-04-18 06:21:23 +02:00
|
|
|
if ((thr->parent == 0) && (thr->child == 0))
|
|
|
|
|
delete thr;
|
|
|
|
|
|
2001-04-13 05:55:18 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2002-03-18 01:19:34 +01:00
|
|
|
/*
|
2003-05-07 05:39:12 +02:00
|
|
|
* These are phantom opcode used to call user defined functions.
|
|
|
|
|
* They are used in code generated by the .ufunc statement. They
|
|
|
|
|
* contain a pointer to executable code of the function, and to a
|
2002-03-18 01:19:34 +01:00
|
|
|
* ufunc_core object that has all the port information about the
|
|
|
|
|
* function.
|
|
|
|
|
*/
|
2003-05-07 05:39:12 +02:00
|
|
|
bool of_FORK_UFUNC(vthread_t thr, vvp_code_t cp)
|
2002-03-18 01:19:34 +01:00
|
|
|
{
|
|
|
|
|
/* Copy all the inputs to the ufunc object to the port
|
|
|
|
|
variables of the function. This copies all the values
|
|
|
|
|
atomically. */
|
|
|
|
|
cp->ufunc_core_ptr->assign_bits_to_ports();
|
|
|
|
|
|
2003-05-07 05:39:12 +02:00
|
|
|
assert(thr->child == 0);
|
|
|
|
|
assert(thr->fork_count == 0);
|
|
|
|
|
|
|
|
|
|
/* Create a temporary thread, and push its execution. This is
|
|
|
|
|
done so that the assign_bits_to_ports above is atomic with
|
|
|
|
|
this startup. */
|
2002-03-18 01:19:34 +01:00
|
|
|
vthread_t child = vthread_new(cp->cptr, cp->ufunc_core_ptr->scope());
|
|
|
|
|
|
2003-05-07 05:39:12 +02:00
|
|
|
child->child = 0;
|
|
|
|
|
child->parent = thr;
|
|
|
|
|
thr->child = child;
|
|
|
|
|
|
|
|
|
|
thr->fork_count += 1;
|
|
|
|
|
schedule_vthread(child, 0, true);
|
|
|
|
|
|
|
|
|
|
/* After this function, the .ufunc code has placed an of_JOIN
|
|
|
|
|
to pause this thread. Since the child was pushed by the
|
|
|
|
|
flag to schecule_vthread, the called function starts up
|
|
|
|
|
immediately. */
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool of_JOIN_UFUNC(vthread_t thr, vvp_code_t cp)
|
|
|
|
|
{
|
2002-03-18 01:19:34 +01:00
|
|
|
/* Now copy the output from the result variable to the output
|
|
|
|
|
ports of the .ufunc device. */
|
|
|
|
|
cp->ufunc_core_ptr->finish_thread(thr);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2001-03-11 01:29:38 +01:00
|
|
|
/*
|
|
|
|
|
* $Log: vthread.cc,v $
|
2006-02-02 03:43:57 +01:00
|
|
|
* Revision 1.151 2006/02/02 02:44:00 steve
|
|
|
|
|
* Allow part selects of memory words in l-values.
|
|
|
|
|
*
|
2005-11-26 18:16:05 +01:00
|
|
|
* Revision 1.150 2005/11/26 17:16:05 steve
|
|
|
|
|
* Force instruction that can be indexed.
|
|
|
|
|
*
|
2005-11-25 18:55:26 +01:00
|
|
|
* Revision 1.149 2005/11/25 17:55:26 steve
|
|
|
|
|
* Put vec8 and vec4 nets into seperate net classes.
|
|
|
|
|
*
|
2005-09-19 23:45:35 +02:00
|
|
|
* Revision 1.148 2005/09/19 21:45:37 steve
|
|
|
|
|
* Spelling patches from Larry.
|
|
|
|
|
*
|
2005-09-17 06:01:01 +02:00
|
|
|
* Revision 1.147 2005/09/17 04:01:02 steve
|
|
|
|
|
* Add the load/v.p instruction.
|
|
|
|
|
*
|
2005-09-14 04:50:07 +02:00
|
|
|
* Revision 1.146 2005/09/14 02:50:07 steve
|
|
|
|
|
* Add word integer compares.
|
|
|
|
|
*
|
2005-08-30 02:49:21 +02:00
|
|
|
* Revision 1.145 2005/08/30 00:49:21 steve
|
|
|
|
|
* minor correction to address check in of_MOV1XZ
|
|
|
|
|
*
|
2005-08-29 06:46:13 +02:00
|
|
|
* Revision 1.144 2005/08/29 04:46:13 steve
|
|
|
|
|
* Minor cleanup.
|
|
|
|
|
*
|
2005-08-27 05:28:57 +02:00
|
|
|
* Revision 1.143 2005/08/27 03:28:57 steve
|
|
|
|
|
* Fix bit destination address in of_AND
|
|
|
|
|
*
|
2005-08-27 04:34:42 +02:00
|
|
|
* Revision 1.142 2005/08/27 02:34:42 steve
|
|
|
|
|
* Bring threads into the vvp_vector4_t structure.
|
|
|
|
|
*
|
2005-06-26 03:57:22 +02:00
|
|
|
* Revision 1.141 2005/06/26 01:57:22 steve
|
|
|
|
|
* Make bit masks of vector4_t 64bit aware.
|
|
|
|
|
*
|
2005-06-19 20:42:00 +02:00
|
|
|
* Revision 1.140 2005/06/19 18:42:00 steve
|
|
|
|
|
* Optimize the LOAD_VEC implementation.
|
|
|
|
|
*
|
2005-06-14 03:44:09 +02:00
|
|
|
* Revision 1.139 2005/06/14 01:44:10 steve
|
|
|
|
|
* Add the assign_v0_d instruction.
|
|
|
|
|
*
|
2005-06-12 03:25:27 +02:00
|
|
|
* Revision 1.138 2005/06/12 01:25:27 steve
|
|
|
|
|
* Remove useless references to functor.h
|
|
|
|
|
*
|
2005-06-02 18:02:11 +02:00
|
|
|
* Revision 1.137 2005/06/02 16:02:11 steve
|
|
|
|
|
* Add support for notif0/1 gates.
|
|
|
|
|
* Make delay nodes support inertial delay.
|
|
|
|
|
* Add the %force/link instruction.
|
|
|
|
|
*
|
2005-05-17 22:51:06 +02:00
|
|
|
* Revision 1.136 2005/05/17 20:51:06 steve
|
|
|
|
|
* Clean up instruction type reverences to bits.
|
|
|
|
|
*
|
2005-05-07 05:15:42 +02:00
|
|
|
* Revision 1.135 2005/05/07 03:15:42 steve
|
|
|
|
|
* Implement non-blocking part assign.
|
|
|
|
|
*
|
2005-05-02 00:05:21 +02:00
|
|
|
* Revision 1.134 2005/05/01 22:05:21 steve
|
|
|
|
|
* Add cassign/link instruction.
|
|
|
|
|
*
|
2005-03-22 06:18:34 +01:00
|
|
|
* Revision 1.133 2005/03/22 05:18:34 steve
|
|
|
|
|
* The indexed set can write a vector, not just a bit.
|
|
|
|
|
*
|
2005-03-06 18:07:48 +01:00
|
|
|
* Revision 1.132 2005/03/06 17:07:48 steve
|
|
|
|
|
* Non blocking assign to memory words.
|
|
|
|
|
*
|
2005-03-05 06:45:18 +01:00
|
|
|
* Revision 1.131 2005/03/05 05:45:18 steve
|
|
|
|
|
* Check that lead.mv vector width matches word.
|
|
|
|
|
*
|
2005-03-03 05:33:10 +01:00
|
|
|
* Revision 1.130 2005/03/03 04:33:10 steve
|
|
|
|
|
* Rearrange how memories are supported as vvp_vector4 arrays.
|
|
|
|
|
*
|
2005-02-14 02:50:23 +01:00
|
|
|
* Revision 1.129 2005/02/14 01:50:23 steve
|
|
|
|
|
* Signals may receive part vectors from %set/x0
|
|
|
|
|
* instructions. Re-implement the %set/x0 to do
|
|
|
|
|
* just that. Remove the useless %set/x0/x instruction.
|
|
|
|
|
*
|
2005-02-12 07:13:22 +01:00
|
|
|
* Revision 1.128 2005/02/12 06:13:22 steve
|
|
|
|
|
* Add debug dumps for vectors, and fix vvp_scaler_t make from BIT4_X values.
|
|
|
|
|
*
|
2005-01-28 06:34:25 +01:00
|
|
|
* Revision 1.127 2005/01/28 05:34:25 steve
|
|
|
|
|
* Add vector4 implementation of .arith/mult.
|
|
|
|
|
*
|
2005-01-22 01:58:22 +01:00
|
|
|
* Revision 1.126 2005/01/22 00:58:22 steve
|
|
|
|
|
* Implement the %load/x instruction.
|
|
|
|
|
*
|
2004-12-17 05:47:47 +01:00
|
|
|
* Revision 1.125 2004/12/17 04:47:47 steve
|
|
|
|
|
* Replace single release with release/net and release/reg.
|
|
|
|
|
*
|
2004-12-15 18:17:42 +01:00
|
|
|
* Revision 1.124 2004/12/15 17:17:42 steve
|
|
|
|
|
* Add the force/v instruction.
|
|
|
|
|
*
|
2004-12-11 03:31:25 +01:00
|
|
|
* Revision 1.123 2004/12/11 02:31:30 steve
|
|
|
|
|
* Rework of internals to carry vectors through nexus instead
|
|
|
|
|
* of single bits. Make the ivl, tgt-vvp and vvp initial changes
|
|
|
|
|
* down this path.
|
|
|
|
|
*
|
2004-10-04 03:10:51 +02:00
|
|
|
* Revision 1.122 2004/10/04 01:11:00 steve
|
|
|
|
|
* Clean up spurious trailing white space.
|
|
|
|
|
*
|
2004-06-19 18:17:02 +02:00
|
|
|
* Revision 1.121 2004/06/19 16:17:02 steve
|
|
|
|
|
* Watch type of mak bit matches masked value.
|
|
|
|
|
*
|
2004-06-19 17:52:53 +02:00
|
|
|
* Revision 1.120 2004/06/19 15:52:53 steve
|
|
|
|
|
* Add signed modulus operator.
|
|
|
|
|
*
|
2004-06-05 01:26:34 +02:00
|
|
|
* Revision 1.119 2004/06/04 23:26:34 steve
|
|
|
|
|
* Pick sign bit from the right place in the exponent number.
|
|
|
|
|
*
|
2004-05-19 05:26:24 +02:00
|
|
|
* Revision 1.118 2004/05/19 03:26:25 steve
|
|
|
|
|
* Support delayed/non-blocking assignment to reals and others.
|
|
|
|
|
*
|
2003-11-10 21:19:32 +01:00
|
|
|
* Revision 1.117 2003/11/10 20:19:32 steve
|
|
|
|
|
* Include config.h
|
|
|
|
|
*
|
2003-09-26 04:15:15 +02:00
|
|
|
* Revision 1.116 2003/09/26 02:15:15 steve
|
|
|
|
|
* Slight performance tweaks of scheduler.
|
|
|
|
|
*
|
2003-09-01 06:03:38 +02:00
|
|
|
* Revision 1.115 2003/09/01 04:03:38 steve
|
|
|
|
|
* 32bit vs 64bit handling in SUBI.
|
|
|
|
|
*
|
2003-08-01 02:58:03 +02:00
|
|
|
* Revision 1.114 2003/08/01 00:58:03 steve
|
|
|
|
|
* Initialize allocated memory.
|
|
|
|
|
*
|
2003-07-21 04:39:15 +02:00
|
|
|
* Revision 1.113 2003/07/21 02:39:15 steve
|
|
|
|
|
* Overflow of unsigned when calculating unsigned long value.
|
|
|
|
|
*
|
2003-07-03 22:03:36 +02:00
|
|
|
* Revision 1.112 2003/07/03 20:03:36 steve
|
|
|
|
|
* Remove the vvp_cpoint_t indirect code pointer.
|
|
|
|
|
*
|
2003-06-18 05:55:18 +02:00
|
|
|
* Revision 1.111 2003/06/18 03:55:19 steve
|
|
|
|
|
* Add arithmetic shift operators.
|
|
|
|
|
*
|
2003-06-17 23:28:59 +02:00
|
|
|
* Revision 1.110 2003/06/17 21:28:59 steve
|
|
|
|
|
* Remove short int restrictions from vvp opcodes. (part 2)
|
|
|
|
|
*
|
2003-06-17 21:17:42 +02:00
|
|
|
* Revision 1.109 2003/06/17 19:17:42 steve
|
|
|
|
|
* Remove short int restrictions from vvp opcodes.
|
|
|
|
|
*
|
2003-05-26 06:44:54 +02:00
|
|
|
* Revision 1.108 2003/05/26 04:44:54 steve
|
|
|
|
|
* Add the set/x0/x instruction.
|
|
|
|
|
*
|
2003-05-07 05:39:12 +02:00
|
|
|
* Revision 1.107 2003/05/07 03:39:12 steve
|
|
|
|
|
* ufunc calls to functions can have scheduling complexities.
|
|
|
|
|
*
|
2003-03-28 03:33:56 +01:00
|
|
|
* Revision 1.106 2003/03/28 02:33:57 steve
|
|
|
|
|
* Add support for division of real operands.
|
|
|
|
|
*
|
2003-03-13 05:36:57 +01:00
|
|
|
* Revision 1.105 2003/03/13 04:36:57 steve
|
|
|
|
|
* Remove the obsolete functor delete functions.
|
|
|
|
|
*
|
2003-02-27 21:36:29 +01:00
|
|
|
* Revision 1.104 2003/02/27 20:36:29 steve
|
|
|
|
|
* Add the cvt/vr instruction.
|
|
|
|
|
*
|
2003-02-22 07:26:58 +01:00
|
|
|
* Revision 1.103 2003/02/22 06:26:58 steve
|
|
|
|
|
* When checking for stop, remember to reschedule.
|
|
|
|
|
*
|
2003-02-22 03:52:06 +01:00
|
|
|
* Revision 1.102 2003/02/22 02:52:06 steve
|
|
|
|
|
* Check for stopped flag in certain strategic points.
|
|
|
|
|
*
|
2003-02-10 00:33:26 +01:00
|
|
|
* Revision 1.101 2003/02/09 23:33:26 steve
|
|
|
|
|
* Spelling fixes.
|
|
|
|
|
*
|
2003-02-06 18:41:47 +01:00
|
|
|
* Revision 1.100 2003/02/06 17:41:47 steve
|
|
|
|
|
* Add the %sub/wr instruction.
|
2001-03-11 01:29:38 +01:00
|
|
|
*/
|
|
|
|
|
|