HL Programming: Mini-Assembler in Java

  • Context: Engineering 
  • Thread starter Thread starter Margarita0076
  • Start date Start date
  • Tags Tags
    Java Programming
Click For Summary
SUMMARY

The forum discussion centers on developing a mini-Assembler in Java for a 32-bit MIPS processor. Key methods include makeR and makeI, which construct 32-bit integers from R-type and I-type instruction components, respectively. The assembler must handle a specific subset of MIPS instructions, including ADD, ADDI, AND, ANDI, BEQ, LW, SW, SRL, and SLL. The program accepts user input until the HALT command is issued, translating each line into MIPS machine code and calculating the total memory required for the program.

PREREQUISITES
  • Understanding of MIPS instruction set architecture (ISA)
  • Proficiency in Java programming, specifically with integer manipulation
  • Familiarity with binary representation and bit manipulation
  • Knowledge of assembly language concepts and R/I-type instruction formats
NEXT STEPS
  • Research MIPS instruction formats and how to encode them into binary
  • Learn about bit manipulation techniques in Java for constructing machine code
  • Explore Java's Scanner class for handling user input effectively
  • Investigate testing strategies for validating assembler functionality
USEFUL FOR

Students and developers interested in systems programming, particularly those learning about assembly language and MIPS architecture, as well as Java programmers looking to deepen their understanding of low-level programming concepts.

Margarita0076
Messages
5
Reaction score
0
Homework Statement
Assembler.java
Relevant Equations
Create a mini-Assembler for a 32-bit MIPS processor.
I already wrote the regToByte method, but I don't understand how to write the makeI and makeR methods correctly.

Create a mini-Assembler for a 32-bit MIPS processor; Program should accept input lines from the user until HALT is read. With each line, translate the line into MIPS machine code. Print the total memory space needed for the completed program.

Conditions:

The form for all assembly lines will be:

<code> <rd> <rs> <rt> (for codes ADD, AND);
<code> <rd> <rt> <shift_amount> (for codes SRL, SLL);
<code> <rt> <rs> <immediate> (for codes ADDI, ANDI);
BEQ <rs> <rt> <branch_address>;
LW <rt> immediate <rs>; SW <rt> immediate <rs>

Your Assembler should accept the following subset of the complete ISA:

Functions: ADD, ADDI, AND, ANDI, BEQ, LW, SW, SRL, SLL; Registers: $zero, $v0-1, $a0-3, $t0-9, $s0-7.

Immediates and shift amounts should be read in decimal. Branch addresses should be read as a decimal offset from PC+4 (positive or negative). That is, you don't need to do any address arithmetic, just use the immediate given.

Printing a 32-bit binary number can be done in Java with the following: System.out.println("***: " + String.format("%32s", Integer.toBinaryString(word)).replace(" ", "0"));

Mod note: Added code tags
Java:
import java.util.Scanner;

public class Assembler
{
   private static final boolean TEST_MODE = true;

   public static void main(String[] args)
   {
      int count = 0;

      if (TEST_MODE)
      {
         testCases();
      }
      else
      {
         System.out.println("Assembler - Your Name Here\n");

        [B] // Your code here[/B]
        
         System.out.println("\n*** Assembly complete. Program required " + count + " words of memory.");
      }
   }

   [B]private static int makeR(byte opcode, byte rs, byte rt, byte rd, byte shamt, byte funct)
   {[/B]
      int returnValue = 0;
     
      return returnValue;
   [B]}[/B]

  [B] private static int makeI(byte opcode, byte rs, byte rt, short immed)
   {[/B]
      int returnValue = 0;
     
      return returnValue;
   [B]}[/B]

