1 // ms1.cxx - Implementations of hand-written functions for the MS1
2 // simulator. -*- C++ -*-
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.
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.
16 using namespace sidutil;
21 engine (32768) // XXX: tune size
23 for (unsigned i = 0; i < 16; ++i)
25 string name = string ("R") + make_numeric_attribute (i);
26 SI* value = & this->hardware.h_spr[i];
27 this->add_watchable_register (name, value);
30 USI* value = & this->hardware.h_pc;
31 this->add_watchable_register (string("pc"), value);
32 this->interrupts_enabled = false;
34 // add accessor for I/O bus
35 add_accessor("io-memory", & this->io_bus);
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;
47 this->create_gdb_register_attrs (47, "12;13;14;16", & this->hardware.h_pc);
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;
62 ms1_cpu::flush_icache ()
64 this->engine.flush ();
69 ms1_cpu::invalid_insn (PCADDR pc)
71 cout << hex << "XXX: invalid insn @ " << pc << dec << endl;
76 // Memory trap(/fault) handling.
78 ms1_cpu::memory_trap (const cpu_memory_fault& t)
80 this->h_pc_set (t.pc);
87 ms1_cpu::do_syscall (PCADDR pc)
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
97 //this->h_pc_set (this->h_pc_get());
100 cpu_trap_disposition whatnext = this->signal_trap (cpu_trap_software, syscall_trap_num);
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.
111 case cpu_trap_reissue:
115 //this->h_pc_set (this->h_pc_get() + 4);
116 this->h_pc_set (pc + 4);
119 case cpu_trap_handled:
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");
126 host_int_4 resultValue;
127 parse_attribute(errAttr, errValue);
128 parse_attribute(resultAttr, resultValue);
131 h_spr_set (5, errValue);
132 h_spr_set (11, resultValue);
140 throw cpu_exception ();
144 ms1_cpu::do_break (PCADDR pc)
146 cpu_trap_disposition whatnext = this->signal_trap (cpu_trap_breakpoint, 0);
149 case cpu_trap_unhandled:
150 // cerr << "hw-cpu-ms1: breakpoint handler unimplemented!" << endl;
151 // No gdb component? Do the proper break processing.
153 h_spr_set (15, pc +4);
154 // Disable interrupts
155 this->disable_interrupts();
156 // Branch to 0x00000010
157 this->h_pc_set (0x10);
164 case cpu_trap_handled:
165 // Gdb processed the trap.
168 case cpu_trap_reissue:
176 throw cpu_exception ();
180 ms1_cpu::io_read (host_int_4 pc, host_int_4 address)
184 (LIKELY(this->io_bus)) ? this->io_bus->read (address, value) : sid::bus::unmapped;
185 if (LIKELY(s == sid::bus::ok))
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");
200 // Pretend everything is ok and 0 was read. (i.e. pretend s == sid::bus::ok)
205 ms1_cpu::io_write (host_int_4 pc, host_int_4 address, big_int_4 value)
208 (LIKELY(this->io_bus)) ? this->io_bus->write (address, value) : sid::bus::unmapped;
209 if (LIKELY(s == sid::bus::ok))
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.
223 // throw cpu_memory_fault (pc, address, s, "IO write");
225 // Pretend everything is ok. (i.e. pretend s == sid::bus::ok)
234 ms1_cpu::step_insns ()
238 const char *printable_name;
239 this->interrupts_enabled = false;
243 PCADDR pc = this->h_pc_get ();
245 ms1_scache* sem = engine.find (pc, found);
250 USI insn = this->GETIMEMSI (pc, pc);
251 sem->decode (this, pc, insn, insn);
253 catch (cpu_memory_fault& t)
255 this->memory_trap (t);
260 // printable_name must agree with bfd/cpu-ms1.c.
261 if (this->get_eflags () == 2)
262 printable_name = "ms1-003";
264 printable_name = "ms1";
266 // Execute the instruction -----------------------------------
267 if (trace_semantics_p)
268 this->begin_trace (pc, sem->idesc->insn_name);
271 this->disassemble (pc, print_insn_ms1,
272 bfd_target_elf_flavour,
274 (current_endianness() == endian_little ?
275 BFD_ENDIAN_LITTLE : BFD_ENDIAN_BIG),
277 0, this->get_eflags ());
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);
285 catch (cpu_memory_fault& t)
287 this->memory_trap (t);
290 catch (cpu_exception& t)
295 if (trace_semantics_p)
298 // Advance PC by one word, by default
300 this->h_pc_set (pc + 4);
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);
307 catch (cpu_memory_fault& t)
309 this->memory_trap (t);
312 catch (cpu_exception& t)
318 // move ahead thru circular pipeline
319 tick = (tick + 1) % ms1::pipe_sz;
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 ();
326 // test for exit condition
327 if (stop_after_insns_p (1))
334 ms1_cpu::stream_state (ostream& o) const
336 o << " ms1-cpu-cgen ";
337 stream_cgen_hardware (o);
338 o << ' ' << tick << ' ';
339 stream_cgen_write_stacks (o, write_stacks);
343 ms1_cpu::destream_state (istream& i)
347 if (key != "ms1-cpu-cgen")
349 i.setstate (ios::badbit);
353 destream_cgen_hardware (i);
355 destream_cgen_write_stacks (i, write_stacks);