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