cpu.cc 19 KB
Newer Older
1
//
Benoit Perrot's avatar
Benoit Perrot committed
2
// This file is part of Nolimips, a MIPS simulator with unlimited registers
Benoit Perrot's avatar
Benoit Perrot committed
3
// Copyright (C) 2003, 2004 Benoit Perrot <benoit@lrde.epita.fr>
4
//
Benoit Perrot's avatar
Benoit Perrot committed
5
// Nolimips is free software; you can redistribute it and/or modify
6
7
8
9
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
// 
Benoit Perrot's avatar
Benoit Perrot committed
10
// Nolimips is distributed in the hope that it will be useful,
11
12
13
14
15
16
17
18
// 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, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
19
20
#include <iomanip>

21
22
23
24
25
26
27
28
29
#include "common.hh"

#include "vm/cpu.hh"

#include "inst/all.hh"

namespace vm
{

Benoit Perrot's avatar
Benoit Perrot committed
30
31
32
33
  // --------------------------------------------------------------------------
  // Constructor and destructor
  // --------------------------------------------------------------------------
  Cpu::Cpu(Mmu& mmu, 
Benoit Perrot's avatar
Benoit Perrot committed
34
	   Cp0 &cp0,
Benoit Perrot's avatar
Benoit Perrot committed
35
36
37
38
	   std::istream& istr, 
	   std::ostream& ostr, 
	   bool check_callee_save_p, 
	   bool trace_p):
Benoit Perrot's avatar
Benoit Perrot committed
39
    mmu_(mmu), cp0_(cp0),
Benoit Perrot's avatar
Benoit Perrot committed
40
41
42
    istr_(istr), ostr_(ostr),
    check_callee_save_p_(check_callee_save_p),
    trace_p_(trace_p),
Benoit Perrot's avatar
Benoit Perrot committed
43
44
45
    bubble_(new inst::Sll(inst::Register(inst::Register::general, Cpu::zero),
			  inst::Register(inst::Register::general, Cpu::zero),
			  new inst::IntExp(0)))
Benoit Perrot's avatar
Benoit Perrot committed
46
47
48
49
  {
    reset();
  }

Benoit Perrot's avatar
Benoit Perrot committed
50
51
  Cpu::~Cpu()
  {
Benoit Perrot's avatar
Benoit Perrot committed
52
    delete bubble_;
Benoit Perrot's avatar
Benoit Perrot committed
53
54
  }

Benoit Perrot's avatar
Benoit Perrot committed
55
56
57
58
59
60
  // --------------------------------------------------------------------------
  // Internals
  // --------------------------------------------------------------------------
  void
  Cpu::reset()
  {
Benoit Perrot's avatar
Benoit Perrot committed
61
    halt_ = false;
Benoit Perrot's avatar
Benoit Perrot committed
62
63
64

    // Initialize general purpose registers to 0.
    for (unsigned i = 0; i < 32; ++i)
Benoit Perrot's avatar
Benoit Perrot committed
65
      GPR_[i] = 0;
Benoit Perrot's avatar
Benoit Perrot committed
66
    // Initialize stack pointers to bottom of stack.
Benoit Perrot's avatar
Benoit Perrot committed
67
68
    GPR_[sp] = Memory::stack_bottom;
    GPR_[fp] = Memory::stack_bottom;
Benoit Perrot's avatar
Benoit Perrot committed
69
    // Initialize special registers to 0.
Benoit Perrot's avatar
Benoit Perrot committed
70
71
    lo_ = 0;
    hi_ = 0;
Benoit Perrot's avatar
Benoit Perrot committed
72
    pc_ = 0;
Benoit Perrot's avatar
Benoit Perrot committed
73
74
75
    
    // Initialize pipeline with nops
    for (unsigned i = 0; i < 6; ++i)
Benoit Perrot's avatar
Benoit Perrot committed
76
      pipeline_[i] = bubble_;
Benoit Perrot's avatar
Benoit Perrot committed
77
78
  }

79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
  // --------------------------------------------------------------------------
  // Print operators
  // --------------------------------------------------------------------------
  void
  Cpu::print(std::ostream &os) const
  {
    std::ios_base::fmtflags flags = os.flags (std::ios_base::hex);

    os << "Register Map: \tpc = " << std::setfill('0') << std::setw(8) << pc_ << std::endl
	 << "zero ($0) = " << std::setfill('0') << std::setw(8) << GPR_[zero]
	 << "  t0 ($8) = " << std::setfill('0') << std::setw(8) << GPR_[t0]
	 << "  s0($16) = " << std::setfill('0') << std::setw(8) << GPR_[s0]
	 << "  t8($24) = " << std::setfill('0') << std::setw(8) << GPR_[t8] << std::endl
	 << "  at ($1) = " << std::setfill('0') << std::setw(8) << GPR_[at]
	 << "  t1 ($9) = " << std::setfill('0') << std::setw(8) << GPR_[t1]
	 << "  s1($17) = " << std::setfill('0') << std::setw(8) << GPR_[s1]
	 << "  t9($25) = " << std::setfill('0') << std::setw(8) << GPR_[t9] << std::endl
	 << "  v0 ($2) = " << std::setfill('0') << std::setw(8) << GPR_[v0]
	 << "  t2($10) = " << std::setfill('0') << std::setw(8) << GPR_[t2]
	 << "  s2($18) = " << std::setfill('0') << std::setw(8) << GPR_[s2]
	 << "  k0($26) = " << std::setfill('0') << std::setw(8) << GPR_[k0] << std::endl
	 << "  v1 ($3) = " << std::setfill('0') << std::setw(8) << GPR_[v1]
	 << "  t3($11) = " << std::setfill('0') << std::setw(8) << GPR_[t3]
	 << "  s3($19) = " << std::setfill('0') << std::setw(8) << GPR_[s3]
	 << "  k1($27) = " << std::setfill('0') << std::setw(8) << GPR_[k1] << std::endl
	 << "  a0 ($4) = " << std::setfill('0') << std::setw(8) << GPR_[a0]
	 << "  t4($12) = " << std::setfill('0') << std::setw(8) << GPR_[t4]
	 << "  s4($20) = " << std::setfill('0') << std::setw(8) << GPR_[s4]
	 << "  gp($28) = " << std::setfill('0') << std::setw(8) << GPR_[gp] << std::endl
	 << "  a1 ($5) = " << std::setfill('0') << std::setw(8) << GPR_[a1]
	 << "  t5($13) = " << std::setfill('0') << std::setw(8) << GPR_[t5]
	 << "  s5($21) = " << std::setfill('0') << std::setw(8) << GPR_[s5]
	 << "  sp($29) = " << std::setfill('0') << std::setw(8) << GPR_[sp] << std::endl
	 << "  a2 ($6) = " << std::setfill('0') << std::setw(8) << GPR_[a2]
	 << "  t6($14) = " << std::setfill('0') << std::setw(8) << GPR_[t6]
	 << "  s6($22) = " << std::setfill('0') << std::setw(8) << GPR_[s6]
	 << "  fp($30) = " << std::setfill('0') << std::setw(8) << GPR_[fp] << std::endl
	 << "  a3 ($7) = " << std::setfill('0') << std::setw(8) << GPR_[a3]
	 << "  t7($15) = " << std::setfill('0') << std::setw(8) << GPR_[t7]
	 << "  s7($23) = " << std::setfill('0') << std::setw(8) << GPR_[s7]
	 << "  ra($31) = " << std::setfill('0') << std::setw(8) << GPR_[ra] << std::endl;
    os.flags(flags);
  }

123
124
125
126
127
128
129
  // --------------------------------------------------------------------------
  // Arithmetic instructions
  // --------------------------------------------------------------------------

