Merge branch ucsim-034-pre3 to main trunk; new version 0.4
[fw/sdcc] / sim / ucsim / s51.src / timer0.cc
index 56f326cb72bec6a04e8c1d6029611ae10673393d..fddf0c8242c3c2c9a024a8dc4cac92561d9581d7 100644 (file)
@@ -27,39 +27,369 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 
 #include "timer0cl.h"
 #include "regs51.h"
+#include "types51.h"
 
 
-cl_timer0::cl_timer0(class cl_uc *auc):
-  cl_hw(auc, HW_TIMER, 0, "timer0")
-{}
+cl_timer0::cl_timer0(class cl_uc *auc, int aid, char *aid_string):
+  cl_hw(auc, HW_TIMER, aid, aid_string)
+{
+  cell_tmod= cell_tcon= 0;
+  if (aid == 0)
+    {
+      mask_M0  = bmM00;
+      mask_M1  = bmM10;
+      mask_C_T = bmC_T0;
+      mask_GATE= bmGATE0;
+      mask_TR  = bmTR0;
+      mask_INT = bm_INT0;
+      mask_TF  = bmTF0;
+      mask_T   = bmT0;
+      addr_tl  = TL0;
+      addr_th  = TH0;
+    }
+  else if (aid == 1)
+    {
+      mask_M0  = bmM01;
+      mask_M1  = bmM11;
+      mask_C_T = bmC_T1;
+      mask_GATE= bmGATE1;
+      mask_TR  = bmTR1;
+      mask_INT = bm_INT1;
+      mask_TF  = bmTF1;
+      mask_T   = bmT1;
+      addr_tl  = TL1;
+      addr_th  = TH1;
+    }
+  else if (aid == 2)
+    {
+      addr_tl  = TL2;
+      addr_th  = TH2;
+      mask_T   = bmT2;
+      mask_C_T = bmC_T2;
+      mask_TR  = bmTR2;
+      mask_TF  = bmTF2;
+      mask_M0= mask_M1= mask_GATE= mask_INT= 0;
+    }
+  else {}
+  make_partner(HW_PCA, 0);
+  make_partner(HW_PCA, 1);
+  make_partner(HW_PCA, 2);
+  make_partner(HW_PCA, 3);
+  make_partner(HW_PCA, 4);
+}
 
-/*int
+int
 cl_timer0::init(void)
 {
+  class cl_mem *sfr= uc->mem(MEM_SFR);
+
+  if (sfr)
+    {
+      //t_mem d;
+      if (id == 0 || id == 1)
+       {
+         //cell_tmod= sfr->register_hw(TMOD, this, 0);
+         register_cell(sfr, TMOD, &cell_tmod, wtd_restore_write);
+         //d= cell_tmod->get(); write(cell_tmod, &d);
+         //cell_tcon= sfr->register_hw(TCON, this, 0);
+         register_cell(sfr, TCON, &cell_tcon, wtd_restore_write);
+         //d= cell_tcon->get(); write(cell_tcon, &d);
+         INT= sfr->read(P3) & mask_INT;
+       }
+      else if (id == 2)
+       {
+         cell_tmod= 0;
+         //cell_tcon= sfr->register_hw(T2CON, this, 0);
+         register_cell(sfr, T2CON, &cell_tcon, wtd_restore_write);
+         //d= cell_tcon->get(); write(cell_tcon, &d);
+       }
+      //cell_tl= sfr->get_cell(addr_tl);
+      //cell_th= sfr->get_cell(addr_th);
+      use_cell(sfr, addr_tl, &cell_tl, wtd_restore);
+      use_cell(sfr, addr_th, &cell_th, wtd_restore);
+    }
   return(0);
+}
+
+void
+cl_timer0::added_to_uc(void)
+{
+  if (id == 0)
+    uc->it_sources->add(new cl_it_src(bmET0, TCON, bmTF0, 0x000b, true,
+                                     "timer #0", 2));
+  else if (id == 1)
+    uc->it_sources->add(new cl_it_src(bmET1, TCON, bmTF1, 0x001b, true,
+                                     "timer #1", 4));
+}
+
+/*t_mem
+cl_timer0::read(class cl_cell *cell)
+{
+  return(cell->get());
 }*/
 
