cpu.cc 19.2 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_;
77
78
79
80

    counters_[0] = 0;
    counters_[1] = 0;
    counters_[2] = 0;
Benoit Perrot's avatar
Benoit Perrot committed
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
123
124
125
126
  // --------------------------------------------------------------------------
  // 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);
  }

127
128
129
130
131
132
133
  // --------------------------------------------------------------------------
  // Arithmetic instructions
  // --------------------------------------------------------------------------

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

Benoit Perrot's avatar
Benoit Perrot committed
137
    register_type	c = a + b;
138
139
140
141
142
    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
143
      cp0_.raise_overflow();
144
145
146
147
  }
  void
  Cpu::visit(const inst::Addi& addi)
  {
Benoit Perrot's avatar
Benoit Perrot committed
148
    register_type	a = get_register(addi.get_src ());
149
150
    int		b = addi.get_imm ();

Benoit Perrot's avatar
Benoit Perrot committed
151
    register_type	c = a + b;
152
153
154
155
156
    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
157
      cp0_.raise_overflow();
158
159
160
161
162
  }
  void
  Cpu::visit(const inst::Addu& addu)
  {
    set_register(addu.get_dest (),
Benoit Perrot's avatar
Benoit Perrot committed
163
164
		 get_register(addu.get_src1 ()) +
		 get_register(addu.get_src2 ()));
165
166
167
168
169
  }
  void
  Cpu::visit(const inst::Addiu& addiu)
  {
    set_register(addiu.get_dest (),
Benoit Perrot's avatar
Benoit Perrot committed
170
		 get_register(addiu.get_src ()) + addiu.get_imm ());
171
172
173
174
175
  }

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

Benoit Perrot's avatar
Benoit Perrot committed
179
    register_type	c = a - b;
180
181
182
    set_register(sub.get_dest (), c);

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

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

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

Benoit Perrot's avatar
Benoit Perrot committed
209
    register_type	c = a << b;
210
211
212
213
214
215
216
217
    set_register(slv.get_dest (), c);

    // FIXME: Check overflow !
  }

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

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

Benoit Perrot's avatar
Benoit Perrot committed
231
    register_type	c = a >> b;
232
233
234
235
236
237
238
239
    set_register(srav.get_dest (), c);

    // FIXME: Check overflow !
  }

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

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

    // FIXME: Check overflow !
  }


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

Benoit Perrot's avatar
Benoit Perrot committed
265
    register_type	c = a * b;
266
267
268
269
270
271
272
273
    set_register(mul.get_dest (), c);

    // FIXME: Check overflow !
  }

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

Benoit Perrot's avatar
Benoit Perrot committed
277
    register_type	c = a / b;
278
279
280
281
282
283
284
285
286
287
    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
288
289
    uregister_type	a = get_register(divu.get_src1 ());
    uregister_type	b = get_register(divu.get_src2 ());
290
291
292
293
294
295
296
297
298
299
300
301
302

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


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

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

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

Benoit Perrot's avatar
Benoit Perrot committed
315
    register_type	c = a & b;
316
317
318
319
320
321
    set_register(andi.get_dest (), c);
  }

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

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

Benoit Perrot's avatar
Benoit Perrot committed
334
    register_type	c = a | b;
335
336
337
338
339
340
    set_register(ori.get_dest (), c);
  }

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

Benoit Perrot's avatar
Benoit Perrot committed
344
    register_type	c = a | b;
345
346
347
348
349
350
    set_register(nor.get_dest (), ~c);
  }

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

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

Benoit Perrot's avatar
Benoit Perrot committed
363
    register_type	c = a ^ b;
364
365
366
367
368
369
370
371
    set_register(xori.get_dest (), c);
  }


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

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

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

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

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

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

  // --------------------------------------------------------------------------
  // 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
439
440
    if ((uregister_type) get_register(sltu.get_src1 ()) < 
	(uregister_type) get_register(sltu.get_src2 ()))
441
442
443
444
445
446
447
      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
448
449
    if ((uregister_type) get_register(sltiu.get_src ()) < 
	(uregister_type) sltiu.get_imm ())
