From 897f559ebda971760aae0bcad949b3cf38847b02 Mon Sep 17 00:00:00 2001 From: Andrea Spadaccini Date: Wed, 11 Oct 2023 14:38:04 +0200 Subject: [PATCH] Fix DMULU and add DMUHU (#798) * test: factor out a test harness with parsing support * refactor: make MemoryTest use BaseWithInstructionBuilderTest * fix: properly implement DMULU In Release 6, the MIPS64 ISA introduced the DMULU instruction, which previously was used as an alias to DMULTU. This commit properly implements DMULU. Fixes #779. * feat: add DMUHU * doc: fix DMULU and add DMUHU * fix: fix Codacy errors Cannot fix the ones complaining about the EX method not conforming to naming conventions. --- docs/user/en/src/instructions.rst | 11 +- docs/user/it/src/instructions.rst | 10 +- .../java/org/edumips64/core/is/DMUHU.java | 87 ++++++++++ .../java/org/edumips64/core/is/DMULU.java | 70 +++++++- .../edumips64/core/is/InstructionBuilder.java | 3 + .../org/edumips64/core/parser/Parser.java | 2 +- .../java/org/edumips64/BaseParsingTest.java | 45 +++++ .../BaseWithInstructionBuilderTest.java | 5 +- .../java/org/edumips64/EndToEndTests.java | 6 + .../java/org/edumips64/core/MemoryTest.java | 48 ++---- .../java/org/edumips64/core/ParserTest.java | 163 ++++++++---------- .../java/org/edumips64/core/is/DMUHUTest.java | 42 +++++ .../java/org/edumips64/core/is/DMULUTest.java | 42 +++++ src/test/resources/dmulu-dmuhu.s | 66 +++++++ src/test/resources/dmulu-simple-test.s | 3 +- 15 files changed, 465 insertions(+), 138 deletions(-) create mode 100644 src/main/java/org/edumips64/core/is/DMUHU.java create mode 100644 src/test/java/org/edumips64/BaseParsingTest.java create mode 100644 src/test/java/org/edumips64/core/is/DMUHUTest.java create mode 100644 src/test/java/org/edumips64/core/is/DMULUTest.java create mode 100644 src/test/resources/dmulu-dmuhu.s diff --git a/docs/user/en/src/instructions.rst b/docs/user/en/src/instructions.rst index f968296b1..62ea5a681 100644 --- a/docs/user/en/src/instructions.rst +++ b/docs/user/en/src/instructions.rst @@ -86,18 +86,23 @@ Here's the list of R-Type ALU Instructions. as unsigned values and putting the 32-bits quotient in LO and the 32-bits remainder in HI. +* `DMUHU rd, rs, rt` + + Executes the multiplication between 64-bits registers rs and rt, + considering them as unsigned values and putting the high-order 64-bits + doubleword of the result into register rd. + * `DMULT rs, rt` Executes the multiplication between 64-bits registers rs and rt, putting the low-order 64-bits doubleword of the result into special register LO and the high-order 64-bits doubleword of the result into special register HI. -* `DMULU rs, rt` +* `DMULU rd, rs, rt` Executes the multiplication between 64-bits registers rs and rt, considering them as unsigned values and putting the low-order 64-bits - doubleword of the result into special register LO and the high-order - 64-bits doubleword of the result into special register HI. + doubleword of the result into register rd. * `DMULTU rs, rt` diff --git a/docs/user/it/src/instructions.rst b/docs/user/it/src/instructions.rst index 9f516b391..58d91b099 100644 --- a/docs/user/it/src/instructions.rst +++ b/docs/user/it/src/instructions.rst @@ -90,6 +90,11 @@ Ecco la lista delle istruzioni ALU di tipo R. valori senza segno e pone i 32-bit del quoziente in LO ed i 32-bit del resto in HI. +* `DMUHU rd, rs, rt` + + Esegue il prodotto tra i registri a 64-bit rs ed rt, considerandoli come + valori senza segno e ponendo i 64 bit alti del risultato nel registro rd. + * `DMULT rs, rt` Esegue il prodotto tra i registri a 64-bit rs ed rt, ponendo i 64 bit bassi @@ -102,11 +107,10 @@ Ecco la lista delle istruzioni ALU di tipo R. valori senza segno e ponendo i 64 bit bassi del risultato nel registro speciale LO e i 64 bit alti del risultato nel registro speciale HI. -* `DMULU rs, rt` +* `DMULU rd, rs, rt` Esegue il prodotto tra i registri a 64-bit rs ed rt, considerandoli come - valori senza segno e ponendo i 64 bit bassi del risultato nel registro - speciale LO e i 64 bit alti del risultato nel registro speciale HI. + valori senza segno e ponendo i 64 bit bassi del risultato nel registro rd. * `DSLL rd, rt, sa` diff --git a/src/main/java/org/edumips64/core/is/DMUHU.java b/src/main/java/org/edumips64/core/is/DMUHU.java new file mode 100644 index 000000000..9cfd0f078 --- /dev/null +++ b/src/main/java/org/edumips64/core/is/DMUHU.java @@ -0,0 +1,87 @@ +/* + * DMUHU.java + * + * Instruction DMUHU of the MIPS64 Instruction Set + * (c) 2023 EduMips64 project + * + * DMUHU: Multiply Doublewords Unsigned, High Doubleword + * + * Performs an unsigned 64-bit integer multiplication, + * and places the high 64 bits of the result in the destination +register. + * This file is part of the EduMIPS64 project, and is released under the GNU + * General Public License. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +package org.edumips64.core.is; + +import java.math.BigInteger; + +import org.edumips64.core.Converter; +import org.edumips64.core.IrregularStringOfBitsException; + +/** + *
+ *      Syntax: DMUHU rd,rs,rt
+ * Description: rd <- hi_doubleword(rs * rt)
+ *              Multiply 64-bit unsigned integers
+ *              The 64-bit doubleword value in GPR rt is multiplied by the 64-bit
+ *              value in GPR rs, and the upper 64 bits of the 128-bit result
+ */
+class DMUHU extends ALU_RType {
+    // See explanation in DMULU.
+    private final String OPCODE_VALUE = "00011" + "011101";
+
+    DMUHU() {
+        super.OPCODE_VALUE = OPCODE_VALUE;
+        name = "DMUHU";
+    }
+
+    public void EX() throws IrregularStringOfBitsException, IntegerOverflowException, TwosComplementSumException {
+        // Getting operands from temporary registers.
+        BigInteger rs = new BigInteger(TR[RS_FIELD].getHexString(), 16);
+        BigInteger rt = new BigInteger(TR[RT_FIELD].getHexString(), 16);
+
+        // Execute the multiplication.
+        BigInteger result = rs.multiply(rt);
+
+        // Convert result to a String of 128-bit
+        String tmp = result.toString(2);
+
+        // 0-pad up to 128 bit.
+        while (tmp.length() < 128) {
+            tmp = "0" + tmp;
+        }
+
+        // Get only the upper 64 bit.
+        String tmpHi = tmp.substring(0, 64);
+        TR[RD_FIELD].setBits(tmpHi, 0);
+
+        if (cpu.isEnableForwarding()) {
+          doWB();
+        }
+    }
+
+    public void pack() throws IrregularStringOfBitsException {
+        // "SPECIAL" value of 000000.
+        repr.setBits("000000", 0);
+        repr.setBits(Converter.intToBin(RS_FIELD_LENGTH, params.get(RS_FIELD)), RS_FIELD_INIT);
+        repr.setBits(Converter.intToBin(RT_FIELD_LENGTH, params.get(RT_FIELD)), RT_FIELD_INIT);
+        repr.setBits(Converter.intToBin(RD_FIELD_LENGTH, params.get(RD_FIELD)), RD_FIELD_INIT);
+        // Opcode and special opcode, at the end.
+        repr.setBits(OPCODE_VALUE, 6 + RT_FIELD_LENGTH + RS_FIELD_LENGTH + RD_FIELD_LENGTH);
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/org/edumips64/core/is/DMULU.java b/src/main/java/org/edumips64/core/is/DMULU.java
index 5f600ce44..a07fd21d3 100644
--- a/src/main/java/org/edumips64/core/is/DMULU.java
+++ b/src/main/java/org/edumips64/core/is/DMULU.java
@@ -2,10 +2,13 @@
  * DMULU.java
  *
  * Instruction DMULU of the MIPS64 Instruction Set
- * (c) 2019 EduMips64 project
+ * (c) 2023 EduMips64 project
  * 
- * Alias for DMULTU, used by WinMIPS64.
+ * DMULU: Multiply Doublewords Unsigned, Low Doubleword
  *
+ * Performs an unsigned 64-bit integer multiplication,
+ * and places the low 64 bits of the result in the destination
+register.
  * This file is part of the EduMIPS64 project, and is released under the GNU
  * General Public License.
  *
@@ -25,4 +28,65 @@
  */
 package org.edumips64.core.is;
 
-class DMULU extends DMULTU {}
\ No newline at end of file
+import java.math.BigInteger;
+
+import org.edumips64.core.Converter;
+import org.edumips64.core.IrregularStringOfBitsException;
+
+/**
+ * 
+ *      Syntax: DMULU rd,rs,rt
+ * Description: rd <- lo_doubleword(rs * rt)
+ *              Multiply 64-bit unsigned integers
+ *              The 64-bit doubleword value in GPR rt is multiplied by the 64-bit
+ *              value in GPR rs, and the lower 64 bits of the 128-bit result
+ */
+class DMULU extends ALU_RType {
+    // Note: there are 2 fields at the end of the DMULU representation:
+    //              the opcode: 00010
+    //   the special opcode 35: 011101
+    // The combination of both fields is necessary for some multiplication
+    // instructions, and is present in DMULU as well.
+    // For simplicity, we bundle them together in a single field.
+    private final String OPCODE_VALUE = "00010" + "011101";
+
+    DMULU() {
+        super.OPCODE_VALUE = OPCODE_VALUE;
+        name = "DMULU";
+    }
+
+    public void EX() throws IrregularStringOfBitsException, IntegerOverflowException, TwosComplementSumException {
+        // Getting operands from temporary registers.
+        BigInteger rs = new BigInteger(TR[RS_FIELD].getHexString(), 16);
+        BigInteger rt = new BigInteger(TR[RT_FIELD].getHexString(), 16);
+
+        // Execute the multiplication.
+        BigInteger result = rs.multiply(rt);
+
+        // Convert result to a String of 128-bit
+        String tmp = result.toString(2);
+
+        // 0-pad up to 128 bit.
+        while (tmp.length() < 128) {
+            tmp = "0" + tmp;
+        }
+
+        // Get only the lower 64 bit.
+        String tmpLo = tmp.substring(64);
+        TR[RD_FIELD].setBits(tmpLo, 0);
+
+        if (cpu.isEnableForwarding()) {
+          doWB();
+        }
+    }
+
+    public void pack() throws IrregularStringOfBitsException {
+        // "SPECIAL" value of 000000.
+        repr.setBits("000000", 0);
+        repr.setBits(Converter.intToBin(RS_FIELD_LENGTH, params.get(RS_FIELD)), RS_FIELD_INIT);
+        repr.setBits(Converter.intToBin(RT_FIELD_LENGTH, params.get(RT_FIELD)), RT_FIELD_INIT);
+        repr.setBits(Converter.intToBin(RD_FIELD_LENGTH, params.get(RD_FIELD)), RD_FIELD_INIT);
+        // Opcode and special opcode, at the end.
+        repr.setBits(OPCODE_VALUE, 6 + RT_FIELD_LENGTH + RS_FIELD_LENGTH + RD_FIELD_LENGTH);
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/org/edumips64/core/is/InstructionBuilder.java b/src/main/java/org/edumips64/core/is/InstructionBuilder.java
index 334de75c1..18333aefc 100644
--- a/src/main/java/org/edumips64/core/is/InstructionBuilder.java
+++ b/src/main/java/org/edumips64/core/is/InstructionBuilder.java
@@ -146,6 +146,9 @@ public Instruction buildInstruction(String instructionName, ParsedInstructionMet
       case "DDIVU":
         instruction = new DDIVU();
         break;
+      case "DMUHU":
+        instruction = new DMUHU();
+        break;
       case "DMULT":
         instruction = new DMULT();
         break;
diff --git a/src/main/java/org/edumips64/core/parser/Parser.java b/src/main/java/org/edumips64/core/parser/Parser.java
index f7d8a0882..2e90d4e17 100644
--- a/src/main/java/org/edumips64/core/parser/Parser.java
+++ b/src/main/java/org/edumips64/core/parser/Parser.java
@@ -76,7 +76,7 @@ public class Parser {
 
   private enum AliasRegister
   {zero, at, v0, v1, a0, a1, a2, a3, t0, t1, t2, t3, t4, t5, t6, t7, s0, s1, s2, s3, s4, s5, s6, s7, t8, t9, k0, k1, gp, sp, fp, ra}
-  private static final String deprecateInstruction[] = {"BNEZ", "BEQZ", "HALT", "DADDUI", "DMULU", "L.D", "S.D"};
+  private static final String deprecateInstruction[] = {"BNEZ", "BEQZ", "HALT", "DADDUI", "L.D", "S.D"};
 
   private ParserMultiException errors;
   /** Base basePath to use for further #include directives. */
diff --git a/src/test/java/org/edumips64/BaseParsingTest.java b/src/test/java/org/edumips64/BaseParsingTest.java
new file mode 100644
index 000000000..213c034e6
--- /dev/null
+++ b/src/test/java/org/edumips64/BaseParsingTest.java
@@ -0,0 +1,45 @@
+package org.edumips64;
+
+import org.edumips64.core.CPU;
+import org.edumips64.core.Dinero;
+import org.edumips64.core.IOManager;
+import org.edumips64.core.Memory;
+import org.edumips64.core.SymbolTable;
+import org.edumips64.core.is.BUBBLE;
+import org.edumips64.core.is.InstructionBuilder;
+import org.edumips64.core.parser.Parser;
+import org.edumips64.utils.io.LocalFileUtils;
+import org.junit.Before;
+
+// Base class for tests that need to run the parser.
+public class BaseParsingTest extends BaseTest {
+  protected Parser parser;
+  protected Memory memory;
+  protected SymbolTable symTab;
+
+  @Before
+  public void setUp() throws Exception {
+    memory = new Memory();
+    CPU cpu = new CPU(memory, config, new BUBBLE());
+    symTab = new SymbolTable(memory);
+    IOManager iom = new IOManager(new LocalFileUtils(), memory);
+    Dinero dinero = new Dinero();
+    InstructionBuilder instructionBuilder = new InstructionBuilder(memory, iom, cpu, dinero, config);
+    parser = new Parser(new LocalFileUtils(), symTab, memory, instructionBuilder);
+  }
+  
+  /** Allows easier testing of .data section contents by adding the ".data" prefix and the "\n.code\nSYSCALL 0" suffix. */
+  protected void parseData(String dataSectionContents) throws Exception {
+    parser.doParsing(".data\n " + dataSectionContents + "\n.code\nSYSCALL 0");
+  }
+
+  /** Allows easier testing of .code section contents by adding the ".code" prefix and the "\nSYSCALL 0" suffix. */
+  protected void parseCode(String codeSectionContents) throws Exception {
+    parser.doParsing(".code\n " + codeSectionContents + "\nSYSCALL 0");
+  }
+
+  /** Parse a double value */
+  protected void parseDouble(String doubleValue) throws Exception {
+    parseData(".double " + doubleValue);
+  }
+}
\ No newline at end of file
diff --git a/src/test/java/org/edumips64/BaseWithInstructionBuilderTest.java b/src/test/java/org/edumips64/BaseWithInstructionBuilderTest.java
index 48837352d..899bbff89 100644
--- a/src/test/java/org/edumips64/BaseWithInstructionBuilderTest.java
+++ b/src/test/java/org/edumips64/BaseWithInstructionBuilderTest.java
@@ -34,6 +34,8 @@
 import org.edumips64.utils.io.LocalFileUtils;
 import org.edumips64.utils.io.StringWriter;
 
+import org.junit.Before;
+
 public class BaseWithInstructionBuilderTest extends BaseTest {
   protected CPU cpu;
   protected SymbolTable symTab;
@@ -42,7 +44,8 @@ public class BaseWithInstructionBuilderTest extends BaseTest {
   protected Memory memory;
   protected InstructionBuilder instructionBuilder;
   protected FileUtils lfu;
-
+  
+  @Before
   public void testSetup() {
     memory = new Memory();
     cpu = new CPU(memory, config, new BUBBLE());
diff --git a/src/test/java/org/edumips64/EndToEndTests.java b/src/test/java/org/edumips64/EndToEndTests.java
index 94af668e9..889837d62 100644
--- a/src/test/java/org/edumips64/EndToEndTests.java
+++ b/src/test/java/org/edumips64/EndToEndTests.java
@@ -716,6 +716,12 @@ public void testDmultu() throws Exception {
     runMipsTest("dmultu.s");
   }
 
+    /* Test for instructions DMULU and DMUHU */
+  @Test(timeout=2000)
+  public void testDmuluDmuhu() throws Exception {
+    runMipsTest("dmulu-dmuhu.s");
+  }
+
   /* Test for instruction DSLLV */
   @Test(timeout=2000)
   public void testDsllv() throws Exception {
diff --git a/src/test/java/org/edumips64/core/MemoryTest.java b/src/test/java/org/edumips64/core/MemoryTest.java
index c1ae57592..f20407902 100644
--- a/src/test/java/org/edumips64/core/MemoryTest.java
+++ b/src/test/java/org/edumips64/core/MemoryTest.java
@@ -1,6 +1,6 @@
 package org.edumips64.core;
 
-import org.edumips64.BaseTest;
+import org.edumips64.BaseWithInstructionBuilderTest;
 import org.edumips64.core.is.BUBBLE;
 import org.edumips64.core.is.InstructionBuilder;
 import org.edumips64.utils.io.LocalFileUtils;
@@ -9,52 +9,40 @@
 
 import static org.junit.Assert.assertEquals;
 
-public class MemoryTest extends BaseTest {
-  private Memory m;
-  private InstructionBuilder instructionBuilder;
-
-  @Before
-  public void setUp() throws Exception {
-    m = new Memory();
-    CPU cpu = new CPU(m, config, new BUBBLE());
-    IOManager iom = new IOManager(new LocalFileUtils(), m);
-    Dinero dinero = new Dinero();
-    instructionBuilder = new InstructionBuilder(m, iom, cpu, dinero, config);
-  }
-
+public class MemoryTest extends BaseWithInstructionBuilderTest {
   /* Regression test for Issue #84 */
   @Test
   public void testInstructionCount() throws Exception {
     // Add 5 BUBBLE instructions.
     for (int i = 0; i < 5; ++i) {
-      m.addInstruction(new BUBBLE(), i*4);
+      memory.addInstruction(new BUBBLE(), i*4);
     }
     // Add 2 non-BUBBLE instructions.
-    m.addInstruction(instructionBuilder.buildInstruction("SYSCALL"), 24);
-    m.addInstruction(instructionBuilder.buildInstruction("SYSCALL"), 28);
+    memory.addInstruction(instructionBuilder.buildInstruction("SYSCALL"), 24);
+    memory.addInstruction(instructionBuilder.buildInstruction("SYSCALL"), 28);
 
     // Only non-bubble instructions should be counted.
-    assertEquals(2, m.getInstructionsNumber());
+    assertEquals(2, memory.getInstructionsNumber());
   }
 
   @Test
   public void testInstructionCountBetweenResets() throws Exception {
-    m.addInstruction(instructionBuilder.buildInstruction("SYSCALL"), 0);
-    m.addInstruction(instructionBuilder.buildInstruction("SYSCALL"), 4);
-    assertEquals(2, m.getInstructionsNumber());
+    memory.addInstruction(instructionBuilder.buildInstruction("SYSCALL"), 0);
+    memory.addInstruction(instructionBuilder.buildInstruction("SYSCALL"), 4);
+    assertEquals(2, memory.getInstructionsNumber());
 
-    m.reset();
-    m.addInstruction(instructionBuilder.buildInstruction("SYSCALL"), 0);
-    assertEquals(1, m.getInstructionsNumber());
+    memory.reset();
+    memory.addInstruction(instructionBuilder.buildInstruction("SYSCALL"), 0);
+    assertEquals(1, memory.getInstructionsNumber());
   }
 
   @Test
   public void testMultipleInsertsSameAddress() throws Exception {
-    m.addInstruction(instructionBuilder.buildInstruction("SYSCALL"), 0);
-    m.addInstruction(instructionBuilder.buildInstruction("SYSCALL"), 0);
-    m.addInstruction(instructionBuilder.buildInstruction("SYSCALL"), 0);
-    m.addInstruction(instructionBuilder.buildInstruction("SYSCALL"), 0);
-    m.addInstruction(instructionBuilder.buildInstruction("SYSCALL"), 0);
-    assertEquals(1, m.getInstructionsNumber());
+    memory.addInstruction(instructionBuilder.buildInstruction("SYSCALL"), 0);
+    memory.addInstruction(instructionBuilder.buildInstruction("SYSCALL"), 0);
+    memory.addInstruction(instructionBuilder.buildInstruction("SYSCALL"), 0);
+    memory.addInstruction(instructionBuilder.buildInstruction("SYSCALL"), 0);
+    memory.addInstruction(instructionBuilder.buildInstruction("SYSCALL"), 0);
+    assertEquals(1, memory.getInstructionsNumber());
   }
 }
\ No newline at end of file
diff --git a/src/test/java/org/edumips64/core/ParserTest.java b/src/test/java/org/edumips64/core/ParserTest.java
index 0703dd630..ec9f14832 100644
--- a/src/test/java/org/edumips64/core/ParserTest.java
+++ b/src/test/java/org/edumips64/core/ParserTest.java
@@ -1,6 +1,6 @@
 package org.edumips64.core;
 
-import org.edumips64.BaseTest;
+import org.edumips64.BaseParsingTest;
 import org.edumips64.core.is.BUBBLE;
 import org.edumips64.core.is.InstructionBuilder;
 import org.edumips64.core.is.InstructionInterface;
@@ -13,39 +13,12 @@
 
 import static org.junit.Assert.assertEquals;
 
-public class ParserTest extends BaseTest {
-  private Parser parser;
-  private Memory memory;
-
-  @Before
-  public void setUp() throws Exception {
-    memory = new Memory();
-    CPU cpu = new CPU(memory, config, new BUBBLE());
-    SymbolTable symTab = new SymbolTable(memory);
-    IOManager iom = new IOManager(new LocalFileUtils(), memory);
-    Dinero dinero = new Dinero();
-    InstructionBuilder instructionBuilder = new InstructionBuilder(memory, iom, cpu, dinero, config);
-    parser = new Parser(new LocalFileUtils(), symTab, memory, instructionBuilder);
-  }
-  /** Allows easier testing of .data section contents by adding the ".data" prefix and the "\n.code\nSYSCALL 0" suffix. */
-  private void ParseData(String dataSectionContents) throws Exception {
-    parser.doParsing(".data\n " + dataSectionContents + "\n.code\nSYSCALL 0");
-  }
-  /** Allows easier testing of .code section contents by adding the ".code" prefix and the "\nSYSCALL 0" suffix. */
-  private void ParseCode(String codeSectionContents) throws Exception {
-    parser.doParsing(".code\n " + codeSectionContents + "\nSYSCALL 0");
-  }
-
-  /** Parse a double value */
-  private void ParseDouble(String doubleValue) throws Exception {
-    ParseData(".double " + doubleValue);
-  }
-
+public class ParserTest extends BaseParsingTest {
   @Test
   public void EscapeSequencesTest() throws Exception {
     // Java has no raw srings, so all special characters need to be escaped twice.
     String expected = "\\\"\t\n\0";
-    ParseData(".ascii \"\\\\\\\"\\t\\n\\0\"");
+    parseData(".ascii \"\\\\\\\"\\t\\n\\0\"");
     MemoryElement el = memory.getCellByIndex(0);
     StringBuilder actual = new StringBuilder();
     for (int i = 0; i < 5; ++i) {
@@ -56,17 +29,17 @@ public void EscapeSequencesTest() throws Exception {
 
   @Test(expected = ParserMultiException.class)
   public void InvalidEscapeSequencesTest() throws Exception {
-    ParseData(".ascii \"\\x\"");
+    parseData(".ascii \"\\x\"");
   }
 
   @Test(expected = ParserMultiException.class)
   public void InvalidPlaceholder() throws Exception {
-    ParseData(".ascii \"%x\"");
+    parseData(".ascii \"%x\"");
   }
 
   @Test
   public void ParseHex() throws Exception {
-    ParseData(".word 0x10");
+    parseData(".word 0x10");
     MemoryElement el = memory.getCellByIndex(0);
     assertEquals(el.readByte(0), 16);
   }
@@ -75,60 +48,60 @@ public void ParseHex() throws Exception {
   public void Spaces() throws Exception {
     // The user should be able to reserve space in small and larger amounts, specifying the amount in hexadecimal
     // if they so desire.
-    ParseData(".space 0x10");
-    ParseData(".space 16");
-    ParseData(".space 8");
-    ParseData(".space 1");
+    parseData(".space 0x10");
+    parseData(".space 16");
+    parseData(".space 8");
+    parseData(".space 1");
   }
 
   @Test(expected = ParserMultiException.class)
   public void NoSpaces() throws Exception {
-    ParseData(".space");
+    parseData(".space");
   }
 
   @Test(expected = ParserMultiException.class)
   public void InvalidSpaces() throws Exception {
-    ParseData(".space yo");
+    parseData(".space yo");
   }
 
   @Test
   public void SpecialFPTest() throws Exception {
-    ParseDouble("POSITIVEINFINITY");  // +Inf
-    ParseDouble("NEGATIVEINFINITY");  // -Inf
-    ParseDouble("POSITIVEZERO");      // +0
-    ParseDouble("NEGATIVEZERO");      // -0
-    ParseDouble("SNAN");              // Signaling NaN
-    ParseDouble("QNAN");              // Quiet NaN
+    parseDouble("POSITIVEINFINITY");  // +Inf
+    parseDouble("NEGATIVEINFINITY");  // -Inf
+    parseDouble("POSITIVEZERO");      // +0
+    parseDouble("NEGATIVEZERO");      // -0
+    parseDouble("SNAN");              // Signaling NaN
+    parseDouble("QNAN");              // Quiet NaN
   }
 
   @Test
   public void FPNumbersTest() throws Exception {
-    ParseDouble("1.5");               // a positive number
-    ParseDouble("-1.5");              // a negative number
-    ParseDouble("1.7E308");           // a positive big number
-    ParseDouble("-1.7E308");          // a negative big number
-    ParseDouble("9.0E-324");          // a positive small number
-    ParseDouble("-9.0E-324");         // a negative small number
-    ParseDouble("-6.0E-324");         // a negative very small number
-    ParseDouble("6.0E-324");          // a positive very small number
+    parseDouble("1.5");               // a positive number
+    parseDouble("-1.5");              // a negative number
+    parseDouble("1.7E308");           // a positive big number
+    parseDouble("-1.7E308");          // a negative big number
+    parseDouble("9.0E-324");          // a positive small number
+    parseDouble("-9.0E-324");         // a negative small number
+    parseDouble("-6.0E-324");         // a negative very small number
+    parseDouble("6.0E-324");          // a positive very small number
   }
 
   @Test(expected = ParserMultiException.class)
   public void FPOverflowPositiveNumberTest() throws Exception {
     parser.getFCSR().setFPExceptions(FCSRRegister.FPExceptions.OVERFLOW, true);
-    ParseDouble("-1.8E308");
+    parseDouble("-1.8E308");
   }
 
   @Test(expected = ParserMultiException.class)
   public void FPOverflowNegativeNumberTest() throws Exception {
     parser.getFCSR().setFPExceptions(FCSRRegister.FPExceptions.OVERFLOW, true);
-    ParseDouble("4.95E324");
+    parseDouble("4.95E324");
   }
 
   @Test
   public void FPOverflowNoThrowOnDisabledExceptionsTest() throws Exception {
     parser.getFCSR().setFPExceptions(FCSRRegister.FPExceptions.OVERFLOW, false);
-    ParseDouble("4.95E324");
+    parseDouble("4.95E324");
   }
 
   @Test
@@ -161,58 +134,58 @@ public void ImmediateNotOutOfBoundsTest() throws Exception {
     // Test that all the values just before overflow are parsed correctly.
 
     // 16-bit signed immediate.
-    ParseCode("daddi r1, r0, 32767");
-    ParseCode("daddi r1, r0, -32768");
+    parseCode("daddi r1, r0, 32767");
+    parseCode("daddi r1, r0, -32768");
 
     // 5-bit unsigned immediate
-    ParseCode("sll r1, r0, 31");
-    ParseCode("sll r1, r0, 0");
+    parseCode("sll r1, r0, 31");
+    parseCode("sll r1, r0, 0");
 
     // 3-bit unsigned immediate
-    ParseCode("movf.d f1, f2, 7");
-    ParseCode("movf.d f3, f4, 0");
+    parseCode("movf.d f1, f2, 7");
+    parseCode("movf.d f3, f4, 0");
   }
 
   @Test
   public void ImmediateCanStartWithHashTest() throws Exception {
     // 16-bit signed immediate.
-    ParseCode("daddi r1, r0, #10");
+    parseCode("daddi r1, r0, #10");
 
     // 5-bit unsigned immediate
-    ParseCode("sll r1, r0, #1");
+    parseCode("sll r1, r0, #1");
 
     // 3-bit unsigned immediate
-    ParseCode("movf.d f1, f2, #7");
+    parseCode("movf.d f1, f2, #7");
   }
 
   @Test(expected = ParserMultiException.class)
   public void Immediate16BitOverflow() throws Exception {
-    ParseCode("daddi r1, r0, 32768");
+    parseCode("daddi r1, r0, 32768");
   }
 
   @Test(expected = ParserMultiException.class)
   public void Immediate16BitUnderflow() throws Exception {
-    ParseCode("daddi r1, r0, -32769");
+    parseCode("daddi r1, r0, -32769");
   }
 
   @Test(expected = ParserMultiException.class)
   public void Immediate5BitOverflow() throws Exception {
-    ParseCode("sll r1, r0, 32");
+    parseCode("sll r1, r0, 32");
   }
 
   @Test(expected = ParserMultiException.class)
   public void Immediate5BitUnderflow() throws Exception {
-    ParseCode("sll r1, r0, -1");
+    parseCode("sll r1, r0, -1");
   }
 
   @Test(expected = ParserMultiException.class)
   public void Immediate3BitOverflow() throws Exception {
-    ParseCode("movf.d f1, f2, 8");
+    parseCode("movf.d f1, f2, 8");
   }
 
   @Test(expected = ParserMultiException.class)
   public void Immediate3BitUnderflow() throws Exception {
-    ParseCode("movf.d f3, f4, -1");
+    parseCode("movf.d f3, f4, -1");
   }
 
   /** Regression test for issue #95 */
@@ -225,75 +198,75 @@ public void CRLFParsingTest() throws Exception {
   @Test
   public void MemoryNotOutOfBoundsTest() throws Exception {
     // Test that all the values just before overflow are parsed correctly.
-    ParseData(".byte -128");
-    ParseData(".byte 127");
-    ParseData(".word16 -32768");
-    ParseData(".word16 32767");
-    ParseData(".word32 -2147483648");
-    ParseData(".word32 2147483647");
+    parseData(".byte -128");
+    parseData(".byte 127");
+    parseData(".word16 -32768");
+    parseData(".word16 32767");
+    parseData(".word32 -2147483648");
+    parseData(".word32 2147483647");
 
-    ParseData(".word -9223372036854775808");
-    ParseData(".word 9223372036854775807");
-    ParseData(".word64 -9223372036854775808");
-    ParseData(".word64 9223372036854775807");
+    parseData(".word -9223372036854775808");
+    parseData(".word 9223372036854775807");
+    parseData(".word64 -9223372036854775808");
+    parseData(".word64 9223372036854775807");
   }
 
   @Test(expected = ParserMultiException.class)
   public void OutOfBoundsByteTest() throws Exception {
-    ParseData(".byte 128");
+    parseData(".byte 128");
   }
 
   @Test(expected = ParserMultiException.class)
   public void NegativeOutOfBoundsByteTest() throws Exception {
-    ParseData(".byte -129");
+    parseData(".byte -129");
   }
 
   @Test(expected = ParserMultiException.class)
   public void OutOfBoundsHalfWordTest() throws Exception {
-    ParseData(".word16 32768");
+    parseData(".word16 32768");
   }
 
   @Test(expected = ParserMultiException.class)
   public void NegativeOutOfBoundsHalfWordTest() throws Exception {
-    ParseData(".word16 -32769");
+    parseData(".word16 -32769");
   }
 
   @Test(expected = ParserMultiException.class)
   public void OutOfBoundsWordTest() throws Exception {
-    ParseData(".word32 2147483648");
+    parseData(".word32 2147483648");
   }
 
   @Test(expected = ParserMultiException.class)
   public void NegativeOutOfBoundsWordTest() throws Exception {
-    ParseData(".word32 -2147483649");
+    parseData(".word32 -2147483649");
   }
 
   @Test(expected = ParserMultiException.class)
   public void OutOfBoundsDoubleWordTest() throws Exception {
-    ParseData(".word 9223372036854775808");
+    parseData(".word 9223372036854775808");
   }
 
   @Test(expected = ParserMultiException.class)
   public void NegativeOutOfBoundsDoubleWordTest() throws Exception {
-    ParseData(".word -9223372036854775809");
+    parseData(".word -9223372036854775809");
   }
 
   /** Tests for #175 */
   @Test()
   public void LargeValuesTest() throws Exception {
-    ParseCode("LW r1, 32768(r0)");
-    ParseCode("LW r1, -32767(r0)");
-    ParseCode("SW r1, 32768(r0)");
-    ParseCode("SW r1, -32767(r0)");
+    parseCode("LW r1, 32768(r0)");
+    parseCode("LW r1, -32767(r0)");
+    parseCode("SW r1, 32768(r0)");
+    parseCode("SW r1, -32767(r0)");
   }
 
   @Test(expected = ParserMultiException.class)
   public void OffsetTooLargePositiveTest() throws Exception {
-    ParseCode("LW r1, 32769(r0)");
+    parseCode("LW r1, 32769(r0)");
   }
 
   @Test(expected = ParserMultiException.class)
   public void OffsetTooLargeNegativeTest() throws Exception {
-    ParseCode("LW r1, -32768(r0)");
+    parseCode("LW r1, -32768(r0)");
   }
 }
\ No newline at end of file
diff --git a/src/test/java/org/edumips64/core/is/DMUHUTest.java b/src/test/java/org/edumips64/core/is/DMUHUTest.java
new file mode 100644
index 000000000..aa748b2e1
--- /dev/null
+++ b/src/test/java/org/edumips64/core/is/DMUHUTest.java
@@ -0,0 +1,42 @@
+package org.edumips64.core.is;
+
+import static org.junit.Assert.assertEquals;
+
+import org.edumips64.BaseParsingTest;
+import org.junit.Test;
+
+public class DMUHUTest extends BaseParsingTest {
+    @Test
+    public void testCanParse() throws Exception {
+        parseCode("dmuhu r1, r2, r3");
+        // Will also include SYSCALL 0
+        assertEquals(2, memory.getInstructionsNumber());
+    }
+
+    @Test
+    public void testName() throws Exception {
+        parseCode("dmuhu r1, r2, r3");
+        var dmulu = memory.getInstruction(0);
+        assertEquals("DMUHU", dmulu.getName());
+    }
+
+    @Test
+    public void testRepr() throws Exception {
+        parseCode("dmuhu r1, r2, r3");
+        var dmulu = memory.getInstruction(0);       
+        // Check the DMULU representation, given the uncommon packing logic.
+        var repr = dmulu.getRepr().getBinString();
+        // SPECIAL = 000000
+        assertEquals("000000", repr.substring(0, 6));
+        // RS = 2 = 00010
+        assertEquals("00010", repr.substring(6, 11));
+        // RT = 3
+        assertEquals("00011", repr.substring(11, 16));
+        // RD = 1
+        assertEquals("00001", repr.substring(16, 21));
+        // Opcode = 00011
+        assertEquals("00011", repr.substring(21, 26));
+        // Special Opcode 35
+        assertEquals("011101", repr.substring(26, 32));
+    }
+}
diff --git a/src/test/java/org/edumips64/core/is/DMULUTest.java b/src/test/java/org/edumips64/core/is/DMULUTest.java
new file mode 100644
index 000000000..6c25eeb43
--- /dev/null
+++ b/src/test/java/org/edumips64/core/is/DMULUTest.java
@@ -0,0 +1,42 @@
+package org.edumips64.core.is;
+
+import static org.junit.Assert.assertEquals;
+
+import org.edumips64.BaseParsingTest;
+import org.junit.Test;
+
+public class DMULUTest extends BaseParsingTest {
+    @Test
+    public void testCanParse() throws Exception {
+        parseCode("dmulu r1, r2, r3");
+        // Will also include SYSCALL 0
+        assertEquals(2, memory.getInstructionsNumber());
+    }
+
+    @Test
+    public void testName() throws Exception {
+        parseCode("dmulu r1, r2, r3");
+        var dmulu = memory.getInstruction(0);
+        assertEquals("DMULU", dmulu.getName());
+    }
+
+    @Test
+    public void testRepr() throws Exception {
+        parseCode("dmulu r1, r2, r3");
+        var dmulu = memory.getInstruction(0);       
+        // Check the DMULU representation, given the uncommon packing logic.
+        var repr = dmulu.getRepr().getBinString();
+        // SPECIAL = 000000
+        assertEquals("000000", repr.substring(0, 6));
+        // RS = 2 = 00010
+        assertEquals("00010", repr.substring(6, 11));
+        // RT = 3
+        assertEquals("00011", repr.substring(11, 16));
+        // RD = 1
+        assertEquals("00001", repr.substring(16, 21));
+        // Opcode = 00010
+        assertEquals("00010", repr.substring(21, 26));
+        // Special Opcode 35
+        assertEquals("011101", repr.substring(26, 32));
+    }
+}
diff --git a/src/test/resources/dmulu-dmuhu.s b/src/test/resources/dmulu-dmuhu.s
new file mode 100644
index 000000000..a242fe46c
--- /dev/null
+++ b/src/test/resources/dmulu-dmuhu.s
@@ -0,0 +1,66 @@
+; dmultu.s - test file for EduMIPS64.
+;
+; Executes dmultu and tests 2^64-1 * 2^64-1, 2^63 * 2^63 = 2^126, 2^63 * 2^62 = 2^125
+; and (2^64-1)^2
+;
+; (c) 2020 Leopold Eckert and the EduMIPS64 team
+;
+; This file is part of the EduMIPS64 project, and is released under the GNU
+; General Public License.
+;
+; This program is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2 of the License, or
+; (at your option) any later version.
+;
+; This program is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with this program; if not, write to the Free Software
+; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+.data
+    .word64 0x8000000000000000 ; 2^63
+    .word64 0x4000000000000000 ;high part of 2^126, also 2^62
+    .word64 0x2000000000000000 ;high part of 2^125
+    .word64 0x7FFFFFFFFFFFFFFF 
+    .word64 0x3FFFFFFFFFFFFFFF ;high part of (2^63-1)^2
+
+.code
+    ;2^64-1 * 2^64-1
+    addi r1, r0, -1
+    dmulu r3, r1, r1
+    dmuhu r2, r1, r1
+    addi r4, r0, 1
+    addi r5, r0, -2
+    bne r2, r5, error
+    bne r3, r4, error
+    ;(2^63)^2
+    ld r1, 0(r0)
+    ld r2, 8(r0)
+    dmuhu r3, r1, r1
+    dmulu r4, r1, r1
+    bne r3, r2, error
+    bne r4, r0, error
+    ;2^63 * 2^62
+    dmuhu r3, r1, r2
+    dmulu r4, r1, r2
+    ld r5, 16(r0)
+    bne r5, r3, error
+    bne r4, r0, error
+    ;(2^63-1)^2
+    ld r1, 24(r0)
+    addi r2, r0, 1
+    ld r3, 32(r0)
+    dmulu r4, r1, r1
+    dmuhu r5, r1, r1
+    bne r2, r4, error
+    bne r3, r5, error
+    syscall 0
+
+error:
+    break
+    syscall 0
+    
diff --git a/src/test/resources/dmulu-simple-test.s b/src/test/resources/dmulu-simple-test.s
index ff30a7574..19de927a1 100644
--- a/src/test/resources/dmulu-simple-test.s
+++ b/src/test/resources/dmulu-simple-test.s
@@ -25,8 +25,7 @@
     ADDI    r1, r0, 2
     ADDI    r2, r0, 3
     ADDI    r10, r0, 6
-    DMULU   r1, r2
-    MFLO    r3
+    DMULU   r3, r1, r2
     BNE     r3, r10, error
     DMULTU  r1, r2
     MFLO    r4