+void
+cl_timer0::write(class cl_cell *cell, t_mem *val)
+{
+  if (cell == cell_tmod)
+    {
+      t_mem md= *val & (mask_M0|mask_M1);
+      if (md == mask_M0)
+       mode= 1;
+      else if (md == mask_M1)
+       mode= 2;
+      else if (md == (mask_M0|mask_M1))
+       mode= 3;
+      else
+       mode= 0;
+      GATE= *val & mask_GATE;
+      C_T = *val & mask_C_T;
+      T_edge= 0;
+    }
+  else if (cell == cell_tcon)
+    {
+      TR= *val & mask_TR;
+      T_edge= 0;
+    }
+}
+
+/*void
+cl_timer0::mem_cell_changed(class cl_mem *mem, t_addr addr)
+{
+  //class cl_mem *sfr= uc->mem(MEM_SFR);
+  //t_mem d;
+
+  cl_hw::mem_cell_changed(mem, addr);
+
+  //d= cell_tmod->get();
+  //write(cell_tmod, &d);
+  //d= cell_tcon->get();
+  //write(cell_tcon, &d);
+  //if (addr == addr_tl) cell_tl= sfr->get_cell(addr_tl);
+  //if (addr == addr_th) cell_th= sfr->get_cell(addr_th);
+}*/
+
+int
+cl_timer0::tick(int cycles)
+{
+  switch (mode)
+    {
+    case 0: do_mode0(cycles); break;
+    case 1: do_mode1(cycles); break;
+    case 2: do_mode2(cycles); break;
+    case 3: do_mode3(cycles); break;
+    }
+  return(resGO);
+}
+
+int
+cl_timer0::do_mode0(int cycles)
+{
+  if (!TR)
+    return(0);
+
+  //t_mem p3= uc->mem(MEM_SFR)->get(P3);
+  if (GATE)
+    {
+      if ((/*p3 & mask_*/INT) == 0)
+       return(0);
+    }
+
+  if (C_T)
+    {
+      /*cycles= 0;
+      if ((uc51->prev_p3 & mask_T) &&
+         !(p3 & uc51->port_pins[3] & mask_T))
+         cycles= 1;*/
+      cycles= T_edge;
+      T_edge= 0;
+    }
+  while (cycles--)
+    {
+      // mod 0, TH= 8 bit t/c, TL= 5 bit precounter
+      t_mem tl= cell_tl->add(1);
+      if ((tl & 0x1f) == 0)
+       {
+         cell_tl->set(0);
+         if (!cell_th->add(1))
+           {
+             cell_tcon->set_bit1(mask_TF);
+             overflow();
+           }
+       }
+    }
+
+  return(0);
+}
+
+int
+cl_timer0::do_mode1(int cycles)
+{
+  if (!TR)
+    return(0);
+
+  //t_mem p3= uc->mem(MEM_SFR)->get(P3);
+  if (GATE)
+    {
+      if ((/*p3 & mask_*/INT) == 0)
+       return(0);
+    }
+
+  if (C_T)
+    {
+      /*cycles= 0;
+      if ((uc51->prev_p3 & mask_T) &&
+         !(p3 & uc51->port_pins[3] & mask_T))
+         cycles= 1;*/
+      cycles= T_edge;
+      T_edge= 0;
+    }
+
+  while (cycles--)
+    {
+      // mod 1 TH+TL= 16 bit t/c
+      if (!cell_tl->add(1))
+       {
+         if (!cell_th->add(1))
+           {
+             cell_tcon->set_bit1(mask_TF);
+             overflow();
+           }
+       }
+    }
+
+  return(0);
+}
+
+int
+cl_timer0::do_mode2(int cycles)
+{
+  if (!TR)
+    return(0);
+
+  //t_mem p3= uc->mem(MEM_SFR)->get(P3);
+  if (GATE)
+    {
+      if ((/*p3 & mask_*/INT) == 0)
+       return(0);
+    }
+
+  if (C_T)
+    {
+      /*cycles= 0;
+      if ((uc51->prev_p3 & mask_T) &&
+         !(p3 & uc51->port_pins[3] & mask_T))
+         cycles= 1;*/
+      cycles= T_edge;
+      T_edge= 0;
+    }
+
+  //unsigned long startt= uc->ticks->ticks-(cycles*12);int i=0;
+  while (cycles--)
+    {
+      // mod 2 TL= 8 bit t/c auto reload from TH
+      if (!cell_tl->add(1))
+       {
+         cell_tl->set(cell_th->get());
+         cell_tcon->set_bit1(mask_TF);
+         //printf("timer%d overflow %d (%d) %d\n",id,uc->ticks->ticks,i,startt+(i*12));
+         overflow();
+       }
+      //i++;
+    }
+  return(0);
+}
+
+int
+cl_timer0::do_mode3(int cycles)
+{
+  int cyc= cycles;
+  //t_mem p3= uc->mem(MEM_SFR)->get(P3);
+
+  if (!TR)
+    goto do_th;
+
+  if (GATE)
+    {
+      if ((/*p3 & mask_*/INT) == 0)
+       goto do_th;
+    }
+
+  if (C_T)
+    {
+      /*cycles= 0;
+      if ((uc51->prev_p3 & mask_T) &&
+         !(p3 & uc51->port_pins[3] & mask_T))
+         cycles= 1;*/
+      cycles= T_edge;
+      T_edge= 0;
+    }
+
+  while (cycles--)
+    {
+      if (!cell_tl->add(1))
+       {
+         cell_tcon->set_bit1(mask_TF);
+         overflow();
+       }
+    }
+
+ do_th:
+  if ((cell_tcon->get() & bmTR1) != 0)
+    while (cyc--)
+      {
+       if (!cell_th->add(1))
+         cell_tcon->set_bit1(bmTF1);
+      }
+  return(0);
+}
+
+void
+cl_timer0::overflow(void)
+{
+  inform_partners(EV_OVERFLOW, 0);
+}
+
+void
+cl_timer0::happen(class cl_hw *where, enum hw_event he, void *params)
+{
+  struct ev_port_changed *ep= (struct ev_port_changed *)params;
+
+  if (where->cathegory == HW_PORT &&
+      he == EV_PORT_CHANGED &&
+      ep->id == 3)
+    {
+      t_mem p3n= ep->new_pins & ep->new_value;
+      t_mem p3o= ep->pins & ep->prev_value;
+      if ((p3n & mask_T) &&
+         !(p3o & mask_T))
+       T_edge++;
+      INT= p3n & mask_INT;
+      //printf("timer%d p%dchanged (%02x,%02x->%02x,%02x) INT=%d(%02x) edge=%d(%02x)\n",id,where->id,ep->prev_value,ep->pins,ep->new_value,ep->new_pins,INT,mask_INT,T_edge,mask_T);
+    }
+}
+
 void
 cl_timer0::print_info(class cl_console *con)
 {
   char *modes[]= { "13 bit", "16 bit", "8 bit autoreload", "2x8 bit" };
-  int tmod= uc->get_mem(MEM_SFR, TMOD);
+  //t_mem tmod= cell_tmod->get();
   int on;
 
   con->dd_printf("%s[%d] 0x%04x", id_string, id,
-                256*uc->get_mem(MEM_SFR, TH0)+uc->get_mem(MEM_SFR, TL0));
-  int mode= tmod & (bmM00|bmM10);
+                256*cell_th->get()+cell_tl->get());
+  //int mode= tmod & (bmM00|bmM10);
   con->dd_printf(" %s", modes[mode]);
