added initial source and readme

This commit is contained in:
Jan Goldacker committed 2019-08-23 21:55:42 +02:00
1 parent 5a9eb41a3b
commit ca1ae1de12
2 files changed
+489

No files matched your search

+12
View File
@@ -0,0 +1,12 @@
# UltraCIC_C
Nintendo64 CIC clone written in C
This should run on every MCU which is fast enough to
handle the IO operations.
You just have to implement the low level gpio functions:
- ReadBit() and
- WriteBit().
Hardware connections
Data Clock Input (DCLK): CIC Pin 14
Data Line, Bidir (DIO): CIC Pin 15
+477
View File
@@ -0,0 +1,477 @@
/**************************************************************
* Generic CIC implementation for N64 *
* ---------------------------------------------------------- *
* This should run on every MCU which is fast enough to *
* handle the IO operations. *
* You just have to implement the low level gpio functions: *
* - ReadBit() and *
* - WriteBit(). *
* *
* Hardware connections *
* Data Clock Input (DCLK): CIC Pin 14 *
* Data Line, Bidir (DIO): CIC Pin 15 *
* *
**************************************************************/
#define REGION_NTSC (0)
#define REGION_PAL (1)
#define GET_REGION() (REGION_NTSC)
/* SEEDs */
// 6102/7101
#define CIC6102_SEED 0x3F
// 6101
#define CIC6101_SEED 0x3F
// 6103/7103
#define CIC6103_SEED 0x78
// 6105/7105
#define CIC6105_SEED 0x91
// 6106/7106
#define CIC6106_SEED 0x85
// 7102
#define CIC7102_SEED 0x3F
/* CHECKSUMs */
// 6102/7101
#define CIC6102_CHECKSUM 0xa, 0x5, 0x3, 0x6, 0xc, 0x0, 0xf, 0x1, 0xd, 0x8, 0x5, 0x9
// 6101
#define CIC6101_CHECKSUM 0x4, 0x5, 0xC, 0xC, 0x7, 0x3, 0xE, 0xE, 0x3, 0x1, 0x7, 0xA
// 6103/7103
#define CIC6103_CHECKSUM 0x5, 0x8, 0x6, 0xf, 0xd, 0x4, 0x7, 0x0, 0x9, 0x8, 0x6, 0x7
// 6105/7105
#define CIC6105_CHECKSUM 0x8, 0x6, 0x1, 0x8, 0xA, 0x4, 0x5, 0xB, 0xC, 0x2, 0xD, 0x3
// 6106/7106
#define CIC6106_CHECKSUM 0x2, 0xB, 0xB, 0xA, 0xD, 0x4, 0xE, 0x6, 0xE, 0xB, 0x7, 0x4
// 7102
#define CIC7102_CHECKSUM 0x4, 0x4, 0x1, 0x6, 0x0, 0xE, 0xC, 0x5, 0xD, 0x9, 0xA, 0xF
void EncodeRound(unsigned char index);
void CicRound(unsigned char *);
void Cic6105Algo(void);
/* Select SEED and CHECKSUM here */
const unsigned char _CicSeed = CIC6102_SEED;
const unsigned char _CicChecksum[] = {
CIC6102_CHECKSUM
};
/* NTSC initial RAM */
const unsigned char _CicRamInitNtsc[] = {
0xE, 0x0, 0x9, 0xA, 0x1, 0x8, 0x5, 0xA, 0x1, 0x3, 0xE, 0x1, 0x0, 0xD, 0xE, 0xC,
0x0, 0xB, 0x1, 0x4, 0xF, 0x8, 0xB, 0x5, 0x7, 0xC, 0xD, 0x6, 0x1, 0xE, 0x9, 0x8
};
/* PAL initial RAM */
const unsigned char _CicRamInitPal[] = {
0xE, 0x0, 0x4, 0xF, 0x5, 0x1, 0x2, 0x1, 0x7, 0x1, 0x9, 0x8, 0x5, 0x7, 0x5, 0xA,
0x0, 0xB, 0x1, 0x2, 0x3, 0xF, 0x8, 0x2, 0x7, 0x1, 0x9, 0x8, 0x1, 0x1, 0x5, 0xC
};
/* Memory for the CIC algorithm */
unsigned char _CicMem[32];
/* Memory for the 6105 algorithm */
unsigned char _6105Mem[32];
/* YOU HAVE TO IMPLEMENT THE LOW LEVEL GPIO FUNCTIONS ReadBit() and WriteBit() */
/* Read a bit synchronized by DCLK */
unsigned char ReadBit(void)
{
unsigned char res;
// wait for DCLK to go low
// while (DCLK_PIN == HIGH)
// { }
// Read the data bit
res = 0;
// wait for DCLK to go high
// while (DCLK_PIN == LOW)
// { }
return res;
}
/* Write a bit synchronized by DCLK */
void WriteBit(unsigned char b)
{
// wait for DCLK to go low
// while (DCLK_PIN == HIGH)
// { }
if (b == 0)
{
// drive the output low
// OUTPUT_TRISTATE = 0;
// OUTPUT_DATA = 0;
}
// wait for DCLK to go high
// while (DCLK_PIN == LOW)
// { }
// tristate the output
// OUTPUT_TRISTATE = 1;
}
/* Writes the lowes 4 bits of the byte */
void WriteNibble(unsigned char n)
{
WriteBit(n & 0x08);
WriteBit(n & 0x04);
WriteBit(n & 0x02);
WriteBit(n & 0x01);
}
// Write RAM nibbles until index hits a 16 Byte border
void WriteRamNibbles(unsigned char index)
{
do
{
WriteNibble(_CicMem[index]);
index++;
} while ((index & 0x0f) != 0);
}
/* Reads 4 bits and returns them in the lowes 4 bits of a byte */
unsigned char ReadNibble(void)
{
unsigned char res = 0;
unsigned char i;
for (i = 0; i < 4; i++)
{
res <<= 1;
res |= ReadBit();
}
return res;
}
/* Encrypt and output the seed */
void WriteSeed(void)
{
_CicMem[0x0a] = 0xb;
_CicMem[0x0b] = 0x5;
_CicMem[0x0c] = _CicSeed >> 4;
_CicMem[0x0d] = _CicSeed;
_CicMem[0x0e] = _CicSeed >> 4;
_CicMem[0x0f] = _CicSeed;
EncodeRound(0x0a);
EncodeRound(0x0a);
WriteRamNibbles(0x0a);
}
/* Encrypt and output the checksum */
void WriteChecksum(void)
{
unsigned char i;
for (i = 0; i < 12; i++)
_CicMem[i + 4] = _CicChecksum[i];
// wait for DCLK to go low
// (doesn't seem to be necessary)
// "encrytion" key
// initial value doesn't matter
//_CicMem[0x00] = 0;
//_CicMem[0x01] = 0xd;
//_CicMem[0x02] = 0;
//_CicMem[0x03] = 0;
EncodeRound(0x00);
EncodeRound(0x00);
EncodeRound(0x00);
EncodeRound(0x00);
// signal that we are done to the pif
// (test with WriteBit(1) also worked)
WriteBit(0);
// Write 16 nibbles
WriteRamNibbles(0);
}
/* seed and checksum encryption algorithm */
void EncodeRound(unsigned char index)
{
unsigned char a;
a = _CicMem[index];
index++;
do
{
a = (a + 1) & 0x0f;
a = (a + _CicMem[index]) & 0x0f;
_CicMem[index] = a;
index++;
} while ((index & 0x0f) != 0);
}
/* Exchange value of a and b */
void Exchange(unsigned char *a, unsigned char *b)
{
unsigned char tmp;
tmp = *a;
*a = *b;
*b = tmp;
}
// translated from PIC asm code (thx to Mike Ryan for the PIC implementation)
// this implementation saves program memory in LM8
/* CIC compare mode memory alternation algorithm */
void CicRound(unsigned char * m)
{
unsigned char a;
unsigned char b, x;
x = m[15];
a = x;
do
{
b = 1;
a += m[b] + 1;
m[b] = a;
b++;
a += m[b] + 1;
Exchange(&a, &m[b]);
m[b] = ~m[b];
b++;
a &= 0xf;
a += (m[b] & 0xf) + 1;
if (a < 16)
{
Exchange(&a, &m[b]);
b++;
}
a += m[b];
m[b] = a;
b++;
a += m[b];
Exchange(&a, &m[b]);
b++;
a &= 0xf;
a += 8;
if (a < 16)
a += m[b];
Exchange(&a, &m[b]);
b++;
do
{
a += m[b] + 1;
m[b] = a;
b++;
b &= 0xf;
} while (b != 0);
a = x + 0xf;
x = a & 0xf;
} while (x != 15);
}
// Big Thx to Mike Ryan, John McMaster, marshallh for publishing their work
/* CIC 6105 algorithm */
void Cic6105Algo(void)
{
unsigned char A = 5;
unsigned char carry = 1;
unsigned char i;
for (i = 0; i < 30; ++i)
{
if (!(_6105Mem[i] & 1))
A += 8;
if (!(A & 2))
A += 4;
A = (A + _6105Mem[i]) & 0xf;
_6105Mem[i] = A;
if (!carry)
A += 7;
A = (A + _6105Mem[i]) & 0xF;
A = A + _6105Mem[i] + carry;
if (A >= 0x10)
{
carry = 1;
A -= 0x10;
}
else
{
carry = 0;
}
A = (~A) & 0xf;
_6105Mem[i] = A;
}
}
/* Wait for reset */
void Die(void)
{
// never return
while (1)
{ }
}
/* CIC compare mode */
void CompareMode(unsigned char isPal)
{
unsigned char ramPtr;
// don't care about the low ram as we don't check this
// CicRound(&_CicMem[0x00]);
// CicRound(&_CicMem[0x00]);
// CicRound(&_CicMem[0x00]);
// only need to calculate the high ram
CicRound(&_CicMem[0x10]);
CicRound(&_CicMem[0x10]);
CicRound(&_CicMem[0x10]);
// 0x17 determines the start index (but never 0)
ramPtr = _CicMem[0x17] & 0xf;
if (ramPtr == 0)
ramPtr = 1;
ramPtr |= 0x10;
do
{
// read the bit from PIF (don't care about the value)
ReadBit();
// send out the lowest bit of the currently indexed ram
WriteBit(_CicMem[ramPtr] & 0x01);
// PAL or NTSC?
if (!isPal)
{
// NTSC
ramPtr++;
}
else
{
// PAL
ramPtr--;
}
// repeat until the end is reached
} while (ramPtr & 0xf);
}
/* CIC 6105 mode */
void Cic6105Mode(void)
{
unsigned char ramPtr;
// write 0xa 0xa
WriteNibble(0xa);
WriteNibble(0xa);
// receive 30 nibbles
for (ramPtr = 0; ramPtr < 30; ramPtr++)
{
_6105Mem[ramPtr] = ReadNibble();
}
// execute the algorithm
Cic6105Algo();
// send bit 0
WriteBit(0);
// send 30 nibbles
for (ramPtr = 0; ramPtr < 30; ramPtr++)
{
WriteNibble(_6105Mem[ramPtr]);
}
}
/* Load initial ram depending on region */
void InitRam(unsigned char isPal)
{
unsigned char i;
if (!isPal)
{
for (i = 0; i < 32; i++)
_CicMem[i] = _CicRamInitNtsc[i];
}
else
{
for (i = 0; i < 32; i++)
_CicMem[i] = _CicRamInitPal[i];
}
}
int main(void)
{
unsigned char isPal;
// read the region setting
isPal = GET_REGION();
// send out the corresponding id
unsigned char hello = 0x1;
if (isPal)
hello |= 0x4;
WriteNibble(hello);
// encode and send the seed
WriteSeed();
// encode and send the checksum
WriteChecksum();
// init the ram corresponding to the region
InitRam(isPal);
// read the initial values from the PIF
_CicMem[0x01] = ReadNibble();
_CicMem[0x11] = ReadNibble();
while(1)
{
// read mode (2 bit)
unsigned char cmd = 0;
cmd |= (ReadBit() << 1);
cmd |= ReadBit();
switch (cmd)
{
case 0:
// 00 (compare)
CompareMode(isPal);
break;
case 2:
// 10 (6105)
Cic6105Mode();
break;
case 3:
// 11 (reset)
WriteBit(0);
break;
case 1:
// 01 (die)
default:
Die();
}
}
}