virtual_machine.hh 5.12 KB
Newer Older
Benoit Perrot's avatar
Benoit Perrot committed
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>
Benoit Perrot's avatar
Benoit Perrot committed
4
//
Benoit Perrot's avatar
Benoit Perrot committed
5
// Nolimips is free software; you can redistribute it and/or modify
Benoit Perrot's avatar
Benoit Perrot committed
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,
Benoit Perrot's avatar
Benoit Perrot committed
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
//
Benoit Perrot's avatar
Benoit Perrot committed
19
20
/** \file vm/virtual_machine.hh
    \brief Declare Virtual Machine class. */
21
22
23
#ifndef VM_VIRTUAL_MACHINE_HH
# define VM_VIRTUAL_MACHINE_HH

24
25
# include <iostream>

26
# include "misc/contract.hh"
27
# include "misc/has.hh"
28
# include "common.hh"
29
30
31
32

# include "inst/program.hh"

# include "vm/memory.hh"
Benoit Perrot's avatar
Benoit Perrot committed
33
# include "vm/mmu.hh"
Benoit Perrot's avatar
Benoit Perrot committed
34
# include "vm/cp0.hh"
Benoit Perrot's avatar
Benoit Perrot committed
35
# include "vm/cpu.hh"
36
37
38

namespace vm
{
Benoit Perrot's avatar
Benoit Perrot committed
39
40

