Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/push pop all feature #28

Open
wants to merge 11 commits into
base: dev
Choose a base branch
from
Prev Previous commit
Next Next commit
Add new syscall ability
  • Loading branch information
erikik8090 committed Mar 21, 2019
commit fb497a1086abf63f30e015bd9df50d08e4d09566
16 changes: 15 additions & 1 deletion src/il/co/codeguru/corewars_riscv/cpu/riscv/CpuRiscV.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
package il.co.codeguru.corewars_riscv.cpu.riscv;

import il.co.codeguru.corewars_riscv.cpu.exceptions.CpuException;
import il.co.codeguru.corewars_riscv.cpu.riscv.rv32i.instruction_formats.InstructionFormatBase;
import il.co.codeguru.corewars_riscv.cpu.riscv.rv32c.InstructionDecoderRv32c;
import il.co.codeguru.corewars_riscv.cpu.riscv.rv32c.instruction_formats.CInstructionFormatBase;
import il.co.codeguru.corewars_riscv.cpu.riscv.rv32i.InstructionDecoder32I;
import il.co.codeguru.corewars_riscv.cpu.riscv.rv32i.InstructionRunner32I;
import il.co.codeguru.corewars_riscv.cpu.riscv.rv32i.instruction_formats.InstructionFormatBase;
import il.co.codeguru.corewars_riscv.features.Syscall;
import il.co.codeguru.corewars_riscv.memory.Memory;
import il.co.codeguru.corewars_riscv.memory.MemoryException;
import il.co.codeguru.corewars_riscv.utils.Logger;

import java.util.ArrayList;
import java.util.List;

public class CpuRiscV {

Expand All @@ -16,6 +21,7 @@ public class CpuRiscV {
private InstructionDecoder32I decoder;
private InstructionDecoderRv32c cDecoder;
private InstructionRunner32I runner;
private List<Syscall> syscalls = new ArrayList<>();

public CpuStateRiscV getState() {
return state;
Expand Down Expand Up @@ -62,4 +68,12 @@ private boolean tryRv32cSet() throws CpuException, MemoryException
return i!=null;
}

public void registerSyscall(int id, Syscall syscall) {
this.syscalls.add(id, syscall);
}

public void callSyscall(int id) {
this.syscalls.get(id).call(this);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ public Instruction decode(InstructionFormat format_input) throws InvalidOpcodeEx
(InstructionFormatBase format, InstructionRunner32I runner) -> runner.lui(new InstructionFormatU(format)));
case RV32I.OpcodeTypes.BRANCH:
return branchOpcode(i);
case RV32I.OpcodeTypes.SYS:
return sysOpcode(i);
case RV32I.OpcodeTypes.JALR:
return new Instruction(RV32I.Opcodes.Jalr, new InstructionFormatI(i),
(InstructionFormatBase format, InstructionRunner32I runner) -> runner.jalr(new InstructionFormatI(format)));
Expand All @@ -38,6 +40,19 @@ public Instruction decode(InstructionFormat format_input) throws InvalidOpcodeEx
}
}

private Instruction sysOpcode(InstructionFormatBase i) throws InvalidOpcodeException {
InstructionFormatI ii = new InstructionFormatI(i);
switch(ii.getFunct3()) {
case 0:
if(ii.getImmediate() == 0) {
return new Instruction(RV32I.Opcodes.Ecall, ii,
(InstructionFormatBase format, InstructionRunner32I runner) -> runner.ecall(new InstructionFormatI(format)));
}
default:
throw new InvalidOpcodeException();
}
}

