f10ab8fc077b273db6fcaaa1eb71e9a77ffb116c
[fw/sdcc] / 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 cl_stack_op::cl_stack_op(enum stack_op op,
38                          t_addr iPC,
39                          t_addr iSP_before, t_addr iSP_after):
40   cl_base()
41 {
42   operation= op;
43   PC= iPC;
44   //addr= iaddr;
45   //data= idata;
46   SP_before= iSP_before;
47   SP_after= iSP_after;
48 }
49
50 cl_stack_op::~cl_stack_op(void)
51 {
52 }
53
54
55 class cl_stack_op *
56 cl_stack_op::mk_copy(void)
57 {
58   class cl_stack_op *so= new cl_stack_op(*this);
59   return(so);
60 }
61
62 void
63 cl_stack_op::info_head(class cl_console *con)
64 {
65   con->dd_printf("OP   SP before-after   L DATA/ADDR   INSTRUCTION\n");
66 }
67
68 void
69 cl_stack_op::info(class cl_console *con, class cl_uc *uc)
70 {
71   con->dd_printf("%-4s 0x%06"_A_"x-0x%06"_A_"x %d ",
72                 get_op_name(), SP_before, SP_after, abs(SP_before-SP_after));
73   print_info(con);
74   con->dd_printf(" ");
75   uc->print_disass(PC, con);
76   //con->dd_printf("\n");
77 }
78
79 char *
80 cl_stack_op::get_op_name(void)
81 {
82   return("op");
83 }
84
85 void
86 cl_stack_op::print_info(class cl_console *con)
87 {
88   con->dd_printf("-");
89 }
90
91 bool
92 cl_stack_op::sp_increased(void)
93 {
94   if (operation & stack_write_operation)
95     return(SP_after > SP_before);
96   else // read operation
97     return(SP_after < SP_before);
98 }
99
100 int
101 cl_stack_op::data_size(void)
102 {
103   int r= SP_after - SP_before;
104
105   return(r<0?-r:r);
106 }
107
108 int
109 cl_stack_op::match(class cl_stack_op *op)
110 {
111   return(DD_FALSE);
112 }
113
114 bool
115 cl_stack_op::can_removed(class cl_stack_op *op)
116 {
117   bool incr= sp_increased(); // FIXME
118   bool op_incr= op->sp_increased(); // FIXME
119
120   if ((incr && !op_incr) ||
121       (!incr && op_incr))
122     {
123       printf("BIGBIG ERROR!\n");
124       return(DD_FALSE);
125     }
126   if (incr)
127     {
128       t_mem opa= op->get_after();
129       return(SP_before >= opa);
130     }
131   else
132     {
133       t_mem opa= op->get_after();
134       return(SP_before <= opa);
135     }
136 }
137
138
139 /*
140  * CALL operation on stack
141  */
142
143 cl_stack_call::cl_stack_call(t_addr iPC, t_addr called, t_addr pushed,
144                             t_addr iSP_before, t_addr iSP_after):
145   cl_stack_op(stack_call, iPC, iSP_before, iSP_after)
146 {
147   called_addr= called;
148   pushed_addr= pushed;
149 }
150
151 class cl_stack_op *
152 cl_stack_call::mk_copy(void)
153 {
154   class cl_stack_call *so= new cl_stack_call(*this);
155   return(so);
156 }
157
158 char *
159 cl_stack_call::get_op_name(void)
160 {
161   return("call");
162 }
163
164 void
165 cl_stack_call::print_info(class cl_console *con)
166 {
167   con->dd_printf("0x%06"_A_"x", called_addr);
168 }
169
170 char *
171 cl_stack_call::get_matching_name(void)
172 {
173   return("ret");
174 }
175
176 enum stack_op
177 cl_stack_call::get_matching_op(void)
178 {
179   return(stack_ret);
180 }
181
182 bool
183 cl_stack_call::match(class cl_stack_op *op)
184 {
185   return(op->get_op() == stack_ret);
186 }
187
188
189 /*
190  * INTERRUPT operation (call) on stack
191  */
192
193 cl_stack_intr::cl_stack_intr(t_addr iPC, t_addr called, t_addr pushed,
194                             t_addr iSP_before, t_addr iSP_after):
195   cl_stack_call(iPC, called, pushed, iSP_before, iSP_after)
196 {
197   //called_addr= called;
198   //pushed_addr= pushed;
199   operation= stack_intr;
200 }
201
202 class cl_stack_op *
203 cl_stack_intr::mk_copy(void)
204 {
205   class cl_stack_intr *so= new cl_stack_intr(*this);
206   return(so);
207 }
208
209 char *
210 cl_stack_intr::get_op_name(void)
211 {
212   return("intr");
213 }
214
215 void
216 cl_stack_intr::print_info(class cl_console *con)
217 {
218   con->dd_printf("0x%06"_A_"x", called_addr);
219 }
220
221 char *
222 cl_stack_intr::get_matching_name(void)
223 {
224   return("iret");
225 }
226
227 enum stack_op
228 cl_stack_intr::get_matching_op(void)
229 {
230   return(stack_iret);
231 }
232
233 int
234 cl_stack_intr::match(class cl_stack_op *op)
235 {
236   return(op->get_op() == stack_iret);
237 }
238
239
240 /*
241  * PUSH operation on stack
242  */
243
244 cl_stack_push::cl_stack_push(t_addr iPC, t_mem idata,
245                             t_addr iSP_before, t_addr iSP_after):
246   cl_stack_op(stack_push, iPC, iSP_before, iSP_after)
247 {
248   data= idata;
249 }
250
251 class cl_stack_op *
252 cl_stack_push::mk_copy(void)
253 {
254   class cl_stack_push *so= new cl_stack_push(*this);
255   return(so);
256 }
257
258 char *
259 cl_stack_push::get_op_name(void)
260 {
261   return("push");
262 }
263
264 char *
265 cl_stack_push::get_matching_name(void)
266 {
267   return("pop");
268 }
269
270 enum stack_op
271 cl_stack_push::get_matching_op(void)
272 {
273   return(stack_pop);
274 }
275
276 void
277 cl_stack_push::print_info(class cl_console *con)
278 {
279   t_addr d= data;
280   con->dd_printf("0x%06"_A_"x", d);
281 }
282
283 int
284 cl_stack_push::match(class cl_stack_op *op)
285 {
286   return(op->get_op() == stack_pop);
287 }
288
289
290 /*
291  * RETURN operation on stack
292  */
293
294 cl_stack_ret::cl_stack_ret(t_addr iPC, t_addr iaddr,
295                           t_addr iSP_before, t_addr iSP_after):
296   cl_stack_call(iPC, iaddr, 0, iSP_before, iSP_after)
297 {
298   operation= stack_ret;
299 }
300
301 class cl_stack_op *
302 cl_stack_ret::mk_copy(void)
303 {
304   class cl_stack_ret *so= new cl_stack_ret(*this);
305   return(so);
306 }
307
308 char *
309 cl_stack_ret::get_op_name(void)
310 {
311   return("ret");
312 }
313
314 char *
315 cl_stack_ret::get_matching_name(void)
316 {
317   return("call");
318 }
319
320 enum stack_op
321 cl_stack_ret::get_matching_op(void)
322 {
323   return(stack_call);
324 }
325
326 int
327 cl_stack_ret::match(class cl_stack_op *op)
328 {
329   return(op->get_op() == stack_call);
330 }
331
332
333 /*
334  * RETURN from interrupt operation on stack
335  */
336
337 cl_stack_iret::cl_stack_iret(t_addr iPC, t_addr iaddr,
338                             t_addr iSP_before, t_addr iSP_after):
339   cl_stack_ret(iPC, iaddr, iSP_before, iSP_after)
340 {
341   operation= stack_iret;
342 }
343
344 class cl_stack_op *
345 cl_stack_iret::mk_copy(void)
346 {
347   class cl_stack_iret *so= new cl_stack_iret(*this);
348   return(so);
349 }
350
351 char *
352 cl_stack_iret::get_op_name(void)
353 {
354   return("iret");
355 }
356
357 char *
358 cl_stack_iret::get_matching_name(void)
359 {
360   return("intr");
361 }
362
363 enum stack_op
364 cl_stack_iret::get_matching_op(void)
365 {
366   return(stack_intr);
367 }
368
369 int
370 cl_stack_iret::match(class cl_stack_op *op)
371 {
372   return(op->get_op() == stack_intr);
373 }
374
375
376 /*
377  * POP operation on stack
378  */
379
380 cl_stack_pop::cl_stack_pop(t_addr iPC, t_mem idata,
381                           t_addr iSP_before, t_addr iSP_after):
382   cl_stack_push(iPC, idata, iSP_before, iSP_after)
383 {
384   operation= stack_pop;
385 }
386
387 class cl_stack_op *
388 cl_stack_pop::mk_copy(void)
389 {
390   class cl_stack_pop *so= new cl_stack_pop(*this);
391   return(so);
392 }
393
394 char *
395 cl_stack_pop::get_op_name(void)
396 {
397   return("pop");
398 }
399
400 char *
401 cl_stack_pop::get_matching_name(void)
402 {
403   return("push");
404 }
405
406 enum stack_op
407 cl_stack_pop::get_matching_op(void)
408 {
409   return(stack_push);
410 }
411
412 int
413 cl_stack_pop::match(class cl_stack_op *op)
414 {
415   return(op->get_op() == stack_push);
416 }
417
418
419 /*
420  * Stack Errors
421  */
422
423 class cl_error_class *cl_error_stack::error_stack_class;
424
425 cl_error_stack::cl_error_stack(void)
426 {
427   if (NULL == error_stack_class)
428     error_stack_class= new cl_error_class(err_error, "stack", classification, ERROR_OFF);
429   classification= error_stack_class;
430 }
431
432 /* Stack Tracker Errors */
433
434 class cl_error_class *cl_error_stack_tracker::error_stack_tracker_class;
435
436 cl_error_stack_tracker::cl_error_stack_tracker(void)
437 {
438 //  cl_error_class *error_stack_tracker_class = new cl_error_class(err_error, "stack_tracker", error_stack_class, ERROR_OFF);
439 //  classification= &error_stack_tracker_class;
440   if (NULL == error_stack_tracker_class)
441     error_stack_tracker_class= new cl_error_class(err_error, "stack_tracker", classification);
442   classification= error_stack_tracker_class;
443 }
444
445 /* Stack Tracker: wrong handle */
446
447 class cl_error_class *cl_error_stack_tracker_wrong_handle::error_stack_tracker_wrong_handle_class;
448
449 cl_error_stack_tracker_wrong_handle::cl_error_stack_tracker_wrong_handle(bool write_op):
450   cl_error_stack_tracker()
451 {
452   write_operation= write_op;
453   if (NULL == error_stack_tracker_wrong_handle_class)
454     error_stack_tracker_wrong_handle_class= new cl_error_class(err_error, "stack_tracker_wrong_handle", classification);
455   classification= error_stack_tracker_wrong_handle_class;
456 }
457
458 void
459 cl_error_stack_tracker_wrong_handle::print(class cl_commander *c)
460 {
461   c->dd_printf("%s: wrong stack tracker handle called for %s operation\n",
462                get_type_name(), write_operation?"write":"read");
463 }
464
465 /* Stack Tracker: operation on empty stack */
466
467 class cl_error_class *cl_error_stack_tracker_empty::error_stack_tracker_empty_class;
468
469 cl_error_stack_tracker_empty::
470 cl_error_stack_tracker_empty(class cl_stack_op *op):
471   cl_error_stack_tracker()
472 {
473   operation= op->mk_copy();
474   if (NULL == error_stack_tracker_empty_class)
475     error_stack_tracker_empty_class= new cl_error_class(err_error, "operation_on_empty_stack", classification);
476   classification= error_stack_tracker_empty_class;
477 }
478
479 cl_error_stack_tracker_empty::~cl_error_stack_tracker_empty(void)
480 {
481   delete operation;
482 }
483
484 void
485 cl_error_stack_tracker_empty::print(class cl_commander *c)
486 {
487   c->dd_printf("%s(0x%06"_A_"x: %s on empty stack, PC="
488                "0x06"_A_"x, SP=0x%06"_A_"x->0x%06"_A_"x\n",
489                get_type_name(), operation->get_pc(), operation->get_op_name(),
490                operation->get_before(), operation->get_after());
491 }
492
493 /* Stack Tracker: operation on empty stack */
494
495 class cl_error_class *cl_error_stack_tracker_unmatch::error_stack_tracker_unmatch_class;
496
497 cl_error_stack_tracker_unmatch::
498 cl_error_stack_tracker_unmatch(class cl_stack_op *Top, class cl_stack_op *op):
499   cl_error_stack_tracker()
500 {
501   top= Top->mk_copy();
502   operation= op->mk_copy();
503   if (NULL == error_stack_tracker_unmatch_class)
504     error_stack_tracker_unmatch_class= new cl_error_class(err_warning, "stack_operation_unmatched_to_top_of_stack", classification);
505   classification= error_stack_tracker_unmatch_class;
506 }
507
508 cl_error_stack_tracker_unmatch::~cl_error_stack_tracker_unmatch(void)
509 {
510   delete operation;
511   delete top;
512 }
513
514 void
515 cl_error_stack_tracker_unmatch::print(class cl_commander *c)
516 {
517   c->dd_printf("%s(0x%06"_A_"x): %s when %s expected, "
518                "SP=0x%06"_A_"x->0x%06"_A_"x\n",
519                get_type_name(), operation->get_pc(),
520                operation->get_op_name(), top->get_matching_name(),
521                operation->get_before(), operation->get_after());
522 }
523
524 /* Stack Tracker: stack is inconsistent */
525
526 class cl_error_class *cl_error_stack_tracker_inconsistent::error_stack_tracker_inconsistent_class;
527
528 cl_error_stack_tracker_inconsistent::
529 cl_error_stack_tracker_inconsistent(class cl_stack_op *op,
530                                    int the_unread_data_size)
531 {
532   operation= op->mk_copy();
533   unread_data_size= the_unread_data_size;
534   if (NULL == error_stack_tracker_inconsistent_class)
535     error_stack_tracker_inconsistent_class= new cl_error_class(err_warning, "stack_looks_corrupted", classification);
536   classification= error_stack_tracker_inconsistent_class;
537 }
538
539 cl_error_stack_tracker_inconsistent::~cl_error_stack_tracker_inconsistent(void)
540 {
541   delete operation;
542 }
543
544 void
545 cl_error_stack_tracker_inconsistent::print(class cl_commander *c)
546 {
547   c->dd_printf("%s(0x%06"_A_"x): %d byte(s) unread from the stack\n",
548                get_type_name(), operation->get_pc(),
549                unread_data_size);
550 }
551
552
553 /* End of sim.src/stack.cc */