diff --git a/libs/symfpu b/libs/symfpu index 423911dc2..37cf1437b 160000 --- a/libs/symfpu +++ b/libs/symfpu @@ -1 +1 @@ -Subproject commit 423911dc2022418d80a5aadd3ea3a876b352c9fc +Subproject commit 37cf1437bd01176b3042b5644346f73df810ef37 diff --git a/passes/cmds/symfpu.cc b/passes/cmds/symfpu.cc index 90f2f3863..acb33f37b 100644 --- a/passes/cmds/symfpu.cc +++ b/passes/cmds/symfpu.cc @@ -99,7 +99,8 @@ using symfpu::ite; using uf = symfpu::unpackedFloat; using uf_flagged = symfpu::floatWithStatusFlags; using uf_flagged_ite = symfpu::ite; -using ubv_flagged = symfpu::ubvWithStatusFlags; +using ubv_flagged = symfpu::bvWithStatusFlags; +using sbv_flagged = symfpu::bvWithStatusFlags; PRIVATE_NAMESPACE_END @@ -183,8 +184,8 @@ template struct bv { return bv{SigSpec(value)}; } - bv toSigned(void) const { return bv(*this); } - bv toUnsigned(void) const { return bv(*this); } + bv toSigned(void) const { return bv(*this); } + bv toUnsigned(void) const { return bv(*this); } bv extract(bwt upper, bwt lower) const { @@ -382,6 +383,13 @@ ubv input_ubv(IdString name, int width) return ubv(SigSpec(input)); } +prop input_prop(IdString name) +{ + auto input = symfpu_mod->addWire(name); + input->port_input = true; + return prop(SigBit(input)); +} + void output_ubv(IdString name, const ubv &value) { auto output = symfpu_mod->addWire(name, value.getWidth()); @@ -766,12 +774,21 @@ struct SymFpuConvertPass : public Pass { output_ubv(ID(o_ff), symfpu::pack(o_format, o_ff.val)); output_flags(ID(flags_ff), o_ff.nv || i_sNaN, o_ff.nx, o_ff.of, o_ff.uf); - ubv o_default = symfpu::ITE(i_f.getSign(), ubv::zero(o_size), ubv::allOnes(o_size)); - ubv_flagged o_fi = symfpu::convertFloatToUBV_flagged(i_format, rounding_mode, i_f, o_size, o_default); - output_ubv(ID(o_fi), o_fi.val); - output_flags(ID(flags_fi), o_fi.nv, o_fi.nx); + auto is_signed = input_prop(ID(is_signed)); - uf_flagged o_if = symfpu::convertUBVToFloat_flagged(o_format, rounding_mode, i_bv); + // use riscv behavior for invalid inputs + ubv o_signed_default = symfpu::ITE(i_f.getSign(), ubv::one(1).append(ubv::zero(o_size-1)), ubv::zero(1).append(ubv::allOnes(o_size-1))); + ubv o_unsigned_default = symfpu::ITE(i_f.getSign(), ubv::zero(o_size), ubv::allOnes(o_size)); + auto o_fi_signed = symfpu::convertFloatToSBV_flagged(i_format, rounding_mode, i_f, o_size, o_signed_default); + auto o_fi_unsigned = symfpu::convertFloatToUBV_flagged(i_format, rounding_mode, i_f, o_size, o_unsigned_default); + output_ubv(ID(o_fi), symfpu::ITE(is_signed, o_fi_signed.val.toUnsigned(), o_fi_unsigned.val)); + output_flags(ID(flags_fi), + symfpu::ITE(is_signed, o_fi_signed.nv, o_fi_unsigned.nv), + symfpu::ITE(is_signed, o_fi_signed.nx, o_fi_unsigned.nx)); + + uf_flagged o_if(uf_flagged_ite::iteOp(is_signed, + symfpu::convertSBVToFloat_flagged(o_format, rounding_mode, i_bv), + symfpu::convertUBVToFloat_flagged(o_format, rounding_mode, i_bv))); output_ubv(ID(o_if), symfpu::pack(o_format, o_if.val)); output_flags(ID(flags_if), o_if.nv, o_if.nx, o_if.of);