Skip to content

Commit f0704b6

Browse files
committed
Redo integer passing on top of bignum
1 parent f7400a0 commit f0704b6

File tree

3 files changed

+233
-59
lines changed

3 files changed

+233
-59
lines changed

kernel/tclapi.cc

Lines changed: 183 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@
2121
#include "kernel/rtlil.h"
2222
#include "libs/json11/json11.hpp"
2323

24+
#ifdef YOSYS_ENABLE_TCL
25+
#include "tclTomMath.h"
26+
#include "tclTomMathDecls.h"
27+
#endif
28+
2429
YOSYS_NAMESPACE_BEGIN
2530

2631
#ifdef YOSYS_ENABLE_TCL
@@ -145,29 +150,106 @@ static int tcl_yosys_cmd(ClientData, Tcl_Interp *interp, int argc, const char *a
145150
continue; \
146151
} \
147152

153+
#define FLAG2(name) \
154+
if (!strcmp(Tcl_GetString(objv[i]), "-" #name)) { \
155+
name##_flag = true; \
156+
continue; \
157+
} \
158+
148159
#define ERROR(str) \
149160
{ \
150161
Tcl_SetResult(interp, (char *)(str), TCL_STATIC); \
151162
return TCL_ERROR; \
152163
}
153164

165+
bool const_to_mp_int(const Const &a, mp_int *b, bool force_signed, bool force_unsigned)
166+
{
167+
if (!a.is_fully_def())
168+
return false;
169+
170+
if (mp_init(b))
171+
return false;
172+
173+
bool negative = ((a.flags & RTLIL::CONST_FLAG_SIGNED) || force_signed) &&
174+
!force_unsigned &&
175+
!a.empty() && (a.back() == RTLIL::S1);
176+
177+
for (int i = a.size() - 1; i >= 0; i--) {
178+
if (mp_mul_2d(b, 1, b)) {
179+
mp_clear(b);
180+
return false;
181+
}
182+
183+
if ((a[i] == RTLIL::S1) ^ negative) {
184+
if (mp_add_d(b, 1, b)) {
185+
mp_clear(b);
186+
return false;
187+
}
188+
}
189+
}
190+
191+
if (negative) {
192+
if (mp_add_d(b, 1, b) || mp_neg(b, b)) {
193+
mp_clear(b);
194+
return false;
195+
}
196+
}
197+
198+
return true;
199+
}
200+
201+
bool mp_int_to_const(mp_int *a, Const &b, bool is_signed)
202+
{
203+
bool negative = (mp_cmp_d(a, 0) == MP_LT);
204+
if (negative && !is_signed)
205+
return false;
206+
207+
if (negative) {
208+
mp_neg(a, a);
209+
mp_sub_d(a, 1, a);
210+
}
211+
212+
std::vector<unsigned char> buf;
213+
buf.resize(mp_ubin_size(a));
214+
size_t written; // dummy
215+
mp_to_ubin(a, buf.data(), buf.size(), &written);
216+
217+
b.bits().reserve(mp_count_bits(a) + is_signed);
218+
for (int i = 0; i < mp_count_bits(a);) {
219+
for (int j = 0; j < 8 && i < mp_count_bits(a); j++, i++) {
220+
bool bv = ((buf.back() & (1 << j)) != 0) ^ negative;
221+
b.bits().push_back(bv ? RTLIL::S1 : RTLIL::S0);
222+
}
223+
buf.pop_back();
224+
}
225+
226+
if (is_signed) {
227+
b.bits().push_back(negative ? RTLIL::S1 : RTLIL::S0);
228+
}
229+
230+
return true;
231+
}
232+
154233
static int tcl_get_attr(ClientData, Tcl_Interp *interp, int argc, const char *argv[])
155234
{
156235
int i;
157-
bool mod_flag = false, string_flag = false, int_flag = false, bool_flag = false;
236+
bool mod_flag = false, string_flag = false, bool_flag = false;
237+
bool int_flag = false, sint_flag = false, uint_flag = false;
158238
for (i = 1; i < argc; i++) {
159239
FLAG(mod)
160240
FLAG(string)
161241
FLAG(int)
242+
FLAG(sint)
243+
FLAG(uint)
162244
FLAG(bool)
163245
break;
164246
}
165247

166248
if ((mod_flag && i != argc - 2) ||
167249
(!mod_flag && i != argc - 3) ||
168-
(string_flag + int_flag + bool_flag > 1))
169-
ERROR("bad usage: expected \"get_attr -mod [-string|-int|-bool] <module> <attrname>\""
170-
" or \"get_attr [-string|-int|-bool] <module> <identifier> <attrname>\"")
250+
(string_flag + int_flag + sint_flag + uint_flag + bool_flag > 1))
251+
ERROR("bad usage: expected \"get_attr -mod [-string|-int|-sint|-uint|-bool] <module> <attrname>\""
252+
" or \"get_attr [-string|-int|-sint|-uint|-bool] <module> <identifier> <attrname>\"")
171253

172254
IdString mod_id, obj_id, attr_id;
173255
mod_id = RTLIL::escape_id(argv[i++]);
@@ -197,19 +279,17 @@ static int tcl_get_attr(ClientData, Tcl_Interp *interp, int argc, const char *ar
197279

198280
if (string_flag) {
199281
Tcl_SetResult(interp, (char *) obj->get_string_attribute(attr_id).c_str(), TCL_VOLATILE);
200-
} else if (int_flag) {
282+
} else if (int_flag || uint_flag || sint_flag) {
201283
if (!obj->has_attribute(attr_id))
202284
ERROR("attribute missing (required for -int)");
203-
204285
RTLIL::Const &value = obj->attributes.at(attr_id);
205-
if (value.size() > 32)
206-
ERROR("value too large")
207286

208-
// FIXME: 32'hffffffff will return as negative despite is_signed=false
209-
Tcl_SetResult(interp, (char *) std::to_string(value.as_int()).c_str(), TCL_VOLATILE);
287+
mp_int value_mp;
288+
if (!const_to_mp_int(value, &value_mp, sint_flag, uint_flag))
289+
ERROR("bignum manipulation failed");
290+
Tcl_SetObjResult(interp, Tcl_NewBignumObj(&value_mp));
210291
} else if (bool_flag) {
211-
bool value = obj->get_bool_attribute(attr_id);
212-
Tcl_SetResult(interp, (char *) std::to_string(value).c_str(), TCL_VOLATILE);
292+
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(obj->get_bool_attribute(attr_id)));
213293
} else {
214294
if (!obj->has_attribute(attr_id))
215295
ERROR("attribute missing (required unless -bool or -string)")
@@ -264,33 +344,34 @@ static int tcl_has_attr(ClientData, Tcl_Interp *interp, int argc, const char *ar
264344
return TCL_OK;
265345
}
266346

267-
static int tcl_set_attr(ClientData, Tcl_Interp *interp, int argc, const char *argv[])
347+
static int tcl_set_attr(ClientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
268348
{
269349
int i;
270-
bool mod_flag = false, string_flag = false, int_flag = false, bool_flag = false;
271-
bool false_flag = false, true_flag = false;
272-
for (i = 1; i < argc; i++) {
273-
FLAG(mod)
274-
FLAG(string)
275-
FLAG(int)
276-
FLAG(bool)
277-
FLAG(false)
278-
FLAG(true)
350+
bool mod_flag = false, string_flag = false, bool_flag = false;
351+
bool true_flag = false, false_flag = false, sint_flag = false, uint_flag = false;
352+
for (i = 1; i < objc; i++) {
353+
FLAG2(mod)
354+
FLAG2(string)
355+
FLAG2(true)
356+
FLAG2(false)
357+
FLAG2(sint)
358+
FLAG2(uint)
359+
FLAG2(bool)
279360
break;
280361
}
281362

282-
if ((i != argc - (2 + !mod_flag + !(true_flag || false_flag))) ||
283-
(string_flag + int_flag + bool_flag + true_flag + false_flag > 1))
284-
ERROR("bad usage: expected \"set_attr -mod [-string|-int|-bool] <module> <attrname> <value>\""
285-
" or \"set_attr [-string|-int|-bool] <module> <identifier> <attrname> <value>\""
363+
if ((i != objc - (2 + !mod_flag + !(true_flag || false_flag))) ||
364+
(string_flag + sint_flag + uint_flag + bool_flag + true_flag + false_flag > 1))
365+
ERROR("bad usage: expected \"set_attr -mod [-string|-sint|-uint|-bool] <module> <attrname> <value>\""
366+
" or \"set_attr [-string|-sint|-uint|-bool] <module> <identifier> <attrname> <value>\""
286367
" or \"set_attr [-true|-false] <module> <identifier> <attrname>\""
287368
" or \"set_attr -mod [-true|-false| <module> <attrname>\"")
288369

289370
IdString mod_id, obj_id, attr_id;
290-
mod_id = RTLIL::escape_id(argv[i++]);
371+
mod_id = RTLIL::escape_id(Tcl_GetString(objv[i++]));
291372
if (!mod_flag)
292-
obj_id = RTLIL::escape_id(argv[i++]);
293-
attr_id = RTLIL::escape_id(argv[i++]);
373+
obj_id = RTLIL::escape_id(Tcl_GetString(objv[i++]));
374+
attr_id = RTLIL::escape_id(Tcl_GetString(objv[i++]));
294375

295376
RTLIL::Module *mod = yosys_design->module(mod_id);
296377
if (!mod)
@@ -313,17 +394,35 @@ static int tcl_set_attr(ClientData, Tcl_Interp *interp, int argc, const char *ar
313394
ERROR("object not found")
314395

315396
if (string_flag) {
316-
obj->set_string_attribute(attr_id, argv[i++]);
317-
} else if (int_flag) {
318-
obj->attributes[attr_id] = atoi(argv[i++]);
397+
obj->set_string_attribute(attr_id, Tcl_GetString(objv[i++]));
398+
} else if (sint_flag || uint_flag) {
399+
RTLIL::Const const_;
400+
mp_int value_mp;
401+
402+
if (Tcl_TakeBignumFromObj(interp, objv[i++], &value_mp))
403+
ERROR("non-integral value")
404+
405+
if (!mp_int_to_const(&value_mp, const_, sint_flag))
406+
ERROR("bignum manipulation failed");
407+
408+
if (sint_flag) {
409+
const_.flags |= RTLIL::CONST_FLAG_SIGNED;
410+
if (const_.size() < 32)
411+
const_.exts(32);
412+
} else {
413+
if (const_.size() < 32)
414+
const_.extu(32);
415+
}
416+
417+
obj->attributes[attr_id] = const_;
319418
} else if (bool_flag) {
320-
obj->set_bool_attribute(attr_id, atoi(argv[i++]) != 0);
419+
obj->set_bool_attribute(attr_id, atoi(Tcl_GetString(objv[i++])) != 0);
321420
} else if (true_flag) {
322421
obj->set_bool_attribute(attr_id, true);
323422
} else if (false_flag) {
324423
obj->set_bool_attribute(attr_id, false);
325424
} else {
326-
obj->attributes[attr_id] = Const::from_string(std::string(argv[i++]));
425+
obj->attributes[attr_id] = Const::from_string(std::string(Tcl_GetString(objv[i++])));
327426
}
328427

329428
return TCL_OK;
@@ -332,10 +431,14 @@ static int tcl_set_attr(ClientData, Tcl_Interp *interp, int argc, const char *ar
332431
static int tcl_get_param(ClientData, Tcl_Interp *interp, int argc, const char *argv[])
333432
{
334433
int i;
335-
bool string_flag = false, int_flag = false;
434+
bool string_flag = false, bool_flag = false;
435+
bool int_flag = false, sint_flag = false, uint_flag = false;
336436
for (i = 1; i < argc; i++) {
337437
FLAG(string)
338438
FLAG(int)
439+
FLAG(sint)
440+
FLAG(uint)
441+
FLAG(bool)
339442
break;
340443
}
341444

@@ -363,35 +466,36 @@ static int tcl_get_param(ClientData, Tcl_Interp *interp, int argc, const char *a
363466

364467
if (string_flag) {
365468
Tcl_SetResult(interp, (char *) value.decode_string().c_str(), TCL_VOLATILE);
366-
} else if (int_flag) {
367-
if (value.size() > 32)
368-
ERROR("value too large")
369-
370-
Tcl_SetResult(interp, (char *) std::to_string(value.as_int()).c_str(), TCL_VOLATILE);
469+
} else if (int_flag || uint_flag || sint_flag) {
470+
mp_int value_mp;
471+
if (!const_to_mp_int(value, &value_mp, sint_flag, uint_flag))
472+
ERROR("bignum manipulation failed");
473+
Tcl_SetObjResult(interp, Tcl_NewBignumObj(&value_mp));
371474
} else {
372475
Tcl_SetResult(interp, (char *) value.as_string().c_str(), TCL_VOLATILE);
373476
}
374477
return TCL_OK;
375478
}
376479

377-
static int tcl_set_param(ClientData, Tcl_Interp *interp, int argc, const char *argv[])
480+
static int tcl_set_param(ClientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
378481
{
379482
int i;
380-
bool string_flag = false, int_flag = false;
381-
for (i = 1; i < argc; i++) {
382-
FLAG(string)
383-
FLAG(int)
483+
bool string_flag = false, sint_flag = false, uint_flag = false;
484+
for (i = 1; i < objc; i++) {
485+
FLAG2(string)
486+
FLAG2(sint)
487+
FLAG2(uint)
384488
break;
385489
}
386490

387-
if ((i != argc - 4) ||
388-
(string_flag + int_flag > 1))
389-
ERROR("bad usage: expected \"get_param [-string|-int] <module> <cellid> <paramname> <value>")
491+
if ((i != objc - 4) ||
492+
(string_flag + sint_flag + uint_flag > 1))
493+
ERROR("bad usage: expected \"set_param [-string|-sint|-uint] <module> <cellid> <paramname> <value>")
390494

391495
IdString mod_id, cell_id, param_id;
392-
mod_id = RTLIL::escape_id(argv[i++]);
393-
cell_id = RTLIL::escape_id(argv[i++]);
394-
param_id = RTLIL::escape_id(argv[i++]);
496+
mod_id = RTLIL::escape_id(Tcl_GetString(objv[i++]));
497+
cell_id = RTLIL::escape_id(Tcl_GetString(objv[i++]));
498+
param_id = RTLIL::escape_id(Tcl_GetString(objv[i++]));
395499

396500
RTLIL::Module *mod = yosys_design->module(mod_id);
397501
if (!mod)
@@ -402,11 +506,29 @@ static int tcl_set_param(ClientData, Tcl_Interp *interp, int argc, const char *a
402506
ERROR("object not found")
403507

404508
if (string_flag) {
405-
cell->setParam(param_id, Const(std::string(argv[i++])));
406-
} else if (int_flag) {
407-
cell->setParam(param_id, Const(atoi(argv[i++])));
509+
cell->setParam(param_id, Const(std::string(Tcl_GetString(objv[i++]))));
510+
} else if (sint_flag || uint_flag) {
511+
RTLIL::Const const_;
512+
mp_int value_mp;
513+
514+
if (Tcl_TakeBignumFromObj(interp, objv[i++], &value_mp))
515+
ERROR("non-integral value")
516+
517+
if (!mp_int_to_const(&value_mp, const_, sint_flag))
518+
ERROR("bignum manipulation failed");
519+
520+
if (sint_flag) {
521+
const_.flags |= RTLIL::CONST_FLAG_SIGNED;
522+
if (const_.size() < 32)
523+
const_.exts(32);
524+
} else {
525+
if (const_.size() < 32)
526+
const_.extu(32);
527+
}
528+
529+
cell->setParam(param_id, const_);
408530
} else {
409-
cell->setParam(param_id, Const::from_string(std::string(argv[i++])));
531+
cell->setParam(param_id, Const::from_string(std::string(Tcl_GetString(objv[i++]))));
410532
}
411533
return TCL_OK;
412534
}
@@ -418,9 +540,9 @@ int yosys_tcl_iterp_init(Tcl_Interp *interp)
418540
Tcl_CreateCommand(interp, "yosys", tcl_yosys_cmd, NULL, NULL);
419541
Tcl_CreateCommand(interp, "rtlil::get_attr", tcl_get_attr, NULL, NULL);
420542
Tcl_CreateCommand(interp, "rtlil::has_attr", tcl_has_attr, NULL, NULL);
421-
Tcl_CreateCommand(interp, "rtlil::set_attr", tcl_set_attr, NULL, NULL);
543+
Tcl_CreateObjCommand(interp, "rtlil::set_attr", tcl_set_attr, NULL, NULL);
422544
Tcl_CreateCommand(interp, "rtlil::get_param", tcl_get_param, NULL, NULL);
423-
Tcl_CreateCommand(interp, "rtlil::set_param", tcl_set_param, NULL, NULL);
545+
Tcl_CreateObjCommand(interp, "rtlil::set_param", tcl_set_param, NULL, NULL);
424546

425547
// TODO:
426548
//
@@ -442,6 +564,10 @@ int yosys_tcl_iterp_init(Tcl_Interp *interp)
442564
// unpack
443565
// pack
444566

567+
// Note (dev jf 24-12-02): Make log_id escape everything that’s not a valid
568+
// verilog identifier before adding any tcl API that returns IdString values
569+
// to avoid -option injection
570+
445571
return TCL_OK ;
446572
}
447573
#endif

0 commit comments

Comments
 (0)