// license:BSD-3-Clause // copyright-holders:ElSemi, Deunan Knute, R. Belmont // thanks-to: kingshriek #include "emu.h" #include "aicadsp.h" #include static u16 PACK(s32 val) { const int sign = (val >> 23) & 0x1; u32 temp = (val ^ (val << 1)) & 0xFFFFFF; int exponent = 0; for (int k = 0; k < 12; k++) { if (temp & 0x800000) break; temp <<= 1; exponent += 1; } if (exponent < 12) val = (val << exponent) & 0x3FFFFF; else val <<= 11; val >>= 11; val &= 0x7FF; val |= sign << 15; val |= exponent << 11; return (u16)val; } static s32 UNPACK(u16 val) { const int sign = (val >> 15) & 0x1; int exponent = (val >> 11) & 0xF; const int mantissa = val & 0x7FF; u32 uval = mantissa << 11; if (exponent > 11) { exponent = 11; uval |= sign << 22; } else uval |= (sign ^ 1) << 22; uval |= sign << 23; uval <<= 8; uval >>= 8; uval >>= exponent; return uval; } void AICADSP::init() { memset(this,0,sizeof(*this)); RBL = (8 * 1024); // Initial RBL is 0 Stopped = true; } void AICADSP::step() { s32 ACC=0; //26 bit s32 MEMVAL=0; s32 FRC_REG=0; //13 bit s32 Y_REG=0; //24 bit u32 ADRS_REG=0; //13 bit if (Stopped) return; std::fill(std::begin(EFREG), std::end(EFREG), 0); #if 0 int dump=0; FILE *f=nullptr; if (dump) f=fopen("dsp.txt","wt"); #endif for (int step = 0; step < /*128*/LastStep; ++step) { u16 *IPtr=MPRO+step*8; // if (IPtr[0]==0 && IPtr[1]==0 && IPtr[2]==0 && IPtr[3]==0) // break; const u32 TRA = (IPtr[0] >> 9) & 0x7F; const u32 TWT = (IPtr[0] >> 8) & 0x01; const u32 TWA = (IPtr[0] >> 1) & 0x7F; const u32 XSEL = (IPtr[2] >> 15) & 0x01; const u32 YSEL = (IPtr[2] >> 13) & 0x03; const u32 IRA = (IPtr[2] >> 7) & 0x3F; const u32 IWT = (IPtr[2] >> 6) & 0x01; const u32 IWA = (IPtr[2] >> 1) & 0x1F; const u32 TABLE = (IPtr[4] >> 15) & 0x01; const u32 MWT = (IPtr[4] >> 14) & 0x01; const u32 MRD = (IPtr[4] >> 13) & 0x01; const u32 EWT = (IPtr[4] >> 12) & 0x01; const u32 EWA = (IPtr[4] >> 8) & 0x0F; const u32 ADRL = (IPtr[4] >> 7) & 0x01; const u32 FRCL = (IPtr[4] >> 6) & 0x01; const u32 SHIFT = (IPtr[4] >> 4) & 0x03; const u32 YRL = (IPtr[4] >> 3) & 0x01; const u32 NEGB = (IPtr[4] >> 2) & 0x01; const u32 ZERO = (IPtr[4] >> 1) & 0x01; const u32 BSEL = (IPtr[4] >> 0) & 0x01; const u32 NOFL = (IPtr[6] >> 15) & 1; //???? const u32 COEF = step; const u32 MASA = (IPtr[6] >> 9) & 0x1f; //??? const u32 ADREB = (IPtr[6] >> 8) & 0x1; const u32 NXADR = (IPtr[6] >> 7) & 0x1; //operations are done at 24 bit precision #if 0 if (MASA) int a=1; if (NOFL) int a=1; // int dump=0; if (f) { #define DUMP(v) fprintf(f," " #v ": %04X",v); fprintf(f,"%d: ",step); DUMP(ACC); DUMP(SHIFTED); DUMP(X); DUMP(Y); DUMP(B); DUMP(INPUTS); DUMP(MEMVAL); DUMP(FRC_REG); DUMP(Y_REG); DUMP(ADDR); DUMP(ADRS_REG); fprintf(f,"\n"); } #endif //INPUTS RW assert(IRA<0x32); s32 INPUTS=0; //24 bit if (IRA <= 0x1f) INPUTS = MEMS[IRA]; else if (IRA <= 0x2F) INPUTS = MIXS[IRA - 0x20] << 4; //MIXS is 20 bit else if (IRA <= 0x31) INPUTS = EXTS[IRA - 0x30] << 8; //EXTS is 16 bit INPUTS <<= 8; INPUTS >>= 8; //if (INPUTS & 0x00800000) // INPUTS |= 0xFF000000; if (IWT) { MEMS[IWA] = MEMVAL; //MEMVAL was selected in previous MRD if (IRA == IWA) INPUTS = MEMVAL; } //Operand sel //B s32 B; //26 bit if (!ZERO) { if (BSEL) B = ACC; else { B = TEMP[(TRA + DEC) & 0x7F]; B <<= 8; B >>= 8; //if (B & 0x00800000) // B |= 0xFF000000; //Sign extend } if (NEGB) B = 0 - B; } else B = 0; //X s32 X; //24 bit if (XSEL) X = INPUTS; else { X = TEMP[(TRA + DEC) & 0x7F]; X <<= 8; X >>= 8; //if (X & 0x00800000) // X |= 0xFF000000; } //Y s32 Y = 0; //13 bit if (YSEL == 0) Y = FRC_REG; else if (YSEL == 1) Y = this->COEF[COEF << 1] >> 3; //COEF is 16 bits else if (YSEL == 2) Y = (Y_REG >> 11) & 0x1FFF; else if (YSEL == 3) Y = (Y_REG >> 4) & 0x0FFF; if (YRL) Y_REG = INPUTS; //Shifter s32 SHIFTED = 0; //24 bit if (SHIFT == 0) SHIFTED = std::max(std::min(ACC, 0x007FFFFF), -0x00800000); else if (SHIFT == 1) SHIFTED = std::max(std::min(ACC * 2, 0x007FFFFF), -0x00800000); else if (SHIFT == 2) { SHIFTED = ACC * 2; SHIFTED <<= 8; SHIFTED >>= 8; //SHIFTED &= 0x00FFFFFF; //if (SHIFTED & 0x00800000) // SHIFTED |= 0xFF000000; } else if (SHIFT == 3) { SHIFTED = ACC; SHIFTED <<= 8; SHIFTED >>= 8; //SHIFTED &= 0x00FFFFFF; //if (SHIFTED & 0x00800000) // SHIFTED |= 0xFF000000; } //ACCUM Y <<= 19; Y >>= 19; //if (Y & 0x1000) // Y |= 0xFFFFF000; const s64 v = (((s64)X * (s64)Y) >> 12); ACC = (int)v + B; if (TWT) TEMP[(TWA + DEC) & 0x7F] = SHIFTED; if (FRCL) { if (SHIFT == 3) FRC_REG = SHIFTED & 0x0FFF; else FRC_REG = (SHIFTED >> 11) & 0x1FFF; } u32 ADDR; if (MRD || MWT) //if (0) { ADDR = MADRS[MASA << 1]; if (!TABLE) ADDR += DEC; if (ADREB) ADDR += ADRS_REG & 0x0FFF; if (NXADR) ADDR++; if (!TABLE) ADDR &= RBL - 1; else ADDR &= 0xFFFF; //ADDR <<= 1; //ADDR += RBP << 13; //MEMVAL = space->read_word(ADDR >> 1); ADDR += RBP << 10; if (MRD && (step & 1)) //memory only allowed on odd? DoA inserts NOPs on even { if (NOFL) MEMVAL = cache->read_word(ADDR) << 8; else MEMVAL = UNPACK(cache->read_word(ADDR)); } if (MWT && (step&1)) { if (NOFL) space->write_word(ADDR, SHIFTED>>8); else space->write_word(ADDR, PACK(SHIFTED)); } } if (ADRL) { if (SHIFT == 3) ADRS_REG = (SHIFTED >> 12) & 0xFFF; else ADRS_REG = (INPUTS >> 16); } if (EWT) EFREG[EWA] += SHIFTED >> 8; } --DEC; std::fill(std::begin(MIXS), std::end(MIXS), 0); // if (f) // fclose(f); } void AICADSP::setsample(s32 sample, u8 SEL, s32 MXL) { //MIXS[SEL] += sample << (MXL + 1)/*7*/; MIXS[SEL] += sample; // if (MXL) // int a=1; } void AICADSP::start() { int i; Stopped = false; for (i = 127; i >= 0; --i) { u16 *IPtr = MPRO + i * 8; if (IPtr[0] != 0 || IPtr[2] != 0 || IPtr[4] != 0 || IPtr[6] != 0) break; } LastStep = i + 1; }