private:
static const unsigned char primes[];
static const unsigned short coef22[][32];
- unsigned int cycles;
#ifdef HAS_AUXSRV
cAuxSrv aux;
#endif
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[] = {
}
}
-// -- 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 {
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;
// -- 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);
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)
{
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)) {
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;
#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)
// 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:
// ----------------------------------------------------------------
+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;
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
void CurveInit(BIGNUM *a);
//
bool DoMap(int f, unsigned char *data=0, int l=0);
+ unsigned int MapCycles() { return cycles; }
public:
cMapCore(void);
};