  [B] private static byte regToByte(String r)
   {[/B]
      byte returnValue = 0;
      String upperCase = r.toUpperCase();

      switch(upperCase)
      {
         case "$AT":
            returnValue = 1;
            break;
         case "$ZERO":
            returnValue = 0;
            break;
         case "$V0":
            returnValue = 2;
            break;
         case "$V1":
            returnValue = 3;
            break;
         case "$A0":
            returnValue = 4;
            break;
         case "$A1":
            returnValue = 5;
            break;
         case "$A2":
            returnValue = 6;
            break;
         case "$A3":
            returnValue = 7;
            break;
         case "$T0":
            returnValue = 8;
            break;
         case "$T1":
            returnValue = 9;
            break;
         case "$T2":
            returnValue = 10;
            break;
         case "$T3":
            returnValue = 11;
            break;
         case "$T4":
            returnValue = 12;
            break;
         case "$T5":
            returnValue = 13;
            break;
         case "$T6":
            returnValue = 14;
            break;
         case "$T7":
            returnValue = 15;
            break;
         case "$T8":
            returnValue = 24;
            break;
         case "$T9":
            returnValue = 25;
            break;
         case "$S0":
            returnValue = 16;
            break;
         case "$S1":
            returnValue = 17;
            break;
         case "$S2":
            returnValue = 18;
            break;
         case "$S3":
            returnValue = 19;
            break;
         case "$S4":
            returnValue = 20;
            break;
         case "$S5":
            returnValue = 21;
            break;
         case "$S6":
            returnValue = 22;
            break;
         case "$S7":
            returnValue = 23;
            break;
      }
      return returnValue;
  [B] }

   /*************************************************************
    *
    *   Test Code below
    *   Do NOT modify
    *
    ************************************************************/[/B]
  
   private static void testCases()
   {
      if (test_regToByte())
         System.out.println("RegToByte working well\n");
      else
         System.out.println("RegToByte failed\n");

      if (test_makeR())
         System.out.println("makeR working well\n");
      else
         System.out.println("makeR failed\n");

      if (test_makeI())
         System.out.println("makeI working well\n");
      else
         System.out.println("makeI failed\n");
   }

   private static boolean test_regToByte()
   {
      boolean passedTest = true;
      String[] regs = { "$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" };

      for (int i = 0; i < regs.length; i++)
      {
         passedTest &= testReg(regs[ i], i);
      }

      return passedTest;
   };

   private static boolean testReg(String regName, int expValue)
   {
      if (regToByte(regName) != expValue) System.out.printf("Fail: regToByte(\"%s\") = %d, should be %d\n", regName, regToByte(regName), expValue);
      return regToByte(regName) == expValue;
   }

   private static boolean test_makeR()
   {
      boolean passedTest = true;
     
      int i = makeR((byte) 1, (byte) 1,(byte) 1,(byte) 1,(byte) 1,(byte) 1);
      if (i != 0b00000100001000010000100001000001)
      {
         System.out.println("Test: makeR(1,1,1,1,1,1) = " + Integer.toBinaryString(i) + " failed");
         passedTest = false;
      }

      i = makeR((byte) 63, (byte) 0,(byte) 31,(byte) 0,(byte) 31,(byte) 0);
      if (i != 0b11111100000111110000011111000000)
      {
         System.out.println("Test: makeR(63,0,31,0,31,0) = " + Integer.toBinaryString(i) + " failed");
         passedTest = false;
      }

      return passedTest;
   };

   private static boolean test_makeI()
   {
      boolean passedTest = true;
     
      int i = makeI((byte) 1, (byte) 1,(byte) 1,(short) 1);
      if (i != 0b00000100001000010000000000000001)
      {
         System.out.println("Test: makeI(1,1,1,1) = " + Integer.toBinaryString(i) + " failed");
         passedTest = false;
      }

      i = makeI((byte) 63, (byte) 0,(byte) 31,(short) 0);
      if (i != 0b11111100000111110000000000000000)
      {
         System.out.println("Test: makeI(63,0,31,0) = " + Integer.toBinaryString(i) + " failed");
         passedTest = false;
      }

      i = makeI((byte) 63, (byte) 0,(byte) 31,(short) -1);
      if (i != 0b11111100000111111111111111111111)
      {
         System.out.println("Test: makeI(63,0,31,-1) = " + Integer.toBinaryString(i) + " failed");
         passedTest = false;
      }

      return passedTest;
   };

}

Аssembler can read and translate one line at a time. It does not need to read in the whole file first. In the example below, I cut and pasted nine lines into the running program. So you main program can be something like:
Until HALT ---- Read a line ------ Translate it ------- Print it

Output:


Assembler - Your Name Here

*** Begin entering Assembler:

