diff options
Diffstat (limited to 'src/arch/x86/isa/microops/regop.isa')
-rw-r--r-- | src/arch/x86/isa/microops/regop.isa | 104 |
1 files changed, 94 insertions, 10 deletions
diff --git a/src/arch/x86/isa/microops/regop.isa b/src/arch/x86/isa/microops/regop.isa index d2cfff9d4..371ff63da 100644 --- a/src/arch/x86/isa/microops/regop.isa +++ b/src/arch/x86/isa/microops/regop.isa @@ -227,6 +227,45 @@ def template MicroRegOpImmConstructor {{ } }}; +output header {{ + void + divide(uint64_t dividend, uint64_t divisor, + uint64_t "ient, uint64_t &remainder); +}}; + +output decoder {{ + void + divide(uint64_t dividend, uint64_t divisor, + uint64_t "ient, uint64_t &remainder) + { + //Check for divide by zero. + if (divisor == 0) + panic("Divide by zero!\\n"); + //If the divisor is bigger than the dividend, don't do anything. + if (divisor <= dividend) { + //Shift the divisor so it's msb lines up with the dividend. + int dividendMsb = findMsbSet(dividend); + int divisorMsb = findMsbSet(divisor); + int shift = dividendMsb - divisorMsb; + divisor <<= shift; + //Compute what we'll add to the quotient if the divisor isn't + //now larger than the dividend. + uint64_t quotientBit = 1; + quotientBit <<= shift; + //If we need to step back a bit (no pun intended) because the + //divisor got too to large, do that here. This is the "or two" + //part of one or two bit division. + if (divisor > dividend) { + quotientBit >>= 1; + divisor >>= 1; + } + //Decrement the remainder and increment the quotient. + quotient += quotientBit; + remainder -= divisor; + } + } +}}; + let {{ # Make these empty strings so that concatenating onto # them will always work. @@ -507,20 +546,65 @@ let {{ ccFlagBits = ccFlagBits & ~(ext & (CFBit | OFBit | ECFBit)); ''' - class Div1(FlagRegOp): + # One or two bit divide + class Div1(WrRegOp): code = ''' - int halfSize = (dataSize * 8) / 2; - IntReg quotient = (psrc1 / op2) & mask(halfSize); - IntReg remainder = (psrc1 % op2) & mask(halfSize); - IntReg result = quotient | (remainder << halfSize); - DestReg = merge(DestReg, result, dataSize); + //These are temporaries so that modifying them later won't make + //the ISA parser think they're also sources. + uint64_t quotient = 0; + uint64_t remainder = psrc1; + //Similarly, this is a temporary so changing it doesn't make it + //a source. + uint64_t divisor = op2; + //This is a temporary just for consistency and clarity. + uint64_t dividend = remainder; + //Do the division. + divide(dividend, divisor, quotient, remainder); + //Record the final results. + Remainder = remainder; + Quotient = quotient; + Divisor = divisor; ''' - class Divq(FlagRegOp): - code = 'DestReg = merge(DestReg, psrc1 / op2, dataSize);' + # Step divide + class Div2(RegOp): + code = ''' + uint64_t dividend = Remainder; + uint64_t divisor = Divisor; + uint64_t quotient = Quotient; + uint64_t remainder = dividend; + int remaining = op2; + //If we overshot, do nothing. This lets us unrool division loops a + //little. + if (remaining) { + //Shift in bits from the low order portion of the dividend + while(dividend < divisor && remaining) { + dividend = (dividend << 1) | bits(SrcReg1, remaining - 1); + quotient <<= 1; + remaining--; + } + remainder = dividend; + //Do the division. + divide(dividend, divisor, quotient, remainder); + } + //Keep track of how many bits there are still to pull in. + DestReg = merge(DestReg, remaining, dataSize); + //Record the final results + Remainder = remainder; + Quotient = quotient; + ''' + flag_code = ''' + if (DestReg == 0) + ccFlagBits = ccFlagBits | (ext & EZFBit); + else + ccFlagBits = ccFlagBits & ~(ext & EZFBit); + ''' + + class Divq(RdRegOp): + code = 'DestReg = merge(SrcReg1, Quotient, dataSize);' - class Divr(FlagRegOp): - code = 'DestReg = merge(DestReg, psrc1 % op2, dataSize);' + class Divr(RdRegOp): + code = 'DestReg = merge(SrcReg1, Remainder, dataSize);' class Mov(CondRegOp): code = 'DestReg = merge(SrcReg1, op2, dataSize)' |