summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGabe Black <gblack@eecs.umich.edu>2007-09-13 16:34:46 -0700
committerGabe Black <gblack@eecs.umich.edu>2007-09-13 16:34:46 -0700
commitf7b6230d99e102f3a6195687fed0617005a70424 (patch)
tree360dd76c0b7d7f159e816af90ab8fb3e62f3c36c /src
parent0f57b407a3df68f93e73e0635569d7bf5dd151b0 (diff)
downloadgem5-f7b6230d99e102f3a6195687fed0617005a70424.tar.xz
X86: Total overhaul of the division instructions and microops.
--HG-- extra : convert_revision : 303ea45f69f7805361ad877fe6bb43fbc3dfd7a6
Diffstat (limited to 'src')
-rw-r--r--src/arch/x86/isa/insts/arithmetic/multiply_and_divide.py579
-rw-r--r--src/arch/x86/isa/microops/regop.isa104
-rw-r--r--src/arch/x86/isa/operands.isa3
-rw-r--r--src/arch/x86/x86_traits.hh3
4 files changed, 650 insertions, 39 deletions
diff --git a/src/arch/x86/isa/insts/arithmetic/multiply_and_divide.py b/src/arch/x86/isa/insts/arithmetic/multiply_and_divide.py
index 197de5fb3..a9b53acac 100644
--- a/src/arch/x86/isa/insts/arithmetic/multiply_and_divide.py
+++ b/src/arch/x86/isa/insts/arithmetic/multiply_and_divide.py
@@ -234,20 +234,70 @@ def macroop IMUL_R_P_I
def macroop DIV_B_R
{
- div1 rax, rax, reg
+ # Do the initial part of the division
+ div1 rsi, reg, dataSize=1
+
+ #These are split out so we can initialize the number of bits in the
+ #second register
+ div2i t1, rax, 8, dataSize=1
+ div2 t1, rax, t1, dataSize=1
+
+ #Loop until we're out of bits to shift in
+divLoopTop:
+ div2 t1, rax, t1, dataSize=1
+ div2 t1, rax, t1, flags=(EZF,), dataSize=1
+ bri t0, label("divLoopTop"), flags=(nCEZF,)
+
+ #Unload the answer
+ divq rax, dataSize=1
+ divr rsi, dataSize=1
};
def macroop DIV_B_M
{
- ld t1, seg, sib, disp
- div1 rax, rax, t1
+ ld t2, seg, sib, disp
+
+ # Do the initial part of the division
+ div1 rsi, t2, dataSize=1
+
+ #These are split out so we can initialize the number of bits in the
+ #second register
+ div2i t1, rax, 8, dataSize=1
+ div2 t1, rax, t1, dataSize=1
+
+ #Loop until we're out of bits to shift in
+divLoopTop:
+ div2 t1, rax, t1, dataSize=1
+ div2 t1, rax, t1, flags=(EZF,), dataSize=1
+ bri t0, label("divLoopTop"), flags=(nCEZF,)
+
+ #Unload the answer
+ divq rax, dataSize=1
+ divr rsi, dataSize=1
};
def macroop DIV_B_P
{
rdip t7
- ld t1, seg, riprel, disp
- div1 rax, rax, t1
+ ld t2, seg, riprel, disp
+
+ # Do the initial part of the division
+ div1 rsi, t2, dataSize=1
+
+ #These are split out so we can initialize the number of bits in the
+ #second register
+ div2i t1, rax, 8, dataSize=1
+ div2 t1, rax, t1, dataSize=1
+
+ #Loop until we're out of bits to shift in
+divLoopTop:
+ div2 t1, rax, t1, dataSize=1
+ div2 t1, rax, t1, flags=(EZF,), dataSize=1
+ bri t0, label("divLoopTop"), flags=(nCEZF,)
+
+ #Unload the answer
+ divq rax, dataSize=1
+ divr rsi, dataSize=1
};
#
@@ -256,24 +306,301 @@ def macroop DIV_B_P
def macroop DIV_R
{
- divr t1, rax, reg
- divq rax, rax, reg
- mov rdx, rdx, t1
+ # Do the initial part of the division
+ div1 rdx, reg
+
+ #These are split out so we can initialize the number of bits in the
+ #second register
+ div2i t1, rax, "env.dataSize * 8"
+ div2 t1, rax, t1
+
+ #Loop until we're out of bits to shift in
+ #The amount of unrolling here could stand some tuning
+divLoopTop:
+ div2 t1, rax, t1
+ div2 t1, rax, t1
+ div2 t1, rax, t1
+ div2 t1, rax, t1, flags=(EZF,)
+ bri t0, label("divLoopTop"), flags=(nCEZF,)
+
+ #Unload the answer
+ divq rax
+ divr rdx
};
def macroop DIV_M
{
- ld t1, seg, sib, disp
- divr rdx, rax, t1
- divq rax, rax, t1
+ ld t2, seg, sib, disp
+
+ # Do the initial part of the division
+ div1 rdx, t2
+
+ #These are split out so we can initialize the number of bits in the
+ #second register
+ div2i t1, rax, "env.dataSize * 8"
+ div2 t1, rax, t1
+
+ #Loop until we're out of bits to shift in
+ #The amount of unrolling here could stand some tuning
+divLoopTop:
+ div2 t1, rax, t1
+ div2 t1, rax, t1
+ div2 t1, rax, t1
+ div2 t1, rax, t1, flags=(EZF,)
+ bri t0, label("divLoopTop"), flags=(nCEZF,)
+
+ #Unload the answer
+ divq rax
+ divr rdx
};
def macroop DIV_P
{
rdip t7
- ld t1, seg, riprel, disp
- divr rdx, rax, t1
- divq rax, rax, t1
+ ld t2, seg, riprel, disp
+
+ # Do the initial part of the division
+ div1 rdx, t2
+
+ #These are split out so we can initialize the number of bits in the
+ #second register
+ div2i t1, rax, "env.dataSize * 8"
+ div2 t1, rax, t1
+
+ #Loop until we're out of bits to shift in
+ #The amount of unrolling here could stand some tuning
+divLoopTop:
+ div2 t1, rax, t1
+ div2 t1, rax, t1
+ div2 t1, rax, t1
+ div2 t1, rax, t1, flags=(EZF,)
+ bri t0, label("divLoopTop"), flags=(nCEZF,)
+
+ #Unload the answer
+ divq rax
+ divr rdx
+};
+
+#
+# One byte version of signed division
+#
+
+def macroop IDIV_B_R
+{
+ # Negate dividend
+ sub t1, t0, rax, flags=(ECF,), dataSize=1
+ ruflag t4, 3
+ sub t2, t0, rsi, dataSize=1
+ sub t2, t2, t4
+
+ #Find the sign of the divisor
+ #FIXME!!! This depends on shifts setting the carry flag correctly.
+ slli t0, reg, 1, flags=(ECF,), dataSize=1
+
+ # Negate divisor
+ sub t3, t0, reg, dataSize=1
+ # Put the divisor's absolute value into t3
+ mov t3, t3, reg, flags=(nCECF,), dataSize=1
+
+ #Find the sign of the dividend
+ #FIXME!!! This depends on shifts setting the carry flag correctly.
+ slli t0, rsi, 1, flags=(ECF,), dataSize=1
+
+ # Put the dividend's absolute value into t1 and t2
+ mov t1, t1, rax, flags=(nCECF,), dataSize=1
+ mov t2, t2, rsi, flags=(nCECF,), dataSize=1
+
+ # Do the initial part of the division
+ div1 t2, t3, dataSize=1
+
+ #These are split out so we can initialize the number of bits in the
+ #second register
+ div2i t4, t1, 8, dataSize=1
+ div2 t4, t1, t4, dataSize=1
+
+ #Loop until we're out of bits to shift in
+divLoopTop:
+ div2 t4, t1, t4, dataSize=1
+ div2 t4, t1, t4, flags=(EZF,), dataSize=1
+ bri t0, label("divLoopTop"), flags=(nCEZF,)
+
+ #Unload the answer
+ divq t5, dataSize=1
+ divr t6, dataSize=1
+
+ # Fix up signs. The sign of the dividend is still lying around in ECF.
+ # The sign of the remainder, ah, is the same as the dividend. The sign
+ # of the quotient is negated if the signs of the divisor and dividend
+ # were different.
+
+ # Negate the remainder
+ sub t4, t0, t6, dataSize=1
+ # If the dividend was negitive, put the negated remainder in rsi.
+ mov rsi, rsi, t4, (CECF,), dataSize=1
+ # Otherwise put the regular remainder in rsi.
+ mov rsi, rsi, t6, (nCECF,), dataSize=1
+
+ # Negate the quotient.
+ sub t4, t0, t5, dataSize=1
+ # If the dividend was negative, start using the negated quotient
+ mov t5, t5, t4, (CECF,), dataSize=1
+
+ # Check the sign of the divisor
+ slli t0, t3, 1, flags=(ECF,), dataSize=1
+
+ # Negate the (possibly already negated) quotient
+ sub t4, t0, t5, dataSize=1
+ # If the divisor was negative, put the negated quotient in rax.
+ mov rax, rax, t4, (CECF,), dataSize=1
+ # Otherwise put the one that wasn't negated (at least here) in rax.
+ mov rax, rax, t5, (nCECF,), dataSize=1
+};
+
+def macroop IDIV_B_M
+{
+ # Negate dividend
+ sub t1, t0, rax, flags=(ECF,), dataSize=1
+ ruflag t4, 3
+ sub t2, t0, rsi, dataSize=1
+ sub t2, t2, t4
+
+ ld t3, seg, sib, disp
+
+ #Find the sign of the divisor
+ #FIXME!!! This depends on shifts setting the carry flag correctly.
+ slli t0, t3, 1, flags=(ECF,), dataSize=1
+
+ # Negate divisor
+ sub t4, t0, t3, dataSize=1
+ # Put the divisor's absolute value into t3
+ mov t3, t3, t4, flags=(CECF,), dataSize=1
+
+ #Find the sign of the dividend
+ #FIXME!!! This depends on shifts setting the carry flag correctly.
+ slli t0, rsi, 1, flags=(ECF,), dataSize=1
+
+ # Put the dividend's absolute value into t1 and t2
+ mov t1, t1, rax, flags=(nCECF,), dataSize=1
+ mov t2, t2, rsi, flags=(nCECF,), dataSize=1
+
+ # Do the initial part of the division
+ div1 t2, t3, dataSize=1
+
+ #These are split out so we can initialize the number of bits in the
+ #second register
+ div2i t4, t1, 8, dataSize=1
+ div2 t4, t1, t4, dataSize=1
+
+ #Loop until we're out of bits to shift in
+divLoopTop:
+ div2 t4, t1, t4, dataSize=1
+ div2 t4, t1, t4, flags=(EZF,), dataSize=1
+ bri t0, label("divLoopTop"), flags=(nCEZF,)
+
+ #Unload the answer
+ divq t5, dataSize=1
+ divr t6, dataSize=1
+
+ # Fix up signs. The sign of the dividend is still lying around in ECF.
+ # The sign of the remainder, ah, is the same as the dividend. The sign
+ # of the quotient is negated if the signs of the divisor and dividend
+ # were different.
+
+ # Negate the remainder
+ sub t4, t0, t6, dataSize=1
+ # If the dividend was negitive, put the negated remainder in rsi.
+ mov rsi, rsi, t4, (CECF,), dataSize=1
+ # Otherwise put the regular remainder in rsi.
+ mov rsi, rsi, t6, (nCECF,), dataSize=1
+
+ # Negate the quotient.
+ sub t4, t0, t5, dataSize=1
+ # If the dividend was negative, start using the negated quotient
+ mov t5, t5, t4, (CECF,), dataSize=1
+
+ # Check the sign of the divisor
+ slli t0, t3, 1, flags=(ECF,), dataSize=1
+
+ # Negate the (possibly already negated) quotient
+ sub t4, t0, t5, dataSize=1
+ # If the divisor was negative, put the negated quotient in rax.
+ mov rax, rax, t4, (CECF,), dataSize=1
+ # Otherwise put the one that wasn't negated (at least here) in rax.
+ mov rax, rax, t5, (nCECF,), dataSize=1
+};
+
+def macroop IDIV_B_P
+{
+ # Negate dividend
+ sub t1, t0, rax, flags=(ECF,), dataSize=1
+ ruflag t4, 3
+ sub t2, t0, rsi, dataSize=1
+ sub t2, t2, t4
+
+ rdip t7
+ ld t3, seg, riprel, disp
+
+ #Find the sign of the divisor
+ #FIXME!!! This depends on shifts setting the carry flag correctly.
+ slli t0, t3, 1, flags=(ECF,), dataSize=1
+
+ # Negate divisor
+ sub t4, t0, t3, dataSize=1
+ # Put the divisor's absolute value into t3
+ mov t3, t3, t4, flags=(CECF,), dataSize=1
+
+ #Find the sign of the dividend
+ #FIXME!!! This depends on shifts setting the carry flag correctly.
+ slli t0, rsi, 1, flags=(ECF,), dataSize=1
+
+ # Put the dividend's absolute value into t1 and t2
+ mov t1, t1, rax, flags=(nCECF,), dataSize=1
+ mov t2, t2, rsi, flags=(nCECF,), dataSize=1
+
+ # Do the initial part of the division
+ div1 t2, t3, dataSize=1
+
+ #These are split out so we can initialize the number of bits in the
+ #second register
+ div2i t4, t1, 8, dataSize=1
+ div2 t4, t1, t4, dataSize=1
+
+ #Loop until we're out of bits to shift in
+divLoopTop:
+ div2 t4, t1, t4, dataSize=1
+ div2 t4, t1, t4, flags=(EZF,), dataSize=1
+ bri t0, label("divLoopTop"), flags=(nCEZF,)
+
+ #Unload the answer
+ divq t5, dataSize=1
+ divr t6, dataSize=1
+
+ # Fix up signs. The sign of the dividend is still lying around in ECF.
+ # The sign of the remainder, ah, is the same as the dividend. The sign
+ # of the quotient is negated if the signs of the divisor and dividend
+ # were different.
+
+ # Negate the remainder
+ sub t4, t0, t6, dataSize=1
+ # If the dividend was negitive, put the negated remainder in rsi.
+ mov rsi, rsi, t4, (CECF,), dataSize=1
+ # Otherwise put the regular remainder in rsi.
+ mov rsi, rsi, t6, (nCECF,), dataSize=1
+
+ # Negate the quotient.
+ sub t4, t0, t5, dataSize=1
+ # If the dividend was negative, start using the negated quotient
+ mov t5, t5, t4, (CECF,), dataSize=1
+
+ # Check the sign of the divisor
+ slli t0, t3, 1, flags=(ECF,), dataSize=1
+
+ # Negate the (possibly already negated) quotient
+ sub t4, t0, t5, dataSize=1
+ # If the divisor was negative, put the negated quotient in rax.
+ mov rax, rax, t4, (CECF,), dataSize=1
+ # Otherwise put the one that wasn't negated (at least here) in rax.
+ mov rax, rax, t5, (nCECF,), dataSize=1
};
#
@@ -282,27 +609,225 @@ def macroop DIV_P
def macroop IDIV_R
{
- divr t1, rax, reg
- divq rax, rax, reg
- mov rdx, rdx, t1
+ # Negate dividend
+ sub t1, t0, rax, flags=(ECF,)
+ ruflag t4, 3
+ sub t2, t0, rdx
+ sub t2, t2, t4
+
+ #Find the sign of the divisor
+ #FIXME!!! This depends on shifts setting the carry flag correctly.
+ slli t0, reg, 1, flags=(ECF,)
+
+ # Negate divisor
+ sub t3, t0, reg
+ # Put the divisor's absolute value into t3
+ mov t3, t3, reg, flags=(nCECF,)
+
+ #Find the sign of the dividend
+ #FIXME!!! This depends on shifts setting the carry flag correctly.
+ slli t0, rdx, 1, flags=(ECF,)
+
+ # Put the dividend's absolute value into t1 and t2
+ mov t1, t1, rax, flags=(nCECF,)
+ mov t2, t2, rdx, flags=(nCECF,)
+
+ # Do the initial part of the division
+ div1 t2, t3
+
+ #These are split out so we can initialize the number of bits in the
+ #second register
+ div2i t4, t1, "env.dataSize * 8"
+ div2 t4, t1, t4
+
+ #Loop until we're out of bits to shift in
+divLoopTop:
+ div2 t4, t1, t4
+ div2 t4, t1, t4
+ div2 t4, t1, t4
+ div2 t4, t1, t4, flags=(EZF,)
+ bri t0, label("divLoopTop"), flags=(nCEZF,)
+
+ #Unload the answer
+ divq t5
+ divr t6
+
+ # Fix up signs. The sign of the dividend is still lying around in ECF.
+ # The sign of the remainder, ah, is the same as the dividend. The sign
+ # of the quotient is negated if the signs of the divisor and dividend
+ # were different.
+
+ # Negate the remainder
+ sub t4, t0, t6
+ # If the dividend was negitive, put the negated remainder in rdx.
+ mov rdx, rdx, t4, (CECF,)
+ # Otherwise put the regular remainder in rdx.
+ mov rdx, rdx, t6, (nCECF,)
+
+ # Negate the quotient.
+ sub t4, t0, t5
+ # If the dividend was negative, start using the negated quotient
+ mov t5, t5, t4, (CECF,)
+
+ # Check the sign of the divisor
+ slli t0, t3, 1, flags=(ECF,)
+
+ # Negate the (possibly already negated) quotient
+ sub t4, t0, t5
+ # If the divisor was negative, put the negated quotient in rax.
+ mov rax, rax, t4, (CECF,)
+ # Otherwise put the one that wasn't negated (at least here) in rax.
+ mov rax, rax, t5, (nCECF,)
};
def macroop IDIV_M
{
- ld t1, seg, sib, disp
- divr rdx, rax, t1
- divq rax, rax, t1
+ # Negate dividend
+ sub t1, t0, rax, flags=(ECF,)
+ ruflag t4, 3
+ sub t2, t0, rdx
+ sub t2, t2, t4
+
+ ld t3, seg, sib, disp
+
+ #Find the sign of the divisor
+ #FIXME!!! This depends on shifts setting the carry flag correctly.
+ slli t0, t3, 1, flags=(ECF,)
+
+ # Negate divisor
+ sub t4, t0, t3
+ # Put the divisor's absolute value into t3
+ mov t3, t3, t4, flags=(CECF,)
+
+ #Find the sign of the dividend
+ #FIXME!!! This depends on shifts setting the carry flag correctly.
+ slli t0, rdx, 1, flags=(ECF,)
+
+ # Put the dividend's absolute value into t1 and t2
+ mov t1, t1, rax, flags=(nCECF,)
+ mov t2, t2, rdx, flags=(nCECF,)
+
+ # Do the initial part of the division
+ div1 t2, t3
+
+ #These are split out so we can initialize the number of bits in the
+ #second register
+ div2i t4, t1, "env.dataSize * 8"
+ div2 t4, t1, t4
+
+ #Loop until we're out of bits to shift in
+divLoopTop:
+ div2 t4, t1, t4
+ div2 t4, t1, t4
+ div2 t4, t1, t4
+ div2 t4, t1, t4, flags=(EZF,)
+ bri t0, label("divLoopTop"), flags=(nCEZF,)
+
+ #Unload the answer
+ divq t5
+ divr t6
+
+ # Fix up signs. The sign of the dividend is still lying around in ECF.
+ # The sign of the remainder, ah, is the same as the dividend. The sign
+ # of the quotient is negated if the signs of the divisor and dividend
+ # were different.
+
+ # Negate the remainder
+ sub t4, t0, t6
+ # If the dividend was negitive, put the negated remainder in rdx.
+ mov rdx, rdx, t4, (CECF,)
+ # Otherwise put the regular remainder in rdx.
+ mov rdx, rdx, t6, (nCECF,)
+
+ # Negate the quotient.
+ sub t4, t0, t5
+ # If the dividend was negative, start using the negated quotient
+ mov t5, t5, t4, (CECF,)
+
+ # Check the sign of the divisor
+ slli t0, t3, 1, flags=(ECF,)
+
+ # Negate the (possibly already negated) quotient
+ sub t4, t0, t5
+ # If the divisor was negative, put the negated quotient in rax.
+ mov rax, rax, t4, (CECF,)
+ # Otherwise put the one that wasn't negated (at least here) in rax.
+ mov rax, rax, t5, (nCECF,)
};
def macroop IDIV_P
{
+ # Negate dividend
+ sub t1, t0, rax, flags=(ECF,)
+ ruflag t4, 3
+ sub t2, t0, rdx
+ sub t2, t2, t4
+
rdip t7
- ld t1, seg, riprel, disp
- divr rdx, rax, t1
- divq rax, rax, t1
+ ld t3, seg, riprel, disp
+
+ #Find the sign of the divisor
+ #FIXME!!! This depends on shifts setting the carry flag correctly.
+ slli t0, t3, 1, flags=(ECF,)
+
+ # Negate divisor
+ sub t4, t0, t3
+ # Put the divisor's absolute value into t3
+ mov t3, t3, t4, flags=(CECF,)
+
+ #Find the sign of the dividend
+ #FIXME!!! This depends on shifts setting the carry flag correctly.
+ slli t0, rdx, 1, flags=(ECF,)
+
+ # Put the dividend's absolute value into t1 and t2
+ mov t1, t1, rax, flags=(nCECF,)
+ mov t2, t2, rdx, flags=(nCECF,)
+
+ # Do the initial part of the division
+ div1 t2, t3
+
+ #These are split out so we can initialize the number of bits in the
+ #second register
+ div2i t4, t1, "env.dataSize * 8"
+ div2 t4, t1, t4
+
+ #Loop until we're out of bits to shift in
+divLoopTop:
+ div2 t4, t1, t4
+ div2 t4, t1, t4
+ div2 t4, t1, t4
+ div2 t4, t1, t4, flags=(EZF,)
+ bri t0, label("divLoopTop"), flags=(nCEZF,)
+
+ #Unload the answer
+ divq t5
+ divr t6
+
+ # Fix up signs. The sign of the dividend is still lying around in ECF.
+ # The sign of the remainder, ah, is the same as the dividend. The sign
+ # of the quotient is negated if the signs of the divisor and dividend
+ # were different.
+
+ # Negate the remainder
+ sub t4, t0, t6
+ # If the dividend was negitive, put the negated remainder in rdx.
+ mov rdx, rdx, t4, (CECF,)
+ # Otherwise put the regular remainder in rdx.
+ mov rdx, rdx, t6, (nCECF,)
+
+ # Negate the quotient.
+ sub t4, t0, t5
+ # If the dividend was negative, start using the negated quotient
+ mov t5, t5, t4, (CECF,)
+
+ # Check the sign of the divisor
+ slli t0, t3, 1, flags=(ECF,)
+
+ # Negate the (possibly already negated) quotient
+ sub t4, t0, t5
+ # If the divisor was negative, put the negated quotient in rax.
+ mov rax, rax, t4, (CECF,)
+ # Otherwise put the one that wasn't negated (at least here) in rax.
+ mov rax, rax, t5, (nCECF,)
};
'''
-#let {{
-# class IDIV(Inst):
-# "GenFault ${new UnimpInstFault}"
-#}};
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)'
diff --git a/src/arch/x86/isa/operands.isa b/src/arch/x86/isa/operands.isa
index fae1aa5ca..7b0427b44 100644
--- a/src/arch/x86/isa/operands.isa
+++ b/src/arch/x86/isa/operands.isa
@@ -105,7 +105,8 @@ def operands {{
'ProdHi': ('IntReg', 'uqw', 'INTREG_IMPLICIT(1)', 'IsInteger', 8),
'Quotient': ('IntReg', 'uqw', 'INTREG_IMPLICIT(2)', 'IsInteger', 9),
'Remainder': ('IntReg', 'uqw', 'INTREG_IMPLICIT(3)', 'IsInteger', 10),
- 'rax': ('IntReg', 'uqw', '(INTREG_RAX)', 'IsInteger', 11),
+ 'Divisor': ('IntReg', 'uqw', 'INTREG_IMPLICIT(4)', 'IsInteger', 11),
+ 'rax': ('IntReg', 'uqw', '(INTREG_RAX)', 'IsInteger', 12),
'FpSrcReg1': ('FloatReg', 'df', 'src1', 'IsFloating', 20),
'FpSrcReg2': ('FloatReg', 'df', 'src2', 'IsFloating', 21),
'FpDestReg': ('FloatReg', 'df', 'dest', 'IsFloating', 22),
diff --git a/src/arch/x86/x86_traits.hh b/src/arch/x86/x86_traits.hh
index 9ea8eaef4..33ec13372 100644
--- a/src/arch/x86/x86_traits.hh
+++ b/src/arch/x86/x86_traits.hh
@@ -64,11 +64,12 @@ namespace X86ISA
const int NumPseudoIntRegs = 1;
//1. The condition code bits of the rflags register.
- const int NumImplicitIntRegs = 4;
+ const int NumImplicitIntRegs = 5;
//1. The lower part of the result of multiplication.
//2. The upper part of the result of multiplication.
//3. The quotient from division
//4. The remainder from division
+ //5. The divisor for division
const int NumMMXRegs = 8;
const int NumXMMRegs = 16;