ADD $v0 $v1 $zero
AND $a0 $a1 $a2
ADDI $a3 $t4 -321
ANDI $t0 $t5 123
BEQ $s0 $t1 +517
LW $s1 -12 $t2
SW $s2 20 $t3
SRL $a2 $a3 3
SLL $a3 $a2 31
HALT
***: 00000000011000000001000000100000
***: 00000000101001100010000000100100
***: 00100001100001111111111010111111
***: 00110001101010000000000001111011
***: 00010010000010010000001000000101
***: 10001101010100011111111111110100
***: 10101101011100100000000000010100
***: 00000000000001110011000011000010
***: 00000000000001100011111111000000

*** Assembly complete. Program required 9 words of memory.
 
Last edited by a moderator:
Physics news on Phys.org
You need to post code in [code] tags. Otherwise the bbCode parser will see [i] and interpret it as an opening italic tag. This makes your code difficult for the reader to follow. [code] also preserves indentation, again making your code clearer.

Mod note: I added code tags
 
Last edited by a moderator:
Margarita0076 said:
Homework Statement:: Assembler.java
Relevant Equations:: Create a mini-Assembler for a 32-bit MIPS processor.

I already wrote the regToByte method, but I don't understand how to write the makeI and makeR methods correctly.
The first step would be to find out what makeI and makeR actually are supposed to do. If you can't write that down, I don't think you will get far with systems programming.
 
  • Like
Likes   Reactions: Mark44
This is my first time encountering bit encryption in Java. My methods:

int makeR(byte opcode, byte rs, byte rt, byte rd, byte shamt, byte funct)
Constructs a 32-bit integer from the component parts for an R-type instruction.

int makeI(byte opcode, byte rs, byte rt, short immed)
Constructs a 32-bit integer from the component parts for an I-type instruction.

byte regToByte(String r)
Converts a string representation of a register to its numeric equivalent. For example, if you pass in “$s5”, it will return 21. Why 21? Check you green sheet, bottom righthand corner).
 
Margarita0076 said:
int makeR(byte opcode, byte rs, byte rt, byte rd, byte shamt, byte funct)
Constructs a 32-bit integer from the component parts for an R-type instruction.
Please describe what needs to be done by the function, in such a way that someone can build it. Do you want the research, the design AND the implementation to be done by the internet?
Hint: Do you have any experience with bit fields? (don't use c bitfields, but you need to make them yourself)
 
Margarita0076 said:
This is my first time encountering bit encryption in Java.
In this case, it's encoding; not encryption ##-## an 'assembler' produces machine instructions ('opcode') from mnemonic (readily-memorizable) 'source code' instructions.
 
Do you understand the formats of the R-type and I-type instructions? If you're expected to write code that generates MIPS instructions, you need to have a clear understanding of how the instructions are laid out and what each field represents.
Margarita0076 said:
int makeR(byte opcode, byte rs, byte rt, byte rd, byte shamt, byte funct)
Constructs a 32-bit integer from the component parts for an R-type instruction.
An R-format instruction has 6 fields, listed from most significant bits to least significant:
opcode - 6 bits
Rs field - 5 bits - first source register
Rt field - 5 fits - second source register
Rd field - 5 bits - destination register
Shamt field - 5 bits - shift amount
Function code - 6 bits - the specific R-format instruction

Margarita0076 said:
int makeI(byte opcode, byte rs, byte rt, short immed)
Constructs a 32-bit integer from the component parts for an I-type instruction.
An I-format instruction has 4 fields, listed from most significant bits to least significant:
opcode - 6 bits
Rs field - 5 bits - first source register
Rt field - 5 fits - second source register (can be destination register for some instructions)
Immediate or offset field - 16 bits - Holds the immediate value for instructions such as addi, andi, etc. Holds the offset value for instructions such as lw, lb, sw, etc.
 
Last edited:
  • Like
Likes   Reactions: Margarita0076 and sysprog
@Margarita0076, are you still stuck? You've started three threads, but haven't returned to any of them to let us know if you have been successful.
 

Similar threads

  • · Replies 3 ·
Replies
3
Views
3K
  • · Replies 12 ·
Replies
12
Views
2K
  • · Replies 1 ·
Replies
1
Views
2K
  • · Replies 4 ·
Replies
4
Views
3K
  • · Replies 1 ·
Replies
1
Views
2K
  • · Replies 9 ·
Replies
9
Views
2K
  • · Replies 3 ·
Replies
3
Views
3K
  • · Replies 3 ·
Replies
3
Views
2K
  • · Replies 2 ·
Replies
2
Views
4K
  • · Replies 2 ·
Replies
2
Views
2K