Fix crash in optimizer when declaring too many unused local variables

This commit is contained in:
drmortalwombat 2022-12-06 15:55:31 +01:00
parent 8b631d564e
commit f56fb9e505
15 changed files with 1047 additions and 19 deletions

View File

@ -672,6 +672,23 @@ Draws filled random circles and fills the space using flood fill.
Similar to its hires counterpart but using four shades of grey.
### Particle systems "particles"
Active hires graphics using particle system
#### Hires fireworks "fireworks_hires.c"
Simple hires particle system using velocity and gravity integration.
#### Multicolor fireworks "fireworks_ptr.c"
Simple multi color hires particle system using velocity and gravity integration.
#### Fireworks with striped memory layout "fireworks_stripe.c"
Simple multi color hires particle system using velocity and gravity integration. This version uses striped memory layout for the particles to simplify addressing for the CPU.
### Mandelbrot renderer "fractals"
Various versions of the mandelbrot set using float arithmetic.
@ -694,6 +711,10 @@ Multi color version using pure and mixed colors.
Mandelbrot rendered in 3D with shading. The image is drawn in columns from back to front, using two adjacent columns to calculate slope and brightness.
#### Interactive Navigate a fractal "mbzoom.c"
Navigate using WASD and zoom using + and -.
### Raster beam interrupts "rasterirq"

View File

