Add samples for 32 and 64 sprite multiplexing

This commit is contained in:
drmortalwombat 2022-07-18 21:22:12 +02:00
parent 0742be3204
commit 864c8ec9a5
17 changed files with 690 additions and 56 deletions

View File

@ -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
![Large text](samples/sprites/multiplexer.png) ![Large text](samples/sprites/multiplexer.png)
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"
![Large text](samples/sprites/sprmux32.png)
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"
![Large text](samples/sprites/sprmux64.png)
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"

View File

@ -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);

View File

@ -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

View File

@ -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)

View File

@ -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);

View File

@ -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)
{ {

View File

@ -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);

View File

@ -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);

View File

@ -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"

View File

@ -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.

View File

@ -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

View File

@ -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

126
samples/sprites/sprmux32.c Normal file
View File

@ -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

178
samples/sprites/sprmux64.c Normal file
View File

@ -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