Add samples for 32 and 64 sprite multiplexing
This commit is contained in:
parent
0742be3204
commit
864c8ec9a5
18
README.md
18
README.md
|
@ -636,7 +636,7 @@ Expands a 2D 4x4 tile grid at any scroll speed. Uses a raster IRQ to limit the
|
||||||
|
|
||||||
Sprites are independed image blocks, such as players, missiles or enemies that can be shown on top of the background.
|
Sprites are independed image blocks, such as players, missiles or enemies that can be shown on top of the background.
|
||||||
|
|
||||||
#### Control a sprite with a joy stick "joycontrol.c"
|
#### Control a sprite with a joystick "joycontrol.c"
|
||||||
|
|
||||||
Combines reading the joystick with the <c64/joystick.h> library and sprite movement with the <c64/sprites.h> library.
|
Combines reading the joystick with the <c64/joystick.h> library and sprite movement with the <c64/sprites.h> library.
|
||||||
|
|
||||||
|
@ -644,7 +644,21 @@ Combines reading the joystick with the <c64/joystick.h> library and sprite movem
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
Shows 16 virtual sprites multiplexed from the phyiscal eight sprites with raster interrupts, using the oscar sprite multiplexer library.
|
Shows 16 virtual sprites multiplexed from the physical eight sprites with raster interrupts, using the oscar sprite multiplexer library.
|
||||||
|
|
||||||
|
#### Use raster IRQ to show 32 sprites "sprmux32.c"
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Shows 32 virtual sprites multiplexed from the physical eight sprites with raster interrupts, using the oscar sprite multiplexer library. This sample requires command line defines to increase the default number of multiplexed sprites and raster interrupt slots:
|
||||||
|
|
||||||
|
oscar64 -n sprmux32.c -O2 -dVSPRITES_MAX=32 -dNUM_IRQS=28
|
||||||
|
|
||||||
|
#### Use raster IRQ to show 64 sprites "sprmux64.c"
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Shows 64 moving sprites using raster interrupts to update the position of the eight physical sprites every 25 screen lines.
|
||||||
|
|
||||||
|
|
||||||
#### Fill the screen with sprites "creditroll.c"
|
#### Fill the screen with sprites "creditroll.c"
|
||||||
|
|
|
@ -84,6 +84,16 @@ void spr_move16(char sp, int xpos, int ypos)
|
||||||
vic.spr_msbx &= ~(1 << sp);
|
vic.spr_msbx &= ~(1 << sp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int spr_posx(char sp)
|
||||||
|
{
|
||||||
|
return vic.spr_pos[sp].x | ((vic.spr_msbx & (1 << sp)) ? 256 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int spr_posy(char sp)
|
||||||
|
{
|
||||||
|
return vic.spr_pos[sp].y;
|
||||||
|
}
|
||||||
|
|
||||||
void spr_image(char sp, char image)
|
void spr_image(char sp, char image)
|
||||||
{
|
{
|
||||||
__assume (sp < 8);
|
__assume (sp < 8);
|
||||||
|
|
|
@ -19,7 +19,16 @@ inline void spr_show(char sp, bool show);
|
||||||
|
|
||||||
inline void spr_move(char sp, int xpos, int ypos);
|
inline void spr_move(char sp, int xpos, int ypos);
|
||||||
|
|
||||||
// move a sprite to the given position
|
// get current x position of sprite
|
||||||
|
|
||||||
|
inline int spr_posx(char sp);
|
||||||
|
|
||||||
|
// get current y position of sprite
|
||||||
|
|
||||||
|
inline int spr_posy(char sp);
|
||||||
|
|
||||||
|
// move a sprite to the given position, only uses 16 bit y and 16 bit x,
|
||||||
|
// moves the sprite to a zero y position if offscreen
|
||||||
void spr_move16(char sp, int xpos, int ypos);
|
void spr_move16(char sp, int xpos, int ypos);
|
||||||
|
|
||||||
// change the image of a sprite
|
// change the image of a sprite
|
||||||
|
|
|
@ -16,6 +16,11 @@ void vic_sprxy(byte s, int x, int y)
|
||||||
vic.spr_msbx &= ~(1 << s);
|
vic.spr_msbx &= ~(1 << s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int vic_sprgetx(byte s)
|
||||||
|
{
|
||||||
|
return vic.spr_pos[s].x | ((vic.spr_msbx & (1 << s)) ? 256 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
void vic_setmode(VicMode mode, char * text, char * font)
|
void vic_setmode(VicMode mode, char * text, char * font)
|
||||||
{
|
{
|
||||||
switch (mode)
|
switch (mode)
|
||||||
|
|
|
@ -97,6 +97,9 @@ void vic_setmode(VicMode mode, char * text, char * font);
|
||||||
// x MSB
|
// x MSB
|
||||||
inline void vic_sprxy(byte s, int x, int y);
|
inline void vic_sprxy(byte s, int x, int y);
|
||||||
|
|
||||||
|
// Read the sprite x position from the LSB and MSB register
|
||||||
|
inline int vic_sprgetx(byte s);
|
||||||
|
|
||||||
// wait for the beam to reach the bottom of the visual area
|
// wait for the beam to reach the bottom of the visual area
|
||||||
inline void vic_waitBottom(void);
|
inline void vic_waitBottom(void);
|
||||||
|
|
||||||
|
|
|
@ -11792,6 +11792,124 @@ bool NativeCodeBasicBlock::OptimizeXYPairUsage(void)
|
||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool NativeCodeBasicBlock::MoveAccuTrainUp(int at, int end)
|
||||||
|
{
|
||||||
|
CheckLive();
|
||||||
|
|
||||||
|
int i = at;
|
||||||
|
while (i > 0)
|
||||||
|
{
|
||||||
|
i--;
|
||||||
|
if (mIns[i].mType == ASMIT_STA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == mIns[at].mAddress)
|
||||||
|
{
|
||||||
|
if (mIns[i].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
int live = 0;
|
||||||
|
if (i > 0)
|
||||||
|
live |= mIns[i - 1].mLive;
|
||||||
|
|
||||||
|
for (int j = i; j < at; j++)
|
||||||
|
mIns[j].mLive |= mIns[end - 1].mLive;
|
||||||
|
|
||||||
|
for (int j = at; j < end; j++)
|
||||||
|
{
|
||||||
|
NativeCodeInstruction ins(mIns[j]);
|
||||||
|
ins.mLive |= live;
|
||||||
|
|
||||||
|
mIns.Remove(j);
|
||||||
|
i++;
|
||||||
|
mIns.Insert(i, ins);
|
||||||
|
}
|
||||||
|
|
||||||
|
CheckLive();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mIns[i].mType == ASMIT_JSR)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (int j = at; j < end; j++)
|
||||||
|
{
|
||||||
|
if (mIns[j].RequiresXReg() && mIns[i].ChangesXReg() || mIns[j].ChangesXReg() && mIns[i].RequiresXReg())
|
||||||
|
return false;
|
||||||
|
if (mIns[j].RequiresYReg() && mIns[i].ChangesYReg() || mIns[j].ChangesYReg() && mIns[i].RequiresYReg())
|
||||||
|
return false;
|
||||||
|
if (mIns[j].MayBeChangedOnAddress(mIns[i]) || mIns[i].MayBeChangedOnAddress(mIns[j]))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NativeCodeBasicBlock::MoveAccuTrainsUp(void)
|
||||||
|
{
|
||||||
|
bool changed = false;
|
||||||
|
|
||||||
|
if (!mVisited)
|
||||||
|
{
|
||||||
|
mVisited = true;
|
||||||
|
|
||||||
|
FastNumberSet wzero(256);
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
while (i < mIns.Size())
|
||||||
|
{
|
||||||
|
if (mIns[i].mType == ASMIT_STA && mIns[i].mMode == ASMIM_ZERO_PAGE)
|
||||||
|
{
|
||||||
|
if (mIns[i].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z))
|
||||||
|
wzero -= mIns[i].mAddress;
|
||||||
|
else
|
||||||
|
wzero += mIns[i].mAddress;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
else if (mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && wzero[mIns[i].mAddress] && !(mIns[i].mLive & LIVE_CPU_REG_C))
|
||||||
|
{
|
||||||
|
int j = i;
|
||||||
|
while (j < mIns.Size() && (mIns[j].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)) && mIns[j].mType != ASMIT_JSR)
|
||||||
|
j++;
|
||||||
|
|
||||||
|
if (j < mIns.Size() && mIns[j].mType != ASMIT_JSR)
|
||||||
|
{
|
||||||
|
j++;
|
||||||
|
if (MoveAccuTrainUp(i, j))
|
||||||
|
{
|
||||||
|
i = j + 1;
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
else if (mIns[i].mType == ASMIT_JSR)
|
||||||
|
{
|
||||||
|
wzero.Clear();
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
else if (mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].ChangesAddress())
|
||||||
|
{
|
||||||
|
wzero -= mIns[i].mAddress;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
CheckLive();
|
||||||
|
|
||||||
|
if (mTrueJump && mTrueJump->MoveAccuTrainsUp())
|
||||||
|
changed = true;
|
||||||
|
if (mFalseJump && mFalseJump->MoveAccuTrainsUp())
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
|
||||||
bool NativeCodeBasicBlock::AlternateXYUsage(void)
|
bool NativeCodeBasicBlock::AlternateXYUsage(void)
|
||||||
{
|
{
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
|
@ -13555,6 +13673,62 @@ bool NativeCodeBasicBlock::CanForwardZPMove(int saddr, int daddr, int & index) c
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool NativeCodeBasicBlock::CanChangeTailZPStoreToX(int addr, const NativeCodeBasicBlock* nblock) const
|
||||||
|
{
|
||||||
|
if (mExitRequiredRegs[CPU_REG_X])
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (mTrueJump && mTrueJump != nblock && mTrueJump->mEntryRequiredRegs[addr])
|
||||||
|
return false;
|
||||||
|
if (mFalseJump && mFalseJump != nblock && mFalseJump->mEntryRequiredRegs[addr])
|
||||||
|
return false;
|
||||||
|
|
||||||
|
int i = mIns.Size();
|
||||||
|
while (i > 0)
|
||||||
|
{
|
||||||
|
i--;
|
||||||
|
|
||||||
|
if (mIns[i].ChangesXReg())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (mIns[i].mType == ASMIT_STA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == addr)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (mIns[i].ReferencesZeroPage(addr))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mEntryBlocks.Size() == 1)
|
||||||
|
return mEntryBlocks[0]->CanChangeTailZPStoreToX(addr, this);
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NativeCodeBasicBlock::ChangeTailZPStoreToX(int addr)
|
||||||
|
{
|
||||||
|
int i = mIns.Size();
|
||||||
|
while (i > 0)
|
||||||
|
{
|
||||||
|
i--;
|
||||||
|
|
||||||
|
mIns[i].mLive |= LIVE_CPU_REG_X;
|
||||||
|
if (mIns[i].mType == ASMIT_STA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == addr)
|
||||||
|
{
|
||||||
|
mIns[i].mType = ASMIT_TAX;
|
||||||
|
mIns[i].mMode = ASMIM_IMPLIED;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mEntryBlocks.Size() == 1)
|
||||||
|
{
|
||||||
|
mEntryBlocks[0]->ChangeTailZPStoreToX(addr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool NativeCodeBasicBlock::JoinTailCodeSequences(NativeCodeProcedure* proc, bool loops)
|
bool NativeCodeBasicBlock::JoinTailCodeSequences(NativeCodeProcedure* proc, bool loops)
|
||||||
{
|
{
|
||||||
|
@ -13818,6 +13992,31 @@ bool NativeCodeBasicBlock::JoinTailCodeSequences(NativeCodeProcedure* proc, bool
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#if 1
|
||||||
|
if (mIns.Size() >= 1 && mIns[0].mType == ASMIT_LDA && mIns[0].mMode == ASMIM_ZERO_PAGE && mEntryBlocks.Size() > 1 && !(mIns[0].mLive & LIVE_MEM))
|
||||||
|
{
|
||||||
|
if (mEntryRequiredRegs.Size() > 0 && !mEntryRequiredRegs[CPU_REG_X])
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
while (i < mEntryBlocks.Size() && mEntryBlocks[i]->CanChangeTailZPStoreToX(mIns[0].mAddress, this))
|
||||||
|
i++;
|
||||||
|
if (i == mEntryBlocks.Size())
|
||||||
|
{
|
||||||
|
for (int i = 0; i < mEntryBlocks.Size(); i++)
|
||||||
|
mEntryBlocks[i]->ChangeTailZPStoreToX(mIns[0].mAddress);
|
||||||
|
mEntryProvidedRegs += CPU_REG_X;
|
||||||
|
mEntryRequiredRegs += CPU_REG_X;
|
||||||
|
mIns[0].mType = ASMIT_TXA;
|
||||||
|
mIns[0].mMode = ASMIM_IMPLIED;
|
||||||
|
changed = true;
|
||||||
|
|
||||||
|
CheckLive();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
#if 1
|
#if 1
|
||||||
if (mIns.Size() >= 1 && mIns[0].mType == ASMIT_TAX && !(mIns[0].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
|
if (mIns.Size() >= 1 && mIns[0].mType == ASMIT_TAX && !(mIns[0].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
|
||||||
{
|
{
|
||||||
|
@ -14033,6 +14232,9 @@ bool NativeCodeBasicBlock::JoinTailCodeSequences(NativeCodeProcedure* proc, bool
|
||||||
}
|
}
|
||||||
if (mFalseJump && mFalseJump->mNumEntries == 1 && mTrueJump && !mFalseJump->mFalseJump && mFalseJump->mTrueJump == mTrueJump)
|
if (mFalseJump && mFalseJump->mNumEntries == 1 && mTrueJump && !mFalseJump->mFalseJump && mFalseJump->mTrueJump == mTrueJump)
|
||||||
{
|
{
|
||||||
|
mTrueJump->CheckLive();
|
||||||
|
mFalseJump->CheckLive();
|
||||||
|
|
||||||
int s = mIns.Size(), ts = mFalseJump->mIns.Size();
|
int s = mIns.Size(), ts = mFalseJump->mIns.Size();
|
||||||
if (s > 1 && ts > 0)
|
if (s > 1 && ts > 0)
|
||||||
{
|
{
|
||||||
|
@ -14045,27 +14247,34 @@ bool NativeCodeBasicBlock::JoinTailCodeSequences(NativeCodeProcedure* proc, bool
|
||||||
mIns[s - 1].mType = ASMIT_LDY;
|
mIns[s - 1].mType = ASMIT_LDY;
|
||||||
mTrueJump->mIns.Insert(0, mIns[s - 2]);
|
mTrueJump->mIns.Insert(0, mIns[s - 2]);
|
||||||
mIns.Remove(s - 2);
|
mIns.Remove(s - 2);
|
||||||
mFalseJump->mIns.Remove(s - 1);
|
mFalseJump->mIns.Remove(ts - 1);
|
||||||
mFalseJump->mIns.Remove(0);
|
mFalseJump->mIns.Remove(0);
|
||||||
mExitRequiredRegs += CPU_REG_A;
|
mExitRequiredRegs += CPU_REG_A;
|
||||||
mFalseJump->mExitRequiredRegs += CPU_REG_A;
|
mFalseJump->mExitRequiredRegs += CPU_REG_A;
|
||||||
mTrueJump->mEntryProvidedRegs += CPU_REG_A;
|
mTrueJump->mEntryProvidedRegs += CPU_REG_A;
|
||||||
changed = true;
|
changed = true;
|
||||||
|
|
||||||
|
mTrueJump->CheckLive();
|
||||||
|
mFalseJump->CheckLive();
|
||||||
}
|
}
|
||||||
else if (!(mIns[s - 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_X)) && HasAsmInstructionMode(ASMIT_LDX, mIns[s - 1].mMode))
|
else if (!(mIns[s - 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_X)) && HasAsmInstructionMode(ASMIT_LDX, mIns[s - 1].mMode))
|
||||||
{
|
{
|
||||||
mIns[s - 1].mType = ASMIT_LDX;
|
mIns[s - 1].mType = ASMIT_LDX;
|
||||||
mTrueJump->mIns.Insert(0, mIns[s - 2]);
|
mTrueJump->mIns.Insert(0, mIns[s - 2]);
|
||||||
mIns.Remove(s - 2);
|
mIns.Remove(s - 2);
|
||||||
mFalseJump->mIns.Remove(s - 1);
|
mFalseJump->mIns.Remove(ts - 1);
|
||||||
mFalseJump->mIns.Remove(0);
|
mFalseJump->mIns.Remove(0);
|
||||||
mExitRequiredRegs += CPU_REG_A;
|
mExitRequiredRegs += CPU_REG_A;
|
||||||
mFalseJump->mExitRequiredRegs += CPU_REG_A;
|
mFalseJump->mExitRequiredRegs += CPU_REG_A;
|
||||||
mTrueJump->mEntryProvidedRegs += CPU_REG_A;
|
mTrueJump->mEntryProvidedRegs += CPU_REG_A;
|
||||||
changed = true;
|
changed = true;
|
||||||
|
|
||||||
|
mTrueJump->CheckLive();
|
||||||
|
mFalseJump->CheckLive();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#if 1
|
#if 1
|
||||||
|
@ -14099,6 +14308,8 @@ bool NativeCodeBasicBlock::JoinTailCodeSequences(NativeCodeProcedure* proc, bool
|
||||||
mFalseJump->mIns.Remove(0); mFalseJump->mIns.Remove(0);
|
mFalseJump->mIns.Remove(0); mFalseJump->mIns.Remove(0);
|
||||||
|
|
||||||
CheckLive();
|
CheckLive();
|
||||||
|
mTrueJump->CheckLive();
|
||||||
|
mFalseJump->CheckLive();
|
||||||
|
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
|
@ -14132,6 +14343,8 @@ bool NativeCodeBasicBlock::JoinTailCodeSequences(NativeCodeProcedure* proc, bool
|
||||||
mFalseJump->mIns.Remove(0); mFalseJump->mIns.Remove(0);
|
mFalseJump->mIns.Remove(0); mFalseJump->mIns.Remove(0);
|
||||||
|
|
||||||
CheckLive();
|
CheckLive();
|
||||||
|
mTrueJump->CheckLive();
|
||||||
|
mFalseJump->CheckLive();
|
||||||
|
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
|
@ -19719,7 +19932,7 @@ bool NativeCodeBasicBlock::OptimizeInnerLoop(NativeCodeProcedure* proc, NativeCo
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NativeCodeBasicBlock::CollectInnerLoop(NativeCodeBasicBlock* head, GrowingArray<NativeCodeBasicBlock*>& lblocks)
|
NativeCodeBasicBlock* NativeCodeBasicBlock::CollectInnerLoop(NativeCodeBasicBlock* head, GrowingArray<NativeCodeBasicBlock*>& lblocks)
|
||||||
{
|
{
|
||||||
if (mLoopHeadBlock != head)
|
if (mLoopHeadBlock != head)
|
||||||
{
|
{
|
||||||
|
@ -19729,37 +19942,20 @@ void NativeCodeBasicBlock::CollectInnerLoop(NativeCodeBasicBlock* head, GrowingA
|
||||||
if (mTrueJump != head && mFalseJump != head)
|
if (mTrueJump != head && mFalseJump != head)
|
||||||
{
|
{
|
||||||
if (mTrueJump)
|
if (mTrueJump)
|
||||||
mTrueJump->CollectInnerLoop(head, lblocks);
|
mLoopTailBlock = mTrueJump->CollectInnerLoop(head, lblocks);
|
||||||
if (mFalseJump)
|
|
||||||
mFalseJump->CollectInnerLoop(head, lblocks);
|
if (mLoopTailBlock && mFalseJump)
|
||||||
|
{
|
||||||
|
NativeCodeBasicBlock * tail = mFalseJump->CollectInnerLoop(head, lblocks);
|
||||||
|
if (tail != mLoopTailBlock)
|
||||||
|
mLoopTailBlock = nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
mLoopTailBlock = this;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
NativeCodeBasicBlock* NativeCodeBasicBlock::FindTailBlock(NativeCodeBasicBlock* head)
|
return mLoopTailBlock;
|
||||||
{
|
|
||||||
if (mVisiting || mVisited)
|
|
||||||
return nullptr;
|
|
||||||
else if (mTrueJump == head || mFalseJump == head)
|
|
||||||
return this;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mVisiting = true;
|
|
||||||
|
|
||||||
NativeCodeBasicBlock* tail = nullptr;
|
|
||||||
if (mTrueJump)
|
|
||||||
{
|
|
||||||
tail = mTrueJump->FindTailBlock(head);
|
|
||||||
if (tail && mFalseJump && mFalseJump->FindTailBlock(head) != tail)
|
|
||||||
tail = nullptr;
|
|
||||||
}
|
|
||||||
else if (mFalseJump)
|
|
||||||
tail = mFalseJump->FindTailBlock(head);
|
|
||||||
|
|
||||||
mVisiting = false;
|
|
||||||
|
|
||||||
return tail;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NativeCodeBasicBlock::OptimizeInnerLoops(NativeCodeProcedure* proc)
|
bool NativeCodeBasicBlock::OptimizeInnerLoops(NativeCodeProcedure* proc)
|
||||||
|
@ -19772,19 +19968,12 @@ bool NativeCodeBasicBlock::OptimizeInnerLoops(NativeCodeProcedure* proc)
|
||||||
|
|
||||||
if (mLoopHead)
|
if (mLoopHead)
|
||||||
{
|
{
|
||||||
NativeCodeBasicBlock* tail = FindTailBlock(this);
|
GrowingArray<NativeCodeBasicBlock*> lblocks(nullptr);
|
||||||
|
|
||||||
|
NativeCodeBasicBlock* tail = CollectInnerLoop(this, lblocks);
|
||||||
|
|
||||||
if (tail)
|
if (tail)
|
||||||
{
|
|
||||||
GrowingArray<NativeCodeBasicBlock*> lblocks(nullptr);
|
|
||||||
|
|
||||||
if (this == tail)
|
|
||||||
lblocks.Push(this);
|
|
||||||
else
|
|
||||||
CollectInnerLoop(this, lblocks);
|
|
||||||
|
|
||||||
changed = OptimizeInnerLoop(proc, this, tail, lblocks);
|
changed = OptimizeInnerLoop(proc, this, tail, lblocks);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CheckLive();
|
CheckLive();
|
||||||
|
@ -22476,7 +22665,7 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass
|
||||||
progress = true;
|
progress = true;
|
||||||
}
|
}
|
||||||
else if (
|
else if (
|
||||||
(mIns[i + 0].mType == ASMIT_ASL || mIns[i + 0].mType == ASMIT_LSR || mIns[i + 0].mType == ASMIT_ROL || mIns[i + 0].mType == ASMIT_ROR) && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
|
mIns[i + 0].IsShift() && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
|
||||||
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mAddress == mIns[i + 0].mAddress && !(mIns[i + 1].mLive & LIVE_MEM))
|
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mAddress == mIns[i + 0].mAddress && !(mIns[i + 1].mLive & LIVE_MEM))
|
||||||
{
|
{
|
||||||
mIns[i + 1].mType = mIns[i + 0].mType;
|
mIns[i + 1].mType = mIns[i + 0].mType;
|
||||||
|
@ -26900,6 +27089,11 @@ void NativeCodeProcedure::Optimize(void)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if _DEBUG
|
||||||
|
ResetVisited();
|
||||||
|
mEntryBlock->CheckBlocks();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#if 1
|
#if 1
|
||||||
if (step > 2 && !changed)
|
if (step > 2 && !changed)
|
||||||
|
@ -27031,6 +27225,14 @@ void NativeCodeProcedure::Optimize(void)
|
||||||
if (mEntryBlock->ApplyEntryDataSet())
|
if (mEntryBlock->ApplyEntryDataSet())
|
||||||
changed = true;
|
changed = true;
|
||||||
#endif
|
#endif
|
||||||
|
#if 1
|
||||||
|
if (step >= 4)
|
||||||
|
{
|
||||||
|
ResetVisited();
|
||||||
|
if (mEntryBlock->MoveAccuTrainsUp())
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
#if 1
|
#if 1
|
||||||
if (step == 5)
|
if (step == 5)
|
||||||
{
|
{
|
||||||
|
|
|
@ -162,7 +162,7 @@ public:
|
||||||
bool mPlaced, mCopied, mKnownShortBranch, mBypassed, mAssembled, mNoFrame, mVisited, mLoopHead, mVisiting, mLocked, mPatched, mPatchFail;
|
bool mPlaced, mCopied, mKnownShortBranch, mBypassed, mAssembled, mNoFrame, mVisited, mLoopHead, mVisiting, mLocked, mPatched, mPatchFail;
|
||||||
NativeCodeBasicBlock * mDominator, * mSameBlock;
|
NativeCodeBasicBlock * mDominator, * mSameBlock;
|
||||||
|
|
||||||
NativeCodeBasicBlock* mLoopHeadBlock;
|
NativeCodeBasicBlock* mLoopHeadBlock, * mLoopTailBlock;
|
||||||
|
|
||||||
NativeRegisterDataSet mDataSet, mNDataSet, mFDataSet;
|
NativeRegisterDataSet mDataSet, mNDataSet, mFDataSet;
|
||||||
|
|
||||||
|
@ -199,9 +199,8 @@ public:
|
||||||
|
|
||||||
bool OptimizeSelect(NativeCodeProcedure* proc);
|
bool OptimizeSelect(NativeCodeProcedure* proc);
|
||||||
|
|
||||||
NativeCodeBasicBlock* FindTailBlock(NativeCodeBasicBlock* head);
|
|
||||||
bool OptimizeInnerLoops(NativeCodeProcedure* proc);
|
bool OptimizeInnerLoops(NativeCodeProcedure* proc);
|
||||||
void CollectInnerLoop(NativeCodeBasicBlock* head, GrowingArray<NativeCodeBasicBlock*>& lblocks);
|
NativeCodeBasicBlock* CollectInnerLoop(NativeCodeBasicBlock* head, GrowingArray<NativeCodeBasicBlock*>& lblocks);
|
||||||
|
|
||||||
void PutByte(uint8 code);
|
void PutByte(uint8 code);
|
||||||
void PutWord(uint16 code);
|
void PutWord(uint16 code);
|
||||||
|
@ -345,6 +344,9 @@ public:
|
||||||
bool HasTailSTA(int& addr, int& index) const;
|
bool HasTailSTA(int& addr, int& index) const;
|
||||||
bool PropagateSinglePath(void);
|
bool PropagateSinglePath(void);
|
||||||
|
|
||||||
|
bool CanChangeTailZPStoreToX(int addr, const NativeCodeBasicBlock * nblock) const;
|
||||||
|
void ChangeTailZPStoreToX(int addr);
|
||||||
|
|
||||||
bool Check16BitSum(int at, NativeRegisterSum16Info& info);
|
bool Check16BitSum(int at, NativeRegisterSum16Info& info);
|
||||||
bool Propagate16BitSum(void);
|
bool Propagate16BitSum(void);
|
||||||
|
|
||||||
|
@ -372,6 +374,9 @@ public:
|
||||||
bool ExpandADCToBranch(NativeCodeProcedure* proc);
|
bool ExpandADCToBranch(NativeCodeProcedure* proc);
|
||||||
bool Split16BitLoopCount(NativeCodeProcedure* proc);
|
bool Split16BitLoopCount(NativeCodeProcedure* proc);
|
||||||
|
|
||||||
|
bool MoveAccuTrainUp(int at, int end);
|
||||||
|
bool MoveAccuTrainsUp(void);
|
||||||
|
|
||||||
bool AlternateXYUsage(void);
|
bool AlternateXYUsage(void);
|
||||||
bool OptimizeXYPairUsage(void);
|
bool OptimizeXYPairUsage(void);
|
||||||
bool ForwardAbsoluteLoadStores(void);
|
bool ForwardAbsoluteLoadStores(void);
|
||||||
|
|
|
@ -74,7 +74,7 @@ int main2(int argc, const char** argv)
|
||||||
|
|
||||||
#else
|
#else
|
||||||
strcpy(strProductName, "oscar64");
|
strcpy(strProductName, "oscar64");
|
||||||
strcpy(strProductVersion, "1.7.146");
|
strcpy(strProductVersion, "1.7.148");
|
||||||
|
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
uint32_t length = sizeof(basePath);
|
uint32_t length = sizeof(basePath);
|
||||||
|
|
|
@ -25,8 +25,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_NEUTRAL
|
||||||
//
|
//
|
||||||
|
|
||||||
VS_VERSION_INFO VERSIONINFO
|
VS_VERSION_INFO VERSIONINFO
|
||||||
FILEVERSION 1,7,146,0
|
FILEVERSION 1,7,148,0
|
||||||
PRODUCTVERSION 1,7,146,0
|
PRODUCTVERSION 1,7,148,0
|
||||||
FILEFLAGSMASK 0x3fL
|
FILEFLAGSMASK 0x3fL
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
FILEFLAGS 0x1L
|
FILEFLAGS 0x1L
|
||||||
|
@ -43,12 +43,12 @@ BEGIN
|
||||||
BEGIN
|
BEGIN
|
||||||
VALUE "CompanyName", "oscar64"
|
VALUE "CompanyName", "oscar64"
|
||||||
VALUE "FileDescription", "oscar64 compiler"
|
VALUE "FileDescription", "oscar64 compiler"
|
||||||
VALUE "FileVersion", "1.7.146.0"
|
VALUE "FileVersion", "1.7.148.0"
|
||||||
VALUE "InternalName", "oscar64.exe"
|
VALUE "InternalName", "oscar64.exe"
|
||||||
VALUE "LegalCopyright", "Copyright (C) 2021"
|
VALUE "LegalCopyright", "Copyright (C) 2021"
|
||||||
VALUE "OriginalFilename", "oscar64.exe"
|
VALUE "OriginalFilename", "oscar64.exe"
|
||||||
VALUE "ProductName", "oscar64"
|
VALUE "ProductName", "oscar64"
|
||||||
VALUE "ProductVersion", "1.7.146.0"
|
VALUE "ProductVersion", "1.7.148.0"
|
||||||
END
|
END
|
||||||
END
|
END
|
||||||
BLOCK "VarFileInfo"
|
BLOCK "VarFileInfo"
|
||||||
|
|
|
@ -100,6 +100,12 @@
|
||||||
}
|
}
|
||||||
"Entry"
|
"Entry"
|
||||||
{
|
{
|
||||||
|
"MsmKey" = "8:_19321EF0356047C9A6AEE738ECDEB9C3"
|
||||||
|
"OwnerKey" = "8:_UNDEFINED"
|
||||||
|
"MsmSig" = "8:_UNDEFINED"
|
||||||
|
}
|
||||||
|
"Entry"
|
||||||
|
{
|
||||||
"MsmKey" = "8:_1AAB1F90101E40B6937A64FD4BF9D469"
|
"MsmKey" = "8:_1AAB1F90101E40B6937A64FD4BF9D469"
|
||||||
"OwnerKey" = "8:_UNDEFINED"
|
"OwnerKey" = "8:_UNDEFINED"
|
||||||
"MsmSig" = "8:_UNDEFINED"
|
"MsmSig" = "8:_UNDEFINED"
|
||||||
|
@ -310,6 +316,12 @@
|
||||||
}
|
}
|
||||||
"Entry"
|
"Entry"
|
||||||
{
|
{
|
||||||
|
"MsmKey" = "8:_610F946CE11C4867B87A581F0FFD9030"
|
||||||
|
"OwnerKey" = "8:_UNDEFINED"
|
||||||
|
"MsmSig" = "8:_UNDEFINED"
|
||||||
|
}
|
||||||
|
"Entry"
|
||||||
|
{
|
||||||
"MsmKey" = "8:_636E67C8267143AA9FC128EB0AF85FC9"
|
"MsmKey" = "8:_636E67C8267143AA9FC128EB0AF85FC9"
|
||||||
"OwnerKey" = "8:_UNDEFINED"
|
"OwnerKey" = "8:_UNDEFINED"
|
||||||
"MsmSig" = "8:_UNDEFINED"
|
"MsmSig" = "8:_UNDEFINED"
|
||||||
|
@ -454,6 +466,12 @@
|
||||||
}
|
}
|
||||||
"Entry"
|
"Entry"
|
||||||
{
|
{
|
||||||
|
"MsmKey" = "8:_8CE64311B70C454D866A7E0098455EB5"
|
||||||
|
"OwnerKey" = "8:_UNDEFINED"
|
||||||
|
"MsmSig" = "8:_UNDEFINED"
|
||||||
|
}
|
||||||
|
"Entry"
|
||||||
|
{
|
||||||
"MsmKey" = "8:_94AD9BFFA9D04AA0B6BC6EEA1D9A93ED"
|
"MsmKey" = "8:_94AD9BFFA9D04AA0B6BC6EEA1D9A93ED"
|
||||||
"OwnerKey" = "8:_UNDEFINED"
|
"OwnerKey" = "8:_UNDEFINED"
|
||||||
"MsmSig" = "8:_UNDEFINED"
|
"MsmSig" = "8:_UNDEFINED"
|
||||||
|
@ -1257,6 +1275,26 @@
|
||||||
"IsDependency" = "11:FALSE"
|
"IsDependency" = "11:FALSE"
|
||||||
"IsolateTo" = "8:"
|
"IsolateTo" = "8:"
|
||||||
}
|
}
|
||||||
|
"{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_19321EF0356047C9A6AEE738ECDEB9C3"
|
||||||
|
{
|
||||||
|
"SourcePath" = "8:..\\samples\\sprites\\sprmux32.c"
|
||||||
|
"TargetName" = "8:sprmux32.c"
|
||||||
|
"Tag" = "8:"
|
||||||
|
"Folder" = "8:_A891BBCA276B4516852A6BFD884353E3"
|
||||||
|
"Condition" = "8:"
|
||||||
|
"Transitive" = "11:FALSE"
|
||||||
|
"Vital" = "11:TRUE"
|
||||||
|
"ReadOnly" = "11:FALSE"
|
||||||
|
"Hidden" = "11:FALSE"
|
||||||
|
"System" = "11:FALSE"
|
||||||
|
"Permanent" = "11:FALSE"
|
||||||
|
"SharedLegacy" = "11:FALSE"
|
||||||
|
"PackageAs" = "3:1"
|
||||||
|
"Register" = "3:1"
|
||||||
|
"Exclude" = "11:FALSE"
|
||||||
|
"IsDependency" = "11:FALSE"
|
||||||
|
"IsolateTo" = "8:"
|
||||||
|
}
|
||||||
"{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_1AAB1F90101E40B6937A64FD4BF9D469"
|
"{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_1AAB1F90101E40B6937A64FD4BF9D469"
|
||||||
{
|
{
|
||||||
"SourcePath" = "8:..\\include\\setjmp.c"
|
"SourcePath" = "8:..\\include\\setjmp.c"
|
||||||
|
@ -1957,6 +1995,26 @@
|
||||||
"IsDependency" = "11:FALSE"
|
"IsDependency" = "11:FALSE"
|
||||||
"IsolateTo" = "8:"
|
"IsolateTo" = "8:"
|
||||||
}
|
}
|
||||||
|
"{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_610F946CE11C4867B87A581F0FFD9030"
|
||||||
|
{
|
||||||
|
"SourcePath" = "8:..\\samples\\resources\\ballsprite.bin"
|
||||||
|
"TargetName" = "8:ballsprite.bin"
|
||||||
|
"Tag" = "8:"
|
||||||
|
"Folder" = "8:_758C6547998745659548D0656D380FEA"
|
||||||
|
"Condition" = "8:"
|
||||||
|
"Transitive" = "11:FALSE"
|
||||||
|
"Vital" = "11:TRUE"
|
||||||
|
"ReadOnly" = "11:FALSE"
|
||||||
|
"Hidden" = "11:FALSE"
|
||||||
|
"System" = "11:FALSE"
|
||||||
|
"Permanent" = "11:FALSE"
|
||||||
|
"SharedLegacy" = "11:FALSE"
|
||||||
|
"PackageAs" = "3:1"
|
||||||
|
"Register" = "3:1"
|
||||||
|
"Exclude" = "11:FALSE"
|
||||||
|
"IsDependency" = "11:FALSE"
|
||||||
|
"IsolateTo" = "8:"
|
||||||
|
}
|
||||||
"{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_636E67C8267143AA9FC128EB0AF85FC9"
|
"{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_636E67C8267143AA9FC128EB0AF85FC9"
|
||||||
{
|
{
|
||||||
"SourcePath" = "8:..\\include\\c64\\kernalio.h"
|
"SourcePath" = "8:..\\include\\c64\\kernalio.h"
|
||||||
|
@ -2437,6 +2495,26 @@
|
||||||
"IsDependency" = "11:FALSE"
|
"IsDependency" = "11:FALSE"
|
||||||
"IsolateTo" = "8:"
|
"IsolateTo" = "8:"
|
||||||
}
|
}
|
||||||
|
"{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_8CE64311B70C454D866A7E0098455EB5"
|
||||||
|
{
|
||||||
|
"SourcePath" = "8:..\\samples\\sprites\\sprmux64.c"
|
||||||
|
"TargetName" = "8:sprmux64.c"
|
||||||
|
"Tag" = "8:"
|
||||||
|
"Folder" = "8:_A891BBCA276B4516852A6BFD884353E3"
|
||||||
|
"Condition" = "8:"
|
||||||
|
"Transitive" = "11:FALSE"
|
||||||
|
"Vital" = "11:TRUE"
|
||||||
|
"ReadOnly" = "11:FALSE"
|
||||||
|
"Hidden" = "11:FALSE"
|
||||||
|
"System" = "11:FALSE"
|
||||||
|
"Permanent" = "11:FALSE"
|
||||||
|
"SharedLegacy" = "11:FALSE"
|
||||||
|
"PackageAs" = "3:1"
|
||||||
|
"Register" = "3:1"
|
||||||
|
"Exclude" = "11:FALSE"
|
||||||
|
"IsDependency" = "11:FALSE"
|
||||||
|
"IsolateTo" = "8:"
|
||||||
|
}
|
||||||
"{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_94AD9BFFA9D04AA0B6BC6EEA1D9A93ED"
|
"{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_94AD9BFFA9D04AA0B6BC6EEA1D9A93ED"
|
||||||
{
|
{
|
||||||
"SourcePath" = "8:..\\bin\\oscar64.bat"
|
"SourcePath" = "8:..\\bin\\oscar64.bat"
|
||||||
|
@ -4153,15 +4231,15 @@
|
||||||
{
|
{
|
||||||
"Name" = "8:Microsoft Visual Studio"
|
"Name" = "8:Microsoft Visual Studio"
|
||||||
"ProductName" = "8:oscar64"
|
"ProductName" = "8:oscar64"
|
||||||
"ProductCode" = "8:{4CED0CCC-42E5-4E78-8322-D85C2511864C}"
|
"ProductCode" = "8:{142E4BF0-B9DB-47DB-9EA2-FF3404EFD5D0}"
|
||||||
"PackageCode" = "8:{51B4E6A6-575E-4C5C-A8C9-18278CCFEB43}"
|
"PackageCode" = "8:{C2449794-2B3A-435B-9211-ED0ED63EAEB7}"
|
||||||
"UpgradeCode" = "8:{9AB61EFF-ACAC-4079-9950-8D96615CD4EF}"
|
"UpgradeCode" = "8:{9AB61EFF-ACAC-4079-9950-8D96615CD4EF}"
|
||||||
"AspNetVersion" = "8:2.0.50727.0"
|
"AspNetVersion" = "8:2.0.50727.0"
|
||||||
"RestartWWWService" = "11:FALSE"
|
"RestartWWWService" = "11:FALSE"
|
||||||
"RemovePreviousVersions" = "11:TRUE"
|
"RemovePreviousVersions" = "11:TRUE"
|
||||||
"DetectNewerInstalledVersion" = "11:TRUE"
|
"DetectNewerInstalledVersion" = "11:TRUE"
|
||||||
"InstallAllUsers" = "11:FALSE"
|
"InstallAllUsers" = "11:FALSE"
|
||||||
"ProductVersion" = "8:1.7.146"
|
"ProductVersion" = "8:1.7.148"
|
||||||
"Manufacturer" = "8:oscar64"
|
"Manufacturer" = "8:oscar64"
|
||||||
"ARPHELPTELEPHONE" = "8:"
|
"ARPHELPTELEPHONE" = "8:"
|
||||||
"ARPHELPLINK" = "8:"
|
"ARPHELPLINK" = "8:"
|
||||||
|
|
Binary file not shown.
|
@ -2,3 +2,5 @@
|
||||||
../../bin/oscar64 joycontrol.c
|
../../bin/oscar64 joycontrol.c
|
||||||
../../bin/oscar64 multiplexer.c -n
|
../../bin/oscar64 multiplexer.c -n
|
||||||
../../bin/oscar64 creditroll.c -n
|
../../bin/oscar64 creditroll.c -n
|
||||||
|
../../bin/oscar64 -n sprmux32.c -O2 -dVSPRITES_MAX=32 -dNUM_IRQS=28
|
||||||
|
../../bin/oscar64 -n sprmux64.c
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
call ..\..\bin\oscar64 joycontrol.c
|
call ..\..\bin\oscar64 joycontrol.c
|
||||||
call ..\..\bin\oscar64 multiplexer.c -n
|
call ..\..\bin\oscar64 multiplexer.c -n
|
||||||
call ..\..\bin\oscar64 creditroll.c -n
|
call ..\..\bin\oscar64 creditroll.c -n
|
||||||
|
call ..\..\bin\oscar64 -n sprmux32.c -O2 -dVSPRITES_MAX=32 -dNUM_IRQS=28
|
||||||
|
call ..\..\bin\oscar64 -n sprmux64.c
|
||||||
|
|
|
@ -0,0 +1,126 @@
|
||||||
|
#include <c64/vic.h>
|
||||||
|
#include <c64/sprites.h>
|
||||||
|
#include <c64/rasterirq.h>
|
||||||
|
#include <c64/memmap.h>
|
||||||
|
#include <c64/cia.h>
|
||||||
|
|
||||||
|
static const sbyte sintab[256] = {
|
||||||
|
0, 2, 4, 7, 9, 11, 13, 15, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 55, 57, 59, 60,
|
||||||
|
62, 64, 65, 67, 68, 70, 71, 72, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 85, 86, 87, 87, 88, 88, 89, 89, 89, 90, 90, 90, 90,
|
||||||
|
90, 90, 90, 90, 90, 89, 89, 89, 88, 88, 87, 87, 86, 85, 85, 84, 83, 82, 81, 80, 79, 78, 77, 76, 75, 74, 72, 71, 70, 68, 67, 65, 64,
|
||||||
|
62, 60, 59, 57, 55, 54, 52, 50, 48, 46, 44, 42, 40, 38, 36, 34, 32, 30, 28, 26, 24, 22, 20, 18, 15, 13, 11, 9, 7, 4, 2,
|
||||||
|
0, -2, -4, -7, -9, -11, -13, -15, -18, -20, -22, -24, -26, -28, -30, -32, -34, -36, -38, -40, -42, -44, -46, -48, -50, -52, -54, -55, -57, -59, -60,
|
||||||
|
-62, -64, -65, -67, -68, -70, -71, -72, -74, -75, -76, -77, -78, -79, -80, -81, -82, -83, -84, -85, -85, -86, -87, -87, -88, -88, -89, -89, -89, -90, -90, -90, -90,
|
||||||
|
-90, -90, -90, -90, -90, -89, -89, -89, -88, -88, -87, -87, -86, -85, -85, -84, -83, -82, -81, -80, -79, -78, -77, -76, -75, -74, -72, -71, -70, -68, -67, -65, -64,
|
||||||
|
-62, -60, -59, -57, -55, -54, -52, -50, -48, -46, -44, -42, -40, -38, -36, -34, -32, -30, -28, -26, -24, -22, -20, -18, -15, -13, -11, -9, -7, -4, -2
|
||||||
|
};
|
||||||
|
|
||||||
|
static const sbyte costab[256] = {
|
||||||
|
120, 120, 120, 120, 119, 119, 119, 118, 118, 117, 116, 116, 115, 114, 113, 112, 111, 110, 108, 107, 106, 104, 103, 101, 100, 98, 96, 95, 93, 91, 89, 87,
|
||||||
|
85, 83, 81, 78, 76, 74, 71, 69, 67, 64, 62, 59, 57, 54, 51, 49, 46, 43, 40, 38, 35, 32, 29, 26, 23, 21, 18, 15, 12, 9, 6, 3,
|
||||||
|
0, -3, -6, -9, -12, -15, -18, -21, -23, -26, -29, -32, -35, -38, -40, -43, -46, -49, -51, -54, -57, -59, -62, -64, -67, -69, -71, -74, -76, -78, -81, -83,
|
||||||
|
-85, -87, -89, -91, -93, -95, -96, -98, -100, -101, -103, -104, -106, -107, -108, -110, -111, -112, -113, -114, -115, -116, -116, -117, -118, -118, -119, -119, -119, -120, -120, -120,
|
||||||
|
-120, -120, -120, -120, -119, -119, -119, -118, -118, -117, -116, -116, -115, -114, -113, -112, -111, -110, -108, -107, -106, -104, -103, -101, -100, -98, -96, -95, -93, -91, -89, -87,
|
||||||
|
-85, -83, -81, -78, -76, -74, -71, -69, -67, -64, -62, -59, -57, -54, -51, -49, -46, -43, -40, -38, -35, -32, -29, -26, -23, -21, -18, -15, -12, -9, -6, -3,
|
||||||
|
0, 3, 6, 9, 12, 15, 18, 21, 23, 26, 29, 32, 35, 38, 40, 43, 46, 49, 51, 54, 57, 59, 62, 64, 67, 69, 71, 74, 76, 78, 81, 83,
|
||||||
|
85, 87, 89, 91, 93, 95, 96, 98, 100, 101, 103, 104, 106, 107, 108, 110, 111, 112, 113, 114, 115, 116, 116, 117, 118, 118, 119, 119, 119, 120, 120, 120
|
||||||
|
};
|
||||||
|
|
||||||
|
#define Screen ((char *)0x400)
|
||||||
|
|
||||||
|
// make space until 0x2000 for code and data
|
||||||
|
|
||||||
|
#pragma region( lower, 0x0a00, 0x2000, , , {code, data} )
|
||||||
|
|
||||||
|
// then space for our sprite data
|
||||||
|
|
||||||
|
#pragma section( spriteset, 0)
|
||||||
|
|
||||||
|
#pragma region( spriteset, 0x2000, 0x2800, , , {spriteset} )
|
||||||
|
|
||||||
|
// everything beyond will be code, data, bss and heap to the end
|
||||||
|
|
||||||
|
#pragma region( main, 0x2800, 0xa000, , , {code, data, bss, heap, stack} )
|
||||||
|
|
||||||
|
|
||||||
|
// spriteset at fixed location
|
||||||
|
|
||||||
|
#pragma data(spriteset)
|
||||||
|
|
||||||
|
static const char spriteset[2048] = {
|
||||||
|
#embed "../resources/digitsprites.bin"
|
||||||
|
};
|
||||||
|
|
||||||
|
#pragma data(data)
|
||||||
|
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
// Disable interrupts while setting up
|
||||||
|
__asm { sei };
|
||||||
|
|
||||||
|
// Kill CIA interrupts
|
||||||
|
cia_init();
|
||||||
|
|
||||||
|
mmap_set(MMAP_NO_ROM);
|
||||||
|
|
||||||
|
// enable raster interrupt via direct path
|
||||||
|
rirq_init(false);
|
||||||
|
|
||||||
|
// initialize sprite multiplexer
|
||||||
|
vspr_init(Screen);
|
||||||
|
|
||||||
|
// initalize sprites
|
||||||
|
for(char i=0; i<32; i++)
|
||||||
|
{
|
||||||
|
vspr_set(i, 30 + 8 * i, 220 - 4 * i, (unsigned)&(spriteset[0]) / 64 + (i & 15), (i & 7) + 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
// initial sort and update
|
||||||
|
vspr_sort();
|
||||||
|
vspr_update();
|
||||||
|
rirq_sort();
|
||||||
|
|
||||||
|
// start raster IRQ processing
|
||||||
|
rirq_start();
|
||||||
|
|
||||||
|
// Black screen
|
||||||
|
vic.color_border = 0;
|
||||||
|
vic.color_back = 0;
|
||||||
|
|
||||||
|
// animation loop
|
||||||
|
unsigned j = 0, t = 0;
|
||||||
|
unsigned k = 91;
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
// Use MSB as start position
|
||||||
|
j = t << 8;
|
||||||
|
|
||||||
|
// Unroll movement loop for performance
|
||||||
|
#pragma unroll(full)
|
||||||
|
for(char i=0; i<32; i++)
|
||||||
|
{
|
||||||
|
vspr_move(i, 170 + costab[((j >> 8) + 8 * i) & 255], 140 + sintab[(t + 8 * i) & 255]);
|
||||||
|
j += k;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Advance animation
|
||||||
|
t+=3;
|
||||||
|
k++;
|
||||||
|
|
||||||
|
// sort virtual sprites by y position
|
||||||
|
vspr_sort();
|
||||||
|
|
||||||
|
// wait for raster IRQ to reach and of frame
|
||||||
|
rirq_wait();
|
||||||
|
|
||||||
|
// update sprites back to normal and set up raster IRQ for sprites 8 to 31
|
||||||
|
vspr_update();
|
||||||
|
|
||||||
|
// sort raster IRQs
|
||||||
|
rirq_sort();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
Binary file not shown.
After Width: | Height: | Size: 5.8 KiB |
|
@ -0,0 +1,178 @@
|
||||||
|
#include <c64/vic.h>
|
||||||
|
#include <c64/rasterirq.h>
|
||||||
|
#include <c64/memmap.h>
|
||||||
|
#include <c64/cia.h>
|
||||||
|
|
||||||
|
static const sbyte costab[256] = {
|
||||||
|
30, 30, 30, 30, 30, 30, 30, 30, 29, 29, 29, 29, 29, 28, 28, 28, 28, 27, 27, 27, 26, 26, 26, 25, 25, 25, 24, 24, 23, 23, 22, 22,
|
||||||
|
21, 21, 20, 20, 19, 18, 18, 17, 17, 16, 15, 15, 14, 13, 13, 12, 11, 11, 10, 9, 9, 8, 7, 7, 6, 5, 4, 4, 3, 2, 1, 1,
|
||||||
|
0, -1, -1, -2, -3, -4, -4, -5, -6, -7, -7, -8, -9, -9, -10, -11, -11, -12, -13, -13, -14, -15, -15, -16, -17, -17, -18, -18, -19, -20, -20,
|
||||||
|
-21, -21, -22, -22, -23, -23, -24, -24, -25, -25, -25, -26, -26, -26, -27, -27, -27, -28, -28, -28, -28, -29, -29, -29, -29, -29, -30, -30, -30, -30, -30, -30, -30,
|
||||||
|
-30, -30, -30, -30, -30, -30, -30, -30, -29, -29, -29, -29, -29, -28, -28, -28, -28, -27, -27, -27, -26, -26, -26, -25, -25, -25, -24, -24, -23, -23, -22, -22,
|
||||||
|
-21, -21, -20, -20, -19, -18, -18, -17, -17, -16, -15, -15, -14, -13, -13, -12, -11, -11, -10, -9, -9, -8, -7, -7, -6, -5, -4, -4, -3, -2, -1, -1,
|
||||||
|
0, 1, 1, 2, 3, 4, 4, 5, 6, 7, 7, 8, 9, 9, 10, 11, 11, 12, 13, 13, 14, 15, 15, 16, 17, 17, 18, 18, 19, 20, 20,
|
||||||
|
21, 21, 22, 22, 23, 23, 24, 24, 25, 25, 25, 26, 26, 26, 27, 27, 27, 28, 28, 28, 28, 29, 29, 29, 29, 29, 30, 30, 30, 30, 30, 30, 30
|
||||||
|
};
|
||||||
|
|
||||||
|
#define Screen ((char *)0x400)
|
||||||
|
|
||||||
|
// make space until 0x2000 for code and data
|
||||||
|
|
||||||
|
#pragma region( lower, 0x0a00, 0x2000, , , {code, data} )
|
||||||
|
|
||||||
|
// then space for our sprite data
|
||||||
|
|
||||||
|
#pragma section( spriteset, 0)
|
||||||
|
|
||||||
|
#pragma region( spriteset, 0x2000, 0x2040, , , {spriteset} )
|
||||||
|
|
||||||
|
// everything beyond will be code, data, bss and heap to the end
|
||||||
|
|
||||||
|
#pragma region( main, 0x2800, 0xa000, , , {code, data, bss, heap, stack} )
|
||||||
|
|
||||||
|
|
||||||
|
// spriteset at fixed location
|
||||||
|
|
||||||
|
#pragma data(spriteset)
|
||||||
|
|
||||||
|
__export const char spriteset[64] = {
|
||||||
|
#embed "../resources/ballsprite.bin"
|
||||||
|
};
|
||||||
|
|
||||||
|
#pragma data(data)
|
||||||
|
|
||||||
|
// Control variables for the interrupt
|
||||||
|
|
||||||
|
char pphase; // global phase
|
||||||
|
char poffset; // phase offset for this row of sprites
|
||||||
|
char yoffset; // vertical offset for this row of sprites
|
||||||
|
|
||||||
|
// Interrupt routine switching to next row of sprites, invokes some lines after
|
||||||
|
// start of previous row
|
||||||
|
|
||||||
|
__interrupt void setspr(void)
|
||||||
|
{
|
||||||
|
// Switch vertical position first, will not take effect
|
||||||
|
// until after the current row of sprites is complete, so it
|
||||||
|
// is done first
|
||||||
|
#pragma unroll(full)
|
||||||
|
for(char i=0; i<8; i++)
|
||||||
|
vic.spr_pos[i].y = yoffset;
|
||||||
|
|
||||||
|
char phase = pphase + poffset; // Effective rotation phase for this row
|
||||||
|
int step = costab[phase]; // 30 * Cosine of phase for x step
|
||||||
|
int xpos0 = 172 - (step >> 1); // Half a step to the left
|
||||||
|
int xpos1 = 172 + (step >> 1); // Half a step to the right
|
||||||
|
|
||||||
|
// Table for xpositions
|
||||||
|
static unsigned xp[8];
|
||||||
|
|
||||||
|
// Calculate xpositions, four to the left and four to the right
|
||||||
|
#pragma unroll(full)
|
||||||
|
for(char i=0; i<4; i++)
|
||||||
|
{
|
||||||
|
xp[3 - i] = xpos0;
|
||||||
|
xp[i + 4] = xpos1;
|
||||||
|
|
||||||
|
// Stepping left and right
|
||||||
|
xpos0 -= step;
|
||||||
|
xpos1 += step;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for end of current sprite, xpos will take effect
|
||||||
|
// at start of line, so we need to patch it after the last
|
||||||
|
// pixel line has started
|
||||||
|
vic_waitLine(yoffset - 4);
|
||||||
|
|
||||||
|
// Left to right or right to left to get a matching z order
|
||||||
|
if (phase & 0x80)
|
||||||
|
{
|
||||||
|
// MSB mask
|
||||||
|
char xymask = 0;
|
||||||
|
|
||||||
|
// Update all sprite x LSB and color, put MSB into
|
||||||
|
// xymask bit
|
||||||
|
#pragma unroll(full)
|
||||||
|
for(char i=0; i<8; i++)
|
||||||
|
{
|
||||||
|
xymask = ((unsigned)xymask | (xp[i] & 0xff00)) >> 1;
|
||||||
|
vic.spr_pos[i].x = xp[i];
|
||||||
|
vic.spr_color[i] = VCOL_ORANGE + i;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update MSB
|
||||||
|
vic.spr_msbx = xymask;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
char xymask = 0;
|
||||||
|
|
||||||
|
// Update all sprite x LSB and color, put MSB into
|
||||||
|
// xymask bit
|
||||||
|
|
||||||
|
#pragma unroll(full)
|
||||||
|
for(char i=0; i<8; i++)
|
||||||
|
{
|
||||||
|
xymask = ((unsigned)xymask | (xp[7 - i] & 0xff00)) >> 1;
|
||||||
|
vic.spr_pos[i].x = xp[7 - i];
|
||||||
|
vic.spr_color[i] = VCOL_ORANGE + (7 - i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update MSB
|
||||||
|
vic.spr_msbx = xymask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Eight raster interrupts
|
||||||
|
RIRQCode spmux[8];
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
// Keep kernal alive
|
||||||
|
rirq_init(true);
|
||||||
|
|
||||||
|
// Setup sprite images
|
||||||
|
for(char i=0; i<8; i++)
|
||||||
|
Screen[0x03f8 + i] = 128;
|
||||||
|
|
||||||
|
// Remaining sprite registers
|
||||||
|
vic.spr_enable = 0xff;
|
||||||
|
vic.spr_multi = 0xff;
|
||||||
|
vic.spr_expand_x = 0x00;
|
||||||
|
vic.spr_expand_y = 0x00;
|
||||||
|
vic.spr_mcolor0 = VCOL_BLACK;
|
||||||
|
vic.spr_mcolor1 = VCOL_WHITE;
|
||||||
|
|
||||||
|
// Setup raster interrupts
|
||||||
|
for(char i=0; i<8; i++)
|
||||||
|
{
|
||||||
|
// Three operations per interrupt
|
||||||
|
rirq_build(spmux + i, 3);
|
||||||
|
// Store phase offset
|
||||||
|
rirq_write(spmux + i, 0, &poffset, 11 * i);
|
||||||
|
// Store vertical position
|
||||||
|
rirq_write(spmux + i, 1, &yoffset, 52 + 25 * i);
|
||||||
|
// Call sprite update function
|
||||||
|
rirq_call(spmux + i, 2, setspr);
|
||||||
|
|
||||||
|
// Place raster interrupt 16 lines before sprite start to
|
||||||
|
// give it enough time for procesing
|
||||||
|
rirq_set(i, 36 + 25 * i, spmux + i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort interrupts and start processing
|
||||||
|
rirq_sort();
|
||||||
|
rirq_start();
|
||||||
|
|
||||||
|
// Forever
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
// Advance phase
|
||||||
|
pphase += 5;
|
||||||
|
|
||||||
|
// Wait for next frame
|
||||||
|
vic_waitFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
Binary file not shown.
After Width: | Height: | Size: 7.2 KiB |
Loading…
Reference in New Issue