mirror of
https://github.com/simon987/Much-Assembly-Required.git
synced 2025-04-10 14:26:45 +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) {
|
} catch (IllegalArgumentException e) {
|
||||||
throw new InvalidOperandException(
|
throw new InvalidOperandException(
|
||||||
"Invalid string operand \"" + string + "\": " + e.getMessage(),
|
"Invalid string operand \"" + string + "\": " + e.getMessage(),
|
||||||
currentLine);
|
currentLine);
|
||||||
}
|
}
|
||||||
|
|
||||||
out.write(string.getBytes(StandardCharsets.UTF_16BE));
|
out.write(string.getBytes(StandardCharsets.UTF_16BE));
|
||||||
@ -219,7 +219,7 @@ public class Assembler {
|
|||||||
return bos.toByteArray();
|
return bos.toByteArray();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse the DW instruction (Define word). Handles DUP operator
|
* 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++
|
/* the EQU pseudo instruction is equivalent to the #define compiler directive in C/C++
|
||||||
* usage: constant_name EQU <immediate_value>
|
* usage: constant_name EQU <immediate_value>
|
||||||
* A constant treated the same way as a label.
|
* A constant treated the same way as a label.
|
||||||
*/
|
*/
|
||||||
line = line.trim();
|
line = line.trim();
|
||||||
String[] tokens = line.split("\\s+");
|
String[] tokens = line.split("\\s+");
|
||||||
|
|
||||||
@ -362,7 +362,47 @@ public class Assembler {
|
|||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
|
|
||||||
//Pass 1: Get code origin
|
//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 {
|
try {
|
||||||
checkForORGInstruction(lines[currentLine], result, currentLine);
|
checkForORGInstruction(lines[currentLine], result, currentLine);
|
||||||
|
|
||||||
@ -373,10 +413,11 @@ public class Assembler {
|
|||||||
//Ignore error
|
//Ignore error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//Pass 2: Save label names and location
|
private void saveLabelNamesAndLocation(String[] lines, AssemblyResult result) {
|
||||||
int currentOffset = 0;
|
int currentOffset = 0;
|
||||||
for (currentLine = 0; currentLine < lines.length; currentLine++) {
|
for (int currentLine = 0; currentLine < lines.length; currentLine++) {
|
||||||
try {
|
try {
|
||||||
checkForLabel(lines[currentLine], result, (char)currentOffset);
|
checkForLabel(lines[currentLine], result, (char)currentOffset);
|
||||||
|
|
||||||
@ -394,11 +435,11 @@ public class Assembler {
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void encodeInstructions(String[] lines, AssemblyResult result, ByteArrayOutputStream out) {
|
||||||
//Pass 3: encode instructions
|
int currentOffset = 0;
|
||||||
currentOffset = 0;
|
for (int currentLine = 0; currentLine < lines.length; currentLine++) {
|
||||||
for (currentLine = 0; currentLine < lines.length; currentLine++) {
|
|
||||||
|
|
||||||
String line = lines[currentLine];
|
String line = lines[currentLine];
|
||||||
|
|
||||||
@ -439,36 +480,6 @@ public class Assembler {
|
|||||||
ioE.printStackTrace();
|
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++;
|
ip++;
|
||||||
instruction.execute(status);
|
instruction.execute(status);
|
||||||
} else if (source == Operand.IMMEDIATE_VALUE) {
|
} else if (source == Operand.IMMEDIATE_VALUE) {
|
||||||
ip++;
|
executeImmediateValue(instruction, source, destination);
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (source == Operand.IMMEDIATE_VALUE_MEM) {
|
} else if (source == Operand.IMMEDIATE_VALUE_MEM) {
|
||||||
//Source is [x]
|
executeImmediateValueMem(instruction, source, destination);
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (source <= registerSetSize) {
|
} else if (source <= registerSetSize) {
|
||||||
//Source is a register
|
executeSourceIsRegister(instruction, source, destination);
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (source <= registerSetSize * 2) {
|
} else if (source <= registerSetSize * 2) {
|
||||||
//Source is [reg]
|
//Source is [reg]
|
||||||
if (destination == 0) {
|
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
|
@Override
|
||||||
public Document mongoSerialise() {
|
public Document mongoSerialise() {
|
||||||
Document dbObject = new Document();
|
Document dbObject = new Document();
|
||||||
|
@ -127,32 +127,27 @@ public class OperandTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Invalid operands
|
//Invalid operands
|
||||||
try{ new Operand("aa", labels, registerSet, 0); } catch (InvalidOperandException e){
|
try{ new Operand("aa", labels, registerSet, 0); } catch (InvalidOperandException ignored){
|
||||||
//It's not a valid Operand; that's okey, just continue; VALID FOR ALL THE OTHER CATCH SENTENCES
|
//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("a1", labels, registerSet, 0); } catch (InvalidOperandException ignored){}
|
||||||
try{ new Operand("a_", labels, registerSet, 0); } catch (InvalidOperandException e){}
|
try{ new Operand("a_", labels, registerSet, 0); } catch (InvalidOperandException ignored){}
|
||||||
try{ new Operand("_a", labels, registerSet, 0); } catch (InvalidOperandException e){}
|
try{ new Operand("_a", labels, registerSet, 0); } catch (InvalidOperandException ignored){}
|
||||||
try{ new Operand("_1", labels, registerSet, 0); } catch (InvalidOperandException e){ }
|
try{ new Operand("_1", labels, registerSet, 0); } catch (InvalidOperandException ignored){ }
|
||||||
try{ new Operand("S", labels, registerSet, 0); } catch (InvalidOperandException e){}
|
try{ new Operand("S", labels, registerSet, 0); } catch (InvalidOperandException ignored){}
|
||||||
try{ new Operand("label1_", labels, registerSet, 0); } catch (InvalidOperandException e){}
|
try{ new Operand("label1_", labels, registerSet, 0); } catch (InvalidOperandException ignored){}
|
||||||
try{ new Operand("+label1", labels, registerSet, 0); } catch (InvalidOperandException e){}
|
try{ new Operand("+label1", labels, registerSet, 0); } catch (InvalidOperandException ignored){}
|
||||||
try{ new Operand("[- 12]", labels, registerSet, 0); } catch (InvalidOperandException e){}
|
try{ new Operand("[- 12]", labels, registerSet, 0); } catch (InvalidOperandException ignored){}
|
||||||
try{ new Operand("[12+1]", labels, registerSet, 0); } catch (InvalidOperandException e){}
|
try{ new Operand("[12+1]", labels, registerSet, 0); } catch (InvalidOperandException ignored){}
|
||||||
try{ new Operand("[+label1", labels, registerSet, 0); } catch (InvalidOperandException e){}
|
try{ new Operand("[+label1", labels, registerSet, 0); } catch (InvalidOperandException ignored){}
|
||||||
try{ new Operand("[*12]", labels, registerSet, 0); } catch (InvalidOperandException e){}
|
try{ new Operand("[*12]", labels, registerSet, 0); } catch (InvalidOperandException ignored){}
|
||||||
try{ new Operand("[-A]", labels, registerSet, 0); } catch (InvalidOperandException e){}
|
try{ new Operand("[-A]", labels, registerSet, 0); } catch (InvalidOperandException ignored){}
|
||||||
try{ new Operand("[A B]", labels, registerSet, 0); } catch (InvalidOperandException e){}
|
try{ new Operand("[A B]", labels, registerSet, 0); } catch (InvalidOperandException ignored){}
|
||||||
try{ new Operand("[A + B]", labels, registerSet, 0); } catch (InvalidOperandException e){}
|
try{ new Operand("[A + B]", labels, registerSet, 0); } catch (InvalidOperandException ignored){}
|
||||||
try{ new Operand("[A + -1]", labels, registerSet, 0); } catch (InvalidOperandException e){}
|
try{ new Operand("[A + -1]", labels, registerSet, 0); } catch (InvalidOperandException ignored){}
|
||||||
try{ new Operand("[A + ]", labels, registerSet, 0); } catch (InvalidOperandException e){}
|
try{ new Operand("[A + ]", labels, registerSet, 0); } catch (InvalidOperandException ignored){}
|
||||||
try{ new Operand("[]", labels, registerSet, 0); } catch (InvalidOperandException e){}
|
try{ new Operand("[]", labels, registerSet, 0); } catch (InvalidOperandException ignored){}
|
||||||
try{ new Operand("[A+A+]", labels, registerSet, 0); } catch (InvalidOperandException e){}
|
try{ new Operand("[A+A+]", labels, registerSet, 0); } catch (InvalidOperandException ignored){}
|
||||||
try{ new Operand("[A+[1]]", labels, registerSet, 0); } catch (InvalidOperandException e){}
|
try{ new Operand("[A+[1]]", labels, registerSet, 0); } catch (InvalidOperandException ignored){}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user