diff --git a/.gitignore b/.gitignore index a5b1113..a007f0d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +.vscode .gradle **/build/ !src/**/build/ @@ -19,3 +20,24 @@ gradle-app.setting .project # JDT-specific (Eclipse Java Development Tools) .classpath + +# Compiled class file +*.class + +# Log file +*.log + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +*.minisig + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* +replay_pid* diff --git a/README.md b/README.md index d97f036..8aa618a 100644 --- a/README.md +++ b/README.md @@ -52,14 +52,17 @@ classDiagram Computer --> ProgramCounter Program <-- ArrayList Program : +toString() - Memory <|-- LongMemory - Word <|-- LongWord + Memory --|> LongMemory + Word --|> LongWord ``` ```mermaid classDiagram + class Operand { + + Word getValue() + } class Instruction { + void execute(Memory memory, ProgramCounter pc) # String opcode() @@ -73,8 +76,9 @@ classDiagram class JumpEq class Mul class Print - Instruction --|> Word - Instruction --|> Address + Instruction *-- Operand + Operand <|-- Word + Operand <|-- Address Add --|> Instruction Copy --|> Instruction Halt --|> Instruction diff --git a/app/src/main/java/hatelace/Address.java b/app/src/main/java/hatelace/Address.java index fb4d249..f914865 100644 --- a/app/src/main/java/hatelace/Address.java +++ b/app/src/main/java/hatelace/Address.java @@ -1,6 +1,6 @@ package hatelace; -public class Address { +public class Address implements Operand { int address; public Address(int address) { @@ -14,4 +14,8 @@ public class Address { public String toString() { return Integer.toString(address); } + + public Word getWord(Memory memory) { + return memory.read(this); + } } diff --git a/app/src/main/java/hatelace/Instruction.java b/app/src/main/java/hatelace/Instruction.java index 43d5bfb..f7d04be 100644 --- a/app/src/main/java/hatelace/Instruction.java +++ b/app/src/main/java/hatelace/Instruction.java @@ -1,8 +1,11 @@ package hatelace; -public interface Instruction { - void execute(Memory memory, ProgramCounter pc); - String opcode(); - Object[] operands(); - String toString(); +public abstract class Instruction { + public abstract void execute(Memory memory, ProgramCounter pc); + + protected abstract String opcode(); + + protected abstract Object[] operands(); + + public abstract String toString(); } diff --git a/app/src/main/java/hatelace/Operand.java b/app/src/main/java/hatelace/Operand.java new file mode 100644 index 0000000..bcdc6be --- /dev/null +++ b/app/src/main/java/hatelace/Operand.java @@ -0,0 +1,5 @@ +package hatelace; + +public interface Operand { + Word getWord(Memory memory); +} diff --git a/app/src/main/java/hatelace/Word.java b/app/src/main/java/hatelace/Word.java index 4ac199f..b0bbb17 100644 --- a/app/src/main/java/hatelace/Word.java +++ b/app/src/main/java/hatelace/Word.java @@ -1,11 +1,11 @@ package hatelace; -public interface Word { - T getValue(); - Word add(Word other); - Word subtract(Word other); - Word multiply(Word other); - Word divide(Word other); - String toString(); - boolean equals(Object other); +public abstract class Word implements Operand { + public abstract T getValue(); + public abstract Word add(Word other); + public abstract Word subtract(Word other); + public abstract Word multiply(Word other); + public abstract Word divide(Word other); + public abstract String toString(); + public abstract boolean equals(Object other); } diff --git a/app/src/main/java/hatelace/instructions/Add.java b/app/src/main/java/hatelace/instructions/Add.java index e45609c..1b88504 100644 --- a/app/src/main/java/hatelace/instructions/Add.java +++ b/app/src/main/java/hatelace/instructions/Add.java @@ -2,32 +2,31 @@ package hatelace.instructions; import hatelace.*; -public class Add implements Instruction { - private Address src; - private Word imm; +public class Add extends Instruction { private Address dest; + private Operand o1, o2; /** Add immediate value to memory address. */ - public Add(Address src, Word imm, Address dest) { - this.src = src; - this.imm = imm; + public Add(Operand o1, Operand o2, Address dest) { + this.o1 = o1; + this.o2 = o2; this.dest = dest; } public void execute(Memory memory, ProgramCounter PC) { - memory.write(this.dest, memory.read(this.src).add(this.imm)); + memory.write(this.dest, this.o1.getWord(memory).add(this.o2.getWord(memory))); PC.incPC(); } - public String opcode() { + protected String opcode() { return "ADD"; } public String toString() { - return String.format("%s [%s] %s [%s]", this.opcode(), this.src, this.imm, this.dest); + return String.format("%s [%s] %s [%s]", this.opcode(), this.o1, this.o2, this.dest); } - public Object[] operands() { - return new Object[] { this.src, this.imm, this.dest }; + protected Object[] operands() { + return new Object[] { this.o1, this.o2, this.dest }; } } diff --git a/app/src/main/java/hatelace/instructions/Copy.java b/app/src/main/java/hatelace/instructions/Copy.java index 215b500..a88c27e 100644 --- a/app/src/main/java/hatelace/instructions/Copy.java +++ b/app/src/main/java/hatelace/instructions/Copy.java @@ -2,30 +2,30 @@ package hatelace.instructions; import hatelace.*; -public class Copy implements Instruction { - private Word imm; +public class Copy extends Instruction { + private Operand src; private Address dest; /** Copy immediate value to memory address. */ - public Copy(Word imm, Address dest) { - this.imm = imm; + public Copy(Operand src, Address dest) { + this.src = src; this.dest = dest; } public void execute(Memory memory, ProgramCounter PC) { - memory.write(this.dest, this.imm); + memory.write(this.dest, this.src.getWord(memory)); PC.incPC(); } - public String opcode() { + protected String opcode() { return "CPY"; } - public Object[] operands() { - return new Object[] {this.imm, this.dest}; + protected Object[] operands() { + return new Object[] {this.src, this.dest}; } public String toString() { - return String.format("%s %s [%s]", this.opcode(), this.imm, this.dest); + return String.format("%s %s [%s]", this.opcode(), this.src, this.dest); } } diff --git a/app/src/main/java/hatelace/instructions/Halt.java b/app/src/main/java/hatelace/instructions/Halt.java index 3fc8485..7823e35 100644 --- a/app/src/main/java/hatelace/instructions/Halt.java +++ b/app/src/main/java/hatelace/instructions/Halt.java @@ -2,7 +2,7 @@ package hatelace.instructions; import hatelace.*; -public class Halt implements Instruction { +public class Halt extends Instruction { /** Halts the CPU */ public Halt(){}; @@ -10,11 +10,11 @@ public class Halt implements Instruction { PC.halt(); } - public String opcode() { + protected String opcode() { return "HLT"; } - public Object[] operands() { + protected Object[] operands() { return new Object[] {}; } diff --git a/app/src/main/java/hatelace/instructions/Jump.java b/app/src/main/java/hatelace/instructions/Jump.java index 5761c4c..972945f 100644 --- a/app/src/main/java/hatelace/instructions/Jump.java +++ b/app/src/main/java/hatelace/instructions/Jump.java @@ -2,7 +2,7 @@ package hatelace.instructions; import hatelace.*; -public class Jump implements Instruction { +public class Jump extends Instruction { private int index; /** Unconditional jump, non-relative */ @@ -14,11 +14,11 @@ public class Jump implements Instruction { PC.setPC(this.index); } - public String opcode() { + protected String opcode() { return "JMP"; } - public Object[] operands() { + protected Object[] operands() { return new Object[] {this.index}; } diff --git a/app/src/main/java/hatelace/instructions/JumpEq.java b/app/src/main/java/hatelace/instructions/JumpEq.java index 9152637..a0b27ba 100644 --- a/app/src/main/java/hatelace/instructions/JumpEq.java +++ b/app/src/main/java/hatelace/instructions/JumpEq.java @@ -2,35 +2,35 @@ package hatelace.instructions; import hatelace.*; -public class JumpEq implements Instruction { +public class JumpEq extends Instruction { private int index; - private Address src; - private Word imm; + private Operand o1; + private Operand o2; /** Conditional jump */ - public JumpEq(int index, Address src, Word imm) { + public JumpEq(int index, Operand o1, Operand o2) { this.index = index; - this.src = src; - this.imm = imm; + this.o1 = o1; + this.o2 = o2; } public void execute(Memory memory, ProgramCounter PC) { - if (this.imm.equals(memory.read(this.src))) { + if (this.o1.getWord(memory).equals(this.o2.getWord(memory))) { PC.setPC(this.index); } else { PC.incPC(); } } - public String opcode() { + protected String opcode() { return "JEQ"; } - public Object[] operands() { - return new Object[] {this.index, this.src, this.imm}; + protected Object[] operands() { + return new Object[] {this.index, this.o1, this.o2}; } public String toString() { - return String.format("%s %s [%s] %s", this.opcode(), this.index, this.src, this.imm); + return String.format("%s %s [%s] %s", this.opcode(), this.index, this.o1, this.o2); } } diff --git a/app/src/main/java/hatelace/instructions/Mul.java b/app/src/main/java/hatelace/instructions/Mul.java index 0cf60da..4536682 100644 --- a/app/src/main/java/hatelace/instructions/Mul.java +++ b/app/src/main/java/hatelace/instructions/Mul.java @@ -2,32 +2,32 @@ package hatelace.instructions; import hatelace.*; -public class Mul implements Instruction { - private Address src1; - private Address src2; +public class Mul extends Instruction { + private Operand o1; + private Operand o2; private Address dest; /** Multiply contents of two addresses and store the result in a third memory address. */ - public Mul(Address src1, Address src2, Address dest) { - this.src1 = src1; - this.src2 = src2; + public Mul(Operand o1, Operand o2, Address dest) { + this.o1 = o1; + this.o2 = o2; this.dest = dest; } public void execute(Memory memory, ProgramCounter PC) { - memory.write(this.dest, memory.read(this.src1).multiply(memory.read(this.src2))); + memory.write(this.dest, this.o1.getWord(memory).multiply(this.o2.getWord(memory))); PC.incPC(); } - public String opcode() { + protected String opcode() { return "MUL"; } - public Object[] operands() { - return new Object[] { this.src1, this.src2, this.dest }; + protected Object[] operands() { + return new Object[] { this.o1, this.o2, this.dest }; } public String toString() { - return String.format("%s [%s] [%s] [%s]", this.opcode(), this.src1, this.src2, this.dest); + return String.format("%s [%s] [%s] [%s]", this.opcode(), this.o1, this.o2, this.dest); } } diff --git a/app/src/main/java/hatelace/instructions/Print.java b/app/src/main/java/hatelace/instructions/Print.java index f73ce0b..17e7ce6 100644 --- a/app/src/main/java/hatelace/instructions/Print.java +++ b/app/src/main/java/hatelace/instructions/Print.java @@ -2,7 +2,7 @@ package hatelace.instructions; import hatelace.*; -public class Print implements Instruction { +public class Print extends Instruction { private Address address; /** Print content of memory address */ @@ -15,11 +15,11 @@ public class Print implements Instruction { PC.incPC(); } - public String opcode() { + protected String opcode() { return "PRT"; } - public Object[] operands() { + protected Object[] operands() { return new Object[] { this.address }; } diff --git a/app/src/main/java/hatelace/memtypes/IntWord.java b/app/src/main/java/hatelace/memtypes/IntWord.java index eea0583..ba8402d 100644 --- a/app/src/main/java/hatelace/memtypes/IntWord.java +++ b/app/src/main/java/hatelace/memtypes/IntWord.java @@ -1,8 +1,9 @@ package hatelace.memtypes; +import hatelace.Memory; import hatelace.Word; -public class IntWord implements Word { +public class IntWord extends Word { private Integer value; public IntWord(Integer value) { @@ -15,6 +16,11 @@ public class IntWord implements Word { return value; } + @Override + public Word getWord(Memory memory) { + return this; + } + public Word add(Word other) { return new IntWord(value + (Integer) other.getValue()); } diff --git a/app/src/main/java/hatelace/memtypes/LongWord.java b/app/src/main/java/hatelace/memtypes/LongWord.java index adb8855..272ffd5 100644 --- a/app/src/main/java/hatelace/memtypes/LongWord.java +++ b/app/src/main/java/hatelace/memtypes/LongWord.java @@ -1,8 +1,9 @@ package hatelace.memtypes; +import hatelace.Memory; import hatelace.Word; -public class LongWord implements Word { +public class LongWord extends Word { private Long value; public LongWord(Long value) { @@ -15,6 +16,11 @@ public class LongWord implements Word { return value; } + @Override + public Word getWord(Memory memory) { + return this; + } + public Word add(Word other) { return new LongWord(value + (Long) other.getValue()); } diff --git a/doc/answers.md b/doc/answers.md new file mode 100644 index 0000000..0112616 --- /dev/null +++ b/doc/answers.md @@ -0,0 +1,15 @@ +1. En interface som alla typer av instruktioner kan ha gemensam borde inte vara helt fel. Vilket i sin tur betyder en klass för varje instruktion där ett instruktions interface implementeras. + +2. Man ärver lämplig collection, ex arraylist. Detta är kass design, då komposition är tydligare. + +3. "Program" och självaste "datorn" borde vara olika paket, paketet "program" rör program som skall köra på datorn, "datorn" har de klasser som är datorn som t.ex. memory och programCounter osv. + +4. Varje instruktion skulle kunna representeras som ett kommando, och datorn skulle utföra dessa kommandon utan att behöva veta exakt vad varje instruktion innebär. På så sätt separeras ansvar, och det blir enklare att lägga till eller ändra instruktioner i framtiden. + +5. Designmönstret Template Method kan vara användbart för att undvika duplicerad kod i likartade klasser, särskilt för de instruktionsklasser som ingår i programmet (t.ex. Copy, JumpEq, Mul, Add, Print, Halt). Eftersom dessa instruktionsklasser kan ha vissa gemensamma delar i hur de utför sin uppgift, kan ett template method-mönster användas för att abstrahera och återanvända gemensam kod. + +6. För att hantera olika sorters operander på ett enhetligt sätt med hjälp av Strategy-mönstret i en datormodell skulle man kunna implementera olika strategier för hur operander ska hanteras. Operander kan vara antingen konstanter eller adresser, och olika instruktioner kräver olika typer av operander. + +7. Additionen bör nog utföras i LongWord. + +8. \ No newline at end of file diff --git a/doc/image1.svg b/doc/image1.svg new file mode 100644 index 0000000..024943f --- /dev/null +++ b/doc/image1.svg @@ -0,0 +1 @@ +
Computer
- Memory memory
- Program program
+Computer(Memory Memory)
+void load(Program program)
+void run()
Memory
+Word read(Address address)
+int size()
+void write(Address address, Word data)
+void dump()
ProgramCounter
- int PC
- int SysTick
- boolean haltFlag
+ProgramCounter()
+ProgramCounter(int PC)
+int getPC()
+int getSysTicks()
+int incPC()
+int setPC(int PC)
+boolean halted()
+void halt()
Program
+toString()
ArrayList
Word
+T getValue()
+Word add(Word other)
+Word subtract(Word other)
+Word multiply(Word other)
+Word divide(Word other)
+String toString()
+boolean equals(Object other)
Address
- int address
+Address(int address)
+int getAddress()
+String toString()
LongMemory
LongWord
\ No newline at end of file diff --git a/doc/image2.svg b/doc/image2.svg new file mode 100644 index 0000000..e604ecd --- /dev/null +++ b/doc/image2.svg @@ -0,0 +1 @@ +
Instruction
+void execute(Memory memory, ProgramCounter pc)
#String opcode()
#Object[] operands()
+String toString()
Add
Copy
Halt
Jump
JumpEq
Mul
Print
Word
Address
\ No newline at end of file diff --git a/doc/image3.svg b/doc/image3.svg new file mode 100644 index 0000000..10b1d86 --- /dev/null +++ b/doc/image3.svg @@ -0,0 +1 @@ +InstructionProgramCounterMemoryProgramComputerInstructionProgramCounterMemoryProgramComputerloop[Instructions Execution]loop[Program Execution]load(program)run()incPC()getPC()executeInstruction()execute(memory, PC)read/write(address)incPC() \ No newline at end of file diff --git a/makefile b/makefile index 19c9fc7..8cca887 100644 --- a/makefile +++ b/makefile @@ -1,3 +1,8 @@ +GITHASH := $(shell git rev-parse --short HEAD)$(shell git diff-index --quiet HEAD || echo "-dirty") + +TARNAME := hatelace-imbus_$(GITHASH).tar.gz +DIRNAME := hatelace + run: ./gradlew run @@ -6,11 +11,35 @@ watch: build: ./gradlew build + ls -lh app/build/libs/*.jar clean: ./gradlew clean + rm -f *.tar.gz *.tar.gz.minisig *.zip *.jpg test: ./gradlew test -.PHONY: run build clean +$(TARNAME): + git archive --format=tar --prefix=$(DIRNAME)/ HEAD > intermediate.tar + tar -f intermediate.tar --delete $(DIRNAME)/doc + gzip -9 -c intermediate.tar > $(TARNAME) + rm intermediate.tar + +$(TARNAME).minisig: $(TARNAME) + minisign -Sm $(TARNAME) + +tar: $(TARNAME) + tar -tvf $(TARNAME) + +sign: $(TARNAME).minisig + +publish: $(TARNAME) $(TARNAME).minisig + @git diff-index --quiet HEAD || (echo "git is dirty, commit changes first"; exit 1) + ssh server mkdir -p /public/$(DIRNAME) + rsync -avz $(TARNAME).minisig server:/public/$(DIRNAME)/$(TARNAME).minisig + rsync -avz $(TARNAME) server:/public/$(DIRNAME)/$(TARNAME) + ssh server ln -sf /public/$(DIRNAME)/$(TARNAME).minisig /public/$(DIRNAME)/latest.tar.gz.minisig + ssh server ln -sf /public/$(DIRNAME)/$(TARNAME) /public/$(DIRNAME)/latest.tar.gz + +.PHONY: run watch build clean test archive sign publish