summaryrefslogtreecommitdiff
path: root/src/arch/x86/isa/microops/regop.isa
diff options
context:
space:
mode:
Diffstat (limited to 'src/arch/x86/isa/microops/regop.isa')
-rw-r--r--src/arch/x86/isa/microops/regop.isa104
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 &quotient, uint64_t &remainder);
+}};
+
+output decoder {{
+ void
+ divide(uint64_t dividend, uint64_t divisor,
+ uint64_t &quotient, 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)'