diff --git a/CHERICC_Fat.bsv b/CHERICC_Fat.bsv index 2d179fa..27b0ed0 100644 --- a/CHERICC_Fat.bsv +++ b/CHERICC_Fat.bsv @@ -392,7 +392,15 @@ function Bit#(n) smearMSBRight(Bit#(n) x); return res; endfunction -function Tuple2#(CapFat, Bool) setBoundsFat(CapFat cap, Address lengthFull); +typedef struct +{ + CapFat cap; + Bool exact; + CapAddress length; + CapAddress mask; +} SetBoundsReturn deriving (Bits, Eq, FShow); + +function SetBoundsReturn setBoundsFat(CapFat cap, Address lengthFull); CapFat ret = cap; // Find new exponent by finding the index of the most significant bit of the // length, or counting leading zeros in the high bits of the length, and @@ -426,7 +434,6 @@ function Tuple2#(CapFat, Bool) setBoundsFat(CapFat cap, Address lengthFull); // Create a mask with all bits set below the MSB of length and then masking all bits // below the mantissa bits. LCapAddress lmask = smearMSBRight(len); - LCapAddress lengthMsb = lmask ^ (lmask>>1); // The shift amount required to put the most significant set bit of the // len just above the bottom HalfExpW bits that are taken by the exp. Integer shiftAmount = valueOf(TSub#(TSub#(MW,2),HalfExpW)); @@ -438,17 +445,16 @@ function Tuple2#(CapFat, Bool) setBoundsFat(CapFat cap, Address lengthFull); // shifted out bits or in the HalfExpW bits stolen for the exponent // Shift by MW-1 to move MSB of mask just below the mantissa, then up HalfExpW // more to take in the bits that will be lost for the exponent when it is non-zero. - LCapAddress lmaskLo = lmask>>fromInteger(shiftAmount+1); + LCapAddress lmaskLor = lmask>>fromInteger(shiftAmount+1); + LCapAddress lmaskLo = lmask>>fromInteger(shiftAmount); // For the len, we're not actually losing significance since we're not storing it, // we just want to know if any low bits are non-zero so that we will know if it will // cause the total length to round up. - Bool lostSignificantLen = (len&lmaskLo)!=0 && intExp; - Bool lostSignificantTop = (top&lmaskLo)!=0 && intExp; + Bool lostSignificantLen = (len&lmaskLor)!=0 && intExp; + Bool lostSignificantTop = (top&lmaskLor)!=0 && intExp; // Check if non-zero bits were lost in the low bits of base, either in the 'e' // shifted out bits or in the HalfExpW bits stolen for the exponent - Bool lostSignificantBase = (base&lmaskLo)!=0 && intExp; - // If either base or top lost significant bits and we wanted an exact setBounds, - // void the return capability + Bool lostSignificantBase = (base&lmaskLor)!=0 && intExp; // Calculate all values associated with E=e+1 (e rounding up due to msb of L increasing by 1) // This value is just to avoid adding later. @@ -457,7 +463,6 @@ function Tuple2#(CapFat, Bool) setBoundsFat(CapFat cap, Address lengthFull); // shifted out bits or in the HalfExpW bits stolen for the exponent // Shift by MW-1 to move MSB of mask just below the mantissa, then up HalfExpW // more to take in the bits that will be lost for the exponent when it is non-zero. - lmaskLo = lmask>>fromInteger(shiftAmount); Bool lostSignificantTopHigher = (top&lmaskLo)!=0 && intExp; // Check if non-zero bits were lost in the low bits of base, either in the 'e' // shifted out bits or in the HalfExpW bits stolen for the exponent @@ -465,24 +470,37 @@ function Tuple2#(CapFat, Bool) setBoundsFat(CapFat cap, Address lengthFull); // If either base or top lost significant bits and we wanted an exact setBounds, // void the return capability + // We need to round up Exp if the msb of length will increase. + // We can check how much the length will increase without looking at the result of adding the + // length to the base. We do this by adding the lower bits of the length to the base and then + // comparing both halves (above and below the mask) to zero. Either side that is non-zero indicates + // an extra "1" that will be added to the "mantissa" bits of the length, potentially causing overflow. + // Finally check how close the requested length is to overflow, and test in relation to how much the + // length will increase. + LCapAddress topLo = (lmaskLor & len) + (lmaskLor & base); + Bool lengthCarryIn = (~lmaskLor & topLo) != 0; + Bool lengthRoundUp = (lmaskLor & topLo) != 0; + Bool lengthIsMax = (len & (~lmaskLor)) == (lmask ^ lmaskLor); + Bool lengthIsMaxLessOne = (len & (~lmaskLor)) == (lmask ^ lmaskLo); - // We need to round up Exp if the length is within 1 of the maximum and if it will increase. - // The lomask for checking for potential overflow should mask all but the bottom bit of the mantissa. - lmaskLo = lmask>>fromInteger(shiftAmount); - Bool lengthMax = (len&(~lmaskLo))==(lmask&(~lmaskLo)); - Bool resultExact = True; - if(lengthMax && intExp && (lostSignificantLen || lostSignificantBase)) begin - e = e+1; - ret.bounds.topBits = (lostSignificantTopHigher) ? (newTopBitsHigher+'b1000):newTopBitsHigher; - ret.bounds.baseBits = truncateLSB(newBaseBits); - if (lostSignificantBaseHigher || lostSignificantTopHigher) resultExact = False; + Bool lengthOverflow = False; + if (lengthIsMax && (lengthCarryIn || lengthRoundUp)) lengthOverflow = True; + if (lengthIsMaxLessOne && lengthCarryIn && lengthRoundUp) lengthOverflow = True; + + Bool exact = True; + LCapAddress baseMask = ~lmaskLor; + if(lengthOverflow && intExp) begin + e = e+1; + ret.bounds.topBits = (lostSignificantTopHigher) ? (newTopBitsHigher+'b1000):newTopBitsHigher; + ret.bounds.baseBits = truncateLSB(newBaseBits); + exact = !(lostSignificantBaseHigher || lostSignificantTopHigher); + baseMask = ~lmaskLo; end else begin - ret.bounds.topBits = (lostSignificantTop) ? truncate(newTopBits+'b1000):truncate(newTopBits); - ret.bounds.baseBits = truncate(newBaseBits); - if (lostSignificantBase || lostSignificantTop) resultExact = False; + ret.bounds.topBits = (lostSignificantTop) ? truncate(newTopBits+'b1000):truncate(newTopBits); + ret.bounds.baseBits = truncate(newBaseBits); + exact = !(lostSignificantBase || lostSignificantTop); end - ret.bounds.exp = e; // Update the addrBits fields ret.addrBits = ret.bounds.baseBits; @@ -497,8 +515,18 @@ function Tuple2#(CapFat, Bool) setBoundsFat(CapFat cap, Address lengthFull); ret.bounds.topBits = {truncateLSB(ret.bounds.topBits), botZeroes}; end + // Begin calculate newLength in case this is a request just for a representable length: + LCapAddress newLength = zeroExtend(length); + if (intExp) begin + LCapAddress oneInLsb = (lmask ^ (lmask>>1)) >> shiftAmount; + LCapAddress newLengthRounded = newLength + oneInLsb; + newLength = (newLength & (~lmaskLor)); + newLengthRounded = (newLengthRounded & (~lmaskLor)); + if (lostSignificantLen) newLength = newLengthRounded; + end + // Return derived capability - return tuple2(ret, resultExact); + return SetBoundsReturn{cap: ret, exact: exact, length: truncate(newLength), mask: truncate(baseMask)}; endfunction function CapFat seal(CapFat cap, TempFields tf, CType otype); CapFat ret = cap; @@ -994,8 +1022,8 @@ instance CHERICap #(CapReg, OTypeW, FlagsW, CapAddressW, CapW, TSub#(MW, 3)); function isInBounds = error("feature not implemented for this cap type"); function Exact#(CapReg) setBounds (CapReg cap, Bit#(CapAddressW) length); - match {.result, .exact} = setBoundsFat(cap, length); - return Exact {exact: exact, value: result}; + SetBoundsReturn sr = setBoundsFat(cap, length); + return Exact {exact: sr.exact, value: sr.cap}; endfunction function CapReg nullWithAddr (Bit#(CapAddressW) addr); @@ -1033,9 +1061,13 @@ instance CHERICap #(CapReg, OTypeW, FlagsW, CapAddressW, CapW, TSub#(MW, 3)); endfunction function Bit#(CapAddressW) getRepresentableAlignmentMask (CapReg dummy, Bit#(CapAddressW) length_request); - let setBoundsCap = nullWithAddr((~0) - length_request); - Exact#(CapFat) result = setBounds(setBoundsCap, length_request); - return (~0) << (result.value.bounds.exp == 0 ? 0 : result.value.bounds.exp + fromInteger(valueOf(HalfExpW))); + SetBoundsReturn sr = setBoundsFat(nullCap, length_request); + return sr.mask; + endfunction + + function Bit#(CapAddressW) getRepresentableLength (CapReg dummy, Bit#(CapAddressW) length_request); + SetBoundsReturn sr = setBoundsFat(nullCap, length_request); + return sr.length; endfunction endinstance