  void
  Cpu::visit(const inst::Add& add)
  {
Benoit Perrot's avatar
Benoit Perrot committed
130
131
    register_type	a = get_register(add.get_src1 ());
    register_type	b = get_register(add.get_src2 ());
132

Benoit Perrot's avatar
Benoit Perrot committed
133
    register_type	c = a + b;
134
135
136
137
138
    set_register(add.get_dest (), c);
    
    // FIXME: might be accelerated by testing only the sign bit.
    if ((a < 0 && b < 0 && c > 0) ||
	(a > 0 && b > 0 && c < 0))
Benoit Perrot's avatar
Benoit Perrot committed
139
      cp0_.raise_overflow();
140
141
142
143
  }
  void
  Cpu::visit(const inst::Addi& addi)
  {
Benoit Perrot's avatar
Benoit Perrot committed
144
    register_type	a = get_register(addi.get_src ());
145
146
    int		b = addi.get_imm ();

Benoit Perrot's avatar
Benoit Perrot committed
147
    register_type	c = a + b;
148
149
150
151
152
    set_register(addi.get_dest (), c);
    
    // FIXME: might be accelerated by testing only the sign bit.
    if ((a < 0 && b < 0 && c > 0) ||
	(a > 0 && b > 0 && c < 0))
Benoit Perrot's avatar
Benoit Perrot committed
153
      cp0_.raise_overflow();
154
155
156
157
158
  }
  void
  Cpu::visit(const inst::Addu& addu)
  {
    set_register(addu.get_dest (),
Benoit Perrot's avatar
Benoit Perrot committed
159
160
		 get_register(addu.get_src1 ()) +
		 get_register(addu.get_src2 ()));
161
162
163
164
165
  }
  void
  Cpu::visit(const inst::Addiu& addiu)
  {
    set_register(addiu.get_dest (),
Benoit Perrot's avatar
Benoit Perrot committed
166
		 get_register(addiu.get_src ()) + addiu.get_imm ());
167
168
169
170
171
  }

