mirror of
https://github.com/simon987/Much-Assembly-Required.git
synced 2025-12-13 22:59:02 +00:00
Merge branch 'master' of https://github.com/simon987/Much-Assembly-Required
# Conflicts: # Server/src/main/java/net/simon987/server/GameServer.java
This commit is contained in:
@@ -224,55 +224,59 @@ public class GameServer implements Runnable {
|
||||
private void save() {
|
||||
|
||||
LogManager.LOGGER.info("Saving to MongoDB | W:" + gameUniverse.getWorlds().size() + " | U:" + gameUniverse.getUsers().size());
|
||||
try{
|
||||
DB db = mongo.getDB("mar");
|
||||
|
||||
DB db = mongo.getDB("mar");
|
||||
int unloaded_worlds = 0;
|
||||
|
||||
int unloaded_worlds = 0;
|
||||
DBCollection worlds = db.getCollection("world");
|
||||
DBCollection users = db.getCollection("user");
|
||||
DBCollection server = db.getCollection("server");
|
||||
|
||||
DBCollection worlds = db.getCollection("world");
|
||||
DBCollection users = db.getCollection("user");
|
||||
DBCollection server = db.getCollection("server");
|
||||
List<DBObject> worldDocuments = new ArrayList<>();
|
||||
int perBatch = 35;
|
||||
int insertedWorlds = 0;
|
||||
GameUniverse universe = GameServer.INSTANCE.getGameUniverse();
|
||||
ArrayList<World> worlds_ = new ArrayList<>(universe.getWorlds());
|
||||
for (World w : worlds_) {
|
||||
LogManager.LOGGER.fine("Saving world "+w.getId()+" to mongodb");
|
||||
insertedWorlds++;
|
||||
worlds.save(w.mongoSerialise());
|
||||
|
||||
// If the world should unload, it is removed from the Universe after having been saved.
|
||||
if (w.shouldUnload()){
|
||||
unloaded_worlds++;
|
||||
LogManager.LOGGER.fine("Unloading world "+w.getId()+" from universe");
|
||||
universe.removeWorld(w);
|
||||
}
|
||||
}
|
||||
|
||||
List<DBObject> worldDocuments = new ArrayList<>();
|
||||
int perBatch = 35;
|
||||
int insertedWorlds = 0;
|
||||
GameUniverse universe = GameServer.INSTANCE.getGameUniverse();
|
||||
ArrayList<World> worlds_ = new ArrayList<>(universe.getWorlds());
|
||||
for (World w : worlds_) {
|
||||
LogManager.LOGGER.fine("Saving world "+w.getId()+" to mongodb");
|
||||
insertedWorlds++;
|
||||
worlds.save(w.mongoSerialise());
|
||||
|
||||
// If the world should unload, it is removed from the Universe after having been saved.
|
||||
if (w.shouldUnload()){
|
||||
unloaded_worlds++;
|
||||
LogManager.LOGGER.fine("Unloading world "+w.getId()+" from universe");
|
||||
universe.removeWorld(w);
|
||||
}
|
||||
List<DBObject> userDocuments = new ArrayList<>();
|
||||
int insertedUsers = 0;
|
||||
ArrayList<User> users_ = new ArrayList<>(GameServer.INSTANCE.getGameUniverse().getUsers());
|
||||
for (User u : users_) {
|
||||
|
||||
insertedUsers++;
|
||||
|
||||
|
||||
if (!u.isGuest()) {
|
||||
users.save(u.mongoSerialise());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
BasicDBObject serverObj = new BasicDBObject();
|
||||
serverObj.put("_id","serverinfo"); // a constant id ensures only one entry is kept and updated, instead of a new entry created every save.
|
||||
serverObj.put("time", gameUniverse.getTime());
|
||||
serverObj.put("nextObjectId", gameUniverse.getNextObjectId());
|
||||
server.save(serverObj);
|
||||
|
||||
LogManager.LOGGER.info(""+insertedWorlds+" worlds saved, "+unloaded_worlds+" unloaded");
|
||||
LogManager.LOGGER.info("Done!");
|
||||
} catch (Exception e) {
|
||||
LogManager.LOGGER.severe("Problem happened during save function");
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
List<DBObject> userDocuments = new ArrayList<>();
|
||||
int insertedUsers = 0;
|
||||
ArrayList<User> users_ = new ArrayList<>(GameServer.INSTANCE.getGameUniverse().getUsers());
|
||||
for (User u : users_) {
|
||||
|
||||
insertedUsers++;
|
||||
|
||||
|
||||
if (!u.isGuest()) {
|
||||
users.save(u.mongoSerialise());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
BasicDBObject serverObj = new BasicDBObject();
|
||||
serverObj.put("_id","serverinfo"); // a constant id ensures only one entry is kept and updated, instead of a new entry created every save.
|
||||
serverObj.put("time", gameUniverse.getTime());
|
||||
serverObj.put("nextObjectId", gameUniverse.getNextObjectId());
|
||||
server.save(serverObj);
|
||||
|
||||
LogManager.LOGGER.info(""+insertedWorlds+" worlds saved, "+unloaded_worlds+" unloaded");
|
||||
LogManager.LOGGER.info("Done!");
|
||||
}
|
||||
|
||||
public ServerConfiguration getConfig() {
|
||||
|
||||
@@ -24,7 +24,7 @@ public class Assembler {
|
||||
|
||||
private RegisterSet registerSet;
|
||||
|
||||
private static final int MEM_SIZE = 0x10000; // Size in words
|
||||
private static final int MEM_SIZE = 0x10000; // Size in words todo load from config
|
||||
|
||||
public Assembler(InstructionSet instructionSet, RegisterSet registerSet, ServerConfiguration config) {
|
||||
this.instructionSet = instructionSet;
|
||||
@@ -54,7 +54,7 @@ public class Assembler {
|
||||
*/
|
||||
private static String removeLabel(String line) {
|
||||
|
||||
return line.replaceAll("\\b\\w*\\b:", "");
|
||||
return line.replaceAll("^\\s*\\b\\w*\\b:", "");
|
||||
|
||||
}
|
||||
|
||||
@@ -97,11 +97,11 @@ public class Assembler {
|
||||
line = removeComment(line);
|
||||
|
||||
//Check for labels
|
||||
Pattern pattern = Pattern.compile("\\b\\w*\\b:");
|
||||
Pattern pattern = Pattern.compile("^\\s*\\b\\w*\\b:");
|
||||
Matcher matcher = pattern.matcher(line);
|
||||
|
||||
if (matcher.find()) {
|
||||
String label = matcher.group(0).substring(0, matcher.group(0).length() - 1);
|
||||
String label = matcher.group(0).substring(0, matcher.group(0).length() - 1).trim();
|
||||
|
||||
LogManager.LOGGER.fine("DEBUG: Label " + label + " @ " + (result.origin + currentOffset));
|
||||
result.labels.put(label, (char) (result.origin + currentOffset));
|
||||
@@ -175,7 +175,18 @@ public class Assembler {
|
||||
out.writeChar(0);
|
||||
|
||||
} else {
|
||||
throw new InvalidOperandException("Invalid operand \"" + value + '"', currentLine);
|
||||
|
||||
//Integer.decode failed, try binary
|
||||
if (value.startsWith("0b")) {
|
||||
try {
|
||||
out.writeChar(Integer.parseInt(value.substring(2), 2));
|
||||
} catch (NumberFormatException e2) {
|
||||
throw new InvalidOperandException("Invalid operand \"" + value + '"', currentLine);
|
||||
}
|
||||
} else {
|
||||
throw new InvalidOperandException("Invalid operand \"" + value + '"', currentLine);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -256,25 +267,25 @@ public class Assembler {
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for and handle segment declarations (.text & .data)
|
||||
* Check for and handle section declarations (.text & .data)
|
||||
*
|
||||
* @param line Current line
|
||||
*/
|
||||
private static void checkForSegmentDeclaration(String line, AssemblyResult result,
|
||||
private static void checkForSectionDeclaration(String line, AssemblyResult result,
|
||||
int currentLine, int currentOffset) throws AssemblyException {
|
||||
|
||||
String[] tokens = line.split("\\s+");
|
||||
|
||||
if (tokens[0].toUpperCase().equals(".TEXT")) {
|
||||
|
||||
result.defineSegment(Segment.TEXT, currentLine, currentOffset);
|
||||
result.defineSecton(Section.TEXT, currentLine, currentOffset);
|
||||
throw new PseudoInstructionException(currentLine);
|
||||
|
||||
} else if (tokens[0].toUpperCase().equals(".DATA")) {
|
||||
|
||||
LogManager.LOGGER.fine("DEBUG: .data @" + currentLine);
|
||||
|
||||
result.defineSegment(Segment.DATA, currentLine, currentOffset);
|
||||
result.defineSecton(Section.DATA, currentLine, currentOffset);
|
||||
throw new PseudoInstructionException(currentLine);
|
||||
}
|
||||
}
|
||||
@@ -296,7 +307,7 @@ public class Assembler {
|
||||
String[] tokens = line.split("\\s+");
|
||||
|
||||
|
||||
if (line.toUpperCase().contains(" EQU ")) {
|
||||
if (line.toUpperCase().matches(".*\\bEQU\\b.*")) {
|
||||
if (tokens[1].toUpperCase().equals("EQU") && tokens.length == 3) {
|
||||
try {
|
||||
//Save value as a label
|
||||
@@ -385,7 +396,7 @@ public class Assembler {
|
||||
}
|
||||
|
||||
//Check for pseudo instructions
|
||||
checkForSegmentDeclaration(line, result, currentLine, currentOffset);
|
||||
checkForSectionDeclaration(line, result, currentLine, currentOffset);
|
||||
checkForEQUInstruction(line, result.labels, currentLine);
|
||||
checkForORGInstruction(line, result, currentLine);
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ package net.simon987.server.assembly;
|
||||
|
||||
import net.simon987.server.ServerConfiguration;
|
||||
import net.simon987.server.assembly.exception.AssemblyException;
|
||||
import net.simon987.server.assembly.exception.DuplicateSegmentException;
|
||||
import net.simon987.server.assembly.exception.DuplicateSectionException;
|
||||
import net.simon987.server.logging.LogManager;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
@@ -31,11 +31,11 @@ public class AssemblyResult {
|
||||
/**
|
||||
* Offset of the code segment
|
||||
*/
|
||||
private int codeSegmentOffset;
|
||||
private int codeSectionOffset;
|
||||
/**
|
||||
* Line of the code segment definition
|
||||
*/
|
||||
private int codeSegmentLine;
|
||||
private int codeSectionLine;
|
||||
|
||||
/**
|
||||
* The encoded user code (will be incomplete or invalid if the
|
||||
@@ -45,60 +45,60 @@ public class AssemblyResult {
|
||||
/**
|
||||
* Offset of the data segment
|
||||
*/
|
||||
private int dataSegmentOffset;
|
||||
private int dataSectionOffset;
|
||||
/**
|
||||
* Line of the data segment definition
|
||||
*/
|
||||
private int dataSegmentLine;
|
||||
private int dataSectionLine;
|
||||
/**
|
||||
* Whether or not the code segment is set
|
||||
*/
|
||||
private boolean codeSegmentSet = false;
|
||||
private boolean codeSectionSet = false;
|
||||
/**
|
||||
* Whether or not the data segment is set
|
||||
*/
|
||||
private boolean dataSegmentSet = false;
|
||||
private boolean dataSectionSet = false;
|
||||
|
||||
AssemblyResult(ServerConfiguration config) {
|
||||
origin = config.getInt("org_offset");
|
||||
}
|
||||
|
||||
/**
|
||||
* Define a segment.
|
||||
* Define a section.
|
||||
*
|
||||
* @param segment Segment to define
|
||||
* @param currentOffset Current offset, in bytes of the segment
|
||||
* @param currentLine Line number of the segment declaration
|
||||
* @throws DuplicateSegmentException when a segment is defined twice
|
||||
* @param section Section to define
|
||||
* @param currentOffset Current offset, in bytes of the section
|
||||
* @param currentLine Line number of the section declaration
|
||||
* @throws DuplicateSectionException when a section is defined twice
|
||||
*/
|
||||
void defineSegment(Segment segment, int currentLine, int currentOffset) throws DuplicateSegmentException {
|
||||
void defineSecton(Section section, int currentLine, int currentOffset) throws DuplicateSectionException {
|
||||
|
||||
if (segment == Segment.TEXT) {
|
||||
//Code segment
|
||||
if (section == Section.TEXT) {
|
||||
//Code section
|
||||
|
||||
if (!codeSegmentSet) {
|
||||
codeSegmentOffset = origin + currentOffset;
|
||||
codeSegmentLine = currentLine;
|
||||
if (!codeSectionSet) {
|
||||
codeSectionOffset = origin + currentOffset;
|
||||
codeSectionLine = currentLine;
|
||||
|
||||
LogManager.LOGGER.fine("DEBUG: .text offset @" + codeSegmentOffset);
|
||||
LogManager.LOGGER.fine("DEBUG: .text offset @" + codeSectionOffset);
|
||||
|
||||
|
||||
codeSegmentSet = true;
|
||||
codeSectionSet = true;
|
||||
} else {
|
||||
throw new DuplicateSegmentException(currentLine);
|
||||
throw new DuplicateSectionException(currentLine);
|
||||
}
|
||||
|
||||
} else {
|
||||
//Data segment
|
||||
if (!dataSegmentSet) {
|
||||
dataSegmentOffset = origin + currentOffset;
|
||||
dataSegmentLine = currentLine;
|
||||
//Data section
|
||||
if (!dataSectionSet) {
|
||||
dataSectionOffset = origin + currentOffset;
|
||||
dataSectionLine = currentLine;
|
||||
|
||||
LogManager.LOGGER.fine("DEBUG: .data offset @" + dataSegmentOffset);
|
||||
LogManager.LOGGER.fine("DEBUG: .data offset @" + dataSectionOffset);
|
||||
|
||||
dataSegmentSet = true;
|
||||
dataSectionSet = true;
|
||||
} else {
|
||||
throw new DuplicateSegmentException(currentLine);
|
||||
throw new DuplicateSectionException(currentLine);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -113,9 +113,9 @@ public class AssemblyResult {
|
||||
return assembledCode;
|
||||
}
|
||||
|
||||
public int getCodeSegmentOffset() {
|
||||
if (codeSegmentSet) {
|
||||
return codeSegmentOffset;
|
||||
public int getCodeSectionOffset() {
|
||||
if (codeSectionSet) {
|
||||
return codeSectionOffset;
|
||||
} else {
|
||||
return origin;
|
||||
}
|
||||
|
||||
@@ -43,10 +43,10 @@ public class CPU implements MongoSerialisable {
|
||||
private RegisterSet registerSet;
|
||||
|
||||
/**
|
||||
* Offset of the code segment. The code starts to get
|
||||
* Offset of the code section. The code starts to get
|
||||
* executed at this address each tick. Defaults to org_offset@config.properties
|
||||
*/
|
||||
private int codeSegmentOffset;
|
||||
private int codeSectionOffset;
|
||||
|
||||
/**
|
||||
* Instruction pointer, always points to the next instruction
|
||||
@@ -73,7 +73,7 @@ public class CPU implements MongoSerialisable {
|
||||
instructionSet = new DefaultInstructionSet();
|
||||
registerSet = new DefaultRegisterSet();
|
||||
attachedHardware = new HashMap<>();
|
||||
codeSegmentOffset = config.getInt("org_offset");
|
||||
codeSectionOffset = config.getInt("org_offset");
|
||||
|
||||
instructionSet.add(new JmpInstruction(this));
|
||||
instructionSet.add(new JnzInstruction(this));
|
||||
@@ -112,7 +112,7 @@ public class CPU implements MongoSerialisable {
|
||||
|
||||
public void reset() {
|
||||
status.clear();
|
||||
ip = codeSegmentOffset;
|
||||
ip = codeSectionOffset;
|
||||
}
|
||||
|
||||
public int execute(int timeout) {
|
||||
@@ -352,7 +352,7 @@ public class CPU implements MongoSerialisable {
|
||||
dbObject.put("memory", memory.mongoSerialise());
|
||||
|
||||
dbObject.put("registerSet", registerSet.mongoSerialise());
|
||||
dbObject.put("codeSegmentOffset", codeSegmentOffset);
|
||||
dbObject.put("codeSegmentOffset", codeSectionOffset);
|
||||
|
||||
BasicDBList hardwareList = new BasicDBList();
|
||||
|
||||
@@ -375,7 +375,7 @@ public class CPU implements MongoSerialisable {
|
||||
|
||||
CPU cpu = new CPU(GameServer.INSTANCE.getConfig(), user);
|
||||
|
||||
cpu.codeSegmentOffset = (int) obj.get("codeSegmentOffset");
|
||||
cpu.codeSectionOffset = (int) obj.get("codeSegmentOffset");
|
||||
|
||||
BasicDBList hardwareList = (BasicDBList) obj.get("hardware");
|
||||
|
||||
@@ -416,8 +416,8 @@ public class CPU implements MongoSerialisable {
|
||||
this.ip = ip;
|
||||
}
|
||||
|
||||
public void setCodeSegmentOffset(int codeSegmentOffset) {
|
||||
this.codeSegmentOffset = codeSegmentOffset;
|
||||
public void setCodeSectionOffset(int codeSectionOffset) {
|
||||
this.codeSectionOffset = codeSectionOffset;
|
||||
}
|
||||
|
||||
public void attachHardware(CpuHardware hardware, int address) {
|
||||
|
||||
@@ -44,6 +44,8 @@ public class DefaultInstructionSet implements InstructionSet {
|
||||
add(new RclInstruction());
|
||||
add(new RcrInstruction());
|
||||
add(new SarInstruction());
|
||||
add(new IncInstruction());
|
||||
add(new DecInstruction());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -6,7 +6,6 @@ import com.mongodb.DBObject;
|
||||
import net.simon987.server.GameServer;
|
||||
import net.simon987.server.io.MongoSerialisable;
|
||||
import net.simon987.server.logging.LogManager;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
@@ -157,36 +156,6 @@ public class Memory implements Target, MongoSerialisable {
|
||||
return memory;
|
||||
}
|
||||
|
||||
public static Memory deserialize(JSONObject json) {
|
||||
|
||||
Memory memory = new Memory(0);
|
||||
|
||||
String zipBytesStr = (String) json.get("zipBytes");
|
||||
|
||||
if (zipBytesStr != null) {
|
||||
byte[] compressedBytes = Base64.getDecoder().decode((String) json.get("zipBytes"));
|
||||
|
||||
try {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
Inflater decompressor = new Inflater(true);
|
||||
InflaterOutputStream inflaterOutputStream = new InflaterOutputStream(baos, decompressor);
|
||||
inflaterOutputStream.write(compressedBytes);
|
||||
inflaterOutputStream.close();
|
||||
|
||||
memory.setBytes(baos.toByteArray());
|
||||
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else {
|
||||
LogManager.LOGGER.severe("Memory was manually deleted");
|
||||
memory = new Memory(GameServer.INSTANCE.getConfig().getInt("memory_size"));
|
||||
}
|
||||
|
||||
|
||||
return memory;
|
||||
}
|
||||
|
||||
public void setBytes(byte[] bytes) {
|
||||
this.words = new char[bytes.length / 2];
|
||||
ByteBuffer.wrap(bytes).order(ByteOrder.BIG_ENDIAN).asCharBuffer().get(this.words);
|
||||
|
||||
@@ -224,11 +224,30 @@ public class Operand {
|
||||
}
|
||||
|
||||
//label is invalid
|
||||
|
||||
data = Integer.decode(expr);
|
||||
value += registerSet.size() * 2; //refers to memory with disp
|
||||
return true;
|
||||
} catch (NumberFormatException e) {
|
||||
|
||||
//Integer.decode failed, try binary
|
||||
if (expr.startsWith("+0b")) {
|
||||
try {
|
||||
data = Integer.parseInt(expr.substring(3), 2);
|
||||
value += registerSet.size() * 2; //refers to memory with disp
|
||||
return true;
|
||||
} catch (NumberFormatException e2) {
|
||||
return false;
|
||||
}
|
||||
} else if (expr.startsWith("-0b")) {
|
||||
try {
|
||||
data = -Integer.parseInt(expr.substring(3), 2);
|
||||
value += registerSet.size() * 2; //refers to memory with disp
|
||||
return true;
|
||||
} catch (NumberFormatException e2) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,10 +3,9 @@ package net.simon987.server.assembly;
|
||||
/**
|
||||
* Section of a user-created program.
|
||||
* The execution will start at the beginning of the code
|
||||
* segment and a warning message will be displayed when execution
|
||||
* reached the data segment during debugging
|
||||
* segment.
|
||||
*/
|
||||
public enum Segment {
|
||||
public enum Section {
|
||||
|
||||
/**
|
||||
* Code section of the program. Contains executable code
|
||||
@@ -3,17 +3,17 @@ package net.simon987.server.assembly.exception;
|
||||
/**
|
||||
* Threw when a user attempts to define the same section twice
|
||||
*/
|
||||
public class DuplicateSegmentException extends AssemblyException {
|
||||
public class DuplicateSectionException extends AssemblyException {
|
||||
|
||||
/**
|
||||
* Message of the exception
|
||||
*/
|
||||
private static final String message = "Segments can only be defined once";
|
||||
private static final String message = "Sections can only be defined once";
|
||||
|
||||
/**
|
||||
* Create a new Duplicate Segment Exception
|
||||
* Create a new Duplicate Section Exception
|
||||
*/
|
||||
public DuplicateSegmentException(int line) {
|
||||
public DuplicateSectionException(int line) {
|
||||
super(message, line);
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,7 @@ public class FatalAssemblyException extends AssemblyException {
|
||||
private static final String message = "A fatal assembly error has occurred";
|
||||
|
||||
/**
|
||||
* Create a new Duplicate Segment Exception
|
||||
* Create a new Duplicate Section Exception
|
||||
*/
|
||||
public FatalAssemblyException(String msg, int line) {
|
||||
super(msg, line);
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
package net.simon987.server.assembly.instruction;
|
||||
|
||||
import net.simon987.server.assembly.Instruction;
|
||||
import net.simon987.server.assembly.Status;
|
||||
import net.simon987.server.assembly.Target;
|
||||
import net.simon987.server.assembly.Util;
|
||||
|
||||
public class DecInstruction extends Instruction {
|
||||
|
||||
public static final int OPCODE = 0x2B;
|
||||
|
||||
public DecInstruction() {
|
||||
super("dec", OPCODE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Status execute(Target dst, int dstIndex, Status status) {
|
||||
char a = (char) dst.get(dstIndex);
|
||||
int result = a - 1;
|
||||
|
||||
// Like x86 Carry flag is preserved during INC/DEC
|
||||
// (Use ADD x, 1 to have carry flag change)
|
||||
// Other flags set according to result
|
||||
status.setSignFlag(Util.checkSign16(result));
|
||||
status.setZeroFlag((char) result == 0);
|
||||
status.setOverflowFlag(Util.checkOverFlowSub16(a, 1));
|
||||
|
||||
dst.set(dstIndex, result);
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
package net.simon987.server.assembly.instruction;
|
||||
|
||||
import net.simon987.server.assembly.Instruction;
|
||||
import net.simon987.server.assembly.Status;
|
||||
import net.simon987.server.assembly.Target;
|
||||
import net.simon987.server.assembly.Util;
|
||||
|
||||
public class IncInstruction extends Instruction {
|
||||
|
||||
public static final int OPCODE = 0x2A;
|
||||
|
||||
public IncInstruction() {
|
||||
super("inc", OPCODE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Status execute(Target dst, int dstIndex, Status status) {
|
||||
char a = (char) dst.get(dstIndex);
|
||||
int result = a + 1;
|
||||
|
||||
// Like x86 Carry flag is preserved during INC/DEC
|
||||
// (Use ADD x, 1 to have carry flag change)
|
||||
// Other flags set according to result
|
||||
status.setSignFlag(Util.checkSign16(result));
|
||||
status.setZeroFlag((char) result == 0);
|
||||
status.setOverflowFlag(Util.checkOverFlowAdd16(a, 1));
|
||||
|
||||
dst.set(dstIndex, result);
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,12 +7,14 @@ public class ObjectDeathEvent extends GameEvent {
|
||||
/**
|
||||
* The GameObject type ID of object that init this event
|
||||
*/
|
||||
private int sourceObjectId;
|
||||
private long sourceObjectId;
|
||||
|
||||
public ObjectDeathEvent(Object source, int sourceObjectId) {
|
||||
setSource(source);
|
||||
this.sourceObjectId = sourceObjectId;
|
||||
}
|
||||
|
||||
public int getSourceObjectId() { return sourceObjectId; }
|
||||
public long getSourceObjectId() {
|
||||
return sourceObjectId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
package net.simon987.server.game;
|
||||
|
||||
/**
|
||||
* Types of GameEffects
|
||||
*/
|
||||
public enum EffectType {
|
||||
|
||||
/**
|
||||
* Warning icon
|
||||
*/
|
||||
WARNING,
|
||||
/**
|
||||
* Error icon
|
||||
*/
|
||||
ERROR,
|
||||
/**
|
||||
* Dig particle effect
|
||||
*/
|
||||
DIG,
|
||||
/**
|
||||
* 'A' Icon
|
||||
*/
|
||||
A_EMOTE
|
||||
|
||||
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
package net.simon987.server.game;
|
||||
|
||||
import net.simon987.server.io.JSONSerialisable;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
/**
|
||||
* Represents a game effect in a World (e.g. Particles made when digging, Error animation, Attack effects etc..)
|
||||
* <br>
|
||||
* These effects are purely visual and could be changed or ignored by the client
|
||||
*/
|
||||
public class GameEffect implements JSONSerialisable {
|
||||
|
||||
|
||||
/**
|
||||
* Type of the effect
|
||||
*/
|
||||
private EffectType type;
|
||||
|
||||
private int x;
|
||||
|
||||
private int y;
|
||||
|
||||
public GameEffect(EffectType type, int x, int y) {
|
||||
this.type = type;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject serialise() {
|
||||
|
||||
JSONObject json = new JSONObject();
|
||||
|
||||
json.put("x", x);
|
||||
json.put("y", y);
|
||||
json.put("type", type);
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
public EffectType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(EffectType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public int getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public void setX(int x) {
|
||||
this.x = x;
|
||||
}
|
||||
|
||||
public int getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
public void setY(int y) {
|
||||
this.y = y;
|
||||
}
|
||||
}
|
||||
@@ -204,7 +204,7 @@ public class GameUniverse {
|
||||
char[] assembledCode = ar.getWords();
|
||||
|
||||
user.getCpu().getMemory().write((char) ar.origin, assembledCode, 0, assembledCode.length);
|
||||
user.getCpu().setCodeSegmentOffset(ar.getCodeSegmentOffset());
|
||||
user.getCpu().setCodeSectionOffset(ar.getCodeSectionOffset());
|
||||
|
||||
|
||||
} else {
|
||||
|
||||
@@ -8,7 +8,7 @@ import java.util.Collections;
|
||||
|
||||
/**
|
||||
* Class to compute paths in the game universe. It supports
|
||||
* paths between within the same World.
|
||||
* paths within the same World.
|
||||
*/
|
||||
public class Pathfinder {
|
||||
|
||||
|
||||
@@ -21,30 +21,32 @@ public class CodeUploadHandler implements MessageHandler {
|
||||
//TODO Should we wait at the end of the tick to modify the CPU ?
|
||||
user.getUser().setUserCode((String) json.get("code"));
|
||||
|
||||
AssemblyResult ar = new Assembler(user.getUser().getCpu().getInstructionSet(),
|
||||
user.getUser().getCpu().getRegisterSet(),
|
||||
GameServer.INSTANCE.getConfig()).parse(user.getUser().getUserCode());
|
||||
if (user.getUser().getUserCode() != null) {
|
||||
AssemblyResult ar = new Assembler(user.getUser().getCpu().getInstructionSet(),
|
||||
user.getUser().getCpu().getRegisterSet(),
|
||||
GameServer.INSTANCE.getConfig()).parse(user.getUser().getUserCode());
|
||||
|
||||
user.getUser().getCpu().getMemory().clear();
|
||||
user.getUser().getCpu().getMemory().clear();
|
||||
|
||||
//Write assembled code to mem
|
||||
char[] assembledCode = ar.getWords();
|
||||
//Write assembled code to mem
|
||||
char[] assembledCode = ar.getWords();
|
||||
|
||||
user.getUser().getCpu().getMemory().write((char) ar.origin, assembledCode, 0, assembledCode.length);
|
||||
user.getUser().getCpu().setCodeSegmentOffset(ar.getCodeSegmentOffset());
|
||||
user.getUser().getCpu().getMemory().write((char) ar.origin, assembledCode, 0, assembledCode.length);
|
||||
user.getUser().getCpu().setCodeSectionOffset(ar.getCodeSectionOffset());
|
||||
|
||||
//Clear keyboard buffer
|
||||
if (user.getUser().getControlledUnit() != null &&
|
||||
user.getUser().getControlledUnit().getKeyboardBuffer() != null) {
|
||||
user.getUser().getControlledUnit().getKeyboardBuffer().clear();
|
||||
//Clear keyboard buffer
|
||||
if (user.getUser().getControlledUnit() != null &&
|
||||
user.getUser().getControlledUnit().getKeyboardBuffer() != null) {
|
||||
user.getUser().getControlledUnit().getKeyboardBuffer().clear();
|
||||
}
|
||||
|
||||
|
||||
JSONObject response = new JSONObject();
|
||||
response.put("t", "codeResponse");
|
||||
response.put("bytes", ar.bytes.length);
|
||||
|
||||
user.getWebSocket().send(response.toJSONString());
|
||||
}
|
||||
|
||||
|
||||
JSONObject response = new JSONObject();
|
||||
response.put("t", "codeResponse");
|
||||
response.put("bytes", ar.bytes.length);
|
||||
|
||||
user.getWebSocket().send(response.toJSONString());
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package net.simon987.server.webserver;
|
||||
|
||||
|
||||
import net.simon987.server.logging.LogManager;
|
||||
import org.java_websocket.exceptions.WebsocketNotConnectedException;
|
||||
import org.json.simple.JSONObject;
|
||||
import org.json.simple.parser.JSONParser;
|
||||
import org.json.simple.parser.ParseException;
|
||||
@@ -28,9 +29,16 @@ public class MessageEventDispatcher {
|
||||
try {
|
||||
JSONObject json = (JSONObject) parser.parse(message);
|
||||
|
||||
if (json.containsKey("t")) {
|
||||
if (json.containsKey("t") && user.getWebSocket().isOpen()) {
|
||||
for (MessageHandler handler : handlers) {
|
||||
handler.handle(user, json);
|
||||
try {
|
||||
handler.handle(user, json);
|
||||
} catch (WebsocketNotConnectedException e) {
|
||||
LogManager.LOGGER.fine("Catched WebsocketNotConnectedException");
|
||||
} catch (Exception e1) {
|
||||
LogManager.LOGGER.severe(e1.getMessage());
|
||||
e1.printStackTrace();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
LogManager.LOGGER.severe("Malformed JSON sent by " + user.getUser().getUsername());
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
package net.simon987.server.webserver;
|
||||
|
||||
import org.java_websocket.exceptions.WebsocketNotConnectedException;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
public interface MessageHandler {
|
||||
|
||||
void handle(OnlineUser user, JSONObject json);
|
||||
void handle(OnlineUser user, JSONObject json) throws WebsocketNotConnectedException;
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
package net.simon987.server.assembly;
|
||||
|
||||
import net.simon987.server.ServerConfiguration;
|
||||
import net.simon987.server.assembly.exception.CancelledException;
|
||||
import net.simon987.server.user.User;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
public class CPUTest {
|
||||
|
||||
@Test
|
||||
public void executeInstruction() throws CancelledException {
|
||||
|
||||
ServerConfiguration config = new ServerConfiguration("config.properties");
|
||||
User user = new User();
|
||||
CPU cpu = new CPU(config, user);
|
||||
|
||||
|
||||
for(int i = 0 ; i < 3 ; i++){
|
||||
//Execute every possible instruction with random values in memory
|
||||
cpu.reset();
|
||||
cpu.getMemory().clear();
|
||||
Random random = new Random();
|
||||
byte[] randomBytes = new byte[cpu.getMemory().getWords().length * 2];
|
||||
random.nextBytes(randomBytes);
|
||||
|
||||
for (int machineCode = Character.MIN_VALUE; machineCode < Character.MAX_VALUE; machineCode++) {
|
||||
Instruction instruction = cpu.getInstructionSet().get(machineCode & 0x03F); // 0000 0000 00XX XXXX
|
||||
|
||||
int source = (machineCode >> 11) & 0x001F; // XXXX X000 0000 0000
|
||||
int destination = (machineCode >> 6) & 0x001F; // 0000 0XXX XX00 0000
|
||||
|
||||
cpu.executeInstruction(instruction, source, destination);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package net.simon987.server.assembly;
|
||||
|
||||
import net.simon987.server.ServerConfiguration;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
|
||||
public class MemoryTest {
|
||||
@Test
|
||||
public void getSet() {
|
||||
ServerConfiguration config = new ServerConfiguration("config.properties");
|
||||
int memorySize = config.getInt("memory_size");
|
||||
Memory memory = new Memory(memorySize);
|
||||
|
||||
memory.set(1, 1);
|
||||
assertEquals(1, memory.get(1));
|
||||
|
||||
memory.set(memorySize / 2 - 1, 1);
|
||||
assertEquals(1, memory.get(memorySize / 2 - 1));
|
||||
|
||||
memory.get(memorySize / 2);
|
||||
memory.get(-1);
|
||||
|
||||
memory.set(memorySize / 2, 1);
|
||||
memory.set(-1, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void write() {
|
||||
|
||||
ServerConfiguration config = new ServerConfiguration("config.properties");
|
||||
int memorySize = config.getInt("memory_size");
|
||||
Memory memory = new Memory(memorySize);
|
||||
|
||||
|
||||
assertTrue(memory.write(0, new char[memorySize], 0, memorySize));
|
||||
assertFalse(memory.write(0, new char[memorySize], 0, memorySize + 1));
|
||||
assertFalse(memory.write(0, new char[memorySize], 0, -1));
|
||||
assertFalse(memory.write(-1, new char[memorySize], 0, 10));
|
||||
|
||||
assertFalse(memory.write(memorySize, new char[15], 0, 1));
|
||||
assertFalse(memory.write((memorySize) - 5, new char[11], 0, 6));
|
||||
assertTrue(memory.write((memorySize) - 5, new char[11], 0, 5));
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
package net.simon987.server.assembly;
|
||||
|
||||
import net.simon987.server.assembly.exception.InvalidOperandException;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
|
||||
|
||||
public class OperandTest {
|
||||
|
||||
|
||||
@Test
|
||||
public void Operand() {
|
||||
|
||||
RegisterSet registerSet = new DefaultRegisterSet();
|
||||
HashMap<String, Character> labels = new HashMap<>(10);
|
||||
labels.put("label1", (char) 10);
|
||||
labels.put("label2", (char) 20);
|
||||
labels.put("label3", (char) 30);
|
||||
labels.put("label4", (char) 40);
|
||||
|
||||
|
||||
//Valid operands
|
||||
try {
|
||||
//Register
|
||||
Operand reg1 = new Operand("a", labels, registerSet, 0);
|
||||
assertEquals(OperandType.REGISTER16, reg1.getType());
|
||||
assertEquals(1, reg1.getValue());
|
||||
assertEquals(0, reg1.getData());
|
||||
|
||||
Operand reg2 = new Operand("a ", labels, registerSet, 0);
|
||||
assertEquals(OperandType.REGISTER16, reg2.getType());
|
||||
assertEquals(1, reg2.getValue());
|
||||
assertEquals(0, reg2.getData());
|
||||
|
||||
Operand reg3 = new Operand(" A ", labels, registerSet, 0);
|
||||
assertEquals(OperandType.REGISTER16, reg3.getType());
|
||||
assertEquals(1, reg3.getValue());
|
||||
assertEquals(0, reg3.getData());
|
||||
|
||||
Operand reg4 = new Operand("B", labels, registerSet, 0);
|
||||
assertEquals(OperandType.REGISTER16, reg4.getType());
|
||||
assertEquals(2, reg4.getValue());
|
||||
assertEquals(0, reg4.getData());
|
||||
|
||||
//Immediate
|
||||
Operand imm1 = new Operand(" +12", labels, registerSet, 0);
|
||||
assertEquals(OperandType.IMMEDIATE16, imm1.getType());
|
||||
assertEquals(Operand.IMMEDIATE_VALUE, imm1.getValue());
|
||||
assertEquals(12, imm1.getData());
|
||||
|
||||
Operand imm2 = new Operand(" -12", labels, registerSet, 0);
|
||||
assertEquals(OperandType.IMMEDIATE16, imm2.getType());
|
||||
assertEquals(Operand.IMMEDIATE_VALUE, imm2.getValue());
|
||||
assertEquals(-12, imm2.getData());
|
||||
|
||||
Operand imm3 = new Operand(" 0xABCD", labels, registerSet, 0);
|
||||
assertEquals(OperandType.IMMEDIATE16, imm3.getType());
|
||||
assertEquals(Operand.IMMEDIATE_VALUE, imm3.getValue());
|
||||
assertEquals(0xABCD, imm3.getData());
|
||||
|
||||
Operand imm4 = new Operand(" label1", labels, registerSet, 0);
|
||||
assertEquals(OperandType.IMMEDIATE16, imm4.getType());
|
||||
assertEquals(Operand.IMMEDIATE_VALUE, imm4.getValue());
|
||||
assertEquals(10, imm4.getData());
|
||||
|
||||
//Memory Immediate
|
||||
Operand mem1 = new Operand("[+12]", labels, registerSet, 0);
|
||||
assertEquals(OperandType.MEMORY_IMM16, mem1.getType());
|
||||
assertEquals(Operand.IMMEDIATE_VALUE_MEM, mem1.getValue());
|
||||
assertEquals(12, mem1.getData());
|
||||
|
||||
Operand mem2 = new Operand("[-12 ]", labels, registerSet, 0);
|
||||
assertEquals(OperandType.MEMORY_IMM16, mem2.getType());
|
||||
assertEquals(Operand.IMMEDIATE_VALUE_MEM, mem2.getValue());
|
||||
assertEquals(-12, mem2.getData());
|
||||
|
||||
Operand mem3 = new Operand(" [ 0xABCD]", labels, registerSet, 0);
|
||||
assertEquals(OperandType.MEMORY_IMM16, mem3.getType());
|
||||
assertEquals(Operand.IMMEDIATE_VALUE_MEM, mem3.getValue());
|
||||
assertEquals(0xABCD, mem3.getData());
|
||||
|
||||
Operand mem4 = new Operand("[ label1 ]", labels, registerSet, 0);
|
||||
assertEquals(OperandType.MEMORY_IMM16, mem4.getType());
|
||||
assertEquals(Operand.IMMEDIATE_VALUE_MEM, mem4.getValue());
|
||||
assertEquals(10, mem4.getData());
|
||||
|
||||
//Memory Reg
|
||||
Operand mem5 = new Operand("[ A ]", labels, registerSet, 0);
|
||||
assertEquals(OperandType.MEMORY_REG16, mem5.getType());
|
||||
assertEquals(1 + registerSet.size(), mem5.getValue());
|
||||
assertEquals(0, mem5.getData());
|
||||
|
||||
Operand mem6 = new Operand("[ B ]", labels, registerSet, 0);
|
||||
assertEquals(OperandType.MEMORY_REG16, mem6.getType());
|
||||
assertEquals(2 + registerSet.size(), mem6.getValue());
|
||||
assertEquals(0, mem6.getData());
|
||||
|
||||
//Memory Reg + displacement
|
||||
Operand mem7 = new Operand("[ A + 1 ]", labels, registerSet, 0);
|
||||
assertEquals(OperandType.MEMORY_REG_DISP16, mem7.getType());
|
||||
assertEquals(1 + 2 * registerSet.size(), mem7.getValue());
|
||||
assertEquals(1, mem7.getData());
|
||||
|
||||
Operand mem8 = new Operand("[ B + label1 ]", labels, registerSet, 0);
|
||||
assertEquals(OperandType.MEMORY_REG_DISP16, mem8.getType());
|
||||
assertEquals(2 + 2 * registerSet.size(), mem8.getValue());
|
||||
assertEquals(10, mem8.getData());
|
||||
|
||||
Operand mem9 = new Operand("[ BP + 1 ]", labels, registerSet, 0);
|
||||
assertEquals(OperandType.MEMORY_REG_DISP16, mem9.getType());
|
||||
assertEquals(8 + 2 * registerSet.size(), mem9.getValue());
|
||||
assertEquals(1, mem9.getData());
|
||||
|
||||
|
||||
} catch (InvalidOperandException e) {
|
||||
fail("Failed trying to parse a valid operand");
|
||||
}
|
||||
|
||||
//Invalid operands
|
||||
try{ new Operand("aa", labels, registerSet, 0); } catch (InvalidOperandException e){}
|
||||
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){}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package net.simon987.server.assembly;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class RegisterSetTest {
|
||||
@Test
|
||||
public void getIndex() {
|
||||
|
||||
RegisterSet registerSet = new RegisterSet();
|
||||
|
||||
Register r1 = new Register("R1");
|
||||
Register r2 = new Register("R2");
|
||||
|
||||
registerSet.put(1, r1);
|
||||
registerSet.put(2, r2);
|
||||
|
||||
assertEquals(1, registerSet.getIndex("R1"));
|
||||
assertEquals(2, registerSet.getIndex("R2"));
|
||||
|
||||
assertEquals(-1, registerSet.getIndex("Unknown register name"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getRegister() {
|
||||
|
||||
RegisterSet registerSet = new RegisterSet();
|
||||
|
||||
Register r1 = new Register("R1");
|
||||
Register r2 = new Register("R2");
|
||||
|
||||
registerSet.put(1, r1);
|
||||
registerSet.put(2, r2);
|
||||
|
||||
assertEquals(r1, registerSet.getRegister("R1"));
|
||||
assertEquals(r1, registerSet.getRegister(1));
|
||||
|
||||
assertEquals(r2, registerSet.getRegister("R2"));
|
||||
assertEquals(r2, registerSet.getRegister(2));
|
||||
|
||||
//Test unknown registers
|
||||
assertEquals(null, registerSet.getRegister("Unknown"));
|
||||
assertEquals(null, registerSet.getRegister(3));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void get() {
|
||||
RegisterSet registerSet = new RegisterSet();
|
||||
|
||||
Register r1 = new Register("R1");
|
||||
|
||||
registerSet.put(1, r1);
|
||||
|
||||
r1.setValue(10);
|
||||
assertEquals(10, registerSet.get(1));
|
||||
|
||||
//Test unknown indexes
|
||||
assertEquals(0, registerSet.get(2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void set() {
|
||||
|
||||
RegisterSet registerSet = new RegisterSet();
|
||||
|
||||
Register r1 = new Register("R1");
|
||||
|
||||
registerSet.put(1, r1);
|
||||
registerSet.set(1, 10);
|
||||
|
||||
assertEquals(10, r1.getValue());
|
||||
|
||||
//Test unknown indexes
|
||||
registerSet.set(3, 10);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
package net.simon987.server.assembly.instruction;
|
||||
|
||||
import net.simon987.server.ServerConfiguration;
|
||||
import net.simon987.server.assembly.Memory;
|
||||
import net.simon987.server.assembly.Register;
|
||||
import net.simon987.server.assembly.RegisterSet;
|
||||
import net.simon987.server.assembly.Status;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
|
||||
public class AddInstructionTest {
|
||||
|
||||
|
||||
/**
|
||||
* ADD mem/reg, mem/reg
|
||||
*/
|
||||
@Test
|
||||
public void addTargetTarget() {
|
||||
ServerConfiguration config = new ServerConfiguration("config.properties");
|
||||
int memorySize = config.getInt("memory_size");
|
||||
|
||||
//Memory
|
||||
Memory memory = new Memory(memorySize);
|
||||
memory.clear();
|
||||
|
||||
//RegisterSet
|
||||
RegisterSet registerSet = new RegisterSet();
|
||||
registerSet.put(1, new Register("T1"));
|
||||
registerSet.put(2, new Register("T2"));
|
||||
registerSet.clear();
|
||||
|
||||
//Status
|
||||
Status status = new Status();
|
||||
status.clear();
|
||||
|
||||
AddInstruction addInstruction = new AddInstruction();
|
||||
|
||||
//ADD mem, mem
|
||||
//Positive numbers
|
||||
memory.set(0, 10);
|
||||
memory.set(1, 10);
|
||||
addInstruction.execute(memory, 0, memory, 1, status);
|
||||
assertEquals(20, memory.get(0));
|
||||
assertEquals(10, memory.get(1));
|
||||
assertEquals(10, memory.get(1));
|
||||
//FLAGS Should be CF=0 ZF=0 SF=0 OF=0
|
||||
assertFalse(status.isSignFlag());
|
||||
assertFalse(status.isZeroFlag());
|
||||
assertFalse(status.isCarryFlag());
|
||||
assertFalse(status.isOverflowFlag());
|
||||
assertFalse(status.isBreakFlag());
|
||||
|
||||
memory.clear();
|
||||
memory.set(memorySize - 1, 10);
|
||||
memory.set(1, 10);
|
||||
addInstruction.execute(memory, memorySize - 1, memory, 1, status);
|
||||
assertEquals(20, memory.get(memorySize - 1));
|
||||
assertEquals(10, memory.get(1));
|
||||
//FLAGS Should be CF=0 ZF=0 SF=0 OF=0
|
||||
assertFalse(status.isSignFlag());
|
||||
assertFalse(status.isZeroFlag());
|
||||
assertFalse(status.isCarryFlag());
|
||||
assertFalse(status.isOverflowFlag());
|
||||
assertFalse(status.isBreakFlag());
|
||||
|
||||
//Large positive numbers
|
||||
memory.clear();
|
||||
memory.set(0, 2);
|
||||
memory.set(1, 0xFFFF);
|
||||
addInstruction.execute(memory, memorySize, memory, 1, status);
|
||||
assertEquals(1, memory.get(0));
|
||||
assertEquals(0xFFFF, memory.get(1));
|
||||
//FLAGS Should be CF=1 ZF=0 SF=0 OF=0
|
||||
assertFalse(status.isSignFlag());
|
||||
assertFalse(status.isZeroFlag());
|
||||
assertTrue(status.isCarryFlag());
|
||||
assertFalse(status.isOverflowFlag());
|
||||
assertFalse(status.isBreakFlag());
|
||||
|
||||
//Zero result
|
||||
memory.clear();
|
||||
memory.set(0, 1);
|
||||
memory.set(1, 0xFFFF);
|
||||
addInstruction.execute(memory, memorySize, memory, 1, status);
|
||||
assertEquals(0, memory.get(0));
|
||||
assertEquals(0xFFFF, memory.get(1));
|
||||
//FLAGS Should be CF=1 ZF=1 SF=0 OF=0
|
||||
assertTrue(status.isCarryFlag());
|
||||
assertTrue(status.isZeroFlag());
|
||||
assertFalse(status.isSignFlag());
|
||||
assertFalse(status.isOverflowFlag());
|
||||
assertFalse(status.isBreakFlag());
|
||||
|
||||
//Overflow
|
||||
memory.clear();
|
||||
memory.set(0, 0x8000);
|
||||
memory.set(1, 0xFFFF);
|
||||
addInstruction.execute(memory, 0, memory, 1, status);
|
||||
assertEquals(0x7FFF, memory.get(0));
|
||||
assertEquals(0xFFFF, memory.get(1));
|
||||
//FLAGS Should be CF=1 ZF=0 SF=0 OF=1
|
||||
assertTrue(status.isCarryFlag());
|
||||
assertFalse(status.isZeroFlag());
|
||||
assertFalse(status.isSignFlag());
|
||||
assertTrue(status.isOverflowFlag());
|
||||
assertFalse(status.isBreakFlag());
|
||||
|
||||
//ADD reg, reg
|
||||
//Positive numbers
|
||||
registerSet.set(1, 10);
|
||||
registerSet.set(2, 10);
|
||||
addInstruction.execute(registerSet, 1, registerSet, 2, status);
|
||||
assertEquals(20, registerSet.get(1));
|
||||
assertEquals(10, registerSet.get(2));
|
||||
//FLAGS Should be CF=0 ZF=0 SF=0 OF=0
|
||||
assertFalse(status.isSignFlag());
|
||||
assertFalse(status.isZeroFlag());
|
||||
assertFalse(status.isCarryFlag());
|
||||
assertFalse(status.isOverflowFlag());
|
||||
assertFalse(status.isBreakFlag());
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ADD mem/reg, imm
|
||||
*/
|
||||
@Test
|
||||
public void addTargetImm() {
|
||||
ServerConfiguration config = new ServerConfiguration("config.properties");
|
||||
int memorySize = config.getInt("memory_size");
|
||||
|
||||
//Memory
|
||||
Memory memory = new Memory(memorySize);
|
||||
memory.clear();
|
||||
|
||||
//Status
|
||||
Status status = new Status();
|
||||
status.clear();
|
||||
|
||||
AddInstruction addInstruction = new AddInstruction();
|
||||
|
||||
//Positive number
|
||||
memory.clear();
|
||||
memory.set(0, 10);
|
||||
addInstruction.execute(memory, 0, 10, status);
|
||||
assertEquals(20, memory.get(0));
|
||||
//FLAGS Should be CF=0 ZF=0 SF=0 OF=0
|
||||
assertFalse(status.isSignFlag());
|
||||
assertFalse(status.isZeroFlag());
|
||||
assertFalse(status.isCarryFlag());
|
||||
assertFalse(status.isOverflowFlag());
|
||||
assertFalse(status.isBreakFlag());
|
||||
|
||||
//The rest is assumed to work since it is tested with addTargetTarget() and behavior shouldn't be different;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package net.simon987.server.assembly.instruction;
|
||||
|
||||
import net.simon987.server.ServerConfiguration;
|
||||
import net.simon987.server.assembly.Memory;
|
||||
import net.simon987.server.assembly.Status;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
|
||||
public class AndInstructionTest {
|
||||
@Test
|
||||
public void executeTargetTarget() {
|
||||
|
||||
ServerConfiguration config = new ServerConfiguration("config.properties");
|
||||
int memorySize = config.getInt("memory_size");
|
||||
|
||||
//Memory
|
||||
Memory memory = new Memory(memorySize);
|
||||
memory.clear();
|
||||
|
||||
//Status
|
||||
Status status = new Status();
|
||||
status.clear();
|
||||
|
||||
AndInstruction andInstruction = new AndInstruction();
|
||||
|
||||
//mem mem
|
||||
memory.clear();
|
||||
memory.set(0, 0xF010);
|
||||
memory.set(1, 0xF111);
|
||||
andInstruction.execute(memory, 0, memory, 1, status);
|
||||
|
||||
assertEquals(0xF010, memory.get(0));
|
||||
assertEquals(true, status.isSignFlag());
|
||||
assertEquals(false, status.isZeroFlag());
|
||||
assertEquals(false, status.isOverflowFlag());
|
||||
assertEquals(false, status.isCarryFlag());
|
||||
|
||||
//mem mem
|
||||
memory.clear();
|
||||
memory.set(0, 0x1010);
|
||||
memory.set(1, 0x0101);
|
||||
andInstruction.execute(memory, 0, memory, 1, status);
|
||||
|
||||
assertEquals(0, memory.get(0));
|
||||
assertEquals(false, status.isSignFlag());
|
||||
assertEquals(true, status.isZeroFlag());
|
||||
assertEquals(false, status.isOverflowFlag());
|
||||
assertEquals(false, status.isCarryFlag());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void executeTargetImm() {
|
||||
|
||||
ServerConfiguration config = new ServerConfiguration("config.properties");
|
||||
int memorySize = config.getInt("memory_size");
|
||||
|
||||
//Memory
|
||||
Memory memory = new Memory(memorySize);
|
||||
memory.clear();
|
||||
|
||||
//Status
|
||||
Status status = new Status();
|
||||
status.clear();
|
||||
|
||||
AndInstruction andInstruction = new AndInstruction();
|
||||
|
||||
//mem imm
|
||||
memory.clear();
|
||||
memory.set(0, 0x1010);
|
||||
andInstruction.execute(memory, 0, 0x0101, status);
|
||||
|
||||
assertEquals(0, memory.get(0));
|
||||
assertEquals(false, status.isSignFlag());
|
||||
assertEquals(true, status.isZeroFlag());
|
||||
assertEquals(false, status.isOverflowFlag());
|
||||
assertEquals(false, status.isCarryFlag());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package net.simon987.server.assembly.instruction;
|
||||
|
||||
import net.simon987.server.assembly.Status;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class BrkInstructionTest {
|
||||
@Test
|
||||
public void execute() throws Exception {
|
||||
|
||||
//Status
|
||||
Status status = new Status();
|
||||
status.clear();
|
||||
|
||||
BrkInstruction brkInstruction = new BrkInstruction();
|
||||
|
||||
brkInstruction.execute(status);
|
||||
|
||||
assertEquals(true, status.isBreakFlag());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package net.simon987.server.assembly.instruction;
|
||||
|
||||
import net.simon987.server.ServerConfiguration;
|
||||
import net.simon987.server.assembly.*;
|
||||
import net.simon987.server.user.User;
|
||||
import org.junit.Test;
|
||||
|
||||
public class CallInstructionTest {
|
||||
|
||||
|
||||
@Test
|
||||
public void execute() throws Exception {
|
||||
|
||||
ServerConfiguration config = new ServerConfiguration("config.properties");
|
||||
int memorySize = config.getInt("memory_size");
|
||||
|
||||
//Memory
|
||||
Memory memory = new Memory(memorySize);
|
||||
memory.clear();
|
||||
|
||||
//RegisterSet
|
||||
RegisterSet registerSet = new RegisterSet();
|
||||
registerSet.put(1, new Register("T1"));
|
||||
registerSet.put(2, new Register("T2"));
|
||||
registerSet.clear();
|
||||
|
||||
//Status
|
||||
Status status = new Status();
|
||||
status.clear();
|
||||
|
||||
CPU cpu = new CPU(config, new User());
|
||||
|
||||
CallInstruction callInstruction = new CallInstruction(cpu);
|
||||
|
||||
//We have to check if IP is 'pushed' correctly (try to pop it), the
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void execute1() throws Exception {
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user