Imported Upstream version 2.9.0
[debian/cc1111] / sim / ucsim / sim.src / stack.cc
1 /*
2  * Simulator of microcontrollers (stack.cc)
3  *
4  * Copyright (C) 2000,00 Drotos Daniel, Talker Bt.
5  * 
6  * To contact author send email to drdani@mazsola.iit.uni-miskolc.hu
7  *
8  */
9
10 /* This file is part of microcontroller simulator: ucsim.
11
12 UCSIM is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 2 of the License, or
15 (at your option) any later version.
16
17 UCSIM is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 GNU General Public License for more details.
21
22 You should have received a copy of the GNU General Public License
23 along with UCSIM; see the file COPYING.  If not, write to the Free
24 Software Foundation, 59 Temple Place - Suite 330, Boston, MA
25 02111-1307, USA. */
26 /*@1@*/
27
28 #include <stdlib.h>
29
30 // cmd.src
31 #include "newcmdcl.h"
32
33 // sim.src
34 #include "stackcl.h"
35
36
37 static class cl_stack_error_registry stack_error_registry;
38
39 cl_stack_op::cl_stack_op(enum stack_op op,
40                          t_addr iPC,
41                          t_addr iSP_before, t_addr iSP_after):
42   cl_base()
43 {
44   operation= op;
45   PC= iPC;
46   //addr= iaddr;
47   //data= idata;
48   SP_before= iSP_before;
49   SP_after= iSP_after;
50 }
51
52 cl_stack_op::~cl_stack_op(void)
53 {
54 }
55
56
57 class cl_stack_op *
58 cl_stack_op::mk_copy(void)
59 {
60   class cl_stack_op *so= new cl_stack_op(*this);
61   return(so);
62 }
63
64 void
65 cl_stack_op::info_head(class cl_console_base *con)
66 {
67   con->dd_printf("OP   SP before-after   L DATA/ADDR   INSTRUCTION\n");
68 }
69
70 void
71 cl_stack_op::info(class cl_console_base *con, class cl_uc *uc)
72 {
73   con->dd_printf("%-4s 0x%06"_A_"x-0x%06"_A_"x %d ",
74                 get_op_name(), SP_before, SP_after, abs(SP_before-SP_after));
75   print_info(con);
76   con->dd_printf(" ");
77   uc->print_disass(PC, con);
78   //con->dd_printf("\n");
79 }
80
81 const char *
82 cl_stack_op::get_op_name(void)
83 {
84   return("op");
85 }
86
87 void
88 cl_stack_op::print_info(class cl_console_base *con)
89 {
90   con->dd_printf("-");
91 }
92
93 bool
94 cl_stack_op::sp_increased(void)
95 {
96   if (operation & stack_write_operation)
97     return(SP_after > SP_before);
98   else // read operation
99     return(SP_after < SP_before);
100 }
101
102 int
103 cl_stack_op::data_size(void)
104 {
105   int r= SP_after - SP_before;
106
107   return(r<0?-r:r);
108 }
109
110 int
111 cl_stack_op::match(class cl_stack_op *op)
112 {
113   return(DD_FALSE);
114 }
115
116 bool
117 cl_stack_op::can_removed(class cl_stack_op *op)
118 {
119   bool incr= sp_increased(); // FIXME
120   bool op_incr= op->sp_increased(); // FIXME
121
122   if ((incr && !op_incr) ||
123       (!incr && op_incr))
124     {
125       printf("BIGBIG ERROR!\n");
126       return(DD_FALSE);
127     }
128   if (incr)
129     {
130       t_mem opa= op->get_after();
131       return(SP_before >= opa);
132     }
133   else
134     {
135       t_mem opa= op->get_after();
136       return(SP_before <= opa);
137     }
138 }
139
140
141 /*
142  * CALL operation on stack
143  */
144
145 cl_stack_call::cl_stack_call(t_addr iPC, t_addr called, t_addr pushed,
146                             t_addr iSP_before, t_addr iSP_after):
147   cl_stack_op(stack_call, iPC, iSP_before, iSP_after)
148 {
149   called_addr= called;
150   pushed_addr= pushed;
151 }
152
153 class cl_stack_op *
154 cl_stack_call::mk_copy(void)
155 {
156   class cl_stack_call *so= new cl_stack_call(*this);
157   return(so);
158 }
159
160 const char *
161 cl_stack_call::get_op_name(void)
162 {
163   return("call");
164 }
165
166 void
167 cl_stack_call::print_info(class cl_console_base *con)
168 {
169   con->dd_printf("0x%06"_A_"x", called_addr);
170 }
171
172 const char *
173 cl_stack_call::get_matching_name(void)
174 {
175   return("ret");
176 }
177
178 enum stack_op
179 cl_stack_call::get_matching_op(void)
180 {
181   return(stack_ret);
182 }
183
184 bool
185 cl_stack_call::match(class cl_stack_op *op)
186 {
187   return(op->get_op() == stack_ret);
188 }
189
190
191 /*
192  * INTERRUPT operation (call) on stack
193  */
194
195 cl_stack_intr::cl_stack_intr(t_addr iPC, t_addr called, t_addr pushed,
196                             t_addr iSP_before, t_addr iSP_after):
197   cl_stack_call(iPC, called, pushed, iSP_before, iSP_after)
198 {
199   //called_addr= called;
200   //pushed_addr= pushed;
201   operation= stack_intr;
202 }
203
204 class cl_stack_op *
205 cl_stack_intr::mk_copy(void)
206 {
207   class cl_stack_intr *so= new cl_stack_intr(*this);
208   return(so);
209 }
210
211 const char *
212 cl_stack_intr::get_op_name(void)
213 {
214   return("intr");
215 }
216
217 void
218 cl_stack_intr::print_info(class cl_console_base *con)
219 {
220   con->dd_printf("0x%06"_A_"x", called_addr);
221 }
222
223 const char *
224 cl_stack_intr::get_matching_name(void)
225 {
226   return("iret");
227 }
228
229 enum stack_op
230 cl_stack_intr::get_matching_op(void)
231 {
232   return(stack_iret);
233 }
234
235 int
236 cl_stack_intr::match(class cl_stack_op *op)
237 {
238   return(op->get_op() == stack_iret);
239 }
240
241
242 /*
243  * PUSH operation on stack
244  */
245
246 cl_stack_push::cl_stack_push(t_addr iPC, t_mem idata,
247                             t_addr iSP_before, t_addr iSP_after):
248   cl_stack_op(stack_push, iPC, iSP_before, iSP_after)
249 {
250   data= idata;
251 }
252
253 class cl_stack_op *
254 cl_stack_push::mk_copy(void)
255 {
256   class cl_stack_push *so= new cl_stack_push(*this);
257   return(so);
258 }
259
260 const char *
261 cl_stack_push::get_op_name(void)
262 {
263   return("push");
264 }
265
266 const char *
267 cl_stack_push::get_matching_name(void)
268 {
269   return("pop");
270 }
271
272 enum stack_op
273 cl_stack_push::get_matching_op(void)
274 {
275   return(stack_pop);
276 }
277
278 void
279 cl_stack_push::print_info(class cl_console_base *con)
280 {
281   t_addr d= data;
282   con->dd_printf("0x%06"_A_"x", d);
283 }
284
285 int
286 cl_stack_push::match(class cl_stack_op *op)
287 {
288   return(op->get_op() == stack_pop);
289 }
290
291
292 /*
293  * RETURN operation on stack
294  */
295
296 cl_stack_ret::cl_stack_ret(t_addr iPC, t_addr iaddr,
297                           t_addr iSP_before, t_addr iSP_after):
298   cl_stack_call(iPC, iaddr, 0, iSP_before, iSP_after)
299 {
300   operation= stack_ret;
301 }
302
303 class cl_stack_op *
304 cl_stack_ret::mk_copy(void)
305 {
306   class cl_stack_ret *so= new cl_stack_ret(*this);
307   return(so);
308 }
309
310 const char *
311 cl_stack_ret::get_op_name(void)
312 {
313   return("ret");
314 }
315
316 const char *
317 cl_stack_ret::get_matching_name(void)
318 {
319   return("call");
320 }
321
322 enum stack_op
323 cl_stack_ret::get_matching_op(void)
324 {
325   return(stack_call);
326 }
327
328 int
329 cl_stack_ret::match(class cl_stack_op *op)
330 {
331   return(op->get_op() == stack_call);
332 }
333
334
335 /*
336  * RETURN from interrupt operation on stack
337  */
338
339 cl_stack_iret::cl_stack_iret(t_addr iPC, t_addr iaddr,
340                             t_addr iSP_before, t_addr iSP_after):
341   cl_stack_ret(iPC, iaddr, iSP_before, iSP_after)
342 {
343   operation= stack_iret;
344 }
345
346 class cl_stack_op *
347 cl_stack_iret::mk_copy(void)
348 {
349   class cl_stack_iret *so= new cl_stack_iret(*this);
350   return(so);
351 }
352
353 const char *
354 cl_stack_iret::get_op_name(void)
355 {
356   return("iret");
357 }
358
359 const char *
360 cl_stack_iret::get_matching_name(void)
361 {
362   return("intr");
363 }
364
365 enum stack_op
366 cl_stack_iret::get_matching_op(void)
367 {
368   return(stack_intr);
369 }
370
371 int
372 cl_stack_iret::match(class cl_stack_op *op)
373 {
374   return(op->get_op() == stack_intr);
375 }
376
377
378 /*
379  * POP operation on stack
380  */
381
382 cl_stack_pop::cl_stack_pop(t_addr iPC, t_mem idata,
383                           t_addr iSP_before, t_addr iSP_after):
384   cl_stack_push(iPC, idata, iSP_before, iSP_after)
385 {
386   operation= stack_pop;
387 }
388
389 class cl_stack_op *
390 cl_stack_pop::mk_copy(void)
391 {
392   class cl_stack_pop *so= new cl_stack_pop(*this);
393   return(so);
394 }
395
396 const char *
397 cl_stack_pop::get_op_name(void)
398 {
399   return("pop");
400 }
401
402 const char *
403 cl_stack_pop::get_matching_name(void)
404 {
405   return("push");
406 }
407
408 enum stack_op
409 cl_stack_pop::get_matching_op(void)
410 {
411   return(stack_push);
412 }
413
414 int
415 cl_stack_pop::match(class cl_stack_op *op)
416 {
417   return(op->get_op() == stack_push);
418 }
419
420
421 /*
422  * Stack Errors
423  */
424
425 cl_error_stack::cl_error_stack(void)
426 {
427   classification = stack_error_registry.find("stack");
428 }
429
430 /* Stack Tracker Errors */
431
432 cl_error_stack_tracker::cl_error_stack_tracker(void)
433 {
434   classification = stack_error_registry.find("stack_tracker");
435 }
436
437 /* Stack Tracker: wrong handle */
438
439 cl_error_stack_tracker_wrong_handle::cl_error_stack_tracker_wrong_handle(bool write_op):
440   cl_error_stack_tracker()
441 {
442   write_operation= write_op;
443   classification = stack_error_registry.find("stack_tracker_wrong_handle");
444 }
445
446 void
447 cl_error_stack_tracker_wrong_handle::print(class cl_commander_base *c)
448 {
449   c->dd_printf("%s: wrong stack tracker handle called for %s operation\n",
450                get_type_name(), write_operation?"write":"read");
451 }
452
453 /* Stack Tracker: operation on empty stack */
454
455 cl_error_stack_tracker_empty::
456 cl_error_stack_tracker_empty(class cl_stack_op *op):
457   cl_error_stack_tracker()
458 {
459   operation= op->mk_copy();
460   classification = stack_error_registry.find("operation_on_empty_stack");
461 }
462
463 cl_error_stack_tracker_empty::~cl_error_stack_tracker_empty(void)
464 {
465   delete operation;
466 }
467
468 void
469 cl_error_stack_tracker_empty::print(class cl_commander_base *c)
470 {
471   c->dd_printf("%s(0x%06"_A_"x: %s on empty stack, PC="
472                "0x06"_A_"x, SP=0x%06"_A_"x->0x%06"_A_"x\n",
473                get_type_name(), operation->get_pc(), operation->get_op_name(),
474                operation->get_before(), operation->get_after());
475 }
476
477 /* Stack Tracker: operation on empty stack */
478
479 cl_error_stack_tracker_unmatch::
480 cl_error_stack_tracker_unmatch(class cl_stack_op *Top, class cl_stack_op *op):
481   cl_error_stack_tracker()
482 {
483   top= Top->mk_copy();
484   operation= op->mk_copy();
485   classification = stack_error_registry.find("stack_operation_unmatched_to_top_of_stack");
486 }
487
488 cl_error_stack_tracker_unmatch::~cl_error_stack_tracker_unmatch(void)
489 {
490   delete operation;
491   delete top;
492 }
493
494 void
495 cl_error_stack_tracker_unmatch::print(class cl_commander_base *c)
496 {
497   c->dd_printf("%s(0x%06"_A_"x): %s when %s expected, "
498                "SP=0x%06"_A_"x->0x%06"_A_"x\n",
499                get_type_name(), operation->get_pc(),
500                operation->get_op_name(), top->get_matching_name(),
501                operation->get_before(), operation->get_after());
502 }
503
504 /* Stack Tracker: stack is inconsistent */
505
506 cl_error_stack_tracker_inconsistent::
507 cl_error_stack_tracker_inconsistent(class cl_stack_op *op,
508                                    int the_unread_data_size)
509 {
510   operation= op->mk_copy();
511   unread_data_size= the_unread_data_size;
512   classification = stack_error_registry.find("stack_looks_corrupted");
513 }
514
515 cl_error_stack_tracker_inconsistent::~cl_error_stack_tracker_inconsistent(void)
516 {
517   delete operation;
518 }
519
520 void
521 cl_error_stack_tracker_inconsistent::print(class cl_commander_base *c)
522 {
523   c->dd_printf("%s(0x%06"_A_"x): %d byte(s) unread from the stack\n",
524                get_type_name(), operation->get_pc(),
525                unread_data_size);
526 }
527
528 cl_stack_error_registry::cl_stack_error_registry(void)
529 {
530   class cl_error_class *prev = stack_error_registry.find("non-classified");
531   prev = register_error(new cl_error_class(err_error, "stack", prev, ERROR_OFF));
532   prev = register_error(new cl_error_class(err_error, "stack_tracker", prev));
533   prev = register_error(new cl_error_class(err_error, "stack_tracker_wrong_handle", prev));
534   prev = register_error(new cl_error_class(err_error, "operation_on_empty_stack", prev));
535   prev = register_error(new cl_error_class(err_warning, "stack_operation_unmatched_to_top_of_stack", prev));
536   prev = register_error(new cl_error_class(err_warning, "stack_looks_corrupted", prev));
537 }
538
539
540 /* End of sim.src/stack.cc */