mirror of
https://github.com/simon987/Much-Assembly-Required.git
synced 2025-04-04 06:22:58 +00:00
Refactoring & code style (#212)
This commit is contained in:
parent
634af8859f
commit
03ff2e5527
@ -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 <immediate_value>
|
||||
* 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;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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();
|
||||
|
@ -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){}
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user