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