private void sid_jmp() { // For de.quippy.sidplay.sidplay compatibility, inherited from environment if (m_mode == SID2Types.sid2_env_t.sid2_envR) { // If a busy loop then just sleep if (Cycle_EffectiveAddress == instrStartPC) { Register_ProgramCounter = SIDEndian.endian_32lo16(Register_ProgramCounter, Cycle_EffectiveAddress); if (!interruptPending()) { this.sleep(); } } else { base.jmp_instr(); } return; } if (player.CheckBankJump(Cycle_EffectiveAddress)) { base.jmp_instr(); } else { sid_rts(); } }
internal override void FetchOpcode() { if (m_mode == SID2Types.sid2_env_t.sid2_envR) { base.FetchOpcode(); return; } // Sid tunes end by wrapping the stack. For compatibility it has to be handled. m_sleeping |= (SIDEndian.endian_16hi8(Register_StackPointer) != SP_PAGE); m_sleeping |= (SIDEndian.endian_32hi16(Register_ProgramCounter) != 0); if (!m_sleeping) { base.FetchOpcode(); } if (m_framelock == false) { int timeout = 6000000; m_framelock = true; // Simulate sidplay1 frame based execution while (!m_sleeping && (timeout != 0)) { base.clock(); timeout--; } if (timeout == 0) { player.Reset(true); } sleep(); m_framelock = false; } }
public void write(short addr, short data) { if (addr > 0x0f) { return; } regs[addr] = data; if (locked) { return; // Stop program changing time interval } // Sync up timer long cycles; cycles = m_eventContext.getTime(m_accessClk, m_phase); m_accessClk += cycles; ta -= (int)cycles; if (ta == 0) { _event(); } switch (addr) { case 0x4: ta_latch = SIDEndian.endian_16lo8(ta_latch, data); break; case 0x5: ta_latch = SIDEndian.endian_16hi8(ta_latch, data); if ((cra & 0x01) == 0) // Reload timer if stopped { ta = ta_latch; } break; case 0x0e: cra = (short)(data | 0x01); if ((data & 0x10) != 0) { cra &= (~0x10 & 0xff); ta = ta_latch; } m_eventContext.schedule(m_taEvent, (long)ta + 1, m_phase); break; default: break; } }
private void galwayInit() { if (active) { return; } // Check all important parameters are legal short r = convertAddr(0x1d); galTones = reg[r]; reg[r] = 0; galInitLength = reg[convertAddr(0x3d)]; if (galInitLength == 0) { return; } galLoopWait = reg[convertAddr(0x3f)]; if (galLoopWait == 0) { return; } galNullWait = reg[convertAddr(0x5d)]; if (galNullWait == 0) { return; } // Load the other parameters r = convertAddr(0x1e); address = SIDEndian.endian_16(reg[r + 1], reg[r]); volShift = (short)(reg[convertAddr(0x3e)] & 0x0f); mode = FM_GALWAY; active = true; cycles = 0; outputs = 0; sampleLimit = 8; sample = (byte)(galVolume - 8); galwayTonePeriod(); // Calculate the sample offset m_xsid.sampleOffsetCalc(); // Schedule a sample update m_context.schedule(m_xsid.xsidEvent, 0, m_phase); m_context.schedule(galwayEvent, cycleCount, m_phase); }
/// <summary> /// Common address resolution procedure /// </summary> /// <param name="c64data"></param> /// <param name="fileOffset2"></param> /// <returns></returns> protected bool resolveAddrs(short[] c64data, int fileOffset2) { // Originally used as a first attempt at an RSID // style format. Now reserved for future use if (info.playAddr == 0xffff) { info.playAddr = 0; } // loadAddr = 0 means, the address is stored in front of the C64 data. if (info.loadAddr == 0) { if (info.c64dataLen < 2) { //info.statusstring = txt_corrupt; return(false); } info.loadAddr = SIDEndian.endian_16(c64data[fileOffset + 1], c64data[fileOffset + 0]); fileOffset += 2; // c64data += 2; info.c64dataLen -= 2; } if (info.compatibility == SIDTUNE_COMPATIBILITY_BASIC) { if (info.initAddr != 0) { //info.statusstring = txt_badAddr; return(false); } } else if (info.initAddr == 0) { info.initAddr = info.loadAddr; } return(true); }
/// <summary> /// Support for OR-ing two LoadStatus enums /// </summary> /// <param name="support"></param> /// <param name="support2"></param> /// <returns></returns> /* * private LoadStatus orStatus(LoadStatus support, LoadStatus support2) * { * int val1 = (support == LoadStatus.LOAD_NOT_MINE) ? 0 : (support == LoadStatus.LOAD_OK) ? 1 : 2; * int val2 = (support2 == LoadStatus.LOAD_NOT_MINE) ? 0 : (support2 == LoadStatus.LOAD_OK) ? 1 : 2; * int erg = val1 | val2; * return (erg == 0) ? LoadStatus.LOAD_NOT_MINE : (erg == 1) ? LoadStatus.LOAD_OK : LoadStatus.LOAD_ERROR; * } */ /// <summary> /// Cache the data of a single-file or two-file sidtune and its corresponding file names /// </summary> /// <param name="buf"></param> /// <returns></returns> private bool acceptSidTune(Buffer_sidtt buf) { // @FIXME@ - MUS if (info.numberOfInfostrings == 3) { // Add <?> (HVSC standard) to // missing title, author, // release fields for (int i = 0; i < 3; i++) { if (infostring[i].Length == 0) { infostring[i] = "<?>"; info.infostring[i] = infostring[i]; } } } // Fix bad sidtune set up. if (info.songs > SIDTUNE_MAX_SONGS) { info.songs = SIDTUNE_MAX_SONGS; } else if (info.songs == 0) { info.songs++; } if (info.startSong > info.songs) { info.startSong = 1; } else if (info.startSong == 0) { info.startSong++; } info.dataFileLen = buf.bufLen; info.c64dataLen = buf.bufLen - fileOffset; // Calculate any remaining addresses and then // confirm all the file details are correct if (resolveAddrs(buf.buf, fileOffset) == false) { return(false); } if (!checkRelocInfo()) { return(false); } if (!checkCompatibility()) { return(false); } if (info.dataFileLen >= 2) { // We only detect an offset of two. Some position independent // sidtunes contain a load address of 0xE000, but are loaded // to 0x0FFE and call player at 0x1000. info.fixLoad = (SIDEndian.endian_little16(buf.buf, fileOffset) == (info.loadAddr + 2)); } // Check the size of the data. if (info.c64dataLen > SIDTUNE_MAX_MEMORY) { //info.statusstring = txt_dataTooLong; return(false); } else if (info.c64dataLen == 0) { //info.statusstring = txt_empty; return(false); } cache.assign(buf.xferPtr(), buf.xferLen()); //info.statusstring = txt_noErrors; return(true); }
private void sampleInit() { if (active && (mode == FM_GALWAY)) { return; } // Check all important parameters are legal short r = convertAddr(0x1d); volShift = (short)((0 - reg[r]) >> 1); reg[r] = 0; r = convertAddr(0x1e); address = SIDEndian.endian_16(reg[r + 1], reg[r]); r = convertAddr(0x3d); samEndAddr = SIDEndian.endian_16(reg[r + 1], reg[r]); if (samEndAddr <= address) { return; } samScale = reg[convertAddr(0x5f)]; r = convertAddr(0x5d); samPeriod = SIDEndian.endian_16(reg[r + 1], reg[r]) >> samScale; if (samPeriod == 0) { // Stop this channel reg[convertAddr(0x1d)] = 0xfd; checkForInit(); return; } // Load the other parameters samNibble = 0; samRepeat = reg[convertAddr(0x3f)]; samOrder = reg[convertAddr(0x7d)]; r = convertAddr(0x7e); samRepeatAddr = SIDEndian.endian_16(reg[r + 1], reg[r]); cycleCount = samPeriod; // Support Galway Samples, but that // mode is setup only when a Galway // Noise sequence begins if (mode == FM_NONE) { mode = FM_HUELS; } active = true; cycles = 0; outputs = 0; sampleLimit = (short)(8 >> volShift); sample = sampleCalculate(); // Calculate the sample offset m_xsid.sampleOffsetCalc(); // Schedule a sample update m_context.schedule(m_xsid.xsidEvent, 0, m_phase); m_context.schedule(sampleEvent, cycleCount, m_phase); }
public void write(short addr, short data) { if (addr > 0x3f) { return; } regs[addr] = data; // Sync up timers _event(); switch (addr) { case 0x11: // Control register 1 { raster_irq = SIDEndian.endian_16hi8(raster_irq, (short)(data >> 7)); ctrl1 = data; y_scroll = data & 7; if (raster_x < 11) { break; } // In line $30, the DEN bit controls if Bad Lines can occur if ((raster_y == first_dma_line) && ((data & 0x10) != 0)) { bad_lines_enabled = true; } // Bad Line condition? bad_line = (raster_y >= first_dma_line) && (raster_y <= last_dma_line) && ((raster_y & 7) == y_scroll) && bad_lines_enabled; // Start bad dma line now if (bad_line && (raster_x < 53)) { addrctrl(false); } break; } case 0x12: // Raster counter raster_irq = SIDEndian.endian_16lo8(raster_irq, data); break; case 0x17: sprite_expand_y |= (short)(~data & 0xff); break; case 0x19: // IRQ flags idr &= (short)((~data & 0x0f) | 0x80); if (idr == 0x80) { trigger(0); } break; case 0x1a: // IRQ mask icr = (short)(data & 0x0f); trigger(icr & idr); break; } }