]> www.vanbest.org Git - sasc-ng.git/commitdiff
nagra 0501: AU with timed map call
authorleslie <unknown>
Thu, 27 Dec 2007 21:23:59 +0000 (22:23 +0100)
committerleslie <unknown>
Thu, 27 Dec 2007 21:23:59 +0000 (22:23 +0100)
systems/nagra/nagra2-0101.c
systems/nagra/nagra2-0501.c
systems/nagra/nagra2.c
systems/nagra/nagra2.h

index 985b852334848c89fd2dc29ed11350243eac6465..db99763c9c0e67ef72ad93f6f6b52ebaf589d1cd 100644 (file)
@@ -122,7 +122,6 @@ class cMap0101 : public cMapCore {
 private:
   static const unsigned char primes[];
   static const unsigned short coef22[][32];
-  unsigned int cycles;
 #ifdef HAS_AUXSRV
   cAuxSrv aux;
 #endif
@@ -130,7 +129,6 @@ private:
   void MakePrime(BIGNUM *n, unsigned char *residues);
 protected:
   void DoMap(int f, unsigned char *data=0, int l=0);
-  unsigned int MapCycles() { return cycles; }
   };
 
 const unsigned char cMap0101::primes[] = {
@@ -520,221 +518,6 @@ void cMap0101::DoMap(int f, unsigned char *data, int l)
     }
 }
 
