+class cl_stack_op *
+cl_stack_op::mk_copy(void)
+{
+ class cl_stack_op *so= new cl_stack_op(*this);
+ return(so);
+}
+
+void
+cl_stack_op::info_head(class cl_console_base *con)
+{
+ con->dd_printf("OP SP before-after L DATA/ADDR INSTRUCTION\n");
+}
+
+void
+cl_stack_op::info(class cl_console_base *con, class cl_uc *uc)
+{
+ con->dd_printf("%-4s 0x%06"_A_"x-0x%06"_A_"x %d ",
+ get_op_name(), SP_before, SP_after, abs(SP_before-SP_after));
+ print_info(con);
+ con->dd_printf(" ");
+ uc->print_disass(PC, con);
+ //con->dd_printf("\n");
+}
+
+const char *
+cl_stack_op::get_op_name(void)
+{
+ return("op");
+}
+
+void
+cl_stack_op::print_info(class cl_console_base *con)
+{
+ con->dd_printf("-");
+}
+
+bool
+cl_stack_op::sp_increased(void)
+{
+ if (operation & stack_write_operation)
+ return(SP_after > SP_before);
+ else // read operation
+ return(SP_after < SP_before);
+}
+
+int
+cl_stack_op::data_size(void)
+{
+ int r= SP_after - SP_before;
+
+ return(r<0?-r:r);
+}
+
+int
+cl_stack_op::match(class cl_stack_op *op)
+{
+ return(DD_FALSE);
+}
+
+bool
+cl_stack_op::can_removed(class cl_stack_op *op)
+{
+ bool incr= sp_increased(); // FIXME
+ bool op_incr= op->sp_increased(); // FIXME
+
+ if ((incr && !op_incr) ||
+ (!incr && op_incr))
+ {
+ printf("BIGBIG ERROR!\n");
+ return(DD_FALSE);
+ }
+ if (incr)
+ {
+ t_mem opa= op->get_after();
+ return(SP_before >= opa);
+ }
+ else
+ {
+ t_mem opa= op->get_after();
+ return(SP_before <= opa);
+ }
+}
+
+
+/*
+ * CALL operation on stack
+ */
+
+cl_stack_call::cl_stack_call(t_addr iPC, t_addr called, t_addr pushed,
+ t_addr iSP_before, t_addr iSP_after):
+ cl_stack_op(stack_call, iPC, iSP_before, iSP_after)
+{
+ called_addr= called;
+ pushed_addr= pushed;
+}
+
+class cl_stack_op *
+cl_stack_call::mk_copy(void)
+{
+ class cl_stack_call *so= new cl_stack_call(*this);
+ return(so);
+}
+
+const char *
+cl_stack_call::get_op_name(void)
+{
+ return("call");
+}
+
+void
+cl_stack_call::print_info(class cl_console_base *con)
+{
+ con->dd_printf("0x%06"_A_"x", called_addr);
+}
+
+const char *
+cl_stack_call::get_matching_name(void)
+{
+ return("ret");
+}
+
+enum stack_op
+cl_stack_call::get_matching_op(void)
+{
+ return(stack_ret);
+}
+
+bool
+cl_stack_call::match(class cl_stack_op *op)
+{
+ return(op->get_op() == stack_ret);
+}
+
+
+/*
+ * INTERRUPT operation (call) on stack
+ */
+
+cl_stack_intr::cl_stack_intr(t_addr iPC, t_addr called, t_addr pushed,
+ t_addr iSP_before, t_addr iSP_after):
+ cl_stack_call(iPC, called, pushed, iSP_before, iSP_after)
+{
+ //called_addr= called;
+ //pushed_addr= pushed;
+ operation= stack_intr;
+}
+
+class cl_stack_op *
+cl_stack_intr::mk_copy(void)
+{
+ class cl_stack_intr *so= new cl_stack_intr(*this);
+ return(so);
+}
+
+const char *
+cl_stack_intr::get_op_name(void)
+{
+ return("intr");
+}
+
+void
+cl_stack_intr::print_info(class cl_console_base *con)
+{
+ con->dd_printf("0x%06"_A_"x", called_addr);
+}
+
+const char *
+cl_stack_intr::get_matching_name(void)
+{
+ return("iret");
+}
+
+enum stack_op
+cl_stack_intr::get_matching_op(void)
+{
+ return(stack_iret);
+}
+
+int
+cl_stack_intr::match(class cl_stack_op *op)
+{
+ return(op->get_op() == stack_iret);
+}
+
+
+/*
+ * PUSH operation on stack
+ */
+
+cl_stack_push::cl_stack_push(t_addr iPC, t_mem idata,
+ t_addr iSP_before, t_addr iSP_after):
+ cl_stack_op(stack_push, iPC, iSP_before, iSP_after)
+{
+ data= idata;
+}
+
+class cl_stack_op *
+cl_stack_push::mk_copy(void)
+{
+ class cl_stack_push *so= new cl_stack_push(*this);
+ return(so);
+}
+
+const char *
+cl_stack_push::get_op_name(void)
+{
+ return("push");
+}
+
+const char *
+cl_stack_push::get_matching_name(void)
+{
+ return("pop");
+}
+
+enum stack_op
+cl_stack_push::get_matching_op(void)
+{
+ return(stack_pop);
+}
+
+void
+cl_stack_push::print_info(class cl_console_base *con)
+{
+ t_addr d= data;
+ con->dd_printf("0x%06"_A_"x", d);
+}
+
+int
+cl_stack_push::match(class cl_stack_op *op)
+{
+ return(op->get_op() == stack_pop);
+}
+
+
+/*
+ * RETURN operation on stack
+ */
+
+cl_stack_ret::cl_stack_ret(t_addr iPC, t_addr iaddr,
+ t_addr iSP_before, t_addr iSP_after):
+ cl_stack_call(iPC, iaddr, 0, iSP_before, iSP_after)
+{
+ operation= stack_ret;
+}
+
+class cl_stack_op *
+cl_stack_ret::mk_copy(void)
+{
+ class cl_stack_ret *so= new cl_stack_ret(*this);
+ return(so);
+}
+
+const char *
+cl_stack_ret::get_op_name(void)
+{
+ return("ret");
+}
+
+const char *
+cl_stack_ret::get_matching_name(void)
+{
+ return("call");
+}
+
+enum stack_op
+cl_stack_ret::get_matching_op(void)
+{
+ return(stack_call);
+}
+
+int
+cl_stack_ret::match(class cl_stack_op *op)
+{
+ return(op->get_op() == stack_call);
+}
+
+
+/*
+ * RETURN from interrupt operation on stack
+ */
+
+cl_stack_iret::cl_stack_iret(t_addr iPC, t_addr iaddr,
+ t_addr iSP_before, t_addr iSP_after):
+ cl_stack_ret(iPC, iaddr, iSP_before, iSP_after)
+{
+ operation= stack_iret;
+}
+
+class cl_stack_op *
+cl_stack_iret::mk_copy(void)
+{
+ class cl_stack_iret *so= new cl_stack_iret(*this);
+ return(so);
+}
+
+const char *
+cl_stack_iret::get_op_name(void)
+{
+ return("iret");
+}
+
+const char *
+cl_stack_iret::get_matching_name(void)
+{
+ return("intr");
+}
+
+enum stack_op
+cl_stack_iret::get_matching_op(void)
+{
+ return(stack_intr);
+}
+
+int
+cl_stack_iret::match(class cl_stack_op *op)
+{
+ return(op->get_op() == stack_intr);
+}
+
+
+/*
+ * POP operation on stack
+ */
+
+cl_stack_pop::cl_stack_pop(t_addr iPC, t_mem idata,
+ t_addr iSP_before, t_addr iSP_after):
+ cl_stack_push(iPC, idata, iSP_before, iSP_after)
+{
+ operation= stack_pop;
+}
+
+class cl_stack_op *
+cl_stack_pop::mk_copy(void)
+{
+ class cl_stack_pop *so= new cl_stack_pop(*this);
+ return(so);
+}
+
+const char *
+cl_stack_pop::get_op_name(void)
+{
+ return("pop");
+}
+
+const char *
+cl_stack_pop::get_matching_name(void)
+{
+ return("push");
+}
+
+enum stack_op
+cl_stack_pop::get_matching_op(void)
+{
+ return(stack_push);
+}
+
+int
+cl_stack_pop::match(class cl_stack_op *op)
+{
+ return(op->get_op() == stack_push);
+}
+
+
+/*
+ * Stack Errors
+ */
+
+cl_error_stack::cl_error_stack(void)
+{
+ classification = stack_error_registry.find("stack");
+}
+
+/* Stack Tracker Errors */
+
+cl_error_stack_tracker::cl_error_stack_tracker(void)
+{
+ classification = stack_error_registry.find("stack_tracker");
+}
+
+/* Stack Tracker: wrong handle */
+
+cl_error_stack_tracker_wrong_handle::cl_error_stack_tracker_wrong_handle(bool write_op):
+ cl_error_stack_tracker()
+{
+ write_operation= write_op;
+ classification = stack_error_registry.find("stack_tracker_wrong_handle");
+}
+
+void
+cl_error_stack_tracker_wrong_handle::print(class cl_commander_base *c)
+{
+ c->dd_printf("%s: wrong stack tracker handle called for %s operation\n",
+ get_type_name(), write_operation?"write":"read");
+}
+
+/* Stack Tracker: operation on empty stack */
+
+cl_error_stack_tracker_empty::
+cl_error_stack_tracker_empty(class cl_stack_op *op):
+ cl_error_stack_tracker()
+{
+ operation= op->mk_copy();
+ classification = stack_error_registry.find("operation_on_empty_stack");
+}
+
+cl_error_stack_tracker_empty::~cl_error_stack_tracker_empty(void)
+{
+ delete operation;
+}
+
+void
+cl_error_stack_tracker_empty::print(class cl_commander_base *c)
+{
+ c->dd_printf("%s(0x%06"_A_"x: %s on empty stack, PC="
+ "0x06"_A_"x, SP=0x%06"_A_"x->0x%06"_A_"x\n",
+ get_type_name(), operation->get_pc(), operation->get_op_name(),
+ operation->get_before(), operation->get_after());
+}
+
+/* Stack Tracker: operation on empty stack */
+
+cl_error_stack_tracker_unmatch::
+cl_error_stack_tracker_unmatch(class cl_stack_op *Top, class cl_stack_op *op):
+ cl_error_stack_tracker()
+{
+ top= Top->mk_copy();
+ operation= op->mk_copy();
+ classification = stack_error_registry.find("stack_operation_unmatched_to_top_of_stack");
+}
+
+cl_error_stack_tracker_unmatch::~cl_error_stack_tracker_unmatch(void)
+{
+ delete operation;
+ delete top;
+}
+
+void
+cl_error_stack_tracker_unmatch::print(class cl_commander_base *c)
+{
+ c->dd_printf("%s(0x%06"_A_"x): %s when %s expected, "
+ "SP=0x%06"_A_"x->0x%06"_A_"x\n",
+ get_type_name(), operation->get_pc(),
+ operation->get_op_name(), top->get_matching_name(),
+ operation->get_before(), operation->get_after());
+}
+
+/* Stack Tracker: stack is inconsistent */
+
+cl_error_stack_tracker_inconsistent::
+cl_error_stack_tracker_inconsistent(class cl_stack_op *op,
+ int the_unread_data_size)
+{
+ operation= op->mk_copy();
+ unread_data_size= the_unread_data_size;
+ classification = stack_error_registry.find("stack_looks_corrupted");
+}
+
+cl_error_stack_tracker_inconsistent::~cl_error_stack_tracker_inconsistent(void)
+{
+ delete operation;
+}
+
+void
+cl_error_stack_tracker_inconsistent::print(class cl_commander_base *c)
+{
+ c->dd_printf("%s(0x%06"_A_"x): %d byte(s) unread from the stack\n",
+ get_type_name(), operation->get_pc(),
+ unread_data_size);
+}
+
+cl_stack_error_registry::cl_stack_error_registry(void)
+{
+ class cl_error_class *prev = stack_error_registry.find("non-classified");
+ prev = register_error(new cl_error_class(err_error, "stack", prev, ERROR_OFF));
+ prev = register_error(new cl_error_class(err_error, "stack_tracker", prev));
+ prev = register_error(new cl_error_class(err_error, "stack_tracker_wrong_handle", prev));
+ prev = register_error(new cl_error_class(err_error, "operation_on_empty_stack", prev));
+ prev = register_error(new cl_error_class(err_warning, "stack_operation_unmatched_to_top_of_stack", prev));
+ prev = register_error(new cl_error_class(err_warning, "stack_looks_corrupted", prev));
+}
+
+