diff --git a/Software/Assembler.java b/Software/Assembler.java new file mode 100644 index 0000000000000000000000000000000000000000..500102ca05d413a5275653d391c05f77ecad01c5 --- /dev/null +++ b/Software/Assembler.java @@ -0,0 +1,406 @@ +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; +import java.util.Scanner; + +public class Assembler { + + private static List <JumpAddress> jumpAddressList; + private static BufferedWriter writer; + + public static void main(String[] args) throws IOException { + + File source = new File(args[0]); + Scanner scannerOne = new Scanner(source); + + jumpAddressList = new ArrayList <JumpAddress> (); + + int position = 0; + int address = 0; + + // TODO : Don't allow the same label twice! + while(scannerOne.hasNextLine()) { + String noComment = scannerOne.nextLine().split("#")[0]; + String line[] = noComment.trim().split("\\s+|,\\s+"); + + if(line[0].equals("")) { + continue; + } else if(line[0].matches("\\w+:$")) { + String labelName = line[0].substring(0, line[0].length() - 1); + jumpAddressList.add(position, new JumpAddress(labelName, address * 2)); + position++; + } else { + address++; + } + } + + writer = new BufferedWriter(new FileWriter(args[1], false)); + Scanner scannerTwo = new Scanner(source); + + address = 0; + + while(scannerTwo.hasNextLine()) { + String noComment = scannerTwo.nextLine().split("#")[0]; + // alternative regular expression: "[\\s,]+" + String line[] = noComment.trim().split("\\s+|,\\s+"); + String mnemonic = line[0]; + + if(mnemonic.equals("")) { // empty line + continue; + } else if(mnemonic.matches("[A-Za-z]*:$")) { // line containing a label + continue; + } else { // line containing an instruction + switch(mnemonic) { + // ----------------------------------------------------- + // -- ALU-Operations ----------------------------------- + // ----------------------------------------------------- + case "MOV": + writeALUOp("00100000", line[1], line[2]); + address++; + break; + case "ADDU": + writeALUOp("00100001", line[1], line[2]); + address++; + break; + case "ADDC": + writeALUOp("00100010", line[1], line[2]); + address++; + break; + case "SUBU": + writeALUOp("00100011", line[1], line[2]); + address++; + break; + case "AND": + writeALUOp("00100100", line[1], line[2]); + address++; + break; + case "OR": + writeALUOp("00100101", line[1], line[2]); + address++; + break; + case "XOR": + writeALUOp("00100110", line[1], line[2]); + address++; + break; + case "NOT": + writeALUOp("00100111", line[1], "0000"); + address++; + break; + // ----------------------------------------------------- + // -- Shift-Operations --------------------------------- + // ----------------------------------------------------- + case "LSL": + writeShiftOp("00101000", line[1], line[2]); + address++; + break; + case "LSR": + writeShiftOp("00101001", line[1], line[2]); + address++; + break; + case "ASR": + writeShiftOp("00101010", line[1], line[2]); + address++; + break; + case "LSLC": + writeShiftOp("00101100", line[1], "0000"); + address++; + break; + case "LSRC": + writeShiftOp("00101101", line[1], "0000"); + address++; + break; + case "ASRC": + writeShiftOp("00101110", line[1], "0000"); + address++; + break; + // ----------------------------------------------------- + // -- Compare-Operations ------------------------------- + // ----------------------------------------------------- + case "CMPE": + writeCompOp("00110000", line[1], line[2]); + address++; + break; + case "CMPNE": + writeCompOp("00110001", line[1], line[2]); + address++; + break; + case "CMPGT": + writeCompOp("00110010", line[1], line[2]); + address++; + break; + case "CMPLT": + writeCompOp("00110011", line[1], line[2]); + address++; + break; + // ----------------------------------------------------- + // -- Immediate-Operations ----------------------------- + // ----------------------------------------------------- + case "MOVI": + writeImmOp("00110100", line[1], line[2]); + address++; + break; + case "ADDI": + writeImmOp("00110101", line[1], line[2]); + address++; + break; + case "SUBI": + writeImmOp("00110110", line[1], line[2]); + address++; + break; + case "ANDI": + writeImmOp("00110111", line[1], line[2]); + address++; + break; + case "LSLI": + writeImmOp("00111000", line[1], line[2]); + address++; + break; + case "LSRI": + writeImmOp("00111001", line[1], line[2]); + address++; + break; + case "BSETI": + writeImmOp("00111010", line[1], line[2]); + address++; + break; + case "BCLRI": + writeImmOp("00111011", line[1], line[2]); + address++; + break; + // ----------------------------------------------------- + // -- Memory-Operations -------------------------------- + // ----------------------------------------------------- + case "LDW": + writeMemOp("0100", line[1], line[2], line[3]); + address++; + break; + case "STW": + writeMemOp("0101", line[1], line[2], line[3]); + address++; + break; + // ----------------------------------------------------- + // -- Control-Flow-Operations -------------------------- + // ----------------------------------------------------- + case "BR": + writeControlFlowOp("1000", line[1], address); + address++; + break; + case "JSR": + writeControlFlowOp("1001", line[1], address); + address++; + break; + case "BT": + writeControlFlowOp("1010", line[1], address); + address++; + break; + case "BF": + writeControlFlowOp("1011", line[1], address); + address++; + break; + case "JMP": + writeJMPOp("1100", line[1]); + address++; + break; + // ----------------------------------------------------- + // -- Halt --------------------------------------------- + // ----------------------------------------------------- + case "HALT": + writeHALTOp("1111"); + address++; + break; + default: + // TODO: Throw exception, if no mnemonic matched! + } + } + } + writer.close(); + scannerTwo.close(); + scannerOne.close(); + } + + public static String regToBin(String register) { + String output; + + switch(register) { + case "R0": + output = "0000"; + break; + case "R1": + output = "0001"; + break; + case "R2": + output = "0010"; + break; + case "R3": + output = "0011"; + break; + case "R4": + output = "0100"; + break; + case "R5": + output = "0101"; + break; + case "R6": + output = "0110"; + break; + case "R7": + output = "0111"; + break; + case "R8": + output = "1000"; + break; + case "R9": + output = "1001"; + break; + case "R10": + output = "1010"; + break; + case "R11": + output = "1011"; + break; + case "R12": + output = "1100"; + break; + case "R13": + output = "1101"; + break; + case "R14": + output = "1110"; + break; + case "R15": + output = "1111"; + break; + default: + // TODO: Throw exception, if no register matched! + output = "0000"; + } + + return output; + } + + public static String hexToBin(String s) { + String hex = ""; + + if(s.startsWith("0x")) { + hex = s.substring(2, s.length()); + } + if(s.startsWith("$")) { + hex = s.substring(1, s.length()); + } + + String bitstring = new BigInteger(hex, 16).toString(2); + StringBuffer extended = new StringBuffer(bitstring); + + for(int i = bitstring.length(); i < 4; i++) { + extended.insert(0, "0"); + } + + return extended.toString(); + } + + public static void writeALUOp(String opCo, String rX, String rY) throws IOException { + writer.append(opCo); + writer.append(regToBin(rY)); + writer.append(regToBin(rX)); + writer.append("\n"); + } + + public static void writeShiftOp(String opCo, String rX, String rY) throws IOException { + writer.append(opCo); + writer.append(regToBin(rY)); + writer.append(regToBin(rX)); + writer.append("\n"); + } + + public static void writeCompOp(String opCo, String rX, String rY) throws IOException { + writer.append(opCo); + writer.append(regToBin(rY)); + writer.append(regToBin(rX)); + writer.append("\n"); + } + + public static void writeImmOp(String opCo, String rX, String imm) throws IOException { + writer.append(opCo); + writer.append(hexToBin(imm)); + writer.append(regToBin(rX)); + writer.append("\n"); + } + + public static void writeMemOp(String opCo, String rX, String rY, String offsetHex) throws IOException { + String offsetBin = hexToBin(offsetHex); + int offsetInt = Integer.parseInt(offsetBin, 2); + + if((offsetInt % 2) == 1 ) { + // TODO: Throw exception, if invalid address is addressed! + } + + if(offsetInt > 30) { + // TODO: Throw exception, if invalid address is addressed! + } + + String offset = offsetBin.substring(0, offsetBin.length()-1); + StringBuffer extended = new StringBuffer(offset); + + for(int i = offset.length(); i < 4; i++) { + extended.insert(0, "0"); + } + + String jumpAddressBinFixedLength = extended.toString(); + + writer.append(opCo); + writer.append(jumpAddressBinFixedLength); + writer.append(regToBin(rY)); + writer.append(regToBin(rX)); + writer.append("\n"); + } + + // TODO Throw exception, if label is not in jumpAddressList! + public static void writeControlFlowOp(String opCo, String label, int address) throws IOException { + // PC = PC + 2 + imm12 + int byteAddress = 2 * (address + 1); + + int labelAddress = 0; + for(int i = 0; i < jumpAddressList.size(); i++) { + if(jumpAddressList.get(i).getLabel().equals(label)) { + labelAddress = jumpAddressList.get(i).getAddress(); + break; + } + } + + int jumpAddressInt = labelAddress - byteAddress; + String jumpAddressBin = Integer.toBinaryString(jumpAddressInt); + String jumpAddressBinFixedLength; + + if(jumpAddressInt < 0) { + jumpAddressBinFixedLength = jumpAddressBin.substring(jumpAddressBin.length()-12, jumpAddressBin.length()); + } else { + StringBuffer extended = new StringBuffer(jumpAddressBin); + for(int i = jumpAddressBin.length(); i < 12; i++) { + extended.insert(0, "0"); + } + jumpAddressBinFixedLength = extended.toString(); + } + + writer.append(opCo); + writer.append(jumpAddressBinFixedLength); + writer.append("\n"); + } + + public static void writeJMPOp(String opCo, String rX) throws IOException { + writer.append(opCo); + writer.append("00000000"); + writer.append(regToBin(rX)); + writer.append("\n"); + } + + public static void writeHALTOp(String opCo) throws IOException { + writer.append(opCo); + writer.append("000000000000"); + writer.append("\n"); + } +} + \ No newline at end of file