Skip to content

Commit

Permalink
Fix DMULU and add DMUHU (#798)
Browse files Browse the repository at this point in the history
* 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.
  • Loading branch information
lupino3 authored Oct 11, 2023
1 parent 25f5f3b commit 897f559
Show file tree
Hide file tree
Showing 15 changed files with 465 additions and 138 deletions.
11 changes: 8 additions & 3 deletions docs/user/en/src/instructions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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`

Expand Down
10 changes: 7 additions & 3 deletions docs/user/it/src/instructions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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`

Expand Down
87 changes: 87 additions & 0 deletions src/main/java/org/edumips64/core/is/DMUHU.java
Original file line number Diff line number Diff line change
@@ -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;

/**
* <pre>
* 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);
}
}
70 changes: 67 additions & 3 deletions src/main/java/org/edumips64/core/is/DMULU.java
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
Expand All @@ -25,4 +28,65 @@
*/
package org.edumips64.core.is;

class DMULU extends DMULTU {}
import java.math.BigInteger;

import org.edumips64.core.Converter;
import org.edumips64.core.IrregularStringOfBitsException;

/**
* <pre>
* 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);
}
}
3 changes: 3 additions & 0 deletions src/main/java/org/edumips64/core/is/InstructionBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/org/edumips64/core/parser/Parser.java
Original file line number Diff line number Diff line change
Expand Up @@ -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. */
Expand Down
45 changes: 45 additions & 0 deletions src/test/java/org/edumips64/BaseParsingTest.java
Original file line number Diff line number Diff line change
@@ -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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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());
Expand Down
6 changes: 6 additions & 0 deletions src/test/java/org/edumips64/EndToEndTests.java
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
Loading

0 comments on commit 897f559

Please sign in to comment.