OSDN Git Service

* public snapshot of sid simulator
[pf3gnuchains/pf3gnuchains3x.git] / sid / component / gloss / mips.cxx
1 // mips.cxx - MIPS monitors (IDT, PMON, ...).  -*- C++ -*-
2
3 // Copyright (C) 1999, 2000 Red Hat.
4 // This file is part of SID and is licensed under the GPL.
5 // See the file COPYING.SID for conditions for redistribution.
6
7 // ??? At present this is very minimal.  Enough to get the simulator going.
8 // Cadillac version left for later.
9
10 #include "config.h"
11 #include "mips.h"
12 #include "newlib.h"
13
14 using namespace std;
15 using namespace sid;
16 using namespace sidutil;
17
18 mips32_idt::mips32_idt()
19 {
20   // so we can query how big it is
21   add_uni_relation("ram", &this->ram);
22   // so we can stuff in our monitor implementation
23   add_uni_relation("rom", &this->rom);
24
25   this->register_attribute_names[-1] = "r0"; // result
26   this->register_attribute_names[-2] = "r0"; // error
27   this->register_attribute_names[0] = "r3";  // function code
28   this->register_attribute_names[1] = "r4";  // arg 1
29   this->register_attribute_names[2] = "r5";  // arg 2
30   this->register_attribute_names[3] = "r6";  // arg 3
31 }
32
33 // For the idt monitor we need to fill the rom with suitable contents.
34
35 void
36 mips32_idt::reset()
37 {
38   gloss32::reset ();
39
40   // Fill the ROM with suitable code.
41   update_endian();
42   int32 syscall_insn = 0x0000000c;
43   int32 return_insn = 0x03e00008;
44   sid::bus* memory = this->rom->find_bus ("read-write-port");
45   assert (memory != 0);
46
47   int32 addr = 0;
48   for (int i = 0; i < SYSCALL_MAX; ++i, addr += 8)
49     {
50       int32 insn = syscall_insn | ((i + SYSCALL_MIN) << 6);
51
52       if (this->endian == sidutil::endian_little)
53         {
54           little_int_4 little_insn = insn;
55           little_int_4 little_return_insn = return_insn;
56           bus::status s = memory->write(addr, little_return_insn);
57           assert (s == bus::ok);
58           // Execute the syscall in the delay slot.
59           s = memory->write(addr + 4, little_insn);
60           assert (s == bus::ok);
61         }
62       else
63         {
64           big_int_4 big_insn = insn;
65           big_int_4 big_return_insn = return_insn;
66           bus::status s = memory->write(addr, big_return_insn);
67           assert (s == bus::ok);
68           // Execute the syscall in the delay slot.
69           s = memory->write(addr + 4, big_insn);
70           assert (s == bus::ok);
71         }
72     }
73 }
74
75 bool
76 mips32_idt::get_int_argument(unsigned index, int32& value)
77 {
78   assert (cpu);
79   string attr_name = register_attribute_names[index];
80   assert (attr_name != "");
81
82   string attr_value = cpu->attribute_value (attr_name);
83   if (attr_value == "")
84     {
85       cerr << "Could not read attribute " << attr_name
86            << " for ABI argument #" << index << endl;
87       return false;
88     }
89
90   host_int_4 value_number;
91   parse_attribute(attr_value, value_number);
92   value = value_number;
93   return true;
94 }
95
96 bool
97 mips32_idt::set_int_result(int32 value) 
98 {
99   assert (cpu);
100   string attr_name = register_attribute_names[-1];
101   assert (attr_name != "");
102
103   host_int_4 value_number = value;
104   string attr_value = make_attribute(value_number);
105
106   cpu->set_attribute_value (attr_name, attr_value);
107   return true; // XXX: check?
108 }
109
110 bool
111 mips32_idt::set_error_result(int32 target_errno) 
112 {
113   assert (cpu);
114   string attr_name = register_attribute_names[-2];
115   assert (attr_name != "");
116
117   host_int_4 value_number = target_errno;
118   string attr_value = make_attribute(value_number);
119
120   cpu->set_attribute_value (attr_name, attr_value);
121   return true; // XXX: safe to assume success?
122 }
123
124 bool
125 mips32_idt::syscall_trap_p()
126 {
127   host_int_4 trap_type = trap_type_ipin.sense ();
128   host_int_4 trap_code = trap_code_pin.sense ();
129
130   // MIPS system calls work by branching to specific entry points in the
131   // ROM monitor.  What we do is fill the ROM with `syscall' insns which we
132   // then intercept.
133   if ((trap_type == sidutil::cpu_trap_syscall)
134       && (trap_code >= SYSCALL_MIN)
135       && (trap_code < (SYSCALL_MIN + SYSCALL_MAX)))
136     return true;
137
138   // _exit however uses the `break' insn.  Lovely.
139   if (trap_type == sidutil::cpu_trap_breakpoint
140       && trap_code == BREAK_EXIT)
141     return true;
142
143   return false;
144 }
145
146 void
147 mips32_idt::syscall_trap()
148 {
149   int syscall;
150
151   // Turn a break exit into a syscall exit.
152   if (trap_type_ipin.sense() == sidutil::cpu_trap_breakpoint
153       && trap_code_pin.sense() == BREAK_EXIT)
154     syscall = SYSCALL_EXIT;
155   else
156     syscall = trap_code_pin.sense() - SYSCALL_MIN;
157
158   if (verbose_p)
159     {
160       cerr << "MIPS/idt call number " << syscall << endl;
161     }
162
163   switch (syscall)
164     {
165     case SYSCALL_EXIT:
166       {
167         int32 value;
168         get_int_argument(1, value);
169         if (verbose_p)
170           cerr << "*** exit(" << value << ")" << endl;
171
172         if (value == 0)
173           process_signal_pin.drive((value << 8) | newlib::sigNone);
174         else
175           process_signal_pin.drive(newlib::sigAbrt);
176       }
177       break;
178
179     case SYSCALL_GET_MEM_INFO:
180       {
181         int32 bufptr;
182         get_int_argument(1, bufptr);
183         // memory size
184         int32 mem_size;
185         string mem_size_attr = "size";
186         string attr_value = this->ram->attribute_value (mem_size_attr);
187         if (attr_value == "")
188           {
189             cerr << "Could not read ram size attribute." << endl;
190             mem_size = 0;
191           }
192         parse_attribute(attr_value, mem_size);
193         set_word(bufptr, mem_size);
194         // instruction cache size
195         set_word(bufptr + 4, 0);
196         // data cache size
197         set_word(bufptr + 8, 0);
198       }
199       break;
200
201     case SYSCALL_WRITE:
202       {
203         int32 fd;
204         int32 address;
205         int32 length;
206         string str;
207
208         get_int_argument(1, fd);
209         get_int_argument(2, address);
210         get_int_argument(3, length);
211
212         size32 len_written;
213         int errcode;
214         if (! this->write (fd, address, length, len_written, errcode))
215           {
216             set_error_result(host_to_target_errno(errcode));
217             set_int_result(-1);
218           }
219         else
220           set_int_result(len_written);
221       }
222       break;
223
224     default:
225       if (verbose_p)
226         {
227           cerr << "Unimplemented syscall " << syscall << endl;
228         }
229       set_int_result(-1);
230       set_error_result(newlib::eNoSys);
231     }
232 }
233
234 // Convert host errno value to target.
235
236 int
237 mips32_idt::host_to_target_errno (int host_errno)
238 {
239   return newlib::host_to_target_errno (host_errno);
240 }