copyleft: gplv3 added and set repo to public
[calu.git] / 3b_sim / ccpu.cpp
1 /*   `Deep Thought', a softcore CPU implemented on a FPGA
2
3     Copyright (C) 2010 Markus Hofstaetter <markus.manrow@gmx.at>
4     Copyright (C) 2010 Martin Perner <e0725782@student.tuwien.ac.at>
5     Copyright (C) 2010 Stefan Rebernig <stefan.rebernig@gmail.com>
6     Copyright (C) 2010 Manfred Schwarz <e0725898@student.tuwien.ac.at>
7     Copyright (C) 2010 Bernhard Urban <lewurm@gmail.com>
8
9     This program is free software: you can redistribute it and/or modify
10     it under the terms of the GNU General Public License as published by
11     the Free Software Foundation, either version 3 of the License, or
12     (at your option) any later version.
13
14     This program is distributed in the hope that it will be useful,
15     but WITHOUT ANY WARRANTY; without even the implied warranty of
16     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17     GNU General Public License for more details.
18
19     You should have received a copy of the GNU General Public License
20     along with this program.  If not, see <http://www.gnu.org/licenses/>. */
21
22 #include "ccpu.hpp"
23
24 /*              CDat m_pc, m_pc_next;
25                 CMem m_regfile, m_ram;
26 */
27
28 //void registerExtension() {};
29
30 const char* expression = "(;.*)|(r0)|(rX)|(r1[0-5])|(r[1-5])|(r[6-9])|(0x[a-fA-F0-9]+)|([-]?\\d+)";
31 const char* format = "(?1$&)"
32                                         //Return-Register: violett
33                                         "(?2\033[0m\033[35m$&\033[0m\\3:)"
34                                         // Callee-saved Register: rot
35                                         "(?4\033[0m\033[31m$&\033[0m\\3:)"
36                                         //Argument-Register: gruen
37                                         "(?5\033[0m\033[32m$&\033[0m\\3:)"
38                                         // Temporary Register: gelb
39                                         "(?6\033[0m\033[33m$&\033[0m\\3:)"
40                                         // Zahlenwerte: tuerkis
41                                         "(?7\033[0m\033[36m$&\033[0m\\3:)"
42                                         "(?8\033[0m\033[36m$&\033[0m\\3:)";
43
44
45 string CCpu::colorifyInstr(string instr)
46 {
47         boost::regex e;
48         e.assign(expression);
49         return boost::regex_replace(instr, e, format, boost::match_default | boost::format_all);
50 }
51
52 void CCpu::registerExtension(Iext* ext)
53 {
54         m_exts.push_back(ext);
55 }
56
57 void CCpu::applyToExtensions(const vector<string>& in)
58 {
59         for(auto iter = m_exts.begin(); iter != m_exts.end(); ++iter) {
60                 (*iter)->parseInput(in);
61         }
62 }
63
64 void CCpu::breakNext()
65 {
66         m_breakNext = true;
67 }
68
69 bool CCpu::shouldBreak()
70 {
71         return m_breakNext;
72 }
73
74 void CCpu::tick()
75 {
76         // signal extensions
77         // Todo
78
79         m_pc = m_pc_next;
80         m_pc_next += 4;
81         Iinstr* instr = this->getProg(m_pc);
82
83         if(instr == NULL) {
84                 throw string("Out of Instructions!");
85         }
86
87         for(auto iter = m_exts.begin(); iter != m_exts.end(); ++iter) {
88                 (*iter)->applyTick();
89         }
90
91         if(this->conditionMet(instr->getCondition())) {
92                 cout << color(green,black) << "Executing: " << color(white,black) << colorifyInstr(instr->toString()) << " (0x" << std::hex << m_pc << std::dec << ")" << endl;
93                 instr->execInstr();
94                 this->incPerfBy(instr->getClockCount());
95         }
96         else {
97                 cout << color(red,black) << "Didn't Execute " << color(white,black) << colorifyInstr(instr->toString()) << "; condition wasn't met" << endl;
98                 this->incPerf();
99         }
100
101 }
102
103 bool CCpu::conditionMet(short cond)
104 {
105         switch(cond) {
106                 case NOT_EQUAL:
107                         return !this->m_Z;
108                         break;
109                 case EQUAL:
110                         return this->m_Z;
111                         break;
112                 case NOT_OVERFLOW:
113                         return !this->m_O;
114                         break;
115                 case OVER_FLOW:
116                         return this->m_O;
117                         break;
118                 case NOT_CARRY:
119                         return !this->m_C;
120                         break;
121                 case CARRY:
122                         return this->m_C;
123                         break;
124                 case NOT_SIGNED:
125                         return !this->m_S;
126                         break;
127                 case SIGNED:
128                         return this->m_S;
129                         break;
130                 case ABOVE:
131                         return (!this->m_C && !this->m_Z);
132                         break;
133                 case BELOW_EQ:
134                         return (this->m_C || this->m_Z);
135                         break;
136                 case GREATER_EQ:
137                         return (this->m_S == this->m_O);
138                         break;
139                 case LESS:
140                         return (this->m_S != this->m_O);
141                         break;
142                 case GREATER:
143                         return (!this->m_Z && (this->m_S == this->m_O));
144                         break;
145                 case LESS_EQ:
146                         return (!this->m_Z || (this->m_S != this->m_O));
147                         break;
148                 case ALWAYS:
149                         return true;
150                         break;
151                 case NEVER:
152                         return false;
153                         break;
154                 default:
155                         cerr << "What did you do? more than 16 values in 5 bits?!" << endl;
156                         return false;
157         }
158
159 }
160
161 CDat CCpu::getNextPC() const
162 {
163         return m_pc_next;
164 }
165
166 CDat CCpu::getCurPC() const
167 {
168         return m_pc;
169 }
170
171 void CCpu::setNextPC(CDat val)
172 {
173         m_pc_next = val;
174 }
175
176 CDat CCpu::getFlags() const {
177         CDat psw = 0;
178         psw += (this->m_Z ? 1 : 0);
179         psw += (this->m_O ? 2 : 0);
180         psw += (this->m_C ? 4 : 0);
181         psw += (this->m_S ? 8 : 0);
182         return psw;
183 }
184
185 void CCpu::setFlags(CDat psw) {
186         this->m_Z = ((psw & 0x1) != 0);
187         this->m_O = ((psw & 0x2) != 0);
188         this->m_C = ((psw & 0x4) != 0);
189         this->m_S = ((psw & 0x8) != 0);
190 }
191
192 void CCpu::updateFlags(CDat val) {
193         this->m_Z = (val == 0);
194         this->m_S = ((val >> (BIT_LEN-1)) & 0x1);
195 /*      this->m_C = false;
196         this->m_O = false; */
197 }
198
199 void CCpu::updateFlags(CDatd val, CDat a, CDat b) {
200         this->m_Z = (val == 0);
201         this->m_S = ((val >> (BIT_LEN-1)) & 0x1);
202         this->m_C = ((val >> (BIT_LEN)) & 0x1);
203         bool a_31 = ((a >> (BIT_LEN-1)) & 0x1);
204         bool b_31 = ((b >> (BIT_LEN-1)) & 0x1);
205         bool val_31 = ((val >> (BIT_LEN-1)) & 0x1);
206         this->m_O = ((a_31 && b_31 && !val_31) || (!a_31 && !b_31 && val_31));
207 }
208
209 void CCpu::updateCarry(bool c)
210 {
211         this->m_C = c;
212 }
213
214 bool CCpu::getCarry()
215 {
216         return this->m_C;
217 }
218
219 void CCpu::updateFlags(bool z, bool o, bool c, bool s)
220 {
221         this->m_Z = z;
222         this->m_O = o;
223         this->m_C = c;
224         this->m_S = s;
225 }
226
227 CDat CCpu::getRegister(const int addr) const
228 {
229         return m_reg.getDirect(addr);
230 }
231
232 void CCpu::setRegister(const int addr, CDat data)
233 {
234         m_reg.setDirect(addr, data);
235 }
236
237 CDat CCpu::getRAM(const int addr) const
238 {
239         if((addr & EXT_MODEL_OFFSET) == 0) {
240                 return m_ram.get(addr);
241         }
242         else {
243                 CDat result = 0;
244                 for(auto iter = m_exts.begin(); iter != m_exts.end(); ++iter) {
245                         result = (*iter)->readData(addr);
246                         if(result != 0) {
247                                 break;
248                         }
249                 }
250                 return result;
251         }
252 }
253
254 void CCpu::setRAM(const int addr, CDat data)
255 {
256         if((addr & EXT_MODEL_OFFSET) == 0) {
257                 m_ram.set(addr, data);
258         }
259         else {
260                 for(auto iter = m_exts.begin(); iter != m_exts.end(); ++iter) {
261                         (*iter)->loadData(addr, data);
262                 }
263         }
264 }
265
266 void CCpu::setProg(int addr, Iinstr* instr)
267 {
268         m_prog.set(addr, instr);
269 }
270
271 Iinstr* CCpu::getProg(const int addr) const
272 {
273         return m_prog.get(addr);
274 }
275
276 int CCpu::getStack() const
277 {
278         return this->m_stack;
279 }
280
281 void CCpu::setStack(const int val)
282 {
283         this->m_stack = val;
284 }
285
286 CDat CCpu::getPerf() const
287 {
288         return this->m_perf;
289 }
290
291 void CCpu::setPerf(CDat val)
292 {
293         this->m_perf = val;
294 }
295
296 void CCpu::incPerf()
297 {
298         this->m_perf++;
299 }
300
301 void CCpu::incPerfBy(short inc)
302 {
303         this->m_perf += inc;
304 }
305
306
307 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)
308 {
309 }
310
311