-// -- cN2Timer -----------------------------------------------------------------
-
-class cN2Timer {
-private:
-  int ctrl, divisor, cycles, remainder, latch;
-  enum { tmCONTINUOUS=0x01, tmRUNNING=0x02, tmMASK=0xFF, tmLATCHED=0x100 };
-  //
-  bool Running(void) { return ctrl&tmRUNNING; }
-  void Stop(void);
-public:
-  cN2Timer(void);
-  void AddCycles(int count);
-  unsigned int Cycles(void) { return (unsigned int)cycles; }
-  unsigned char Ctrl(void) { return ctrl&tmMASK; }
-  void Ctrl(unsigned char c);
-  unsigned char Latch(void) { return latch&0xFF; }
-  void Latch(unsigned char val);
-  };
-
-cN2Timer::cN2Timer(void)
-{
-  cycles=0; ctrl=0; divisor=1; remainder=-1; latch=0xFF;
-}
-
-void cN2Timer::AddCycles(int count)
-{
-  if(Running()) {
-    remainder+=count;
-    if(remainder>=divisor) {
-      cycles-=remainder/divisor;
-      remainder%=divisor;
-      }
-    if(ctrl&tmCONTINUOUS) {
-      while(cycles<0) cycles+=latch+1;
-      }
-    else if(cycles<0 || (cycles==0 && remainder>=4)) {
-      cycles=0;
-      Stop();
-      }
-    }
-}
-
-void cN2Timer::Latch(unsigned char val)
-{
-  if(!Running()) {
-    latch=val; if(latch==0) latch=0x100;
-    cycles=latch; remainder=0;
-    ctrl|=tmLATCHED;
-    }
-}
-
-void cN2Timer::Ctrl(unsigned char val)
-{
-  if(Running()) {
-    ctrl=(ctrl&~tmRUNNING) | (val&tmRUNNING);
-    if(!Running()) Stop();
-    }
-  else {
-    ctrl=(ctrl&~tmMASK) | (val&tmMASK);
-    if(Running()) {
-      if((ctrl&0xc0)==0x40) divisor=1 << (2 *(1 + ((ctrl & 0x38) >> 3)));
-      else divisor=4; // This is wrong, but we haven't figured the right value out yet
-      if(divisor<=0) divisor=1; // sanity
-      if(!(ctrl&tmLATCHED)) cycles=(unsigned int)(cycles-1)&0xFF;
-      remainder=-1;
-      if(!(ctrl&tmCONTINUOUS) && cycles==0) ctrl&=~tmRUNNING;
-      }
-    }
-}
-
-void cN2Timer::Stop(void)
-{
-  ctrl&=~(tmRUNNING|tmLATCHED);
-}
-
-// -- cMapMemHW ----------------------------------------------------------------
-
-#define HW_REGS   0x20
-#define HW_OFFSET 0x0000
-
-#define MAX_TIMERS 3
-#define TIMER_NUM(x) (((x)>>2)&3) // timer order doesn't match HW order
-
-class cMapMemHW : public cMapMem {
-private:
-  // memory mapped HW
-  enum {
-    HW_IO=0x00, HW_SECURITY,
-    HW_TIMER0_DATA=0x08, HW_TIMER0_LATCH, HW_TIMER0_CONTROL,
-    HW_CRC_CONTROL=0x0e, HW_CRC_DATA,
-    HW_TIMER1_DATA=0x10, HW_TIMER1_LATCH, HW_TIMER1_CONTROL,
-    HW_TIMER2_DATA=0x14, HW_TIMER2_LATCH, HW_TIMER2_CONTROL
-    };
-  // timer hardware
-  cN2Timer timer[MAX_TIMERS];
-  // CRC hardware
-  enum { CRCCALC_DELAY=9, CRC_BUSY=1, CRC_DISABLED=2 };
-  unsigned short CRCvalue;
-  unsigned char CRCpos;
-  unsigned int CRCstarttime;
-  unsigned short crc16table[256];
-  // counter
-  unsigned int cycles;
-  //
-  void GenCRC16Table(void);
-public:
-  cMapMemHW(void);
-  virtual unsigned char Get(unsigned short ea);
-  virtual void Set(unsigned short ea, unsigned char val);
-  void AddCycles(unsigned int num);
-  };
-
-cMapMemHW::cMapMemHW(void)
-:cMapMem(HW_OFFSET,HW_REGS)
-{
-  cycles=0;
-  CRCvalue=0; CRCpos=0; CRCstarttime=0;
-  GenCRC16Table();
-  PRINTF(L_SYS_EMU,"mapmemhw: new HW map off=%04x size=%04x",offset,size);
-}
-
-void cMapMemHW::GenCRC16Table(void)
-{
-  unsigned char hi[256];
-    for(int i=0; i<256; ++i) {
-      unsigned short c = i;
-      for(int j=0; j<8; ++j) c = (c>>1) ^ ((c&1) ? 0x8408 : 0); // ccitt poly
-      crc16table[0xff-i] = c & 0xff;
-      hi[i] = c>>8;
-      }
-    for(int i=0; i<32; ++i)
-      for(int j=0; j<8; ++j)
-        crc16table[i*8+j] |= hi[(0x87+(i*8)-j)&0xff]<<8;
-}
-
-void cMapMemHW::AddCycles(unsigned int num)
-{
-  cycles+=num;
-  for(int i=0; i<MAX_TIMERS; i++) timer[i].AddCycles(num);
-}
-
-unsigned char cMapMemHW::Get(unsigned short ea)
-{
-  if(ea<offset || ea>=offset+size) return 0;
-  ea-=offset;
-  switch(ea) {
-    case HW_SECURITY:
-      return 0x0F;
-    case HW_TIMER0_CONTROL:
-    case HW_TIMER1_CONTROL:
-    case HW_TIMER2_CONTROL:
-      return timer[TIMER_NUM(ea)].Ctrl();
-    case HW_TIMER0_DATA:
-    case HW_TIMER1_DATA:
-    case HW_TIMER2_DATA:
-      return timer[TIMER_NUM(ea)].Cycles();
-    case HW_TIMER0_LATCH:
-    case HW_TIMER1_LATCH:
-    case HW_TIMER2_LATCH:
-      return timer[TIMER_NUM(ea)].Latch();
-    case HW_CRC_CONTROL:
-      {
-      unsigned char r=mem[ea];
-      if(!(r&CRC_DISABLED) && cycles-CRCstarttime<CRCCALC_DELAY) r|=CRC_BUSY; // busy
-      else r&=~CRC_BUSY; // not busy
-      return r;
-      }
-    case HW_CRC_DATA:
-      {
-      unsigned char r=CRCvalue>>((CRCpos&1)<<3);
-      CRCpos=!CRCpos;
-      return r;
-      }
-    default:
-      return mem[ea];
-    }
-}
-
-void cMapMemHW::Set(unsigned short ea, unsigned char val)
-{
-  if(ea<offset || ea>=offset+size) return;
-  ea-=offset;
-  switch(ea) {
-    case HW_SECURITY:
-      break;
-    case HW_TIMER0_CONTROL:
-    case HW_TIMER1_CONTROL:
-    case HW_TIMER2_CONTROL:
-      timer[TIMER_NUM(ea)].Ctrl(val);
-      break;
-    case HW_TIMER0_LATCH:
-    case HW_TIMER1_LATCH:
-    case HW_TIMER2_LATCH:
-      timer[TIMER_NUM(ea)].Latch(val);
-      break;
-    case HW_CRC_CONTROL:
-      mem[ea]=val;
-      if(!(val&CRC_DISABLED)) {
-        CRCvalue=0; CRCpos=0;
-        CRCstarttime=cycles-CRCCALC_DELAY;
-        }
-      break;
-    case HW_CRC_DATA:
-      if(!(mem[HW_CRC_CONTROL]&CRC_DISABLED) && cycles-CRCstarttime>=CRCCALC_DELAY) {
-        CRCvalue=(CRCvalue>>8)^crc16table[(CRCvalue^val)&0xFF];
-        CRCpos=0;
-        CRCstarttime=cycles;
-        }
-      break;
-    default:
-      mem[ea]=val;
-      break;
-    }
-}
-
 // -- cN2Prov0101 --------------------------------------------------------------
 
 class cN2Prov0101 : public cN2Prov, public cN2Emu, private cMap0101 {
index 03dfce8b3aeb3b909c5ed14dd0dc65470b07708f..ae6e8a7b7473437dff48584b4f4432b3dac73227 100644 (file)
@@ -42,6 +42,7 @@ cMap0501::cMap0501(int Id)
 void cMap0501::DoMap(int f, unsigned char *data, int l)
 {
   PRINTF(L_SYS_MAP,"%04x: calling function %02X",mId,f);
+  cycles=0;
   switch(f) {
     case 0x37:
       l=(l?l:wordsize)<<3;
@@ -63,9 +64,17 @@ void cMap0501::DoMap(int f, unsigned char *data, int l)
 // -- cN2Prov0501 --------------------------------------------------------------
 
 class cN2Prov0501 : public cN2Prov, private cMap0501, public cN2Emu {
+private:
+  cMapMemHW *hwMapper;
+  //
+  bool ProcessMap(int f);
+  bool RomCallbacks(void);
+  void AddRomCallbacks(void);
 protected:
   virtual bool Algo(int algo, unsigned char *hd, const unsigned char *ed, unsigned char *hw);
   virtual bool NeedsCwSwap(void) { return true; }
+  virtual bool RomInit(void);
+  virtual void TimerHandler(unsigned int num);
 public:
   cN2Prov0501(int Id, int Flags);
   virtual int ProcessBx(unsigned char *data, int len, int pos);
@@ -76,7 +85,9 @@ static cN2ProvLinkReg<cN2Prov0501,0x0501,(N2FLAG_MECM|N2FLAG_INV|N2FLAG_Bx)> sta
 cN2Prov0501::cN2Prov0501(int Id, int Flags)
 :cN2Prov(Id,Flags)
 ,cMap0501(Id)
-{}
+{
+  hwMapper=0;
+}
 
 bool cN2Prov0501::Algo(int algo, unsigned char *hd, const unsigned char *ed, unsigned char *hw)
 {
@@ -107,6 +118,92 @@ bool cN2Prov0501::Algo(int algo, unsigned char *hd, const unsigned char *ed, uns
   return false;
 }
 
+bool cN2Prov0501::RomInit(void)
+{
+  if(!AddMapper(hwMapper=new cMapMemHW(),HW_OFFSET,HW_REGS,0x00)) return false;
+  return true;
+}
+
+bool cN2Prov0501::ProcessMap(int f)
+{
+  unsigned short addr;
+  int size=wordsize<<3;
+  unsigned char tmp[256];
+
+  switch(f) {
+    case SETSIZE: // set map size 
+      DoMap(f,0,Get(0x48));
+      if((wordsize<<3)>256) {
+        PRINTF(L_SYS_EMU,"%04x: MAP word size too large: %d",id,wordsize);
+        return false;
+        }
+      break;
+    case IMPORT_J: //Import Ram at [44:45] to Map Registers A-E, E is 0x03 the rest in sequence
+    case IMPORT_A:
+    case IMPORT_B:
+    case IMPORT_C:
+    case IMPORT_D:
+    case IMPORT_LAST:
+      addr=HILO(0x44);
+      GetMem(addr,tmp,size,0); DoMap(f,tmp);
+      AddCycles(MapCycles());
+      break;
+    case EXPORT_J: //Export Registers A-E with 44:45: 0x09 is E
+    case EXPORT_A:
+    case EXPORT_B:
+    case EXPORT_C:
+    case EXPORT_D:
+    case EXPORT_LAST:
+      addr=HILO(0x44);
+      DoMap(f,tmp); SetMem(addr,tmp,size,0);
+      break;
+    case SWAP_A: //Swap Registers A-D with 44:45
+    case SWAP_B:
+    case SWAP_C:
+    case SWAP_D:
+      addr=HILO(0x44);
+      GetMem(addr,tmp,size,0); DoMap(f,tmp); SetMem(addr,tmp,size,0);
+      break;
+    case CLEAR_A:
+    case CLEAR_B:
+    case CLEAR_C:
+    case CLEAR_D:
+    case COPY_A_B:
+    case COPY_B_A:
+    case COPY_A_C:
+    case COPY_C_A:
+    case COPY_C_D:
+    case COPY_D_C:
+      DoMap(f); break;
+    default:
+      PRINTF(L_SYS_EMU,"%04x: map call %02x not emulated",id,f);
+      return false;
+    }
+  return true;
+}
+
+bool cN2Prov0501::RomCallbacks(void)
+{
+  unsigned int ea=GetPc();
+  if(ea&0x8000) ea|=(cr<<16);
+  switch(ea) {
+    case 0x3840: //MAP Handler
+      if(!ProcessMap(a)) return false;
+      break;
+    default:
+      PRINTF(L_SYS_EMU,"%04X: unknown ROM breakpoint %04x",id,ea);
+      return false;
+    }
+  if(ea>=0x8000) PopCr();
+  PopPc();
+  return true;
+}
+
+void cN2Prov0501::AddRomCallbacks(void)
+{
+  AddBreakpoint(0x3840); // map handler
+}
+
 int cN2Prov0501::ProcessBx(unsigned char *data, int len, int pos)
 {
   if(Init(id,120)) {
@@ -118,17 +215,25 @@ int cN2Prov0501::ProcessBx(unsigned char *data, int len, int pos)
     Set(0x0000,0x04);
     ClearBreakpoints();
     AddBreakpoint(0x821f);
+    AddBreakpoint(0x0000);
+    AddRomCallbacks();
     while(!Run(5000)) {
-      switch(GetPc()) {
-        case 0x821f:
-          GetMem(0x80,data,len);
-          return a;
+      if(GetPc()==0x821f) {
+        GetMem(0x80,data,len);
+        return a;
         }
+      else if(GetPc()==0x0000) break;
+      else if(!RomCallbacks()) break;
       }
     }
   return -1;
 }
 
+void cN2Prov0501::TimerHandler(unsigned int num)
+{
+  if(hwMapper) hwMapper->AddCycles(num);
+}
+
 // -- cN2Prov0511 ----------------------------------------------------------------
 
 static cN2ProvLinkReg<cN2Prov0501,0x0511,(N2FLAG_MECM|N2FLAG_INV)> staticPL0511;
index b4700cd36f8370aac4223e014fdec03009c318b7..746b966869c9fc093cea0317ae4ea3ef1bd685cb 100644 (file)
 #define SYSTEM_NAME          "Nagra2"
 #define SYSTEM_PRI           -10
 
+// -- cN2Timer -----------------------------------------------------------------
+
+cN2Timer::cN2Timer(void)
+{
+  cycles=0; ctrl=0; divisor=1; remainder=-1; latch=0xFF;
+}
+
+void cN2Timer::AddCycles(int count)
+{
+  if(Running()) {
+    remainder+=count;
+    if(remainder>=divisor) {
+      cycles-=remainder/divisor;
+      remainder%=divisor;
+      }
+    if(ctrl&tmCONTINUOUS) {
+      while(cycles<0) cycles+=latch+1;
+      }
+    else if(cycles<0 || (cycles==0 && remainder>=4)) {
+      cycles=0;
+      Stop();
+      }
+    }
+}
+
+void cN2Timer::Latch(unsigned char val)
+{
+  if(!Running()) {
+    latch=val; if(latch==0) latch=0x100;
+    cycles=latch; remainder=0;
+    ctrl|=tmLATCHED;
+    }
+}
+
+void cN2Timer::Ctrl(unsigned char val)
+{
+  if(Running()) {
+    ctrl=(ctrl&~tmRUNNING) | (val&tmRUNNING);
+    if(!Running()) Stop();
+    }
+  else {
+    ctrl=(ctrl&~tmMASK) | (val&tmMASK);
+    if(Running()) {
+      if((ctrl&0xc0)==0x40) divisor=1 << (2 *(1 + ((ctrl & 0x38) >> 3)));
+      else divisor=4; // This is wrong, but we haven't figured the right value out yet
+      if(divisor<=0) divisor=1; // sanity
+      if(!(ctrl&tmLATCHED)) cycles=(unsigned int)(cycles-1)&0xFF;
+      PRINTF(L_SYS_EMU,"n2timer: started latch=%x div=%d cycles=%x ctrl=%x",latch,divisor,cycles,ctrl);
+      remainder=-1;
+      if(!(ctrl&tmCONTINUOUS) && cycles==0) ctrl&=~tmRUNNING;
+      }
+    }
+}
+
+void cN2Timer::Stop(void)
+{
+  ctrl&=~(tmRUNNING|tmLATCHED);
+}
+
+// -- cMapMemHW ----------------------------------------------------------------
+
+cMapMemHW::cMapMemHW(void)
+:cMapMem(HW_OFFSET,HW_REGS)
+{
+  cycles=0;
+  CRCvalue=0; CRCpos=0; CRCstarttime=0;
+  GenCRC16Table();
+  PRINTF(L_SYS_EMU,"mapmemhw: new HW map off=%04x size=%04x",offset,size);
+}
+
+void cMapMemHW::GenCRC16Table(void)
+{
+  unsigned char hi[256];
+    for(int i=0; i<256; ++i) {
+      unsigned short c = i;
+      for(int j=0; j<8; ++j) c = (c>>1) ^ ((c&1) ? 0x8408 : 0); // ccitt poly
+      crc16table[0xff-i] = c & 0xff;
+      hi[i] = c>>8;
+      }
+    for(int i=0; i<32; ++i)
+      for(int j=0; j<8; ++j)
+        crc16table[i*8+j] |= hi[(0x87+(i*8)-j)&0xff]<<8;
+}
+
+void cMapMemHW::AddCycles(unsigned int num)
+{
+  cycles+=num;
+  for(int i=0; i<MAX_TIMERS; i++) timer[i].AddCycles(num);
+}
+
+unsigned char cMapMemHW::Get(unsigned short ea)
+{
+  if(ea<offset || ea>=offset+size) return 0;
+  ea-=offset;
+  switch(ea) {
+    case HW_SECURITY:
+      return 0x0F;
+    case HW_TIMER0_CONTROL:
+    case HW_TIMER1_CONTROL:
+    case HW_TIMER2_CONTROL:
+      return timer[TIMER_NUM(ea)].Ctrl();
+    case HW_TIMER0_DATA:
+    case HW_TIMER1_DATA:
+    case HW_TIMER2_DATA:
+      return timer[TIMER_NUM(ea)].Cycles();
+    case HW_TIMER0_LATCH:
+    case HW_TIMER1_LATCH:
+    case HW_TIMER2_LATCH:
+      return timer[TIMER_NUM(ea)].Latch();
+    case HW_CRC_CONTROL:
+      {
+      unsigned char r=mem[ea];
+      if(!(r&CRC_DISABLED) && cycles-CRCstarttime<CRCCALC_DELAY) r|=CRC_BUSY; // busy
+      else r&=~CRC_BUSY; // not busy
+      return r;
+      }
+    case HW_CRC_DATA:
+      {
+      unsigned char r=CRCvalue>>((CRCpos&1)<<3);
+      CRCpos=!CRCpos;
+      return r;
+      }
+    default:
+      return mem[ea];
+    }
+}
+
+void cMapMemHW::Set(unsigned short ea, unsigned char val)
+{
+  if(ea<offset || ea>=offset+size) return;
+  ea-=offset;
+  switch(ea) {
+    case HW_SECURITY:
+      break;
+    case HW_TIMER0_CONTROL:
+    case HW_TIMER1_CONTROL:
+    case HW_TIMER2_CONTROL:
+      timer[TIMER_NUM(ea)].Ctrl(val);
+      break;
+    case HW_TIMER0_LATCH:
+    case HW_TIMER1_LATCH:
+    case HW_TIMER2_LATCH:
+      timer[TIMER_NUM(ea)].Latch(val);
+      break;
+    case HW_CRC_CONTROL:
+      mem[ea]=val;
+      if(!(val&CRC_DISABLED)) {
+        CRCvalue=0; CRCpos=0;
+        CRCstarttime=cycles-CRCCALC_DELAY;
+        }
+      break;
+    case HW_CRC_DATA:
+      if(!(mem[HW_CRC_CONTROL]&CRC_DISABLED) && cycles-CRCstarttime>=CRCCALC_DELAY) {
+        CRCvalue=(CRCvalue>>8)^crc16table[(CRCvalue^val)&0xFF];
+        CRCpos=0;
+        CRCstarttime=cycles;
+        }
+      break;
+    default:
+      mem[ea]=val;
+      break;
+    }
+}
+
 // -- cN2Emu -------------------------------------------------------------------
 
 cN2Emu::cN2Emu(void)
@@ -297,6 +461,7 @@ bool cMapCore::DoMap(int f, unsigned char *data, int l)
       // fall through
     case IMPORT_LAST:
       regs[last]->GetLE(data,last>0?dl:8);
+      cycles=944; // certainly dependant on the wordsize, but for now enough for PW
       break;
 
     case EXPORT_J:
index 96e00a12814ac3747fa083160b586c83990f7506..97c5bf579fe68fce47a9e06e51678ce451fbeeba 100644 (file)
 
 // ----------------------------------------------------------------
 
+class cN2Timer {
+private:
+  int ctrl, divisor, cycles, remainder, latch;
+  enum { tmCONTINUOUS=0x01, tmRUNNING=0x02, tmMASK=0xFF, tmLATCHED=0x100 };
+  //
+  bool Running(void) { return ctrl&tmRUNNING; }
+  void Stop(void);
+public:
+  cN2Timer(void);
+  void AddCycles(int count);
+  unsigned int Cycles(void) { return (unsigned int)cycles; }
+  unsigned char Ctrl(void) { return ctrl&tmMASK; }
+  void Ctrl(unsigned char c);
+  unsigned char Latch(void) { return latch&0xFF; }
+  void Latch(unsigned char val);
+  };
+
+// ----------------------------------------------------------------
+
+#define HW_REGS   0x20
+#define HW_OFFSET 0x0000
+
+#define MAX_TIMERS 3
+#define TIMER_NUM(x) (((x)>>2)&3) // timer order doesn't match HW order
+
+class cMapMemHW : public cMapMem {
+private:
+  // memory mapped HW
+  enum {
+    HW_IO=0x00, HW_SECURITY,
+    HW_TIMER0_DATA=0x08, HW_TIMER0_LATCH, HW_TIMER0_CONTROL,
+    HW_CRC_CONTROL=0x0e, HW_CRC_DATA,
+    HW_TIMER1_DATA=0x10, HW_TIMER1_LATCH, HW_TIMER1_CONTROL,
+    HW_TIMER2_DATA=0x14, HW_TIMER2_LATCH, HW_TIMER2_CONTROL
+    };
+  // timer hardware
+  cN2Timer timer[MAX_TIMERS];
+  // CRC hardware
+  enum { CRCCALC_DELAY=9, CRC_BUSY=1, CRC_DISABLED=2 };
+  unsigned short CRCvalue;
+  unsigned char CRCpos;
+  unsigned int CRCstarttime;
+  unsigned short crc16table[256];
+  // counter
+  unsigned int cycles;
+  //
+  void GenCRC16Table(void);
+public:
+  cMapMemHW(void);
+  virtual unsigned char Get(unsigned short ea);
+  virtual void Set(unsigned short ea, unsigned char val);
+  void AddCycles(unsigned int num);
+  };
+
+// ----------------------------------------------------------------
+
 class cN2Emu : protected c6805 {
 private:
   bool initDone;
@@ -87,6 +143,7 @@ private:
   cBN *regs[5];
   cBN x, y, s;
 protected:
+  unsigned int cycles;
   int wordsize;
   cBN A, B, C, D, J, I;
   cBN Px, Py, Pz,Qx, Qy, Qz; // 0x00,0x20,0x40,0x60,0x80,0x180
@@ -110,6 +167,7 @@ protected:
   void CurveInit(BIGNUM *a);
   //
   bool DoMap(int f, unsigned char *data=0, int l=0);
+  unsigned int MapCycles() { return cycles; }
 public:
   cMapCore(void);
   };