Add iecbus library

This commit is contained in:
drmortalwombat 2023-05-21 17:19:26 +02:00
parent e6b46a3acf
commit cdbb24b6b2
6 changed files with 409 additions and 13 deletions

View File

@ -63,7 +63,7 @@ The compiler can also be built using MSVC or GCC. A visual studio project and a
The compiler is command line driven, and creates an executable .prg file.
oscar64 {-i=includePath} [-o=output.prg] [-rt=runtime.c] [-tf=format] [-e] [-n] [-dSYMBOL[=value]] {source.c}
oscar64 {-i=includePath} [-o=output.prg] [-rt=runtime.c] [-tf=format] [-tm=machine] [-e] [-n] [-dSYMBOL[=value]] {source.c}
* -v : verbose output for diagnostics
* -v2 : more verbose output

238
include/c64/iecbus.c Normal file
View File

@ -0,0 +1,238 @@
#include "iecbus.h"
#include <c64/cia.h>
#include <c64/vic.h>
IEC_STATUS iec_status;
#define CIA2B_ATNOUT 0x08
#define CIA2B_CLKOUT 0x10
#define CIA2B_DATAOUT 0x20
#define CIA2B_CLKIN 0x40
#define CIA2B_DATAIN 0x80
#pragma optimize(push)
#pragma optimize(1)
static void delay(char n)
{
while (n)
{
__asm {
nop
}
n--;
}
}
static inline void data_low(void)
{
cia2.pra &= ~CIA2B_DATAOUT;
}
static inline void data_high(void)
{
cia2.pra |= CIA2B_DATAOUT;
}
static inline void clock_low(void)
{
cia2.pra &= ~CIA2B_CLKOUT;
}
static inline void cdata_low(void)
{
cia2.pra &= ~(CIA2B_CLKOUT | CIA2B_DATAOUT);
}
static inline void clock_high(void)
{
cia2.pra |= CIA2B_CLKOUT;
}
static inline void atn_low(void)
{
cia2.pra &= ~CIA2B_ATNOUT;
}
static inline void atn_high(void)
{
cia2.pra |= CIA2B_ATNOUT;
}
static bool data_check(void)
{
char cnt = 100;
while (cnt > 0 && (cia2.pra & CIA2B_DATAIN))
cnt--;
if (cnt)
return true;
else
{
iec_status = IEC_TIMEOUT;
return false;
}
}
bool iec_eoi(void)
{
cdata_low();
while (!(cia2.pra & CIA2B_DATAIN))
;
delay(50);
return data_check();
}
bool iec_write(char b)
{
cdata_low();
while (!(cia2.pra & CIA2B_DATAIN))
;
for(char i=0; i<8; i++)
{
clock_high();
if (b & 1)
data_low();
else
data_high();
clock_low();
b >>= 1;
__asm
{
nop
nop
nop
nop
}
}
data_low();
clock_high();
return data_check();
}
char iec_read(void)
{
while (!(cia2.pra & CIA2B_CLKIN))
;
data_low();
char cnt = 100;
while (cnt > 0 && (cia2.pra & CIA2B_CLKIN))
cnt--;
if (cnt == 0)
{
iec_status = IEC_EOF;
data_high();
__asm
{
nop
nop
nop
nop
}
data_low();
cnt = 200;
while (cnt > 0 && (cia2.pra & CIA2B_CLKIN))
cnt--;
if (cnt == 0)
{
iec_status = IEC_TIMEOUT;
return 0;
}
}
char b = 0;
for(char i=0; i<8; i++)
{
char c;
while (!((c = cia2.pra) & CIA2B_CLKIN))
;
b >>= 1;
b |= c & 0x80;
while (cia2.pra & CIA2B_CLKIN)
;
}
data_high();
return b;
}
void iec_atn(char dev, char sec)
{
atn_high();
clock_high();
delay(100);
iec_write(dev);
if (sec != 0xff)
iec_write(sec);
data_high();
atn_low();
}
void iec_talk(char dev, char sec)
{
iec_status = IEC_OK;
iec_atn(dev | 0x40, sec);
clock_low();
}
void iec_untalk(void)
{
iec_atn(0x5f, 0xff);
}
void iec_listen(char dev, char sec)
{
iec_status = IEC_OK;
iec_atn(dev | 0x20, sec);
}
void iec_unlisten(void)
{
iec_atn(0x3f, 0xff);
}
void iec_open(char dev, char sec, const char * fname)
{
iec_status = IEC_OK;
iec_atn(dev | 0x20, sec | 0xf0);
char i = 0;
while (fname[i])
{
if (!fname[i + 1])
iec_eoi();
iec_write(fname[i]);
i++;
}
iec_unlisten();
}
void iec_close(char dev, char sec)
{
iec_atn(dev | 0x20, sec | 0xe0);
iec_unlisten();
}
#pragma optimize(pop)

