/* * Copyright 2010 Georgios Migdos <cyberpython@gmail.com>. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * under the License. */ package bmach.logic.processor; import bmach.logic.machine.IMachine; import bmach.logic.memory.IMainMemory; import bmach.logic.memory.IMemoryAddress; import bmach.logic.memory.MemoryAddress; import bmach.logic.programcounter.IProgramCounter; import bmach.logic.programcounter.ProgramCounter; import bmach.logic.registers.IRegister; import bmach.logic.registers.IRegisterAddress; import bmach.logic.registers.Register; import bmach.logic.registers.RegisterAddress; import java.io.PrintStream; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import util.binary.bitpattern.BitPattern; import util.binary.bitpattern.BitPatternOverflowException; import util.binary.bitpattern.BitPatternUtils; import util.binary.bitpattern.ByteBitPattern; import util.binary.bitpattern.IBitPattern; import util.patterns.observer.IObserver; /** * * @author Georgios Migdos <cyberpython@gmail.com> */ public class Processor implements IProcessor { private IMachine machine; private IProgramCounter programCounter; private HashMap<IRegisterAddress, IRegister> registers; private List<IObserver> observers; private ByteBitPattern zero; private IRegisterAddress zeroRegisterAddress; private boolean hasReachedEnd; public Processor() { this.machine = null; this.programCounter = new ProgramCounter(); this.registers = new HashMap<IRegisterAddress, IRegister>(16, 1.0f); this.observers = new ArrayList<IObserver>(); this.hasReachedEnd = false; this.zero = new ByteBitPattern(); this.zeroRegisterAddress = new RegisterAddress("0x" + Integer.toHexString(0)); try{ zero.setValue(0); }catch(Exception e){ } generateRegisters(); } private void generateRegisters() { for (int i = 0; i < 16; i++) { IRegisterAddress address = new RegisterAddress("0x" + Integer.toHexString(i)); registers.put(address, new Register(address)); } } public IRegister getRegister(int registerIndex) { return registers.get(new RegisterAddress("0x" + Integer.toHexString(registerIndex))); } public int getNumberOfRegisters() { return this.registers.size(); } public IProgramCounter getProgramCounter() { return this.programCounter; } public boolean hasReachedEnd() { return this.hasReachedEnd; } public void init(IMachine machine) { this.machine = machine; this.observers.add(machine); this.programCounter.reset(); this.hasReachedEnd = false; for (Iterator<IRegisterAddress> it = registers.keySet().iterator(); it.hasNext();) { IRegisterAddress address = it.next(); IRegister register = registers.get(address); register.setContentValue("00000000"); } notifyObservers(new ProcessorNotificationData("init")); } public void execNext() throws MalformedProcessorInstructionException, BitPatternOverflowException { IMainMemory memory = this.machine.getMemory(); IMemoryAddress instructionAddress = programCounter.get(); IMemoryAddress instructionAddressPlusOne = new MemoryAddress("0x" + Integer.toHexString(Integer.parseInt(instructionAddress.toHexString().substring(2), 16) + 1)); IBitPattern byte1 = memory.get(instructionAddress).getContent(); IBitPattern byte2 = memory.get(instructionAddressPlusOne).getContent(); String opCode = byte1.toBinaryString().substring(0, 4); String register = byte1.toBinaryString().substring(4, 8); IMemoryAddress pcVal = programCounter.get(); if (opCode.equals("0001") || opCode.equals("0010") || opCode.equals("0011") || opCode.equals("1011")) { if (opCode.equals("0001")) {// 0x1 : LOAD from memory IMemoryAddress src = new MemoryAddress(byte2.toBinaryString()); IRegisterAddress dest = new RegisterAddress(register); load(src, dest); } else if (opCode.equals("0010")) {// 0x2 : LOAD bit pattern IRegisterAddress dest = new RegisterAddress(register); load(byte2, dest); } else if (opCode.equals("0011")) {// 0x3 : STORE to memory IRegisterAddress src = new RegisterAddress(register); IMemoryAddress dest = new MemoryAddress(byte2.toBinaryString()); store(src, dest); } else {// 0xB : JUMP to target if address contents == contents at register 0 IRegisterAddress address = new RegisterAddress(register); IMemoryAddress target = new MemoryAddress(byte2.toBinaryString()); jump(address, target); } } else { String op1 = byte2.toBinaryString().substring(0, 4); String op2 = byte2.toBinaryString().substring(4, 8); if (opCode.equals("0100")) {// 0x4 : MOVE from R to S IRegisterAddress src = new RegisterAddress(op1); IRegisterAddress dest = new RegisterAddress(op2); move(src, dest); } else if (opCode.equals("0101")) {// 0x5 : ADD S and T ans save to R try { IRegisterAddress src1 = new RegisterAddress(op1); IRegisterAddress src2 = new RegisterAddress(op2); IRegisterAddress dest = new RegisterAddress(register); add(src1, src2, dest); } catch (BitPatternOverflowException boe) { notifyObservers(new ProcessorNotificationData(boe)); throw boe; } } else if (opCode.equals("0110")) {// 0x6 : ADD floats in S and T ans save to R try { IRegisterAddress src1 = new RegisterAddress(op1); IRegisterAddress src2 = new RegisterAddress(op2); IRegisterAddress dest = new RegisterAddress(register); addFloat(src1, src2, dest); } catch (BitPatternOverflowException boe) { notifyObservers(new ProcessorNotificationData(boe)); throw boe; } } else if (opCode.equals("0111")) {// 0x7 : OR S and T ans save to R try { IRegisterAddress src1 = new RegisterAddress(op1); IRegisterAddress src2 = new RegisterAddress(op2); IRegisterAddress dest = new RegisterAddress(register); or(src1, src2, dest); } catch (BitPatternOverflowException boe) { notifyObservers(new ProcessorNotificationData(boe)); throw boe; } } else if (opCode.equals("1000")) {// 0x8 : AND S and T ans save to R try { IRegisterAddress src1 = new RegisterAddress(op1); IRegisterAddress src2 = new RegisterAddress(op2); IRegisterAddress dest = new RegisterAddress(register); and(src1, src2, dest); } catch (BitPatternOverflowException boe) { notifyObservers(new ProcessorNotificationData(boe)); throw boe; } } else if (opCode.equals("1001")) {// 0x9 : XOR S and T ans save to R try { IRegisterAddress src1 = new RegisterAddress(op1); IRegisterAddress src2 = new RegisterAddress(op2); IRegisterAddress dest = new RegisterAddress(register); xor(src1, src2, dest); } catch (BitPatternOverflowException boe) { notifyObservers(new ProcessorNotificationData(boe)); throw boe; } } else if (opCode.equals("1010")) {// 0xA : ROTATE R right X times IRegisterAddress address = new RegisterAddress(register); int times = Integer.parseInt(op2, 2); rotate(address, times); } else if (opCode.equals("1100")) {// 0xC : HALT hasReachedEnd = true; halt(); } else { MalformedProcessorInstructionException mpie = new MalformedProcessorInstructionException(new BitPattern(16, byte1.toBinaryString() + byte2.toBinaryString())); notifyObservers(new ProcessorNotificationData(mpie)); throw mpie; } } notifyObservers(new ProcessorNotificationData(new BitPattern(24, pcVal.toBinaryString() + byte1.toBinaryString() + byte2.toBinaryString()))); } public void halt() { machine.halt(); notifyObservers(new ProcessorNotificationData("halt")); } public void load(IMemoryAddress src, IRegisterAddress dest) { String newValue = machine.getMemory().get(src).getContent().toBinaryString(); registers.get(dest).setContentValue(newValue); programCounter.inc(); } public void load(IBitPattern value, IRegisterAddress dest) { registers.get(dest).setContentValue(value.toBinaryString()); programCounter.inc(); } public void store(IRegisterAddress src, IMemoryAddress dest) { String newValue = registers.get(src).getContent().toBinaryString(); machine.getMemory().get(dest).setContentValue(newValue); programCounter.inc(); } public void move(IRegisterAddress src, IRegisterAddress dest) { String newValue = registers.get(src).getContent().toBinaryString(); registers.get(dest).setContentValue(newValue); programCounter.inc(); } public void add(IRegisterAddress src1, IRegisterAddress src2, IRegisterAddress dest) throws BitPatternOverflowException { IBitPattern value1 = registers.get(src1).getContent(); IBitPattern value2 = registers.get(src2).getContent(); registers.get(dest).setContentValue(BitPattern.add(value1, value2).toBinaryString()); programCounter.inc(); } public void addFloat(IRegisterAddress src1, IRegisterAddress src2, IRegisterAddress dest) throws BitPatternOverflowException { IBitPattern value1 = registers.get(src1).getContent(); IBitPattern value2 = registers.get(src2).getContent(); registers.get(dest).setContentValue(BitPatternUtils.addFloats(value1, value2).toBinaryString()); programCounter.inc(); } public void and(IRegisterAddress src1, IRegisterAddress src2, IRegisterAddress dest) throws BitPatternOverflowException { IBitPattern value1 = registers.get(src1).getContent(); IBitPattern value2 = registers.get(src2).getContent(); registers.get(dest).setContentValue(BitPattern.and(value1, value2).toBinaryString()); programCounter.inc(); } public void or(IRegisterAddress src1, IRegisterAddress src2, IRegisterAddress dest) throws BitPatternOverflowException { IBitPattern value1 = registers.get(src1).getContent(); IBitPattern value2 = registers.get(src2).getContent(); registers.get(dest).setContentValue(BitPattern.or(value1, value2).toBinaryString()); programCounter.inc(); } public void xor(IRegisterAddress src1, IRegisterAddress src2, IRegisterAddress dest) throws BitPatternOverflowException { IBitPattern value1 = registers.get(src1).getContent(); IBitPattern value2 = registers.get(src2).getContent(); registers.get(dest).setContentValue(BitPattern.xor(value1, value2).toBinaryString()); programCounter.inc(); } public void rotate(IRegisterAddress address, int times) { IBitPattern registerContent = registers.get(address).getContent(); for (int i = 0; i < times; i++) { registerContent.rotateRight(); } registers.get(address).setContentValue(registerContent.toBinaryString()); programCounter.inc(); } public void jump(IRegisterAddress address, IMemoryAddress target) { IBitPattern op1 = registers.get(address).getContent(); IBitPattern op2 = registers.get(zeroRegisterAddress).getContent(); if (op2.compareTo(op1) == 0) { programCounter.set(target); } else { programCounter.inc(); } } public void addObserver(IObserver observer) { if (!this.observers.contains(observer)) { this.observers.add(observer); } } public void removeObserver(IObserver observer) { this.observers.remove(observer); } public void notifyObservers(Object notificationData) { for (Iterator<IObserver> it = observers.iterator(); it.hasNext();) { IObserver iObserver = it.next(); iObserver.notifyObserver(notificationData); } } public void printRegistersHex(PrintStream out) { for (int i = 0; i < 16; i++) { out.println(String.format("Register[%1$2d]: %2$s", i, registers.get(new RegisterAddress("0x" + Integer.toHexString(i))).getContent().toHexString())); } } public void printRegistersBinary(PrintStream out) { for (int i = 0; i < 16; i++) { out.println(String.format("Register[%1$2d]: %2$s", i, registers.get(new RegisterAddress("0x" + Integer.toHexString(i))).getContent().toBinaryString())); } } }