/* `Deep Thought', a softcore CPU implemented on a FPGA Copyright (C) 2010 Markus Hofstaetter Copyright (C) 2010 Martin Perner Copyright (C) 2010 Stefan Rebernig Copyright (C) 2010 Manfred Schwarz Copyright (C) 2010 Bernhard Urban This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "ccpu.hpp" /* CDat m_pc, m_pc_next; CMem m_regfile, m_ram; */ //void registerExtension() {}; const char* expression = "(;.*)|(r0)|(rX)|(r1[0-5])|(r[1-5])|(r[6-9])|(0x[a-fA-F0-9]+)|([-]?\\d+)"; const char* format = "(?1$&)" //Return-Register: violett "(?2\033[0m\033[35m$&\033[0m\\3:)" // Callee-saved Register: rot "(?4\033[0m\033[31m$&\033[0m\\3:)" //Argument-Register: gruen "(?5\033[0m\033[32m$&\033[0m\\3:)" // Temporary Register: gelb "(?6\033[0m\033[33m$&\033[0m\\3:)" // Zahlenwerte: tuerkis "(?7\033[0m\033[36m$&\033[0m\\3:)" "(?8\033[0m\033[36m$&\033[0m\\3:)"; string CCpu::colorifyInstr(string instr) { boost::regex e; e.assign(expression); return boost::regex_replace(instr, e, format, boost::match_default | boost::format_all); } void CCpu::registerExtension(Iext* ext) { m_exts.push_back(ext); } void CCpu::applyToExtensions(const vector& in) { for(auto iter = m_exts.begin(); iter != m_exts.end(); ++iter) { (*iter)->parseInput(in); } } void CCpu::breakNext() { m_breakNext = true; } bool CCpu::shouldBreak() { return m_breakNext; } void CCpu::tick() { // signal extensions // Todo m_pc = m_pc_next; m_pc_next += 4; Iinstr* instr = this->getProg(m_pc); if(instr == NULL) { throw string("Out of Instructions!"); } for(auto iter = m_exts.begin(); iter != m_exts.end(); ++iter) { (*iter)->applyTick(); } if(this->conditionMet(instr->getCondition())) { cout << color(green,black) << "Executing: " << color(white,black) << colorifyInstr(instr->toString()) << " (0x" << std::hex << m_pc << std::dec << ")" << endl; instr->execInstr(); this->incPerfBy(instr->getClockCount()); } else { cout << color(red,black) << "Didn't Execute " << color(white,black) << colorifyInstr(instr->toString()) << "; condition wasn't met" << endl; this->incPerf(); } } bool CCpu::conditionMet(short cond) { switch(cond) { case NOT_EQUAL: return !this->m_Z; break; case EQUAL: return this->m_Z; break; case NOT_OVERFLOW: return !this->m_O; break; case OVER_FLOW: return this->m_O; break; case NOT_CARRY: return !this->m_C; break; case CARRY: return this->m_C; break; case NOT_SIGNED: return !this->m_S; break; case SIGNED: return this->m_S; break; case ABOVE: return (!this->m_C && !this->m_Z); break; case BELOW_EQ: return (this->m_C || this->m_Z); break; case GREATER_EQ: return (this->m_S == this->m_O); break; case LESS: return (this->m_S != this->m_O); break; case GREATER: return (!this->m_Z && (this->m_S == this->m_O)); break; case LESS_EQ: return (!this->m_Z || (this->m_S != this->m_O)); break; case ALWAYS: return true; break; case NEVER: return false; break; default: cerr << "What did you do? more than 16 values in 5 bits?!" << endl; return false; } } CDat CCpu::getNextPC() const { return m_pc_next; } CDat CCpu::getCurPC() const { return m_pc; } void CCpu::setNextPC(CDat val) { m_pc_next = val; } CDat CCpu::getFlags() const { CDat psw = 0; psw += (this->m_Z ? 1 : 0); psw += (this->m_O ? 2 : 0); psw += (this->m_C ? 4 : 0); psw += (this->m_S ? 8 : 0); return psw; } void CCpu::setFlags(CDat psw) { this->m_Z = ((psw & 0x1) != 0); this->m_O = ((psw & 0x2) != 0); this->m_C = ((psw & 0x4) != 0); this->m_S = ((psw & 0x8) != 0); } void CCpu::updateFlags(CDat val) { this->m_Z = (val == 0); this->m_S = ((val >> (BIT_LEN-1)) & 0x1); /* this->m_C = false; this->m_O = false; */ } void CCpu::updateFlags(CDatd val, CDat a, CDat b) { this->m_Z = (val == 0); this->m_S = ((val >> (BIT_LEN-1)) & 0x1); this->m_C = ((val >> (BIT_LEN)) & 0x1); bool a_31 = ((a >> (BIT_LEN-1)) & 0x1); bool b_31 = ((b >> (BIT_LEN-1)) & 0x1); bool val_31 = ((val >> (BIT_LEN-1)) & 0x1); this->m_O = ((a_31 && b_31 && !val_31) || (!a_31 && !b_31 && val_31)); } void CCpu::updateCarry(bool c) { this->m_C = c; } bool CCpu::getCarry() { return this->m_C; } void CCpu::updateFlags(bool z, bool o, bool c, bool s) { this->m_Z = z; this->m_O = o; this->m_C = c; this->m_S = s; } CDat CCpu::getRegister(const int addr) const { return m_reg.getDirect(addr); } void CCpu::setRegister(const int addr, CDat data) { m_reg.setDirect(addr, data); } CDat CCpu::getRAM(const int addr) const { if((addr & EXT_MODEL_OFFSET) == 0) { return m_ram.get(addr); } else { CDat result = 0; for(auto iter = m_exts.begin(); iter != m_exts.end(); ++iter) { result = (*iter)->readData(addr); if(result != 0) { break; } } return result; } } void CCpu::setRAM(const int addr, CDat data) { if((addr & EXT_MODEL_OFFSET) == 0) { m_ram.set(addr, data); } else { for(auto iter = m_exts.begin(); iter != m_exts.end(); ++iter) { (*iter)->loadData(addr, data); } } } void CCpu::setProg(int addr, Iinstr* instr) { m_prog.set(addr, instr); } Iinstr* CCpu::getProg(const int addr) const { return m_prog.get(addr); } int CCpu::getStack() const { return this->m_stack; } void CCpu::setStack(const int val) { this->m_stack = val; } CDat CCpu::getPerf() const { return this->m_perf; } void CCpu::setPerf(CDat val) { this->m_perf = val; } void CCpu::incPerf() { this->m_perf++; } void CCpu::incPerfBy(short inc) { this->m_perf += inc; } CCpu::CCpu(int regs, int ram, int prog) : m_Z(false), m_S(false), m_C(false), m_O(false), m_breakNext(0), m_pc(0), m_pc_next(0), m_perf(0), m_reg(regs), m_ram(ram), m_prog(prog), m_exts(0), m_stack(0) { }