38
include/c64/iecbus.h Normal file
View File

@ -0,0 +1,38 @@
#ifndef C64_IECBUS_H
#define C64_IECBUS_H
enum IEC_STATUS
{
IEC_OK = 0x00,
IEC_EOF = 0x01,
IEC_ERROR = 0x80,
IEC_TIMEOUT
};
extern IEC_STATUS iec_status;
bool iec_eoi(void);
bool iec_write(char b);
char iec_read(void);
void iec_atn(char dev, char sec);
void iec_talk(char dev, char sec);
void iec_untalk(void);
void iec_listen(char dev, char sec);
void iec_unlisten(void);
void iec_open(char dev, char sec, const char * fname);
void iec_close(char dev, char sec);
#pragma compile("iecbus.c")
#endif

View File

@ -1,7 +1,6 @@
#ifndef NES_MMC1_H
#define NES_MMC1_H
#include <c64/types.h>
enum MMC1Mirror

View File

@ -19226,14 +19226,14 @@ bool NativeCodeBasicBlock::JoinTailCodeSequences(NativeCodeProcedure* proc, bool
int ns = mIns.Size();
if ((mIns[ns - 2].mType == ASMIT_INY || mIns[ns - 2].mType == ASMIT_DEY) && mIns[ns - 1].mType == ASMIT_TYA)
{
if (mBranch == ASMIT_BEQ && !mFalseJump->mEntryRequiredRegs[CPU_REG_A])
if (mBranch == ASMIT_BEQ && !mFalseJump->mEntryRequiredRegs[CPU_REG_A] && mTrueJump->mNumEntries == 1)
{
mTrueJump->mIns.Insert(0, NativeCodeInstruction(mIns[ns - 1].mIns, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns[ns - 1].mType = ASMIT_NOP;
mIns[ns - 2].mLive |= LIVE_CPU_REG_Z;
changed = true;
}
else if (mBranch == ASMIT_BNE && !mTrueJump->mEntryRequiredRegs[CPU_REG_A])
else if (mBranch == ASMIT_BNE && !mTrueJump->mEntryRequiredRegs[CPU_REG_A] && mFalseJump->mNumEntries == 1)
{
mFalseJump->mIns.Insert(0, NativeCodeInstruction(mIns[ns - 1].mIns, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns[ns - 1].mType = ASMIT_NOP;
@ -19243,14 +19243,14 @@ bool NativeCodeBasicBlock::JoinTailCodeSequences(NativeCodeProcedure* proc, bool
}
else if ((mIns[ns - 2].mType == ASMIT_INX || mIns[ns - 2].mType == ASMIT_DEX) && mIns[ns - 1].mType == ASMIT_TXA)
{
if (mBranch == ASMIT_BEQ && !mFalseJump->mEntryRequiredRegs[CPU_REG_A])
if (mBranch == ASMIT_BEQ && !mFalseJump->mEntryRequiredRegs[CPU_REG_A] && mTrueJump->mNumEntries == 1)
{
mTrueJump->mIns.Insert(0, NativeCodeInstruction(mIns[ns - 1].mIns, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns[ns - 1].mType = ASMIT_NOP;
mIns[ns - 2].mLive |= LIVE_CPU_REG_Z;
changed = true;
}
else if (mBranch == ASMIT_BNE && !mTrueJump->mEntryRequiredRegs[CPU_REG_A])
else if (mBranch == ASMIT_BNE && !mTrueJump->mEntryRequiredRegs[CPU_REG_A] && mFalseJump->mNumEntries == 1)
{
mFalseJump->mIns.Insert(0, NativeCodeInstruction(mIns[ns - 1].mIns, ASMIT_LDA, ASMIM_IMMEDIATE, 0));
mIns[ns - 1].mType = ASMIT_NOP;
@ -19283,6 +19283,37 @@ bool NativeCodeBasicBlock::JoinTailCodeSequences(NativeCodeProcedure* proc, bool
}
}
#endif
if (mIns.Size() >= 2 && mNumEntries == 1)
{
if (mIns[0].mType == ASMIT_TYA && mIns[1].IsShift() && mIns[1].mMode == ASMIM_IMPLIED)
{
NativeCodeBasicBlock* block = mEntryBlocks[0];
int ns = block->mIns.Size();
if (ns >= 2 && block->mIns[ns - 2].mType == ASMIT_TAY && block->mIns[ns - 1].IsSame(mIns[1]))
{
mIns[0].mType = ASMIT_NOP; mIns[0].mMode = ASMIM_IMPLIED;
mIns[1].mType = ASMIT_NOP; mIns[1].mMode = ASMIM_IMPLIED;
block->mIns[ns - 1].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_C;
changed = true;
}
}
}
if (mIns.Size() >= 1 && mNumEntries == 1)
{
if (mIns[0].IsShift() && mIns[0].mMode == ASMIM_ZERO_PAGE && !(mIns[0].mLive & LIVE_MEM))
{
NativeCodeBasicBlock* block = mEntryBlocks[0];
int ns = block->mIns.Size();
if (ns >= 2 &&
block->mIns[ns - 2].mType == ASMIT_STA && block->mIns[ns - 2].SameEffectiveAddress(mIns[0]) &&
block->mIns[ns - 1].mType == mIns[0].mType && block->mIns[ns - 1].mMode == ASMIM_IMPLIED && !(mIns[0].mLive & LIVE_MEM))
{
mIns[0].mType = ASMIT_NOP; mIns[0].mMode = ASMIM_IMPLIED;
block->mIns[ns - 1].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_C;
changed = true;
}
}
}
#if 1
if (mIns.Size() >= 2)
{
@ -20300,6 +20331,47 @@ bool NativeCodeBasicBlock::FoldLoopEntry(void)
}
}
}
if (!changed && mTrueJump && mFalseJump && mIns.Size() >= 2)
{
int sz = mIns.Size();
if (mIns[sz - 2].mType == ASMIT_LDA && ((mIns[sz - 1].mType == ASMIT_AND && mIns[sz - 1].mMode == ASMIM_IMMEDIATE) || (mIns[sz - 1].IsShift() && mIns[sz - 1].mMode == ASMIM_IMPLIED)))
{
if (mTrueJump->mIns.Size() == 2 && mTrueJump != this)
{
if (mTrueJump->mIns[0].IsSame(mIns[sz - 2]) && mTrueJump->mIns[1].IsSame(mIns[sz - 1]))
{
if (mBranch == mTrueJump->mBranch && mFalseJump == mTrueJump->mFalseJump && mTrueJump == mTrueJump->mTrueJump ||
mBranch == InvertBranchCondition(mTrueJump->mBranch) && mFalseJump == mTrueJump->mTrueJump && mTrueJump == mTrueJump->mFalseJump)
{
mIns[sz - 1].mType = ASMIT_NOP; mIns[sz - 1].mMode = ASMIM_IMPLIED;
mIns[sz - 2].mType = ASMIT_NOP; mIns[sz - 2].mMode = ASMIM_IMPLIED;
mBranch = ASMIT_JMP;
mFalseJump->RemEntryBlock(this);
mFalseJump = nullptr;
changed = true;
}
}
}
if (!changed && mFalseJump->mIns.Size() == 2 && mFalseJump != this)
{
if (mFalseJump->mIns[0].IsSame(mIns[sz - 2]) && mFalseJump->mIns[1].IsSame(mIns[sz - 1]))
{
if (mBranch == mFalseJump->mBranch && mFalseJump == mFalseJump->mFalseJump && mFalseJump == mTrueJump->mTrueJump ||
mBranch == InvertBranchCondition(mFalseJump->mBranch) && mFalseJump == mFalseJump->mTrueJump && mTrueJump == mFalseJump->mFalseJump)
{
mIns[sz - 1].mType = ASMIT_NOP;
mIns[sz - 1].mMode = ASMIM_IMPLIED;
mBranch = ASMIT_JMP;
mTrueJump->RemEntryBlock(this);
mTrueJump = mFalseJump;
mFalseJump = nullptr;
changed = true;
}
}
}
}
}
if (mTrueJump && mTrueJump->FoldLoopEntry())
changed = true;
@ -33930,6 +34002,17 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
progress = true;
}
#if 1
else if (
mIns[i + 0].mType == ASMIT_STX && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 1].IsShift() && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mAddress == mIns[i + 0].mAddress && !(mIns[i + 1].mLive & (LIVE_CPU_REG_A | LIVE_MEM)))
{
mIns[i + 0].mType = ASMIT_TXA; mIns[i + 0].mMode = ASMIM_IMPLIED; mIns[i + 0].mLive |= LIVE_CPU_REG_A;
mIns[i + 1].mMode = ASMIM_IMPLIED;
progress = true;
}
#endif
#if 0
else if (
mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_IMMEDIATE &&
@ -35476,6 +35559,16 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass
progress = true;
}
else if (
mIns[i + 0].mType == ASMIT_LDA &&
mIns[i + 1].IsShift() && mIns[i + 1].mMode == ASMIM_IMPLIED &&
mIns[i + 2].mType == mIns[i + 1].mType && mIns[i + 2].SameEffectiveAddress(mIns[i + 0]) &&
mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].SameEffectiveAddress(mIns[i + 0]))
{
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
mIns[i + 1].mLive |= LIVE_CPU_REG_C;
progress = true;
}
else if (
mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 2].mType == ASMIT_LDX && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress == mIns[i + 0].mAddress &&
@ -36743,7 +36836,7 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass
}
else if (
mIns[i + 0].mType == ASMIT_LDA && (mIns[i + 0].mMode == ASMIM_ZERO_PAGE || mIns[i + 0].mMode == ASMIM_ABSOLUTE) &&
mIns[i + 1].mType == ASMIT_TAX &&
mIns[i + 1].mType == ASMIT_TAX &&
mIns[i + 2].mType == ASMIT_CLC &&
mIns[i + 3].mType == ASMIT_ADC && mIns[i + 3].mMode == ASMIM_IMMEDIATE && mIns[i + 3].mAddress == 1 &&
mIns[i + 4].mType == ASMIT_STA && mIns[i + 0].SameEffectiveAddress(mIns[i + 4]) && !(mIns[i + 4].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z | LIVE_CPU_REG_C)))
@ -36798,7 +36891,7 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass
mIns.Insert(i, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_STA, ASMIM_ZERO_PAGE, a1));
mIns.Insert(i + 1, NativeCodeInstruction(mIns[i + 0].mIns, ASMIT_LDA, ASMIM_ZERO_PAGE, a0));
mIns[i + 2].mMode = ASMIM_IMPLIED;
mIns[i + 3].mMode = ASMIM_IMPLIED;
mIns[i + 4].mMode = ASMIM_IMPLIED;
@ -36807,6 +36900,22 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass
progress = true;
}
#endif
#if 1
else if (
mIns[i + 0].mType == ASMIT_AND && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress == 0x80 &&
mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress != mIns[i + 1].mAddress &&
mIns[i + 3].mType == ASMIT_LSR && mIns[i + 3].mMode == ASMIM_IMPLIED &&
mIns[i + 4].mType == ASMIT_ORA && mIns[i + 4].mMode == ASMIM_ZERO_PAGE && mIns[i + 4].mAddress == mIns[i + 1].mAddress && !(mIns[i + 4].mLive & (LIVE_CPU_REG_C | LIVE_MEM)))
{
mIns[i + 0].mType = ASMIT_ASL; mIns[i + 0].mMode = ASMIM_IMPLIED; mIns[i + 0].mLive |= LIVE_CPU_REG_C;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 2].mLive |= LIVE_CPU_REG_C;
mIns[i + 3].mType = ASMIT_ROR;
mIns[i + 4].mType = ASMIT_NOP; mIns[i + 4].mMode = ASMIM_IMPLIED;
progress = true;
}
#endif
#if 0
else if (
mIns[i + 0].mType == ASMIT_LDY && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
@ -38139,6 +38248,19 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass
changed = true;
}
else if (pass >= 7 && sz >= 1 &&
mIns[sz - 1].mType == ASMIT_AND && mIns[sz - 1].mMode == ASMIM_IMMEDIATE && mIns[sz - 1].mAddress == 0x40 && !(mIns[sz - 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)) &&
(mBranch == ASMIT_BEQ || mBranch == ASMIT_BNE) && !mExitRequiredRegs[CPU_REG_Z])
{
mIns[sz - 1].mType = ASMIT_ASL; mIns[sz - 1].mMode = ASMIM_IMPLIED;
if (mBranch == ASMIT_BEQ)
mBranch = ASMIT_BPL;
else
mBranch = ASMIT_BMI;
changed = true;
}
if (sz == 1 && mBranch == ASMIT_BNE && mTrueJump == this)
{
@ -38946,7 +39068,7 @@ void NativeCodeProcedure::Compile(InterCodeProcedure* proc)
{
mInterProc = proc;
CheckFunc = !strcmp(mInterProc->mIdent->mString, "fill_screen");
CheckFunc = !strcmp(mInterProc->mIdent->mString, "iec_read");
int nblocks = proc->mBlocks.Size();
tblocks = new NativeCodeBasicBlock * [nblocks];
@ -39596,7 +39718,6 @@ void NativeCodeProcedure::Optimize(void)
mEntryBlock->ReplaceFinalZeroPageUse(this);
}
#endif
int t = 0;
#if 1
do
@ -39785,8 +39906,6 @@ void NativeCodeProcedure::Optimize(void)
}
#endif
#if _DEBUG
ResetVisited();
mEntryBlock->CheckBlocks(true);
@ -40174,8 +40293,10 @@ void NativeCodeProcedure::Optimize(void)
else
cnt++;
} while (changed);
#if 1
ResetVisited();
mEntryBlock->ReduceLocalYPressure();

View File

@ -3988,7 +3988,6 @@ void Parser::ParsePragma(void)
}
else if (ConsumeIdentIf("optimize"))
{
mScanner->NextToken();
ConsumeToken(TK_OPEN_PARENTHESIS);
if (!ConsumeTokenIf(TK_CLOSE_PARENTHESIS))
{
@ -4026,6 +4025,7 @@ void Parser::ParsePragma(void)
default:
mErrors->Error(mScanner->mLocation, ERRR_INVALID_NUMBER, "Invalid number");
}
mScanner->NextToken();
}
else if (ConsumeIdentIf("asm"))
mCompilerOptions |= COPT_OPTIMIZE_ASSEMBLER;