Improve inline assembler parser
This commit is contained in:
parent
0e59af5122
commit
d493bddf8d
92
README.md
92
README.md
|
@ -49,7 +49,6 @@ After four weeks, the compiler has now matured significantly. There are still s
|
|||
|
||||
* Simple loop opmtimization
|
||||
* Partial block domination analysis
|
||||
* No register use for arguments
|
||||
* Auto variables placed on fixed stack for known call sequence
|
||||
|
||||
### Intermediate code generation
|
||||
|
@ -77,7 +76,98 @@ The compiler is command line driven, and creates an executable .prg file.
|
|||
|
||||
A list of source files can be provided.
|
||||
|
||||
## Inline Assembler
|
||||
|
||||
Inline assembler can be embedded inside of any functions, regardles of their compilation target of byte code or native.
|
||||
|
||||
### Accessing variables in assembler
|
||||
|
||||
Access to local variables and parameters is done with zero page registers, global variables are accessed using absolute addressing.
|
||||
|
||||
void putchar(char c)
|
||||
{
|
||||
__asm {
|
||||
lda c
|
||||
bne w1
|
||||
lda #13
|
||||
w1:
|
||||
jsr 0xffd2
|
||||
}
|
||||
}
|
||||
|
||||
A function return value can be provided in the zero page addresses ACCU (+0..+3).
|
||||
|
||||
char getchar(void)
|
||||
{
|
||||
__asm {
|
||||
jsr 0xffcf
|
||||
sta accu
|
||||
lda #0
|
||||
sta accu + 1
|
||||
}
|
||||
}
|
||||
|
||||
Labels are defined with a colon after the name. Pure assembler functions can be defined outside of the scope of a function and accessed using their name inside of other assembler function. One can e.g. set up an interrupt
|
||||
|
||||
### Interrupt routines
|
||||
|
||||
The C compiler will not generate good interrupt code, it is simply too greedy with the zero page registers. Interrupt code should therefore be written in assembler.
|
||||
|
||||
|
||||
#include <math.h>
|
||||
|
||||
// Next line for interrupt
|
||||
char npos;
|
||||
|
||||
// Interrupt routine
|
||||
__asm irq
|
||||
{
|
||||
lda $d019 // Check if it is raster IRQ
|
||||
and #$01
|
||||
beq w1
|
||||
|
||||
inc $d020 // Start colored section
|
||||
inc $d021
|
||||
|
||||
ldx #20 // Wait for 2/3 lines
|
||||
l1: dex
|
||||
bne l1
|
||||
|
||||
dec $d020 // End colored section
|
||||
dec $d021
|
||||
|
||||
lda npos // Setup next interrupt
|
||||
sta $d012
|
||||
w1:
|
||||
asl $d019 // Ack interrupt
|
||||
|
||||
jmp $ea31 // System IRQ routine
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
__asm { sei } // Disable interrupt
|
||||
|
||||
|
||||
*(void **)0x0314 = irq; // Install interrupt routine
|
||||
*(char *)0xd01a = 1; // Enable raster interrupt
|
||||
*(char *)0xd011 &= 0x7f; // Set raster line for IRQ
|
||||
*(char *)0xd012 = 100;
|
||||
|
||||
npos = 100;
|
||||
|
||||
__asm { cli } // Re-enable interrupt
|
||||
|
||||
// Move the interrupt raster line up/down
|
||||
float f = 0;
|
||||
while (true)
|
||||
{
|
||||
npos = 130 + (int)(100 * sin(f));
|
||||
f += 0.1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
## Implementation Details
|
||||
|
||||
|
|
|
@ -668,6 +668,23 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration*
|
|||
|
||||
} break;
|
||||
|
||||
case DT_CONST_ASSEMBLER:
|
||||
{
|
||||
if (!dec->mLinkerObject)
|
||||
TranslateAssembler(proc->mModule, dec->mValue, nullptr);
|
||||
|
||||
InterInstruction* ins = new InterInstruction();
|
||||
ins->mCode = IC_CONSTANT;
|
||||
ins->mDst.mType = IT_POINTER;
|
||||
ins->mDst.mTemp = proc->AddTemporary(ins->mDst.mType);
|
||||
ins->mConst.mVarIndex = dec->mVarIndex;
|
||||
ins->mConst.mLinkerObject = dec->mLinkerObject;
|
||||
ins->mConst.mMemory = IM_PROCEDURE;
|
||||
ins->mConst.mIntConst = 0;
|
||||
block->Append(ins);
|
||||
return ExValue(TheVoidPointerTypeDeclaration, ins->mDst.mTemp);
|
||||
}
|
||||
|
||||
case DT_CONST_POINTER:
|
||||
{
|
||||
vl = TranslateExpression(procType, proc, block, dec->mValue, breakBlock, continueBlock, inlineMapper);
|
||||
|
|
|
@ -1991,6 +1991,17 @@ Expression* Parser::ParseAssemblerBaseOperand(void)
|
|||
else
|
||||
mErrors->Error(mScanner->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Identifier for qualification expected");
|
||||
}
|
||||
|
||||
if (exp->mDecValue->mType == DT_CONST_ASSEMBLER)
|
||||
{
|
||||
Declaration* ndec = new Declaration(mScanner->mLocation, DT_LABEL);
|
||||
ndec->mIdent = exp->mDecValue->mIdent;
|
||||
ndec->mBase = exp->mDecValue;
|
||||
ndec->mInteger = 0;
|
||||
exp->mDecValue = ndec;
|
||||
exp->mDecType = TheUnsignedIntTypeDeclaration;
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
mErrors->Error(mScanner->mLocation, EERR_ASM_INVALD_OPERAND, "Invalid assembler operand");
|
||||
|
@ -2286,7 +2297,7 @@ Expression* Parser::ParseAssembler(void)
|
|||
{
|
||||
ilast->mAsmInsType = ins;
|
||||
mScanner->NextToken();
|
||||
if (mScanner->mToken == TK_EOL)
|
||||
if (mScanner->mToken == TK_EOL || mScanner->mToken == TK_CLOSE_BRACE)
|
||||
ilast->mAsmInsMode = ASMIM_IMPLIED;
|
||||
else if (mScanner->mToken == TK_HASH)
|
||||
{
|
||||
|
@ -2382,12 +2393,12 @@ Expression* Parser::ParseAssembler(void)
|
|||
if (ilast->mAsmInsType == ASMIT_BYTE)
|
||||
ilast->mAsmInsMode = ASMIM_IMMEDIATE;
|
||||
|
||||
if (mScanner->mToken != TK_EOL)
|
||||
if (mScanner->mToken != TK_EOL && mScanner->mToken != TK_CLOSE_BRACE)
|
||||
{
|
||||
mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "End of line expected");
|
||||
}
|
||||
|
||||
while (mScanner->mToken != TK_EOL && mScanner->mToken != TK_EOF)
|
||||
while (mScanner->mToken != TK_EOL && mScanner->mToken != TK_EOF && mScanner->mToken != TK_CLOSE_BRACE)
|
||||
mScanner->NextToken();
|
||||
|
||||
offset += AsmInsSize(ilast->mAsmInsType, ilast->mAsmInsMode);
|
||||
|
|
Loading…
Reference in New Issue