  void
  Cpu::visit(const inst::Sub& sub)
  {
Benoit Perrot's avatar
Benoit Perrot committed
172
173
    register_type	a = get_register(sub.get_src1 ());
    register_type	b = get_register(sub.get_src2 ());
174

Benoit Perrot's avatar
Benoit Perrot committed
175
    register_type	c = a - b;
176
177
178
    set_register(sub.get_dest (), c);

    if ((a < b && c > 0) || (a > b && c < 0))
Benoit Perrot's avatar
Benoit Perrot committed
179
      cp0_.raise_overflow();
180
181
182
183
184
  }
  void
  Cpu::visit(const inst::Subu& subu)
  {
    set_register(subu.get_dest (),
Benoit Perrot's avatar
Benoit Perrot committed
185
186
		 get_register(subu.get_src1 ()) - 
		 get_register(subu.get_src2 ()));
187
188
189
190
191
  }

  void
  Cpu::visit(const inst::Sll& sll)
  {
Benoit Perrot's avatar
Benoit Perrot committed
192
    uregister_type	a = get_register(sll.get_src ());
193
    unsigned	i = sll.get_imm ();
Benoit Perrot's avatar
Benoit Perrot committed
194
    register_type	c = a << i;
195
196
197
198
199
200
201
    set_register(sll.get_dest (), c);

    // FIXME: Check overflow !
  }
  void
  Cpu::visit(const inst::Sllv& slv)
  {
Benoit Perrot's avatar
Benoit Perrot committed
202
203
    uregister_type	a = get_register(slv.get_src1 ());
    uregister_type	b = get_register(slv.get_src2 ());
204

Benoit Perrot's avatar
Benoit Perrot committed
205
    register_type	c = a << b;
206
207
208
209
210
211
212
213
    set_register(slv.get_dest (), c);

    // FIXME: Check overflow !
  }

  void
  Cpu::visit(const inst::Sra& sra)
  {
Benoit Perrot's avatar
Benoit Perrot committed
214
    register_type	a = get_register(sra.get_src ());
215
    unsigned	b = sra.get_imm ();
Benoit Perrot's avatar
Benoit Perrot committed
216
    register_type	c = a >> b;
217
218
219
220
221
222
223
    set_register(sra.get_dest (), c);

    // FIXME: Check overflow !
  }
  void
  Cpu::visit(const inst::Srav& srav)
  {
Benoit Perrot's avatar
Benoit Perrot committed
224
225
    register_type	a = get_register(srav.get_src1 ());
    register_type	b = get_register(srav.get_src2 ());
226

Benoit Perrot's avatar
Benoit Perrot committed
227
    register_type	c = a >> b;
228
229
230
231
232
233
234
235
    set_register(srav.get_dest (), c);

    // FIXME: Check overflow !
  }

  void
  Cpu::visit(const inst::Srl& srl)
  {
Benoit Perrot's avatar
Benoit Perrot committed
236
    uregister_type	a = get_register(srl.get_src ());
237
    unsigned	i = srl.get_imm ();
Benoit Perrot's avatar
Benoit Perrot committed
238
    uregister_type	c = a >> i;
239
240
241
242
243
244
245
    set_register(srl.get_dest (), c);

    // FIXME: Check overflow !
  }
  void
  Cpu::visit(const inst::Srlv& srlv)
  {
Benoit Perrot's avatar
Benoit Perrot committed
246
247
248
    uregister_type	a = get_register(srlv.get_src1 ());
    uregister_type	b = get_register(srlv.get_src2 ());
    uregister_type	c = a >> b;
249
250
251
252
253
254
255
256
257
    set_register(srlv.get_dest (), c);

    // FIXME: Check overflow !
  }


