Skip to content
Snippets Groups Projects
Commit 2bcc55ec authored by Tim Miller's avatar Tim Miller
Browse files

ADD: Source for SWEN90006 Assignment 1, 2018.

parent 29802a87
Branches
No related tags found
No related merge requests found
Showing
with 493 additions and 0 deletions
File added
<project name="Project" default="classes">
<target name="classes">
<mkdir dir="classes" />
<javac srcdir="src:test" destdir="classes"
classpath="lib/junit-4.11.jar;lib/hamcrest-core-1.3.jar"
includeantruntime="false"/>
</target>
<target name="clean">
<delete dir="classes" />
</target>
<target name="run" depends="classes">
<java classname="swen90006.machine.SimpleDriver"
classpath="classes/;lib/junit-4.11.jar;lib/hamcrest-core-1.3.jar">
</java>
</target>
<target name="partitioning" depends="classes">
<junit printsummary="yes" fork="yes" haltonfailure="yes">
<classpath>
<pathelement path="classes/"/>
<pathelement path="lib/junit-4.11.jar"/>
<pathelement path="lib/hamcrest-core-1.3.jar"/>
</classpath>
<formatter type="plain"/>
<test name="swen90006.machine.PartitioningTests"/>
</junit>
</target>
<target name="boundary" depends="classes">
<junit printsummary="yes" fork="yes" haltonfailure="yes">
<classpath>
<pathelement path="classes/"/>
<pathelement path="lib/junit-4.11.jar"/>
<pathelement path="lib/hamcrest-core-1.3.jar"/>
</classpath>
<formatter type="plain"/>
<test name="swen90006.machine.BoundaryTests"/>
</junit>
</target>
</project>
File added
File added
File added
File added
File added
File added
File added
;; array program. Fills an array with the values 0 ... N-1
;; and then interates through the array, summing its elements
;; global constants:
;; R3 holds 'N', the length of the array
;; R2 holds 1, the increment value used below
MOV R3 10 ; N = 10
MOV R2 1 ;
;; create the array
;; local variables
;; R1 holds 'i', which is a counter from 0 .. N-1
;; R0 holds 'p', the address of the array's ith element
MOV R1 0 ; i = 0;
MOV R0 100
SUB R4 R3 R1 ; while(i != N)
JZ R4 5 ; {
STR R0 0 R1 ; *p = i;
ADD R1 R1 R2 ; i = i + 1;
ADD R0 R0 R2 ; p = p + 1;
JMP -5 ; }
;; sum up the array
;; local variables
;; R1 holds 'i', which is a counter from 0 .. N-1
;; R0 holds 'p', the address of the array's ith element
;; R5 holds 'sum', which always holds the sum of the array's first i elements
MOV R1 0 ; i = 0;
MOV R0 100
MOV R5 0 ; sum = 0;
SUB R4 R3 R1 ; while(i != N)
JZ R4 6 ; {
LDR R4 R0 0 ;
ADD R5 R5 R4 ; sum = sum + *p;
ADD R0 R0 R2 ; p = p + 1;
ADD R1 R1 R2 ; i = i + 1;
JMP -6 ; }
RET R5 ; return sum;
;; factorial program, to calculate N!
;; global constants:
;; R3 holds 'N', the thing we are computing factorial of
;; R2 holds 1, the increment value used below
MOV R3 12 ; N = 12
MOV R2 1 ;
;; local variables
;; R1 holds 'i', which is a counter from 0 .. N
;; R0 holds 'n', which is always equal to i!
MOV R1 0 ; i = 0;
MOV R0 1 ; n = 1;
;; program body
;; loop invariant (see SWEN90010 next semester): n = i!
SUB R4 R3 R1 ; while(i != N)
JZ R4 4 ; {
ADD R1 R1 R2 ; i = i + 1;
MUL R0 R0 R1 ; n = n * i;
JMP -4 ; }
RET R0 ; return n;
File added
File added
File added
package swen90006.machine;
public class BugException extends Exception {
public BugException(String msg){
super("You triggered one of the security bugs!\n" + msg);
}
}
package swen90006.machine;
public class InvalidInstructionException extends RuntimeException
{
public String toString()
{
return "InvalidInstructionException";
}
}
package swen90006.machine;
import java.util.Arrays;
import java.util.List;
public class Machine
{
/** arithmetic instructions each take three registers as arguments with the
* destination register appearing first
*/
/** add rd rs1 rs2 =~ rd = rs1 + rs2 */
public static final String INSTRUCTION_ADD = "add";
/** sub rd rs1 rs2 =~ rd = rs1 - rs2 */
public static final String INSTRUCTION_SUBTRACT = "sub";
/** mul rd rs1 rs2 =~ rd = rs1 * rs2 */
public static final String INSTRUCTION_MULT = "mul";
/** div rd rs1 rs2 =~ rd = rs1 / rs2 */
public static final String INSTRUCTION_DIVIDE = "div";
/** ret rs =~ return rs */
public static final String INSTRUCTION_RETURN = "ret";
/** ldr rd rs offs =~ rd = rs[offs] */
public static final String INSTRUCTION_LOAD = "ldr";
/** str ra offs rb =~ ra[offs] = rb */
public static final String INSTRUCTION_STORE = "str";
/** mov rd val =~ rd = val */
public static final String INSTRUCTION_MOVE = "mov";
/** jmp offs =~ pc = pc + offs */
public static final String INSTRUCTION_JUMP = "jmp";
/** jz ra offs =~ if (ra == 0) pc = pc + offs else pc = pc + 1 */
public static final String INSTRUCTION_JZ = "jz";
public static final int NUM_REGS = 32;
public static final int MAX_REG = (NUM_REGS - 1);
public static final int MEMORY_SIZE = 65536; /* 4 x as much memory as a 64 */
public static final int MAX_ADDR = MEMORY_SIZE-1;
private int[] memory;
private int[] regs;
private int count = 0; /* counts number of instructions executed so far */
public Machine()
{
memory = new int[MEMORY_SIZE];
regs = new int[NUM_REGS];
count = 0;
}
private void do_add(int dest, int src1, int src2)
{
regs[dest] = regs[src1] + regs[src2];
}
private void do_sub(int dest, int src1, int src2)
{
regs[dest] = regs[src1] - regs[src2];
}
private void do_mult(int dest, int src1, int src2)
{
regs[dest] = regs[src1] * regs[src2];
}
private void do_div(int dest, int src1, int src2)
{
if (regs[src2] == 0){
/* no op */
}else{
regs[dest] = regs[src1] / regs[src2];
}
}
private void do_load(int dest, int src, int offs) {
if (regs[src] + offs > MAX_ADDR){
/* no op */
}else if(regs[src] + offs < 0){
/* no op */
}else{
regs[dest] = memory[regs[src] + offs];
}
}
private void do_store(int a, int offs, int b) {
if (regs[a] + offs > MAX_ADDR){
/* no op */
}else if(regs[a] + offs < 0){
/* no op */
}else{
memory[regs[a] + offs] = regs[b];
}
}
private void do_move(int rd, int val){
regs[rd] = val;
}
private int parseReg(String s) throws InvalidInstructionException
{
if (s.length() < 2){
throw new InvalidInstructionException();
}
if (s.charAt(0) != 'r'){
throw new InvalidInstructionException();
}
String numstr = s.substring(1);
int num = 0;
try {
num = Integer.parseInt(numstr);
} catch (Exception e){
throw new InvalidInstructionException();
}
validate_reg(num);
return num;
}
private int parseOffset(String s)
throws InvalidInstructionException
{
int num = 0;
try {
num = Integer.parseInt(s);
} catch (Exception e){
throw new InvalidInstructionException();
}
validate_offset(num);
return num;
}
private void validate_reg(int reg)
throws InvalidInstructionException
{
if (reg < 0 || reg > MAX_REG) {
throw new InvalidInstructionException();
}
}
private void validate_offset(int offset)
throws InvalidInstructionException
{
if (offset < -MAX_ADDR || offset > MAX_ADDR) {
throw new InvalidInstructionException();
}
}
/** Execute an assembly program.
*
* @param prog is the program to execute as an iterable collection of strings,
* each of which is a single instruction.
* @return the program's return value.
* @throws Exception when program has unrecognised or
* invalid instructions, or when it returns no result when it finishes
*/
int execute(List<String> instructions)
throws InvalidInstructionException,
NoReturnValueException
{
int instructionsExecuted = 0;
int pc = 0;
final int progLength = instructions.size();
while(true){
if (pc < 0 || pc >= progLength){
/* will cause NoReturnValueException to be thrown
* but that is not a bug and and indeed is what the
* VM is supposed to do if the pc becomes negative,
* since in this case the program's execution
* finishes early without a return value having
* been produced. */
break;
}
String inst = instructions.get(pc);
/* strip leading and trailing whitespace */
inst = inst.toLowerCase().replaceAll("^\\s+","").replaceAll("\\s+$","");
/* strip out any comments */
String[] toks = inst.split(";");
inst = toks[0];
/* check for blank lines */
if (inst.equals("")){
pc = pc + 1;
count++;
continue;
}
instructionsExecuted++;
/* now tokenize by splitting on whitespace */
toks = inst.split("\\s+");
/* check minimum number of tokens */
if (toks.length < 2){
throw new InvalidInstructionException();
}
if (toks[0].equals(INSTRUCTION_ADD)){
if (toks.length != 4){
throw new InvalidInstructionException();
}
int rd = parseReg(toks[1]);
int rs1 = parseReg(toks[2]);
int rs2 = parseReg(toks[3]);
do_add(rd,rs1,rs2);
} else if (toks[0].equals(INSTRUCTION_SUBTRACT)){
if (toks.length != 4){
throw new InvalidInstructionException();
}
int rd = parseReg(toks[1]);
int rs1 = parseReg(toks[2]);
int rs2 = parseReg(toks[3]);
do_sub(rd,rs1,rs2);
} else if (toks[0].equals(INSTRUCTION_MULT)){
if (toks.length != 4){
throw new InvalidInstructionException();
}
int rd = parseReg(toks[1]);
int rs1 = parseReg(toks[2]);
int rs2 = parseReg(toks[3]);
do_mult(rd,rs1,rs2);
} else if (toks[0].equals(INSTRUCTION_DIVIDE)){
if (toks.length != 4){
throw new InvalidInstructionException();
}
int rd = parseReg(toks[1]);
int rs1 = parseReg(toks[2]);
int rs2 = parseReg(toks[3]);
do_div(rd,rs1,rs2);
} else if (toks[0].equals(INSTRUCTION_RETURN)){
int rs = parseReg(toks[1]);
count++;
return regs[rs];
} else if (toks[0].equals(INSTRUCTION_LOAD)){
if (toks.length != 4){
throw new InvalidInstructionException();
}
int rd = parseReg(toks[1]);
int rs = parseReg(toks[2]);
int offs = parseOffset(toks[3]);
do_load(rd,rs,offs);
} else if (toks[0].equals(INSTRUCTION_STORE)){
if (toks.length != 4){
throw new InvalidInstructionException();
}
int ra = parseReg(toks[1]);
int offs = parseOffset(toks[2]);
int rb = parseReg(toks[3]);
do_store(ra,offs,rb);
} else if (toks[0].equals(INSTRUCTION_MOVE)){
if (toks.length != 3){
throw new InvalidInstructionException();
}
int rd = parseReg(toks[1]);
int offs = parseOffset(toks[2]);
do_move(rd,offs);
} else if (toks[0].equals(INSTRUCTION_JUMP)){
if (toks.length != 2){
throw new InvalidInstructionException();
}
int offs = parseOffset(toks[1]);
pc = pc + offs;
count++;
continue; /* avoid default increment of pc below */
} else if (toks[0].equals(INSTRUCTION_JZ)){
if (toks.length != 3){
throw new InvalidInstructionException();
}
int ra = parseReg(toks[1]);
int offs = parseOffset(toks[2]);
if (regs[ra] == 0){
pc = pc + offs;
}else{
pc = pc + 1;
}
count++;
continue; /* avoid default increment the pc below */
} else {
System.err.println("Unrecognised instruction: " + inst);
throw new InvalidInstructionException();
}
count++;
pc = pc + 1;
}
/* got here without returning already... */
throw new NoReturnValueException();
}
/**
* get the number of instructions successfully executed by the VM so far
*/
public int getCount(){
return count;
}
}
package swen90006.machine;
public class NoReturnValueException extends RuntimeException
{
public NoReturnValueException() {}
public String toString()
{
return "NoReturnValueException";
}
}
package swen90006.machine;
import java.nio.charset.Charset;
import java.nio.file.Path;
import java.nio.file.Files;
import java.nio.file.FileSystems;
import java.util.List;
public class SimpleDriver {
private static final int MEMORY_SIZE = Machine.MAX_ADDR+1;
public static void main(String[] args) throws Exception
{
if (args.length != 1){
System.err.println("Usage: java SimpleDriver <inputfile>");
System.err.println("\nMust have 1 argument instead of " + args.length);
System.exit(1);
}
Charset charset = Charset.forName("UTF-8");
List<String> lines = null;
try {
lines = Files.readAllLines(FileSystems.getDefault().getPath(args[0]), charset);
}catch (Exception e){
System.err.println("Invalid input file! (stacktrace follows)");
e.printStackTrace(System.err);
System.exit(1);
}
Machine m = null;
try {
System.out.println("There are this many instructions: " + lines.size());
m = new Machine();
Integer res = null;
res = m.execute(lines);
System.out.println("Program result: " + res + "\n");
} catch (Exception e) {
System.err.println("Exception while executing program. (stacktrace follows)");
e.printStackTrace(System.err);
if (m != null){
System.err.println("Number of instructions executed before exception: " + m.getCount());
}
System.exit(1);
}
}
}
package swen90006.machine;
public class BugException extends Exception {
public BugException(String msg){
super("You triggered one of the security bugs!\n" + msg);
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment