diff --git a/driver/main.c b/driver/main.c index 015b8af75..df624cdc6 100644 --- a/driver/main.c +++ b/driver/main.c @@ -239,6 +239,23 @@ static FILE*fopen_safe(const char*path) } #endif +#ifdef __MINGW32__ +/* + * The MinGW version of getenv() returns the path with a forward + * slash. This should be converted to a back slash to keep every + * thing in the code using a back slash. This function wraps the + * code for this in one place. The conversion can not be done + * directly on the getenv() result since it is const char*. + */ +static void convert_to_MS_path(char *path) +{ + char *t; + for (t = path; *t; t++) { + if (*t == '/') *t = '\\'; + } +} +#endif + static const char*my_tempfile(const char*str, FILE**fout) { FILE*file; @@ -269,6 +286,9 @@ static const char*my_tempfile(const char*str, FILE**fout) unsigned code = rand(); snprintf(pathbuf, sizeof pathbuf, "%s%c%s%04x", tmpdir, sep, str, code); +#ifdef __MINGW32__ + convert_to_MS_path(pathbuf); +#endif file = fopen_safe(pathbuf); retry -= 1; } @@ -391,7 +411,7 @@ static int t_compile() #endif /* Build the ivl command and pipe it to the preprocessor. */ - snprintf(tmp, sizeof tmp, " | %s/ivl", base); + snprintf(tmp, sizeof tmp, " | %s%civl", base, sep); rc = strlen(tmp); cmd = realloc(cmd, ncmd+rc+1); strcpy(cmd+ncmd, tmp); @@ -425,16 +445,6 @@ static int t_compile() strcpy(cmd+ncmd, tmp); ncmd += rc; -#ifdef __MINGW32__ - { - char *t; - for (t = cmd+ncmd_start; *t; t++) - { - if (*t == '/') *t = '\\'; - } - } -#endif - if (verbose_flag) printf("translate: %s\n", cmd); diff --git a/eval_tree.cc b/eval_tree.cc index 3f278f842..598628dfd 100644 --- a/eval_tree.cc +++ b/eval_tree.cc @@ -996,6 +996,11 @@ NetExpr* NetEBPow::eval_tree_real_() NetECReal*res = new NetECReal( pow(lval,rval) ); res->set_line(*this); + + if (debug_eval_tree) + cerr << get_fileline() << ": debug: Evaluate (real) " + << lval << " ** " << rval << " --> " << *res << endl; + return res; } @@ -1016,7 +1021,14 @@ NetExpr* NetEBPow::eval_tree(int prune_to_width) verinum lval = lc->value(); verinum rval = rc->value(); - return new NetEConst( pow(lval,rval) ); + NetEConst*res = new NetEConst( pow(lval,rval) ); + res->set_line(*this); + + if (debug_eval_tree) + cerr << get_fileline() << ": debug: Evaluate " + << lval << " ** " << rval << " --> " << *res << endl; + + return res; } /* diff --git a/verinum.cc b/verinum.cc index 739095e8c..6bfcd0a98 100644 --- a/verinum.cc +++ b/verinum.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2008 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2009 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -746,7 +746,7 @@ verinum::V operator == (const verinum&left, const verinum&right) right_pad = right.get(right.len()-1); if (left_pad == verinum::V1 && right_pad == verinum::V0) - return verinum::V1; + return verinum::V0; if (left_pad == verinum::V0 && right_pad == verinum::V1) return verinum::V0; } @@ -1051,9 +1051,45 @@ verinum operator * (const verinum&left, const verinum&right) verinum pow(const verinum&left, const verinum&right) { verinum result = left; - unsigned pow_count = right.as_ulong(); + long pow_count = right.as_long(); - for (unsigned idx = 1 ; idx < pow_count ; idx += 1) + // We need positive and negative one in a few places. + verinum one (verinum::V0, left.len(), left.has_len()); + one.has_sign(left.has_sign()); + one.set(0, verinum::V1); + verinum m_one (verinum::V1, left.len(), left.has_len()); + m_one.has_sign(true); + + // If either the right or left values are undefined we return 'bx. + if (!right.is_defined() || !left.is_defined()) { + result = verinum(verinum::Vx, left.len(), left.has_len()); + result.has_sign(left.has_sign()); + // If the right value is zero we need to set the result to 1. + } else if (pow_count == 0) { + result = one; + } else if (pow_count < 0) { + // 0 ** is 'bx. + if (left.is_zero()) { + result = verinum(verinum::Vx, left.len(), left.has_len()); + result.has_sign(left.has_sign()); + // 1 ** is 1. + } else if (left == one) { + result = one; + // -1 ** is 1 or -1. + } else if (left.has_sign() && left == m_one) { + if (pow_count%2 == 0) { + result = one; + } else { + result = m_one; + } + // Everything else is 0. + } else { + result = verinum(verinum::V0, left.len(), left.has_len()); + result.has_sign(left.has_sign()); + } + } + + for (long idx = 1 ; idx < pow_count ; idx += 1) result = result * left; return result; diff --git a/vpi/wavealloca.h b/vpi/wavealloca.h index 27476df6e..5f4b2186e 100644 --- a/vpi/wavealloca.h +++ b/vpi/wavealloca.h @@ -17,6 +17,8 @@ #ifndef alloca #define alloca __builtin_alloca #endif +#else +#include #endif #elif defined(_MSC_VER) #include @@ -26,8 +28,11 @@ #endif /* - * $Id: wavealloca.h,v 1.2 2007/08/26 21:35:50 gtkwave Exp $ + * $Id: wavealloca.h,v 1.3 2009/12/06 00:10:17 gtkwave Exp $ * $Log: wavealloca.h,v $ + * Revision 1.3 2009/12/06 00:10:17 gtkwave + * mingw compatibility fix from icarus + * * Revision 1.2 2007/08/26 21:35:50 gtkwave * integrated global context management from SystemOfCode2007 branch * diff --git a/vvp/schedule.cc b/vvp/schedule.cc index 2be203119..c94fac1c3 100644 --- a/vvp/schedule.cc +++ b/vvp/schedule.cc @@ -753,6 +753,9 @@ void schedule_generic(vvp_gen_event_t obj, vvp_time64_t delay, cur->delete_obj_when_done = delete_when_done; schedule_event_(cur, delay, sync_flag? (ro_flag?SEQ_ROSYNC:SEQ_RWSYNC) : SEQ_ACTIVE); + + if (sync_flag) + vthread_delay_delete(); } void schedule_at_start_of_simtime(vvp_gen_event_t obj, vvp_time64_t delay) diff --git a/vvp/vthread.cc b/vvp/vthread.cc index d15e61cd2..41904e1b3 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -112,6 +112,7 @@ struct vthread_s { unsigned i_have_ended :1; unsigned waiting_for_event :1; unsigned is_scheduled :1; + unsigned delay_delete :1; unsigned fork_count :8; /* This points to the sole child of the thread. */ struct vthread_s*child; @@ -425,6 +426,7 @@ vthread_t vthread_new(vvp_code_t pc, struct __vpiScope*scope) thr->schedule_parent_on_end = 0; thr->is_scheduled = 0; thr->i_have_ended = 0; + thr->delay_delete = 0; thr->waiting_for_event = 0; thr->fork_count = 0; thr->event = 0; @@ -512,7 +514,10 @@ static void vthread_reap(vthread_t thr) if ((thr->is_scheduled == 0) && (thr->waiting_for_event == 0)) { assert(thr->fork_count == 0); assert(thr->wait_next == 0); - schedule_del_thr(thr); + if (thr->delay_delete) + schedule_del_thr(thr); + else + vthread_delete(thr); } } @@ -531,6 +536,12 @@ void vthread_mark_scheduled(vthread_t thr) } } +void vthread_delay_delete() +{ + if (running_thread) + running_thread->delay_delete = 1; +} + /* * This function runs each thread by fetching an instruction, * incrementing the PC, and executing the instruction. The thread may @@ -4504,9 +4515,12 @@ bool of_XOR(vthread_t thr, vvp_code_t cp) bool of_ZOMBIE(vthread_t thr, vvp_code_t) { thr->pc = codespace_null(); - if ((thr->parent == 0) && (thr->child == 0)) - schedule_del_thr(thr); - + if ((thr->parent == 0) && (thr->child == 0)) { + if (thr->delay_delete) + schedule_del_thr(thr); + else + vthread_delete(thr); + } return false; } diff --git a/vvp/vthread.h b/vvp/vthread.h index 46999fa57..0e8d47966 100644 --- a/vvp/vthread.h +++ b/vvp/vthread.h @@ -1,7 +1,7 @@ #ifndef __vthread_H #define __vthread_H /* - * 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 * and/or modify it in source code form under the terms of the GNU @@ -48,6 +48,14 @@ extern vthread_t vthread_new(vvp_code_t sa, struct __vpiScope*scope); */ extern void vthread_mark_scheduled(vthread_t thr); +/* + * This function causes deletion of the currently running thread to + * be delayed until after all sync events have been processed for the + * time step in which the thread terminates. It is only used by the + * schedule_generic function. + */ +extern void vthread_delay_delete(); + /* * Cause this thread to execute instructions until in is put to sleep * by executing some sort of delay or wait instruction.