  void
  Cpu::visit(const inst::Mul& mul)
  {
Benoit Perrot's avatar
Benoit Perrot committed
258
259
    register_type	a = get_register(mul.get_src1 ());
    register_type	b = get_register(mul.get_src2 ());
260

Benoit Perrot's avatar
Benoit Perrot committed
261
    register_type	c = a * b;
262
263
264
265
266
267
268
269
    set_register(mul.get_dest (), c);

    // FIXME: Check overflow !
  }

  void
  Cpu::visit(const inst::Div& div)
  {
Benoit Perrot's avatar
Benoit Perrot committed
270
271
    register_type	a = get_register(div.get_src1 ());
    register_type	b = get_register(div.get_src2 ());
272

Benoit Perrot's avatar
Benoit Perrot committed
273
    register_type	c = a / b;
274
275
276
277
278
279
280
281
282
283
    set_lo(c);

    c = a % b;
    set_hi(c);

    // FIXME: Check overflow !
  }
  void
  Cpu::visit(const inst::Divu& divu)
  {
Benoit Perrot's avatar
Benoit Perrot committed
284
285
    uregister_type	a = get_register(divu.get_src1 ());
    uregister_type	b = get_register(divu.get_src2 ());
286
287
288
289
290
291
292
293
294
295
296
297
298

    set_lo(a / b);
    set_hi(a % b);
  }


  // --------------------------------------------------------------------------
  // Binary instructions
  // --------------------------------------------------------------------------

  void
  Cpu::visit(const inst::And& _and)
  {
Benoit Perrot's avatar
Benoit Perrot committed
299
300
    register_type	a = get_register(_and.get_src1 ());
    register_type	b = get_register(_and.get_src2 ());
301

Benoit Perrot's avatar
Benoit Perrot committed
302
    register_type	c = a & b;
303
304
305
306
307
    set_register(_and.get_dest (), c);
  }
  void
  Cpu::visit(const inst::Andi& andi)
  {
Benoit Perrot's avatar
Benoit Perrot committed
308
    register_type	a = get_register(andi.get_src ());
309
310
    int		b = andi.get_imm ();

Benoit Perrot's avatar
Benoit Perrot committed
311
    register_type	c = a & b;
312
313
314
315
316
317
    set_register(andi.get_dest (), c);
  }

  void
  Cpu::visit(const inst::Or& _or)
  {
Benoit Perrot's avatar
Benoit Perrot committed
318
319
    register_type	a = get_register(_or.get_src1 ());
    register_type	b = get_register(_or.get_src2 ());
320

Benoit Perrot's avatar
Benoit Perrot committed
321
    register_type	c = a | b;
322
323
324
325
326
    set_register(_or.get_dest (), c);
  }
  void
  Cpu::visit(const inst::Ori& ori)
  {
Benoit Perrot's avatar
Benoit Perrot committed
327
    register_type	a = get_register(ori.get_src ());
328
329
    int		b = ori.get_imm ();

Benoit Perrot's avatar
Benoit Perrot committed
330
    register_type	c = a | b;
331
332
333
334
335
336
    set_register(ori.get_dest (), c);
  }

  void
  Cpu::visit(const inst::Nor& nor)
  {
Benoit Perrot's avatar
Benoit Perrot committed
337
338
    register_type	a = get_register(nor.get_src1 ());
    register_type	b = get_register(nor.get_src2 ());
339

Benoit Perrot's avatar
Benoit Perrot committed
340
    register_type	c = a | b;
341
342
343
344
345
346
    set_register(nor.get_dest (), ~c);
  }

  void
  Cpu::visit(const inst::Xor& _xor)
  {
Benoit Perrot's avatar
Benoit Perrot committed
347
348
    register_type	a = get_register(_xor.get_src1 ());
    register_type	b = get_register(_xor.get_src2 ());
349

Benoit Perrot's avatar
Benoit Perrot committed
350
    register_type	c = a ^ b;
351
352
353
354
355
    set_register(_xor.get_dest (), c);
  }
  void
  Cpu::visit(const inst::Xori& xori)
  {
Benoit Perrot's avatar
Benoit Perrot committed
356
    register_type	a = get_register(xori.get_src ());
357
358
    int		b = xori.get_imm ();

Benoit Perrot's avatar
Benoit Perrot committed
359
    register_type	c = a ^ b;
360
361
362
363
364
365
366
367
    set_register(xori.get_dest (), c);
  }


