OSDN Git Service

01965d61d8662a8d59be065695bda74c57d3ea58
[pf3gnuchains/pf3gnuchains4x.git] / sid / component / cgen-cpu / ms1 / ms1.cxx
1 // ms1.cxx - Implementations of hand-written functions for the MS1
2 // simulator. -*- C++ -*-
3
4 // Copyright (C) 2004 Red Hat.
5 // This file is part of SID and is licensed under the GPL.
6 // See the file COPYING.SID for conditions for redistribution.
7
8 // Normally, cpu ports are divided into a common part (e.g. arm-cmn.{h,cxx})
9 // and one or more cpu-family specific parts.  MSi1 is a fairly simple
10 // port so we don't currently do this.
11
12 #include "ms1.h"
13
14 using namespace std;
15 using namespace sid;
16 using namespace sidutil;
17 using namespace ms1;
18
19 ms1_cpu::ms1_cpu ()
20   :tick(0),
21    engine (32768) // XXX: tune size  
22 {
23   for (unsigned i = 0; i < 16; ++i)
24     {
25       string name = string ("R") + make_numeric_attribute (i);
26       SI* value = & this->hardware.h_spr[i];
27       this->add_watchable_register (name, value);
28     }
29
30   USI* value = & this->hardware.h_pc;
31   this->add_watchable_register (string("pc"), value);
32   this->interrupts_enabled = false;
33   this->io_bus = NULL;
34   // add accessor for I/O bus
35   add_accessor("io-memory", & this->io_bus);
36
37   // add syscall registers
38   this->add_watchable_register (string("syscall-arg0"), &syscall_arg0);
39   this->add_watchable_register (string("syscall-arg1"), &syscall_arg1);
40   this->add_watchable_register (string("syscall-arg2"), &syscall_arg2);
41   this->add_watchable_register (string("syscall-arg3"), &syscall_arg3);
42   this->add_watchable_register (string("syscall-result"), &syscall_result);
43   this->add_watchable_register (string("syscall-error"), &syscall_error);
44   this->add_attribute (string("syscall-trap"), &syscall_trap_num,"setting");
45   this->syscall_trap_num = 0;
46   // For gdb.
47   this->create_gdb_register_attrs (47, "12;13;14;16", & this->hardware.h_pc);
48
49 }
50
51 void
52 ms1_cpu::reset()
53 {
54   this->write_stacks.reset();
55   this->hardware.h_pc = 0;
56   this->interrupts_enabled = false;
57   for (unsigned i = 0; i < 16; i++)
58     this->hardware.h_spr[i] = 0;
59 }
60
61 void
62 ms1_cpu::flush_icache ()
63 {
64   this->engine.flush ();
65 }
66
67
68 void
69 ms1_cpu::invalid_insn (PCADDR pc)
70 {
71   cout << hex << "XXX: invalid insn @ " << pc << dec << endl;
72   // abort();
73 }
74
75
76 // Memory trap(/fault) handling.
77 void
78 ms1_cpu::memory_trap (const cpu_memory_fault& t)
79 {
80   this->h_pc_set (t.pc);
81   
82   abort();
83 }
84
85
86 void
87 ms1_cpu::do_syscall (PCADDR pc)
88 {
89
90   // Get the syscall arguments
91   syscall_arg0 = h_spr_get(1); // This specifies which syscall
92   syscall_arg1 = h_spr_get(2); // First arg
93   syscall_arg2 = h_spr_get(3); // Second arg
94   syscall_arg3 = h_spr_get(4); // Third arg
95
96
97   //this->h_pc_set (this->h_pc_get());
98   this->h_pc_set (pc);
99
100   cpu_trap_disposition whatnext = this->signal_trap (cpu_trap_software, syscall_trap_num);
101
102
103   switch (whatnext)
104     {
105     case cpu_trap_unhandled:
106       // cerr << "hw-cpu-ms1: invalid insn handler unimplemented!" << endl;
107       // When no gloss component is configured, we have to do the normal SI.
108       h_pc_set(8);
109       return;
110
111     case cpu_trap_reissue:
112       break;
113
114     case cpu_trap_skip:
115       //this->h_pc_set (this->h_pc_get() + 4);
116       this->h_pc_set (pc + 4);
117       /* fall-through */
118
119     case cpu_trap_handled:
120       {
121         // must get syscall results and place them in current context registers
122         string errAttr = this->attribute_value ("syscall-error");
123         string resultAttr = this->attribute_value ("syscall-result");
124
125         host_int_4 errValue;
126         host_int_4 resultValue;
127         parse_attribute(errAttr, errValue);
128         parse_attribute(resultAttr, resultValue);
129
130
131         h_spr_set (5, errValue);
132         h_spr_set (11, resultValue);
133       }
134       return;
135     default:
136       abort ();
137     }
138
139   this->yield();
140   throw cpu_exception ();
141 }
142
143 void
144 ms1_cpu::do_break (PCADDR pc)
145 {
146   cpu_trap_disposition whatnext = this->signal_trap (cpu_trap_breakpoint, 0);
147   switch (whatnext)
148     {
149     case cpu_trap_unhandled:
150       // cerr << "hw-cpu-ms1: breakpoint handler unimplemented!" << endl;
151       // No gdb component?  Do the proper break processing.
152       // Put pc+4 into R15
153       h_spr_set (15, pc +4);
154       // Disable interrupts
155       this->disable_interrupts();
156       // Branch to 0x00000010
157       this->h_pc_set (0x10);
158       return;
159       //break;
160
161     case cpu_trap_skip:
162       break;
163
164     case cpu_trap_handled:
165       // Gdb processed the trap. 
166       break;
167
168     case cpu_trap_reissue:
169       break;
170
171     default:
172       abort ();
173     }
174
175   this->yield();
176   throw cpu_exception ();
177 }
178
179 USI
180 ms1_cpu::io_read (host_int_4 pc, host_int_4 address) 
181 {
182   big_int_4 value;
183   sid::bus::status s =
184     (LIKELY(this->io_bus)) ? this->io_bus->read (address, value) : sid::bus::unmapped;
185   if (LIKELY(s == sid::bus::ok))
186     return (USI)value;
187    
188   // A bus tracer has been connected to the io bus accessor in the sid
189   // configuration file to verify that reads from and write to the io bus
190   // are actaully being requested when io instructions are processed.
191   // I/O devices and their associated memory are not part of the ISS so
192   // so there is nothing to connect the bus tracer to which will cause
193   // an "unmapped" error to occur.  If this were to occur when the io 
194   // devices are part of the simulation, the proper thing to do would
195   // be to issue a memory fault.  If the ISS is ever expanded to include
196   // io devices, uncomment the next line and comment out everything after
197   // the remainder of this method.
198   //throw cpu_memory_fault (pc, address, s, "IO read");
199
200   // Pretend everything is ok and 0 was read.  (i.e. pretend s == sid::bus::ok)
201   return (USI) 0;
202
203
204 void
205 ms1_cpu::io_write (host_int_4 pc, host_int_4 address, big_int_4 value)
206
207   sid::bus::status s =  
208     (LIKELY(this->io_bus)) ? this->io_bus->write (address, value) : sid::bus::unmapped;
209   if (LIKELY(s == sid::bus::ok))
210     return;
211
212   // A bus tracer has been connected to the io bus accessor in the sid
213   // configuration file to verify that reads from and write to the io bus
214   // are actaully being requested when io instructions are processed.
215   // I/O devices and their associated memory are not part of the ISS so
216   // so there is nothing to connect the bus tracer to which will cause
217   // an "unmapped" error to occur.  If this were to occur when the io 
218   // devices are part of the simulation, the proper thing to do would
219   // be to issue a memory fault.  If the ISS is ever expanded to include
220   // io devices, uncomment the next line and comment out everything after
221   // the remainder of this method.
222
223   // throw cpu_memory_fault (pc, address, s, "IO write");
224   
225   // Pretend everything is ok.  (i.e. pretend s == sid::bus::ok)
226   return;
227 }
228
229     
230 \f
231 // Stepper
232
233 void
234 ms1_cpu::step_insns ()
235 {
236   bool found;
237   bool increment;
238   const char *printable_name;
239   this->interrupts_enabled = false;
240   while (true)
241     {
242       increment = true;
243       PCADDR pc = this->h_pc_get ();
244       bool found;
245       ms1_scache* sem = engine.find (pc, found);
246       if (!found)
247         {
248           try
249             {
250               USI insn = this->GETIMEMSI (pc, pc);
251               sem->decode (this, pc, insn, insn);
252             }
253           catch (cpu_memory_fault& t)
254             {
255               this->memory_trap (t);
256               break;
257             }
258         }
259
260       // printable_name must agree with bfd/cpu-ms1.c.
261       if (this->get_eflags () == 2)
262         printable_name = "ms1-003";
263       else
264         printable_name = "ms1";
265
266       // Execute the instruction  -----------------------------------
267       if (trace_semantics_p)
268         this->begin_trace (pc, sem->idesc->insn_name);
269
270       if (trace_disass_p)
271         this->disassemble (pc, print_insn_ms1,
272                            bfd_target_elf_flavour,
273                            bfd_arch_ms1,
274                            (current_endianness() == endian_little ? 
275                             BFD_ENDIAN_LITTLE : BFD_ENDIAN_BIG), 
276                            printable_name,
277                            0, this->get_eflags ());
278       try
279         {
280           // R0 is always zero.
281           this->h_spr_set (0, 0);
282           sem->idesc->execute (this, sem, tick, write_stacks);
283           this->h_spr_set (0, 0);
284         }
285       catch (cpu_memory_fault& t)
286         {
287           this->memory_trap (t);
288           this->yield ();
289         }
290       catch (cpu_exception& t)
291         {
292           this->yield ();
293           increment = false;
294         }
295       if (trace_semantics_p)
296         this->end_trace ();
297
298       // Advance PC by one word, by default
299       if (increment)
300          this->h_pc_set (pc + 4);
301       // Execute writeback 
302       try {
303         write_stacks.writeback (tick, this);
304         // Overwrite R0 yet again, just in case a delayed load to R0 was performed
305         this->h_spr_set (0, 0);
306       }
307       catch (cpu_memory_fault& t)
308         {
309           this->memory_trap (t);
310           this->yield ();
311         }
312       catch (cpu_exception& t)
313         {
314           this->yield ();
315         }
316
317
318       // move ahead thru circular pipeline
319       tick = (tick + 1) % ms1::pipe_sz;
320
321       // Do post-instruction processing  ----------------------------
322       if (this->enable_step_trap_p) 
323         this->signal_trap (sidutil::cpu_trap_stepped);
324       this->triggerpoint_manager.check_and_dispatch ();
325       
326       // test for exit condition
327       if (stop_after_insns_p (1))
328         break;
329     }
330 }
331
332
333 void
334 ms1_cpu::stream_state (ostream& o) const
335 {
336   o << " ms1-cpu-cgen ";
337   stream_cgen_hardware (o);
338   o << ' ' << tick << ' ';
339   stream_cgen_write_stacks (o, write_stacks);
340 }
341
342 void
343 ms1_cpu::destream_state (istream& i)
344 {
345   string key;
346   i >> key;
347   if (key != "ms1-cpu-cgen")
348     {
349       i.setstate (ios::badbit);
350       return;
351     }
352
353   destream_cgen_hardware (i);
354   i >> tick;
355   destream_cgen_write_stacks (i, write_stacks);
356 }