450
451
452
453
454
455
456
457
458
459
460
461
462
463
      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
464
465
466
467
    // Jump
    set_pc(get_pc() + jmp.get_label() - 8);

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

Benoit Perrot's avatar
Benoit Perrot committed
478
479
480
481
    // Jump
    set_pc(get_register(jr.get_dest()) - 8);

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

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

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

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

    // 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
526
527
528
529
530
      {
	// Jump
	set_pc(get_pc() + beq.get_label() - 8);
	
	// Bubble in decode stage
Benoit Perrot's avatar
Benoit Perrot committed
531
	pipeline_[d_stage] = bubble_;
Benoit Perrot's avatar
Benoit Perrot committed
532
	// Speculatively fetched instruction
Benoit Perrot's avatar
Benoit Perrot committed
533
	pipeline_[i_stage] = & mmu_.inst_load(pc_ / 4);
Benoit Perrot's avatar
Benoit Perrot committed
534
      }
535
536
537
538
539
  }
  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
540
541
542
543
544
      {
	// Jump
	set_pc(get_pc() + bne.get_label() - 8);

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

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

	// Bubble in decode stage
Benoit Perrot's avatar
Benoit Perrot committed
561
	pipeline_[d_stage] = bubble_;
Benoit Perrot's avatar
Benoit Perrot committed
562
	// Speculatively fetched instruction
Benoit Perrot's avatar
Benoit Perrot committed
563
	pipeline_[i_stage] = & mmu_.inst_load(pc_ / 4);
Benoit Perrot's avatar
Benoit Perrot committed
564
      }
565
566
567
568
569
570
571
572
  }
  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
573
574

	// Save return address
Benoit Perrot's avatar
Benoit Perrot committed
575
	set_register(Cpu::ra, get_pc());
Benoit Perrot's avatar
Benoit Perrot committed
576
577
578
579
	// Jump
	set_pc(get_pc() + bgezal.get_label() - 8);

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

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

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

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

	// Bubble in decode stage
Benoit Perrot's avatar
Benoit Perrot committed
624
	pipeline_[d_stage] = bubble_;
Benoit Perrot's avatar
Benoit Perrot committed
625
	// Speculatively fetched instruction
Benoit Perrot's avatar
Benoit Perrot committed
626
	pipeline_[i_stage] = & mmu_.inst_load(pc_ / 4);
Benoit Perrot's avatar
Benoit Perrot committed
627
      }
628
629
630
631
632
633
634
635
636
  }
  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
637
638
639
640
641
642
	// 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
643
	pipeline_[d_stage] = bubble_;
Benoit Perrot's avatar
Benoit Perrot committed
644
	// Speculatively fetched instruction
Benoit Perrot's avatar
Benoit Perrot committed
645
	pipeline_[i_stage] = & mmu_.inst_load(pc_ / 4);
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
      }
  }


  // --------------------------------------------------------------------------
  // 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
674
675
676
677
678
679
680
681
682
683
  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()));
  }
684
685
686
687
688
689
690
691
692


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

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

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

	// sbrk (size: $a0)
      case 9: 
Benoit Perrot's avatar
Benoit Perrot committed
730
	set_register(Cpu::v0, mmu_.data_sbrk(get_register(Cpu::a0)));
731
732
733
734
	break;

	// exit (status : $a0)
      case 10:
Benoit Perrot's avatar
Benoit Perrot committed
735
	halt_ = true;
736
	if (!exit_status)
Benoit Perrot's avatar
Benoit Perrot committed
737
	  exit_status = (exit_type) get_register(Cpu::a0);
738
739
	break;
	
740
741
742
743
744
745
746
747
748
749
750
	// print_err (buffer: $a0)
      case 15:
	for (int i = get_register(Cpu::a0); true; ++i)
	  {
	    char b = mmu_.data_load_byte(i);
	    if (b == 0)
	      break;
	    std::cerr << b;
	  }
	break;

751
752
753
      default:
	assertion(!"syscall: Not implemented yet");
      };
Benoit Perrot's avatar
Benoit Perrot committed
754
    ostr_.flush();
755
756
757
  }

} // namespace vm