  // --------------------------------------------------------------------------
  // Move instructions
  // --------------------------------------------------------------------------
  
Benoit Perrot's avatar
Benoit Perrot committed
368
369
370
371
372
373
  void
  Cpu::visit(const inst::Lui& lui)
  {
    set_register(lui.get_dest (), lui.get_imm () << 16);
  }

374
375
376
377
  // Store
  void
  Cpu::visit(const inst::Sb& sb)
  {
Benoit Perrot's avatar
Benoit Perrot committed
378
    register_type	addr = get_register(sb.get_base ()) + sb.get_offset ();
Benoit Perrot's avatar
Benoit Perrot committed
379
    mmu_.data_store_byte(addr, get_register(sb.get_src ()));
380
381
382
383
384
  }

  void
  Cpu::visit(const inst::Sw& sw)
  {
Benoit Perrot's avatar
Benoit Perrot committed
385
    register_type	addr = get_register(sw.get_base ()) + sw.get_offset ();
Benoit Perrot's avatar
Benoit Perrot committed
386
    mmu_.data_store_word(addr, get_register(sw.get_src ()));
387
388
389
390
391
392
  }

  // Load
  void
  Cpu::visit(const inst::Lb& lb)
  {
Benoit Perrot's avatar
Benoit Perrot committed
393
    register_type	addr = get_register(lb.get_base ()) + lb.get_offset ();
Benoit Perrot's avatar
Benoit Perrot committed
394
    set_register(lb.get_dest (), mmu_.data_load_byte(addr));
395
396
397
398
399
  }

  void
  Cpu::visit(const inst::Lbu& lbu)
  {
Benoit Perrot's avatar
Benoit Perrot committed
400
    register_type	addr = get_register(lbu.get_base ()) + lbu.get_offset ();
Benoit Perrot's avatar
Benoit Perrot committed
401
    unsigned	b = mmu_.data_load_byte(addr);
402
403
404
405
406
407
    set_register(lbu.get_dest (), b % 256);
  }

  void
  Cpu::visit(const inst::Lw& lw)
  {
Benoit Perrot's avatar
Benoit Perrot committed
408
    register_type	addr = get_register(lw.get_base ()) + lw.get_offset ();
Benoit Perrot's avatar
Benoit Perrot committed
409
    set_register(lw.get_dest (), mmu_.data_load_word(addr));
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
  }

  // --------------------------------------------------------------------------
  // Test instructions
  // --------------------------------------------------------------------------

  void
  Cpu::visit(const inst::Slt& slt)
  {
    if (get_register(slt.get_src1 ()) < get_register(slt.get_src2 ()))
      set_register(slt.get_dest(), 1);
    else
      set_register(slt.get_dest(), 0);
  }
  void
  Cpu::visit(const inst::Slti& slti)
  {
    if (get_register(slti.get_src ()) < slti.get_imm ())
      set_register(slti.get_dest(), 1);
    else
      set_register(slti.get_dest(), 0);
  }
  void
  Cpu::visit(const inst::Sltu& sltu)
  {
Benoit Perrot's avatar
Benoit Perrot committed
435
436
    if ((uregister_type) get_register(sltu.get_src1 ()) < 
	(uregister_type) get_register(sltu.get_src2 ()))
437
438
439
440
441
442
443
      set_register(sltu.get_dest(), 1);
    else
      set_register(sltu.get_dest(), 0);
  }
  void
  Cpu::visit(const inst::Sltiu& sltiu)
  {
Benoit Perrot's avatar
Benoit Perrot committed
444
445
    if ((uregister_type) get_register(sltiu.get_src ()) < 
	(uregister_type) sltiu.get_imm ())
446
447
448
449
450
451
452
453
454
455
456
457
458
459
      set_register(sltiu.get_dest(), 1);
    else
      set_register(sltiu.get_dest(), 0);
  }
  

  // --------------------------------------------------------------------------
  // Branch and jump instructions
  // --------------------------------------------------------------------------