private Instruction branchOpcode(InstructionFormatBase i) throws InvalidOpcodeException {
InstructionFormatSB sb = new InstructionFormatSB(i);
switch(sb.getFunct3())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,18 @@
import il.co.codeguru.corewars_riscv.cpu.riscv.rv32i.instruction_formats.*;
import il.co.codeguru.corewars_riscv.memory.Memory;
import il.co.codeguru.corewars_riscv.memory.MemoryException;
import il.co.codeguru.corewars_riscv.utils.Logger;

public class InstructionRunner32I {

private CpuRiscV cpu;
private CpuStateRiscV state;
private Memory memory;

public InstructionRunner32I(CpuRiscV cpu) {
this.state = cpu.getState();
this.memory = cpu.getMemory();
this.cpu = cpu;
}

/**
Expand Down Expand Up @@ -315,6 +318,10 @@ void bgeu(InstructionFormatSB i) {
}


void ecall(InstructionFormatI i) {
cpu.callSyscall(state.getReg(8));
}

private void jump(CpuStateRiscV state, int immediate, int instructionSize) {
state.setPc(state.getPc() + immediate - instructionSize);
}
Expand Down
4 changes: 4 additions & 0 deletions src/il/co/codeguru/corewars_riscv/cpu/riscv/rv32i/RV32I.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ public final class OpcodeTypes {
public static final int LUI = 0x37;
public static final int JALR = 0x67;
public static final int JAL = 0x6f;
public static final int SYS = 0x73;
}

public static final class Opcodes{
Expand Down Expand Up @@ -74,6 +75,9 @@ public static final class Opcodes{
public static Instruction.InstructionInfo Auipc= new Instruction.InstructionInfo("Auipc",OpcodeTypes.AUIPC);
public static Instruction.InstructionInfo Jal = new Instruction.InstructionInfo("Jal",OpcodeTypes.JAL);
public static Instruction.InstructionInfo Jalr = new Instruction.InstructionInfo("Jalr",OpcodeTypes.JALR);

//System
public static Instruction.InstructionInfo Ecall= new Instruction.InstructionInfo("Ecall",OpcodeTypes.SYS, 0);
}

}
2 changes: 0 additions & 2 deletions src/il/co/codeguru/corewars_riscv/features/NewMemory.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import il.co.codeguru.corewars_riscv.memory.MemoryBus;
import il.co.codeguru.corewars_riscv.memory.MemoryRegion;
import il.co.codeguru.corewars_riscv.memory.RawMemory;
import il.co.codeguru.corewars_riscv.utils.Logger;
import il.co.codeguru.corewars_riscv.war.Warrior;

import java.util.HashMap;
Expand All @@ -29,7 +28,6 @@ public void initWarriorGroup(Warrior... warriors) {

warrior.getCpuState().setReg(2, StackMemory.m_start);
warrior.getCpuState().setReg(3, SharedMemory.m_start);

}
}
}
Expand Down
5 changes: 4 additions & 1 deletion src/il/co/codeguru/corewars_riscv/features/Syscall.java
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
package il.co.codeguru.corewars_riscv.features;

public class Syscall {
import il.co.codeguru.corewars_riscv.cpu.riscv.CpuRiscV;

public abstract class Syscall {
public abstract void call(CpuRiscV cpuRiscV);
}
119 changes: 68 additions & 51 deletions src/il/co/codeguru/corewars_riscv/war/Warrior.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,58 @@
import il.co.codeguru.corewars_riscv.cpu.exceptions.CpuException;
import il.co.codeguru.corewars_riscv.cpu.riscv.CpuRiscV;
import il.co.codeguru.corewars_riscv.cpu.riscv.CpuStateRiscV;
import il.co.codeguru.corewars_riscv.memory.*;
import il.co.codeguru.corewars_riscv.memory.Memory;
import il.co.codeguru.corewars_riscv.memory.MemoryBus;
import il.co.codeguru.corewars_riscv.memory.MemoryException;
import il.co.codeguru.corewars_riscv.memory.MemoryRegion;

import static il.co.codeguru.corewars_riscv.war.War.*;
import static il.co.codeguru.corewars_riscv.war.War.ARENA_SIZE;


/**
* A single CoreWars warrior.
*
*
* @author DL
*/
public class Warrior
{
public final MemoryRegion arenaRegion = new MemoryRegion(0, ARENA_SIZE -1);
public class Warrior {
public final MemoryRegion arenaRegion = new MemoryRegion(0, ARENA_SIZE - 1);
public final int m_myIndex; // in the War m_warriors array. used for identifying breakpoints
private final MemoryBus bus = new MemoryBus();
/**
* Warrior's name
*/
private final String m_name;
private final String m_label;
/**
* Warrior's initial code size
*/
private final int m_codeSize;
/**
* Warrior's initial load address
*/
private final int m_loadAddress;
private int teamId;
/**
* Current state of registers & flags
*/
private CpuStateRiscV m_state;
/**
* CPU instance
*/
private CpuRiscV m_cpu;
/**
* Whether or not the warrior is still alive
*/
private boolean m_isAlive;

/**
* Constructor.
* @param name Warrior's name.
* @param codeSize Warrior's code size.
* @param teamId
* @param core Real mode memory used as core.
* @param loadAddress Warrior's load address in the core (initial CS:IP).
*
* @param name Warrior's name.
* @param codeSize Warrior's code size.
* @param teamId Warrior's team id
* @param core Real mode memory used as core.
* @param loadAddress Warrior's load address in the core (initial CS:IP).
*/
public Warrior(
String name,
Expand All @@ -34,8 +63,7 @@ public Warrior(
int teamId,
Memory core,
int loadAddress,
int myIndex)
{
int myIndex) {
m_label = label; // this comes from Code label
m_name = name;
m_codeSize = codeSize;
Expand All @@ -50,13 +78,7 @@ public Warrior(

m_cpu = new CpuRiscV(m_state, bus);

m_isAlive = true;
}

// Quick and dirty hack for creating a seam for unit testing
public void setCpu(CpuRiscV cpu)
{
m_cpu = cpu;
m_isAlive = true;
}

/**
Expand All @@ -71,14 +93,15 @@ public boolean isAlive() {
*/
public void kill() {
m_isAlive = false;
}
}

/**
* @return the warrior's name.
*/
public String getName() {
return m_name;
}

public String getLabel() {
return m_label;
}
Expand All @@ -87,8 +110,9 @@ public String getLabel() {
* @return the warrior's load offset.
*/
public short getLoadOffset() {
return (short)(m_loadAddress);
return (short) (m_loadAddress);
}

public int getLoadOffsetInt() {
return m_loadAddress & 0xFFFF;
}
Expand All @@ -107,29 +131,29 @@ public int getCodeSize() {
public short getEnergy() {
return 0;
}
public void setEnergy(short value) { }

public void setEnergy(short value) {
}

/**
* Performs the warrior's next turn (= next InstructionInfo).
* @throws CpuException on any CPU error.
* @throws MemoryException on any RawMemory error.
*
* @throws CpuException on any CPU error.
* @throws MemoryException on any RawMemory error.
*/
public void nextOpcode() throws CpuException, MemoryException {
m_cpu.nextOpcode();
if(m_cpu.getState().getPc() >= ARENA_SIZE || m_cpu.getState().getPc() < 0)
{
if (m_cpu.getState().getPc() >= ARENA_SIZE || m_cpu.getState().getPc() < 0) {
throw new MemoryException("Warrior " + m_name + " tried to execute instructions outside of the arena");
}
}

/**
* Initializes the CpuRiscV registers & flags:
* <p>
* x1 and PC - To the warriors load address in the memory
*
* x1 and PC - To the warriors load address in the memory
* x2 - The stack
* x3 - The shared memory between the players in the team
*
* @param loadAddress Warrior's load address in the core.
* @param loadAddress Warrior's load address in the core.
*/
private void initializeCpuState(int loadAddress) {
int loadIndex = (loadAddress) & 0xFFFF;
Expand All @@ -138,26 +162,10 @@ private void initializeCpuState(int loadAddress) {
m_state.setPc(loadIndex);
m_state.setReg(1, loadIndex);
}

public CpuStateRiscV getCpuState(){
return m_state;
}

/** Warrior's name */
private final String m_name;
private final String m_label;
/** Warrior's initial code size */
private final int m_codeSize;
/** Warrior's initial load address */
private final int m_loadAddress;
/** Current state of registers & flags */
private CpuStateRiscV m_state;
/** CPU instance */
private CpuRiscV m_cpu;
/** Whether or not the warrior is still alive */
private boolean m_isAlive;

public final int m_myIndex; // in the War m_warriors array. used for identifying breakpoints
public CpuStateRiscV getCpuState() {
return m_state;
}

public MemoryBus getBus() {
return bus;
Expand All @@ -166,4 +174,13 @@ public MemoryBus getBus() {
public int getTeamId() {
return teamId;
}

public CpuRiscV getCpu() {
return m_cpu;
}

// Quick and dirty hack for creating a seam for unit testing
public void setCpu(CpuRiscV cpu) {
m_cpu = cpu;
}
}
13 changes: 6 additions & 7 deletions test/il/co/codeguru/corewars_riscv/features/FeatureSetTest.java
Original file line number Diff line number Diff line change
@@ -1,24 +1,23 @@
package il.co.codeguru.corewars_riscv.features;

import il.co.codeguru.corewars_riscv.war.Warrior;
import org.junit.Assert;
import org.junit.Test;

public class FeatureSetTest {

@Test
public void registerSingleTest() {
FeatureSet set = new FeatureSet();
Feature f = new Feature();
class EmptyFeature extends Feature {

set.register("new-feature", f);
@Override
public void initWarriorGroup(Warrior... warriors) {

Assert.assertArrayEquals(new Feature[]{f}, set.getRegisterdFeatures());
}
}

@Test
public void enableSingleTest() {
FeatureSet set = new FeatureSet();
Feature f = new Feature();
Feature f = new EmptyFeature();
set.register("new-feature", f);

set.enableFeature("new-feature");
Expand Down