2748 lines
74 KiB
C++
2748 lines
74 KiB
C++
//
|
|
// Copyright (c) 2004 K. Wilkins
|
|
//
|
|
// This software is provided 'as-is', without any express or implied warranty.
|
|
// In no event will the authors be held liable for any damages arising from
|
|
// the use of this software.
|
|
//
|
|
// Permission is granted to anyone to use this software for any purpose,
|
|
// including commercial applications, and to alter it and redistribute it
|
|
// freely, subject to the following restrictions:
|
|
//
|
|
// 1. The origin of this software must not be misrepresented; you must not
|
|
// claim that you wrote the original software. If you use this software
|
|
// in a product, an acknowledgment in the product documentation would be
|
|
// appreciated but is not required.
|
|
//
|
|
// 2. Altered source versions must be plainly marked as such, and must not
|
|
// be misrepresented as being the original software.
|
|
//
|
|
// 3. This notice may not be removed or altered from any source distribution.
|
|
//
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// Handy - An Atari Lynx Emulator //
|
|
// Copyright (c) 1996,1997 //
|
|
// K. Wilkins //
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// Mikey chip emulation class //
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// This class emulates all of the Mikey hardware with the exception of the //
|
|
// CPU and memory selector. Update() does most of the work and does screen //
|
|
// DMA and counter updates, it also schecules in which cycle the next timer //
|
|
// update will occur so that the CSystem->Update() doesnt have to call it //
|
|
// every cycle, massive speedup but big complexity headache. //
|
|
// //
|
|
// K. Wilkins //
|
|
// August 1997 //
|
|
// //
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// Revision History: //
|
|
// ----------------- //
|
|
// //
|
|
// 01Aug1997 KW Document header added & class documented. //
|
|
// //
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
#define MIKIE_CPP
|
|
|
|
//#include <crtdbg.h>
|
|
//#define TRACE_MIKIE
|
|
|
|
#include "system.h"
|
|
#include "mikie.h"
|
|
#include "lynxdef.h"
|
|
|
|
/*
|
|
void CMikie::BlowOut()
|
|
{
|
|
C6502_REGS regs;
|
|
mSystem.GetRegs(regs);
|
|
//sprintf(addr,"Runtime Error - System Halted\nCMikie::Poke() - Read/Write to counter clocks at PC=$%04x.",regs.PC);
|
|
//gError->Warning(addr);
|
|
gSystemHalt=TRUE;
|
|
}
|
|
*/
|
|
|
|
CMikie::CMikie(CSystem& parent)
|
|
:mSystem(parent)
|
|
{
|
|
TRACE_MIKIE0("CMikie()");
|
|
|
|
int loop;
|
|
for(loop=0;loop<16;loop++) mPalette[loop].Index=loop;
|
|
|
|
DisplaySetAttributes();
|
|
|
|
Reset();
|
|
}
|
|
|
|
CMikie::~CMikie()
|
|
{
|
|
TRACE_MIKIE0("~CMikie()");
|
|
}
|
|
|
|
void CMikie::SetCPUSleep() { mSystem.gSystemCPUSleep = true; }
|
|
void CMikie::ClearCPUSleep() { mSystem.gSystemCPUSleep = false; }
|
|
|
|
|
|
void CMikie::Reset()
|
|
{
|
|
TRACE_MIKIE0("Reset()");
|
|
|
|
mAudioInputComparator=FALSE; // Initialises to unknown
|
|
mDisplayAddress=0x00; // Initialises to unknown
|
|
mLynxLine=0;
|
|
mLynxLineDMACounter=0;
|
|
mLynxAddr=0;
|
|
|
|
mpDisplayCurrentLine = 0;
|
|
|
|
mTimerStatusFlags=0x00; // Initialises to ZERO, i.e No IRQ's
|
|
mTimerInterruptMask=0x00;
|
|
|
|
mpRamPointer=mSystem.GetRamPointer(); // Fetch pointer to system RAM
|
|
|
|
mTIM_0_BKUP=0;
|
|
mTIM_0_ENABLE_RELOAD=0;
|
|
mTIM_0_ENABLE_COUNT=0;
|
|
mTIM_0_LINKING=0;
|
|
mTIM_0_CURRENT=0;
|
|
mTIM_0_TIMER_DONE=0;
|
|
mTIM_0_LAST_CLOCK=0;
|
|
mTIM_0_BORROW_IN=0;
|
|
mTIM_0_BORROW_OUT=0;
|
|
mTIM_0_LAST_LINK_CARRY=0;
|
|
mTIM_0_LAST_COUNT=0;
|
|
|
|
mTIM_1_BKUP=0;
|
|
mTIM_1_ENABLE_RELOAD=0;
|
|
mTIM_1_ENABLE_COUNT=0;
|
|
mTIM_1_LINKING=0;
|
|
mTIM_1_CURRENT=0;
|
|
mTIM_1_TIMER_DONE=0;
|
|
mTIM_1_LAST_CLOCK=0;
|
|
mTIM_1_BORROW_IN=0;
|
|
mTIM_1_BORROW_OUT=0;
|
|
mTIM_1_LAST_LINK_CARRY=0;
|
|
mTIM_1_LAST_COUNT=0;
|
|
|
|
mTIM_2_BKUP=0;
|
|
mTIM_2_ENABLE_RELOAD=0;
|
|
mTIM_2_ENABLE_COUNT=0;
|
|
mTIM_2_LINKING=0;
|
|
mTIM_2_CURRENT=0;
|
|
mTIM_2_TIMER_DONE=0;
|
|
mTIM_2_LAST_CLOCK=0;
|
|
mTIM_2_BORROW_IN=0;
|
|
mTIM_2_BORROW_OUT=0;
|
|
mTIM_2_LAST_LINK_CARRY=0;
|
|
mTIM_2_LAST_COUNT=0;
|
|
|
|
mTIM_3_BKUP=0;
|
|
mTIM_3_ENABLE_RELOAD=0;
|
|
mTIM_3_ENABLE_COUNT=0;
|
|
mTIM_3_LINKING=0;
|
|
mTIM_3_CURRENT=0;
|
|
mTIM_3_TIMER_DONE=0;
|
|
mTIM_3_LAST_CLOCK=0;
|
|
mTIM_3_BORROW_IN=0;
|
|
mTIM_3_BORROW_OUT=0;
|
|
mTIM_3_LAST_LINK_CARRY=0;
|
|
mTIM_3_LAST_COUNT=0;
|
|
|
|
mTIM_4_BKUP=0;
|
|
mTIM_4_ENABLE_RELOAD=0;
|
|
mTIM_4_ENABLE_COUNT=0;
|
|
mTIM_4_LINKING=0;
|
|
mTIM_4_CURRENT=0;
|
|
mTIM_4_TIMER_DONE=0;
|
|
mTIM_4_LAST_CLOCK=0;
|
|
mTIM_4_BORROW_IN=0;
|
|
mTIM_4_BORROW_OUT=0;
|
|
mTIM_4_LAST_LINK_CARRY=0;
|
|
mTIM_4_LAST_COUNT=0;
|
|
|
|
mTIM_5_BKUP=0;
|
|
mTIM_5_ENABLE_RELOAD=0;
|
|
mTIM_5_ENABLE_COUNT=0;
|
|
mTIM_5_LINKING=0;
|
|
mTIM_5_CURRENT=0;
|
|
mTIM_5_TIMER_DONE=0;
|
|
mTIM_5_LAST_CLOCK=0;
|
|
mTIM_5_BORROW_IN=0;
|
|
mTIM_5_BORROW_OUT=0;
|
|
mTIM_5_LAST_LINK_CARRY=0;
|
|
mTIM_5_LAST_COUNT=0;
|
|
|
|
mTIM_6_BKUP=0;
|
|
mTIM_6_ENABLE_RELOAD=0;
|
|
mTIM_6_ENABLE_COUNT=0;
|
|
mTIM_6_LINKING=0;
|
|
mTIM_6_CURRENT=0;
|
|
mTIM_6_TIMER_DONE=0;
|
|
mTIM_6_LAST_CLOCK=0;
|
|
mTIM_6_BORROW_IN=0;
|
|
mTIM_6_BORROW_OUT=0;
|
|
mTIM_6_LAST_LINK_CARRY=0;
|
|
mTIM_6_LAST_COUNT=0;
|
|
|
|
mTIM_7_BKUP=0;
|
|
mTIM_7_ENABLE_RELOAD=0;
|
|
mTIM_7_ENABLE_COUNT=0;
|
|
mTIM_7_LINKING=0;
|
|
mTIM_7_CURRENT=0;
|
|
mTIM_7_TIMER_DONE=0;
|
|
mTIM_7_LAST_CLOCK=0;
|
|
mTIM_7_BORROW_IN=0;
|
|
mTIM_7_BORROW_OUT=0;
|
|
mTIM_7_LAST_LINK_CARRY=0;
|
|
mTIM_7_LAST_COUNT=0;
|
|
|
|
for(int y = 0; y < 4; y++)
|
|
{
|
|
mAUDIO_BKUP[y]=0;
|
|
mAUDIO_ENABLE_RELOAD[y]=0;
|
|
mAUDIO_ENABLE_COUNT[y]=0;
|
|
mAUDIO_LINKING[y]=0;
|
|
mAUDIO_CURRENT[y]=0;
|
|
mAUDIO_TIMER_DONE[y]=0;
|
|
mAUDIO_LAST_CLOCK[y]=0;
|
|
mAUDIO_BORROW_IN[y]=0;
|
|
mAUDIO_BORROW_OUT[y]=0;
|
|
mAUDIO_LAST_LINK_CARRY[y]=0;
|
|
mAUDIO_LAST_COUNT[y]=0;
|
|
mAUDIO_VOLUME[y]=0;
|
|
mAUDIO_INTEGRATE_ENABLE[y]=0;
|
|
mAUDIO_WAVESHAPER[y]=0;
|
|
|
|
mAUDIO_OUTPUT[y] = 0;
|
|
}
|
|
mSTEREO=0xff; // xored! All channels enabled
|
|
mPAN=0x00; // all channels panning OFF
|
|
mAUDIO_ATTEN[0]=0xff; // Full volume
|
|
mAUDIO_ATTEN[1]=0xff;
|
|
mAUDIO_ATTEN[2]=0xff;
|
|
mAUDIO_ATTEN[3]=0xff;
|
|
|
|
// Start with an empty palette
|
|
|
|
for(int loop=0;loop<16;loop++)
|
|
{
|
|
mPalette[loop].Index=loop;
|
|
}
|
|
|
|
// Initialise IODAT register
|
|
|
|
mIODAT=0x00;
|
|
mIODIR=0x00;
|
|
mIODAT_REST_SIGNAL=0x00;
|
|
|
|
// Initialise display control register vars
|
|
mDISPCTL_DMAEnable=FALSE;
|
|
mDISPCTL_Flip=FALSE;
|
|
mDISPCTL_FourColour=0;
|
|
mDISPCTL_Colour=0;
|
|
|
|
// Initialise the UART variables
|
|
mUART_RX_IRQ_ENABLE=0;
|
|
mUART_TX_IRQ_ENABLE=0;
|
|
|
|
mUART_TX_COUNTDOWN=UART_TX_INACTIVE;
|
|
mUART_RX_COUNTDOWN=UART_RX_INACTIVE;
|
|
|
|
mUART_Rx_input_ptr=0;
|
|
mUART_Rx_output_ptr=0;
|
|
mUART_Rx_waiting=0;
|
|
mUART_Rx_framing_error=0;
|
|
mUART_Rx_overun_error=0;
|
|
|
|
mUART_SENDBREAK=0;
|
|
mUART_TX_DATA=0;
|
|
mUART_RX_DATA=0;
|
|
mUART_RX_READY=0;
|
|
|
|
mUART_PARITY_ENABLE=0;
|
|
mUART_PARITY_EVEN=0;
|
|
}
|
|
|
|
uint32 CMikie::GetLfsrNext(uint32 current)
|
|
{
|
|
// The table is built thus:
|
|
// Bits 0-11 LFSR (12 Bits)
|
|
// Bits 12-20 Feedback switches (9 Bits)
|
|
// (Order = 7,0,1,2,3,4,5,10,11)
|
|
// Order is mangled to make peek/poke easier as
|
|
// bit 7 is in a seperate register
|
|
//
|
|
// Total 21 bits = 2MWords @ 4 Bytes/Word = 8MB !!!!!
|
|
//
|
|
// If the index is a combination of Current LFSR+Feedback the
|
|
// table will give the next value.
|
|
|
|
uint32 switches,lfsr,next,swloop,result;
|
|
static const uint32 switchbits[9]={7,0,1,2,3,4,5,10,11};
|
|
|
|
switches=current>>12;
|
|
lfsr=current&0xfff;
|
|
result=0;
|
|
for(swloop=0;swloop<9;swloop++)
|
|
{
|
|
if((switches>>swloop)&0x001) result^=(lfsr>>switchbits[swloop])&0x001;
|
|
}
|
|
result=(result)?0:1;
|
|
next=(switches<<12)|((lfsr<<1)&0xffe)|result;
|
|
return next;
|
|
}
|
|
|
|
void CMikie::ComLynxCable(int status)
|
|
{
|
|
mUART_CABLE_PRESENT=status;
|
|
}
|
|
|
|
void CMikie::ComLynxRxData(int data)
|
|
{
|
|
TRACE_MIKIE1("ComLynxRxData() - Received %04x",data);
|
|
// Copy over the data
|
|
if(mUART_Rx_waiting<UART_MAX_RX_QUEUE)
|
|
{
|
|
// Trigger incoming receive IF none waiting otherwise
|
|
// we NEVER get to receive it!!!
|
|
if(!mUART_Rx_waiting) mUART_RX_COUNTDOWN=UART_RX_TIME_PERIOD;
|
|
|
|
// Receive the byte
|
|
mUART_Rx_input_queue[mUART_Rx_input_ptr]=data;
|
|
mUART_Rx_input_ptr = (mUART_Rx_input_ptr + 1) % UART_MAX_RX_QUEUE;
|
|
mUART_Rx_waiting++;
|
|
TRACE_MIKIE2("ComLynxRxData() - input ptr=%02d waiting=%02d",mUART_Rx_input_ptr,mUART_Rx_waiting);
|
|
}
|
|
else
|
|
{
|
|
TRACE_MIKIE0("ComLynxRxData() - UART RX Overun");
|
|
}
|
|
}
|
|
|
|
void CMikie::ComLynxTxLoopback(int data)
|
|
{
|
|
TRACE_MIKIE1("ComLynxTxLoopback() - Received %04x",data);
|
|
|
|
if(mUART_Rx_waiting<UART_MAX_RX_QUEUE)
|
|
{
|
|
// Trigger incoming receive IF none waiting otherwise
|
|
// we NEVER get to receive it!!!
|
|
if(!mUART_Rx_waiting) mUART_RX_COUNTDOWN=UART_RX_TIME_PERIOD;
|
|
|
|
// Receive the byte - INSERT into front of queue
|
|
mUART_Rx_output_ptr = (mUART_Rx_output_ptr - 1) % UART_MAX_RX_QUEUE;
|
|
mUART_Rx_input_queue[mUART_Rx_output_ptr]=data;
|
|
mUART_Rx_waiting++;
|
|
TRACE_MIKIE2("ComLynxTxLoopback() - input ptr=%02d waiting=%02d",mUART_Rx_input_ptr,mUART_Rx_waiting);
|
|
}
|
|
else
|
|
{
|
|
TRACE_MIKIE0("ComLynxTxLoopback() - UART RX Overun");
|
|
}
|
|
}
|
|
|
|
void CMikie::ComLynxTxCallback(void (*function)(int data,uint32 objref),uint32 objref)
|
|
{
|
|
mpUART_TX_CALLBACK=function;
|
|
mUART_TX_CALLBACK_OBJECT=objref;
|
|
}
|
|
|
|
|
|
void CMikie::DisplaySetAttributes()
|
|
{
|
|
//
|
|
// Calculate the colour lookup tabes for the relevant mode
|
|
//
|
|
TPALETTE Spot;
|
|
|
|
for(Spot.Index=0;Spot.Index<4096;Spot.Index++)
|
|
{
|
|
mColourMap[Spot.Index] =
|
|
0xff000000 |
|
|
(Spot.Colours.Red * 15 + 30) << 16 |
|
|
(Spot.Colours.Green * 15 + 30) << 8 |
|
|
(Spot.Colours.Blue * 15 + 30);
|
|
}
|
|
}
|
|
|
|
void CMikie::BlankLineSurface()
|
|
{
|
|
uint32* bitmap_tmp = framebuffer + mpDisplayCurrentLine * SCREEN_WIDTH;
|
|
for (int i = 0; i < SCREEN_WIDTH; i++)
|
|
bitmap_tmp[i] = 0xff000000;
|
|
}
|
|
|
|
void CMikie::CopyLineSurface()
|
|
{
|
|
uint32* bitmap_tmp = framebuffer + mpDisplayCurrentLine * SCREEN_WIDTH;
|
|
|
|
for (int loop = 0; loop < SCREEN_WIDTH / 2; loop++)
|
|
{
|
|
uint32 source = mpRamPointer[(uint16)mLynxAddr];
|
|
if(mDISPCTL_Flip)
|
|
{
|
|
mLynxAddr--;
|
|
*bitmap_tmp=mColourMap[mPalette[source&0x0f].Index];
|
|
bitmap_tmp++;
|
|
*bitmap_tmp=mColourMap[mPalette[source>>4].Index];
|
|
bitmap_tmp++;
|
|
}
|
|
else
|
|
{
|
|
mLynxAddr++;
|
|
*bitmap_tmp = mColourMap[mPalette[source>>4].Index];
|
|
bitmap_tmp++;
|
|
*bitmap_tmp = mColourMap[mPalette[source&0x0f].Index];
|
|
bitmap_tmp++;
|
|
}
|
|
}
|
|
}
|
|
|
|
uint32 CMikie::DisplayRenderLine()
|
|
{
|
|
uint32 work_done=0;
|
|
|
|
if(!mDISPCTL_DMAEnable) return 0;
|
|
// if(mLynxLine&0x80000000) return 0;
|
|
|
|
// Set the timer interrupt flag
|
|
if(mTimerInterruptMask&0x01)
|
|
{
|
|
TRACE_MIKIE0("Update() - TIMER0 IRQ Triggered (Line Timer)");
|
|
mTimerStatusFlags|=0x01;
|
|
}
|
|
|
|
// Logic says it should be 101 but testing on an actual lynx shows the rest
|
|
// persiod is between lines 102,101,100 with the new line being latched at
|
|
// the beginning of count==99 hence the code below !!
|
|
|
|
// Emulate REST signal
|
|
if(mLynxLine==mTIM_2_BKUP-2 || mLynxLine==mTIM_2_BKUP-3 || mLynxLine==mTIM_2_BKUP-4) mIODAT_REST_SIGNAL=TRUE; else mIODAT_REST_SIGNAL=FALSE;
|
|
|
|
if(mLynxLine==(mTIM_2_BKUP-3))
|
|
{
|
|
if(mDISPCTL_Flip)
|
|
{
|
|
mLynxAddr=mDisplayAddress&0xfffc;
|
|
mLynxAddr+=3;
|
|
}
|
|
else
|
|
{
|
|
mLynxAddr=mDisplayAddress&0xfffc;
|
|
}
|
|
// Trigger line rending to start
|
|
mLynxLineDMACounter=102;
|
|
}
|
|
|
|
// Decrement line counter logic
|
|
if(mLynxLine) mLynxLine--;
|
|
|
|
// Do 102 lines, nothing more, less is OK.
|
|
if(mLynxLineDMACounter)
|
|
{
|
|
// TRACE_MIKIE1("Update() - Screen DMA, line %03d",line_count);
|
|
mLynxLineDMACounter--;
|
|
|
|
// Cycle hit for a 80 RAM access in rendering a line
|
|
work_done+=80*DMA_RDWR_CYC;
|
|
|
|
// Mikie screen DMA can only see the system RAM....
|
|
// (Step through bitmap, line at a time)
|
|
|
|
if (mpDisplayCurrentLine < 102)
|
|
{
|
|
CopyLineSurface();
|
|
}
|
|
else
|
|
{
|
|
// ??
|
|
printf("Lynx Line Overflow: %d\n", mpDisplayCurrentLine);
|
|
}
|
|
|
|
mpDisplayCurrentLine++;
|
|
}
|
|
return work_done;
|
|
}
|
|
|
|
uint32 CMikie::DisplayEndOfFrame()
|
|
{
|
|
// Stop any further line rendering
|
|
mLynxLineDMACounter=0;
|
|
mLynxLine=mTIM_2_BKUP;
|
|
|
|
// Set the timer status flag
|
|
if(mTimerInterruptMask&0x04)
|
|
{
|
|
TRACE_MIKIE0("Update() - TIMER2 IRQ Triggered (Frame Timer)");
|
|
mTimerStatusFlags|=0x04;
|
|
}
|
|
|
|
// blank remaining lines and blit to output
|
|
while (mpDisplayCurrentLine < 102)
|
|
{
|
|
BlankLineSurface();
|
|
mpDisplayCurrentLine++;
|
|
}
|
|
|
|
mSystem.Blit(framebuffer);
|
|
|
|
mpDisplayCurrentLine = 0;
|
|
return 0;
|
|
}
|
|
|
|
// Peek/Poke memory handlers
|
|
|
|
void CMikie::Poke(uint32 addr,uint8 data)
|
|
{
|
|
/* Sound register area */
|
|
if(addr >= 0xFD20 && addr <= 0xFD3F)
|
|
{
|
|
int which = (addr - 0xFD20) >> 3; // Each channel gets 8 ports/registers
|
|
switch(addr & 0x7)
|
|
{
|
|
case (AUD0VOL&0x7):
|
|
mAUDIO_VOLUME[which]=(int8)data;
|
|
TRACE_MIKIE2("Poke(AUD0VOL,%02x) at PC=%04x",data,mSystem.mCpu->GetPC());
|
|
CombobulateSound(mSystem.gSystemCycleCount - startTS);
|
|
break;
|
|
case (AUD0SHFTFB&0x7):
|
|
mAUDIO_WAVESHAPER[which]&=0x001fff;
|
|
mAUDIO_WAVESHAPER[which]|=(uint32)data<<13;
|
|
TRACE_MIKIE2("Poke(AUD0SHFTB,%02x) at PC=%04x",data,mSystem.mCpu->GetPC());
|
|
CombobulateSound(mSystem.gSystemCycleCount - startTS);
|
|
break;
|
|
case (AUD0OUTVAL&0x7):
|
|
mAUDIO_OUTPUT[which]=data;
|
|
TRACE_MIKIE2("Poke(AUD0OUTVAL,%02x) at PC=%04x",data,mSystem.mCpu->GetPC());
|
|
CombobulateSound(mSystem.gSystemCycleCount - startTS);
|
|
break;
|
|
case (AUD0L8SHFT&0x7):
|
|
mAUDIO_WAVESHAPER[which]&=0x1fff00;
|
|
mAUDIO_WAVESHAPER[which]|=data;
|
|
TRACE_MIKIE2("Poke(AUD0L8SHFT,%02x) at PC=%04x",data,mSystem.mCpu->GetPC());
|
|
CombobulateSound(mSystem.gSystemCycleCount - startTS);
|
|
break;
|
|
case (AUD0TBACK&0x7):
|
|
mAUDIO_BKUP[which]=data;
|
|
TRACE_MIKIE2("Poke(AUD0TBACK,%02x) at PC=%04x",data,mSystem.mCpu->GetPC());
|
|
CombobulateSound(mSystem.gSystemCycleCount - startTS);
|
|
break;
|
|
case (AUD0CTL&0x7):
|
|
mAUDIO_ENABLE_RELOAD[which]=data&0x10;
|
|
mAUDIO_ENABLE_COUNT[which]=data&0x08;
|
|
mAUDIO_LINKING[which]=data&0x07;
|
|
mAUDIO_INTEGRATE_ENABLE[which]=data&0x20;
|
|
if(data&0x40) mAUDIO_TIMER_DONE[which]=0;
|
|
mAUDIO_WAVESHAPER[which]&=0x1fefff;
|
|
mAUDIO_WAVESHAPER[which]|=(data&0x80)?0x001000:0x000000;
|
|
if(data&0x48)
|
|
{
|
|
mAUDIO_LAST_COUNT[which]=mSystem.gSystemCycleCount;
|
|
mSystem.gNextTimerEvent=mSystem.gSystemCycleCount;
|
|
}
|
|
TRACE_MIKIE2("Poke(AUD0CTL,%02x) at PC=%04x",data,mSystem.mCpu->GetPC());
|
|
CombobulateSound(mSystem.gSystemCycleCount - startTS);
|
|
break;
|
|
case (AUD0COUNT&0x7):
|
|
mAUDIO_CURRENT[which]=data;
|
|
TRACE_MIKIE2("Poke(AUD0COUNT,%02x) at PC=%04x",data,mSystem.mCpu->GetPC());
|
|
CombobulateSound(mSystem.gSystemCycleCount - startTS);
|
|
break;
|
|
case (AUD0MISC&0x7):
|
|
mAUDIO_WAVESHAPER[which]&=0x1ff0ff;
|
|
mAUDIO_WAVESHAPER[which]|=(data&0xf0)<<4;
|
|
mAUDIO_BORROW_IN[which]=data&0x02;
|
|
mAUDIO_BORROW_OUT[which]=data&0x01;
|
|
mAUDIO_LAST_CLOCK[which]=data&0x04;
|
|
TRACE_MIKIE2("Poke(AUD0MISC,%02x) at PC=%04x",data,mSystem.mCpu->GetPC());
|
|
CombobulateSound(mSystem.gSystemCycleCount - startTS);
|
|
break;
|
|
}
|
|
}
|
|
else switch(addr&0xff)
|
|
{
|
|
case (TIM0BKUP&0xff):
|
|
mTIM_0_BKUP=data;
|
|
TRACE_MIKIE2("Poke(TIM0BKUP,%02x) at PC=%04x",data,mSystem.mCpu->GetPC());
|
|
break;
|
|
case (TIM1BKUP&0xff):
|
|
mTIM_1_BKUP=data;
|
|
TRACE_MIKIE2("Poke(TIM1BKUP,%02x) at PC=%04x",data,mSystem.mCpu->GetPC());
|
|
break;
|
|
case (TIM2BKUP&0xff):
|
|
mTIM_2_BKUP=data;
|
|
TRACE_MIKIE2("Poke(TIM2BKUP,%02x) at PC=%04x",data,mSystem.mCpu->GetPC());
|
|
break;
|
|
case (TIM3BKUP&0xff):
|
|
mTIM_3_BKUP=data;
|
|
TRACE_MIKIE2("Poke(TIM3BKUP,%02x) at PC=%04x",data,mSystem.mCpu->GetPC());
|
|
break;
|
|
case (TIM4BKUP&0xff):
|
|
mTIM_4_BKUP=data;
|
|
TRACE_MIKIE2("Poke(TIM4BKUP,%02x) at PC=%04x",data,mSystem.mCpu->GetPC());
|
|
break;
|
|
case (TIM5BKUP&0xff):
|
|
mTIM_5_BKUP=data;
|
|
TRACE_MIKIE2("Poke(TIM5BKUP,%02x) at PC=%04x",data,mSystem.mCpu->GetPC());
|
|
break;
|
|
case (TIM6BKUP&0xff):
|
|
mTIM_6_BKUP=data;
|
|
TRACE_MIKIE2("Poke(TIM6BKUP,%02x) at PC=%04x",data,mSystem.mCpu->GetPC());
|
|
break;
|
|
case (TIM7BKUP&0xff):
|
|
mTIM_7_BKUP=data;
|
|
TRACE_MIKIE2("Poke(TIM7BKUP,%02x) at PC=%04x",data,mSystem.mCpu->GetPC());
|
|
break;
|
|
|
|
|
|
case (TIM0CTLA&0xff):
|
|
mTimerInterruptMask&=(0x01^0xff);
|
|
mTimerInterruptMask|=(data&0x80)?0x01:0x00;
|
|
mTIM_0_ENABLE_RELOAD=data&0x10;
|
|
mTIM_0_ENABLE_COUNT=data&0x08;
|
|
mTIM_0_LINKING=data&0x07;
|
|
if(data&0x40) mTIM_0_TIMER_DONE=0;
|
|
if(data&0x48)
|
|
{
|
|
mTIM_0_LAST_COUNT=mSystem.gSystemCycleCount;
|
|
mSystem.gNextTimerEvent=mSystem.gSystemCycleCount;
|
|
}
|
|
TRACE_MIKIE2("Poke(TIM0CTLA,%02x) at PC=%04x",data,mSystem.mCpu->GetPC());
|
|
break;
|
|
case (TIM1CTLA&0xff):
|
|
mTimerInterruptMask&=(0x02^0xff);
|
|
mTimerInterruptMask|=(data&0x80)?0x02:0x00;
|
|
mTIM_1_ENABLE_RELOAD=data&0x10;
|
|
mTIM_1_ENABLE_COUNT=data&0x08;
|
|
mTIM_1_LINKING=data&0x07;
|
|
if(data&0x40) mTIM_1_TIMER_DONE=0;
|
|
if(data&0x48)
|
|
{
|
|
mTIM_1_LAST_COUNT=mSystem.gSystemCycleCount;
|
|
mSystem.gNextTimerEvent=mSystem.gSystemCycleCount;
|
|
}
|
|
TRACE_MIKIE2("Poke(TIM1CTLA,%02x) at PC=%04x",data,mSystem.mCpu->GetPC());
|
|
break;
|
|
case (TIM2CTLA&0xff):
|
|
mTimerInterruptMask&=(0x04^0xff);
|
|
mTimerInterruptMask|=(data&0x80)?0x04:0x00;
|
|
mTIM_2_ENABLE_RELOAD=data&0x10;
|
|
mTIM_2_ENABLE_COUNT=data&0x08;
|
|
mTIM_2_LINKING=data&0x07;
|
|
if(data&0x40) mTIM_2_TIMER_DONE=0;
|
|
if(data&0x48)
|
|
{
|
|
mTIM_2_LAST_COUNT=mSystem.gSystemCycleCount;
|
|
mSystem.gNextTimerEvent=mSystem.gSystemCycleCount;
|
|
}
|
|
TRACE_MIKIE2("Poke(TIM2CTLA,%02x) at PC=%04x",data,mSystem.mCpu->GetPC());
|
|
break;
|
|
case (TIM3CTLA&0xff):
|
|
mTimerInterruptMask&=(0x08^0xff);
|
|
mTimerInterruptMask|=(data&0x80)?0x08:0x00;
|
|
mTIM_3_ENABLE_RELOAD=data&0x10;
|
|
mTIM_3_ENABLE_COUNT=data&0x08;
|
|
mTIM_3_LINKING=data&0x07;
|
|
if(data&0x40) mTIM_3_TIMER_DONE=0;
|
|
if(data&0x48)
|
|
{
|
|
mTIM_3_LAST_COUNT=mSystem.gSystemCycleCount;
|
|
mSystem.gNextTimerEvent=mSystem.gSystemCycleCount;
|
|
}
|
|
TRACE_MIKIE2("Poke(TIM3CTLA,%02x) at PC=%04x",data,mSystem.mCpu->GetPC());
|
|
break;
|
|
case (TIM4CTLA&0xff):
|
|
// Timer 4 can never generate interrupts as its timer output is used
|
|
// to drive the UART clock generator
|
|
mTIM_4_ENABLE_RELOAD=data&0x10;
|
|
mTIM_4_ENABLE_COUNT=data&0x08;
|
|
mTIM_4_LINKING=data&0x07;
|
|
if(data&0x40) mTIM_4_TIMER_DONE=0;
|
|
if(data&0x48)
|
|
{
|
|
mTIM_4_LAST_COUNT=mSystem.gSystemCycleCount;
|
|
mSystem.gNextTimerEvent=mSystem.gSystemCycleCount;
|
|
}
|
|
TRACE_MIKIE2("Poke(TIM4CTLA,%02x) at PC=%04x",data,mSystem.mCpu->GetPC());
|
|
break;
|
|
case (TIM5CTLA&0xff):
|
|
mTimerInterruptMask&=(0x20^0xff);
|
|
mTimerInterruptMask|=(data&0x80)?0x20:0x00;
|
|
mTIM_5_ENABLE_RELOAD=data&0x10;
|
|
mTIM_5_ENABLE_COUNT=data&0x08;
|
|
mTIM_5_LINKING=data&0x07;
|
|
if(data&0x40) mTIM_5_TIMER_DONE=0;
|
|
if(data&0x48)
|
|
{
|
|
mTIM_5_LAST_COUNT=mSystem.gSystemCycleCount;
|
|
mSystem.gNextTimerEvent=mSystem.gSystemCycleCount;
|
|
}
|
|
TRACE_MIKIE2("Poke(TIM5CTLA,%02x) at PC=%04x",data,mSystem.mCpu->GetPC());
|
|
break;
|
|
case (TIM6CTLA&0xff):
|
|
mTimerInterruptMask&=(0x40^0xff);
|
|
mTimerInterruptMask|=(data&0x80)?0x40:0x00;
|
|
mTIM_6_ENABLE_RELOAD=data&0x10;
|
|
mTIM_6_ENABLE_COUNT=data&0x08;
|
|
mTIM_6_LINKING=data&0x07;
|
|
if(data&0x40) mTIM_6_TIMER_DONE=0;
|
|
if(data&0x48)
|
|
{
|
|
mTIM_6_LAST_COUNT=mSystem.gSystemCycleCount;
|
|
mSystem.gNextTimerEvent=mSystem.gSystemCycleCount;
|
|
}
|
|
TRACE_MIKIE2("Poke(TIM6CTLA,%02x) at PC=%04x",data,mSystem.mCpu->GetPC());
|
|
break;
|
|
case (TIM7CTLA&0xff):
|
|
mTimerInterruptMask&=(0x80^0xff);
|
|
mTimerInterruptMask|=(data&0x80)?0x80:0x00;
|
|
mTIM_7_ENABLE_RELOAD=data&0x10;
|
|
mTIM_7_ENABLE_COUNT=data&0x08;
|
|
mTIM_7_LINKING=data&0x07;
|
|
if(data&0x40) mTIM_7_TIMER_DONE=0;
|
|
if(data&0x48)
|
|
{
|
|
mTIM_7_LAST_COUNT=mSystem.gSystemCycleCount;
|
|
mSystem.gNextTimerEvent=mSystem.gSystemCycleCount;
|
|
}
|
|
TRACE_MIKIE2("Poke(TIM7CTLA,%02x) at PC=%04x",data,mSystem.mCpu->GetPC());
|
|
break;
|
|
|
|
|
|
case (TIM0CNT&0xff):
|
|
mTIM_0_CURRENT=data;
|
|
mSystem.gNextTimerEvent=mSystem.gSystemCycleCount;
|
|
TRACE_MIKIE2("Poke(TIM0CNT ,%02x) at PC=%04x",data,mSystem.mCpu->GetPC());
|
|
break;
|
|
case (TIM1CNT&0xff):
|
|
mTIM_1_CURRENT=data;
|
|
mSystem.gNextTimerEvent=mSystem.gSystemCycleCount;
|
|
TRACE_MIKIE2("Poke(TIM1CNT ,%02x) at PC=%04x",data,mSystem.mCpu->GetPC());
|
|
break;
|
|
case (TIM2CNT&0xff):
|
|
mTIM_2_CURRENT=data;
|
|
mSystem.gNextTimerEvent=mSystem.gSystemCycleCount;
|
|
TRACE_MIKIE2("Poke(TIM2CNT ,%02x) at PC=%04x",data,mSystem.mCpu->GetPC());
|
|
break;
|
|
case (TIM3CNT&0xff):
|
|
mTIM_3_CURRENT=data;
|
|
mSystem.gNextTimerEvent=mSystem.gSystemCycleCount;
|
|
TRACE_MIKIE2("Poke(TIM3CNT ,%02x) at PC=%04x",data,mSystem.mCpu->GetPC());
|
|
break;
|
|
case (TIM4CNT&0xff):
|
|
mTIM_4_CURRENT=data;
|
|
mSystem.gNextTimerEvent=mSystem.gSystemCycleCount;
|
|
TRACE_MIKIE2("Poke(TIM4CNT ,%02x) at PC=%04x",data,mSystem.mCpu->GetPC());
|
|
break;
|
|
case (TIM5CNT&0xff):
|
|
mTIM_5_CURRENT=data;
|
|
mSystem.gNextTimerEvent=mSystem.gSystemCycleCount;
|
|
TRACE_MIKIE2("Poke(TIM5CNT ,%02x) at PC=%04x",data,mSystem.mCpu->GetPC());
|
|
break;
|
|
case (TIM6CNT&0xff):
|
|
mTIM_6_CURRENT=data;
|
|
mSystem.gNextTimerEvent=mSystem.gSystemCycleCount;
|
|
TRACE_MIKIE2("Poke(TIM6CNT ,%02x) at PC=%04x",data,mSystem.mCpu->GetPC());
|
|
break;
|
|
case (TIM7CNT&0xff):
|
|
mTIM_7_CURRENT=data;
|
|
mSystem.gNextTimerEvent=mSystem.gSystemCycleCount;
|
|
TRACE_MIKIE2("Poke(TIM7CNT ,%02x) at PC=%04x",data,mSystem.mCpu->GetPC());
|
|
break;
|
|
|
|
case (TIM0CTLB&0xff):
|
|
mTIM_0_TIMER_DONE=data&0x08;
|
|
mTIM_0_LAST_CLOCK=data&0x04;
|
|
mTIM_0_BORROW_IN=data&0x02;
|
|
mTIM_0_BORROW_OUT=data&0x01;
|
|
TRACE_MIKIE2("Poke(TIM0CTLB ,%02x) at PC=%04x",data,mSystem.mCpu->GetPC());
|
|
// BlowOut();
|
|
break;
|
|
case (TIM1CTLB&0xff):
|
|
mTIM_1_TIMER_DONE=data&0x08;
|
|
mTIM_1_LAST_CLOCK=data&0x04;
|
|
mTIM_1_BORROW_IN=data&0x02;
|
|
mTIM_1_BORROW_OUT=data&0x01;
|
|
TRACE_MIKIE2("Poke(TIM1CTLB ,%02x) at PC=%04x",data,mSystem.mCpu->GetPC());
|
|
// BlowOut();
|
|
break;
|
|
case (TIM2CTLB&0xff):
|
|
mTIM_2_TIMER_DONE=data&0x08;
|
|
mTIM_2_LAST_CLOCK=data&0x04;
|
|
mTIM_2_BORROW_IN=data&0x02;
|
|
mTIM_2_BORROW_OUT=data&0x01;
|
|
TRACE_MIKIE2("Poke(TIM2CTLB ,%02x) at PC=%04x",data,mSystem.mCpu->GetPC());
|
|
// BlowOut();
|
|
break;
|
|
case (TIM3CTLB&0xff):
|
|
mTIM_3_TIMER_DONE=data&0x08;
|
|
mTIM_3_LAST_CLOCK=data&0x04;
|
|
mTIM_3_BORROW_IN=data&0x02;
|
|
mTIM_3_BORROW_OUT=data&0x01;
|
|
TRACE_MIKIE2("Poke(TIM3CTLB ,%02x) at PC=%04x",data,mSystem.mCpu->GetPC());
|
|
// BlowOut();
|
|
break;
|
|
case (TIM4CTLB&0xff):
|
|
mTIM_4_TIMER_DONE=data&0x08;
|
|
mTIM_4_LAST_CLOCK=data&0x04;
|
|
mTIM_4_BORROW_IN=data&0x02;
|
|
mTIM_4_BORROW_OUT=data&0x01;
|
|
TRACE_MIKIE2("Poke(TIM4CTLB ,%02x) at PC=%04x",data,mSystem.mCpu->GetPC());
|
|
// BlowOut();
|
|
break;
|
|
case (TIM5CTLB&0xff):
|
|
mTIM_5_TIMER_DONE=data&0x08;
|
|
mTIM_5_LAST_CLOCK=data&0x04;
|
|
mTIM_5_BORROW_IN=data&0x02;
|
|
mTIM_5_BORROW_OUT=data&0x01;
|
|
TRACE_MIKIE2("Poke(TIM5CTLB ,%02x) at PC=%04x",data,mSystem.mCpu->GetPC());
|
|
// BlowOut();
|
|
break;
|
|
case (TIM6CTLB&0xff):
|
|
mTIM_6_TIMER_DONE=data&0x08;
|
|
mTIM_6_LAST_CLOCK=data&0x04;
|
|
mTIM_6_BORROW_IN=data&0x02;
|
|
mTIM_6_BORROW_OUT=data&0x01;
|
|
TRACE_MIKIE2("Poke(TIM6CTLB ,%02x) at PC=%04x",data,mSystem.mCpu->GetPC());
|
|
// BlowOut();
|
|
break;
|
|
case (TIM7CTLB&0xff):
|
|
mTIM_7_TIMER_DONE=data&0x08;
|
|
mTIM_7_LAST_CLOCK=data&0x04;
|
|
mTIM_7_BORROW_IN=data&0x02;
|
|
mTIM_7_BORROW_OUT=data&0x01;
|
|
TRACE_MIKIE2("Poke(TIM7CTLB ,%02x) at PC=%04x",data,mSystem.mCpu->GetPC());
|
|
// BlowOut();
|
|
break;
|
|
|
|
case (ATTEN_A&0xff):
|
|
mAUDIO_ATTEN[0] = data;
|
|
TRACE_MIKIE2("Poke(ATTEN_A ,%02x) at PC=%04x",data,mSystem.mCpu->GetPC());
|
|
CombobulateSound(mSystem.gSystemCycleCount - startTS);
|
|
break;
|
|
case (ATTEN_B&0xff):
|
|
mAUDIO_ATTEN[1] = data;
|
|
TRACE_MIKIE2("Poke(ATTEN_B ,%02x) at PC=%04x",data,mSystem.mCpu->GetPC());
|
|
CombobulateSound(mSystem.gSystemCycleCount - startTS);
|
|
break;
|
|
case (ATTEN_C&0xff):
|
|
mAUDIO_ATTEN[2] = data;
|
|
TRACE_MIKIE2("Poke(ATTEN_C ,%02x) at PC=%04x",data,mSystem.mCpu->GetPC());
|
|
CombobulateSound(mSystem.gSystemCycleCount - startTS);
|
|
break;
|
|
case (ATTEN_D&0xff):
|
|
mAUDIO_ATTEN[3] = data;
|
|
TRACE_MIKIE2("Poke(ATTEN_D ,%02x) at PC=%04x",data,mSystem.mCpu->GetPC());
|
|
CombobulateSound(mSystem.gSystemCycleCount - startTS);
|
|
break;
|
|
case (MPAN&0xff):
|
|
TRACE_MIKIE2("Poke(MPAN ,%02x) at PC=%04x",data,mSystem.mCpu->GetPC());
|
|
mPAN = data;
|
|
CombobulateSound(mSystem.gSystemCycleCount - startTS);
|
|
break;
|
|
|
|
case (MSTEREO&0xff):
|
|
TRACE_MIKIE2("Poke(MSTEREO ,%02x) at PC=%04x",data,mSystem.mCpu->GetPC());
|
|
data^=0xff;
|
|
mSTEREO=data;
|
|
CombobulateSound(mSystem.gSystemCycleCount - startTS);
|
|
break;
|
|
|
|
case (INTRST&0xff):
|
|
data^=0xff;
|
|
mTimerStatusFlags&=data;
|
|
mSystem.gNextTimerEvent=mSystem.gSystemCycleCount;
|
|
TRACE_MIKIE2("Poke(INTRST ,%02x) at PC=%04x",data,mSystem.mCpu->GetPC());
|
|
break;
|
|
|
|
case (INTSET&0xff):
|
|
TRACE_MIKIE2("Poke(INTSET ,%02x) at PC=%04x",data,mSystem.mCpu->GetPC());
|
|
mTimerStatusFlags|=data;
|
|
mSystem.gNextTimerEvent=mSystem.gSystemCycleCount;
|
|
break;
|
|
|
|
case (SYSCTL1&0xff):
|
|
TRACE_MIKIE2("Poke(SYSCTL1 ,%02x) at PC=%04x",data,mSystem.mCpu->GetPC());
|
|
if(!(data&0x02))
|
|
{
|
|
C6502_REGS regs;
|
|
mSystem.GetRegs(regs);
|
|
TRACE_MIKIE1("Runtime Alert - System Halted\nCMikie::Poke(SYSCTL1) - Lynx power down occured at PC=$%04x.\nResetting system.",regs.PC);
|
|
// can't reset in the middle of a frame, screws the timekeeping; and it doesn't make a difference anyway
|
|
// mSystem.Reset();
|
|
mSystem.gSystemHalt=TRUE;
|
|
}
|
|
mSystem.CartAddressStrobe((data&0x01)?TRUE:FALSE);
|
|
break;
|
|
|
|
case (MIKEYSREV&0xff):
|
|
TRACE_MIKIE2("Poke(MIKEYSREV,%02x) at PC=%04x",data,mSystem.mCpu->GetPC());
|
|
break;
|
|
|
|
case (IODIR&0xff):
|
|
TRACE_MIKIE2("Poke(IODIR ,%02x) at PC=%04x",data,mSystem.mCpu->GetPC());
|
|
mIODIR=data;
|
|
break;
|
|
|
|
case (IODAT&0xff):
|
|
TRACE_MIKIE2("Poke(IODAT ,%02x) at PC=%04x",data,mSystem.mCpu->GetPC());
|
|
mIODAT=data;
|
|
mSystem.CartAddressData((mIODAT&0x02)?TRUE:FALSE);
|
|
// Enable cart writes to BANK1 on AUDIN if AUDIN is set to output
|
|
if(mIODIR&0x10) mSystem.mCart->mWriteEnableBank1=(mIODAT&0x10)?true:false;
|
|
break;
|
|
|
|
case (SERCTL&0xff):
|
|
TRACE_MIKIE2("Poke(SERCTL ,%02x) at PC=%04x",data,mSystem.mCpu->GetPC());
|
|
mUART_TX_IRQ_ENABLE=(data&0x80)?true:false;
|
|
mUART_RX_IRQ_ENABLE=(data&0x40)?true:false;
|
|
mUART_PARITY_ENABLE=(data&0x10)?true:false;
|
|
mUART_SENDBREAK=data&0x02;
|
|
mUART_PARITY_EVEN=data&0x01;
|
|
|
|
// Reset all errors if required
|
|
if(data&0x08)
|
|
{
|
|
mUART_Rx_overun_error=0;
|
|
mUART_Rx_framing_error=0;
|
|
}
|
|
|
|
if(mUART_SENDBREAK)
|
|
{
|
|
// Trigger send break, it will self sustain as long as sendbreak is set
|
|
mUART_TX_COUNTDOWN=UART_TX_TIME_PERIOD;
|
|
// Loop back what we transmitted
|
|
ComLynxTxLoopback(UART_BREAK_CODE);
|
|
}
|
|
break;
|
|
|
|
case (SERDAT&0xff):
|
|
TRACE_MIKIE2("Poke(SERDAT ,%04x) at PC=%04x",data,mSystem.mCpu->GetPC());
|
|
//
|
|
// Fake transmission, set counter to be decremented by Timer 4
|
|
//
|
|
// ComLynx only has one output pin, hence Rx & Tx are shorted
|
|
// therefore any transmitted data will loopback
|
|
//
|
|
mUART_TX_DATA=data;
|
|
// Calculate Parity data
|
|
if(mUART_PARITY_ENABLE)
|
|
{
|
|
// Calc parity value
|
|
// Leave at zero !!
|
|
}
|
|
else
|
|
{
|
|
// If disabled then the PAREVEN bit is sent
|
|
if(mUART_PARITY_EVEN) data|=0x0100;
|
|
}
|
|
// Set countdown to transmission
|
|
mUART_TX_COUNTDOWN=UART_TX_TIME_PERIOD;
|
|
// Loop back what we transmitted
|
|
ComLynxTxLoopback(mUART_TX_DATA);
|
|
break;
|
|
|
|
case (SDONEACK&0xff):
|
|
TRACE_MIKIE2("Poke(SDONEACK,%02x) at PC=%04x",data,mSystem.mCpu->GetPC());
|
|
break;
|
|
case (CPUSLEEP&0xff):
|
|
mSystem.gSuzieDoneTime = mSystem.gSystemCycleCount+mSystem.PaintSprites();
|
|
SetCPUSleep();
|
|
break;
|
|
|
|
case (DISPCTL&0xff):
|
|
TRACE_MIKIE2("Poke(DISPCTL,%02x) at PC=%04x",data,mSystem.mCpu->GetPC());
|
|
{
|
|
TDISPCTL tmp;
|
|
tmp.Byte=data;
|
|
mDISPCTL_DMAEnable=tmp.Bits.DMAEnable;
|
|
mDISPCTL_Flip=tmp.Bits.Flip;
|
|
mDISPCTL_FourColour=tmp.Bits.FourColour;
|
|
mDISPCTL_Colour=tmp.Bits.Colour;
|
|
}
|
|
break;
|
|
case (PBKUP&0xff):
|
|
TRACE_MIKIE2("Poke(PBKUP,%02x) at PC=%04x",data,mSystem.mCpu->GetPC());
|
|
break;
|
|
|
|
case (DISPADRL&0xff):
|
|
TRACE_MIKIE2("Poke(DISPADRL,%02x) at PC=%04x",data,mSystem.mCpu->GetPC());
|
|
mDisplayAddress&=0xff00;
|
|
mDisplayAddress+=data;
|
|
break;
|
|
|
|
case (DISPADRH&0xff):
|
|
TRACE_MIKIE2("Poke(DISPADRH,%02x) at PC=%04x",data,mSystem.mCpu->GetPC());
|
|
mDisplayAddress&=0x00ff;
|
|
mDisplayAddress+=(data<<8);
|
|
break;
|
|
|
|
case (Mtest0&0xff):
|
|
case (Mtest1&0xff):
|
|
// Test registers are unimplemented
|
|
// lets hope no programs use them.
|
|
TRACE_MIKIE2("Poke(MTEST0/1,%02x) at PC=%04x",data,mSystem.mCpu->GetPC());
|
|
case (Mtest2&0xff):
|
|
// Test registers are unimplemented
|
|
// lets hope no programs use them.
|
|
//gError->Warning("CMikie::Poke() - Write to MTEST2");
|
|
TRACE_MIKIE2("Poke(MTEST2,%02x) at PC=%04x",data,mSystem.mCpu->GetPC());
|
|
break;
|
|
|
|
case (GREEN0&0xff):
|
|
case (GREEN1&0xff):
|
|
case (GREEN2&0xff):
|
|
case (GREEN3&0xff):
|
|
case (GREEN4&0xff):
|
|
case (GREEN5&0xff):
|
|
case (GREEN6&0xff):
|
|
case (GREEN7&0xff):
|
|
case (GREEN8&0xff):
|
|
case (GREEN9&0xff):
|
|
case (GREENA&0xff):
|
|
case (GREENB&0xff):
|
|
case (GREENC&0xff):
|
|
case (GREEND&0xff):
|
|
case (GREENE&0xff):
|
|
case (GREENF&0xff):
|
|
TRACE_MIKIE2("Poke(GREENPAL0-F,%02x) at PC=%04x",data,mSystem.mCpu->GetPC());
|
|
mPalette[addr&0x0f].Colours.Green=data&0x0f;
|
|
break;
|
|
|
|
case (BLUERED0&0xff):
|
|
case (BLUERED1&0xff):
|
|
case (BLUERED2&0xff):
|
|
case (BLUERED3&0xff):
|
|
case (BLUERED4&0xff):
|
|
case (BLUERED5&0xff):
|
|
case (BLUERED6&0xff):
|
|
case (BLUERED7&0xff):
|
|
case (BLUERED8&0xff):
|
|
case (BLUERED9&0xff):
|
|
case (BLUEREDA&0xff):
|
|
case (BLUEREDB&0xff):
|
|
case (BLUEREDC&0xff):
|
|
case (BLUEREDD&0xff):
|
|
case (BLUEREDE&0xff):
|
|
case (BLUEREDF&0xff):
|
|
TRACE_MIKIE2("Poke(BLUEREDPAL0-F,%02x) at PC=%04x",data,mSystem.mCpu->GetPC());
|
|
mPalette[addr&0x0f].Colours.Blue=(data&0xf0)>>4;
|
|
mPalette[addr&0x0f].Colours.Red=data&0x0f;
|
|
break;
|
|
|
|
// Errors on read only register accesses
|
|
|
|
case (MAGRDY0&0xff):
|
|
case (MAGRDY1&0xff):
|
|
case (AUDIN&0xff):
|
|
case (MIKEYHREV&0xff):
|
|
TRACE_MIKIE3("Poke(%04x,%02x) - Poke to read only register location at PC=%04x",addr,data,mSystem.mCpu->GetPC());
|
|
break;
|
|
|
|
// Errors on illegal location accesses
|
|
|
|
default:
|
|
TRACE_MIKIE3("Poke(%04x,%02x) - Poke to illegal location at PC=%04x",addr,data,mSystem.mCpu->GetPC());
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
uint8 CMikie::Peek(uint32 addr)
|
|
{
|
|
/* Sound register area */
|
|
if(addr >= 0xFD20 && addr <= 0xFD3F)
|
|
{
|
|
int which = (addr - 0xFD20) >> 3; // Each channel gets 8 ports/registers
|
|
switch(addr & 0x7)
|
|
{
|
|
case (AUD0VOL&0x7):
|
|
return (uint8)mAUDIO_VOLUME[which];
|
|
break;
|
|
case (AUD0SHFTFB&0x7):
|
|
return (uint8)((mAUDIO_WAVESHAPER[which]>>13)&0xff);
|
|
break;
|
|
case (AUD0OUTVAL&0x7):
|
|
return (uint8)mAUDIO_OUTPUT[which];
|
|
break;
|
|
case (AUD0L8SHFT&0x7):
|
|
return (uint8)(mAUDIO_WAVESHAPER[which]&0xff);
|
|
break;
|
|
case (AUD0TBACK&0x7):
|
|
return (uint8)mAUDIO_BKUP[which];
|
|
break;
|
|
case (AUD0CTL&0x7):
|
|
{
|
|
uint8 retval=0;
|
|
retval|=(mAUDIO_INTEGRATE_ENABLE[which])?0x20:0x00;
|
|
retval|=(mAUDIO_ENABLE_RELOAD[which])?0x10:0x00;
|
|
retval|=(mAUDIO_ENABLE_COUNT[which])?0x08:0x00;
|
|
retval|=(mAUDIO_WAVESHAPER[which]&0x001000)?0x80:0x00;
|
|
retval|=mAUDIO_LINKING[which];
|
|
return retval;
|
|
}
|
|
break;
|
|
case (AUD0COUNT&0x7):
|
|
return (uint8)mAUDIO_CURRENT[which];
|
|
break;
|
|
case (AUD0MISC&0x7):
|
|
{
|
|
uint8 retval=0;
|
|
retval|=(mAUDIO_BORROW_OUT[which])?0x01:0x00;
|
|
retval|=(mAUDIO_BORROW_IN[which])?0x02:0x00;
|
|
retval|=(mAUDIO_LAST_CLOCK[which])?0x08:0x00;
|
|
retval|=(mAUDIO_WAVESHAPER[which]>>4)&0xf0;
|
|
return retval;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
else switch(addr&0xff)
|
|
{
|
|
|
|
// Timer control registers
|
|
|
|
case (TIM0BKUP&0xff):
|
|
TRACE_MIKIE2("Peek(TIM0KBUP ,%02x) at PC=%04x",mTIM_0_BKUP,mSystem.mCpu->GetPC());
|
|
return (uint8)mTIM_0_BKUP;
|
|
break;
|
|
case (TIM1BKUP&0xff):
|
|
TRACE_MIKIE2("Peek(TIM1KBUP ,%02x) at PC=%04x",mTIM_1_BKUP,mSystem.mCpu->GetPC());
|
|
return (uint8)mTIM_1_BKUP;
|
|
break;
|
|
case (TIM2BKUP&0xff):
|
|
TRACE_MIKIE2("Peek(TIM2KBUP ,%02x) at PC=%04x",mTIM_2_BKUP,mSystem.mCpu->GetPC());
|
|
return (uint8)mTIM_2_BKUP;
|
|
break;
|
|
case (TIM3BKUP&0xff):
|
|
TRACE_MIKIE2("Peek(TIM3KBUP ,%02x) at PC=%04x",mTIM_3_BKUP,mSystem.mCpu->GetPC());
|
|
return (uint8)mTIM_3_BKUP;
|
|
break;
|
|
case (TIM4BKUP&0xff):
|
|
TRACE_MIKIE2("Peek(TIM4KBUP ,%02x) at PC=%04x",mTIM_4_BKUP,mSystem.mCpu->GetPC());
|
|
return (uint8)mTIM_4_BKUP;
|
|
break;
|
|
case (TIM5BKUP&0xff):
|
|
TRACE_MIKIE2("Peek(TIM5KBUP ,%02x) at PC=%04x",mTIM_5_BKUP,mSystem.mCpu->GetPC());
|
|
return (uint8)mTIM_5_BKUP;
|
|
break;
|
|
case (TIM6BKUP&0xff):
|
|
TRACE_MIKIE2("Peek(TIM6KBUP ,%02x) at PC=%04x",mTIM_6_BKUP,mSystem.mCpu->GetPC());
|
|
return (uint8)mTIM_6_BKUP;
|
|
break;
|
|
case (TIM7BKUP&0xff):
|
|
TRACE_MIKIE2("Peek(TIM7KBUP ,%02x) at PC=%04x",mTIM_7_BKUP,mSystem.mCpu->GetPC());
|
|
return (uint8)mTIM_7_BKUP;
|
|
break;
|
|
|
|
case (TIM0CTLA&0xff):
|
|
{
|
|
uint8 retval=0;
|
|
retval|=(mTimerInterruptMask&0x01)?0x80:0x00;
|
|
retval|=(mTIM_0_ENABLE_RELOAD)?0x10:0x00;
|
|
retval|=(mTIM_0_ENABLE_COUNT)?0x08:0x00;
|
|
retval|=mTIM_0_LINKING;
|
|
TRACE_MIKIE2("Peek(TIM0CTLA ,%02x) at PC=%04x",retval,mSystem.mCpu->GetPC());
|
|
return retval;
|
|
}
|
|
break;
|
|
case (TIM1CTLA&0xff):
|
|
{
|
|
uint8 retval=0;
|
|
retval|=(mTimerInterruptMask&0x02)?0x80:0x00;
|
|
retval|=(mTIM_1_ENABLE_RELOAD)?0x10:0x00;
|
|
retval|=(mTIM_1_ENABLE_COUNT)?0x08:0x00;
|
|
retval|=mTIM_1_LINKING;
|
|
TRACE_MIKIE2("Peek(TIM1CTLA ,%02x) at PC=%04x",retval,mSystem.mCpu->GetPC());
|
|
return retval;
|
|
}
|
|
break;
|
|
case (TIM2CTLA&0xff):
|
|
{
|
|
uint8 retval=0;
|
|
retval|=(mTimerInterruptMask&0x04)?0x80:0x00;
|
|
retval|=(mTIM_2_ENABLE_RELOAD)?0x10:0x00;
|
|
retval|=(mTIM_2_ENABLE_COUNT)?0x08:0x00;
|
|
retval|=mTIM_2_LINKING;
|
|
TRACE_MIKIE2("Peek(TIM2CTLA ,%02x) at PC=%04x",retval,mSystem.mCpu->GetPC());
|
|
return retval;
|
|
}
|
|
break;
|
|
case (TIM3CTLA&0xff):
|
|
{
|
|
uint8 retval=0;
|
|
retval|=(mTimerInterruptMask&0x08)?0x80:0x00;
|
|
retval|=(mTIM_3_ENABLE_RELOAD)?0x10:0x00;
|
|
retval|=(mTIM_3_ENABLE_COUNT)?0x08:0x00;
|
|
retval|=mTIM_3_LINKING;
|
|
TRACE_MIKIE2("Peek(TIM3CTLA ,%02x) at PC=%04x",retval,mSystem.mCpu->GetPC());
|
|
return retval;
|
|
}
|
|
break;
|
|
case (TIM4CTLA&0xff):
|
|
{
|
|
uint8 retval=0;
|
|
retval|=(mTimerInterruptMask&0x10)?0x80:0x00;
|
|
retval|=(mTIM_4_ENABLE_RELOAD)?0x10:0x00;
|
|
retval|=(mTIM_4_ENABLE_COUNT)?0x08:0x00;
|
|
retval|=mTIM_4_LINKING;
|
|
TRACE_MIKIE2("Peek(TIM4CTLA ,%02x) at PC=%04x",retval,mSystem.mCpu->GetPC());
|
|
return retval;
|
|
}
|
|
break;
|
|
case (TIM5CTLA&0xff):
|
|
{
|
|
uint8 retval=0;
|
|
retval|=(mTimerInterruptMask&0x20)?0x80:0x00;
|
|
retval|=(mTIM_5_ENABLE_RELOAD)?0x10:0x00;
|
|
retval|=(mTIM_5_ENABLE_COUNT)?0x08:0x00;
|
|
retval|=mTIM_5_LINKING;
|
|
TRACE_MIKIE2("Peek(TIM5CTLA ,%02x) at PC=%04x",retval,mSystem.mCpu->GetPC());
|
|
return retval;
|
|
}
|
|
break;
|
|
case (TIM6CTLA&0xff):
|
|
{
|
|
uint8 retval=0;
|
|
retval|=(mTimerInterruptMask&0x40)?0x80:0x00;
|
|
retval|=(mTIM_6_ENABLE_RELOAD)?0x10:0x00;
|
|
retval|=(mTIM_6_ENABLE_COUNT)?0x08:0x00;
|
|
retval|=mTIM_6_LINKING;
|
|
TRACE_MIKIE2("Peek(TIM6CTLA ,%02x) at PC=%04x",retval,mSystem.mCpu->GetPC());
|
|
return retval;
|
|
}
|
|
break;
|
|
case (TIM7CTLA&0xff):
|
|
{
|
|
uint8 retval=0;
|
|
retval|=(mTimerInterruptMask&0x80)?0x80:0x00;
|
|
retval|=(mTIM_7_ENABLE_RELOAD)?0x10:0x00;
|
|
retval|=(mTIM_7_ENABLE_COUNT)?0x08:0x00;
|
|
retval|=mTIM_7_LINKING;
|
|
TRACE_MIKIE2("Peek(TIM7CTLA ,%02x) at PC=%04x",retval,mSystem.mCpu->GetPC());
|
|
return retval;
|
|
}
|
|
break;
|
|
|
|
case (TIM0CNT&0xff):
|
|
Update();
|
|
TRACE_MIKIE2("Peek(TIM0CNT ,%02x) at PC=%04x",mTIM_0_CURRENT,mSystem.mCpu->GetPC());
|
|
return (uint8)mTIM_0_CURRENT;
|
|
break;
|
|
case (TIM1CNT&0xff):
|
|
Update();
|
|
TRACE_MIKIE2("Peek(TIM1CNT ,%02x) at PC=%04x",mTIM_1_CURRENT,mSystem.mCpu->GetPC());
|
|
return (uint8)mTIM_1_CURRENT;
|
|
break;
|
|
case (TIM2CNT&0xff):
|
|
Update();
|
|
TRACE_MIKIE2("Peek(TIM2CNT ,%02x) at PC=%04x",mTIM_2_CURRENT,mSystem.mCpu->GetPC());
|
|
return (uint8)mTIM_2_CURRENT;
|
|
break;
|
|
case (TIM3CNT&0xff):
|
|
Update();
|
|
TRACE_MIKIE2("Peek(TIM3CNT ,%02x) at PC=%04x",mTIM_3_CURRENT,mSystem.mCpu->GetPC());
|
|
return (uint8)mTIM_3_CURRENT;
|
|
break;
|
|
case (TIM4CNT&0xff):
|
|
Update();
|
|
TRACE_MIKIE2("Peek(TIM4CNT ,%02x) at PC=%04x",mTIM_4_CURRENT,mSystem.mCpu->GetPC());
|
|
return (uint8)mTIM_4_CURRENT;
|
|
break;
|
|
case (TIM5CNT&0xff):
|
|
Update();
|
|
TRACE_MIKIE2("Peek(TIM5CNT ,%02x) at PC=%04x",mTIM_5_CURRENT,mSystem.mCpu->GetPC());
|
|
return (uint8)mTIM_5_CURRENT;
|
|
break;
|
|
case (TIM6CNT&0xff):
|
|
Update();
|
|
TRACE_MIKIE2("Peek(TIM6CNT ,%02x) at PC=%04x",mTIM_6_CURRENT,mSystem.mCpu->GetPC());
|
|
return (uint8)mTIM_6_CURRENT;
|
|
break;
|
|
case (TIM7CNT&0xff):
|
|
Update();
|
|
TRACE_MIKIE2("Peek(TIM7CNT ,%02x) at PC=%04x",mTIM_7_CURRENT,mSystem.mCpu->GetPC());
|
|
return (uint8)mTIM_7_CURRENT;
|
|
break;
|
|
|
|
case (TIM0CTLB&0xff):
|
|
{
|
|
uint8 retval=0;
|
|
retval|=(mTIM_0_TIMER_DONE)?0x08:0x00;
|
|
retval|=(mTIM_0_LAST_CLOCK)?0x04:0x00;
|
|
retval|=(mTIM_0_BORROW_IN)?0x02:0x00;
|
|
retval|=(mTIM_0_BORROW_OUT)?0x01:0x00;
|
|
TRACE_MIKIE2("Peek(TIM0CTLB ,%02x) at PC=%04x",retval,mSystem.mCpu->GetPC());
|
|
return retval;
|
|
}
|
|
// BlowOut();
|
|
break;
|
|
case (TIM1CTLB&0xff):
|
|
{
|
|
uint8 retval=0;
|
|
retval|=(mTIM_1_TIMER_DONE)?0x08:0x00;
|
|
retval|=(mTIM_1_LAST_CLOCK)?0x04:0x00;
|
|
retval|=(mTIM_1_BORROW_IN)?0x02:0x00;
|
|
retval|=(mTIM_1_BORROW_OUT)?0x01:0x00;
|
|
TRACE_MIKIE2("Peek(TIM1CTLB ,%02x) at PC=%04x",retval,mSystem.mCpu->GetPC());
|
|
return retval;
|
|
}
|
|
// BlowOut();
|
|
break;
|
|
case (TIM2CTLB&0xff):
|
|
{
|
|
uint8 retval=0;
|
|
retval|=(mTIM_2_TIMER_DONE)?0x08:0x00;
|
|
retval|=(mTIM_2_LAST_CLOCK)?0x04:0x00;
|
|
retval|=(mTIM_2_BORROW_IN)?0x02:0x00;
|
|
retval|=(mTIM_2_BORROW_OUT)?0x01:0x00;
|
|
TRACE_MIKIE2("Peek(TIM2CTLB ,%02x) at PC=%04x",retval,mSystem.mCpu->GetPC());
|
|
return retval;
|
|
}
|
|
// BlowOut();
|
|
break;
|
|
case (TIM3CTLB&0xff):
|
|
{
|
|
uint8 retval=0;
|
|
retval|=(mTIM_3_TIMER_DONE)?0x08:0x00;
|
|
retval|=(mTIM_3_LAST_CLOCK)?0x04:0x00;
|
|
retval|=(mTIM_3_BORROW_IN)?0x02:0x00;
|
|
retval|=(mTIM_3_BORROW_OUT)?0x01:0x00;
|
|
TRACE_MIKIE2("Peek(TIM3CTLB ,%02x) at PC=%04x",retval,mSystem.mCpu->GetPC());
|
|
return retval;
|
|
}
|
|
// BlowOut();
|
|
break;
|
|
case (TIM4CTLB&0xff):
|
|
{
|
|
uint8 retval=0;
|
|
retval|=(mTIM_4_TIMER_DONE)?0x08:0x00;
|
|
retval|=(mTIM_4_LAST_CLOCK)?0x04:0x00;
|
|
retval|=(mTIM_4_BORROW_IN)?0x02:0x00;
|
|
retval|=(mTIM_4_BORROW_OUT)?0x01:0x00;
|
|
TRACE_MIKIE2("Peek(TIM4CTLB ,%02x) at PC=%04x",retval,mSystem.mCpu->GetPC());
|
|
return retval;
|
|
}
|
|
// BlowOut();
|
|
break;
|
|
case (TIM5CTLB&0xff):
|
|
{
|
|
uint8 retval=0;
|
|
retval|=(mTIM_5_TIMER_DONE)?0x08:0x00;
|
|
retval|=(mTIM_5_LAST_CLOCK)?0x04:0x00;
|
|
retval|=(mTIM_5_BORROW_IN)?0x02:0x00;
|
|
retval|=(mTIM_5_BORROW_OUT)?0x01:0x00;
|
|
TRACE_MIKIE2("Peek(TIM5CTLB ,%02x) at PC=%04x",retval,mSystem.mCpu->GetPC());
|
|
return retval;
|
|
}
|
|
// BlowOut();
|
|
break;
|
|
case (TIM6CTLB&0xff):
|
|
{
|
|
uint8 retval=0;
|
|
retval|=(mTIM_6_TIMER_DONE)?0x08:0x00;
|
|
retval|=(mTIM_6_LAST_CLOCK)?0x04:0x00;
|
|
retval|=(mTIM_6_BORROW_IN)?0x02:0x00;
|
|
retval|=(mTIM_6_BORROW_OUT)?0x01:0x00;
|
|
TRACE_MIKIE2("Peek(TIM6CTLB ,%02x) at PC=%04x",retval,mSystem.mCpu->GetPC());
|
|
return retval;
|
|
}
|
|
// BlowOut();
|
|
break;
|
|
case (TIM7CTLB&0xff):
|
|
{
|
|
uint8 retval=0;
|
|
retval|=(mTIM_7_TIMER_DONE)?0x08:0x00;
|
|
retval|=(mTIM_7_LAST_CLOCK)?0x04:0x00;
|
|
retval|=(mTIM_7_BORROW_IN)?0x02:0x00;
|
|
retval|=(mTIM_7_BORROW_OUT)?0x01:0x00;
|
|
TRACE_MIKIE2("Peek(TIM7CTLB ,%02x) at PC=%04x",retval,mSystem.mCpu->GetPC());
|
|
return retval;
|
|
}
|
|
// BlowOut();
|
|
break;
|
|
|
|
// Extra audio control registers
|
|
|
|
case (ATTEN_A&0xff):
|
|
TRACE_MIKIE1("Peek(ATTEN_A) at PC=%04x",mSystem.mCpu->GetPC());
|
|
return (uint8) mAUDIO_ATTEN[0];
|
|
break;
|
|
case (ATTEN_B&0xff):
|
|
TRACE_MIKIE1("Peek(ATTEN_B) at PC=%04x",mSystem.mCpu->GetPC());
|
|
return (uint8) mAUDIO_ATTEN[1];
|
|
break;
|
|
case (ATTEN_C&0xff):
|
|
TRACE_MIKIE1("Peek(ATTEN_C) at PC=%04x",mSystem.mCpu->GetPC());
|
|
return (uint8) mAUDIO_ATTEN[2];
|
|
break;
|
|
case (ATTEN_D&0xff):
|
|
TRACE_MIKIE1("Peek(ATTEN_D) at PC=%04x",mSystem.mCpu->GetPC());
|
|
return (uint8) mAUDIO_ATTEN[3];
|
|
break;
|
|
case (MPAN&0xff):
|
|
TRACE_MIKIE1("Peek(MPAN) at PC=%04x",mSystem.mCpu->GetPC());
|
|
return (uint8) mPAN;
|
|
break;
|
|
|
|
case (MSTEREO&0xff):
|
|
TRACE_MIKIE2("Peek(MSTEREO,%02x) at PC=%04x",(uint8)mSTEREO^0xff,mSystem.mCpu->GetPC());
|
|
return (uint8) mSTEREO^0xff;
|
|
break;
|
|
|
|
// Miscellaneous registers
|
|
|
|
case (SERCTL&0xff):
|
|
{
|
|
uint32 retval=0;
|
|
retval|=(mUART_TX_COUNTDOWN&UART_TX_INACTIVE)?0xA0:0x00; // Indicate TxDone & TxAllDone
|
|
retval|=(mUART_RX_READY)?0x40:0x00; // Indicate Rx data ready
|
|
retval|=(mUART_Rx_overun_error)?0x08:0x0; // Framing error
|
|
retval|=(mUART_Rx_framing_error)?0x04:0x00; // Rx overrun
|
|
retval|=(mUART_RX_DATA&UART_BREAK_CODE)?0x02:0x00; // Indicate break received
|
|
retval|=(mUART_RX_DATA&0x0100)?0x01:0x00; // Add parity bit
|
|
TRACE_MIKIE2("Peek(SERCTL ,%02x) at PC=%04x",retval,mSystem.mCpu->GetPC());
|
|
return (uint8)retval;
|
|
}
|
|
break;
|
|
|
|
case (SERDAT&0xff):
|
|
mUART_RX_READY=0;
|
|
TRACE_MIKIE2("Peek(SERDAT ,%02x) at PC=%04x",(uint8)mUART_RX_DATA,mSystem.mCpu->GetPC());
|
|
return (uint8)(mUART_RX_DATA&0xff);
|
|
break;
|
|
|
|
case (IODAT&0xff):
|
|
{
|
|
uint32 retval=0;
|
|
retval|=(mIODIR&0x10)?mIODAT&0x10:0x10; // IODIR = output bit : input high (eeprom write done)
|
|
retval|=(mIODIR&0x08)?(((mIODAT&0x08)&&mIODAT_REST_SIGNAL)?0x00:0x08):0x00; // REST = output bit : input low
|
|
retval|=(mIODIR&0x04)?mIODAT&0x04:((mUART_CABLE_PRESENT)?0x04:0x00); // NOEXP = output bit : input low
|
|
retval|=(mIODIR&0x02)?mIODAT&0x02:0x00; // CARTAD = output bit : input low
|
|
retval|=(mIODIR&0x01)?mIODAT&0x01:0x01; // EXTPW = output bit : input high (Power connected)
|
|
TRACE_MIKIE2("Peek(IODAT ,%02x) at PC=%04x",retval,mSystem.mCpu->GetPC());
|
|
return (uint8)retval;
|
|
}
|
|
break;
|
|
|
|
case (INTRST&0xff):
|
|
case (INTSET&0xff):
|
|
TRACE_MIKIE2("Peek(INTSET ,%02x) at PC=%04x",mTimerStatusFlags,mSystem.mCpu->GetPC());
|
|
return (uint8)mTimerStatusFlags;
|
|
break;
|
|
|
|
case (MAGRDY0&0xff):
|
|
case (MAGRDY1&0xff):
|
|
TRACE_MIKIE2("Peek(MAGRDY0/1,%02x) at PC=%04x",0x00,mSystem.mCpu->GetPC());
|
|
return 0x00;
|
|
break;
|
|
|
|
case (AUDIN&0xff):
|
|
// TRACE_MIKIE2("Peek(AUDIN,%02x) at PC=%04x",mAudioInputComparator?0x80:0x00,mSystem.mCpu->GetPC());
|
|
// if(mAudioInputComparator) return 0x80; else return 0x00;
|
|
TRACE_MIKIE2("Peek(AUDIN,%02x) at PC=%04x",0x80,mSystem.mCpu->GetPC());
|
|
return 0x80;
|
|
break;
|
|
|
|
case (MIKEYHREV&0xff):
|
|
TRACE_MIKIE2("Peek(MIKEYHREV,%02x) at PC=%04x",0x01,mSystem.mCpu->GetPC());
|
|
return 0x01;
|
|
break;
|
|
|
|
// Pallette registers
|
|
|
|
case (GREEN0&0xff):
|
|
case (GREEN1&0xff):
|
|
case (GREEN2&0xff):
|
|
case (GREEN3&0xff):
|
|
case (GREEN4&0xff):
|
|
case (GREEN5&0xff):
|
|
case (GREEN6&0xff):
|
|
case (GREEN7&0xff):
|
|
case (GREEN8&0xff):
|
|
case (GREEN9&0xff):
|
|
case (GREENA&0xff):
|
|
case (GREENB&0xff):
|
|
case (GREENC&0xff):
|
|
case (GREEND&0xff):
|
|
case (GREENE&0xff):
|
|
case (GREENF&0xff):
|
|
TRACE_MIKIE2("Peek(GREENPAL0-F,%02x) at PC=%04x",mPalette[addr&0x0f].Colours.Green,mSystem.mCpu->GetPC());
|
|
return mPalette[addr&0x0f].Colours.Green;
|
|
break;
|
|
|
|
case (BLUERED0&0xff):
|
|
case (BLUERED1&0xff):
|
|
case (BLUERED2&0xff):
|
|
case (BLUERED3&0xff):
|
|
case (BLUERED4&0xff):
|
|
case (BLUERED5&0xff):
|
|
case (BLUERED6&0xff):
|
|
case (BLUERED7&0xff):
|
|
case (BLUERED8&0xff):
|
|
case (BLUERED9&0xff):
|
|
case (BLUEREDA&0xff):
|
|
case (BLUEREDB&0xff):
|
|
case (BLUEREDC&0xff):
|
|
case (BLUEREDD&0xff):
|
|
case (BLUEREDE&0xff):
|
|
case (BLUEREDF&0xff):
|
|
TRACE_MIKIE2("Peek(BLUEREDPAL0-F,%02x) at PC=%04x",(mPalette[addr&0x0f].Colours.Red | (mPalette[addr&0x0f].Colours.Blue<<4)),mSystem.mCpu->GetPC());
|
|
return (mPalette[addr&0x0f].Colours.Red | (mPalette[addr&0x0f].Colours.Blue<<4));
|
|
break;
|
|
|
|
// Errors on write only register accesses
|
|
|
|
// For easier debugging
|
|
|
|
case (DISPADRL&0xff):
|
|
TRACE_MIKIE2("Peek(DISPADRL,%02x) at PC=%04x",(uint8)(mDisplayAddress&0xff),mSystem.mCpu->GetPC());
|
|
return (uint8)(mDisplayAddress&0xff);
|
|
case (DISPADRH&0xff):
|
|
TRACE_MIKIE2("Peek(DISPADRH,%02x) at PC=%04x",(uint8)(mDisplayAddress>>8)&0xff,mSystem.mCpu->GetPC());
|
|
return (uint8)(mDisplayAddress>>8)&0xff;
|
|
|
|
case (DISPCTL&0xff):
|
|
case (SYSCTL1&0xff):
|
|
case (MIKEYSREV&0xff):
|
|
case (IODIR&0xff):
|
|
case (SDONEACK&0xff):
|
|
case (CPUSLEEP&0xff):
|
|
case (PBKUP&0xff):
|
|
case (Mtest0&0xff):
|
|
case (Mtest1&0xff):
|
|
case (Mtest2&0xff):
|
|
TRACE_MIKIE2("Peek(%04x) - Peek from write only register location at PC=$%04x",addr,mSystem.mCpu->GetPC());
|
|
break;
|
|
|
|
// Register to let programs know handy is running
|
|
|
|
case (0xfd97&0xff):
|
|
TRACE_MIKIE2("Peek(%04x) - **** HANDY DETECT ATTEMPTED **** at PC=$%04x",addr,mSystem.mCpu->GetPC());
|
|
// gError->Warning("EMULATOR DETECT REGISTER HAS BEEN READ");
|
|
return 0x42;
|
|
break;
|
|
|
|
// Errors on illegal location accesses
|
|
|
|
default:
|
|
TRACE_MIKIE2("Peek(%04x) - Peek from illegal location at PC=$%04x",addr,mSystem.mCpu->GetPC());
|
|
break;
|
|
}
|
|
return 0xff;
|
|
}
|
|
|
|
|
|
void CMikie::CombobulateSound(uint32 teatime)
|
|
{
|
|
int cur_lsample = 0;
|
|
int cur_rsample = 0;
|
|
int x;
|
|
|
|
teatime >>= 2;
|
|
for(x = 0; x < 4; x++)
|
|
{
|
|
/// Assumption (seems there is no documentation for the Attenuation registers)
|
|
/// a) they are linear from $0 to $f
|
|
/// b) an attenuation of $0 is equal to channel OFF (bits in mSTEREO not set)
|
|
/// c) an attenuation of $f is equal to no attenuation (bits in PAN not set)
|
|
/// These assumptions can only checked with an oszilloscope...
|
|
/// the values stored in mSTEREO are bit-inverted ...
|
|
/// mSTEREO was found to be set like that already (why?), but unused
|
|
|
|
if(mSTEREO & (0x10 << x))
|
|
{
|
|
if(mPAN & (0x10 << x))
|
|
cur_lsample += (mAUDIO_OUTPUT[x]*(mAUDIO_ATTEN[x]&0xF0))/(15*16);
|
|
else
|
|
cur_lsample += mAUDIO_OUTPUT[x];
|
|
}
|
|
if(mSTEREO & (0x01 << x))
|
|
{
|
|
if(mPAN & (0x01 << x))
|
|
cur_rsample += (mAUDIO_OUTPUT[x]*(mAUDIO_ATTEN[x]&0x0F))/15;
|
|
else
|
|
cur_rsample += mAUDIO_OUTPUT[x];
|
|
}
|
|
}
|
|
if(cur_lsample != last_lsample)
|
|
{
|
|
miksynth.offset_inline(teatime, cur_lsample - last_lsample, mikbuf.left());
|
|
last_lsample = cur_lsample;
|
|
}
|
|
if(cur_rsample != last_rsample)
|
|
{
|
|
miksynth.offset_inline(teatime, cur_rsample - last_rsample, mikbuf.right());
|
|
last_rsample = cur_rsample;
|
|
}
|
|
}
|
|
|
|
void CMikie::CheckWrap()
|
|
{
|
|
//
|
|
// To stop problems with cycle count wrap we will check and then correct the
|
|
// cycle counter.
|
|
//
|
|
#define DEC(X) do { if((X)) { (X) -= 0x80000000; } } while (0)
|
|
|
|
if(mSystem.gSystemCycleCount>0xf0000000)
|
|
{
|
|
DEC(mSystem.gSystemCycleCount);
|
|
DEC(mTIM_0_LAST_COUNT);
|
|
DEC(mTIM_1_LAST_COUNT);
|
|
DEC(mTIM_2_LAST_COUNT);
|
|
DEC(mTIM_3_LAST_COUNT);
|
|
DEC(mTIM_4_LAST_COUNT);
|
|
DEC(mTIM_5_LAST_COUNT);
|
|
DEC(mTIM_6_LAST_COUNT);
|
|
DEC(mTIM_7_LAST_COUNT);
|
|
DEC(mAUDIO_LAST_COUNT[0]);
|
|
DEC(mAUDIO_LAST_COUNT[1]);
|
|
DEC(mAUDIO_LAST_COUNT[2]);
|
|
DEC(mAUDIO_LAST_COUNT[3]);
|
|
DEC(startTS);
|
|
DEC(mSystem.gSuzieDoneTime);
|
|
DEC(mSystem.gNextTimerEvent);
|
|
}
|
|
#undef DEC
|
|
}
|
|
|
|
void CMikie::Update()
|
|
{
|
|
int32 divide;
|
|
int32 decval;
|
|
uint32 tmp;
|
|
uint32 mikie_work_done=0;
|
|
|
|
|
|
// TRACE_MIKIE0("Update()");
|
|
|
|
mSystem.gNextTimerEvent=0xffffffff;
|
|
|
|
if(mSystem.gSuzieDoneTime)
|
|
{
|
|
if(mSystem.gSystemCycleCount >= mSystem.gSuzieDoneTime)
|
|
{
|
|
ClearCPUSleep();
|
|
mSystem.gSuzieDoneTime = 0;
|
|
}
|
|
else if(mSystem.gSuzieDoneTime > mSystem.gSystemCycleCount) mSystem.gNextTimerEvent = mSystem.gSuzieDoneTime;
|
|
}
|
|
|
|
// Timer updates, rolled out flat in group order
|
|
//
|
|
// Group A:
|
|
// Timer 0 -> Timer 2 -> Timer 4.
|
|
//
|
|
// Group B:
|
|
// Timer 1 -> Timer 3 -> Timer 5 -> Timer 7 -> Audio 0 -> Audio 1-> Audio 2 -> Audio 3 -> Timer 1.
|
|
//
|
|
|
|
//
|
|
// Within each timer code block we will predict the cycle count number of
|
|
// the next timer event
|
|
//
|
|
// We don't need to count linked timers as the timer they are linked
|
|
// from will always generate earlier events.
|
|
//
|
|
// As Timer 4 (UART) will generate many events we will ignore it
|
|
//
|
|
// We set the next event to the end of time at first and let the timers
|
|
// overload it. Any writes to timer controls will force next event to
|
|
// be immediate and hence a new preidction will be done. The prediction
|
|
// causes overflow as opposed to zero i.e. current+1
|
|
// (In reality T0 line counter should always be running.)
|
|
//
|
|
|
|
|
|
//
|
|
// Timer 0 of Group A
|
|
//
|
|
|
|
//
|
|
// Optimisation, assume T0 (Line timer) is never in one-shot,
|
|
// never placed in link mode
|
|
//
|
|
|
|
// KW bugfix 13/4/99 added (mTIM_x_ENABLE_RELOAD || ..)
|
|
// if(mTIM_0_ENABLE_COUNT && (mTIM_0_ENABLE_RELOAD || !mTIM_0_TIMER_DONE))
|
|
if(mTIM_0_ENABLE_COUNT)
|
|
{
|
|
// Timer 0 has no linking
|
|
// if(mTIM_0_LINKING!=0x07)
|
|
{
|
|
// Ordinary clocked mode as opposed to linked mode
|
|
// 16MHz clock downto 1us == cyclecount >> 4
|
|
divide=(4+mTIM_0_LINKING);
|
|
decval=(mSystem.gSystemCycleCount-mTIM_0_LAST_COUNT)>>divide;
|
|
|
|
if(decval)
|
|
{
|
|
mTIM_0_LAST_COUNT+=decval<<divide;
|
|
mTIM_0_CURRENT-=decval;
|
|
|
|
if(mTIM_0_CURRENT&0x80000000)
|
|
{
|
|
// Set carry out
|
|
mTIM_0_BORROW_OUT=TRUE;
|
|
|
|
// // Reload if neccessary
|
|
// if(mTIM_0_ENABLE_RELOAD)
|
|
// {
|
|
mTIM_0_CURRENT+=mTIM_0_BKUP+1;
|
|
// }
|
|
// else
|
|
// {
|
|
// mTIM_0_CURRENT=0;
|
|
// }
|
|
|
|
mTIM_0_TIMER_DONE=TRUE;
|
|
|
|
// Interupt flag setting code moved into DisplayRenderLine()
|
|
|
|
// Line timer has expired, render a line, we cannot incrememnt
|
|
// the global counter at this point as it will screw the other timers
|
|
// so we save under work done and inc at the end.
|
|
mikie_work_done+=DisplayRenderLine();
|
|
|
|
}
|
|
else
|
|
{
|
|
mTIM_0_BORROW_OUT=FALSE;
|
|
}
|
|
// Set carry in as we did a count
|
|
mTIM_0_BORROW_IN=TRUE;
|
|
}
|
|
else
|
|
{
|
|
// Clear carry in as we didn't count
|
|
mTIM_0_BORROW_IN=FALSE;
|
|
// Clear carry out
|
|
mTIM_0_BORROW_OUT=FALSE;
|
|
}
|
|
}
|
|
|
|
// Prediction for next timer event cycle number
|
|
|
|
// if(mTIM_0_LINKING!=7)
|
|
{
|
|
// Sometimes timeupdates can be >2x rollover in which case
|
|
// then CURRENT may still be negative and we can use it to
|
|
// calc the next timer value, we just want another update ASAP
|
|
tmp=(mTIM_0_CURRENT&0x80000000)?1:((mTIM_0_CURRENT+1)<<divide);
|
|
tmp+=mSystem.gSystemCycleCount;
|
|
if(tmp<mSystem.gNextTimerEvent)
|
|
{
|
|
mSystem.gNextTimerEvent=tmp;
|
|
// TRACE_MIKIE1("Update() - TIMER 0 Set NextTimerEvent = %012d",gNextTimerEvent);
|
|
}
|
|
}
|
|
// TRACE_MIKIE1("Update() - mTIM_0_CURRENT = %012d",mTIM_0_CURRENT);
|
|
// TRACE_MIKIE1("Update() - mTIM_0_BKUP = %012d",mTIM_0_BKUP);
|
|
// TRACE_MIKIE1("Update() - mTIM_0_LASTCNT = %012d",mTIM_0_LAST_COUNT);
|
|
// TRACE_MIKIE1("Update() - mTIM_0_LINKING = %012d",mTIM_0_LINKING);
|
|
}
|
|
|
|
//
|
|
// Timer 2 of Group A
|
|
//
|
|
|
|
//
|
|
// Optimisation, assume T2 (Frame timer) is never in one-shot
|
|
// always in linked mode i.e clocked by Line Timer
|
|
//
|
|
|
|
// KW bugfix 13/4/99 added (mTIM_x_ENABLE_RELOAD || ..)
|
|
// if(mTIM_2_ENABLE_COUNT && (mTIM_2_ENABLE_RELOAD || !mTIM_2_TIMER_DONE))
|
|
if(mTIM_2_ENABLE_COUNT)
|
|
{
|
|
decval=0;
|
|
|
|
// if(mTIM_2_LINKING==0x07)
|
|
{
|
|
if(mTIM_0_BORROW_OUT) decval=1;
|
|
mTIM_2_LAST_LINK_CARRY=mTIM_0_BORROW_OUT;
|
|
divide = 0;
|
|
}
|
|
// else
|
|
// {
|
|
// // Ordinary clocked mode as opposed to linked mode
|
|
// // 16MHz clock downto 1us == cyclecount >> 4
|
|
// divide=(4+mTIM_2_LINKING);
|
|
// decval=(gSystemCycleCount-mTIM_2_LAST_COUNT)>>divide;
|
|
// }
|
|
|
|
if(decval)
|
|
{
|
|
// mTIM_2_LAST_COUNT+=decval<<divide;
|
|
mTIM_2_CURRENT-=decval;
|
|
if(mTIM_2_CURRENT&0x80000000)
|
|
{
|
|
// Set carry out
|
|
mTIM_2_BORROW_OUT=TRUE;
|
|
|
|
// // Reload if neccessary
|
|
// if(mTIM_2_ENABLE_RELOAD)
|
|
// {
|
|
mTIM_2_CURRENT+=mTIM_2_BKUP+1;
|
|
// }
|
|
// else
|
|
// {
|
|
// mTIM_2_CURRENT=0;
|
|
// }
|
|
mTIM_2_TIMER_DONE=TRUE;
|
|
|
|
// Interupt flag setting code moved into DisplayEndOfFrame(), also
|
|
// park any CPU cycles lost for later inclusion
|
|
mikie_work_done+=DisplayEndOfFrame();
|
|
}
|
|
else
|
|
{
|
|
mTIM_2_BORROW_OUT=FALSE;
|
|
}
|
|
// Set carry in as we did a count
|
|
mTIM_2_BORROW_IN=TRUE;
|
|
}
|
|
else
|
|
{
|
|
// Clear carry in as we didn't count
|
|
mTIM_2_BORROW_IN=FALSE;
|
|
// Clear carry out
|
|
mTIM_2_BORROW_OUT=FALSE;
|
|
}
|
|
|
|
// Prediction for next timer event cycle number
|
|
// We dont need to predict this as its the frame timer and will always
|
|
// be beaten by the line timer on Timer 0
|
|
// if(mTIM_2_LINKING!=7)
|
|
// {
|
|
// tmp=gSystemCycleCount+((mTIM_2_CURRENT+1)<<divide);
|
|
// if(tmp<gNextTimerEvent) gNextTimerEvent=tmp;
|
|
// }
|
|
// TRACE_MIKIE1("Update() - mTIM_2_CURRENT = %012d",mTIM_2_CURRENT);
|
|
// TRACE_MIKIE1("Update() - mTIM_2_BKUP = %012d",mTIM_2_BKUP);
|
|
// TRACE_MIKIE1("Update() - mTIM_2_LASTCNT = %012d",mTIM_2_LAST_COUNT);
|
|
// TRACE_MIKIE1("Update() - mTIM_2_LINKING = %012d",mTIM_2_LINKING);
|
|
}
|
|
|
|
//
|
|
// Timer 4 of Group A
|
|
//
|
|
// For the sake of speed it is assumed that Timer 4 (UART timer)
|
|
// never uses one-shot mode, never uses linking, hence the code
|
|
// is commented out. Timer 4 is at the end of a chain and seems
|
|
// no reason to update its carry in-out variables
|
|
//
|
|
|
|
// KW bugfix 13/4/99 added (mTIM_x_ENABLE_RELOAD || ..)
|
|
// if(mTIM_4_ENABLE_COUNT && (mTIM_4_ENABLE_RELOAD || !mTIM_4_TIMER_DONE))
|
|
if(mTIM_4_ENABLE_COUNT)
|
|
{
|
|
decval=0;
|
|
|
|
// if(mTIM_4_LINKING==0x07)
|
|
// {
|
|
//// if(mTIM_2_BORROW_OUT && !mTIM_4_LAST_LINK_CARRY) decval=1;
|
|
// if(mTIM_2_BORROW_OUT) decval=1;
|
|
// mTIM_4_LAST_LINK_CARRY=mTIM_2_BORROW_OUT;
|
|
// }
|
|
// else
|
|
{
|
|
// Ordinary clocked mode as opposed to linked mode
|
|
// 16MHz clock downto 1us == cyclecount >> 4
|
|
// Additional /8 (+3) for 8 clocks per bit transmit
|
|
divide=4+3+mTIM_4_LINKING;
|
|
decval=(mSystem.gSystemCycleCount-mTIM_4_LAST_COUNT)>>divide;
|
|
}
|
|
|
|
if(decval)
|
|
{
|
|
mTIM_4_LAST_COUNT+=decval<<divide;
|
|
mTIM_4_CURRENT-=decval;
|
|
if(mTIM_4_CURRENT&0x80000000)
|
|
{
|
|
// Set carry out
|
|
mTIM_4_BORROW_OUT=TRUE;
|
|
|
|
//
|
|
// Update the UART counter models for Rx & Tx
|
|
//
|
|
|
|
//
|
|
// According to the docs IRQ's are level triggered and hence will always assert
|
|
// what a pain in the arse
|
|
//
|
|
// Rx & Tx are loopedback due to comlynx structure
|
|
|
|
//
|
|
// Receive
|
|
//
|
|
if(!mUART_RX_COUNTDOWN)
|
|
{
|
|
// Fetch a byte from the input queue
|
|
if(mUART_Rx_waiting>0)
|
|
{
|
|
mUART_RX_DATA=mUART_Rx_input_queue[mUART_Rx_output_ptr];
|
|
mUART_Rx_output_ptr = (mUART_Rx_output_ptr + 1) % UART_MAX_RX_QUEUE;
|
|
mUART_Rx_waiting--;
|
|
TRACE_MIKIE2("Update() - RX Byte output ptr=%02d waiting=%02d",mUART_Rx_output_ptr,mUART_Rx_waiting);
|
|
}
|
|
else
|
|
{
|
|
TRACE_MIKIE0("Update() - RX Byte but no data waiting ????");
|
|
}
|
|
|
|
// Retrigger input if more bytes waiting
|
|
if(mUART_Rx_waiting>0)
|
|
{
|
|
mUART_RX_COUNTDOWN=UART_RX_TIME_PERIOD+UART_RX_NEXT_DELAY;
|
|
TRACE_MIKIE1("Update() - RX Byte retriggered, %d waiting",mUART_Rx_waiting);
|
|
}
|
|
else
|
|
{
|
|
mUART_RX_COUNTDOWN=UART_RX_INACTIVE;
|
|
TRACE_MIKIE0("Update() - RX Byte nothing waiting, deactivated");
|
|
}
|
|
|
|
// If RX_READY already set then we have an overrun
|
|
// as previous byte hasnt been read
|
|
if(mUART_RX_READY) mUART_Rx_overun_error=1;
|
|
|
|
// Flag byte as being recvd
|
|
mUART_RX_READY=1;
|
|
}
|
|
else if(!(mUART_RX_COUNTDOWN&UART_RX_INACTIVE))
|
|
{
|
|
mUART_RX_COUNTDOWN--;
|
|
}
|
|
|
|
if(!mUART_TX_COUNTDOWN)
|
|
{
|
|
if(mUART_SENDBREAK)
|
|
{
|
|
mUART_TX_DATA=UART_BREAK_CODE;
|
|
// Auto-Respawn new transmit
|
|
mUART_TX_COUNTDOWN=UART_TX_TIME_PERIOD;
|
|
// Loop back what we transmitted
|
|
ComLynxTxLoopback(mUART_TX_DATA);
|
|
}
|
|
else
|
|
{
|
|
// Serial activity finished
|
|
mUART_TX_COUNTDOWN=UART_TX_INACTIVE;
|
|
}
|
|
|
|
// If a networking object is attached then use its callback to send the data byte.
|
|
if(mpUART_TX_CALLBACK)
|
|
{
|
|
TRACE_MIKIE0("Update() - UART_TX_CALLBACK");
|
|
(*mpUART_TX_CALLBACK)(mUART_TX_DATA,mUART_TX_CALLBACK_OBJECT);
|
|
}
|
|
|
|
}
|
|
else if(!(mUART_TX_COUNTDOWN&UART_TX_INACTIVE))
|
|
{
|
|
mUART_TX_COUNTDOWN--;
|
|
}
|
|
|
|
// Set the timer status flag
|
|
// Timer 4 is the uart timer and doesn't generate IRQ's using this method
|
|
|
|
// 16 Clocks = 1 bit transmission. Hold separate Rx & Tx counters
|
|
|
|
// Reload if neccessary
|
|
// if(mTIM_4_ENABLE_RELOAD)
|
|
// {
|
|
mTIM_4_CURRENT+=mTIM_4_BKUP+1;
|
|
// The low reload values on TIM4 coupled with a longer
|
|
// timer service delay can sometimes cause
|
|
// an underun, check and fix
|
|
if(mTIM_4_CURRENT&0x80000000)
|
|
{
|
|
mTIM_4_CURRENT=mTIM_4_BKUP;
|
|
mTIM_4_LAST_COUNT=mSystem.gSystemCycleCount;
|
|
}
|
|
// }
|
|
// else
|
|
// {
|
|
// mTIM_4_CURRENT=0;
|
|
// }
|
|
// mTIM_4_TIMER_DONE=TRUE;
|
|
}
|
|
// else
|
|
// {
|
|
// mTIM_4_BORROW_OUT=FALSE;
|
|
// }
|
|
// // Set carry in as we did a count
|
|
// mTIM_4_BORROW_IN=TRUE;
|
|
}
|
|
// else
|
|
// {
|
|
// // Clear carry in as we didn't count
|
|
// mTIM_4_BORROW_IN=FALSE;
|
|
// // Clear carry out
|
|
// mTIM_4_BORROW_OUT=FALSE;
|
|
// }
|
|
//
|
|
// // Prediction for next timer event cycle number
|
|
//
|
|
// if(mTIM_4_LINKING!=7)
|
|
// {
|
|
// Sometimes timeupdates can be >2x rollover in which case
|
|
// then CURRENT may still be negative and we can use it to
|
|
// calc the next timer value, we just want another update ASAP
|
|
tmp=(mTIM_4_CURRENT&0x80000000)?1:((mTIM_4_CURRENT+1)<<divide);
|
|
tmp+=mSystem.gSystemCycleCount;
|
|
if(tmp<mSystem.gNextTimerEvent)
|
|
{
|
|
mSystem.gNextTimerEvent=tmp;
|
|
TRACE_MIKIE1("Update() - TIMER 4 Set NextTimerEvent = %012d",gNextTimerEvent);
|
|
}
|
|
// }
|
|
// TRACE_MIKIE1("Update() - mTIM_4_CURRENT = %012d",mTIM_4_CURRENT);
|
|
// TRACE_MIKIE1("Update() - mTIM_4_BKUP = %012d",mTIM_4_BKUP);
|
|
// TRACE_MIKIE1("Update() - mTIM_4_LASTCNT = %012d",mTIM_4_LAST_COUNT);
|
|
// TRACE_MIKIE1("Update() - mTIM_4_LINKING = %012d",mTIM_4_LINKING);
|
|
}
|
|
|
|
// Emulate the UART bug where UART IRQ is level sensitive
|
|
// in that it will continue to generate interrupts as long
|
|
// as they are enabled and the interrupt condition is true
|
|
|
|
// If Tx is inactive i.e ready for a byte to eat and the
|
|
// IRQ is enabled then generate it always
|
|
if((mUART_TX_COUNTDOWN&UART_TX_INACTIVE) && mUART_TX_IRQ_ENABLE)
|
|
{
|
|
TRACE_MIKIE0("Update() - UART TX IRQ Triggered");
|
|
mTimerStatusFlags|=0x10;
|
|
}
|
|
// Is data waiting and the interrupt enabled, if so then
|
|
// what are we waiting for....
|
|
if(mUART_RX_READY && mUART_RX_IRQ_ENABLE)
|
|
{
|
|
TRACE_MIKIE0("Update() - UART RX IRQ Triggered");
|
|
mTimerStatusFlags|=0x10;
|
|
}
|
|
|
|
//
|
|
// Timer 1 of Group B
|
|
//
|
|
// KW bugfix 13/4/99 added (mTIM_x_ENABLE_RELOAD || ..)
|
|
if(mTIM_1_ENABLE_COUNT && (mTIM_1_ENABLE_RELOAD || !mTIM_1_TIMER_DONE))
|
|
{
|
|
divide = 0;
|
|
if(mTIM_1_LINKING!=0x07)
|
|
{
|
|
// Ordinary clocked mode as opposed to linked mode
|
|
// 16MHz clock downto 1us == cyclecount >> 4
|
|
divide=(4+mTIM_1_LINKING);
|
|
decval=(mSystem.gSystemCycleCount-mTIM_1_LAST_COUNT)>>divide;
|
|
|
|
if(decval)
|
|
{
|
|
mTIM_1_LAST_COUNT+=decval<<divide;
|
|
mTIM_1_CURRENT-=decval;
|
|
if(mTIM_1_CURRENT&0x80000000)
|
|
{
|
|
// Set carry out
|
|
mTIM_1_BORROW_OUT=TRUE;
|
|
|
|
// Set the timer status flag
|
|
if(mTimerInterruptMask&0x02)
|
|
{
|
|
TRACE_MIKIE0("Update() - TIMER1 IRQ Triggered");
|
|
mTimerStatusFlags|=0x02;
|
|
}
|
|
|
|
// Reload if neccessary
|
|
if(mTIM_1_ENABLE_RELOAD)
|
|
{
|
|
mTIM_1_CURRENT+=mTIM_1_BKUP+1;
|
|
}
|
|
else
|
|
{
|
|
mTIM_1_CURRENT=0;
|
|
}
|
|
mTIM_1_TIMER_DONE=TRUE;
|
|
}
|
|
else
|
|
{
|
|
mTIM_1_BORROW_OUT=FALSE;
|
|
}
|
|
// Set carry in as we did a count
|
|
mTIM_1_BORROW_IN=TRUE;
|
|
}
|
|
else
|
|
{
|
|
// Clear carry in as we didn't count
|
|
mTIM_1_BORROW_IN=FALSE;
|
|
// Clear carry out
|
|
mTIM_1_BORROW_OUT=FALSE;
|
|
}
|
|
}
|
|
|
|
// Prediction for next timer event cycle number
|
|
|
|
if(mTIM_1_LINKING!=7)
|
|
{
|
|
// Sometimes timeupdates can be >2x rollover in which case
|
|
// then CURRENT may still be negative and we can use it to
|
|
// calc the next timer value, we just want another update ASAP
|
|
tmp=(mTIM_1_CURRENT&0x80000000)?1:((mTIM_1_CURRENT+1)<<divide);
|
|
tmp+=mSystem.gSystemCycleCount;
|
|
if(tmp<mSystem.gNextTimerEvent)
|
|
{
|
|
mSystem.gNextTimerEvent=tmp;
|
|
TRACE_MIKIE1("Update() - TIMER 1 Set NextTimerEvent = %012d",gNextTimerEvent);
|
|
}
|
|
}
|
|
// TRACE_MIKIE1("Update() - mTIM_1_CURRENT = %012d",mTIM_1_CURRENT);
|
|
// TRACE_MIKIE1("Update() - mTIM_1_BKUP = %012d",mTIM_1_BKUP);
|
|
// TRACE_MIKIE1("Update() - mTIM_1_LASTCNT = %012d",mTIM_1_LAST_COUNT);
|
|
// TRACE_MIKIE1("Update() - mTIM_1_LINKING = %012d",mTIM_1_LINKING);
|
|
}
|
|
|
|
//
|
|
// Timer 3 of Group A
|
|
//
|
|
// KW bugfix 13/4/99 added (mTIM_x_ENABLE_RELOAD || ..)
|
|
if(mTIM_3_ENABLE_COUNT && (mTIM_3_ENABLE_RELOAD || !mTIM_3_TIMER_DONE))
|
|
{
|
|
decval=0;
|
|
|
|
if(mTIM_3_LINKING==0x07)
|
|
{
|
|
if(mTIM_1_BORROW_OUT) decval=1;
|
|
mTIM_3_LAST_LINK_CARRY=mTIM_1_BORROW_OUT;
|
|
divide = 0;
|
|
}
|
|
else
|
|
{
|
|
// Ordinary clocked mode as opposed to linked mode
|
|
// 16MHz clock downto 1us == cyclecount >> 4
|
|
divide=(4+mTIM_3_LINKING);
|
|
decval=(mSystem.gSystemCycleCount-mTIM_3_LAST_COUNT)>>divide;
|
|
}
|
|
|
|
if(decval)
|
|
{
|
|
mTIM_3_LAST_COUNT+=decval<<divide;
|
|
mTIM_3_CURRENT-=decval;
|
|
if(mTIM_3_CURRENT&0x80000000)
|
|
{
|
|
// Set carry out
|
|
mTIM_3_BORROW_OUT=TRUE;
|
|
|
|
// Set the timer status flag
|
|
if(mTimerInterruptMask&0x08)
|
|
{
|
|
TRACE_MIKIE0("Update() - TIMER3 IRQ Triggered");
|
|
mTimerStatusFlags|=0x08;
|
|
}
|
|
|
|
// Reload if neccessary
|
|
if(mTIM_3_ENABLE_RELOAD)
|
|
{
|
|
mTIM_3_CURRENT+=mTIM_3_BKUP+1;
|
|
}
|
|
else
|
|
{
|
|
mTIM_3_CURRENT=0;
|
|
}
|
|
mTIM_3_TIMER_DONE=TRUE;
|
|
}
|
|
else
|
|
{
|
|
mTIM_3_BORROW_OUT=FALSE;
|
|
}
|
|
// Set carry in as we did a count
|
|
mTIM_3_BORROW_IN=TRUE;
|
|
}
|
|
else
|
|
{
|
|
// Clear carry in as we didn't count
|
|
mTIM_3_BORROW_IN=FALSE;
|
|
// Clear carry out
|
|
mTIM_3_BORROW_OUT=FALSE;
|
|
}
|
|
|
|
// Prediction for next timer event cycle number
|
|
|
|
if(mTIM_3_LINKING!=7)
|
|
{
|
|
// Sometimes timeupdates can be >2x rollover in which case
|
|
// then CURRENT may still be negative and we can use it to
|
|
// calc the next timer value, we just want another update ASAP
|
|
tmp=(mTIM_3_CURRENT&0x80000000)?1:((mTIM_3_CURRENT+1)<<divide);
|
|
tmp+=mSystem.gSystemCycleCount;
|
|
if(tmp<mSystem.gNextTimerEvent)
|
|
{
|
|
mSystem.gNextTimerEvent=tmp;
|
|
TRACE_MIKIE1("Update() - TIMER 3 Set NextTimerEvent = %012d",gNextTimerEvent);
|
|
}
|
|
}
|
|
// TRACE_MIKIE1("Update() - mTIM_3_CURRENT = %012d",mTIM_3_CURRENT);
|
|
// TRACE_MIKIE1("Update() - mTIM_3_BKUP = %012d",mTIM_3_BKUP);
|
|
// TRACE_MIKIE1("Update() - mTIM_3_LASTCNT = %012d",mTIM_3_LAST_COUNT);
|
|
// TRACE_MIKIE1("Update() - mTIM_3_LINKING = %012d",mTIM_3_LINKING);
|
|
}
|
|
|
|
//
|
|
// Timer 5 of Group A
|
|
//
|
|
// KW bugfix 13/4/99 added (mTIM_x_ENABLE_RELOAD || ..)
|
|
if(mTIM_5_ENABLE_COUNT && (mTIM_5_ENABLE_RELOAD || !mTIM_5_TIMER_DONE))
|
|
{
|
|
decval=0;
|
|
|
|
if(mTIM_5_LINKING==0x07)
|
|
{
|
|
if(mTIM_3_BORROW_OUT) decval=1;
|
|
mTIM_5_LAST_LINK_CARRY=mTIM_3_BORROW_OUT;
|
|
divide = 0;
|
|
}
|
|
else
|
|
{
|
|
// Ordinary clocked mode as opposed to linked mode
|
|
// 16MHz clock downto 1us == cyclecount >> 4
|
|
divide=(4+mTIM_5_LINKING);
|
|
decval=(mSystem.gSystemCycleCount-mTIM_5_LAST_COUNT)>>divide;
|
|
}
|
|
|
|
if(decval)
|
|
{
|
|
mTIM_5_LAST_COUNT+=decval<<divide;
|
|
mTIM_5_CURRENT-=decval;
|
|
if(mTIM_5_CURRENT&0x80000000)
|
|
{
|
|
// Set carry out
|
|
mTIM_5_BORROW_OUT=TRUE;
|
|
|
|
// Set the timer status flag
|
|
if(mTimerInterruptMask&0x20)
|
|
{
|
|
TRACE_MIKIE0("Update() - TIMER5 IRQ Triggered");
|
|
mTimerStatusFlags|=0x20;
|
|
}
|
|
|
|
// Reload if neccessary
|
|
if(mTIM_5_ENABLE_RELOAD)
|
|
{
|
|
mTIM_5_CURRENT+=mTIM_5_BKUP+1;
|
|
}
|
|
else
|
|
{
|
|
mTIM_5_CURRENT=0;
|
|
}
|
|
mTIM_5_TIMER_DONE=TRUE;
|
|
}
|
|
else
|
|
{
|
|
mTIM_5_BORROW_OUT=FALSE;
|
|
}
|
|
// Set carry in as we did a count
|
|
mTIM_5_BORROW_IN=TRUE;
|
|
}
|
|
else
|
|
{
|
|
// Clear carry in as we didn't count
|
|
mTIM_5_BORROW_IN=FALSE;
|
|
// Clear carry out
|
|
mTIM_5_BORROW_OUT=FALSE;
|
|
}
|
|
|
|
// Prediction for next timer event cycle number
|
|
|
|
if(mTIM_5_LINKING!=7)
|
|
{
|
|
// Sometimes timeupdates can be >2x rollover in which case
|
|
// then CURRENT may still be negative and we can use it to
|
|
// calc the next timer value, we just want another update ASAP
|
|
tmp=(mTIM_5_CURRENT&0x80000000)?1:((mTIM_5_CURRENT+1)<<divide);
|
|
tmp+=mSystem.gSystemCycleCount;
|
|
if(tmp<mSystem.gNextTimerEvent)
|
|
{
|
|
mSystem.gNextTimerEvent=tmp;
|
|
TRACE_MIKIE1("Update() - TIMER 5 Set NextTimerEvent = %012d",gNextTimerEvent);
|
|
}
|
|
}
|
|
// TRACE_MIKIE1("Update() - mTIM_5_CURRENT = %012d",mTIM_5_CURRENT);
|
|
// TRACE_MIKIE1("Update() - mTIM_5_BKUP = %012d",mTIM_5_BKUP);
|
|
// TRACE_MIKIE1("Update() - mTIM_5_LASTCNT = %012d",mTIM_5_LAST_COUNT);
|
|
// TRACE_MIKIE1("Update() - mTIM_5_LINKING = %012d",mTIM_5_LINKING);
|
|
}
|
|
|
|
//
|
|
// Timer 7 of Group A
|
|
//
|
|
// KW bugfix 13/4/99 added (mTIM_x_ENABLE_RELOAD || ..)
|
|
if(mTIM_7_ENABLE_COUNT && (mTIM_7_ENABLE_RELOAD || !mTIM_7_TIMER_DONE))
|
|
{
|
|
decval=0;
|
|
|
|
if(mTIM_7_LINKING==0x07)
|
|
{
|
|
if(mTIM_5_BORROW_OUT) decval=1;
|
|
mTIM_7_LAST_LINK_CARRY=mTIM_5_BORROW_OUT;
|
|
divide = 0;
|
|
}
|
|
else
|
|
{
|
|
// Ordinary clocked mode as opposed to linked mode
|
|
// 16MHz clock downto 1us == cyclecount >> 4
|
|
divide=(4+mTIM_7_LINKING);
|
|
decval=(mSystem.gSystemCycleCount-mTIM_7_LAST_COUNT)>>divide;
|
|
}
|
|
|
|
if(decval)
|
|
{
|
|
mTIM_7_LAST_COUNT+=decval<<divide;
|
|
mTIM_7_CURRENT-=decval;
|
|
if(mTIM_7_CURRENT&0x80000000)
|
|
{
|
|
// Set carry out
|
|
mTIM_7_BORROW_OUT=TRUE;
|
|
|
|
// Set the timer status flag
|
|
if(mTimerInterruptMask&0x80)
|
|
{
|
|
TRACE_MIKIE0("Update() - TIMER7 IRQ Triggered");
|
|
mTimerStatusFlags|=0x80;
|
|
}
|
|
|
|
// Reload if neccessary
|
|
if(mTIM_7_ENABLE_RELOAD)
|
|
{
|
|
mTIM_7_CURRENT+=mTIM_7_BKUP+1;
|
|
}
|
|
else
|
|
{
|
|
mTIM_7_CURRENT=0;
|
|
}
|
|
mTIM_7_TIMER_DONE=TRUE;
|
|
|
|
}
|
|
else
|
|
{
|
|
mTIM_7_BORROW_OUT=FALSE;
|
|
}
|
|
// Set carry in as we did a count
|
|
mTIM_7_BORROW_IN=TRUE;
|
|
}
|
|
else
|
|
{
|
|
// Clear carry in as we didn't count
|
|
mTIM_7_BORROW_IN=FALSE;
|
|
// Clear carry out
|
|
mTIM_7_BORROW_OUT=FALSE;
|
|
}
|
|
|
|
// Prediction for next timer event cycle number
|
|
|
|
if(mTIM_7_LINKING!=7)
|
|
{
|
|
// Sometimes timeupdates can be >2x rollover in which case
|
|
// then CURRENT may still be negative and we can use it to
|
|
// calc the next timer value, we just want another update ASAP
|
|
tmp=(mTIM_7_CURRENT&0x80000000)?1:((mTIM_7_CURRENT+1)<<divide);
|
|
tmp+=mSystem.gSystemCycleCount;
|
|
if(tmp<mSystem.gNextTimerEvent)
|
|
{
|
|
mSystem.gNextTimerEvent=tmp;
|
|
TRACE_MIKIE1("Update() - TIMER 7 Set NextTimerEvent = %012d",gNextTimerEvent);
|
|
}
|
|
}
|
|
// TRACE_MIKIE1("Update() - mTIM_7_CURRENT = %012d",mTIM_7_CURRENT);
|
|
// TRACE_MIKIE1("Update() - mTIM_7_BKUP = %012d",mTIM_7_BKUP);
|
|
// TRACE_MIKIE1("Update() - mTIM_7_LASTCNT = %012d",mTIM_7_LAST_COUNT);
|
|
// TRACE_MIKIE1("Update() - mTIM_7_LINKING = %012d",mTIM_7_LINKING);
|
|
}
|
|
|
|
//
|
|
// Timer 6 has no group
|
|
//
|
|
// KW bugfix 13/4/99 added (mTIM_x_ENABLE_RELOAD || ..)
|
|
if(mTIM_6_ENABLE_COUNT && (mTIM_6_ENABLE_RELOAD || !mTIM_6_TIMER_DONE))
|
|
{
|
|
// if(mTIM_6_LINKING!=0x07)
|
|
{
|
|
// Ordinary clocked mode as opposed to linked mode
|
|
// 16MHz clock downto 1us == cyclecount >> 4
|
|
divide=(4+mTIM_6_LINKING);
|
|
decval=(mSystem.gSystemCycleCount-mTIM_6_LAST_COUNT)>>divide;
|
|
|
|
if(decval)
|
|
{
|
|
mTIM_6_LAST_COUNT+=decval<<divide;
|
|
mTIM_6_CURRENT-=decval;
|
|
if(mTIM_6_CURRENT&0x80000000)
|
|
{
|
|
// Set carry out
|
|
mTIM_6_BORROW_OUT=TRUE;
|
|
|
|
// Set the timer status flag
|
|
if(mTimerInterruptMask&0x40)
|
|
{
|
|
TRACE_MIKIE0("Update() - TIMER6 IRQ Triggered");
|
|
mTimerStatusFlags|=0x40;
|
|
}
|
|
|
|
// Reload if neccessary
|
|
if(mTIM_6_ENABLE_RELOAD)
|
|
{
|
|
mTIM_6_CURRENT+=mTIM_6_BKUP+1;
|
|
}
|
|
else
|
|
{
|
|
mTIM_6_CURRENT=0;
|
|
}
|
|
mTIM_6_TIMER_DONE=TRUE;
|
|
}
|
|
else
|
|
{
|
|
mTIM_6_BORROW_OUT=FALSE;
|
|
}
|
|
// Set carry in as we did a count
|
|
mTIM_6_BORROW_IN=TRUE;
|
|
}
|
|
else
|
|
{
|
|
// Clear carry in as we didn't count
|
|
mTIM_6_BORROW_IN=FALSE;
|
|
// Clear carry out
|
|
mTIM_6_BORROW_OUT=FALSE;
|
|
}
|
|
}
|
|
|
|
// Prediction for next timer event cycle number
|
|
// (Timer 6 doesn't support linking)
|
|
|
|
// if(mTIM_6_LINKING!=7)
|
|
{
|
|
// Sometimes timeupdates can be >2x rollover in which case
|
|
// then CURRENT may still be negative and we can use it to
|
|
// calc the next timer value, we just want another update ASAP
|
|
tmp=(mTIM_6_CURRENT&0x80000000)?1:((mTIM_6_CURRENT+1)<<divide);
|
|
tmp+=mSystem.gSystemCycleCount;
|
|
if(tmp<mSystem.gNextTimerEvent)
|
|
{
|
|
mSystem.gNextTimerEvent=tmp;
|
|
TRACE_MIKIE1("Update() - TIMER 6 Set NextTimerEvent = %012d",gNextTimerEvent);
|
|
}
|
|
}
|
|
// TRACE_MIKIE1("Update() - mTIM_6_CURRENT = %012d",mTIM_6_CURRENT);
|
|
// TRACE_MIKIE1("Update() - mTIM_6_BKUP = %012d",mTIM_6_BKUP);
|
|
// TRACE_MIKIE1("Update() - mTIM_6_LASTCNT = %012d",mTIM_6_LAST_COUNT);
|
|
// TRACE_MIKIE1("Update() - mTIM_6_LINKING = %012d",mTIM_6_LINKING);
|
|
}
|
|
|
|
//
|
|
// Update the sound subsystem
|
|
//
|
|
{
|
|
int y;
|
|
for(y = 0; y < 4; y++)
|
|
{
|
|
if(mAUDIO_ENABLE_COUNT[y] && (mAUDIO_ENABLE_RELOAD[y] || !mAUDIO_TIMER_DONE[y]))
|
|
{
|
|
decval=0;
|
|
|
|
if(mAUDIO_LINKING[y]==0x07)
|
|
{
|
|
int bort;
|
|
if(y)
|
|
bort = mAUDIO_BORROW_OUT[y - 1];
|
|
else
|
|
bort = mTIM_7_BORROW_OUT;
|
|
|
|
if(bort) decval=1;
|
|
mAUDIO_LAST_LINK_CARRY[y]=bort;
|
|
divide = 0;
|
|
}
|
|
else
|
|
{
|
|
// Ordinary clocked mode as opposed to linked mode
|
|
// 16MHz clock downto 1us == cyclecount >> 4
|
|
divide=(4+mAUDIO_LINKING[y]);
|
|
decval=(mSystem.gSystemCycleCount-mAUDIO_LAST_COUNT[y])>>divide;
|
|
}
|
|
|
|
if(decval)
|
|
{
|
|
mAUDIO_LAST_COUNT[y] += decval<<divide;
|
|
mAUDIO_CURRENT[y]-=decval;
|
|
if(mAUDIO_CURRENT[y]&0x80000000)
|
|
{
|
|
// Set carry out
|
|
mAUDIO_BORROW_OUT[y]=TRUE;
|
|
|
|
// Reload if neccessary
|
|
if(mAUDIO_ENABLE_RELOAD[y])
|
|
{
|
|
mAUDIO_CURRENT[y]+=mAUDIO_BKUP[y]+1;
|
|
if(mAUDIO_CURRENT[y]&0x80000000) mAUDIO_CURRENT[y]=0;
|
|
}
|
|
else
|
|
{
|
|
// Set timer done
|
|
mAUDIO_TIMER_DONE[y]=TRUE;
|
|
mAUDIO_CURRENT[y]=0;
|
|
}
|
|
|
|
//
|
|
// Update audio circuitry
|
|
//
|
|
if(mAUDIO_BKUP[y] || mAUDIO_LINKING[y])
|
|
mAUDIO_WAVESHAPER[y] = GetLfsrNext(mAUDIO_WAVESHAPER[y]);
|
|
|
|
if(mAUDIO_INTEGRATE_ENABLE[y])
|
|
{
|
|
int32 temp=mAUDIO_OUTPUT[y];
|
|
if(mAUDIO_WAVESHAPER[y]&0x0001) temp+=mAUDIO_VOLUME[y]; else temp-=mAUDIO_VOLUME[y];
|
|
if(temp>127) temp=127;
|
|
if(temp<-128) temp=-128;
|
|
mAUDIO_OUTPUT[y]=(int8)temp;
|
|
}
|
|
else
|
|
{
|
|
if(mAUDIO_WAVESHAPER[y]&0x0001) mAUDIO_OUTPUT[y]=mAUDIO_VOLUME[y]; else mAUDIO_OUTPUT[y]=-mAUDIO_VOLUME[y];
|
|
}
|
|
CombobulateSound(mSystem.gSystemCycleCount - startTS);
|
|
}
|
|
else
|
|
{
|
|
mAUDIO_BORROW_OUT[y]=FALSE;
|
|
}
|
|
// Set carry in as we did a count
|
|
mAUDIO_BORROW_IN[y]=TRUE;
|
|
}
|
|
else
|
|
{
|
|
// Clear carry in as we didn't count
|
|
mAUDIO_BORROW_IN[y]=FALSE;
|
|
// Clear carry out
|
|
mAUDIO_BORROW_OUT[y]=FALSE;
|
|
}
|
|
|
|
// Prediction for next timer event cycle number
|
|
|
|
if(mAUDIO_LINKING[y]!=7)
|
|
{
|
|
// Sometimes timeupdates can be >2x rollover in which case
|
|
// then CURRENT may still be negative and we can use it to
|
|
// calc the next timer value, we just want another update ASAP
|
|
tmp=(mAUDIO_CURRENT[y]&0x80000000)?1:((mAUDIO_CURRENT[y]+1)<<divide);
|
|
tmp+=mSystem.gSystemCycleCount;
|
|
if(tmp<mSystem.gNextTimerEvent)
|
|
{
|
|
mSystem.gNextTimerEvent=tmp;
|
|
TRACE_MIKIE1("Update() - AUDIO 0 Set NextTimerEvent = %012d",gNextTimerEvent);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// if(gSystemCycleCount==gNextTimerEvent) gError->Warning("CMikie::Update() - gSystemCycleCount==gNextTimerEvent, system lock likely");
|
|
// TRACE_MIKIE1("Update() - NextTimerEvent = %012d",gNextTimerEvent);
|
|
|
|
// Update system IRQ status as a result of timer activity
|
|
// OR is required to ensure serial IRQ's are not masked accidentally
|
|
|
|
mSystem.gSystemIRQ=(mTimerStatusFlags)?TRUE:FALSE;
|
|
if(mSystem.gSystemIRQ && mSystem.gSystemCPUSleep) { ClearCPUSleep(); /*puts("ARLARM"); */ }
|
|
//else if(gSuzieDoneTime) SetCPUSleep();
|
|
|
|
// Now all the timer updates are done we can increment the system
|
|
// counter for any work done within the Update() function, gSystemCycleCounter
|
|
// cannot be updated until this point otherwise it screws up the counters.
|
|
mSystem.gSystemCycleCount+=mikie_work_done;
|
|
}
|
|
|
|
SYNCFUNC(CMikie)
|
|
{
|
|
NSS(startTS);
|
|
// SSS(miksynth);
|
|
// SSS(mikbuf);
|
|
|
|
// mpDisplayCurrent;
|
|
NSS(mpDisplayCurrentLine);
|
|
NSS(framebuffer);
|
|
|
|
NSS(last_lsample);
|
|
NSS(last_rsample);
|
|
|
|
NSS(mDisplayAddress);
|
|
NSS(mAudioInputComparator);
|
|
NSS(mTimerStatusFlags);
|
|
NSS(mTimerInterruptMask);
|
|
|
|
NSS(mPalette);
|
|
NSS(mColourMap);
|
|
|
|
NSS(mIODAT);
|
|
NSS(mIODIR);
|
|
NSS(mIODAT_REST_SIGNAL);
|
|
|
|
NSS(mDISPCTL_DMAEnable);
|
|
NSS(mDISPCTL_Flip);
|
|
NSS(mDISPCTL_FourColour);
|
|
NSS(mDISPCTL_Colour);
|
|
|
|
|
|
|
|
NSS(mTIM_0_BKUP);
|
|
NSS(mTIM_0_ENABLE_RELOAD);
|
|
NSS(mTIM_0_ENABLE_COUNT);
|
|
NSS(mTIM_0_LINKING);
|
|
NSS(mTIM_0_CURRENT);
|
|
NSS(mTIM_0_TIMER_DONE);
|
|
NSS(mTIM_0_LAST_CLOCK);
|
|
NSS(mTIM_0_BORROW_IN);
|
|
NSS(mTIM_0_BORROW_OUT);
|
|
NSS(mTIM_0_LAST_LINK_CARRY);
|
|
NSS(mTIM_0_LAST_COUNT);
|
|
|
|
NSS(mTIM_1_BKUP);
|
|
NSS(mTIM_1_ENABLE_RELOAD);
|
|
NSS(mTIM_1_ENABLE_COUNT);
|
|
NSS(mTIM_1_LINKING);
|
|
NSS(mTIM_1_CURRENT);
|
|
NSS(mTIM_1_TIMER_DONE);
|
|
NSS(mTIM_1_LAST_CLOCK);
|
|
NSS(mTIM_1_BORROW_IN);
|
|
NSS(mTIM_1_BORROW_OUT);
|
|
NSS(mTIM_1_LAST_LINK_CARRY);
|
|
NSS(mTIM_1_LAST_COUNT);
|
|
|
|
NSS(mTIM_2_BKUP);
|
|
NSS(mTIM_2_ENABLE_RELOAD);
|
|
NSS(mTIM_2_ENABLE_COUNT);
|
|
NSS(mTIM_2_LINKING);
|
|
NSS(mTIM_2_CURRENT);
|
|
NSS(mTIM_2_TIMER_DONE);
|
|
NSS(mTIM_2_LAST_CLOCK);
|
|
NSS(mTIM_2_BORROW_IN);
|
|
NSS(mTIM_2_BORROW_OUT);
|
|
NSS(mTIM_2_LAST_LINK_CARRY);
|
|
NSS(mTIM_2_LAST_COUNT);
|
|
|
|
NSS(mTIM_3_BKUP);
|
|
NSS(mTIM_3_ENABLE_RELOAD);
|
|
NSS(mTIM_3_ENABLE_COUNT);
|
|
NSS(mTIM_3_LINKING);
|
|
NSS(mTIM_3_CURRENT);
|
|
NSS(mTIM_3_TIMER_DONE);
|
|
NSS(mTIM_3_LAST_CLOCK);
|
|
NSS(mTIM_3_BORROW_IN);
|
|
NSS(mTIM_3_BORROW_OUT);
|
|
NSS(mTIM_3_LAST_LINK_CARRY);
|
|
NSS(mTIM_3_LAST_COUNT);
|
|
|
|
NSS(mTIM_4_BKUP);
|
|
NSS(mTIM_4_ENABLE_RELOAD);
|
|
NSS(mTIM_4_ENABLE_COUNT);
|
|
NSS(mTIM_4_LINKING);
|
|
NSS(mTIM_4_CURRENT);
|
|
NSS(mTIM_4_TIMER_DONE);
|
|
NSS(mTIM_4_LAST_CLOCK);
|
|
NSS(mTIM_4_BORROW_IN);
|
|
NSS(mTIM_4_BORROW_OUT);
|
|
NSS(mTIM_4_LAST_LINK_CARRY);
|
|
NSS(mTIM_4_LAST_COUNT);
|
|
|
|
NSS(mTIM_5_BKUP);
|
|
NSS(mTIM_5_ENABLE_RELOAD);
|
|
NSS(mTIM_5_ENABLE_COUNT);
|
|
NSS(mTIM_5_LINKING);
|
|
NSS(mTIM_5_CURRENT);
|
|
NSS(mTIM_5_TIMER_DONE);
|
|
NSS(mTIM_5_LAST_CLOCK);
|
|
NSS(mTIM_5_BORROW_IN);
|
|
NSS(mTIM_5_BORROW_OUT);
|
|
NSS(mTIM_5_LAST_LINK_CARRY);
|
|
NSS(mTIM_5_LAST_COUNT);
|
|
|
|
NSS(mTIM_6_BKUP);
|
|
NSS(mTIM_6_ENABLE_RELOAD);
|
|
NSS(mTIM_6_ENABLE_COUNT);
|
|
NSS(mTIM_6_LINKING);
|
|
NSS(mTIM_6_CURRENT);
|
|
NSS(mTIM_6_TIMER_DONE);
|
|
NSS(mTIM_6_LAST_CLOCK);
|
|
NSS(mTIM_6_BORROW_IN);
|
|
NSS(mTIM_6_BORROW_OUT);
|
|
NSS(mTIM_6_LAST_LINK_CARRY);
|
|
NSS(mTIM_6_LAST_COUNT);
|
|
|
|
NSS(mTIM_7_BKUP);
|
|
NSS(mTIM_7_ENABLE_RELOAD);
|
|
NSS(mTIM_7_ENABLE_COUNT);
|
|
NSS(mTIM_7_LINKING);
|
|
NSS(mTIM_7_CURRENT);
|
|
NSS(mTIM_7_TIMER_DONE);
|
|
NSS(mTIM_7_LAST_CLOCK);
|
|
NSS(mTIM_7_BORROW_IN);
|
|
NSS(mTIM_7_BORROW_OUT);
|
|
NSS(mTIM_7_LAST_LINK_CARRY);
|
|
NSS(mTIM_7_LAST_COUNT);
|
|
|
|
NSS(mAUDIO_BKUP);
|
|
NSS(mAUDIO_ENABLE_RELOAD);
|
|
NSS(mAUDIO_ENABLE_COUNT);
|
|
NSS(mAUDIO_LINKING);
|
|
NSS(mAUDIO_CURRENT);
|
|
NSS(mAUDIO_TIMER_DONE);
|
|
NSS(mAUDIO_LAST_CLOCK);
|
|
NSS(mAUDIO_BORROW_IN);
|
|
NSS(mAUDIO_BORROW_OUT);
|
|
NSS(mAUDIO_LAST_LINK_CARRY);
|
|
NSS(mAUDIO_LAST_COUNT);
|
|
NSS(mAUDIO_VOLUME);
|
|
NSS(mAUDIO_INTEGRATE_ENABLE);
|
|
NSS(mAUDIO_WAVESHAPER);
|
|
|
|
NSS(mAUDIO_OUTPUT);
|
|
NSS(mAUDIO_ATTEN);
|
|
NSS(mSTEREO);
|
|
NSS(mPAN);
|
|
|
|
|
|
|
|
NSS(mUART_RX_IRQ_ENABLE);
|
|
NSS(mUART_TX_IRQ_ENABLE);
|
|
|
|
NSS(mUART_RX_COUNTDOWN);
|
|
NSS(mUART_TX_COUNTDOWN);
|
|
|
|
NSS(mUART_SENDBREAK);
|
|
NSS(mUART_TX_DATA);
|
|
NSS(mUART_RX_DATA);
|
|
NSS(mUART_RX_READY);
|
|
|
|
NSS(mUART_PARITY_ENABLE);
|
|
NSS(mUART_PARITY_EVEN);
|
|
|
|
NSS(mUART_CABLE_PRESENT);
|
|
// mpUART_TX_CALLBACK;
|
|
// mUART_TX_CALLBACK_OBJECT;
|
|
|
|
NSS(mUART_Rx_input_queue);
|
|
NSS(mUART_Rx_input_ptr);
|
|
NSS(mUART_Rx_output_ptr);
|
|
NSS(mUART_Rx_waiting);
|
|
NSS(mUART_Rx_framing_error);
|
|
NSS(mUART_Rx_overun_error);
|
|
|
|
|
|
// mpRamPointer;
|
|
NSS(mLynxLine);
|
|
NSS(mLynxLineDMACounter);
|
|
NSS(mLynxAddr);
|
|
}
|