  // Unconditional
  void
  Cpu::visit(const inst::Jmp& jmp)
  {
Benoit Perrot's avatar
Benoit Perrot committed
460
461
462
463
    // Jump
    set_pc(get_pc() + jmp.get_label() - 8);

    // Bubble in decode stage
Benoit Perrot's avatar
Benoit Perrot committed
464
    pipeline_[d_stage] = bubble_;
Benoit Perrot's avatar
Benoit Perrot committed
465
    // Speculatively fetched instruction
Benoit Perrot's avatar
Benoit Perrot committed
466
    pipeline_[i_stage] = & mmu_.inst_load(pc_ / 4);
467
468
469
470
471
472
473
  }
  void
  Cpu::visit(const inst::Jr& jr)
  {
    // Assume it is a ret
    ret();

Benoit Perrot's avatar
Benoit Perrot committed
474
475
476
477
    // Jump
    set_pc(get_register(jr.get_dest()) - 8);

    // Bubble in decode stage
Benoit Perrot's avatar
Benoit Perrot committed
478
    pipeline_[d_stage] = bubble_;
Benoit Perrot's avatar
Benoit Perrot committed
479
    // Speculatively fetched instruction
Benoit Perrot's avatar
Benoit Perrot committed
480
    pipeline_[i_stage] = & mmu_.inst_load(pc_ / 4);
481
482
483
484
485
  }

  void
  Cpu::visit(const inst::Jal& jal)
  {
Benoit Perrot's avatar
Benoit Perrot committed
486
    // Save return address
Benoit Perrot's avatar
Benoit Perrot committed
487
    set_register(Cpu::ra, get_pc());
Benoit Perrot's avatar
Benoit Perrot committed
488
489
490
491
    // Jump
    set_pc(get_register(Cpu::ra) + jal.get_label() - 8);

    // Bubble in decode stage
Benoit Perrot's avatar
Benoit Perrot committed
492
    pipeline_[d_stage] = bubble_;
Benoit Perrot's avatar
Benoit Perrot committed
493
    // Speculatively fetched instruction
Benoit Perrot's avatar
Benoit Perrot committed
494
    pipeline_[i_stage] = & mmu_.inst_load(pc_ / 4);
Benoit Perrot's avatar
Benoit Perrot committed
495
    
496
497
498
499
500
501
    // Assume it is a call
    call();
  }
  void
  Cpu::visit(const inst::Jalr& jalr)
  {
Benoit Perrot's avatar
Benoit Perrot committed
502
    // Save return address
Benoit Perrot's avatar
Benoit Perrot committed
503
    set_register(Cpu::ra, get_pc());
Benoit Perrot's avatar
Benoit Perrot committed
504
505
506
507
    // Jump
    set_pc(get_register(jalr.get_dest()) - 8);

    // Bubble in decode stage
Benoit Perrot's avatar
Benoit Perrot committed
508
    pipeline_[d_stage] = bubble_;
Benoit Perrot's avatar
Benoit Perrot committed
509
    // Speculatively fetched instruction
Benoit Perrot's avatar
Benoit Perrot committed
510
    pipeline_[i_stage] = & mmu_.inst_load(pc_ / 4);
511
512
513
514
515
516
517
518
519
520
521

    // Assume it is a call
    call();
  }


  // Equality
  void
  Cpu::visit(const inst::Beq& beq)
  {
    if (get_register(beq.get_src1 ()) == get_register(beq.get_src2 ()))
Benoit Perrot's avatar
Benoit Perrot committed
522
523
524
525
526
      {
	// Jump
	set_pc(get_pc() + beq.get_label() - 8);
	
	// Bubble in decode stage
Benoit Perrot's avatar
Benoit Perrot committed
527
	pipeline_[d_stage] = bubble_;
Benoit Perrot's avatar
Benoit Perrot committed
528
	// Speculatively fetched instruction
Benoit Perrot's avatar
Benoit Perrot committed
529
	pipeline_[i_stage] = & mmu_.inst_load(pc_ / 4);
Benoit Perrot's avatar
Benoit Perrot committed
530
      }
531
532
533
534
535
  }
  void
  Cpu::visit(const inst::Bne& bne)
  {
    if (get_register(bne.get_src1 ()) != get_register(bne.get_src2 ()))
Benoit Perrot's avatar
Benoit Perrot committed
536
537
538
539
540
      {
	// Jump
	set_pc(get_pc() + bne.get_label() - 8);

	// Bubble in decode stage
Benoit Perrot's avatar
Benoit Perrot committed
541
	pipeline_[d_stage] = bubble_;
Benoit Perrot's avatar
Benoit Perrot committed
542
	// Speculatively fetched instruction
Benoit Perrot's avatar
Benoit Perrot committed
543
	pipeline_[i_stage] = & mmu_.inst_load(pc_ / 4);
Benoit Perrot's avatar
Benoit Perrot committed
544
      }
545
546
547
548
549
550
551
  }