@ -8792,24 +8792,24 @@ void InterCodeBasicBlock::MarkRelevantStatics(void)
if (ins->mCode == IC_LOAD)
{
if (ins->mSrc[0].mTemp < 0 && ins->mSrc[0].mMemory == IM_GLOBAL)
ins->mSrc[0].mLinkerObject->mFlags |= LOBJF_RELEVANT;
ins->mSrc[0].mLinkerObject->MarkRelevant();
}
else if (ins->mCode == IC_LEA)
{
if (ins->mSrc[1].mTemp < 0 && ins->mSrc[1].mMemory == IM_GLOBAL)
ins->mSrc[1].mLinkerObject->mFlags |= LOBJF_RELEVANT;
ins->mSrc[1].mLinkerObject->MarkRelevant();
}
else if (ins->mCode == IC_CONSTANT && ins->mDst.mType == IT_POINTER)
{
if (ins->mConst.mMemory == IM_GLOBAL)
ins->mConst.mLinkerObject->mFlags |= LOBJF_RELEVANT;
ins->mConst.mLinkerObject->MarkRelevant();
}
else if (ins->mCode == IC_COPY || ins->mCode == IC_STRCPY)
{
if (ins->mSrc[0].mTemp < 0 && ins->mSrc[0].mMemory == IM_GLOBAL)
ins->mSrc[0].mLinkerObject->mFlags |= LOBJF_RELEVANT;
ins->mSrc[0].mLinkerObject->MarkRelevant();
if (ins->mSrc[1].mTemp < 0 && ins->mSrc[1].mMemory == IM_GLOBAL)
ins->mSrc[1].mLinkerObject->mFlags |= LOBJF_RELEVANT;
ins->mSrc[1].mLinkerObject->MarkRelevant();
}
}
@ -13018,12 +13018,12 @@ void InterCodeProcedure::RemoveUnusedStoreInstructions(InterMemory paramMemory)
{
if (mLocalVars.Size() > 0 || mParamVars.Size() > 0)
{
for (int i = 0; i < mLocalVars.Size(); i++)
for (int i = 0; i < mLocalAliasedSet.Size(); i++)
{
if (mLocalAliasedSet[i])
mLocalVars[i]->mAliased = true;
}
for (int i = 0; i < mParamVars.Size(); i++)
for (int i = 0; i < mParamAliasedSet.Size(); i++)
{
if (mParamAliasedSet[i])
mParamVars[i]->mAliased = true;

View File

@ -43,6 +43,17 @@ void LinkerObject::AddReference(const LinkerReference& ref)
mReferences.Push(nref);
}
void LinkerObject::MarkRelevant(void)
{
if (!(mFlags & LOBJF_RELEVANT))
{
mFlags |= LOBJF_RELEVANT;
for (int i = 0; i < mReferences.Size(); i++)
if (mReferences[i]->mRefObject)
mReferences[i]->mRefObject->MarkRelevant();
}
}
void LinkerObject::MoveToSection(LinkerSection* section)
{
if (section != mSection)

View File

@ -167,6 +167,8 @@ public:
void AddReference(const LinkerReference& ref);
void MoveToSection(LinkerSection* section);
void MarkRelevant(void);
};
class Linker

View File

@ -3038,9 +3038,16 @@ bool NativeCodeInstruction::ValueForwarding(NativeRegisterDataSet& data, AsmInsT
#if 1
if (mMode == ASMIM_ABSOLUTE_X && data.mRegs[CPU_REG_X].SameData(data.mRegs[CPU_REG_Y]) && HasAsmInstructionMode(mType, ASMIM_ABSOLUTE_Y) && !(mFlags & NICT_INDEXFLIPPED))
{
mFlags |= NICT_INDEXFLIPPED;
mMode = ASMIM_ABSOLUTE_Y;
changed = true;
}
else if (mMode == ASMIM_ABSOLUTE_Y && data.mRegs[CPU_REG_X].SameData(data.mRegs[CPU_REG_Y]) && HasAsmInstructionMode(mType, ASMIM_ABSOLUTE_X) && !(mFlags & NICT_INDEXFLIPPED))
{
mFlags |= NICT_INDEXFLIPPED;
mMode = ASMIM_ABSOLUTE_X;
changed = true;
}
#endif
if (mMode == ASMIM_ZERO_PAGE)
{
@ -20966,6 +20973,23 @@ bool NativeCodeBasicBlock::ValueForwarding(const NativeRegisterDataSet& data, bo
{
AsmInsType carryop;
#if 1
if (mIns[i].mMode == ASMIM_INDIRECT_Y && HasAsmInstructionMode(mIns[i].mType, ASMIM_ABSOLUTE_Y) &&
mNDataSet.mRegs[CPU_REG_Y].mMode == NRDM_IMMEDIATE &&
mNDataSet.mRegs[mIns[i].mAddress + 1].mMode == NRDM_IMMEDIATE_ADDRESS && (mNDataSet.mRegs[mIns[i].mAddress + 1].mFlags & NCIF_UPPER) &&
mNDataSet.mRegs[mIns[i].mAddress].mMode != NRDM_IMMEDIATE_ADDRESS)
{
int reg = mIns[i].mAddress;
mIns.Insert(i, NativeCodeInstruction(ASMIT_LDY, ASMIM_ZERO_PAGE, reg));
mIns[i + 1].mMode = ASMIM_ABSOLUTE_Y;
mIns[i + 1].mLinkerObject = mNDataSet.mRegs[reg + 1].mLinkerObject;
mIns[i + 1].mAddress = mNDataSet.mRegs[reg + 1].mValue + mNDataSet.mRegs[CPU_REG_Y].mValue;
mIns[i + 1].mFlags |= NCIF_LOWER;
mIns.Insert(i + 2, NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, mNDataSet.mRegs[CPU_REG_Y].mValue));
mIns.Insert(i + 3, NativeCodeInstruction(ASMIT_ORA, ASMIM_IMMEDIATE, 0));
changed = true;
}
#endif
// Check load and commutative with current accu value
#if 1
if (i + 1 < mIns.Size() && mIns[i].mType == ASMIT_LDA && mIns[i + 1].IsCommutative() && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mNDataSet.mRegs[CPU_REG_A].mMode == NRDM_ZERO_PAGE && mNDataSet.mRegs[CPU_REG_A].mValue == mIns[i + 1].mAddress)
@ -29339,21 +29363,19 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass
}
#endif
#if 1
else if (
mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[i + 1].mFlags & NCIF_UPPER) &&
mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
!(mIns[i + 1].mLive & LIVE_CPU_REG_A))
}
if (i + 1 < mIns.Size() &&
mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[i + 0].mFlags & NCIF_UPPER) &&
mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE)
{
proc->ResetPatched();
if (CheckGlobalAddressSumYPointer(this, mIns[i + 1].mAddress - 1, mIns[i + 1].mAddress - 1, i + 2, -1))
{
proc->ResetPatched();
if (CheckGlobalAddressSumYPointer(this, mIns[i + 1].mAddress - 1, mIns[i + 1].mAddress - 1, i + 2, -1))
{
proc->ResetPatched();
if (PatchGlobalAddressSumYPointer(this, mIns[i + 1].mAddress - 1, mIns[i + 1].mAddress - 1, i + 2, -1, mIns[i + 0].mLinkerObject, mIns[i + 0].mAddress))
progress = true;
}
if (PatchGlobalAddressSumYPointer(this, mIns[i + 1].mAddress - 1, mIns[i + 1].mAddress - 1, i + 2, -1, mIns[i + 0].mLinkerObject, mIns[i + 0].mAddress))
progress = true;
}
#endif
}
if (i + 5 < mIns.Size() &&

View File

@ -15,6 +15,10 @@ cd hiresmc
./build.sh
cd ..
cd particles
./build.sh
cd ..
cd kernalio
./build.sh
cd ..

View File

@ -4,4 +4,5 @@
../../bin/oscar64 mbmulti.c -n
../../bin/oscar64 mbmulti3d.c -n
../../bin/oscar64 mbfixed.c -n -O3
../../bin/oscar64 mbzoom.c -n -O3

View File

@ -3,3 +3,4 @@ call ..\..\bin\oscar64 mbhires.c -n
call ..\..\bin\oscar64 mbmulti.c -n
call ..\..\bin\oscar64 mbmulti3d.c -n
call ..\..\bin\oscar64 mbfixed.c -n -O3
call ..\..\bin\oscar64 mbzoom.c -n -O3

293
samples/fractals/mbzoom.c Normal file
View File

@ -0,0 +1,293 @@
#include <string.h>
#include <conio.h>
#include <c64/vic.h>
#define Screen ((char *)0x0400)
#define Color ((char *)0xd800)
// Lookup table for squares from 0..255
__striped unsigned sqb[256];
#pragma align(sqb, 256);
// Square an unsigned int into an unsigned long
inline unsigned long ssquare(unsigned x)
{
// Split into low byte and highbyte, so we have x = a + 0x100 * b
unsigned a = x & 0xff;
unsigned b = x >> 8;
// So now we calculate (a + 0x100 * b)²
// Result will be a² + 0x100 * 2 * a * b + 0x10000 * b²
// with 2 * a * b == (a + b)² - a² - b²
// We can cover all cases with the square table except if a + b >= 0x100
// in this case we have abp := a + b - 0x100
// (abp + 0x100)² == abp² + 2 * 0x100 * abp + 0x10000
// Get squares of the bytes and the sum of the bytes
unsigned a2 = sqb[a], b2 = sqb[b];
unsigned apb = a + b;
// First approximation approximation
// a² + 0x10000 * b²
unsigned long sum = a2 + ((unsigned long)b2 << 16);
// Check if a + b >= 0x100
if (apb & 0xff00)
{
apb &= 0xff;
sum += 0x1000000UL;
sum += (unsigned long)apb << 17;
sum += (unsigned long)sqb[apb] << 8;
}
else
{
apb &= 0xff;
sum += (unsigned long)sqb[apb] << 8;
}
// Now w have a² + 0x1000 * b² + (a + b)²
sum -= (unsigned long)a2 << 8;
sum -= (unsigned long)b2 << 8;
// And finaly the complete result
return sum;
}
// Signed square of x
inline long sq(int x)
{
if (x < 0)
x = -x;
return ssquare(x);
}
// Colors to fill in the different levels
static const char colors[32] = {
VCOL_BLUE,
VCOL_LT_BLUE,
VCOL_WHITE,
VCOL_LT_GREEN,
VCOL_GREEN,
VCOL_YELLOW,
VCOL_ORANGE,
VCOL_RED,
VCOL_PURPLE,
VCOL_BLUE,
VCOL_BLUE,
VCOL_LT_BLUE,
VCOL_LT_BLUE,
VCOL_WHITE,
VCOL_WHITE,
VCOL_LT_GREEN,
VCOL_LT_GREEN,
VCOL_GREEN,
VCOL_GREEN,
VCOL_YELLOW,
VCOL_YELLOW,
VCOL_ORANGE,
VCOL_ORANGE,
VCOL_RED,
VCOL_RED,
VCOL_PURPLE,
VCOL_PURPLE,
VCOL_LT_GREY,
VCOL_LT_GREY,
VCOL_MED_GREY,
VCOL_MED_GREY,
VCOL_DARK_GREY,
};
// Return color for a given coordinate in the complex plane using
// 12.4bit fixed numbers using m'=m²+b
inline char fcolor(int xz, int yz)
{
// Start value for iteration is the offset value itself
int x = xz, y = yz;
// Iterate up to 32 steps
for(int i=0; i<32; i++)
{
// Build squares of real and imaginery component
long xx = sq(x), yy = sq(y), xxyy = sq(x + y);
// Use squares to check for exit condition of sure
// to proress towards infinity
if (xx + yy >= 4L * 4096 * 4096) return colors[i];
// Next iteration values using complex artithmetic
// Mx' = Mx² - My² + Bx
// My' = 2 * Mx * My + By = (Mx + My)² - Mx² - My² + By
x = ((xx - yy + 2048) >> 12) + xz;
y = ((xxyy - xx - yy + 2048) >> 12) + yz;
}
// More than maximum number of iterations, so assume progress
// towards zero
return VCOL_BLACK;
}
// Fill a row with color
void fill_row(char py, int cix, int yz, int cis)
{
int xz = cix;
for(int px=0; px<40; px++)
{
Color[py * 40 + px] = fcolor(xz, yz);
xz += cis;
}
}
// Fill a column with color
void fill_column(char px, int xz, int ciy, int cis)
{
int yz = ciy;
for(int py=0; py<25; py++)
{
Color[py * 40 + px] = fcolor(xz, yz);
yz += cis;
}
}
// Fill the complete image
void fill_image(int cix, int ciy, int cis)
{
int yz = ciy;
for(int py=0; py<25; py++)
{
fill_row(py, cix, yz, cis);
yz += cis;
}
}
// Scroll screen to the left
void scroll_left(void)
{
for(char x=0; x<39; x++)
{
#pragma unroll(full)
for(char y=0; y<25; y++)
{
Color[y * 40 + x] = Color[y * 40 + x + 1];
}
}
}
// Scroll screen to the right
void scroll_right(void)
{
for(signed char x=38; x>=0; x--)
{
#pragma unroll(full)
for(char y=0; y<25; y++)
{
Color[y * 40 + x + 1] = Color[y * 40 + x];
}
}
}
// Scroll screen up
void scroll_up(void)
{
for(char x=0; x<40; x++)
{
#pragma unroll(full)
for(char y=0; y<24; y++)
{
Color[y * 40 + x] = Color[(y + 1) * 40 + x];
}
}
}
// Scroll screen down
void scroll_down(void)
{
for(char x=0; x<40; x++)
{
#pragma unroll(full)
for(char y=0; y<24; y++)
{
Color[(24 - y) * 40 + x] = Color[(23 - y) * 40 + x];
}
}
}
int main(void)
{
// Initialize square table
for(unsigned i=0; i<256; i++)
sqb[i] = i * i;
// Clear screen
memset(Screen, 160, 1024);
// Start coordinates in float
float cx = -0.4;
float cy = 0.0;
float cw = 3.2;
// Convert to top, left and step in 12.4 fixed point
int cix = (int)((cx - 0.5 * cw) * 4096);
int ciy = (int)((cy - 12.0 * cw / 40.0) * 4096);
int cis = (int)(cw / 40.0 * 4096);
// Initial image
fill_image(cix, ciy, cis);
for(;;)
{
// Wait for keypress
char ch = getch();
switch (ch)
{
case 'S':
ciy += cis;
scroll_up();
fill_row(24, cix, ciy + 24 * cis, cis);
break;
case 'W':
ciy -= cis;
scroll_down();
fill_row(0, cix, ciy, cis);
break;
case 'A':
cix -= cis;
scroll_right();
fill_column(0, cix, ciy, cis);
break;
case 'D':
cix += cis;
scroll_left();
fill_column(39, cix + 39 * cis, ciy, cis);
break;
case '+':
cix += 20 * cis;
ciy += 12 * cis;
cis = cis * 2 / 3;
cix -= 20 * cis;
ciy -= 12 * cis;
fill_image(cix, ciy, cis);
break;
case '-':
cix += 20 * cis;
ciy += 12 * cis;
cis = cis * 3 / 2;
cix -= 20 * cis;
ciy -= 12 * cis;
fill_image(cix, ciy, cis);
break;
}
}
return 0;
}

View File

@ -14,6 +14,10 @@ cd hiresmc
call make.bat
cd ..
cd particles
call make.bat
cd ..
cd kernalio
call make.bat
cd ..

View File

@ -0,0 +1,5 @@
#!/bin/sh
../../bin/oscar64 -n fireworks_ptr.c
../../bin/oscar64 -n fireworks_hires.c
../../bin/oscar64 -n fireworks_stripe.c

View File

@ -0,0 +1,215 @@
#include <c64/vic.h>
#include <c64/memmap.h>
#include <string.h>
#include <stdlib.h>
static char * const Screen = (char *)0xc800;
static char * const Color = (char *)0xd800;
static char * const Hires = (char *)0xe000;
// Single particle, with position and veloicty, using a next
// pointer for single linked list
struct Particle
{
int px, py, vx, vy;
Particle * next;
};
// Storage for up to 256 particles
Particle particles[256];
// Heads of used and free list
Particle * pfirst, * pfree;
// Lookup table for hires row buffer
static char * Hirows[25];
// Pixel masks
static const char setmask[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
static const char clrmask[8] = {0x7f, 0xbf, 0xdf, 0xef, 0xf7, 0xfb, 0xfd, 0xfe};
// Set a pixel at the given coordiate
void pix_set(unsigned px, unsigned py)
{
// Give the compiler a hand
__assume(px < 320);
__assume(py < 200);
// Calculate base position in hires
char * dp = Hirows[py >> 3] + (px & ~7);
// Set the pixel
dp[py & 7] |= setmask[px & 7];
}
// Clear a pixel at the given coordiate
void pix_clr(unsigned px, unsigned py)
{
__assume(px < 320);
__assume(py < 200);
// Calculate base position in hires
char * dp = Hirows[py >> 3] + (px & ~7);
// Clear the pixel
dp[py & 7] &= clrmask[px & 7];
}
// Init free list of particles
void particle_init(void)
{
// Init address table for hires
for(int i=0; i<25; i++)
Hirows[i] = Hires + 320 * i;
// Init list heads
pfirst = nullptr;
pfree = particles;
// Link all particles in free list
for(int i=0; i<255; i++)
particles[i].next = particles + i + 1;
}
// Add a particle to the list
void particle_add(int px, int py, int vx, int vy)
{
// Check if we have a particle left
if (pfree)
{
// Remove from free list
Particle * p = pfree;
pfree = pfree->next;
// Add to used list
p->next = pfirst;
pfirst = p;
// Init particle data
p->px = px;
p->py = py;
p->vx = vx;
p->vy = vy;
}
}
// Move particles in used list
void particle_move(void)
{
// Start with first particle, remember previous
// particle for list removal
Particle * p = pfirst, * pp = nullptr;
// Loop over all particles in used list
while (p)
{
// Clear previous particle image, using 10.6 fixed point
pix_clr(p->px >> 6, p->py >> 6);
// Advance position by velocity
p->px += p->vx;
p->py += p->vy;
// Apply gravity
p->vy += 8;
// Check if particle is still on screen
if (p->px < 0 || p->px >= 320 * 64 || p->py < 0 || p->py >= 200 * 64)
{
// Particle is offscreen, so we remove it from the used list
// Remember next particle in used list
Particle * pn = p->next;
// Remove from used list
if (pp)
pp->next = pn;
else
pfirst = pn;
// Attach to free list
p->next = pfree;
pfree = p;
// Advance to next particle
p = pn;
}
else
{
// Set image at new position
pix_set(p->px >> 6, p->py >> 6);
// Advance to next particle
pp = p;
p = p->next;
}
}
}
// Normalized random function
int rnorm(void)
{
int l0 = (rand() & 0xfff) - 0x800;
int l1 = (rand() & 0xfff) - 0x800;
int l2 = (rand() & 0xfff) - 0x800;
int l3 = (rand() & 0xfff) - 0x800;
return l0 + l1 + l2 + l3;
}
int main(void)
{
// Turn off BASIC ROM
mmap_set(MMAP_NO_BASIC);
// Install IRQ trampoline
mmap_trampoline();
// Turn off kernal ROM
mmap_set(MMAP_NO_ROM);
// Switch to hires mode
vic_setmode(VICM_HIRES, Screen, Hires);
// Clear screen
memset(Screen, 0x10, 1000);
memset(Hires, 0x00, 8000);
// Black background
vic.color_border = 0x00;
vic.color_back = 0x00;
// Init particle system
particle_init();
char k = 0;
for(int i=0; i<10000; i++)
{
// Advance particles
particle_move();
if (k < 25)
{
// Add a particle from the left for the first third
particle_add(4 * 64, 196 * 64, 256 + (rnorm() >> 6), -(384 + (rnorm() >> 6)));
}
else if (k < 50)
{
// Add a particle from the right for the second third
particle_add(316 * 64, 196 * 64, - (256 + (rnorm() >> 6)), -(384 + (rnorm() >> 6)));
}
else if (k < 75)
{
// Add a particle from the middle for the final third
particle_add(160 * 64, 196 * 64, rnorm() >> 6, -(384 + (rnorm() >> 6)));
}
// Advance thirds counter
k++;
if (k == 75)
k = 0;
}
return 0;
}

View File

@ -0,0 +1,219 @@
#include <c64/vic.h>
#include <c64/memmap.h>
#include <string.h>
#include <stdlib.h>
static char * const Screen = (char *)0xc800;
static char * const Color = (char *)0xd800;
static char * const Hires = (char *)0xe000;
// Single particle, with position, veloicty and color pattern, using a next
// pointer for single linked list
struct Particle
{
int px, py, vx, vy;
char pat;
Particle * next;
};
// Storage for up to 256 particles
Particle particles[256];
// Heads of used and free list
Particle * pfirst, * pfree;
// Lookup table for hires row buffer
static char * Hirows[25];
// Pixel masks
static const char setmask[8] = {0xc0, 0xc0, 0x30, 0x30, 0x0c, 0x0c, 0x03, 0x03};
static const char clrmask[8] = {0x3f, 0x3f, 0xcf, 0xcf, 0xf3, 0xf3, 0xfc, 0xfc};
// Set a pixel at the given coordiate
void pix_set(unsigned px, unsigned py, char pat)
{
__assume(px < 320);
__assume(py < 200);
// Calculate base position in hires
char * dp = Hirows[py >> 3] + (px & ~7);
// Set two pixels for a square pixel look
char ly = py & 6;
dp[ly + 1] = dp[ly + 0] |= setmask[px & 7] & pat;
}
// Clear a pixel at the given coordiate
void pix_clr(unsigned px, unsigned py)
{
__assume(px < 320);
__assume(py < 200);
// Calculate base position in hires
char * dp = Hirows[py >> 3] + (px & ~7);
// Clear two pixels for a square pixel look
char ly = py & 6;
dp[ly + 1] = dp[ly + 0] &= clrmask[px & 7];
}
// Init free list of particles
void particle_init(void)
{
// Init address table for hires
for(int i=0; i<25; i++)
Hirows[i] = Hires + 320 * i;
// Init list heads
pfirst = nullptr;
pfree = particles;
// Link all particles in free list
for(int i=0; i<255; i++)
particles[i].next = particles + i + 1;
}
// Add a particle to the list
void particle_add(int px, int py, int vx, int vy, char pat)
{
// Check if we have a particle left
if (pfree)
{
// Remove from free list
Particle * p = pfree;
pfree = pfree->next;
// Add to used list
p->next = pfirst;
pfirst = p;
// Init particle data
p->px = px;
p->py = py;
p->vx = vx;
p->vy = vy;
p->pat = pat;
}
}
// Move particles in used list
void particle_move(void)
{
// Start with first particle, remember previous
// particle for list removal
Particle * p = pfirst, * pp = nullptr;
// Loop over all particles in used list
while (p)
{
// Clear previous particle image, using 10.6 fixed point
pix_clr(p->px >> 6, p->py >> 6);
// Advance position by velocity
p->px += p->vx;
p->py += p->vy;
// Apply gravity
p->vy += 8;
// Check if particle is still on screen
if (p->px < 0 || p->px >= 320 * 64 || p->py < 0 || p->py >= 200 * 64)
{
// Particle is offscreen, so we remove it from the used list
// Remember next particle in used list
Particle * pn = p->next;
// Remove from used list
if (pp)
pp->next = pn;
else
pfirst = pn;
// Attach to free list
p->next = pfree;
pfree = p;
// Advance to next particle
p = pn;
}
else
{
// Set image at new position
pix_set(p->px >> 6, p->py >> 6, p->pat);
// Advance to next particle
pp = p;
p = p->next;
}
}
}
// Normalized random function
int rnorm(void)
{
int l0 = (rand() & 0xfff) - 0x800;
int l1 = (rand() & 0xfff) - 0x800;
int l2 = (rand() & 0xfff) - 0x800;
int l3 = (rand() & 0xfff) - 0x800;
return l0 + l1 + l2 + l3;
}
int main(void)
{
// Turn off BASIC ROM
mmap_set(MMAP_NO_BASIC);
// Install IRQ trampoline
mmap_trampoline();
// Turn off kernal ROM
mmap_set(MMAP_NO_ROM);
// Switch to hires multicolor mode
vic_setmode(VICM_HIRES_MC, Screen, Hires);
// Clear screen
memset(Screen, 0x78, 1000);
memset(Color, 0x0e, 1000);
memset(Hires, 0x00, 8000);
// Black background
vic.color_border = 0x00;
vic.color_back = 0x00;
// Init particle system
particle_init();
char k = 0;
for(int i=0; i<10000; i++)
{
// Advance particles
particle_move();
if (k < 25)
{
// Add a particle from the left for the first third
particle_add(4 * 64, 196 * 64, 256 + (rnorm() >> 6), -(384 + (rnorm() >> 6)), 0x55);
}
else if (k < 50)
{
// Add a particle from the right for the second third
particle_add(316 * 64, 196 * 64, - (256 + (rnorm() >> 6)), -(384 + (rnorm() >> 6)), 0xaa);
}
else if (k < 75)
{
// Add a particle from the middle for the final third
particle_add(160 * 64, 196 * 64, rnorm() >> 6, -(384 + (rnorm() >> 6)), 0xff);
}
// Advance thirds counter
k++;
if (k == 75)
k = 0;
}
return 0;
}

View File

@ -0,0 +1,226 @@
#include <c64/vic.h>
#include <c64/memmap.h>
#include <string.h>
#include <stdlib.h>
static char * const Screen = (char *)0xc800;
static char * const Color = (char *)0xd800;
static char * const Hires = (char *)0xe000;
// Single particle, with position, veloicty and color pattern, using a next
// index for single linked list
struct Particle
{
int px, py, vx, vy;
char pat;
char next;
};
// Striped storage of particles, using an index for linkage
__striped Particle particles[256];
#pragma align(particles, 256)
// Index for used and free list heads
char pfirst, pfree;
static char * Hirows[25];
static const char setmask[4] = {0xc0, 0x30, 0x0c, 0x03};
static const char clrmask[4] = {0x3f, 0xcf, 0xf3, 0xfc};
// Set a pixel at the given coordiate
void pix_set(char px, char py, char pat)
{
__assume(px < 160);
__assume(py < 100);
// Calculate base position in hires
char * dp = Hirows[py >> 2] + 2 * (px & ~3);
// Set two pixels for a square pixel look
char ly = 2 * (py & 3);
dp[ly + 1] = dp[ly + 0] |= setmask[px & 3] & pat;
}
// Clear a pixel at the given coordiate
void pix_clr(char px, char py)
{
__assume(px < 160);
__assume(py < 100);
// Calculate base position in hires
char * dp = Hirows[py >> 2] + 2 * (px & ~3);
// Clear two pixels for a square pixel look
char ly = 2 * (py & 3);
dp[ly + 1] = dp[ly + 0] &= clrmask[px & 3];
}
// Init free list of particles
void particle_init(void)
{
// Init address table for hires
for(int i=0; i<25; i++)
Hirows[i] = Hires + 320 * i;
// Init list heads, using index 0 for list termination
pfirst = 0;
pfree = 1;
// Link all particles in free list
for(int i=1; i<255; i++)
particles[i].next = i + 1;
}
// Add a particle to the list
void particle_add(int px, int py, int vx, int vy, char pat)
{
// Check if we have a particle left
if (pfree)
{
// Use "auto" to generate a striped pointer
char i = pfree;
auto p = particles + pfree;
// Remove from free list
pfree = p->next;
p->next = pfirst;
// Add to used list
pfirst = i;
// Init particle data
p->px = px;
p->py = py;
p->vx = vx;
p->vy = vy;
p->pat = pat;
}
}
// Move particles in used list
void particle_move(void)
{
// Start with first particle, remember previous
// particle for list removal, using indices instead of pointers
char i = pfirst, pi = 0;
// Zero is still list termination
while (i)
{
// Use "auto" to generate a striped pointer
auto p = particles + i;
// Clear previous particle image, using 9.7 fixed point
pix_clr(p->px >> 7, p->py >> 7);
// Advance position by velocity
p->px += p->vx;
p->py += p->vy;
// Apply gravity
p->vy += 8;
// Check if particle is still on screen
if (p->px < 0 || p->px >= 160 * 128 || p->py < 0 || p->py >= 100 * 128)
{
// Particle is offscreen, so we remove it from the used list
// Remember next particle in used list
char pn = p->next;
// Remove from used list
if (pi)
particles[pi].next = pn;
else
pfirst = pn;
// Attach to free list
p->next = pfree;
pfree = i;
// Advance to next particle
i = pn;
}
else
{
// Set image at new position
pix_set(p->px >> 7, p->py >> 7, p->pat);
// Advance to next particle
pi = i;
i = p->next;
}
}
}
// Normalized random function
int rnorm(void)
{
int l0 = (rand() & 0xfff) - 0x800;
int l1 = (rand() & 0xfff) - 0x800;
int l2 = (rand() & 0xfff) - 0x800;
int l3 = (rand() & 0xfff) - 0x800;
return l0 + l1 + l2 + l3;
}
int main(void)
{
// Turn off BASIC ROM
mmap_set(MMAP_NO_BASIC);
// Install IRQ trampoline
mmap_trampoline();
// Turn off kernal ROM
mmap_set(MMAP_NO_ROM);
// Switch to hires multicolor mode
vic_setmode(VICM_HIRES_MC, Screen, Hires);
// Clear screen
memset(Screen, 0x78, 1000);
memset(Color, 0x0e, 1000);
memset(Hires, 0x00, 8000);
// Black background
vic.color_border = 0x00;
vic.color_back = 0x00;
// Init particle system
particle_init();
char k = 0;
for(int i=0; i<10000; i++)
{
// Advance particles
particle_move();
if (k < 25)
{
// Add a particle from the left for the first third
particle_add(4 * 64, 196 * 64, 256 + (rnorm() >> 6), -(384 + (rnorm() >> 6)), 0x55);
}
else if (k < 50)
{
// Add a particle from the right for the second third
particle_add(316 * 64, 196 * 64, - (256 + (rnorm() >> 6)), -(384 + (rnorm() >> 6)), 0xaa);
}
else if (k < 75)
{
// Add a particle from the middle for the final third
particle_add(160 * 64, 196 * 64, rnorm() >> 6, -(384 + (rnorm() >> 6)), 0xff);
}
// Advance thirds counter
k++;
if (k == 75)
k = 0;
}
return 0;
}

View File

@ -0,0 +1,4 @@
call ..\..\bin\oscar64 -n fireworks_ptr.c
call ..\..\bin\oscar64 -n fireworks_hires.c
call ..\..\bin\oscar64 -n fireworks_stripe.c