Add support for 64 bit delays in procedural non-blocking assignments.

This patch adds support for 64 bit non-blocking delays in procedural
code. We fixed the procedural delay operator (blocking delays) earlier.
This patch mostly mimics what was done there. The continuous assignment
delay operator still needs to be fixed.
This commit is contained in:
Cary R 2009-02-16 16:44:52 -08:00 committed by Stephen Williams
parent 93ad8ff95f
commit 5ae86bd6b4
11 changed files with 231 additions and 110 deletions

View File

@ -39,6 +39,7 @@ ivl_expr_type
ivl_expr_bits ivl_expr_bits
ivl_expr_branch ivl_expr_branch
ivl_expr_def ivl_expr_def
ivl_expr_delay_val
ivl_expr_dvalue ivl_expr_dvalue
ivl_expr_event ivl_expr_event
ivl_expr_file ivl_expr_file

View File

@ -1,7 +1,7 @@
#ifndef __ivl_target_H #ifndef __ivl_target_H
#define __ivl_target_H #define __ivl_target_H
/* /*
* Copyright (c) 2000-2008 Stephen Williams (steve@icarus.com) * Copyright (c) 2000-2009 Stephen Williams (steve@icarus.com)
* *
* This source code is free software; you can redistribute it * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -211,6 +211,7 @@ typedef enum ivl_expr_type_e {
IVL_EX_BACCESS= 19, IVL_EX_BACCESS= 19,
IVL_EX_BINARY = 2, IVL_EX_BINARY = 2,
IVL_EX_CONCAT = 3, IVL_EX_CONCAT = 3,
IVL_EX_DELAY = 20,
IVL_EX_EVENT = 17, IVL_EX_EVENT = 17,
IVL_EX_MEMORY = 4, IVL_EX_MEMORY = 4,
IVL_EX_NUMBER = 5, IVL_EX_NUMBER = 5,
@ -749,6 +750,8 @@ extern const char* ivl_expr_bits(ivl_expr_t net);
extern ivl_branch_t ivl_expr_branch(ivl_expr_t net); extern ivl_branch_t ivl_expr_branch(ivl_expr_t net);
/* IVL_EX_UFUNC */ /* IVL_EX_UFUNC */
extern ivl_scope_t ivl_expr_def(ivl_expr_t net); extern ivl_scope_t ivl_expr_def(ivl_expr_t net);
/* IVL_EX_DELAY */
extern uint64_t ivl_expr_delay_val(ivl_expr_t net);
/* IVL_EX_REALNUM */ /* IVL_EX_REALNUM */
extern double ivl_expr_dvalue(ivl_expr_t net); extern double ivl_expr_dvalue(ivl_expr_t net);
/* IVL_EX_SIGNAL, IVL_EX_SFUNC, IVL_EX_VARIABLE */ /* IVL_EX_SIGNAL, IVL_EX_SFUNC, IVL_EX_VARIABLE */

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2000-2008 Stephen Williams (steve@icarus.com) * Copyright (c) 2000-2009 Stephen Williams (steve@icarus.com)
* *
* This source code is free software; you can redistribute it * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -309,6 +309,12 @@ extern "C" ivl_scope_t ivl_expr_def(ivl_expr_t net)
return 0; return 0;
} }
extern "C" uint64_t ivl_expr_delay_val(ivl_expr_t net)
{
assert(net->type_ == IVL_EX_DELAY);
return net->u_.delay_.value;
}
extern "C" double ivl_expr_dvalue(ivl_expr_t net) extern "C" double ivl_expr_dvalue(ivl_expr_t net)
{ {
assert(net->type_ == IVL_EX_REALNUM); assert(net->type_ == IVL_EX_REALNUM);
@ -2137,7 +2143,7 @@ extern "C" ivl_expr_t ivl_stmt_delay_expr(ivl_statement_t net)
extern "C" uint64_t ivl_stmt_delay_val(ivl_statement_t net) extern "C" uint64_t ivl_stmt_delay_val(ivl_statement_t net)
{ {
assert(net->type_ == IVL_ST_DELAY); assert(net->type_ == IVL_ST_DELAY);
return net->u_.delay_.delay_; return net->u_.delay_.value;
} }
extern "C" unsigned ivl_stmt_nevent(ivl_statement_t net) extern "C" unsigned ivl_stmt_nevent(ivl_statement_t net)

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2000-2008 Stephen Williams (steve@icarus.com) * Copyright (c) 2000-2009 Stephen Williams (steve@icarus.com)
* *
* This source code is free software; you can redistribute it * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -249,10 +249,10 @@ void dll_target::proc_assign_nb(const NetAssignNB*net)
if (const NetEConst*delay_num = dynamic_cast<const NetEConst*>(delay_exp)) { if (const NetEConst*delay_num = dynamic_cast<const NetEConst*>(delay_exp)) {
verinum val = delay_num->value(); verinum val = delay_num->value();
ivl_expr_t de = new struct ivl_expr_s; ivl_expr_t de = new struct ivl_expr_s;
de->type_ = IVL_EX_ULONG; de->type_ = IVL_EX_DELAY;
de->width_ = 8 * sizeof(unsigned long); de->width_ = 8 * sizeof(uint64_t);
de->signed_ = 0; de->signed_ = 0;
de->u_.ulong_.value = val.as_ulong(); de->u_.delay_.value = val.as_ulong64();
stmt_cur_->u_.assign_.delay = de; stmt_cur_->u_.assign_.delay = de;
} else if (delay_exp != 0) { } else if (delay_exp != 0) {
@ -563,7 +563,7 @@ bool dll_target::proc_delay(const NetPDelay*net)
} else { } else {
stmt_cur_->type_ = IVL_ST_DELAY; stmt_cur_->type_ = IVL_ST_DELAY;
stmt_cur_->u_.delay_.stmt_ = tmp; stmt_cur_->u_.delay_.stmt_ = tmp;
stmt_cur_->u_.delay_.delay_ = net->delay(); stmt_cur_->u_.delay_.value = net->delay();
} }
ivl_statement_t save_cur_ = stmt_cur_; ivl_statement_t save_cur_ = stmt_cur_;

View File

@ -291,6 +291,10 @@ struct ivl_expr_s {
ivl_expr_t sub_; ivl_expr_t sub_;
} unary_; } unary_;
struct {
uint64_t value;
} delay_;
} u_; } u_;
}; };
@ -714,7 +718,7 @@ struct ivl_statement_s {
} contrib_; } contrib_;
struct { /* IVL_ST_DELAY */ struct { /* IVL_ST_DELAY */
uint64_t delay_; uint64_t value;
ivl_statement_t stmt_; ivl_statement_t stmt_;
} delay_; } delay_;

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2005-2008 Stephen Williams (steve@icarus.com) * Copyright (c) 2005-2009 Stephen Williams (steve@icarus.com)
* *
* This source code is free software; you can redistribute it * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -64,7 +64,7 @@ static int draw_number_bool64(ivl_expr_t expr)
int res; int res;
const char*bits = ivl_expr_bits(expr); const char*bits = ivl_expr_bits(expr);
uint64_t val = 0; uint64_t val = 0;
unsigned long idx; unsigned long idx, low, hig;
for (idx = 0 ; idx < ivl_expr_width(expr) ; idx += 1) { for (idx = 0 ; idx < ivl_expr_width(expr) ; idx += 1) {
if (bits[idx] == '1') if (bits[idx] == '1')
@ -72,7 +72,9 @@ static int draw_number_bool64(ivl_expr_t expr)
} }
res = allocate_word(); res = allocate_word();
fprintf(vvp_out, " %%ix/load %d, %" PRIu64 ";\n", res, val); low = val % UINT64_C(0x100000000);
hig = val / UINT64_C(0x100000000);
fprintf(vvp_out, " %%ix/load %d, %lu, %lu;\n", res, low, hig);
return res; return res;
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2001-2008 Stephen Williams (steve@icarus.com) * Copyright (c) 2001-2009 Stephen Williams (steve@icarus.com)
* *
* This source code is free software; you can redistribute it * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -62,7 +62,8 @@ int number_is_immediate(ivl_expr_t ex, unsigned lim_wid, int negative_ok_flag)
unsigned idx; unsigned idx;
if (ivl_expr_type(ex) != IVL_EX_NUMBER if (ivl_expr_type(ex) != IVL_EX_NUMBER
&& ivl_expr_type(ex) != IVL_EX_ULONG) && ivl_expr_type(ex) != IVL_EX_ULONG
&& ivl_expr_type(ex) != IVL_EX_DELAY)
return 0; return 0;
if (ivl_expr_type(ex) == IVL_EX_ULONG) { if (ivl_expr_type(ex) == IVL_EX_ULONG) {
@ -74,6 +75,12 @@ int number_is_immediate(ivl_expr_t ex, unsigned lim_wid, int negative_ok_flag)
else return 0; else return 0;
} }
if (ivl_expr_type(ex) == IVL_EX_DELAY) {
if (lim_wid >= 8*sizeof(uint64_t)) return 1;
/* For now we only support this as a 64 bit value. */
else return 0;
}
bits = ivl_expr_bits(ex); bits = ivl_expr_bits(ex);
if (ivl_expr_signed(ex) && bits[nbits-1]=='1') if (ivl_expr_signed(ex) && bits[nbits-1]=='1')
@ -134,10 +141,10 @@ static void eval_logic_into_integer(ivl_expr_t expr, unsigned ix)
assert(number_is_immediate(expr, IMM_WID, 1)); assert(number_is_immediate(expr, IMM_WID, 1));
long imm = get_number_immediate(expr); long imm = get_number_immediate(expr);
if (imm >= 0) { if (imm >= 0) {
fprintf(vvp_out, " %%ix/load %u, %ld;\n", ix, imm); fprintf(vvp_out, " %%ix/load %u, %ld, 0;\n", ix, imm);
} else { } else {
fprintf(vvp_out, " %%ix/load %u, 0; loading %ld\n", ix, imm); fprintf(vvp_out, " %%ix/load %u, 0, 0; loading %ld\n", ix, imm);
fprintf(vvp_out, " %%ix/sub %u, %ld;\n", ix, -imm); fprintf(vvp_out, " %%ix/sub %u, %ld, 0;\n", ix, -imm);
} }
/* This can not have have a X/Z value so clear bit 4. */ /* This can not have have a X/Z value so clear bit 4. */
fprintf(vvp_out, " %%mov 4, 0, 1;\n"); fprintf(vvp_out, " %%mov 4, 0, 1;\n");
@ -1200,6 +1207,7 @@ static struct vector_info draw_load_add_immediate(ivl_expr_t le,
{ {
struct vector_info lv; struct vector_info lv;
long imm = get_number_immediate(re); long imm = get_number_immediate(re);
assert(number_is_immediate(re, IMM_WID, 1));
lv.base = allocate_vector(wid); lv.base = allocate_vector(wid);
lv.wid = wid; lv.wid = wid;
if (lv.base == 0) { if (lv.base == 0) {
@ -2094,7 +2102,7 @@ static void draw_signal_dest(ivl_expr_t exp, struct vector_info res,
const char*sign_flag = (add_index>0)? "/s" : ""; const char*sign_flag = (add_index>0)? "/s" : "";
/* Add an immediate value to an array value. */ /* Add an immediate value to an array value. */
fprintf(vvp_out, " %%ix/load 0, %lu;\n", immediate); fprintf(vvp_out, " %%ix/load 0, %lu, 0;\n", immediate);
fprintf(vvp_out, " %%load/avp0%s %u, v%p, %u;\n", fprintf(vvp_out, " %%load/avp0%s %u, v%p, %u;\n",
sign_flag, res.base, sig, res.wid); sign_flag, res.base, sig, res.wid);
} }
@ -2117,10 +2125,10 @@ static void draw_signal_dest(ivl_expr_t exp, struct vector_info res,
/* If this is a REG (a variable) then I can do a vector read. */ /* If this is a REG (a variable) then I can do a vector read. */
if (immediate >= 0) { if (immediate >= 0) {
fprintf(vvp_out, " %%ix/load 0, %lu;\n", immediate); fprintf(vvp_out, " %%ix/load 0, %lu, 0;\n", immediate);
} else { } else {
fprintf(vvp_out, " %%ix/load 0, 0; immediate=%ld\n", immediate); fprintf(vvp_out, " %%ix/load 0, 0, 0; immediate=%ld\n", immediate);
fprintf(vvp_out, " %%ix/sub 0, %ld;\n", -immediate); fprintf(vvp_out, " %%ix/sub 0, %ld, 0;\n", -immediate);
} }
fprintf(vvp_out, " %%load/vp0%s %u, v%p_%u, %u;\n", sign_flag, fprintf(vvp_out, " %%load/vp0%s %u, v%p_%u, %u;\n", sign_flag,
res.base, sig,word, res.wid); res.base, sig,word, res.wid);

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2001-2008 Stephen Williams (steve@icarus.com) * Copyright (c) 2001-2009 Stephen Williams (steve@icarus.com)
* *
* This source code is free software; you can redistribute it * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -77,7 +77,7 @@ static void set_to_lvariable(ivl_lval_t lval,
{ {
ivl_signal_t sig = ivl_lval_sig(lval); ivl_signal_t sig = ivl_lval_sig(lval);
ivl_expr_t part_off_ex = ivl_lval_part_off(lval); ivl_expr_t part_off_ex = ivl_lval_part_off(lval);
unsigned part_off = 0; unsigned long part_off = 0;
/* Although Verilog doesn't support it, we'll handle /* Although Verilog doesn't support it, we'll handle
here the case of an l-value part select of an array here the case of an l-value part select of an array
@ -87,7 +87,7 @@ static void set_to_lvariable(ivl_lval_t lval,
if (part_off_ex == 0) { if (part_off_ex == 0) {
part_off = 0; part_off = 0;
} else if (number_is_immediate(part_off_ex, 64, 0)) { } else if (number_is_immediate(part_off_ex, IMM_WID, 0)) {
part_off = get_number_immediate(part_off_ex); part_off = get_number_immediate(part_off_ex);
part_off_ex = 0; part_off_ex = 0;
} }
@ -130,7 +130,7 @@ static void set_to_lvariable(ivl_lval_t lval,
draw_eval_expr_into_integer(word_ix, 3); draw_eval_expr_into_integer(word_ix, 3);
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set); fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set);
} else { } else {
fprintf(vvp_out, " %%ix/load 3, %lu;\n", use_word); fprintf(vvp_out, " %%ix/load 3, %lu, 0;\n", use_word);
} }
draw_eval_expr_into_integer(part_off_ex, 1); draw_eval_expr_into_integer(part_off_ex, 1);
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set); fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set);
@ -147,9 +147,9 @@ static void set_to_lvariable(ivl_lval_t lval,
draw_eval_expr_into_integer(word_ix, 3); draw_eval_expr_into_integer(word_ix, 3);
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set); fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set);
} else { } else {
fprintf(vvp_out, " %%ix/load 3, %lu;\n", use_word); fprintf(vvp_out, " %%ix/load 3, %lu, 0;\n", use_word);
} }
fprintf(vvp_out, " %%ix/load 1, %u;\n", part_off); fprintf(vvp_out, " %%ix/load 1, %lu, 0;\n", part_off);
fprintf(vvp_out, " %%set/av v%p, %u, %u;\n", fprintf(vvp_out, " %%set/av v%p, %u, %u;\n",
sig, bit, wid); sig, bit, wid);
if (word_ix) /* Only need this label if word_ix is set. */ if (word_ix) /* Only need this label if word_ix is set. */
@ -164,7 +164,7 @@ static void set_to_lvariable(ivl_lval_t lval,
/* If the word index is a constant, then we can write /* If the word index is a constant, then we can write
directly to the word and save the index calculation. */ directly to the word and save the index calculation. */
if (word_ix == 0) { if (word_ix == 0) {
fprintf(vvp_out, " %%ix/load 0, %u;\n", part_off); fprintf(vvp_out, " %%ix/load 0, %lu, 0;\n", part_off);
fprintf(vvp_out, " %%set/x0 v%p_%lu, %u, %u;\n", fprintf(vvp_out, " %%set/x0 v%p_%lu, %u, %u;\n",
sig, use_word, bit, wid); sig, use_word, bit, wid);
@ -173,7 +173,7 @@ static void set_to_lvariable(ivl_lval_t lval,
unsigned index_reg = 3; unsigned index_reg = 3;
draw_eval_expr_into_integer(word_ix, index_reg); draw_eval_expr_into_integer(word_ix, index_reg);
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set); fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set);
fprintf(vvp_out, " %%ix/load 1, %u;\n", part_off); fprintf(vvp_out, " %%ix/load 1, %lu, 0;\n", part_off);
fprintf(vvp_out, " %%set/av v%p, %u, %u;\n", fprintf(vvp_out, " %%set/av v%p, %u, %u;\n",
sig, bit, wid); sig, bit, wid);
fprintf(vvp_out, "t_%u ;\n", skip_set); fprintf(vvp_out, "t_%u ;\n", skip_set);
@ -188,8 +188,8 @@ static void set_to_lvariable(ivl_lval_t lval,
directly to the word and save the index calculation. */ directly to the word and save the index calculation. */
if (word_ix == 0) { if (word_ix == 0) {
if (use_word < ivl_signal_array_count(sig)) { if (use_word < ivl_signal_array_count(sig)) {
fprintf(vvp_out, " %%ix/load 1, 0;\n"); fprintf(vvp_out, " %%ix/load 1, 0, 0;\n");
fprintf(vvp_out, " %%ix/load 3, %lu;\n", use_word); fprintf(vvp_out, " %%ix/load 3, %lu, 0;\n", use_word);
fprintf(vvp_out, " %%set/av v%p, %u, %u;\n", fprintf(vvp_out, " %%set/av v%p, %u, %u;\n",
sig, bit, wid); sig, bit, wid);
} else { } else {
@ -202,7 +202,7 @@ static void set_to_lvariable(ivl_lval_t lval,
unsigned index_reg = 3; unsigned index_reg = 3;
draw_eval_expr_into_integer(word_ix, index_reg); draw_eval_expr_into_integer(word_ix, index_reg);
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set); fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set);
fprintf(vvp_out, " %%ix/load 1, 0;\n"); fprintf(vvp_out, " %%ix/load 1, 0, 0;\n");
fprintf(vvp_out, " %%set/av v%p, %u, %u;\n", fprintf(vvp_out, " %%set/av v%p, %u, %u;\n",
sig, bit, wid); sig, bit, wid);
fprintf(vvp_out, "t_%u ;\n", skip_set); fprintf(vvp_out, "t_%u ;\n", skip_set);
@ -223,23 +223,23 @@ static void set_to_lvariable(ivl_lval_t lval,
} }
static void assign_to_array_word(ivl_signal_t lsig, ivl_expr_t word_ix, static void assign_to_array_word(ivl_signal_t lsig, ivl_expr_t word_ix,
unsigned bit, unsigned delay, ivl_expr_t dexp, unsigned bit, uint64_t delay, ivl_expr_t dexp,
ivl_expr_t part_off_ex, unsigned width, ivl_expr_t part_off_ex, unsigned width,
unsigned nevents) unsigned nevents)
{ {
unsigned skip_assign = transient_id++; unsigned skip_assign = transient_id++;
unsigned part_off = 0; unsigned long part_off = 0;
if (part_off_ex == 0) { if (part_off_ex == 0) {
part_off = 0; part_off = 0;
} else if (number_is_immediate(part_off_ex, 64, 0)) { } else if (number_is_immediate(part_off_ex, IMM_WID, 0)) {
part_off = get_number_immediate(part_off_ex); part_off = get_number_immediate(part_off_ex);
part_off_ex = 0; part_off_ex = 0;
} }
/* This code is common to all the different types of array delays. */ /* This code is common to all the different types of array delays. */
if (number_is_immediate(word_ix, 64, 0)) { if (number_is_immediate(word_ix, IMM_WID, 0)) {
fprintf(vvp_out, " %%ix/load 3, %lu; address\n", fprintf(vvp_out, " %%ix/load 3, %lu, 0; address\n",
get_number_immediate(word_ix)); get_number_immediate(word_ix));
} else { } else {
/* Calculate array word index into index register 3 */ /* Calculate array word index into index register 3 */
@ -248,14 +248,14 @@ static void assign_to_array_word(ivl_signal_t lsig, ivl_expr_t word_ix,
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_assign); fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_assign);
} }
/* Store expression width into index word 0 */ /* Store expression width into index word 0 */
fprintf(vvp_out, " %%ix/load 0, %u; word width\n", width); fprintf(vvp_out, " %%ix/load 0, %u, 0; word width\n", width);
if (part_off_ex) { if (part_off_ex) {
draw_eval_expr_into_integer(part_off_ex, 1); draw_eval_expr_into_integer(part_off_ex, 1);
/* If the index expression has XZ bits, skip the assign. */ /* If the index expression has XZ bits, skip the assign. */
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_assign); fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_assign);
} else { } else {
/* Store word part select into index 1 */ /* Store word part select into index 1 */
fprintf(vvp_out, " %%ix/load 1, %u; part off\n", part_off); fprintf(vvp_out, " %%ix/load 1, %lu, 0; part off\n", part_off);
} }
if (dexp != 0) { if (dexp != 0) {
@ -270,8 +270,24 @@ static void assign_to_array_word(ivl_signal_t lsig, ivl_expr_t word_ix,
fprintf(vvp_out, " %%assign/av/e v%p, %u;\n", lsig, bit); fprintf(vvp_out, " %%assign/av/e v%p, %u;\n", lsig, bit);
} else { } else {
/* Constant delay... */ /* Constant delay... */
fprintf(vvp_out, " %%assign/av v%p, %u, %u;\n", lsig, unsigned long low_d = delay % UINT64_C(0x100000000);
delay, bit); unsigned long hig_d = delay / UINT64_C(0x100000000);
/*
* The %assign can only take a 32 bit delay. For a larger
* delay we need to put it into an index register.
*/
if (hig_d != 0) {
int delay_index = allocate_word();
fprintf(vvp_out, " %%ix/load %d, %lu, %lu;\n",
delay_index, low_d, hig_d);
fprintf(vvp_out, " %%assign/av/d v%p, %d, %u;\n", lsig,
delay_index, bit);
clr_word(delay_index);
} else {
fprintf(vvp_out, " %%assign/av v%p, %lu, %u;\n",
lsig, low_d, bit);
}
} }
fprintf(vvp_out, "t_%u ;\n", skip_assign); fprintf(vvp_out, "t_%u ;\n", skip_assign);
@ -281,12 +297,12 @@ static void assign_to_array_word(ivl_signal_t lsig, ivl_expr_t word_ix,
} }
static void assign_to_lvector(ivl_lval_t lval, unsigned bit, static void assign_to_lvector(ivl_lval_t lval, unsigned bit,
unsigned delay, ivl_expr_t dexp, uint64_t delay, ivl_expr_t dexp,
unsigned width, unsigned nevents) unsigned width, unsigned nevents)
{ {
ivl_signal_t sig = ivl_lval_sig(lval); ivl_signal_t sig = ivl_lval_sig(lval);
ivl_expr_t part_off_ex = ivl_lval_part_off(lval); ivl_expr_t part_off_ex = ivl_lval_part_off(lval);
unsigned part_off = 0; unsigned long part_off = 0;
ivl_expr_t word_ix = ivl_lval_idx(lval); ivl_expr_t word_ix = ivl_lval_idx(lval);
const unsigned long use_word = 0; const unsigned long use_word = 0;
@ -300,7 +316,7 @@ static void assign_to_lvector(ivl_lval_t lval, unsigned bit,
if (part_off_ex == 0) { if (part_off_ex == 0) {
part_off = 0; part_off = 0;
} else if (number_is_immediate(part_off_ex, 64, 0)) { } else if (number_is_immediate(part_off_ex, IMM_WID, 0)) {
part_off = get_number_immediate(part_off_ex); part_off = get_number_immediate(part_off_ex);
part_off_ex = 0; part_off_ex = 0;
} }
@ -308,6 +324,9 @@ static void assign_to_lvector(ivl_lval_t lval, unsigned bit,
if (ivl_lval_mux(lval)) if (ivl_lval_mux(lval))
part_off_ex = ivl_lval_mux(lval); part_off_ex = ivl_lval_mux(lval);
unsigned long low_d = delay % UINT64_C(0x100000000);
unsigned long hig_d = delay / UINT64_C(0x100000000);
if (part_off_ex) { if (part_off_ex) {
unsigned skip_assign = transient_id++; unsigned skip_assign = transient_id++;
if (dexp != 0) { if (dexp != 0) {
@ -317,8 +336,8 @@ static void assign_to_lvector(ivl_lval_t lval, unsigned bit,
draw_eval_expr_into_integer(part_off_ex, 1); draw_eval_expr_into_integer(part_off_ex, 1);
/* If the index expression has XZ bits, skip the assign. */ /* If the index expression has XZ bits, skip the assign. */
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_assign); fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_assign);
fprintf(vvp_out, " %%ix/load 0, %u;\n", width); fprintf(vvp_out, " %%ix/load 0, %u, 0;\n", width);
fprintf(vvp_out, " %%assign/v0/x1 v%p_%lu, %u, %u;\n", fprintf(vvp_out, " %%assign/v0/x1/d v%p_%lu, %d, %u;\n",
sig, use_word, delay_index, bit); sig, use_word, delay_index, bit);
fprintf(vvp_out, "t_%u ;\n", skip_assign); fprintf(vvp_out, "t_%u ;\n", skip_assign);
clr_word(delay_index); clr_word(delay_index);
@ -327,7 +346,7 @@ static void assign_to_lvector(ivl_lval_t lval, unsigned bit,
draw_eval_expr_into_integer(part_off_ex, 1); draw_eval_expr_into_integer(part_off_ex, 1);
/* If the index expression has XZ bits, skip the assign. */ /* If the index expression has XZ bits, skip the assign. */
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_assign); fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_assign);
fprintf(vvp_out, " %%ix/load 0, %u;\n", width); fprintf(vvp_out, " %%ix/load 0, %u, 0;\n", width);
fprintf(vvp_out, " %%assign/v0/x1/e v%p_%lu, %u;\n", fprintf(vvp_out, " %%assign/v0/x1/e v%p_%lu, %u;\n",
sig, use_word, bit); sig, use_word, bit);
fprintf(vvp_out, "t_%u ;\n", skip_assign); fprintf(vvp_out, "t_%u ;\n", skip_assign);
@ -337,9 +356,24 @@ static void assign_to_lvector(ivl_lval_t lval, unsigned bit,
draw_eval_expr_into_integer(part_off_ex, 1); draw_eval_expr_into_integer(part_off_ex, 1);
/* If the index expression has XZ bits, skip the assign. */ /* If the index expression has XZ bits, skip the assign. */
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_assign); fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_assign);
fprintf(vvp_out, " %%ix/load 0, %u;\n", width); fprintf(vvp_out, " %%ix/load 0, %u, 0;\n", width);
fprintf(vvp_out, " %%assign/v0/x1 v%p_%lu, %u, %u;\n", /*
sig, use_word, delay, bit); * The %assign can only take a 32 bit delay. For a larger
* delay we need to put it into an index register.
*/
if (hig_d != 0) {
int delay_index = allocate_word();
fprintf(vvp_out, " %%ix/load %d, %lu, %lu;\n",
delay_index, low_d, hig_d);
fprintf(vvp_out,
" %%assign/v0/x1/d v%p_%lu, %d, %u;\n",
sig, use_word, delay_index, bit);
clr_word(delay_index);
} else {
fprintf(vvp_out,
" %%assign/v0/x1 v%p_%lu, %lu, %u;\n",
sig, use_word, low_d, bit);
}
fprintf(vvp_out, "t_%u ;\n", skip_assign); fprintf(vvp_out, "t_%u ;\n", skip_assign);
} }
@ -353,41 +387,71 @@ static void assign_to_lvector(ivl_lval_t lval, unsigned bit,
/* Calculated delay... */ /* Calculated delay... */
int delay_index = allocate_word(); int delay_index = allocate_word();
draw_eval_expr_into_integer(dexp, delay_index); draw_eval_expr_into_integer(dexp, delay_index);
fprintf(vvp_out, " %%ix/load 0, %u;\n", width); fprintf(vvp_out, " %%ix/load 0, %u, 0;\n", width);
fprintf(vvp_out, " %%ix/load 1, %u;\n", part_off); fprintf(vvp_out, " %%ix/load 1, %lu, 0;\n", part_off);
fprintf(vvp_out, " %%assign/v0/x1/d v%p_%lu, %d, %u;\n", fprintf(vvp_out, " %%assign/v0/x1/d v%p_%lu, %d, %u;\n",
sig, use_word, delay_index, bit); sig, use_word, delay_index, bit);
clr_word(delay_index); clr_word(delay_index);
} else if (nevents != 0) { } else if (nevents != 0) {
/* Event control delay... */ /* Event control delay... */
fprintf(vvp_out, " %%ix/load 0, %u;\n", width); fprintf(vvp_out, " %%ix/load 0, %u, 0;\n", width);
fprintf(vvp_out, " %%ix/load 1, %u;\n", part_off); fprintf(vvp_out, " %%ix/load 1, %lu, 0;\n", part_off);
fprintf(vvp_out, " %%assign/v0/x1/e v%p_%lu, %u;\n", fprintf(vvp_out, " %%assign/v0/x1/e v%p_%lu, %u;\n",
sig, use_word, bit); sig, use_word, bit);
} else { } else {
/* Constant delay... */ /* Constant delay... */
fprintf(vvp_out, " %%ix/load 0, %u;\n", width); fprintf(vvp_out, " %%ix/load 0, %u, 0;\n", width);
fprintf(vvp_out, " %%ix/load 1, %u;\n", part_off); fprintf(vvp_out, " %%ix/load 1, %lu, 0;\n", part_off);
fprintf(vvp_out, " %%assign/v0/x1 v%p_%lu, %u, %u;\n", /*
sig, use_word, delay, bit); * The %assign can only take a 32 bit delay. For a larger
* delay we need to put it into an index register.
*/
if (hig_d != 0) {
int delay_index = allocate_word();
fprintf(vvp_out, " %%ix/load %d, %lu, %lu;\n",
delay_index, low_d, hig_d);
fprintf(vvp_out,
" %%assign/v0/x1/d v%p_%lu, %d, %u;\n",
sig, use_word, delay_index, bit);
clr_word(delay_index);
} else {
fprintf(vvp_out,
" %%assign/v0/x1 v%p_%lu, %lu, %u;\n",
sig, use_word, low_d, bit);
}
} }
} else if (dexp != 0) { } else if (dexp != 0) {
/* Calculated delay... */ /* Calculated delay... */
draw_eval_expr_into_integer(dexp, 1); int delay_index = allocate_word();
fprintf(vvp_out, " %%ix/load 0, %u;\n", width); draw_eval_expr_into_integer(dexp, delay_index);
fprintf(vvp_out, " %%assign/v0/d v%p_%lu, 1, %u;\n", fprintf(vvp_out, " %%ix/load 0, %u, 0;\n", width);
sig, use_word, bit); fprintf(vvp_out, " %%assign/v0/d v%p_%lu, %d, %u;\n",
sig, use_word, delay_index, bit);
clr_word(delay_index);
} else if (nevents != 0) { } else if (nevents != 0) {
/* Event control delay... */ /* Event control delay... */
fprintf(vvp_out, " %%ix/load 0, %u;\n", width); fprintf(vvp_out, " %%ix/load 0, %u, 0;\n", width);
fprintf(vvp_out, " %%assign/v0/e v%p_%lu, %u;\n", fprintf(vvp_out, " %%assign/v0/e v%p_%lu, %u;\n",
sig, use_word, bit); sig, use_word, bit);
} else { } else {
/* Constant delay... */ /* Constant delay... */
fprintf(vvp_out, " %%ix/load 0, %u;\n", width); fprintf(vvp_out, " %%ix/load 0, %u, 0;\n", width);
fprintf(vvp_out, " %%assign/v0 v%p_%lu, %u, %u;\n", /*
sig, use_word, delay, bit); * The %assign can only take a 32 bit delay. For a larger
* delay we need to put it into an index register.
*/
if (hig_d != 0) {
int delay_index = allocate_word();
fprintf(vvp_out, " %%ix/load %d, %lu, %lu;\n",
delay_index, low_d, hig_d);
fprintf(vvp_out, " %%assign/v0/d v%p_%lu, %d, %u;\n",
sig, use_word, delay_index, bit);
clr_word(delay_index);
} else {
fprintf(vvp_out, " %%assign/v0 v%p_%lu, %lu, %u;\n",
sig, use_word, low_d, bit);
}
} }
} }
@ -569,7 +633,7 @@ static int show_stmt_assign_nb_real(ivl_statement_t net)
unsigned long use_word = 0; unsigned long use_word = 0;
/* thread address for a word value. */ /* thread address for a word value. */
int word; int word;
unsigned long delay = 0; uint64_t delay = 0;
unsigned nevents = ivl_stmt_nevent(net); unsigned nevents = ivl_stmt_nevent(net);
/* Must be exactly 1 l-value. */ /* Must be exactly 1 l-value. */
@ -586,9 +650,9 @@ static int show_stmt_assign_nb_real(ivl_statement_t net)
use_word = get_number_immediate(word_ix); use_word = get_number_immediate(word_ix);
} }
if (del && (ivl_expr_type(del) == IVL_EX_ULONG)) { if (del && (ivl_expr_type(del) == IVL_EX_DELAY)) {
assert(number_is_immediate(del, IMM_WID, 0)); assert(number_is_immediate(del, 64, 0));
delay = ivl_expr_uvalue(del); delay = ivl_expr_delay_val(del);
del = 0; del = 0;
} }
@ -607,8 +671,24 @@ static int show_stmt_assign_nb_real(ivl_statement_t net)
fprintf(vvp_out, " %%assign/wr/e v%p_%lu, %u;\n", fprintf(vvp_out, " %%assign/wr/e v%p_%lu, %u;\n",
sig, use_word, word); sig, use_word, word);
} else { } else {
fprintf(vvp_out, " %%assign/wr v%p_%lu, %lu, %u;\n", unsigned long low_d = delay % UINT64_C(0x100000000);
sig, use_word, delay, word); unsigned long hig_d = delay / UINT64_C(0x100000000);
/*
* The %assign can only take a 32 bit delay. For a larger
* delay we need to put it into an index register.
*/
if (hig_d != 0) {
int delay_index = allocate_word();
fprintf(vvp_out, " %%ix/load %d, %lu, %lu;\n",
delay_index, low_d, hig_d);
fprintf(vvp_out, " %%assign/wr/d v%p_%lu, %d, %u;\n",
sig, use_word, delay_index, word);
clr_word(delay_index);
} else {
fprintf(vvp_out, " %%assign/wr v%p_%lu, %lu, %u;\n",
sig, use_word, low_d, word);
}
} }
clr_word(word); clr_word(word);
@ -669,7 +749,7 @@ static int show_stmt_assign_nb(ivl_statement_t net)
assert(ivl_stmt_cond_expr(net) == 0); assert(ivl_stmt_cond_expr(net) == 0);
} }
unsigned long delay = 0; uint64_t delay = 0;
/* Detect special cases that are handled elsewhere. */ /* Detect special cases that are handled elsewhere. */
lval = ivl_stmt_lval(net,0); lval = ivl_stmt_lval(net,0);
@ -682,9 +762,9 @@ static int show_stmt_assign_nb(ivl_statement_t net)
} }
} }
if (del && (ivl_expr_type(del) == IVL_EX_ULONG)) { if (del && (ivl_expr_type(del) == IVL_EX_DELAY)) {
assert(number_is_immediate(del, IMM_WID, 0)); assert(number_is_immediate(del, 64, 0));
delay = ivl_expr_uvalue(del); delay = ivl_expr_delay_val(del);
del = 0; del = 0;
} }
@ -1017,14 +1097,14 @@ static void force_vector_to_lval(ivl_statement_t net, struct vector_info rvec)
unsigned use_wid = ivl_lval_width(lval); unsigned use_wid = ivl_lval_width(lval);
ivl_expr_t part_off_ex = ivl_lval_part_off(lval); ivl_expr_t part_off_ex = ivl_lval_part_off(lval);
unsigned part_off; unsigned long part_off;
ivl_expr_t word_idx = ivl_lval_idx(lval); ivl_expr_t word_idx = ivl_lval_idx(lval);
unsigned long use_word = 0; unsigned long use_word = 0;
if (part_off_ex == 0) { if (part_off_ex == 0) {
part_off = 0; part_off = 0;
} else { } else {
assert(number_is_immediate(part_off_ex, 64, 0)); assert(number_is_immediate(part_off_ex, IMM_WID, 0));
part_off = get_number_immediate(part_off_ex); part_off = get_number_immediate(part_off_ex);
} }
@ -1039,7 +1119,7 @@ static void force_vector_to_lval(ivl_statement_t net, struct vector_info rvec)
if (part_off != 0 || use_wid != ivl_signal_width(lsig)) { if (part_off != 0 || use_wid != ivl_signal_width(lsig)) {
command_name = command_name_x0; command_name = command_name_x0;
fprintf(vvp_out, " %%ix/load 0, %u;\n", part_off); fprintf(vvp_out, " %%ix/load 0, %lu, 0;\n", part_off);
} else { } else {
/* Do not support bit or part selects of l-values yet. */ /* Do not support bit or part selects of l-values yet. */

View File

@ -133,18 +133,18 @@ const static struct opcode_table_s opcode_table[] = {
{ "%evctl/s",of_EVCTLS, 2, {OA_FUNC_PTR, OA_BIT1, OA_NONE} }, { "%evctl/s",of_EVCTLS, 2, {OA_FUNC_PTR, OA_BIT1, OA_NONE} },
{ "%force/link",of_FORCE_LINK,2,{OA_FUNC_PTR,OA_FUNC_PTR2,OA_NONE} }, { "%force/link",of_FORCE_LINK,2,{OA_FUNC_PTR,OA_FUNC_PTR2,OA_NONE} },
{ "%force/v",of_FORCE_V,3, {OA_FUNC_PTR, OA_BIT1, OA_BIT2} }, { "%force/v",of_FORCE_V,3, {OA_FUNC_PTR, OA_BIT1, OA_BIT2} },
{ "%force/wr",of_FORCE_WR,2, {OA_FUNC_PTR, OA_BIT1, OA_NONE} }, { "%force/wr",of_FORCE_WR,2,{OA_FUNC_PTR, OA_BIT1, OA_NONE} },
{ "%force/x0",of_FORCE_X0,3,{OA_FUNC_PTR, OA_BIT1, OA_BIT2} }, { "%force/x0",of_FORCE_X0,3,{OA_FUNC_PTR, OA_BIT1, OA_BIT2} },
{ "%free", of_FREE, 1, {OA_VPI_PTR, OA_NONE, OA_NONE} }, { "%free", of_FREE, 1, {OA_VPI_PTR, OA_NONE, OA_NONE} },
{ "%inv", of_INV, 2, {OA_BIT1, OA_BIT2, OA_NONE} }, { "%inv", of_INV, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
{ "%ix/add", of_IX_ADD, 2, {OA_BIT1, OA_NUMBER, OA_NONE} }, { "%ix/add", of_IX_ADD, 3, {OA_NUMBER, OA_BIT1, OA_BIT2} },
{ "%ix/get", of_IX_GET, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} }, { "%ix/get", of_IX_GET, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%ix/get/s",of_IX_GET_S,3,{OA_BIT1, OA_BIT2, OA_NUMBER} }, { "%ix/get/s",of_IX_GET_S,3,{OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%ix/getv",of_IX_GETV,2, {OA_BIT1, OA_FUNC_PTR, OA_NONE} }, { "%ix/getv",of_IX_GETV,2, {OA_BIT1, OA_FUNC_PTR, OA_NONE} },
{ "%ix/getv/s",of_IX_GETVS,2, {OA_BIT1, OA_FUNC_PTR, OA_NONE} }, { "%ix/getv/s",of_IX_GETVS,2, {OA_BIT1, OA_FUNC_PTR, OA_NONE} },
{ "%ix/load",of_IX_LOAD,2, {OA_BIT1, OA_NUMBER, OA_NONE} }, { "%ix/load",of_IX_LOAD,3, {OA_NUMBER, OA_BIT1, OA_BIT2} },
{ "%ix/mul", of_IX_MUL, 2, {OA_BIT1, OA_NUMBER, OA_NONE} }, { "%ix/mul", of_IX_MUL, 3, {OA_NUMBER, OA_BIT1, OA_BIT2} },
{ "%ix/sub", of_IX_SUB, 2, {OA_BIT1, OA_NUMBER, OA_NONE} }, { "%ix/sub", of_IX_SUB, 3, {OA_NUMBER, OA_BIT1, OA_BIT2} },
{ "%jmp", of_JMP, 1, {OA_CODE_PTR, OA_NONE, OA_NONE} }, { "%jmp", of_JMP, 1, {OA_CODE_PTR, OA_NONE, OA_NONE} },
{ "%jmp/0", of_JMP0, 2, {OA_CODE_PTR, OA_BIT1, OA_NONE} }, { "%jmp/0", of_JMP0, 2, {OA_CODE_PTR, OA_BIT1, OA_NONE} },
{ "%jmp/0xz",of_JMP0XZ, 2, {OA_CODE_PTR, OA_BIT1, OA_NONE} }, { "%jmp/0xz",of_JMP0XZ, 2, {OA_CODE_PTR, OA_BIT1, OA_NONE} },

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2001-2008 Stephen Williams (steve@icarus.com) * Copyright (c) 2001-2009 Stephen Williams (steve@icarus.com)
* *
*/ */
@ -417,22 +417,25 @@ These instructions are like the %ix/get instructions, except that they
read directly from a functor label instead of from thread bits. They read directly from a functor label instead of from thread bits. They
set bit 4 just like %ix/get. set bit 4 just like %ix/get.
* %ix/load <idx>, <value> * %ix/load <idx>, <low> <high>
This instruction loads an immediate value into the addressed index This instruction loads an immediate value into the addressed index
register. The index register holds numeric values, so the <value> is a register. The index register holds signed 64 bit numeric values, so
number. The idx value selects the index register. This is different <low> and <high> are used to separate the value in two 32 bit chunks.
from %ix/get, which loads the index register from a value in the The idx value selects the index register. This is different from
thread bit vector. The value is a signed decimal value >= 0. %ix/get, which loads the index register from a value in the thread bit
vector. The values are unsigned decimal values and are combined as
<high> << 32 | <low> to produce the final value.
* %ix/add <idx>, <value> * %ix/add <idx>, <low> <high>
* %ix/sub <idx>, <value> * %ix/sub <idx>, <low> <high>
* %ix/mul <idx>, <value> * %ix/mul <idx>, <low> <high>
This instruction adds, subtracts, or multiplies an immediate value to These instructions add, subtract, or multiply the selected index
the addressed index register. The index register holds numeric values, register by the immediate value. The 64 bit immediate value is built
so the <value> is a number. The <idx> value selects the index register. from the two 32 bit chunks <low> and <high> (see %ix/load above).
The <idx> value selects the index register.
* %jmp <code-label> * %jmp <code-label>

View File

@ -862,7 +862,7 @@ bool of_ASSIGN_AVD(vthread_t thr, vvp_code_t cp)
unsigned wid = thr->words[0].w_int; unsigned wid = thr->words[0].w_int;
long off = thr->words[1].w_int; long off = thr->words[1].w_int;
unsigned adr = thr->words[3].w_int; unsigned adr = thr->words[3].w_int;
unsigned long delay = thr->words[cp->bit_idx[0]].w_int; vvp_time64_t delay = thr->words[cp->bit_idx[0]].w_int;
unsigned bit = cp->bit_idx[1]; unsigned bit = cp->bit_idx[1];
long vwidth = get_array_word_size(cp->array); long vwidth = get_array_word_size(cp->array);
@ -956,7 +956,7 @@ bool of_ASSIGN_V0D(vthread_t thr, vvp_code_t cp)
unsigned wid = thr->words[0].w_int; unsigned wid = thr->words[0].w_int;
assert(wid > 0); assert(wid > 0);
unsigned long delay = thr->words[cp->bit_idx[0]].w_int; vvp_time64_t delay = thr->words[cp->bit_idx[0]].w_int;
unsigned bit = cp->bit_idx[1]; unsigned bit = cp->bit_idx[1];
vvp_net_ptr_t ptr (cp->net, 0); vvp_net_ptr_t ptr (cp->net, 0);
@ -1044,7 +1044,7 @@ bool of_ASSIGN_V0X1D(vthread_t thr, vvp_code_t cp)
{ {
unsigned wid = thr->words[0].w_int; unsigned wid = thr->words[0].w_int;
long off = thr->words[1].w_int; long off = thr->words[1].w_int;
unsigned delay = thr->words[cp->bit_idx[0]].w_int; vvp_time64_t delay = thr->words[cp->bit_idx[0]].w_int;
unsigned bit = cp->bit_idx[1]; unsigned bit = cp->bit_idx[1];
vvp_fun_signal_vec*sig vvp_fun_signal_vec*sig
@ -1152,7 +1152,7 @@ bool of_ASSIGN_WR(vthread_t thr, vvp_code_t cp)
bool of_ASSIGN_WRD(vthread_t thr, vvp_code_t cp) bool of_ASSIGN_WRD(vthread_t thr, vvp_code_t cp)
{ {
unsigned delay = thr->words[cp->bit_idx[0]].w_int; vvp_time64_t delay = thr->words[cp->bit_idx[0]].w_int;
unsigned index = cp->bit_idx[1]; unsigned index = cp->bit_idx[1];
s_vpi_time del; s_vpi_time del;
@ -2554,30 +2554,44 @@ bool of_INV(vthread_t thr, vvp_code_t cp)
/* /*
** Index registers, unsigned arithmetic. * Index registers, arithmetic.
*/ */
static inline int64_t get_as_64_bit(uint32_t low_32, uint32_t high_32)
{
int64_t low = low_32;
int64_t res = high_32;
res <<= 32;
res |= low;
return res;
}
bool of_IX_ADD(vthread_t thr, vvp_code_t cp) bool of_IX_ADD(vthread_t thr, vvp_code_t cp)
{ {
thr->words[cp->bit_idx[0]].w_int += cp->number; thr->words[cp->number].w_int += get_as_64_bit(cp->bit_idx[0],
return true; cp->bit_idx[1]);
return true;
} }
bool of_IX_SUB(vthread_t thr, vvp_code_t cp) bool of_IX_SUB(vthread_t thr, vvp_code_t cp)
{ {
thr->words[cp->bit_idx[0]].w_int -= cp->number; thr->words[cp->number].w_int -= get_as_64_bit(cp->bit_idx[0],
return true; cp->bit_idx[1]);
return true;
} }
bool of_IX_MUL(vthread_t thr, vvp_code_t cp) bool of_IX_MUL(vthread_t thr, vvp_code_t cp)
{ {
thr->words[cp->bit_idx[0]].w_int *= cp->number; thr->words[cp->number].w_int *= get_as_64_bit(cp->bit_idx[0],
return true; cp->bit_idx[1]);
return true;
} }
bool of_IX_LOAD(vthread_t thr, vvp_code_t cp) bool of_IX_LOAD(vthread_t thr, vvp_code_t cp)
{ {
thr->words[cp->bit_idx[0]].w_int = cp->number; thr->words[cp->number].w_int = get_as_64_bit(cp->bit_idx[0],
cp->bit_idx[1]);
return true; return true;
} }