  // Greater
  void
  Cpu::visit(const inst::Bgez& bgez)
  {
    if (get_register(bgez.get_src ()) >= 0)
Benoit Perrot's avatar
Benoit Perrot committed
552
553
554
555
556
      {
	// Jump
	set_pc(get_pc() + bgez.get_label() - 8);

	// Bubble in decode stage
Benoit Perrot's avatar
Benoit Perrot committed
557
	pipeline_[d_stage] = bubble_;
Benoit Perrot's avatar
Benoit Perrot committed
558
	// Speculatively fetched instruction
Benoit Perrot's avatar
Benoit Perrot committed
559
	pipeline_[i_stage] = & mmu_.inst_load(pc_ / 4);
Benoit Perrot's avatar
Benoit Perrot committed
560
      }
561
562
563
564
565
566
567
568
  }
  void
  Cpu::visit(const inst::Bgezal& bgezal)
  {
    if (get_register(bgezal.get_src ()) >= 0)
      {
	// Assume it is a call
	call();
Benoit Perrot's avatar
Benoit Perrot committed
569
570

	// Save return address
Benoit Perrot's avatar
Benoit Perrot committed
571
	set_register(Cpu::ra, get_pc());
Benoit Perrot's avatar
Benoit Perrot committed
572
573
574
575
	// Jump
	set_pc(get_pc() + bgezal.get_label() - 8);

	// Bubble in decode stage
Benoit Perrot's avatar
Benoit Perrot committed
576
	pipeline_[d_stage] = bubble_;
Benoit Perrot's avatar
Benoit Perrot committed
577
	// Speculatively fetched instruction
Benoit Perrot's avatar
Benoit Perrot committed
578
	pipeline_[i_stage] = & mmu_.inst_load(pc_ / 4);
579
580
581
582
583
584
      }
  }
  void
  Cpu::visit(const inst::Bgtz& bgtz)
  {
    if (get_register(bgtz.get_src ()) > 0)
Benoit Perrot's avatar
Benoit Perrot committed
585
586
587
588
589
      {
	// Jump
	set_pc(get_pc() + bgtz.get_label() - 8);

	// Bubble in decode stage
Benoit Perrot's avatar
Benoit Perrot committed
590
	pipeline_[d_stage] = bubble_;
Benoit Perrot's avatar
Benoit Perrot committed
591
	// Speculatively fetched instruction
Benoit Perrot's avatar
Benoit Perrot committed
592
	pipeline_[i_stage] = & mmu_.inst_load(pc_ / 4);
Benoit Perrot's avatar
Benoit Perrot committed
593
      }
594
595
596
597
598
599
600
  }

  // Lower
  void
  Cpu::visit(const inst::Blez& blez)
  {
    if (get_register(blez.get_src ()) <= 0)
Benoit Perrot's avatar
Benoit Perrot committed
601
602
603
604
605
      {
	// Jump
	set_pc(get_pc() + blez.get_label() - 8);

	// Bubble in decode stage
Benoit Perrot's avatar
Benoit Perrot committed
606
	pipeline_[d_stage] = bubble_;
Benoit Perrot's avatar
Benoit Perrot committed
607
	// Speculatively fetched instruction
Benoit Perrot's avatar
Benoit Perrot committed
608
	pipeline_[i_stage] = & mmu_.inst_load(pc_ / 4);
Benoit Perrot's avatar
Benoit Perrot committed
609
      }
610
611
612
613
614
  }
  void
  Cpu::visit(const inst::Bltz& bltz)
  {
    if (get_register(bltz.get_src ()) < 0)
Benoit Perrot's avatar
Benoit Perrot committed
615
616
617
618
619
      {
	// Jump
	set_pc(get_pc() + bltz.get_label() - 8);

	// Bubble in decode stage
Benoit Perrot's avatar
Benoit Perrot committed
620
	pipeline_[d_stage] = bubble_;
Benoit Perrot's avatar
Benoit Perrot committed
621
	// Speculatively fetched instruction
Benoit Perrot's avatar
Benoit Perrot committed
622
	pipeline_[i_stage] = & mmu_.inst_load(pc_ / 4);
Benoit Perrot's avatar
Benoit Perrot committed
623
      }
624
625
626
627
628
629
630
631
632
  }
  void
  Cpu::visit(const inst::Bltzal& bltzal)
  {
    if (get_register(bltzal.get_src ()) < 0)
      {
	// Assume it is a call
	call();

Benoit Perrot's avatar
Benoit Perrot committed
633
634
635
636
637
638
	// Save return address
	set_register(Cpu::ra, get_pc());
	// Jump
	set_pc(get_pc() + bltzal.get_label() - 8);

	// Bubble in decode stage
Benoit Perrot's avatar
Benoit Perrot committed
639
	pipeline_[d_stage] = bubble_;
Benoit Perrot's avatar
Benoit Perrot committed
640
	// Speculatively fetched instruction
Benoit Perrot's avatar
Benoit Perrot committed
641
	pipeline_[i_stage] = & mmu_.inst_load(pc_ / 4);
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
      }
  }


