diff --git a/include/crt.c b/include/crt.c index 6cbaf4c..745292d 100644 --- a/include/crt.c +++ b/include/crt.c @@ -4739,9 +4739,14 @@ __asm inp_free #pragma bytecode(BC_FREE, inp_free) +__asm breakpoint +{ + rts +} #pragma runtime(malloc, malloc) #pragma runtime(free, free) +#pragma runtime(breakpoint, breakpoint) #if 0 diff --git a/include/oscar.h b/include/oscar.h index 6101a06..2c988f0 100644 --- a/include/oscar.h +++ b/include/oscar.h @@ -11,6 +11,13 @@ __native const char * oscar_expand_rle(char * dp, const char * sp); // memory as buffer __native const char * oscar_expand_lzo_buf(char * dp, const char * sp); +// Write a breakpoint instruction into the .lbl file for vice. This +// intrinsic function will change the behaviour of the optimizer to ensure +// that the breakpoint is not move around into wild places. +void breakpoint(void); + +#pragma intrinsic(breakpoint) + #pragma compile("oscar.c") #endif diff --git a/oscar64/Compiler.cpp b/oscar64/Compiler.cpp index 3b79ee7..83c84b2 100644 --- a/oscar64/Compiler.cpp +++ b/oscar64/Compiler.cpp @@ -961,6 +961,7 @@ bool Compiler::GenerateCode(void) RegisterRuntime(loc, Ident::Unique("malloc")); RegisterRuntime(loc, Ident::Unique("free")); + RegisterRuntime(loc, Ident::Unique("breakpoint")); } // Register extended byte code functions diff --git a/oscar64/Declaration.cpp b/oscar64/Declaration.cpp index 60d93c6..4109c61 100644 --- a/oscar64/Declaration.cpp +++ b/oscar64/Declaration.cpp @@ -1037,7 +1037,7 @@ Expression* Expression::ConstantFold(Errors * errors, LinkerSection * dataSectio ex->mDecType = mDecType; return ex; } - else if (mType == EX_CALL && mLeft->mType == EX_CONSTANT && (mLeft->mDecValue->mFlags & DTF_INTRINSIC) && mRight->mType == EX_CONSTANT) + else if (mType == EX_CALL && mLeft->mType == EX_CONSTANT && (mLeft->mDecValue->mFlags & DTF_INTRINSIC) && mRight && mRight->mType == EX_CONSTANT) { Declaration* decf = mLeft->mDecValue, * decp = mRight->mDecValue; const Ident* iname = decf->mQualIdent; diff --git a/oscar64/InterCode.cpp b/oscar64/InterCode.cpp index 83a625c..fc87337 100644 --- a/oscar64/InterCode.cpp +++ b/oscar64/InterCode.cpp @@ -1698,12 +1698,12 @@ void ValueSet::InsertValue(InterInstruction * ins) static bool HasSideEffect(InterCode code) { - return code == IC_CALL || code == IC_CALL_NATIVE || code == IC_ASSEMBLER || code == IC_DISPATCH /* || code == IC_MALLOC || code == IC_FREE */; + return code == IC_CALL || code == IC_CALL_NATIVE || code == IC_ASSEMBLER || code == IC_DISPATCH || code == IC_BREAKPOINT;/* || code == IC_MALLOC || code == IC_FREE */; } static bool IsObservable(InterCode code) { - return code == IC_CALL || code == IC_CALL_NATIVE || code == IC_ASSEMBLER || code == IC_DISPATCH || code == IC_STORE || code == IC_COPY || code == IC_STRCPY || code == IC_FILL || code == IC_MALLOC || code == IC_FREE; + return code == IC_CALL || code == IC_CALL_NATIVE || code == IC_ASSEMBLER || code == IC_DISPATCH || code == IC_STORE || code == IC_COPY || code == IC_STRCPY || code == IC_FILL || code == IC_MALLOC || code == IC_FREE || code == IC_BREAKPOINT; } static bool IsMoveable(InterCode code) @@ -5389,6 +5389,9 @@ void InterInstruction::Disassemble(FILE* file, InterCodeProcedure* proc) case IC_UNREACHABLE: fprintf(file, "UNREACHABLE"); break; + case IC_BREAKPOINT: + fprintf(file, "BREAKPOINT"); + break; } static char typechars[] = "NBCILFP"; diff --git a/oscar64/InterCode.h b/oscar64/InterCode.h index 91ecf2d..ee4b39f 100644 --- a/oscar64/InterCode.h +++ b/oscar64/InterCode.h @@ -42,7 +42,8 @@ enum InterCode IC_JUMPF, IC_SELECT, IC_DISPATCH, - IC_UNREACHABLE + IC_UNREACHABLE, + IC_BREAKPOINT }; enum InterType diff --git a/oscar64/InterCodeGenerator.cpp b/oscar64/InterCodeGenerator.cpp index f2bd4bd..015d3e0 100644 --- a/oscar64/InterCodeGenerator.cpp +++ b/oscar64/InterCodeGenerator.cpp @@ -3436,6 +3436,14 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* else if (!strcmp(iname->mString, "exp")) { } + else if (!strcmp(iname->mString, "breakpoint")) + { + InterInstruction* ins = new InterInstruction(MapLocation(exp, inlineMapper), IC_BREAKPOINT); + ins->mNumOperands = 0; + block->Append(ins); + + return ExValue(TheVoidTypeDeclaration, 0); + } else if (!strcmp(iname->mString, "malloc")) { vr = TranslateExpression(procType, proc, block, exp->mRight, destack, gotos, breakBlock, continueBlock, inlineMapper); diff --git a/oscar64/Linker.cpp b/oscar64/Linker.cpp index 051531b..eb1c118 100644 --- a/oscar64/Linker.cpp +++ b/oscar64/Linker.cpp @@ -137,7 +137,7 @@ LinkerOverlay::~LinkerOverlay(void) } Linker::Linker(Errors* errors) - : mErrors(errors), mSections(nullptr), mReferences(nullptr), mObjects(nullptr), mRegions(nullptr), mOverlays(nullptr), mCompilerOptions(COPT_DEFAULT) + : mErrors(errors), mSections(nullptr), mReferences(nullptr), mObjects(nullptr), mRegions(nullptr), mOverlays(nullptr), mBreakpoints(0), mCompilerOptions(COPT_DEFAULT) { for (int i = 0; i < 64; i++) { @@ -850,6 +850,32 @@ void Linker::CopyObjects(bool inlays) } } +void Linker::CollectBreakpoints(void) +{ + for (int i = 0; i < mReferences.Size(); i++) + { + LinkerReference* ref = mReferences[i]; + if (ref->mFlags & LREF_BREAKPOINT) + { + LinkerObject* obj = ref->mObject; + if (obj->mFlags & LOBJF_REFERENCED) + { + if (obj->mRegion) + { + if (obj->mRegion->mCartridgeBanks) + { + } + else + { + mBreakpoints.Push(obj->mAddress + ref->mOffset); + } + } + } + } + } + +} + void Linker::PatchReferences(bool inlays) { for (int i = 0; i < mReferences.Size(); i++) @@ -1119,6 +1145,7 @@ void Linker::Link(void) CopyObjects(false); PatchReferences(false); + CollectBreakpoints(); for (int i = 0; i < mObjects.Size(); i++) { @@ -1866,6 +1893,11 @@ bool Linker::WriteLblFile(const char* filename) } } + for (int i = 0; i < mBreakpoints.Size(); i++) + { + fprintf(file, "break %04x\n", mBreakpoints[i]); + } + fclose(file); return true; diff --git a/oscar64/Linker.h b/oscar64/Linker.h index 3deb140..f02108a 100644 --- a/oscar64/Linker.h +++ b/oscar64/Linker.h @@ -110,6 +110,7 @@ static const uint32 LREF_HIGHBYTE = 0x00000002; static const uint32 LREF_TEMPORARY = 0x00000004; static const uint32 LREF_INBLOCK = 0x00000008; static const uint32 LREF_LOWBYTE_OFFSET = 0x00000010; +static const uint32 LREF_BREAKPOINT = 0x00000020; class LinkerReference { @@ -292,6 +293,7 @@ public: GrowingArray mSections; GrowingArray mObjects; GrowingArray mOverlays; + GrowingArray mBreakpoints; uint8 mMemory[0x10000], mWorkspace[0x10000]; uint8 mCartridge[64][0x10000]; @@ -312,6 +314,7 @@ public: void CopyObjects(bool inlays); void PlaceObjects(bool retry); void Link(void); + void CollectBreakpoints(void); protected: NativeCodeDisassembler mNativeDisassembler; ByteCodeDisassembler mByteCodeDisassembler; diff --git a/oscar64/NativeCodeGenerator.cpp b/oscar64/NativeCodeGenerator.cpp index db21363..dd4970d 100644 --- a/oscar64/NativeCodeGenerator.cpp +++ b/oscar64/NativeCodeGenerator.cpp @@ -4884,6 +4884,17 @@ void NativeCodeInstruction::Assemble(NativeCodeBasicBlock* block) if (mType == ASMIT_BYTE) block->PutByte(mAddress); + else if (mType == ASMIT_JSR && (mFlags & NCIF_BREAKPOINT)) + { + LinkerReference rl; + rl.mOffset = block->mCode.Size(); + + rl.mRefObject = nullptr; + rl.mRefOffset = 0; + rl.mFlags = LREF_BREAKPOINT; + + block->mRelocations.Push(rl); + } else if (mType == ASMIT_JSR && mLinkerObject && (mLinkerObject->mFlags & LOBJF_INLINE)) { int pos = block->mCode.Size(); @@ -52564,6 +52575,11 @@ void NativeCodeProcedure::CompileInterBlock(InterCodeProcedure* iproc, InterCode case IC_FREE: block->CallFree(iproc, ins, this); break; + case IC_BREAKPOINT: + { + NativeCodeGenerator::Runtime& frt(mGenerator->ResolveRuntime(Ident::Unique("breakpoint"))); + block->mIns.Push(NativeCodeInstruction(ins, ASMIT_JSR, ASMIM_ABSOLUTE, frt.mOffset, frt.mLinkerObject, NCIF_LOWER | NCIF_UPPER | NCIF_VOLATILE | NCIF_BREAKPOINT)); + } break; case IC_LOAD_TEMPORARY: { diff --git a/oscar64/NativeCodeGenerator.h b/oscar64/NativeCodeGenerator.h index d289348..539098a 100644 --- a/oscar64/NativeCodeGenerator.h +++ b/oscar64/NativeCodeGenerator.h @@ -133,6 +133,8 @@ static const uint32 NCIF_USE_ZP_32_X = 0x00008000; static const uint32 NICF_USE_ZP_ADDR = 0x00010000; static const uint32 NICF_USE_WORKREGS = 0x00020000; +static const uint32 NCIF_BREAKPOINT = 0x00040000; + class NativeCodeInstruction { public: