diff --git a/Server/src/main/java/net/simon987/server/assembly/Assembler.java b/Server/src/main/java/net/simon987/server/assembly/Assembler.java index 2c8af1e..c5088f6 100755 --- a/Server/src/main/java/net/simon987/server/assembly/Assembler.java +++ b/Server/src/main/java/net/simon987/server/assembly/Assembler.java @@ -170,7 +170,7 @@ public class Assembler { } catch (IllegalArgumentException e) { throw new InvalidOperandException( "Invalid string operand \"" + string + "\": " + e.getMessage(), - currentLine); + currentLine); } out.write(string.getBytes(StandardCharsets.UTF_16BE)); @@ -219,7 +219,7 @@ public class Assembler { return bos.toByteArray(); } - + /** * Parse the DW instruction (Define word). Handles DUP operator * @@ -318,7 +318,7 @@ public class Assembler { /* the EQU pseudo instruction is equivalent to the #define compiler directive in C/C++ * usage: constant_name EQU * A constant treated the same way as a label. - */ + */ line = line.trim(); String[] tokens = line.split("\\s+"); @@ -362,7 +362,47 @@ public class Assembler { ByteArrayOutputStream out = new ByteArrayOutputStream(); //Pass 1: Get code origin - for (currentLine = 0; currentLine < lines.length; currentLine++) { + getCodeOrigin(lines, result); + //Pass 2: Save label names and location + saveLabelNamesAndLocation(lines, result); + //Pass 3: encode instructions + encodeInstructions(lines, result, out); + + + //If the code contains OffsetOverFlowException(s), don't bother writing the assembled bytes to memory + boolean writeToMemory = true; + for (Exception e : result.exceptions) { + if (e instanceof OffsetOverflowException) { + writeToMemory = false; + break; + } + } + + if (writeToMemory) { + result.bytes = out.toByteArray(); + } else { + result.bytes = new byte[0]; + LogManager.LOGGER.fine("Skipping writing assembled bytes to memory. (OffsetOverflowException)"); + } + + try { + out.close(); + } catch (IOException e) { + e.printStackTrace(); + } + + LogManager.LOGGER.info("Assembled " + result.bytes.length + " bytes (" + result.exceptions.size() + " errors)"); + for (AssemblyException e : result.exceptions) { + LogManager.LOGGER.severe(e.getMessage() + '@' + e.getLine()); + } + LogManager.LOGGER.info('\n' + Util.toHex(result.bytes)); + + return result; + + } + + private void getCodeOrigin(String[] lines, AssemblyResult result) { + for (int currentLine = 0; currentLine < lines.length; currentLine++) { try { checkForORGInstruction(lines[currentLine], result, currentLine); @@ -373,10 +413,11 @@ public class Assembler { //Ignore error } } + } - //Pass 2: Save label names and location + private void saveLabelNamesAndLocation(String[] lines, AssemblyResult result) { int currentOffset = 0; - for (currentLine = 0; currentLine < lines.length; currentLine++) { + for (int currentLine = 0; currentLine < lines.length; currentLine++) { try { checkForLabel(lines[currentLine], result, (char)currentOffset); @@ -394,11 +435,11 @@ public class Assembler { } } + } - - //Pass 3: encode instructions - currentOffset = 0; - for (currentLine = 0; currentLine < lines.length; currentLine++) { + private void encodeInstructions(String[] lines, AssemblyResult result, ByteArrayOutputStream out) { + int currentOffset = 0; + for (int currentLine = 0; currentLine < lines.length; currentLine++) { String line = lines[currentLine]; @@ -439,36 +480,6 @@ public class Assembler { ioE.printStackTrace(); } } - - //If the code contains OffsetOverFlowException(s), don't bother writing the assembled bytes to memory - boolean writeToMemory = true; - for (Exception e : result.exceptions) { - if (e instanceof OffsetOverflowException) { - writeToMemory = false; - } - } - - if (writeToMemory) { - result.bytes = out.toByteArray(); - } else { - result.bytes = new byte[0]; - LogManager.LOGGER.fine("Skipping writing assembled bytes to memory. (OffsetOverflowException)"); - } - - try { - out.close(); - } catch (IOException e) { - e.printStackTrace(); - } - - LogManager.LOGGER.info("Assembled " + result.bytes.length + " bytes (" + result.exceptions.size() + " errors)"); - for (AssemblyException e : result.exceptions) { - LogManager.LOGGER.severe(e.getMessage() + '@' + e.getLine()); - } - LogManager.LOGGER.info('\n' + Util.toHex(result.bytes)); - - return result; - } /** diff --git a/Server/src/main/java/net/simon987/server/assembly/CPU.java b/Server/src/main/java/net/simon987/server/assembly/CPU.java index 0cd4e96..1867e65 100755 --- a/Server/src/main/java/net/simon987/server/assembly/CPU.java +++ b/Server/src/main/java/net/simon987/server/assembly/CPU.java @@ -207,104 +207,11 @@ public class CPU implements MongoSerializable { ip++; instruction.execute(status); } else if (source == Operand.IMMEDIATE_VALUE) { - ip++; - int sourceValue = memory.get(ip); - - if (destination == 0) { - //Single operand - ip++; - instruction.execute(sourceValue, status); - } else if (destination == Operand.IMMEDIATE_VALUE) { - //Destination is an immediate value too - //this shouldn't happen - LogManager.LOGGER.severe("Trying to execute an instruction with 2" + - "immediate values as operands"); //todo remove debug info - - } else if (destination == Operand.IMMEDIATE_VALUE_MEM) { - //Destination is memory immediate - ip += 2; - instruction.execute(memory, memory.get(ip - 1), sourceValue, status); - } else if (destination <= registerSetSize) { - //Destination is a register - ip++; - instruction.execute(registerSet, destination, sourceValue, status); - - } else if (destination <= registerSetSize * 2) { - //Destination is [reg] - ip++; - instruction.execute(memory, registerSet.get(destination - registerSetSize), sourceValue, status); - } else { - //Assuming that destination is [reg + x] - ip += 2; - instruction.execute(memory, registerSet.get(destination - registerSetSize - registerSetSize) + memory.get(ip - 1), - sourceValue, status); - } - + executeImmediateValue(instruction, source, destination); } else if (source == Operand.IMMEDIATE_VALUE_MEM) { - //Source is [x] - ip++; - int sourceValue = memory.get(memory.get(ip)); - - if (destination == 0) { - //Single operand - ip++; - instruction.execute(memory, memory.get(ip - 1), status); - } else if (destination == Operand.IMMEDIATE_VALUE) { - //Destination is an immediate value - - //this shouldn't happen - LogManager.LOGGER.severe("Trying to execute an instruction with an" + - "immediate values as dst operand"); //todo remove debug info - } else if (destination == Operand.IMMEDIATE_VALUE_MEM) { - //Destination is memory immediate too - ip += 2; - instruction.execute(memory, memory.get(ip - 1), sourceValue, status); - } else if (destination <= registerSetSize) { - //Destination is a register - ip++; - instruction.execute(registerSet, destination, sourceValue, status); - } else if (destination <= registerSetSize * 2) { - //Destination is [reg] - ip++; - instruction.execute(memory, registerSet.get(destination - registerSetSize), sourceValue, status); - } else { - //Assuming that destination is [reg + x] - ip += 2; - instruction.execute(memory, registerSet.get(destination - registerSetSize - registerSetSize) + memory.get(ip - 1), sourceValue, status); - } - + executeImmediateValueMem(instruction, source, destination); } else if (source <= registerSetSize) { - //Source is a register - - if (destination == 0) { - //Single operand - ip++; - instruction.execute(registerSet, source, status); - - } else if (destination == Operand.IMMEDIATE_VALUE) { - //Destination is an immediate value - //this shouldn't happen - LogManager.LOGGER.severe("Trying to execute an instruction with an" + - "immediate values as dst operand"); //todo remove debug info - } else if (destination == Operand.IMMEDIATE_VALUE_MEM) { - //Destination is memory immediate - ip += 2; - instruction.execute(memory, memory.get(ip - 1), registerSet, source, status); - } else if (destination <= registerSetSize) { - //Destination is a register too - ip++; - instruction.execute(registerSet, destination, registerSet, source, status); - } else if (destination <= registerSetSize * 2) { - //Destination is [reg] - ip++; - instruction.execute(memory, registerSet.get(destination - registerSetSize), registerSet, source, status); - } else { - //Assuming that destination is [reg + x] - ip += 2; - instruction.execute(memory, registerSet.get(destination - registerSetSize - registerSetSize) + memory.get(ip - 1), - registerSet, source, status); - } - + executeSourceIsRegister(instruction, source, destination); } else if (source <= registerSetSize * 2) { //Source is [reg] if (destination == 0) { @@ -374,6 +281,107 @@ public class CPU implements MongoSerializable { } } + private void executeSourceIsRegister(Instruction instruction, int source, int destination) { + //Source is a register + if (destination == 0) { + //Single operand + ip++; + instruction.execute(registerSet, source, status); + + } else if (destination == Operand.IMMEDIATE_VALUE) { + //Destination is an immediate value + //this shouldn't happen + LogManager.LOGGER.severe("Trying to execute an instruction with an" + + "immediate values as dst operand"); //todo remove debug info + } else if (destination == Operand.IMMEDIATE_VALUE_MEM) { + //Destination is memory immediate + ip += 2; + instruction.execute(memory, memory.get(ip - 1), registerSet, source, status); + } else if (destination <= registerSetSize) { + //Destination is a register too + ip++; + instruction.execute(registerSet, destination, registerSet, source, status); + } else if (destination <= registerSetSize * 2) { + //Destination is [reg] + ip++; + instruction.execute(memory, registerSet.get(destination - registerSetSize), registerSet, source, status); + } else { + //Assuming that destination is [reg + x] + ip += 2; + instruction.execute(memory, registerSet.get(destination - registerSetSize - registerSetSize) + memory.get(ip - 1), + registerSet, source, status); + } + } + + private void executeImmediateValue(Instruction instruction, int source, int destination) { + ip++; + int sourceValue = memory.get(ip); + + if (destination == 0) { + //Single operand + ip++; + instruction.execute(sourceValue, status); + } else if (destination == Operand.IMMEDIATE_VALUE) { + //Destination is an immediate value too + //this shouldn't happen + LogManager.LOGGER.severe("Trying to execute an instruction with 2" + + "immediate values as operands"); //todo remove debug info + + } else if (destination == Operand.IMMEDIATE_VALUE_MEM) { + //Destination is memory immediate + ip += 2; + instruction.execute(memory, memory.get(ip - 1), sourceValue, status); + } else if (destination <= registerSetSize) { + //Destination is a register + ip++; + instruction.execute(registerSet, destination, sourceValue, status); + + } else if (destination <= registerSetSize * 2) { + //Destination is [reg] + ip++; + instruction.execute(memory, registerSet.get(destination - registerSetSize), sourceValue, status); + } else { + //Assuming that destination is [reg + x] + ip += 2; + instruction.execute(memory, registerSet.get(destination - registerSetSize - registerSetSize) + memory.get(ip - 1), + sourceValue, status); + } + } + + private void executeImmediateValueMem(Instruction instruction, int source, int destination) { + //Source is [x] + ip++; + int sourceValue = memory.get(memory.get(ip)); + + if (destination == 0) { + //Single operand + ip++; + instruction.execute(memory, memory.get(ip - 1), status); + } else if (destination == Operand.IMMEDIATE_VALUE) { + //Destination is an immediate value + + //this shouldn't happen + LogManager.LOGGER.severe("Trying to execute an instruction with an" + + "immediate values as dst operand"); //todo remove debug info + } else if (destination == Operand.IMMEDIATE_VALUE_MEM) { + //Destination is memory immediate too + ip += 2; + instruction.execute(memory, memory.get(ip - 1), sourceValue, status); + } else if (destination <= registerSetSize) { + //Destination is a register + ip++; + instruction.execute(registerSet, destination, sourceValue, status); + } else if (destination <= registerSetSize * 2) { + //Destination is [reg] + ip++; + instruction.execute(memory, registerSet.get(destination - registerSetSize), sourceValue, status); + } else { + //Assuming that destination is [reg + x] + ip += 2; + instruction.execute(memory, registerSet.get(destination - registerSetSize - registerSetSize) + memory.get(ip - 1), sourceValue, status); + } + } + @Override public Document mongoSerialise() { Document dbObject = new Document(); diff --git a/Server/src/test/java/net/simon987/server/assembly/OperandTest.java b/Server/src/test/java/net/simon987/server/assembly/OperandTest.java index 9f89eb6..e89de92 100644 --- a/Server/src/test/java/net/simon987/server/assembly/OperandTest.java +++ b/Server/src/test/java/net/simon987/server/assembly/OperandTest.java @@ -127,32 +127,27 @@ public class OperandTest { } //Invalid operands - try{ new Operand("aa", labels, registerSet, 0); } catch (InvalidOperandException e){ - //It's not a valid Operand; that's okey, just continue; VALID FOR ALL THE OTHER CATCH SENTENCES + try{ new Operand("aa", labels, registerSet, 0); } catch (InvalidOperandException ignored){ + //It's not a valid Operand; that's okay, just continue; VALID FOR ALL THE OTHER CATCH SENTENCES } - try{ new Operand("a1", labels, registerSet, 0); } catch (InvalidOperandException e){} - try{ new Operand("a_", labels, registerSet, 0); } catch (InvalidOperandException e){} - try{ new Operand("_a", labels, registerSet, 0); } catch (InvalidOperandException e){} - try{ new Operand("_1", labels, registerSet, 0); } catch (InvalidOperandException e){ } - try{ new Operand("S", labels, registerSet, 0); } catch (InvalidOperandException e){} - try{ new Operand("label1_", labels, registerSet, 0); } catch (InvalidOperandException e){} - try{ new Operand("+label1", labels, registerSet, 0); } catch (InvalidOperandException e){} - try{ new Operand("[- 12]", labels, registerSet, 0); } catch (InvalidOperandException e){} - try{ new Operand("[12+1]", labels, registerSet, 0); } catch (InvalidOperandException e){} - try{ new Operand("[+label1", labels, registerSet, 0); } catch (InvalidOperandException e){} - try{ new Operand("[*12]", labels, registerSet, 0); } catch (InvalidOperandException e){} - try{ new Operand("[-A]", labels, registerSet, 0); } catch (InvalidOperandException e){} - try{ new Operand("[A B]", labels, registerSet, 0); } catch (InvalidOperandException e){} - try{ new Operand("[A + B]", labels, registerSet, 0); } catch (InvalidOperandException e){} - try{ new Operand("[A + -1]", labels, registerSet, 0); } catch (InvalidOperandException e){} - try{ new Operand("[A + ]", labels, registerSet, 0); } catch (InvalidOperandException e){} - try{ new Operand("[]", labels, registerSet, 0); } catch (InvalidOperandException e){} - try{ new Operand("[A+A+]", labels, registerSet, 0); } catch (InvalidOperandException e){} - try{ new Operand("[A+[1]]", labels, registerSet, 0); } catch (InvalidOperandException e){} - - - - + try{ new Operand("a1", labels, registerSet, 0); } catch (InvalidOperandException ignored){} + try{ new Operand("a_", labels, registerSet, 0); } catch (InvalidOperandException ignored){} + try{ new Operand("_a", labels, registerSet, 0); } catch (InvalidOperandException ignored){} + try{ new Operand("_1", labels, registerSet, 0); } catch (InvalidOperandException ignored){ } + try{ new Operand("S", labels, registerSet, 0); } catch (InvalidOperandException ignored){} + try{ new Operand("label1_", labels, registerSet, 0); } catch (InvalidOperandException ignored){} + try{ new Operand("+label1", labels, registerSet, 0); } catch (InvalidOperandException ignored){} + try{ new Operand("[- 12]", labels, registerSet, 0); } catch (InvalidOperandException ignored){} + try{ new Operand("[12+1]", labels, registerSet, 0); } catch (InvalidOperandException ignored){} + try{ new Operand("[+label1", labels, registerSet, 0); } catch (InvalidOperandException ignored){} + try{ new Operand("[*12]", labels, registerSet, 0); } catch (InvalidOperandException ignored){} + try{ new Operand("[-A]", labels, registerSet, 0); } catch (InvalidOperandException ignored){} + try{ new Operand("[A B]", labels, registerSet, 0); } catch (InvalidOperandException ignored){} + try{ new Operand("[A + B]", labels, registerSet, 0); } catch (InvalidOperandException ignored){} + try{ new Operand("[A + -1]", labels, registerSet, 0); } catch (InvalidOperandException ignored){} + try{ new Operand("[A + ]", labels, registerSet, 0); } catch (InvalidOperandException ignored){} + try{ new Operand("[]", labels, registerSet, 0); } catch (InvalidOperandException ignored){} + try{ new Operand("[A+A+]", labels, registerSet, 0); } catch (InvalidOperandException ignored){} + try{ new Operand("[A+[1]]", labels, registerSet, 0); } catch (InvalidOperandException ignored){} } - }