  // --------------------------------------------------------------------------
  // Data movement instructions
  // --------------------------------------------------------------------------

  void
  Cpu::visit(const inst::Mfhi& mfhi)
  {
    set_register(mfhi.get_dest(), get_hi());
  }
  void
  Cpu::visit(const inst::Mflo& mflo)
  {
    set_register(mflo.get_dest(), get_lo());
  }
  void
  Cpu::visit(const inst::Mthi& mthi)
  {
    set_hi(get_register(mthi.get_src()));
  }
  void
  Cpu::visit(const inst::Mtlo& mtlo)
  {
    set_lo(get_register(mtlo.get_src()));
  }
Benoit Perrot's avatar
Benoit Perrot committed
670
671
672
673
674
675
676
677
678
679
  void
  Cpu::visit(const inst::Mfc0& mfc0)
  {
    set_register(mfc0.get_dest(), cp0_.get_register(mfc0.get_src()));
  }
  void
  Cpu::visit(const inst::Mtc0& mtc0)
  {
    cp0_.set_register(mtc0.get_dest(), get_register(mtc0.get_src()));
  }
680
681
682
683
684
685
686
687
688


  // --------------------------------------------------------------------------
  // Exception and trap instructions
  // --------------------------------------------------------------------------

  void
  Cpu::visit(const inst::Syscall&)
  {
Benoit Perrot's avatar
Benoit Perrot committed
689
    switch (get_register(Cpu::v0))
690
691
692
      {
	// print_int (integer: $a0)
      case 1:
Benoit Perrot's avatar
Benoit Perrot committed
693
	ostr_ << get_register(Cpu::a0);
694
695
696
697
	break;

	// print_string (buffer: $a0)
      case 4:
Benoit Perrot's avatar
Benoit Perrot committed
698
	for (int i = get_register(Cpu::a0); true; ++i)
699
	  {
Benoit Perrot's avatar
Benoit Perrot committed
700
	    char b = mmu_.data_load_byte(i);
701
702
	    if (b == 0)
	      break;
Benoit Perrot's avatar
Benoit Perrot committed
703
	    ostr_ << b;
704
705
706
707
708
709
710
711
	  }
	break;
	
	// read_string (buffer: $a0, length: $a1)
      case 8:
	{
	  int i = 0;
	  int c = 0;
Benoit Perrot's avatar
Benoit Perrot committed
712
713
	  for (; (i < get_register(Cpu::a1) - 1) && (c != '\n') && (c != '\r');
	       ++i)
714
	    {
Benoit Perrot's avatar
Benoit Perrot committed
715
716
	      c = istr_.get();
	      if (istr_.eof())
717
		break;
Benoit Perrot's avatar
Benoit Perrot committed
718
	      mmu_.data_store_byte(get_register(Cpu::a0) + i, c);
719
	    }
Benoit Perrot's avatar
Benoit Perrot committed
720
	  mmu_.data_store_byte(get_register(Cpu::a0) + i, 0);
721
722
723
724
725
	}
	break;

	// sbrk (size: $a0)
      case 9: 
Benoit Perrot's avatar
Benoit Perrot committed
726
	set_register(Cpu::v0, mmu_.data_sbrk(get_register(Cpu::a0)));
727
728
729
730
	break;

	// exit (status : $a0)
      case 10:
Benoit Perrot's avatar
Benoit Perrot committed
731
	halt_ = true;
732
	if (!exit_status)
Benoit Perrot's avatar
Benoit Perrot committed
733
	  exit_status = (exit_type) get_register(Cpu::a0);
734
735
736
737
738
	break;
	
      default:
	assertion(!"syscall: Not implemented yet");
      };
Benoit Perrot's avatar
Benoit Perrot committed
739
    ostr_.flush();
740
741
742
  }

} // namespace vm