summaryrefslogtreecommitdiff
path: root/sim/ucsim/sim.src/uc.cc
diff options
context:
space:
mode:
authorXavier ASUS <xavi92psx@gmail.com>2019-10-18 00:31:54 +0200
committerXavier ASUS <xavi92psx@gmail.com>2019-10-18 00:31:54 +0200
commit268a53de823a6750d6256ee1fb1e7707b4b45740 (patch)
tree42c1799a9a82b2f7d9790ee9fe181d72a7274751 /sim/ucsim/sim.src/uc.cc
downloadsdcc-gas-268a53de823a6750d6256ee1fb1e7707b4b45740.tar.gz
sdcc-3.9.0 fork implementing GNU assembler syntax
This fork aims to provide better support for stm8-binutils
Diffstat (limited to 'sim/ucsim/sim.src/uc.cc')
-rw-r--r--sim/ucsim/sim.src/uc.cc2616
1 files changed, 2616 insertions, 0 deletions
diff --git a/sim/ucsim/sim.src/uc.cc b/sim/ucsim/sim.src/uc.cc
new file mode 100644
index 0000000..983d2b6
--- /dev/null
+++ b/sim/ucsim/sim.src/uc.cc
@@ -0,0 +1,2616 @@
+/*
+ * Simulator of microcontrollers (uc.cc)
+ *
+ * Copyright (C) 1999,99 Drotos Daniel, Talker Bt.
+ *
+ * To contact author send email to drdani@mazsola.iit.uni-miskolc.hu
+ *
+ */
+
+/* This file is part of microcontroller simulator: ucsim.
+
+UCSIM is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+UCSIM is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with UCSIM; see the file COPYING. If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA. */
+/*@1@*/
+
+#include "ddconfig.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <ctype.h>
+#include "i_string.h"
+
+// prj
+#include "globals.h"
+#include "utils.h"
+
+// cmd.src
+#include "newcmdcl.h"
+#include "cmdutil.h"
+#include "cmd_uccl.h"
+#include "cmd_bpcl.h"
+#include "cmd_getcl.h"
+#include "cmd_setcl.h"
+#include "cmd_infocl.h"
+#include "cmd_timercl.h"
+#include "cmd_statcl.h"
+#include "cmd_memcl.h"
+
+// local, sim.src
+#include "uccl.h"
+#include "hwcl.h"
+#include "memcl.h"
+#include "simcl.h"
+#include "itsrccl.h"
+#include "simifcl.h"
+#include "vcdcl.h"
+
+
+static class cl_uc_error_registry uc_error_registry;
+
+/*
+ * Clock counter
+ */
+
+cl_ticker::cl_ticker(int adir, int in_isr, const char *aname)
+{
+ options= TICK_RUN;
+ if (in_isr)
+ options|= TICK_INISR;
+ dir= adir;
+ ticks= 0;
+ set_name(aname);
+}
+
+cl_ticker::~cl_ticker(void) {}
+
+int
+cl_ticker::tick(int nr)
+{
+ if (options&TICK_RUN)
+ ticks+= dir*nr;
+ return(ticks);
+}
+
+double
+cl_ticker::get_rtime(double xtal)
+{
+ double d;
+
+ d= (double)ticks/xtal;
+ return(d);
+}
+
+void
+cl_ticker::dump(int nr, double xtal, class cl_console_base *con)
+{
+ con->dd_printf("timer #%d(\"%s\") %s%s: %g sec (%lu clks)\n",
+ nr, get_name("unnamed"),
+ (options&TICK_RUN)?"ON":"OFF",
+ (options&TICK_INISR)?",ISR":"",
+ get_rtime(xtal), ticks);
+}
+
+
+/*
+ * Options of uc
+ */
+
+cl_xtal_option::cl_xtal_option(class cl_uc *the_uc):
+ cl_optref(the_uc)
+{
+ uc= the_uc;
+}
+
+void
+cl_xtal_option::option_changed(void)
+{
+ if (!uc)
+ return;
+ double d;
+ option->get_value(&d);
+ uc->xtal= d;
+}
+
+
+/* Time measurer */
+
+cl_time_measurer::cl_time_measurer(class cl_uc *the_uc):
+ cl_base()
+{
+ to_reach= 0;
+ uc= the_uc;
+}
+
+void
+cl_time_measurer::set_reach(unsigned long val)
+{
+ to_reach= val;
+}
+
+void
+cl_time_measurer::from_now(unsigned long val)
+{
+ set_reach(now() + val);
+}
+
+bool
+cl_time_measurer::reached()
+{
+ return to_reach &&
+ (now() >= to_reach);
+}
+
+unsigned long
+cl_time_measurer::now()
+{
+ return 0;
+}
+
+
+/* value of xtal clock */
+
+unsigned long
+cl_time_clk::now()
+{
+ if (!uc) return 0;
+ return uc->ticks->ticks;
+}
+
+
+/* value of virtual clocks */
+
+unsigned long
+cl_time_vclk::now()
+{
+ if (!uc) return 0;
+ return uc->vc.fetch + uc->vc.rd + uc->vc.wr;
+}
+
+
+/* value of fetches */
+
+unsigned long
+cl_time_fclk::now()
+{
+ if (!uc) return 0;
+ return uc->vc.fetch;
+}
+
+
+/* value of reads */
+
+unsigned long
+cl_time_rclk::now()
+{
+ if (!uc) return 0;
+ return uc->vc.rd;
+}
+
+
+/* value of writes */
+
+unsigned long
+cl_time_wclk::now()
+{
+ if (!uc) return 0;
+ return uc->vc.wr;
+}
+
+
+/* OMF file record */
+
+cl_omf_rec::cl_omf_rec(void):
+ cl_base()
+{
+ offset= 0;
+ f_offset= 0;
+ type= 0;
+ len= 0;
+ rec= NULL;
+ chk= 0;
+}
+
+cl_omf_rec::~cl_omf_rec(void)
+{
+ if (rec)
+ free(rec);
+}
+
+unsigned char
+cl_omf_rec::g(cl_f *f)
+{
+ unsigned char c= f->get_c();
+ offset++;
+ return c;
+}
+
+u16_t
+cl_omf_rec::pick_word(int i)
+{
+ unsigned char h, l;
+ u16_t w;
+
+ if (i >= len-1)
+ return 0;
+ l= rec[i];
+ h= rec[i+1];
+ w= h*256+l;
+ return w;
+}
+
+chars
+cl_omf_rec::pick_str(int i)
+{
+ unsigned char l, j;
+ chars s= "";
+
+ if (i >= len-1)
+ return chars("");
+ l= rec[i];
+ j= 0;
+ while (l &&
+ (i < len))
+ {
+ s+= rec[i+1+j];
+ l--;
+ j++;
+ }
+ return s;
+}
+
+bool
+cl_omf_rec::read(cl_f *f)
+{
+ unsigned char c;
+ int i, l, h;
+
+ if (rec)
+ {
+ free(rec);
+ rec= NULL;
+ }
+ f_offset= offset;
+ if (f->eof())
+ return false;
+ c= g(f);
+ type= c;
+ if (f->eof())
+ return false;
+ c= g(f);
+ l= c;
+ //printf("l=%02x\n", c);
+ if (f->eof())
+ return false;
+ c= g(f);
+ h= c;
+ //printf("h=%02x\n", c);
+ if (f->eof())
+ return false;
+ len= h*256+l-1;
+ rec= (u8_t*)malloc(len);
+ for (i= 0; i < len; i++)
+ {
+ rec[i]= g(f);
+ if (f->eof())
+ return false;
+ }
+ chk= g(f);
+
+ return true;
+}
+
+
+/*
+ * Abstract microcontroller
+ ******************************************************************************
+ */
+
+cl_uc::cl_uc(class cl_sim *asim):
+ cl_base()
+{
+ type= NULL;
+ //int i;
+ sim = asim;
+ //mems= new cl_list(MEM_TYPES, 1);
+ memchips= new cl_list(2, 2, "memchips");
+ address_spaces= new cl_address_space_list(this);
+ //address_decoders= new cl_list(2, 2);
+ rom= 0;
+
+ hws = new cl_hws();
+ //options= new cl_list(2, 2);
+ //for (i= MEM_ROM; i < MEM_TYPES; i++) mems->add(0);
+ xtal_option= new cl_xtal_option(this);
+ xtal_option->init();
+ ticks= new cl_ticker(+1, 0, "time");
+ isr_ticks= new cl_ticker(+1, TICK_INISR, "isr");
+ idle_ticks= new cl_ticker(+1, TICK_IDLE, "idle");
+ counters= new cl_list(2, 2, "counters");
+ it_levels= new cl_list(2, 2, "it levels");
+ it_sources= new cl_irqs(2, 2);
+ class it_level *il= new it_level(-1, 0, 0, 0);
+ it_levels->push(il);
+ stack_ops= new cl_list(2, 2, "stack operations");
+ errors= new cl_list(2, 2, "errors in uc");
+ events= new cl_list(2, 2, "events in uc");
+ sp_max= 0;
+ sp_avg= 0;
+ inst_exec= false;
+}
+
+
+cl_uc::~cl_uc(void)
+{
+ //delete mems;
+ delete hws;
+ //delete options;
+ delete ticks;
+ delete isr_ticks;
+ delete idle_ticks;
+ delete counters;
+ events->disconn_all();
+ delete events;
+ delete fbrk;
+ delete ebrk;
+ delete it_levels;
+ delete it_sources;
+ delete stack_ops;
+ errors->free_all();
+ delete errors;
+ delete xtal_option;
+ delete address_spaces;
+ delete memchips;
+ //delete address_decoders;
+}
+
+
+int
+cl_uc::init(void)
+{
+ int i;
+
+ set_name("controller");
+ cl_base::init();
+ if (xtal_option->use("xtal"))
+ xtal= xtal_option->get_value(xtal);
+ else
+ xtal= 11059200;
+ vars= new cl_var_list();
+ make_variables();
+ make_memories();
+ if (rom == NULL)
+ rom= address_space(cchars("rom")/*MEM_ROM_ID*/);
+ ebrk= new brk_coll(2, 2, rom);
+ fbrk= new brk_coll(2, 2, rom);
+ fbrk->Duplicates= false;
+ brk_counter= 0;
+ stop_at_time= 0;
+ make_cpu_hw();
+ mk_hw_elements();
+ class cl_cmdset *cs= sim->app->get_commander()->cmdset;
+ build_cmdset(cs);
+ irq= false;
+ reset();
+
+ return 0;
+ for (i= 0; i < sim->app->in_files->count; i++)
+ {
+ char *fname= (char *)(sim->app->in_files->at(i));
+ long l;
+ if ((l= read_hex_file(fname)) >= 0)
+ {
+ /*sim->app->get_commander()->all_*/printf("%ld words read from %s\n",
+ l, fname);
+ }
+ }
+ return(0);
+}
+
+char *
+cl_uc::id_string(void)
+{
+ return((char*)"unknown microcontroller");
+}
+
+void
+cl_uc::reset(void)
+{
+ class it_level *il;
+
+ irq= false;
+ instPC= PC= 0;
+ state = stGO;
+ ticks->ticks= 0;
+ isr_ticks->ticks= 0;
+ idle_ticks->ticks= 0;
+ vc.inst= vc.fetch= vc.rd= vc.wr= 0;
+ /*FIXME should we clear user counters?*/
+ il= (class it_level *)(it_levels->top());
+ while (il &&
+ il->level >= 0)
+ {
+ il= (class it_level *)(it_levels->pop());
+ delete il;
+ il= (class it_level *)(it_levels->top());
+ }
+ sp_max= 0;
+ sp_avg= 0;
+
+ stack_ops->free_all();
+
+ int i;
+ for (i= 0; i < hws->count; i++)
+ {
+ class cl_hw *hw= (class cl_hw *)(hws->at(i));
+ hw->reset();
+ }
+}
+
+/*
+ * Making elements
+ */
+
+void
+cl_uc::make_memories(void)
+{
+}
+
+void
+cl_uc::make_variables(void)
+{
+ class cl_address_space *as;
+ class cl_option *o= sim->app->options->get_option("var_size");
+ long l, i;
+
+ if (o)
+ o->get_value(&l);
+ else
+ l= 0x100;
+
+ class cl_address_decoder *ad;
+ class cl_memory_chip *chip;
+
+ if (l > 0)
+ {
+ variables= as= new cl_address_space("variables", 0, l, 32);
+ as->init();
+ address_spaces->add(as);
+
+ chip= new cl_memory_chip("variable_storage", l, 32);
+ chip->init();
+ memchips->add(chip);
+ ad= new cl_address_decoder(variables, chip, 0, l-1, 0);
+ ad->init();
+ variables->decoders->add(ad);
+ ad->activate(0);
+
+ for (i= 0; i < l; i++)
+ variables->set(i, 0);
+ }
+}
+
+/*t_addr
+cl_uc::get_mem_size(char *id)
+{
+ class cl_memory *m= memory(id);
+ return(m?(m->get_size()):0);
+}
+
+int
+cl_uc::get_mem_width(char *id)
+{
+ class cl_memory *m= memory(id);
+ return(m?(m->width):8);
+}
+*/
+void
+cl_uc::make_cpu_hw(void)
+{
+ cpu= NULL;
+}
+
+void
+cl_uc::mk_hw_elements(void)
+{
+ class cl_hw *h;
+
+ add_hw(h= new cl_simulator_interface(this));
+ h->init();
+ add_hw(h= new cl_vcd(this, 0, "vcd"));
+ h->init();
+}
+
+void
+cl_uc::build_cmdset(class cl_cmdset *cmdset)
+{
+ class cl_cmd *cmd;
+ class cl_super_cmd *super_cmd;
+ class cl_cmdset *cset;
+
+ cmdset->add(cmd= new cl_state_cmd("state", 0));
+ cmd->init();
+
+#ifdef STATISTIC
+ cmdset->add(cmd= new cl_statistic_cmd("statistic", 0));
+ cmd->init();
+#endif
+
+ cmdset->add(cmd= new cl_file_cmd("file", 0));
+ cmd->init();
+ cmd->add_name("load");
+
+ cmdset->add(cmd= new cl_dl_cmd("download", 0));
+ cmd->init();
+ cmd->add_name("dl");
+
+ cmdset->add(cmd= new cl_pc_cmd("pc", 0));
+ cmd->init();
+
+ cmdset->add(cmd= new cl_reset_cmd("reset", 0));
+ cmd->init();
+
+ cmdset->add(cmd= new cl_dump_cmd("dump", true));
+ cmd->init();
+
+ cmdset->add(cmd= new cl_dch_cmd("dch", true));
+ cmd->init();
+
+ cmdset->add(cmd= new cl_dc_cmd("dc", true));
+ cmd->init();
+
+ cmdset->add(cmd= new cl_disassemble_cmd("disassemble", true));
+ cmd->init();
+
+ cmdset->add(cmd= new cl_fill_cmd("fill", 0));
+ cmd->init();
+
+ cmdset->add(cmd= new cl_where_cmd("where", 0));
+ cmd->init();
+
+ cmdset->add(cmd= new cl_Where_cmd("Where", 0));
+ cmd->init();
+
+ cmdset->add(cmd= new cl_hole_cmd("hole", 0));
+ cmd->init();
+
+ cmdset->add(cmd= new cl_break_cmd("break", 0));
+ cmd->init();
+
+ cmdset->add(cmd= new cl_tbreak_cmd("tbreak", 0));
+ cmd->init();
+
+ cmdset->add(cmd= new cl_clear_cmd("clear", 0));
+ cmd->init();
+
+ cmdset->add(cmd= new cl_delete_cmd("delete", 0));
+ cmd->init();
+
+ cmdset->add(cmd= new cl_commands_cmd("commands", 0));
+ cmd->init();
+
+ {
+ super_cmd= (class cl_super_cmd *)(cmdset->get_cmd("get"));
+ if (super_cmd)
+ cset= super_cmd->commands;
+ else {
+ cset= new cl_cmdset();
+ cset->init();
+ }
+ cset->add(cmd= new cl_get_sfr_cmd("sfr", 0));
+ cmd->init();
+ /*cset->add(cmd= new cl_get_option_cmd("option", 0));
+ cmd->init();*/
+ }
+ if (!super_cmd)
+ {
+ cmdset->add(cmd= new cl_super_cmd("get", 0, cset));
+ cmd->init();
+ set_get_help(cmd);
+ }
+
+ {
+ super_cmd= (class cl_super_cmd *)(cmdset->get_cmd("set"));
+ if (super_cmd)
+ cset= super_cmd->commands;
+ else {
+ cset= new cl_cmdset();
+ cset->init();
+ }
+ cset->add(cmd= new cl_set_mem_cmd("memory", 0));
+ cmd->init();
+ cset->add(cmd= new cl_set_bit_cmd("bit", 0));
+ cmd->init();
+ cset->add(cmd= new cl_set_hw_cmd("hardware", 0));
+ cmd->add_name("hw");
+ cmd->init();
+ }
+ if (!super_cmd)
+ {
+ cmdset->add(cmd= new cl_super_cmd("set", 0, cset));
+ cmd->init();
+ set_set_help(cmd);
+ }
+
+ { // info
+ super_cmd= (class cl_super_cmd *)(cmdset->get_cmd("info"));
+ if (super_cmd)
+ cset= super_cmd->get_subcommands();
+ else {
+ cset= new cl_cmdset();
+ cset->init();
+ }
+ cset->add(cmd= new cl_info_bp_cmd("breakpoints", 0));
+ cmd->add_name("bp");
+ cmd->init();
+ cset->add(cmd= new cl_info_reg_cmd("registers", 0));
+ cmd->init();
+ cset->add(cmd= new cl_info_hw_cmd("hardware", 0));
+ cmd->add_name("hw");
+ cmd->init();
+ /*
+ cset->add(cmd= new cl_info_stack_cmd("stack", 0,
+ "info stack Status of stack of the CPU",
+ "long help of info stack"));
+ cmd->init();
+ */
+ cset->add(cmd= new cl_info_memory_cmd("memory", 0));
+ cmd->init();
+ cset->add(cmd= new cl_info_var_cmd("variables", 0));
+ cmd->init();
+ cmd->add_name("vars");
+ }
+ if (!super_cmd) {
+ cmdset->add(cmd= new cl_super_cmd("info", 0, cset));
+ cmd->init();
+ set_info_help(cmd);
+ }
+
+ {
+ super_cmd= (class cl_super_cmd *)(cmdset->get_cmd("timer"));
+ if (super_cmd)
+ cset= super_cmd->get_subcommands();
+ else {
+ cset= new cl_cmdset();
+ cset->init();
+ }
+ cset->add(cmd= new cl_timer_add_cmd("add", 0));
+ cmd->init();
+ cmd->add_name("create");
+ cmd->add_name("make");
+ cset->add(cmd= new cl_timer_delete_cmd("delete", 0));
+ cmd->init();
+ cmd->add_name("remove");
+ cset->add(cmd= new cl_timer_get_cmd("get", 0));
+ cmd->init();
+ cset->add(cmd= new cl_timer_run_cmd("run", 0));
+ cmd->init();
+ cmd->add_name("start");
+ cset->add(cmd= new cl_timer_stop_cmd("stop", 0));
+ cmd->init();
+ cset->add(cmd= new cl_timer_value_cmd("set", 0));
+ cmd->init();
+ cmd->add_name("value");
+ }
+ if (!super_cmd) {
+ cmdset->add(cmd= new cl_super_cmd("timer", 0, cset));
+ cmd->init();
+ set_timer_help(cmd);
+ }
+
+ {
+ class cl_super_cmd *mem_create;
+ class cl_cmdset *mem_create_cset;
+ super_cmd= (class cl_super_cmd *)(cmdset->get_cmd("memory"));
+ if (super_cmd)
+ cset= super_cmd->get_subcommands();
+ else {
+ cset= new cl_cmdset();
+ cset->init();
+ }
+ /*
+ cset->add(cmd= new cl_memory_cmd("_no_parameters_", 0));
+ cmd->init();
+ */
+ mem_create= (class cl_super_cmd *)cset->get_cmd("create");
+ if (mem_create)
+ mem_create_cset= mem_create->get_subcommands();
+ else {
+ mem_create_cset= new cl_cmdset();
+ mem_create_cset->init();
+ }
+
+ mem_create_cset->add(cmd= new cl_memory_create_chip_cmd("chip", 0));
+ cmd->init();
+
+ mem_create_cset->add(cmd= new cl_memory_create_addressspace_cmd("addressspace", 0));
+ cmd->init();
+ cmd->add_name("addrspace");
+ cmd->add_name("aspace");
+ cmd->add_name("as");
+ cmd->add_name("addrs");
+ cmd->add_name("addr");
+
+ mem_create_cset->add(cmd= new cl_memory_create_addressdecoder_cmd("addressdecoder", 0));
+ cmd->init();
+ cmd->add_name("addrdecoder");
+ cmd->add_name("adecoder");
+ cmd->add_name("addressdec");
+ cmd->add_name("addrdec");
+ cmd->add_name("adec");
+ cmd->add_name("ad");
+
+ mem_create_cset->add(cmd= new cl_memory_create_banker_cmd("banker", 0));
+ cmd->init();
+ cmd->add_name("bankswitcher");
+ cmd->add_name("banksw");
+ cmd->add_name("bsw");
+ cmd->add_name("bs");
+
+ mem_create_cset->add(cmd= new cl_memory_create_bank_cmd("bank", 0));
+ cmd->init();
+
+ mem_create_cset->add(cmd= new cl_memory_create_bander_cmd("bander", 0));
+ cmd->init();
+ cmd->add_name("bitbander");
+ cmd->add_name("bitband");
+ cmd->add_name("band");
+ cmd->add_name("bb");
+
+ if (!mem_create)
+ cset->add(mem_create= new cl_super_cmd("create", 0, mem_create_cset));
+ mem_create->init();
+ mem_create->add_name("add");
+ set_memory_create_help(mem_create);
+
+ cset->add(cmd= new cl_info_memory_cmd("info", 0));
+ cmd->init();
+ cset->add(cmd= new cl_memory_cell_cmd("cell", 0));
+ cmd->init();
+ }
+ if (!super_cmd) {
+ cmdset->add(cmd= new cl_super_cmd("memory", 0, cset));
+ cmd->init();
+ set_memory_help(cmd);
+ }
+
+ cmdset->add(cmd= new cl_var_cmd("var", 0));
+ cmd->init();
+ cmd->add_name("variable");
+}
+
+
+/*
+ * Read/write simulated memory
+ */
+
+t_mem
+cl_uc::read_mem(char *id, t_addr addr)
+{
+ class cl_address_space *m= address_space(id);
+
+ return(m?(m->read(addr)):0);
+}
+
+t_mem
+cl_uc::get_mem(char *id, t_addr addr)
+{
+ class cl_address_space *m= address_space(id);
+
+ return(m?(m->get(addr)):0);
+}
+
+void
+cl_uc::write_mem(char *id, t_addr addr, t_mem val)
+{
+ class cl_address_space *m= address_space(id);
+
+ if (m)
+ m->write(addr, val);
+}
+
+void
+cl_uc::set_mem(char *id, t_addr addr, t_mem val)
+{
+ class cl_address_space *m= address_space(id);
+
+ if(m)
+ m->set(addr, val);
+}
+
+
+/*
+class cl_memory *
+cl_uc::mem(enum mem_class type)
+{
+ class cl_m *m;
+
+ if (mems->count < type)
+ m= (class cl_m *)(mems->at(MEM_DUMMY));
+ else
+ m= (class cl_m *)(mems->at(type));
+ return(m);
+}
+*/
+
+class cl_address_space *
+cl_uc::address_space(const char *id)
+{
+ int i;
+
+ if (!id ||
+ !(*id))
+ return(0);
+ for (i= 0; i < address_spaces->count; i++)
+ {
+ class cl_address_space *m= (cl_address_space *)(address_spaces->at(i));
+ if (!m ||
+ !m->have_real_name())
+ continue;
+ if (m->is_inamed(id))
+ return(m);
+ }
+ return(0);
+}
+
+class cl_address_space *
+cl_uc::address_space(class cl_memory_cell *cell)
+{
+ return(address_space(cell, (t_addr*)NULL));
+}
+
+class cl_address_space *
+cl_uc::address_space(class cl_memory_cell *cell, t_addr *addr)
+{
+ int i;
+
+ for (i= 0; i < address_spaces->count; i++)
+ {
+ class cl_address_space *m= (cl_address_space *)(address_spaces->at(i));
+ if (!m)
+ continue;
+ if (m->is_owned(cell, addr))
+ return(m);
+ }
+ return(0);
+}
+
+class cl_memory *
+cl_uc::memory(const char *id)
+{
+ int i;
+
+ if (!id ||
+ !(*id))
+ return(0);
+ for (i= 0; i < address_spaces->count; i++)
+ {
+ class cl_base *b= address_spaces->object_at(i);
+ class cl_memory *m= dynamic_cast<cl_memory *>(b);
+ if (!m ||
+ !m->have_real_name())
+ continue;
+ if (m->is_inamed(id))
+ return(m);
+ }
+ for (i= 0; i < memchips->count; i++)
+ {
+ class cl_memory *m= (cl_memory *)(memchips->at(i));
+ if (!m ||
+ !m->have_real_name())
+ continue;
+ if (m->is_inamed(id))
+ return(m);
+ }
+ return(0);
+}
+
+
+static long
+ReadInt(cl_f *f, bool *ok, int bytes)
+{
+ char s2[3];
+ long l= 0;
+ int c;
+
+ *ok= false;
+ while (bytes)
+ {
+ if (f->eof())
+ return(0);
+ c= f->get_c();
+ if ((c < 0) ||
+ (c == 0) ||
+ (c > 0xff))
+ return 0;
+ s2[0]= c;
+ if (f->eof())
+ return(0);
+ c= f->get_c();
+ if ((c < 0) ||
+ (c == 0) ||
+ (c > 0xff))
+ return 0;
+ s2[1]= c;
+ s2[2]= '\0';
+ l= l*256 + strtol(s2, NULL, 16);
+ bytes--;
+ }
+ *ok= true;
+ return(l);
+}
+
+
+/*
+ * Reading intel hexa file into EROM
+ *____________________________________________________________________________
+ *
+ * If parameter is a NULL pointer, this function reads data from `cmd_in'
+ *
+ */
+
+void
+cl_uc::set_rom(t_addr addr, t_mem val)
+{
+ //printf("rom[%06lx]=%02x\n", addr, val);
+ t_addr size= rom->get_size();
+ if (addr < size)
+ {
+ rom->download(addr, val);
+ return;
+ }
+ t_addr bank, caddr;
+ bank= addr / size;
+ caddr= addr % size;
+ //printf("getting decoder of %ld/%lx\n", bank, caddr);
+ class cl_banker *d= (class cl_banker *)(rom->get_decoder_of(caddr));
+ if (d)
+ {
+ if (!d->is_banker())
+ {
+ //printf("cell at %lx has no banker\n", caddr);
+ return;
+ }
+ //printf("setting %ld/rom[%lx]=%x\n", bank, caddr, val);
+ d->switch_to(bank, NULL);
+ rom->download(caddr, val);
+ d->activate(NULL);
+ }
+ else
+ ;//printf("no decoder at %lx\n", caddr);
+}
+
+long
+cl_uc::read_hex_file(const char *nam)
+{
+ cl_f *f;
+
+ if (!nam)
+ {
+ fprintf(stderr, "cl_uc::read_hex_file File name not specified\n");
+ return(-1);
+ }
+ else
+ if ((f= /*fopen*/mk_io(nam, "r")) == NULL)
+ {
+ fprintf(stderr, "Can't open `%s': %s\n", nam, strerror(errno));
+ return(-1);
+ }
+ long l= read_hex_file(f);
+ delete f;
+ return l;
+}
+
+long
+cl_uc::read_hex_file(cl_console_base *con)
+{
+ cl_f *f;
+ if (con == NULL)
+ return -1;
+ f= con->get_fin();
+ if (f == NULL)
+ return -1;
+ long l= read_hex_file(f);
+ return l;
+}
+
+long
+cl_uc::read_hex_file(cl_f *f)
+{
+ int c;
+ long written= 0, recnum= 0;
+
+ uint base= 0; // extended address, added to every adress
+ uchar dnum; // data number
+ uchar rtyp=0; // record type
+ uint addr= 0; // address
+ uchar rec[300]; // data record
+ uchar sum ; // checksum
+ uchar chk ; // check
+ int i;
+ bool ok, get_low= 1;
+ uchar low= 0, high;
+
+ if (!rom)
+ {
+ sim->app->get_commander()->
+ dd_printf("No ROM address space to read in.\n");
+ return(-1);
+ }
+
+ //memset(inst_map, '\0', sizeof(inst_map));
+ ok= true;
+ while (ok &&
+ rtyp != 1)
+ {
+ while (((c= /*getc(f)*/f->get_c()) != ':') &&
+ (/*c != EOF*/!f->eof())) /*printf("search_record=%c\n",c)*/;
+ if (c != ':')
+ {fprintf(stderr, ": not found\n");break;}
+ recnum++;
+ dnum= ReadInt(f, &ok, 1);//printf("%ld:dnum=%02x ",recnum,dnum);
+ chk = dnum;
+ addr= ReadInt(f, &ok, 2);//printf("%ld:addr=%04x ",recnum,addr);
+ chk+= (addr & 0xff);
+ chk+= ((addr >> 8) & 0xff);
+ rtyp= ReadInt(f, &ok, 1);//printf("%ld:rtyp=%02x ",recnum,rtyp);
+ chk+= rtyp;
+ for (i= 0; ok && (i < dnum); i++)
+ {
+ rec[i]= ReadInt(f, &ok, 1);//printf("%02x",rec[i]);
+ chk+= rec[i];
+ }
+ if (ok)
+ {
+ sum= ReadInt(f, &ok, 1);//printf(" %ld:sum=%02x\n",recnum,sum);
+ if (ok)
+ {
+ if (((sum + chk) & 0xff) == 0)
+ {
+ if (rtyp == 0)
+ {
+ if (rom->width > 8)
+ addr/= 2;
+ for (i= 0; i < dnum; i++)
+ {
+ if (rom->width <= 8)
+ {
+ set_rom(base+addr, rec[i]);
+ addr++;
+ written++;
+ }
+ else if (rom->width <= 16)
+ {
+ if (get_low)
+ {
+ low= rec[i];
+ get_low= 0;
+ }
+ else
+ {
+ high= rec[i];
+ set_rom(base+addr, (high*256)+low);
+ addr++;
+ written++;
+ get_low= 1;
+ }
+ }
+ }
+ }
+ else if (rtyp == 4)
+ {
+ //printf("hex record type=4\n");
+ if (dnum >= 2)
+ {
+ base= (rec[0]*256+rec[1]) << 16;
+ //printf("hex base=%x\n", base);
+ }
+ }
+ else
+ if (rtyp != 1)
+ /*application->debug*/fprintf(stderr, "Unknown record type %d(0x%x)\n",
+ rtyp, rtyp);
+ }
+ else
+ /*application->debug*/fprintf(stderr, "Checksum error (%x instead of %x) in "
+ "record %ld.\n", chk, sum, recnum);
+ }
+ else
+ /*application->debug*/fprintf(stderr, "Read error in record %ld.\n", recnum);
+ }
+ }
+ if (rom->width > 8 &&
+ !get_low)
+ rom->set(addr, low);
+
+ analyze(0);
+ return(written);
+}
+
+long
+cl_uc::read_omf_file(cl_f *f)
+{
+ long written= 0;
+ class cl_omf_rec rec;
+ while (rec.read(f))
+ {
+ if (rec.type == 0x06)
+ {
+ // content
+ u16_t addr= rec.pick_word(1);
+ int i= 3;
+ while (i < rec.len)
+ {
+ set_rom(addr+i, rec.rec[i]);
+ written++;
+ i++;
+ }
+ }
+ }
+ return (written);
+}
+
+long
+cl_uc::read_cdb_file(cl_f *f)
+{
+ class cl_cdb_recs *fns= new cl_cdb_recs();
+ chars ln;
+ char *lc;
+ long cnt= 0;
+ class cl_cdb_rec *r;
+ class cl_var *v;
+
+ ln= f->get_s();
+ while (!ln.empty())
+ {
+ //printf("CBD LN=%s\n",(char*)ln);
+ lc= (char*)ln;
+ if (lc[0] == 'F')
+ {
+ if (ln.len() > 5)
+ {
+ if ((lc[1] == ':') &&
+ (lc[2] == 'G'))
+ {
+ ln.start_parse(4);
+ chars n= ln.token("$");
+ if ((r= fns->rec(n)) != NULL)
+ {
+ vars->add(v= new cl_var(n, rom, r->addr, ""));
+ v->init();
+ fns->del(n);
+ cnt++;
+ }
+ else
+ fns->add(new cl_cdb_rec(n));
+ }
+ }
+ }
+ else if (lc[0] == 'L')
+ {
+ if (ln.len() > 5)
+ {
+ if ((ln[1] == ':') &&
+ (lc[2] == 'G'))
+ {
+ ln.start_parse(4);
+ chars n= ln.token("$");
+ chars t= ln.token(":");
+ t= ln.token(" ");
+ t_addr a= strtol((char*)t, 0, 16);
+ if ((r= fns->rec(n)) != NULL)
+ {
+ fns->del(n);
+ vars->add(v= new cl_var(n, rom, a, ""));
+ v->init();
+ cnt++;
+ }
+ else
+ fns->add(new cl_cdb_rec(n, a));
+ }
+ }
+ }
+ ln= f->get_s();
+ }
+ fns->free_all();
+ delete fns;
+ return cnt;
+}
+
+cl_f *
+cl_uc::find_loadable_file(chars nam)
+{
+ cl_f *f;
+ bool o;
+ chars c;
+
+ f= mk_io(nam, "r");
+ o= (f->opened());
+ if (o)
+ return f;
+
+ c= chars("", "%s.ihx", (char*)nam);
+ f->open(c, chars("r"));
+ o= (f->opened());
+ if (o)
+ return f;
+ c= chars("", "%s.hex", (char*)nam);
+ f->open(c, chars("r"));
+ o= (f->opened());
+ if (o)
+ return f;
+ c= chars("", "%s.ihex", (char*)nam);
+ f->open(c, chars("r"));
+ o= (f->opened());
+ if (o)
+ return f;
+
+ c= chars("", "%s.omf", (char*)nam);
+ f->open(c, chars("r"));
+ o= (f->opened());
+ if (o)
+ return f;
+
+ delete f;
+ return NULL;
+}
+
+long
+cl_uc::read_file(chars nam, class cl_console_base *con)
+{
+ cl_f *f= find_loadable_file(nam);
+ long l= 0;
+
+ if (!f)
+ {
+ if (con) con->dd_printf("no loadable file found\n");
+ return 0;
+ }
+ /*if (con) con->dd_*/printf("Loading from %s\n", f->get_file_name());
+ if (is_hex_file(f))
+ {
+ l= read_hex_file(f);
+ printf("%ld words read from %s\n", l, f->get_fname());
+ }
+ else if (is_omf_file(f))
+ {
+ l= read_omf_file(f);
+ printf("%ld words read from %s\n", l, f->get_fname());
+ }
+ else if (is_cdb_file(f))
+ {
+ l= read_cdb_file(f);
+ printf("%ld symbols read from %s\n", l, f->get_fname());
+ }
+ if (strcmp(nam, f->get_fname()) != 0)
+ {
+ chars n= nam;
+ n+= (char*)".cdb";
+ cl_f *c= mk_io(n, "r");
+ if (c->opened())
+ {
+ l= read_cdb_file(c);
+ printf("%ld symbols read from %s\n", l, c->get_fname());
+ }
+ delete c;
+ }
+ delete f;
+ return l;
+}
+
+
+/*
+ * Handling instruction map
+ *
+ * `inst_at' is checking if the specified address is in instruction
+ * map and `set_inst_at' marks the address in the map and
+ * `del_inst_at' deletes the mark. `there_is_inst' cheks if there is
+ * any mark in the map
+ */
+
+bool
+cl_uc::inst_at(t_addr addr)
+{
+ if (!rom)
+ return(0);
+ return(rom->get_cell_flag(addr, CELL_INST));
+}
+
+void
+cl_uc::set_inst_at(t_addr addr)
+{
+ if (rom)
+ rom->set_cell_flag(addr, true, CELL_INST);
+}
+
+void
+cl_uc::del_inst_at(t_addr addr)
+{
+ if (rom)
+ rom->set_cell_flag(addr, false, CELL_INST);
+}
+
+bool
+cl_uc::there_is_inst(void)
+{
+ if (!rom)
+ return(0);
+ bool got= false;
+ t_addr addr;
+ for (addr= 0; rom->valid_address(addr) && !got; addr++)
+ got= rom->get_cell_flag(addr, CELL_INST);
+ return(got);
+}
+
+
+/*
+ * Manipulating HW elements of the CPU
+ *****************************************************************************
+ */
+
+/* Register callback hw objects for mem read/write */
+
+/*void
+cl_uc::register_hw_read(enum mem_class type, t_addr addr, class cl_hw *hw)
+{
+ class cl_m *m;
+ class cl_memloc *l;
+
+ if ((m= (class cl_m*)mems->at(type)))
+ {
+ if ((l= m->read_locs->get_loc(addr)) == 0)
+ {
+ l= new cl_memloc(addr);
+ l->init();
+ m->read_locs->add(l);
+ }
+ l->hws->add(hw);
+ }
+ else
+ printf("cl_uc::register_hw_read TROUBLE\n");
+}*/
+
+/*void
+cl_uc::register_hw_write(enum mem_class type, t_addr addr, class cl_hw *hw)
+{
+}*/
+
+void
+cl_uc::add_hw(class cl_hw *hw)
+{
+ int i;
+ for (i= 0; i < hws->count; i++)
+ {
+ class cl_hw *h= (class cl_hw *)(hws->at(i));
+ h->new_hw_adding(hw);
+ }
+ hws->add(hw);
+ for (i= 0; i < hws->count; i++)
+ {
+ class cl_hw *h= (class cl_hw *)(hws->at(i));
+ if (h != hw)
+ h->new_hw_added(hw);
+ }
+}
+
+int
+cl_uc::nuof_hws(void)
+{
+ return hws->count;
+}
+
+/* Looking for a specific HW element */
+
+class cl_hw *
+cl_uc::get_hw(int idx)
+{
+ if (idx >= hws->count)
+ return NULL;
+ return (class cl_hw *)(hws->at(idx));
+}
+
+class cl_hw *
+cl_uc::get_hw(enum hw_cath cath, int *idx)
+{
+ class cl_hw *hw= 0;
+ int i= 0;
+
+ if (idx)
+ i= *idx;
+ for (; i < hws->count; i++)
+ {
+ hw= (class cl_hw *)(hws->at(i));
+ if (hw->cathegory == cath)
+ break;
+ }
+ if (i >= hws->count)
+ return(0);
+ if (idx)
+ *idx= i;
+ return(hw);
+}
+
+class cl_hw *
+cl_uc::get_hw(char *id_string, int *idx)
+{
+ class cl_hw *hw= 0;
+ int i= 0;
+
+ if (idx)
+ i= *idx;
+ for (; i < hws->count; i++)
+ {
+ hw= (class cl_hw *)(hws->at(i));
+ if (strstr(hw->id_string, id_string) == hw->id_string)
+ break;
+ }
+ if (i >= hws->count)
+ return(0);
+ if (idx)
+ *idx= i;
+ return(hw);
+}
+
+class cl_hw *
+cl_uc::get_hw(enum hw_cath cath, int hwid, int *idx)
+{
+ class cl_hw *hw;
+ int i= 0;
+
+ if (idx)
+ i= *idx;
+ hw= get_hw(cath, &i);
+ while (hw &&
+ hw->id != hwid)
+ {
+ i++;
+ hw= get_hw(cath, &i);
+ }
+ if (hw &&
+ idx)
+ *idx= i;
+ return(hw);
+}
+
+class cl_hw *
+cl_uc::get_hw(char *id_string, int hwid, int *idx)
+{
+ class cl_hw *hw;
+ int i= 0;
+
+ if (idx)
+ i= *idx;
+ hw= get_hw(id_string, &i);
+ while (hw &&
+ hw->id != hwid)
+ {
+ i++;
+ hw= get_hw(id_string, &i);
+ }
+ if (hw &&
+ idx)
+ *idx= i;
+ return(hw);
+}
+
+int
+cl_uc::get_max_hw_id(enum hw_cath cath)
+{
+ class cl_hw *hw;
+ int i, max= -1;
+
+ for (i= 0; i < hws->count; i++)
+ {
+ hw= (class cl_hw *)(hws->at(i));
+ if (hw->id > max)
+ max= hw->id;
+ }
+ return max;
+}
+
+/*
+ * Help of the command interpreter
+ */
+
+struct dis_entry *
+cl_uc::dis_tbl(void)
+{
+ static struct dis_entry empty= { 0, 0, 0, 0, NULL };
+ return(&empty);
+}
+
+char *
+cl_uc::disass(t_addr addr, const char *sep)
+{
+ char *buf;
+
+ buf= (char*)malloc(100);
+ strcpy(buf, "uc::disass() unimplemented\n");
+ return(buf);
+}
+
+void
+cl_uc::print_disass(t_addr addr, class cl_console_base *con)
+{
+ char *dis;
+ class cl_brk *b;
+ int i, l;
+
+ if (!rom)
+ return;
+
+ t_mem code= rom->get(addr);
+ b= fbrk_at(addr);
+ dis= disass(addr, NULL);
+ if (b)
+ con->dd_cprintf("answer", "%c", (b->perm == brkFIX)?'F':'D');
+ else
+ con->dd_printf(" ");
+ con->dd_cprintf("answer", "%c ", inst_at(addr)?' ':'?');
+ con->dd_cprintf("dump_address", rom->addr_format, addr); con->dd_printf(" ");
+ con->dd_cprintf("dump_number", rom->data_format, code);
+ l= inst_length(addr);
+ for (i= 1; i < l; i++)
+ {
+ con->dd_printf(" ");
+ con->dd_cprintf("dump_number", rom->data_format, rom->get(addr+i));
+ }
+ int li= longest_inst();
+ while (i < li)
+ {
+ int j;
+ j= rom->width/4 + ((rom->width%4)?1:0) + 1;
+ while (j)
+ con->dd_printf(" "), j--;
+ i++;
+ }
+ con->dd_cprintf("dump_char", " %s\n", dis);
+ free((char *)dis);
+}
+
+void
+cl_uc::print_regs(class cl_console_base *con)
+{
+ con->dd_printf("No registers\n");
+}
+
+int
+cl_uc::inst_length(t_addr addr)
+{
+ struct dis_entry *tabl= dis_tbl();
+ int i;
+ t_mem code;
+
+ if (!rom)
+ return(0);
+
+ code = rom->get(addr);
+ for (i= 0; tabl[i].mnemonic && (code & tabl[i].mask) != tabl[i].code; i++) ;
+ return(tabl[i].mnemonic?tabl[i].length:1);
+}
+
+int
+cl_uc::inst_branch(t_addr addr)
+{
+ struct dis_entry *tabl= dis_tbl();
+ int i;
+ t_mem code;
+
+ if (!rom)
+ return(0);
+
+ code = rom->get(addr);
+ for (i= 0; tabl[i].mnemonic && (code & tabl[i].mask) != tabl[i].code; i++)
+ ;
+ return tabl[i].branch;
+}
+
+bool
+cl_uc::is_call(t_addr addr)
+{
+ struct dis_entry *tabl= dis_tbl();
+ int i;
+ t_mem code;
+
+ if (!rom)
+ return(0);
+
+ code = rom->get(addr);
+ for (i= 0; tabl[i].mnemonic && (code & tabl[i].mask) != tabl[i].code; i++)
+ ;
+ return tabl[i].is_call;
+}
+
+int
+cl_uc::longest_inst(void)
+{
+ struct dis_entry *de= dis_tbl();
+ int max= 0;
+
+ while (de &&
+ de->mnemonic)
+ {
+ if (de->length > max)
+ max= de->length;
+ de++;
+ }
+ return(max);
+}
+
+bool
+cl_uc::addr_name(t_addr addr, class cl_address_space *as, char *buf)
+{
+ t_index i;
+
+ for (i= 0; i < vars->count; i++)
+ {
+ class cl_var *v= (cl_var *)(vars->at(i));
+ if ((v->as == as) &&
+ (v->addr == addr))
+ {
+ strcpy(buf, v->get_name());
+ return true;
+ }
+ }
+ unsigned int a= addr;
+ sprintf(buf, "%02x", a);
+ return false;
+}
+
+bool
+cl_uc::addr_name(t_addr addr, class cl_address_space *as, int bitnr, char *buf)
+{
+ t_index i;
+
+ for (i= 0; i < vars->count; i++)
+ {
+ class cl_var *v= (cl_var *)(vars->at(i));
+ if ((v->as == as) &&
+ (v->addr == addr) &&
+ (v->bitnr == bitnr))
+ {
+ strcpy(buf, v->get_name());
+ return true;
+ }
+ }
+ unsigned int a= addr;
+ sprintf(buf, "%02x.%d", a, bitnr);
+ return false;
+}
+
+bool
+cl_uc::symbol2address(char *sym,
+ class cl_address_space **as,
+ t_addr *addr)
+{
+ class cl_var *v;
+ t_index i;
+
+ if (!sym ||
+ !*sym)
+ return false;
+ if (vars->search(sym, i))
+ {
+ v= (class cl_var *)(vars->at(i));
+ if (v->bitnr >= 0)
+ return false;
+ if (as)
+ *as= v->as;
+ if (addr)
+ *addr= v->addr;
+ return true;
+ }
+ return false;
+}
+
+char *
+cl_uc::symbolic_bit_name(t_addr bit_address,
+ class cl_memory *mem,
+ t_addr mem_addr,
+ t_mem bit_mask)
+{
+ //char *sym_name= 0;
+ int i;
+ chars c= chars("", mem?(mem->addr_format):"0x%06lx", (unsigned long)mem_addr);
+ /*if (!sym_name)
+ {
+ sym_name= (char *)malloc(16);
+ sprintf(sym_name, mem?(mem->addr_format):"0x%06lx", (unsigned long)mem_addr);
+ }*/
+ /*sym_name= (char *)realloc(sym_name, strlen(sym_name)+2);
+ strcat(sym_name, ".");*/
+ c+= cchars(".");
+ i= 0;
+ while (bit_mask > 1)
+ {
+ bit_mask>>=1;
+ i++;
+ }
+ //char bitnumstr[10];
+ /*sprintf(bitnumstr, "%1d", i);
+ strcat(sym_name, bitnumstr);*/
+ c.append("%d", i);
+ return(/*sym_name*/strdup((char*)c));
+}
+
+
+/*
+ * Searching for a name in the specified table
+ */
+
+struct name_entry *
+cl_uc::get_name_entry(struct name_entry tabl[], char *name)
+{
+ int i= 0;
+ char *p;
+
+ if (!tabl ||
+ !name ||
+ !(*name))
+ return(0);
+ for (p= name; *p; *p= toupper(*p), p++);
+ while (tabl[i].name &&
+ (!(tabl[i].cpu_type & type->type) ||
+ (strcmp(tabl[i].name, name) != 0)))
+ {
+ //printf("tabl[%d].name=%s <-> %s\n",i,tabl[i].name,name);
+ i++;
+ }
+ if (tabl[i].name != NULL)
+ return(&tabl[i]);
+ else
+ return(0);
+}
+
+chars
+cl_uc::cell_name(class cl_memory_cell *cell)
+{
+ if (cell == NULL)
+ return chars("");
+ if (cell->get_flag(CELL_VAR))
+ {
+ int i;
+ for (i= 0; i < vars->count; i++)
+ {
+ class cl_var *v= (cl_var*)(vars->at(i));
+ if (v->get_cell() &&
+ (cell == v->get_cell()))
+ return chars(v->get_name());
+ }
+ }
+ class cl_address_space *as;
+ t_addr a;
+ as= address_space(cell, &a);
+ if (as == NULL)
+ return chars("");
+ return chars("", "%s_%06x", as->get_name(), a);
+}
+
+class cl_var *
+cl_uc::var(char *nam)
+{
+ if (!vars)
+ return NULL;
+ t_index i;
+ if (!vars->search(nam, i))
+ return NULL;
+ class cl_var *v= (cl_var*)(vars->at(i));
+ return v;
+}
+
+
+/*
+ * Messages to broadcast
+ */
+
+bool
+cl_uc::handle_event(class cl_event &event)
+{
+ switch (event.what)
+ {
+ case ev_address_space_added:
+ {
+ try {
+ class cl_event_address_space_added &e=
+ dynamic_cast<class cl_event_address_space_added &>(event);
+ address_space_added(e.as);
+ e.handle();
+ }
+ catch (...)
+ { break; }
+ break;
+ }
+ default:
+ return(pass_event_down(event));
+ break;
+ }
+ return(false);
+}
+
+/*
+void
+cl_uc::mem_cell_changed(class cl_address_space *mem, t_addr addr)
+{
+ if (hws)
+ hws->mem_cell_changed(mem, addr);
+ else
+ printf("JAJ uc\n");//FIXME
+ if (mems &&
+ mems->count)
+ {
+ int i;
+ for (i= 0; i < mems->count; i++)
+ {
+ }
+ }
+}
+*/
+
+void
+cl_uc::address_space_added(class cl_address_space *as)
+{
+ /*
+ if (hws)
+ hws->address_space_added(as);
+ else
+ printf("JAJ uc\n");//FIXME
+ */
+}
+
+
+/*
+ * Error handling
+ */
+
+void
+cl_uc::error(class cl_error *error)
+{
+ //printf("error adding: %s...\n", error->get_class()->get_name());
+ errors->add(error);
+ if ((error->inst= inst_exec))
+ error->PC= instPC;
+}
+
+void
+cl_uc::check_errors(void)
+{
+ int i;
+ class cl_commander_base *c= sim->app->get_commander();
+ bool must_stop= false;
+
+ if (c)
+ {
+ //printf("error list: %d items\n", errors->count);
+ for (i= 0; i < errors->count; i++)
+ {
+ class cl_error *error= (class cl_error *)(errors->at(i));
+ if (!error->is_on())
+ continue;
+ error->print(c);
+ must_stop= must_stop || (error->get_type() & err_stop);
+ if (error->inst)
+ {
+ class cl_console_base *con;
+ con= c->actual_console;
+ if (!con)
+ con= c->frozen_console;
+ if (con)
+ {
+ con->dd_printf("Erronouse instruction: ");
+ print_disass(error->PC, con);
+ }
+ }
+ }
+ errors->free_all();
+ }
+ else
+ fprintf(stderr, "no actual console, %d errors\n", errors->count);
+ if (must_stop)
+ sim->stop(resERROR);
+}
+
+
+/*
+ * Converting bit address into real memory
+ */
+
+class cl_address_space *
+cl_uc::bit2mem(t_addr bitaddr, t_addr *memaddr, t_mem *bitmask)
+{
+ if (memaddr)
+ *memaddr= bitaddr;
+ if (bitmask)
+ *bitmask= 1 << (bitaddr & 0x7);
+ return(0); // abstract...
+}
+
+
+/*
+ * Execution
+ */
+
+int
+cl_uc::tick_hw(int cycles)
+{
+ class cl_hw *hw;
+ int i;//, cpc= clock_per_cycle();
+
+ // tick hws
+ for (i= 0; i < hws->count; i++)
+ {
+ hw= (class cl_hw *)(hws->at(i));
+ if ((hw->flags & HWF_INSIDE) &&
+ (hw->on))
+ hw->tick(cycles);
+ }
+ do_extra_hw(cycles);
+ return(0);
+}
+
+void
+cl_uc::do_extra_hw(int cycles)
+{}
+
+int
+cl_uc::tick(int cycles)
+{
+ //class cl_hw *hw;
+ int i, cpc= clock_per_cycle();
+
+ // increase time
+ ticks->tick(cycles * cpc);
+ class it_level *il= (class it_level *)(it_levels->top());
+ if (il->level >= 0)
+ isr_ticks->tick(cycles * cpc);
+ if (state == stIDLE)
+ idle_ticks->tick(cycles * cpc);
+ for (i= 0; i < counters->count; i++)
+ {
+ class cl_ticker *t= (class cl_ticker *)(counters->at(i));
+ if (t)
+ {
+ if ((t->options&TICK_INISR) ||
+ il->level < 0)
+ t->tick(cycles * cpc);
+ }
+ }
+
+ // tick for hardwares
+ inst_ticks+= cycles;
+ return(0);
+}
+
+class cl_ticker *
+cl_uc::get_counter(int nr)
+{
+ if (nr >= counters->count)
+ return(0);
+ return((class cl_ticker *)(counters->at(nr)));
+}
+
+class cl_ticker *
+cl_uc::get_counter(const char *nam)
+{
+ int i;
+
+ if (!nam)
+ return(0);
+ for (i= 0; i < counters->count; i++)
+ {
+ class cl_ticker *t= (class cl_ticker *)(counters->at(i));
+ if (t &&
+ t->get_name() &&
+ strcmp(t->get_name(), nam) == 0)
+ return(t);
+ }
+ return(0);
+}
+
+void
+cl_uc::add_counter(class cl_ticker *ticker, int nr)
+{
+ while (counters->count <= nr)
+ counters->add(0);
+ counters->put_at(nr, ticker);
+}
+
+void
+cl_uc::add_counter(class cl_ticker *ticker, const char */*nam*/)
+{
+ int i;
+
+ if (counters->count < 1)
+ counters->add(0);
+ for (i= 1; i < counters->count; i++)
+ {
+ class cl_ticker *t= (class cl_ticker *)(counters->at(i));
+ if (!t)
+ {
+ counters->put_at(i, ticker);
+ return;
+ }
+ }
+ counters->add(ticker);
+}
+
+void
+cl_uc::del_counter(int nr)
+{
+ class cl_ticker *t;
+
+ if (nr >= counters->count)
+ return;
+ if ((t= (class cl_ticker *)(counters->at(0))) != 0)
+ delete t;
+ counters->put_at(nr, 0);
+}
+
+void
+cl_uc::del_counter(const char *nam)
+{
+ int i;
+
+ if (!nam)
+ return;
+ for (i= 0; i < counters->count; i++)
+ {
+ class cl_ticker *t= (class cl_ticker *)(counters->at(i));
+ if (t &&
+ t->get_name() &&
+ strcmp(t->get_name(), nam) == 0)
+ {
+ delete t;
+ counters->put_at(i, 0);
+ return;
+ }
+ }
+}
+
+/*
+ * Fetch without checking for breakpoint hit
+ */
+
+t_mem
+cl_uc::fetch(void)
+{
+ ulong code;
+
+ if (!rom)
+ return(0);
+
+ code= rom->read(PC);
+ PC= rom->inc_address(PC);
+ vc.fetch++;
+ return(code);
+}
+
+/*
+ * Fetch but checking for breakpoint hit first, returns TRUE if
+ * a breakpoint is hit
+ */
+
+bool
+cl_uc::fetch(t_mem *code)
+{
+ class cl_brk *brk;
+ int idx;
+
+ if (!code)
+ return(0);
+ if ((sim->state & SIM_GO) &&
+ rom &&
+ (sim->steps_done > 0))
+ {
+ if (rom->get_cell_flag(PC, CELL_FETCH_BRK))
+ if ((brk= fbrk->get_bp(PC, &idx)))
+ if (brk->do_hit())
+ {
+ if (brk->perm == brkDYNAMIC)
+ fbrk->del_bp(PC);
+ return(1);
+ }
+ }
+ *code= fetch();
+ return(0);
+}
+
+int
+cl_uc::do_inst(int step)
+{
+ t_addr PCsave;
+ int res= resGO;
+
+ if (step < 0)
+ step= 1;
+ while (step-- &&
+ res == resGO)
+ {
+ pre_inst();
+ PCsave = PC;
+ res= exec_inst();
+
+ if (res == resINV_INST)
+ /* backup to start of instruction */
+ PC = PCsave;
+
+ post_inst();
+
+ if ((res == resGO) &&
+ irq)
+ {
+ //printf("DO INTERRUPT PC=%lx\n", PC);
+ int r= do_interrupt();
+ if (r != resGO)
+ res= r;
+ }
+
+ if (stop_at_time &&
+ stop_at_time->reached())
+ {
+ delete stop_at_time;
+ stop_at_time= NULL;
+ res= resBREAKPOINT;
+ }
+ }
+ if (res != resGO)
+ sim->stop(res);
+ return(res);
+}
+
+void
+cl_uc::pre_inst(void)
+{
+ inst_exec= true;
+ inst_ticks= 0;
+ events->disconn_all();
+ vc.inst++;
+}
+
+int
+cl_uc::exec_inst(void)
+{
+ instPC= PC;
+ return(resGO);
+}
+
+int
+cl_uc::exec_inst_tab(instruction_wrapper_fn itab[])
+{
+ t_mem c;
+ int res= resGO;
+ instPC= PC;
+ if (fetch(&c))
+ return resBREAKPOINT;
+ if (itab[c] == NULL)
+ {
+ PC= instPC;
+ return resNOT_DONE;
+ }
+ res= itab[c](this, c);
+ if (res == resNOT_DONE)
+ {
+ PC= instPC;
+ return res;
+ }
+ tick(1);
+ return res;
+}
+
+
+void
+cl_uc::post_inst(void)
+{
+ tick_hw(inst_ticks);
+ if (errors->count)
+ check_errors();
+ if (events->count)
+ check_events();
+ inst_exec= false;
+}
+
+
+/*
+ * Interrupt processing
+ */
+
+int
+cl_uc::do_interrupt(void)
+{
+ int i;
+ // NMI?
+
+ // Maskable interrupts
+ if (!it_enabled())
+ {
+ //printf("do_interrupt skip (it disabled)\n");
+ return resGO;
+ }
+ class it_level *il= (class it_level *)(it_levels->top()), *IL= 0;
+ irq= false;
+ //printf("Checking IRQs...\n");
+ for (i= 0; i < it_sources->count; i++)
+ {
+ class cl_it_src *is= (class cl_it_src *)(it_sources->at(i));
+ if (is->is_active() &&
+ is->enabled() &&
+ is->pending())
+ {
+ int pr= priority_of(is->nuof);
+ int ap;
+ irq= true;
+ if (il &&
+ il->level >= 0)
+ ap= il->level;
+ else
+ ap= priority_main();
+ if (ap >= pr)
+ continue;
+ is->clear();
+ sim->app->get_commander()->
+ debug("%g sec (%d clks): Accepting interrupt `%s' PC= 0x%06x\n",
+ get_rtime(), ticks->ticks, object_name(is), PC);
+ IL= new it_level(pr, is->addr, PC, is);
+ return(accept_it(IL));
+ }
+ }
+ return resGO;
+}
+
+int
+cl_uc::accept_it(class it_level *il)
+{
+ it_levels->push(il);
+ return resGO;
+}
+
+
+/*
+ * Time related functions
+ */
+
+double
+cl_uc::get_rtime(void)
+{
+ /* double d;
+
+ d= (double)ticks/xtal;
+ return(d);*/
+ return(ticks->get_rtime(xtal));
+}
+
+unsigned long
+cl_uc::clocks_of_time(double t)
+{
+ return (unsigned long)(t * xtal);
+}
+
+int
+cl_uc::clock_per_cycle(void)
+{
+ return(1);
+}
+
+void
+cl_uc::touch(void)
+{
+ class cl_hw *hw;
+ int i;
+ for (i= 0; i < hws->count; i++)
+ {
+ hw= (class cl_hw *)(hws->at(i));
+ hw->touch();
+ }
+}
+
+
+/*
+ * Stack tracking system
+ */
+
+void
+cl_uc::stack_write(class cl_stack_op *op)
+{
+ delete op;
+ return ;
+ if (op->get_op() & stack_read_operation)
+ {
+ class cl_error_stack_tracker_wrong_handle *e= new
+ cl_error_stack_tracker_wrong_handle(false);
+ e->init();
+ error(e);
+ return;
+ }
+ stack_ops->push(op);
+}
+
+void
+cl_uc::stack_read(class cl_stack_op *op)
+{
+ delete op;
+ return ;
+ class cl_stack_op *top= (class cl_stack_op *)(stack_ops->top());
+
+ if (op->get_op() & stack_write_operation)
+ {
+ class cl_error_stack_tracker_wrong_handle *e= new
+ cl_error_stack_tracker_wrong_handle(true);
+ e->init();
+ error(e);
+ return;
+ }
+ if (!top)
+ {
+ class cl_error *e= new cl_error_stack_tracker_empty(op);
+ e->init();
+ error(e);
+ return;
+ }
+
+ if (top)
+ {
+ if (!top->match(op))
+ {
+ class cl_error *e= new cl_error_stack_tracker_unmatch(top, op);
+ e->init();
+ error(e);
+ }
+ int top_size= top->data_size(), op_size= op->data_size();
+ if (top_size != op_size)
+ {
+ application->debug("0x%06x %d bytes to read out of stack "
+ "but %d was pushed in last operation\n",
+ (int)op->get_pc(), op_size, top_size);
+ }
+ }
+
+ int removed= 0;
+ while (top &&
+ top->can_removed(op))
+ {
+ top= (class cl_stack_op *)stack_ops->pop();
+ delete top;
+ top= (class cl_stack_op *)stack_ops->top();
+ removed++;
+ }
+ if (removed != 1)
+ {
+ application->debug("0x%06x %d ops removed from stack-tracker "
+ "when %s happened, top pc=0x%06x "
+ "top before=0x%06x op after=0x%06x\n",
+ (int)op->get_pc(), removed, op->get_op_name(),
+ top?((int)top->get_pc()):0,
+ top?((int)top->get_before()):0,
+ (int)op->get_after());
+ }
+
+ if (top)
+ {
+ int ta= top->get_after(), oa= op->get_after();
+ if (ta != oa)
+ {
+ application->debug("0x%06x stack still inconsistent after %s, "
+ "%d byte(s) should be read out; top after"
+ "=0x%06x op after=0x%06x\n",
+ (int)op->get_pc(),
+ op->get_op_name(),
+ abs(ta-oa),
+ ta, oa);
+ class cl_error *e=
+ new cl_error_stack_tracker_inconsistent(op, abs(ta-oa));
+ e->init();
+ error(e);
+ }
+ }
+
+ delete op;
+}
+
+/*
+ * Breakpoint handling
+ */
+
+class cl_fetch_brk *
+cl_uc::fbrk_at(t_addr addr)
+{
+ int idx;
+
+ return((class cl_fetch_brk *)(fbrk->get_bp(addr, &idx)));
+}
+
+class cl_ev_brk *
+cl_uc::ebrk_at(t_addr addr, char *id)
+{
+ int i;
+ class cl_ev_brk *eb;
+
+ for (i= 0; i < ebrk->count; i++)
+ {
+ eb= (class cl_ev_brk *)(ebrk->at(i));
+ if (eb->addr == addr &&
+ !strcmp(eb->id, id))
+ return(eb);
+ }
+ return(0);
+}
+
+/*void
+cl_uc::rm_fbrk(long addr)
+{
+ fbrk->del_bp(addr);
+}*/
+
+/* Get a breakpoint specified by its number */
+
+class cl_brk *
+cl_uc::brk_by_nr(int nr)
+{
+ class cl_brk *bp;
+
+ if ((bp= fbrk->get_bp(nr)))
+ return(bp);
+ if ((bp= ebrk->get_bp(nr)))
+ return(bp);
+ return(0);
+}
+
+/* Get a breakpoint from the specified collection by its number */
+
+class cl_brk *
+cl_uc::brk_by_nr(class brk_coll *bpcoll, int nr)
+{
+ class cl_brk *bp;
+
+ if ((bp= bpcoll->get_bp(nr)))
+ return(bp);
+ return(0);
+}
+
+/* Remove an event breakpoint specified by its address and id */
+
+void
+cl_uc::rm_ebrk(t_addr addr, char *id)
+{
+ int i;
+ class cl_ev_brk *eb;
+
+ for (i= 0; i < ebrk->count; i++)
+ {
+ eb= (class cl_ev_brk *)(ebrk->at(i));
+ if (eb->addr == addr &&
+ !strcmp(eb->id, id))
+ ebrk->del_bp(i, 0);
+ }
+}
+
+/* Remove a breakpoint specified by its number */
+
+bool
+cl_uc::rm_brk(int nr)
+{
+ class cl_brk *bp;
+
+ if ((bp= brk_by_nr(fbrk, nr)))
+ {
+ fbrk->del_bp(bp->addr);
+ return(true);
+ }
+ else if ((bp= brk_by_nr(ebrk, nr)))
+ {
+ ebrk->del_bp(ebrk->index_of(bp), 0);
+ return(true);
+ }
+ return(false);
+}
+
+void
+cl_uc::put_breaks(void)
+{}
+
+/* Remove all fetch and event breakpoints */
+
+void
+cl_uc::remove_all_breaks(void)
+{
+ while (fbrk->count)
+ {
+ class cl_brk *brk= (class cl_brk *)(fbrk->at(0));
+ fbrk->del_bp(brk->addr);
+ }
+ while (ebrk->count)
+ ebrk->del_bp(ebrk->count-1, 0);
+}
+
+int
+cl_uc::make_new_brknr(void)
+{
+ if (brk_counter == 0)
+ return(brk_counter= 1);
+ if (fbrk->count == 0 &&
+ ebrk->count == 0)
+ return(brk_counter= 1);
+ return(++brk_counter);
+}
+
+class cl_ev_brk *
+cl_uc::mk_ebrk(enum brk_perm perm, class cl_address_space *mem,
+ char op, t_addr addr, int hit)
+{
+ class cl_ev_brk *b;
+ op= toupper(op);
+
+ b= new cl_ev_brk(mem, make_new_brknr(), addr, perm, hit, op);
+ b->init();
+ return(b);
+}
+
+void
+cl_uc::check_events(void)
+{
+ int i;
+ //sim->stop(resEVENTBREAK);
+ for (i= 0; i < events->count; i++)
+ {
+ class cl_ev_brk *brk=
+ dynamic_cast<class cl_ev_brk *>(events->object_at(i));
+ sim->stop(resEVENTBREAK, brk);
+ }
+}
+
+void
+cl_uc::stop_when(class cl_time_measurer *t)
+{
+ if (stop_at_time != NULL)
+ delete stop_at_time;
+ stop_at_time= t;
+}
+
+
+/*
+ * Errors
+ *----------------------------------------------------------------------------
+ */
+
+cl_error_unknown_code::cl_error_unknown_code(class cl_uc *the_uc)
+{
+ uc= the_uc;
+ classification= uc_error_registry.find("unknown_code");
+}
+
+void
+cl_error_unknown_code::print(class cl_commander_base *c)
+{
+ //FILE *f= c->get_out();
+ /*cmd_fprintf(f,*/c->dd_printf("%s: unknown instruction code at ", get_type_name());
+ if (uc->rom)
+ {
+ /*cmd_fprintf(f,*/c->dd_printf(uc->rom->addr_format, PC);
+ /*cmd_fprintf(f,*/c->dd_printf(" (");
+ /*cmd_fprintf(f,*/c->dd_printf(uc->rom->data_format, uc->rom->get(PC));
+ /*cmd_fprintf(f,*/c->dd_printf(")");
+ }
+ else
+ /*cmd_fprintf(f,*/c->dd_printf("0x%06x", AU(PC));
+ /*cmd_fprintf(f,*/c->dd_printf("\n");
+}
+
+
+cl_uc_error_registry::cl_uc_error_registry(void)
+{
+ class cl_error_class *prev = uc_error_registry.find("non-classified");
+ prev = register_error(new cl_error_class(err_error, "unknown_code", prev, ERROR_OFF));
+}
+
+/* End of uc.cc */