Fix LF line ending on windows, float and loop optimizations

This commit is contained in:
drmortalwombat 2022-01-25 14:31:36 +01:00
parent 9f41a55a18
commit f25bf80a0f
16 changed files with 712 additions and 45 deletions

View File

@ -1,6 +1,6 @@
#include "joystick.h" #include "joystick.h"
signed char joyx[2], joyy[2]; sbyte joyx[2], joyy[2];
bool joyb[2]; bool joyb[2];
void joy_poll(char n) void joy_poll(char n)

View File

@ -1,7 +1,9 @@
#ifndef C64_JOYSTICK_H #ifndef C64_JOYSTICK_H
#define C64_JOYSTICK_H #define C64_JOYSTICK_H
extern signed char joyx[2], joyy[2]; #include "types.h"
extern sbyte joyx[2], joyy[2];
extern bool joyb[2]; extern bool joyb[2];
// poll joystick input for joystick 0 or 1 and place // poll joystick input for joystick 0 or 1 and place

View File

@ -245,6 +245,14 @@ void rirq_write(RIRQCode * ic, byte n, void * addr, byte data)
ic->code[p] = data; ic->code[p] = data;
} }
void rirq_call(RIRQCode * ic, byte n, void * addr)
{
byte p = irqai[n];
ic->code[p - 1] = 0x20;
ic->code[p + 0] = (unsigned)addr & 0xff;
ic->code[p + 1] = (unsigned)addr >> 8;
}
void rirq_delay(RIRQCode * ic, byte cycles) void rirq_delay(RIRQCode * ic, byte cycles)
{ {
ic->code[ 1] = cycles; ic->code[ 1] = cycles;

View File

@ -40,6 +40,9 @@ void rirq_build(RIRQCode * ic, byte size);
// Add a write command to a raster IRQ // Add a write command to a raster IRQ
inline void rirq_write(RIRQCode * ic, byte n, void * addr, byte data); inline void rirq_write(RIRQCode * ic, byte n, void * addr, byte data);
// Add a call command to a raster IRQ
inline void rirq_call(RIRQCode * ic, byte n, void * addr);
// Change the address of a raster IRQ write command // Change the address of a raster IRQ write command
inline void rirq_addr(RIRQCode * ic, byte n, void * addr); inline void rirq_addr(RIRQCode * ic, byte n, void * addr);

View File

@ -2597,6 +2597,24 @@ bool InterInstruction::ConstantFolding(void)
mNumOperands = 1; mNumOperands = 1;
return true; return true;
} }
else if (mOperator == IA_MODU && (mSrc[0].mIntConst & (mSrc[0].mIntConst - 1)) == 0)
{
mOperator = IA_AND;
mSrc[0].mIntConst--;
return true;
}
else if (mOperator == IA_DIVU && (mSrc[0].mIntConst & (mSrc[0].mIntConst - 1)) == 0)
{
int n = 0;
while (mSrc[0].mIntConst > 1)
{
n++;
mSrc[0].mIntConst >>= 1;
}
mOperator = IA_SHR;
mSrc[0].mIntConst = n;
return true;
}
} }
} }
else if (mSrc[1].mTemp < 0) else if (mSrc[1].mTemp < 0)
@ -3005,6 +3023,7 @@ void InterCodeBasicBlock::GenerateTraces(bool expand)
else if (mTrueJump && !mFalseJump && ((expand && mTrueJump->mInstructions.Size() < 10 && mTrueJump->mInstructions.Size() > 1) || mTrueJump->mNumEntries == 1) && !mTrueJump->mLoopHead && !IsInfiniteLoop(mTrueJump, mTrueJump)) else if (mTrueJump && !mFalseJump && ((expand && mTrueJump->mInstructions.Size() < 10 && mTrueJump->mInstructions.Size() > 1) || mTrueJump->mNumEntries == 1) && !mTrueJump->mLoopHead && !IsInfiniteLoop(mTrueJump, mTrueJump))
{ {
mTrueJump->mNumEntries--; mTrueJump->mNumEntries--;
int n = mTrueJump->mNumEntries;
mInstructions.Pop(); mInstructions.Pop();
for (i = 0; i < mTrueJump->mInstructions.Size(); i++) for (i = 0; i < mTrueJump->mInstructions.Size(); i++)
@ -3013,11 +3032,14 @@ void InterCodeBasicBlock::GenerateTraces(bool expand)
mFalseJump = mTrueJump->mFalseJump; mFalseJump = mTrueJump->mFalseJump;
mTrueJump = mTrueJump->mTrueJump; mTrueJump = mTrueJump->mTrueJump;
if (n > 0)
{
if (mTrueJump) if (mTrueJump)
mTrueJump->mNumEntries++; mTrueJump->mNumEntries++;
if (mFalseJump) if (mFalseJump)
mFalseJump->mNumEntries++; mFalseJump->mNumEntries++;
} }
}
else else
break; break;
} }
@ -3474,6 +3496,11 @@ void InterCodeBasicBlock::CheckValueUsage(InterInstruction * ins, const GrowingI
ins->mSrc[0].mIntConst = 3; ins->mSrc[0].mIntConst = 3;
} }
} }
else if (ins->mOperator == IA_MODU && (ins->mSrc[0].mIntConst & (ins->mSrc[0].mIntConst - 1)) == 0)
{
ins->mOperator = IA_AND;
ins->mSrc[0].mIntConst--;
}
} }
if (ins->mSrc[0].mTemp > 0 && ins->mSrc[1].mTemp > 0 && ins->mSrc[0].mTemp == ins->mSrc[1].mTemp) if (ins->mSrc[0].mTemp > 0 && ins->mSrc[1].mTemp > 0 && ins->mSrc[0].mTemp == ins->mSrc[1].mTemp)
@ -3915,6 +3942,17 @@ void InterCodeBasicBlock::SimplifyIntegerRangeRelops(void)
{ {
mInstructions[i]->mOperator = IA_EXT8TO16U; mInstructions[i]->mOperator = IA_EXT8TO16U;
} }
else if (mInstructions[i]->mCode == IC_BINARY_OPERATOR && mInstructions[i]->mOperator == IA_DIVS && mInstructions[i]->mSrc[0].IsUnsigned() && mInstructions[i]->mSrc[1].IsUnsigned())
{
mInstructions[i]->mOperator = IA_DIVU;
mInstructions[i]->ConstantFolding();
}
else if (mInstructions[i]->mCode == IC_BINARY_OPERATOR && mInstructions[i]->mOperator == IA_MODS && mInstructions[i]->mSrc[0].IsUnsigned() && mInstructions[i]->mSrc[1].IsUnsigned())
{
mInstructions[i]->mOperator = IA_MODU;
mInstructions[i]->ConstantFolding();
}
#endif #endif
} }
#endif #endif
@ -6655,16 +6693,16 @@ void InterCodeBasicBlock::FollowJumps(void)
} }
InterCodeBasicBlock* InterCodeBasicBlock::PropagateDominator(InterCodeProcedure* proc) InterCodeBasicBlock* InterCodeBasicBlock::BuildLoopPrefix(InterCodeProcedure* proc)
{ {
if (!mVisited) if (!mVisited)
{ {
mVisited = true; mVisited = true;
if (mTrueJump) if (mTrueJump)
mTrueJump = mTrueJump->PropagateDominator(proc); mTrueJump = mTrueJump->BuildLoopPrefix(proc);
if (mFalseJump) if (mFalseJump)
mFalseJump = mFalseJump->PropagateDominator(proc); mFalseJump = mFalseJump->BuildLoopPrefix(proc);
if (mLoopHead) if (mLoopHead)
{ {
@ -8458,7 +8496,7 @@ void InterCodeProcedure::Close(void)
TempForwarding(); TempForwarding();
} }
BuildDominators(); BuildLoopPrefix();
DisassembleDebug("added dominators"); DisassembleDebug("added dominators");
ResetVisited(); ResetVisited();
@ -8655,6 +8693,21 @@ void InterCodeProcedure::Close(void)
#endif #endif
#if 1
BuildLoopPrefix();
DisassembleDebug("added dominators");
ResetVisited();
mEntryBlock->SingleBlockLoopOptimisation(mParamAliasedSet);
DisassembleDebug("single block loop opt 2");
BuildDataFlowSets();
BuildTraces(false);
DisassembleDebug("Rebuilt traces");
#endif
#if 1 #if 1
ResetVisited(); ResetVisited();
mEntryBlock->PeepholeOptimization(); mEntryBlock->PeepholeOptimization();
@ -8848,10 +8901,14 @@ void InterCodeProcedure::MergeBasicBlocks(void)
} }
void InterCodeProcedure::BuildDominators(void) void InterCodeProcedure::BuildLoopPrefix(void)
{ {
ResetVisited(); ResetVisited();
mEntryBlock = mEntryBlock->PropagateDominator(this);
for (int i = 0; i < mBlocks.Size(); i++)
mBlocks[i]->mLoopPrefix = nullptr;
mEntryBlock = mEntryBlock->BuildLoopPrefix(this);
ResetVisited(); ResetVisited();
for (int i = 0; i < mBlocks.Size(); i++) for (int i = 0; i < mBlocks.Size(); i++)
@ -9002,7 +9059,7 @@ void InterCodeProcedure::Disassemble(FILE* file)
static char typechars[] = "NBCILFP"; static char typechars[] = "NBCILFP";
for (int i = 0; i < mTemporaries.Size(); i++) for (int i = 0; i < mTemporaries.Size(); i++)
{ {
fprintf(file, "$%02x T%d(%c), ", mTempOffset[i], i, typechars[mTemporaries[i]]); fprintf(file, "$%02x R%d(%c), ", mTempOffset[i], i, typechars[mTemporaries[i]]);
} }
fprintf(file, "\n"); fprintf(file, "\n");

View File

@ -445,7 +445,7 @@ public:
void CollectLoopPath(const GrowingArray<InterCodeBasicBlock*>& body, GrowingArray<InterCodeBasicBlock*>& path); void CollectLoopPath(const GrowingArray<InterCodeBasicBlock*>& body, GrowingArray<InterCodeBasicBlock*>& path);
void InnerLoopOptimization(const NumberSet& aliasedParams); void InnerLoopOptimization(const NumberSet& aliasedParams);
InterCodeBasicBlock* PropagateDominator(InterCodeProcedure * proc); InterCodeBasicBlock* BuildLoopPrefix(InterCodeProcedure * proc);
void SplitBranches(InterCodeProcedure* proc); void SplitBranches(InterCodeProcedure* proc);
void FollowJumps(void); void FollowJumps(void);
@ -517,7 +517,7 @@ protected:
void TempForwarding(void); void TempForwarding(void);
void RemoveUnusedInstructions(void); void RemoveUnusedInstructions(void);
bool GlobalConstantPropagation(void); bool GlobalConstantPropagation(void);
void BuildDominators(void); void BuildLoopPrefix(void);
void SingleAssignmentForwarding(void); void SingleAssignmentForwarding(void);
void MergeBasicBlocks(void); void MergeBasicBlocks(void);

View File

@ -5106,6 +5106,7 @@ NativeCodeBasicBlock* NativeCodeBasicBlock::BinaryOperator(InterCodeProcedure* p
{ {
int sop0 = 0, sop1 = 1; int sop0 = 0, sop1 = 1;
bool flipop = false; bool flipop = false;
bool changedSign = false;
if (ins->mOperator == IA_ADD || ins->mOperator == IA_MUL || ins->mOperator == IA_SUB) if (ins->mOperator == IA_ADD || ins->mOperator == IA_MUL || ins->mOperator == IA_SUB)
{ {
@ -5128,6 +5129,13 @@ NativeCodeBasicBlock* NativeCodeBasicBlock::BinaryOperator(InterCodeProcedure* p
if (ins->mSrc[sop1].mTemp < 0) if (ins->mSrc[sop1].mTemp < 0)
{ {
union { float f; unsigned int v; } cc; union { float f; unsigned int v; } cc;
if (ins->mOperator == IA_SUB && flipop)
{
changedSign = true;
cc.f = -ins->mSrc[sop1].mFloatConst;
}
else
cc.f = ins->mSrc[sop1].mFloatConst; cc.f = ins->mSrc[sop1].mFloatConst;
mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, cc.v & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, cc.v & 0xff));
@ -5168,6 +5176,13 @@ NativeCodeBasicBlock* NativeCodeBasicBlock::BinaryOperator(InterCodeProcedure* p
if (ins->mSrc[sop0].mTemp < 0) if (ins->mSrc[sop0].mTemp < 0)
{ {
union { float f; unsigned int v; } cc; union { float f; unsigned int v; } cc;
if (ins->mOperator == IA_SUB && !flipop)
{
changedSign = true;
cc.f = -ins->mSrc[sop0].mFloatConst;
}
else
cc.f = ins->mSrc[sop0].mFloatConst; cc.f = ins->mSrc[sop0].mFloatConst;
mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, cc.v & 0xff)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, cc.v & 0xff));
@ -5213,6 +5228,8 @@ NativeCodeBasicBlock* NativeCodeBasicBlock::BinaryOperator(InterCodeProcedure* p
mIns.Push(NativeCodeInstruction(ASMIT_JSR, ASMIM_ABSOLUTE, art.mOffset, art.mLinkerObject, NCIF_RUNTIME)); mIns.Push(NativeCodeInstruction(ASMIT_JSR, ASMIM_ABSOLUTE, art.mOffset, art.mLinkerObject, NCIF_RUNTIME));
} break; } break;
case IA_SUB: case IA_SUB:
{
if (!changedSign)
{ {
if (flipop) if (flipop)
{ {
@ -5226,6 +5243,7 @@ NativeCodeBasicBlock* NativeCodeBasicBlock::BinaryOperator(InterCodeProcedure* p
mIns.Push(NativeCodeInstruction(ASMIT_EOR, ASMIM_IMMEDIATE, 0x80)); mIns.Push(NativeCodeInstruction(ASMIT_EOR, ASMIM_IMMEDIATE, 0x80));
mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 3)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 3));
} }
}
NativeCodeGenerator::Runtime& art(nproc->mGenerator->ResolveRuntime(Ident::Unique("faddsub"))); NativeCodeGenerator::Runtime& art(nproc->mGenerator->ResolveRuntime(Ident::Unique("faddsub")));
mIns.Push(NativeCodeInstruction(ASMIT_JSR, ASMIM_ABSOLUTE, art.mOffset, art.mLinkerObject, NCIF_RUNTIME)); mIns.Push(NativeCodeInstruction(ASMIT_JSR, ASMIM_ABSOLUTE, art.mOffset, art.mLinkerObject, NCIF_RUNTIME));
@ -15103,18 +15121,34 @@ void NativeCodeProcedure::Compile(InterCodeProcedure* proc)
mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK)); mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK));
mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_SBC, ASMIM_IMMEDIATE, commonFrameSize & 0xff)); mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_SBC, ASMIM_IMMEDIATE, commonFrameSize & 0xff));
mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_STACK)); mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_STACK));
if (commonFrameSize >= 256)
{
mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK + 1)); mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK + 1));
mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_SBC, ASMIM_IMMEDIATE, (commonFrameSize >> 8) & 0xff)); mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_SBC, ASMIM_IMMEDIATE, (commonFrameSize >> 8) & 0xff));
mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_STACK + 1)); mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_STACK + 1));
}
else
{
mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_BCS, ASMIM_RELATIVE, 2));
mEntryBlock->mIns.Push(NativeCodeInstruction(ASMIT_DEC, ASMIM_ZERO_PAGE, BC_REG_STACK + 1));
}
mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_CLC, ASMIM_IMPLIED)); mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_CLC, ASMIM_IMPLIED));
mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK)); mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK));
mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_IMMEDIATE, commonFrameSize & 0xff)); mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_IMMEDIATE, commonFrameSize & 0xff));
mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_STACK)); mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_STACK));
if (commonFrameSize >= 256)
{
mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK + 1)); mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK + 1));
mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_IMMEDIATE, (commonFrameSize >> 8) & 0xff)); mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_IMMEDIATE, (commonFrameSize >> 8) & 0xff));
mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_STACK + 1)); mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_STACK + 1));
} }
else
{
mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_BCC, ASMIM_RELATIVE, 2));
mExitBlock->mIns.Push(NativeCodeInstruction(ASMIT_INC, ASMIM_ZERO_PAGE, BC_REG_STACK + 1));
}
}
if (mNoFrame) if (mNoFrame)
{ {

View File

@ -88,7 +88,7 @@ bool SourceFile::Open(const char* name, const char* path, bool binary)
strcat_s(fname + n, sizeof(fname) - n, name); strcat_s(fname + n, sizeof(fname) - n, name);
if (!fopen_s(&mFile, fname, binary ? "rb" : "r")) if (!fopen_s(&mFile, fname, "rb"))
{ {
_fullpath(mFileName, fname, sizeof(mFileName)); _fullpath(mFileName, fname, sizeof(mFileName));
char* p = mFileName; char* p = mFileName;
@ -158,7 +158,7 @@ bool Preprocessor::NextLine(void)
mLocation.mLine++; mLocation.mLine++;
s = strlen(mLine); s = strlen(mLine);
while (s > 0 && mLine[s - 1] == '\n') while (s > 0 && (mLine[s - 1] == '\n' || mLine[s - 1] == '\r'))
s--; s--;
if (s == 0 || mLine[s - 1] != '\\') if (s == 0 || mLine[s - 1] != '\\')
return true; return true;

View File

@ -73,7 +73,7 @@ int main(int argc, const char** argv)
#else #else
strcpy(strProductName, "oscar64"); strcpy(strProductName, "oscar64");
strcpy(strProductVersion, "1.2.66"); strcpy(strProductVersion, "1.2.67");
#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,2,66,0 FILEVERSION 1,2,67,0
PRODUCTVERSION 1,2,66,0 PRODUCTVERSION 1,2,67,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.2.66.0" VALUE "FileVersion", "1.2.67.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.2.66.0" VALUE "ProductVersion", "1.2.67.0"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"

View File

@ -3169,15 +3169,15 @@
{ {
"Name" = "8:Microsoft Visual Studio" "Name" = "8:Microsoft Visual Studio"
"ProductName" = "8:oscar64" "ProductName" = "8:oscar64"
"ProductCode" = "8:{71F1F5C2-A7B5-46C1-8354-C7B870ADCD34}" "ProductCode" = "8:{118A6EF7-D160-4A3E-AECC-5B0D9AA16099}"
"PackageCode" = "8:{7F48C21E-E13E-479D-824A-5AB731A09EB1}" "PackageCode" = "8:{8B7C9187-A38D-43DB-B458-3E80FDB17616}"
"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.2.66" "ProductVersion" = "8:1.2.67"
"Manufacturer" = "8:oscar64" "Manufacturer" = "8:oscar64"
"ARPHELPTELEPHONE" = "8:" "ARPHELPTELEPHONE" = "8:"
"ARPHELPLINK" = "8:" "ARPHELPLINK" = "8:"

279
samples/games/lander.c Normal file
View File

@ -0,0 +1,279 @@
#include <c64/joystick.h>
#include <c64/vic.h>
#include <c64/sprites.h>
#include <stdlib.h>
#include <string.h>
byte landersprites[] = {
#embed "../resources/landersprites.bin"
};
// Screen and color ram address
#define Screen ((byte *)0x0400)
#define Color ((byte *)0xd800)
struct Lander
{
float px, py, vx, vy;
};
enum GameState
{
GS_READY, // Getting ready
GS_PLAYING, // Playing the game
GS_LANDED, // Landed on pad
GS_COLLIDE // Collided with something
};
// State of the game
struct Game
{
GameState state;
byte count;
Lander lander; // use an array for multiplayer
} TheGame; // Only one game, so global variable
// Put one char on screen
inline void screen_put(byte x, byte y, char ch, char color)
{
__assume(y < 25);
Screen[40 * y + x] = ch;
Color[40 * y + x] = color;
}
// Get one char from screen
inline char screen_get(byte x, byte y)
{
__assume(y < 25);
return Screen[40 * y + x];
}
void screen_init(void)
{
// Fill screen with spaces
memset(Screen, ' ', 1000);
for(char i=0; i<100; i++)
screen_put(rand() % 40, rand() % 25, '.', VCOL_WHITE)
sbyte height[41];
for(char i=0; i<41; i+=8)
height[i] = 4 + rand() % 16;
for(char step = 8; step > 1; step /= 2)
{
for(char i=0; i<40; i+=step)
{
char p = (height[i] + height[i + step]) >> 1;
p += rand() % step - (step / 2);
height[i + step / 2] = p;
}
}
char xp = 2 + rand() % 33;
char yp = height[xp];
for(char i=1; i<4; i++)
if (height[xp + i] < yp)
yp = height[xp + i]
for(char i=0; i<4; i++)
height[xp + i] = yp;
for(char x=0; x<40; x++)
{
char h = height[x];
for(char y=0; y<h; y++)
screen_put(x, 24 - y, 160, VCOL_YELLOW)
}
for(char i=0; i<4; i++)
{
screen_put(xp + i, 24 - yp, 128 + 86, VCOL_MED_GREY)
screen_put(xp + i, 23 - yp, 100, VCOL_WHITE)
}
}
void lander_init(Lander * lander)
{
lander->px = 160;
lander->py = 50;
lander->vx = 0;
lander->vy = 0;
spr_set(0, true, (int)lander->px, (int)lander->py, 0x0380 / 64, VCOL_DARK_GREY, false, false, false);
spr_set(1, true, (int)lander->px, (int)lander->py, 0x0340 / 64, VCOL_LT_GREY, true, false, false);
spr_set(2, false, (int)lander->px, (int)lander->py + 20, 0x03c0 / 64, VCOL_WHITE, false, false, false);
}
char ExhaustColor[] = {VCOL_YELLOW, VCOL_WHITE, VCOL_ORANGE, VCOL_LT_BLUE};
void lander_move(Lander * lander, sbyte jx, sbyte jy)
{
lander->px += lander->vx;
lander->py += lander->vy;
lander->vx += jx * 0.02;
lander->vy += jy * 0.1 + 0.01;
}
void lander_show(Lander * lander, sbyte jx, sbyte jy)
{
vic.color_border++;
int ix = (int)lander->px, iy = (int)lander->py;
spr_move(0, ix, iy);
spr_move(1, ix, iy);
if (jy < 0)
{
spr_move(2, ix, iy + 20);
spr_color(2, ExhaustColor[rand() & 3]);
spr_show(2, true);
}
else
spr_show(2, false);
vic.color_border--;
}
void lander_flash(Lander * lander, char c)
{
spr_color(0, rand() & 1);
}
enum LanderCollision
{
LCOL_FREE,
LCOL_GROUND,
LCOL_PAD
};
LanderCollision lander_check(Lander * lander)
{
sbyte ix = (sbyte)((lander->px - 24) * 0.125);
sbyte iy = (sbyte)((lander->py - 29) * 0.125);
if (iy > 24)
return LCOL_GROUND;
if (iy < 0)
return LCOL_FREE;
LanderCollision col = LCOL_FREE;
for(char i=0; i<4; i++)
{
if (ix >= 0 && ix < 40)
{
char ch = screen_get(ix, iy);
if (ch == 160)
return LCOL_GROUND;
else if (ch == 128 + 86)
col = LCOL_PAD;
}
ix++;
}
return col;
}
void game_state(GameState state)
{
// Set new state
TheGame.state = state;
switch(state)
{
case GS_READY:
// Clear the screen
lander_init(&TheGame.lander)
screen_init();
TheGame.count = 32;
break;
case GS_PLAYING:
break;
case GS_LANDED:
TheGame.lander.py = (sbyte)((TheGame.lander.py - 29) * 0.125) * 8 + 28;
lander_show(&TheGame.lander, 0, 0);
TheGame.count = 16;
break;
case GS_COLLIDE:
TheGame.count = 32;
lander_show(&TheGame.lander, 0, 0);
break;
}
}
// Main game loop, invoked every vsync
void game_loop(void)
{
switch (TheGame.state)
{
case GS_READY:
// Countdown ready to start
if (!--TheGame.count)
game_state(GS_PLAYING);
break;
case GS_PLAYING:
{
// Check player input on every frame
joy_poll(0);
lander_move(&TheGame.lander, joyx[0], joyy[0]);
LanderCollision col = lander_check(&TheGame.lander);
if (col == LCOL_GROUND)
game_state(GS_COLLIDE);
else if (col == LCOL_PAD)
game_state(GS_LANDED);
else
lander_show(&TheGame.lander, joyx[0], joyy[0]);
} break;
case GS_LANDED:
if (!--TheGame.count)
game_state(GS_READY);
break;
case GS_COLLIDE:
lander_flash(&TheGame.lander, TheGame.count);
if (!--TheGame.count)
game_state(GS_READY);
break;
}
}
int main(void)
{
// Screen color to black
vic.color_border = VCOL_BLACK;
vic.color_back = VCOL_BLACK;
vic.spr_mcolor0 = VCOL_MED_GREY;
vic.spr_mcolor1 = VCOL_YELLOW;
memcpy((char *)0x0340, landersprites, 192);
spr_init(Screen);
// Start the game in ready state
game_state(GS_READY);
// Forever
for(;;)
{
// One game loop iteration
game_loop();
// Wait one vsync
vic_waitFrame();
}
// Never reached
return 0;
}

2
samples/games/make.bat Normal file
View File

@ -0,0 +1,2 @@
call ..\..\bin\oscar64 snake.c
call ..\..\bin\oscar64 -n lander.c

282
samples/games/snake.c Normal file
View File

@ -0,0 +1,282 @@
#include <c64/joystick.h>
#include <c64/vic.h>
#include <stdlib.h>
#include <string.h>
// Position/Direction on screen
struct Point
{
sbyte x, y;
};
struct Snake
{
Point head; // Position of head
Point dir; // Direction of head
Point tail[256]; // Position of tail
byte length; // Length of tail
byte pos; // Tail start
};
enum GameState
{
GS_READY, // Getting ready
GS_PLAYING, // Playing the game
GS_COLLIDE // Collided with something
};
// State of the game
struct Game
{
GameState state;
byte count;
Snake snake; // use an array for multiplayer
} TheGame; // Only one game, so global variable
// Screen and color ram address
#define Screen ((byte *)0x0400)
#define Color ((byte *)0xd800)
// Put one char on screen
inline void screen_put(byte x, byte y, char ch, char color)
{
Screen[40 * y + x] = ch;
Color[40 * y + x] = color;
}
// Get one char from screen
inline char screen_get(byte x, byte y)
{
return Screen[40 * y + x];
}
// Put a fruit/heart at random position
void screen_fruit(void)
{
byte x, y;
do
{
// Draw a random position
x = 1 + rand() % 38;
y = 1 + rand() % 23;
// Ensure it is an empty place
} while (screen_get(x, y) != ' ');
// Put the heart on screen
screen_put(x, y, 83, VCOL_YELLOW);
}
// Clear screen and draw borders
void screen_init(void)
{
// Fill screen with spaces
memset(Screen, ' ', 1000);
// Bottom and top row
for(byte x=0; x<40; x++)
{
screen_put(x, 0, 0xa0, VCOL_LT_GREY);
screen_put(x, 24, 0xa0, VCOL_LT_GREY);
}
// Left and right column
for(byte y=0; y<25; y++)
{
screen_put( 0, y, 0xa0, VCOL_LT_GREY);
screen_put( 39, y, 0xa0, VCOL_LT_GREY);
}
}
// Initialize a snake
void snake_init(Snake * s)
{
// Length of tail is one
s->length = 1;
s->pos = 0;
// Snake in the center of screen
s->head.x = 20;
s->head.y = 12;
// Starting to the right
s->dir.x = 1;
s->dir.y = 0;
// Show head
screen_put(s->head.x, s->head.y, 81, VCOL_WHITE);
}
bool snake_advance(Snake * s)
{
// Promote head to start of tail
s->tail[s->pos] = s->head;
s->pos++;
screen_put(s->head.x, s->head.y, 81, VCOL_LT_BLUE);
// Advance head
s->head.x += s->dir.x;
s->head.y += s->dir.y;
// Get character at new head position
char ch = screen_get(s->head.x, s->head.y);
// Draw head
screen_put(s->head.x, s->head.y, 81, VCOL_WHITE);
// Clear tail
char tpos = s->pos - s->length;
screen_put(s->tail[tpos].x, s->tail[tpos].y, ' ', VCOL_BLACK);
// Did snake collect the fruit
if (ch == 83)
{
// Extend tail
s->length++;
screen_fruit();
}
else if (ch != ' ')
{
// Snake collided with something
return true;
}
return false;
}
// flash the snake after collision
bool snake_flash(Snake * s, char c)
{
// Loop over all tail elements
for(char i=0; i<s->length; i++)
{
// Set color
char tpos = s->pos - i - 1;
screen_put(s->tail[tpos].x, s->tail[tpos].y, 81, c);
}
}
// Change snake direction based on user input
void snake_control(Snake * s, sbyte jx, sbyte jy)
{
// First change from horizontal to vertical, otherwise
// check vertical to horizontal
if (s->dir.x && jy)
{
s->dir.x = 0;
s->dir.y = jy;
}
else if (s->dir.y && jx)
{
s->dir.y = 0;
s->dir.x = jx;
}
}
void game_state(GameState state)
{
// Set new state
TheGame.state = state;
switch(state)
{
case GS_READY:
// Clear the screen
screen_init();
TheGame.count = 32;
break;
case GS_PLAYING:
// Init the snake
snake_init(&TheGame.snake);
// Initial fruit
screen_fruit();
TheGame.count = 16;
break;
case GS_COLLIDE:
TheGame.count = 16;
break;
}
}
// Colors for collision "animation"
char FlashColors[] = {
VCOL_YELLOW,
VCOL_WHITE,
VCOL_LT_GREY,
VCOL_YELLOW,
VCOL_ORANGE,
VCOL_RED,
VCOL_MED_GREY,
VCOL_DARK_GREY
};
// Main game loop, invoked every vsync
void game_loop(void)
{
switch (TheGame.state)
{
case GS_READY:
// Countdown ready to start
if (!--TheGame.count)
game_state(GS_PLAYING);
break;
case GS_PLAYING:
// Check player input on every frame
joy_poll(0);
snake_control(&TheGame.snake, joyx[0], joyy[0]);
if (!--TheGame.count)
{
// Move snake every four frames, advance to collision
// state if collided
if (snake_advance(&TheGame.snake))
game_state(GS_COLLIDE);
else
TheGame.count = 4;
}
break;
case GS_COLLIDE:
// Flash the collided snake
snake_flash(&TheGame.snake, FlashColors[(16 - TheGame.count) / 2]);
if (!--TheGame.count)
game_state(GS_READY);
break;
}
}
int main(void)
{
// Screen color to black
vic.color_border = VCOL_BLACK;
vic.color_back = VCOL_BLACK;
// Start the game in ready state
game_state(GS_READY);
// Forever
for(;;)
{
// One game loop iteration
game_loop();
// Wait one vsync
vic_waitFrame();
}
// Never reached
return 0;
}

Binary file not shown.

Binary file not shown.