cpu.hh 8.44 KB
Newer Older
Benoit Perrot's avatar
Benoit Perrot committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//
// This file is part of Mipsy, a tiny MIPS simulator
// Copyright (C) 2003 Benoit Perrot <benoit@lrde.epita.fr>
//
// Mipsy 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 2 of the License, or
// (at your option) any later version.
// 
// Mipsy 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, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
Benoit Perrot's avatar
Benoit Perrot committed
19
20
/** \file vm/cpu.hh
    \brief Declare Central Processor Unit class. */
21
22
23
24
25
26
#ifndef VM_CPU_HH
# define VM_CPU_HH

// FIXME: lack of compatibility
# include <stdint.h>

27
28
29
# include <stack>

# include "inst/visitor.hh"
30
# include "inst/register.hh"
Benoit Perrot's avatar
Benoit Perrot committed
31
# include "inst/program.hh"
32

Benoit Perrot's avatar
Benoit Perrot committed
33
# include "vm/mmu.hh"
34
35
36
37
38
39
40
41
# include "vm/table.hh"

namespace vm
{

  typedef int32_t	register_t;
  typedef uint32_t	uregister_t;
  
Benoit Perrot's avatar
Benoit Perrot committed
42
  /// Central Processor Unit abstraction
43
  class Cpu:
Benoit Perrot's avatar
Benoit Perrot committed
44
    protected inst::ConstVisitor
45
  {
46
  public:
Benoit Perrot's avatar
Benoit Perrot committed
47
    /// General purpose registers indices
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
    enum kind_t
      {
	zero = 0,
	at,
	v0, v1,
	a0, a1, a2, a3,
	t0, t1, t2, t3, t4, t5, t6, t7,
	s0, s1, s2, s3, s4, s5, s6, s7,
	t8, t9,
	k0, k1,
	gp,
	sp,
	fp,
	ra = 31
      };

Benoit Perrot's avatar
Benoit Perrot committed
64
65
    /** \name Constructor and destructor 
	\{ */
66
  public:
Benoit Perrot's avatar
Benoit Perrot committed
67
    /// Construct a CPU.
Benoit Perrot's avatar
Benoit Perrot committed
68
    Cpu(Mmu& mmu, 
69
70
	std::istream& istr, 
	std::ostream& ostr, 
Benoit Perrot's avatar
Benoit Perrot committed
71
72
	bool check_callee_save_p, 
	bool trace_p):
Benoit Perrot's avatar
Benoit Perrot committed
73
      mmu(mmu),
74
      istr(istr), ostr(ostr),
Benoit Perrot's avatar
Benoit Perrot committed
75
76
      check_callee_save_p(check_callee_save_p),
      trace_p(trace_p)
77
78
79
    {
      reset();
    }
Benoit Perrot's avatar
Benoit Perrot committed
80
    /** \} */
81
82

  public:
Benoit Perrot's avatar
Benoit Perrot committed
83
84
    /// Reset the CPU (set general purpose registers to zero, etc.)
    void	reset()
85
    {
86
87
88
      halt = false;

      // Initialize general purpose registers to 0.
89
90
      for (unsigned i = 0; i < 32; ++i)
	GPR[i] = 0;
91
      // Initialize stack pointers to bottom of stack.
92
93
      GPR[sp] = Memory::stack_bottom;
      GPR[fp] = Memory::stack_bottom;
94
      // Initialize special registers to 0.
95
96
      lo = 0;
      hi = 0;
97
98
    }

Benoit Perrot's avatar
Benoit Perrot committed
99
100
    /** \name General purpose registers accessors.
	\{ */
101
  public:
Benoit Perrot's avatar
Benoit Perrot committed
102
103
    /// Return the general purpose register \a k.
    register_t	get_register(kind_t k) const
104
105
106
    {
      return GPR[k];
    }
Benoit Perrot's avatar
Benoit Perrot committed
107
108
    /// Set the general purpose register \a k to \a r.
    void	set_register(kind_t k, register_t r)
109
    {
Benoit Perrot's avatar
Benoit Perrot committed
110
111
      if (k != Cpu::zero)
	GPR[k] = r;
112
    }
Benoit Perrot's avatar
Benoit Perrot committed
113
    /** \} */
114

Benoit Perrot's avatar
Benoit Perrot committed
115
116
117
118
119
    /** \name Unlimited registers accessors.
	\{ */
  public:
    /// Return true if the unlimited register \a i exists.
    bool	has_unlimited(int i) const
120
121
122
    {
      return unlimited.has(i);
    }
Benoit Perrot's avatar
Benoit Perrot committed
123
124
    /// Return the unlimited register indexed by \a i.
    register_t	get_unlimited(int i) const
125
    {
126
      precondition(has_unlimited(i));
127
128
      return unlimited.get(i);
    }
Benoit Perrot's avatar
Benoit Perrot committed
129
130
    /// Set the unlimited register indexed by \a i to \a r.
    void	set_unlimited(int i, register_t r)
131
    {
132
      unlimited.put(i, r);
133
    }
Benoit Perrot's avatar
Benoit Perrot committed
134
    /** \} */
135

Benoit Perrot's avatar
Benoit Perrot committed
136
137
138
139
140
    /** \name Registers unified accessors.
	\{ */
  public:
    /// Return the register identified by \a reg.
    register_t	get_register(const inst::Register& reg) const
141
    {
142
143
144
145
146
      if (reg.get_kind() == inst::Register::unlimited)
	{
	  precondition(has_unlimited(reg.get_index ()));
	  return unlimited.get(reg.get_index ());
	}
Benoit Perrot's avatar
Benoit Perrot committed
147
148
149
      precondition(reg.get_kind() == inst::Register::general &&
		   Cpu::zero <= reg.get_index() && reg.get_index() <= Cpu::ra);
      return get_register((kind_t) reg.get_index());
150
    }
Benoit Perrot's avatar
Benoit Perrot committed
151
152
    /// Set the register identified by \a reg to \a r.
    void	set_register(const inst::Register& reg, register_t r)
153
    {
154
      if (reg.get_kind() == inst::Register::unlimited)
155
	{
Benoit Perrot's avatar
Benoit Perrot committed
156
	  unlimited.put(reg.get_index(), r);
157
	  return;
158
	}
Benoit Perrot's avatar
Benoit Perrot committed
159
160
161
      precondition(reg.get_kind() == inst::Register::general &&
		   Cpu::zero <= reg.get_index() && reg.get_index() <= Cpu::ra);
      set_register((kind_t) reg.get_index(), r);
162
    }
Benoit Perrot's avatar
Benoit Perrot committed
163
    /** \} */
164

Benoit Perrot's avatar
Benoit Perrot committed
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
    /** \name Special registers accessors.
	\{ */
  public:
    /// Return the HI register.
    register_t	get_hi() const { return hi; }
    /// Set the HI register to \a r.
    void	set_hi(register_t r) { hi = r; }

    /// Return the LO register.
    register_t	get_lo() const { return lo; }
    /// Set the LO register to \a r.
    void	set_lo(register_t r) { lo = r; }

    /// Return the PC register.
    register_t	get_pc() const { return pc; }
    /// Set the PC register to \a r.
    void	set_pc(register_t r) { pc = r; }
    /** \} */
183

184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
  protected:
    virtual void	visit(const inst::Add& add);
    virtual void	visit(const inst::Addi& addi);
    virtual void	visit(const inst::Addu& addu);
    virtual void	visit(const inst::Addiu& addiu);
    virtual void	visit(const inst::Sub& sub);
    virtual void	visit(const inst::Subu& subu);

    virtual void	visit(const inst::Sll& sll);
    virtual void	visit(const inst::Sllv& slv);
    virtual void	visit(const inst::Sra& sra);
    virtual void	visit(const inst::Srav& srav);
    virtual void	visit(const inst::Srl& srl);
    virtual void	visit(const inst::Srlv& srlv);

    virtual void	visit(const inst::Mul& mul);
    virtual void	visit(const inst::Div& div);
    virtual void	visit(const inst::Divu& divu);

    virtual void	visit(const inst::Lb& lb);
    virtual void	visit(const inst::Lbu& Lbu);
    virtual void	visit(const inst::Lw& lw);
    virtual void	visit(const inst::Li& li);
    virtual void	visit(const inst::Sb& sb);
    virtual void	visit(const inst::Sw& sw);

    virtual void	visit(const inst::And& _and);
    virtual void	visit(const inst::Andi& andi);
    virtual void	visit(const inst::Or& _or);
    virtual void	visit(const inst::Ori& ori);
    virtual void	visit(const inst::Nor& nor);
    virtual void	visit(const inst::Xor& _xor);
    virtual void	visit(const inst::Xori& xori);

    virtual void	visit(const inst::Slt& slt);
    virtual void	visit(const inst::Slti& slti);
    virtual void	visit(const inst::Sltu&);
    virtual void	visit(const inst::Sltiu& sltiu);

    virtual void	visit(const inst::Jmp& jmp);
    virtual void	visit(const inst::Jr& jr);
    virtual void	visit(const inst::Jal& jal);
    virtual void	visit(const inst::Jalr& jalr);

    virtual void	visit(const inst::Beq& beq);
    virtual void	visit(const inst::Bne& bne);

    virtual void	visit(const inst::Bgez& bgez);
    virtual void	visit(const inst::Bgezal& bgezal);
    virtual void	visit(const inst::Bgtz& bgtz);

    virtual void	visit(const inst::Blez& blez);
    virtual void	visit(const inst::Bltz& bltz);
    virtual void	visit(const inst::Bltzal& bltzal);

    virtual void	visit(const inst::Mfhi& mfhi);
    virtual void	visit(const inst::Mflo& mflo);
    virtual void	visit(const inst::Mthi& mthi);
    virtual void	visit(const inst::Mtlo& mtlo);

    virtual void	visit(const inst::Syscall& sycall);

  protected:
Benoit Perrot's avatar
Benoit Perrot committed
247
248
249
250
251
252
253
254
255
256
257
258
259
    /// Memory management unit link.
    Mmu&	mmu;

    /// General purpose registers.
    register_t	GPR[32];
    /// Special HIgh register.
    register_t	hi;
    /// Special LOw register.
    register_t	lo;
    /// Special Program Counter.
    register_t	pc;

    /// Unilimited registers.
260
261
    Table<int, register_t>	unlimited;

262

263
  public:
Benoit Perrot's avatar
Benoit Perrot committed
264
    bool	get_halt() const { return halt; }
265
  protected:
Benoit Perrot's avatar
Benoit Perrot committed
266
    bool	halt;
267
268
269
270
271
272

    std::istream&	istr;
    std::ostream&	ostr;


  protected:
Benoit Perrot's avatar
Benoit Perrot committed
273
    void	call()
274
    {
275
276
277
278
279
      if (check_callee_save_p)
	for (int i = Cpu::s0; i <= Cpu::s7; ++i)
	  set_unlimited(-i, get_register((Cpu::kind_t) i));
      call_stack.push(get_pc ());

280
281
      unlimited.begin_scope();
    }
Benoit Perrot's avatar
Benoit Perrot committed
282
    void	ret()
283
284
285
    {
      unlimited.end_scope();

286
287
288
289
290
291
292
      if (check_callee_save_p)
	for (int i = Cpu::s0; i <= Cpu::s7; ++i)
	  if (get_unlimited(-i) != get_register((Cpu::kind_t) i))
	    {
	      std::cerr
		<< "Warning: callee save register `$s" << i - Cpu::s0
		<< "' was not preserved across last call to 0x"
Benoit Perrot's avatar
Benoit Perrot committed
293
		<< std::hex << call_stack.top() << std::dec << std::endl;
294
295
296
297
298
	      set_register((Cpu::kind_t) i, get_unlimited(-i));
	      exit_set(exit_runtime);
	    }
      call_stack.pop();
    }
299
  protected:
300
    std::stack<register_t>	call_stack;
Benoit Perrot's avatar
Benoit Perrot committed
301
302
    bool	check_callee_save_p;

Benoit Perrot's avatar
Benoit Perrot committed
303
304

  public:
Benoit Perrot's avatar
Benoit Perrot committed
305
306
    /// Make one execution step.
    void	step()
Benoit Perrot's avatar
Benoit Perrot committed
307
    {
Benoit Perrot's avatar
Benoit Perrot committed
308
      const inst::Inst& ri = mmu.inst()[pc / 4];
Benoit Perrot's avatar
Benoit Perrot committed
309
310
311
312
313
314
315
      pc = pc + 4;
      
      if (trace_p)
	std::cout << ri << std::endl;
      ri.accept(*this);
    }
  protected:
Benoit Perrot's avatar
Benoit Perrot committed
316
    bool	trace_p;
317
318
319
320
321
  };

} // namespace vm

#endif // !VM_CPU_HH