  /// Virtual Machine abstraction
41
  class VirtualMachine
42
  {
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
  public:
    enum mode_type
      {
	normal,
	step
      };

    enum status_type
      {
	run,
	pause,
	stop,
	halt
      };

Benoit Perrot's avatar
Benoit Perrot committed
58
59
    /** \name Constructor and destructor.
	\{ */
60
  public:
Benoit Perrot's avatar
Benoit Perrot committed
61
    VirtualMachine(bool check_callee_save_p,
Benoit Perrot's avatar
Benoit Perrot committed
62
		   bool trace_exec_p,
63
		   mode_type mode = normal,
Benoit Perrot's avatar
Benoit Perrot committed
64
		   std::istream& istr = std::cin,
65
		   std::ostream& ostr = std::cout):
66
67
      mode_(mode),
      status_(stop),
Benoit Perrot's avatar
Benoit Perrot committed
68
      mmu_(memory_),
Benoit Perrot's avatar
Benoit Perrot committed
69
      cpu_(mmu_, cp0_, istr, ostr, check_callee_save_p, trace_exec_p)
70
71
    {
    }
Benoit Perrot's avatar
Benoit Perrot committed
72
    /** \} */
73

74
75
76
77
78
79
80
81
82
83
84
85
86
  public:
    /// Reset the vm
    void		reset()
    {
    }
    /// Print the vm
    void		print(std::ostream& ostr) const
    {
      // FIXME: print the whole cpu, and cp0.
      ostr << cpu_;
    }


87
  public:
Benoit Perrot's avatar
Benoit Perrot committed
88
    /// Load a program into memory.
89
    void		load_program(const inst::Program& program)
90
    {
91
      if (! program.text_section ().has_label(inst::Label("main")))
Benoit Perrot's avatar
Benoit Perrot committed
92
93
	{
	  std::cerr << "No `main' label in assembly file." << std::endl;
94
	  exit_set(exit_runtime);
Benoit Perrot's avatar
Benoit Perrot committed
95
96
	  return;
	}
Benoit Perrot's avatar
Benoit Perrot committed
97
98
99
      mmu_.data_store(program.data_section());
      mmu_.inst_store(program.text_section());
      cpu_.set_pc(program.text_section ().get_offset(inst::Label("main")));
100
    }
101

102
  public:
Benoit Perrot's avatar
Benoit Perrot committed
103
    /// Execute a program.
Benoit Perrot's avatar
Benoit Perrot committed
104
    void		execute()
105
    {
Benoit Perrot's avatar
Benoit Perrot committed
106
107
      // FIXME: precondition on loaded program

Benoit Perrot's avatar
Benoit Perrot committed
108
      while (!cpu_.get_halt())
Benoit Perrot's avatar
Benoit Perrot committed
109
	{
Benoit Perrot's avatar
Benoit Perrot committed
110
	  cpu_.step();
Benoit Perrot's avatar
Benoit Perrot committed
111
112
	  cp0_.set_count(cp0_.get_count() + 1);
	}
113
114
    }

115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
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
    /** \name Shell entry point
	\{ */
  protected:
    /// Check if a label exists
    bool	has_label(const std::string& label) const
    {
      return mmu_.inst().has_label(inst::Label(label));
    }

    /// Return the offset of a label
    int		get_offset(const std::string& label) const
    {
      return mmu_.inst().get_offset(inst::Label(label));
    }

  public:
    /// Execute a program
    void		execute(bool trace_p)
    {
      if (status_ == stop)
	return;

      cpu_.set_trace(trace_p);
      while (status_ == run)
	{
	  cpu_.step();
	  cp0_.set_count(cp0_.get_count() + 1);
	  if (cpu_.get_halt())
	    {
	      status_ = halt;
	      std::cerr << "Program exited." << std::endl;
	      break;
	    }
	  if (has(breakpoints_, cpu_.get_pc()))
	    {
	      std::cout << "Breakpoint at pc = " << cpu_.get_pc() << std::endl;
	      status_ = pause;
	    }
	  if (mode_ == step)
	    status_ = pause;
	}
    }

    /// Add a breakpoint
    void                add_breakpoint(const std::string& label)
    {
      int offset;

      if (!has_label(label))
	{
	  std::cerr << "Label " << label << " not found" << std::endl;
	  return;
	}
      offset = get_offset(label);

      std::cout << "Breakpoint " << label
		<< " at " << offset << " (+4)" << std::endl;
      breakpoints_.push_back(offset + 4);
    }

  protected:
    /// The list of breakpoints
    std::list<int> breakpoints_;


  public:
    /// Make the vm runnable
    void                set_runnable()
    {
      status_ = run;
      mode_ = normal;
    }

    /// Run only the next instruction
    void                set_run_next()
    {
      status_ = run;
      mode_ = step;
    }

    /// Return the status of the vm
    status_type		get_status() const
    {
      return status_;
    }


    /// Return the value of a register
    register_type	get_cpu_register(Cpu::kind_type k) const
    {
      return cpu_.get_register(k);
    }

    /// Return the value of the pc
    register_type	get_cpu_pc() const
    {
      return cpu_.get_pc();
    }

  protected:
    /// The virtual machine mode.
    mode_type	mode_;
    /// The virtual machine status.
    status_type	status_;
    /** \} */

221
  protected:
Benoit Perrot's avatar
Benoit Perrot committed
222
    /// Memory block.
Benoit Perrot's avatar
Benoit Perrot committed
223
    Memory		memory_;
Benoit Perrot's avatar
Benoit Perrot committed
224

Benoit Perrot's avatar
Benoit Perrot committed
225
    /// Memory management unit.
Benoit Perrot's avatar
Benoit Perrot committed
226
    Mmu			mmu_;
Benoit Perrot's avatar
Benoit Perrot committed
227
228
    /// Control coprocessor.
    Cp0			cp0_;
Benoit Perrot's avatar
Benoit Perrot committed
229
    /// Central processor unit.
Benoit Perrot's avatar
Benoit Perrot committed
230
    Cpu			cpu_;
231
232
  };

233
234
235
236
237
238
239
  inline std::ostream&
  operator<<(std::ostream &os, const VirtualMachine &vm)
  {
    vm.print(os);
    return os;
  }

240
241
242
} // namespace vm

#endif // !VM_VIRTUAL_MACHINE_HH