-  con->dd_printf(" %s", (tmod&bmC_T0)?"counter":"timer");
-  if (tmod&bmGATE0)
+  con->dd_printf(" %s", (/*tmod&bm*/C_T/*0*/)?"counter":"timer");
+  if (/*tmod&bm*/GATE/*0*/)
     {
       con->dd_printf(" gated");
-      on= uc->get_mem(MEM_SFR, P3) & uc->port_pins[3] & bm_INT0;
+      on= /*uc->get_mem(MEM_SFR, P3) & uc->port_pins[3] & mask_*/INT/*bm_INT0*/;
     }
   else
-    on= uc->get_mem(MEM_SFR, TCON) & bmTR0;
+    on= TR/*cell_tcon->get(TCON) & mask_TR*/;
   con->dd_printf(" %s", on?"ON":"OFF");
-  con->dd_printf(" irq=%c", (uc->get_mem(MEM_SFR, TCON)&bmTF0)?'1':'0');
+  con->dd_printf(" irq=%c", (cell_tcon->get()&mask_TF)?'1':'0');
   con->dd_printf(" %s", (uc->get_mem(MEM_SFR, IE)&bmET0)?"en":"dis");
   con->dd_printf(" prio=%d", uc->it_priority(bmPT0));
   con->dd_printf("\n");