mirror of
https://github.com/irmen/prog8.git
synced 2024-09-06 12:54:36 +00:00
added memory() function for memory slab allocations
This commit is contained in:
parent
3b8e18004c
commit
b40e1eabb9
@ -964,11 +964,14 @@ internal class AstChecker(private val program: Program,
|
|||||||
val targetStatement = checkFunctionOrLabelExists(functionCallStatement.target, functionCallStatement)
|
val targetStatement = checkFunctionOrLabelExists(functionCallStatement.target, functionCallStatement)
|
||||||
if(targetStatement!=null)
|
if(targetStatement!=null)
|
||||||
checkFunctionCall(targetStatement, functionCallStatement.args, functionCallStatement.position)
|
checkFunctionCall(targetStatement, functionCallStatement.args, functionCallStatement.position)
|
||||||
if(!functionCallStatement.void && targetStatement is Subroutine && targetStatement.returntypes.isNotEmpty()) {
|
if (!functionCallStatement.void) {
|
||||||
if(targetStatement.returntypes.size==1)
|
// check for unused return values
|
||||||
errors.warn("result value of subroutine call is discarded (use void?)", functionCallStatement.position)
|
if (targetStatement is Subroutine && targetStatement.returntypes.isNotEmpty()) {
|
||||||
else
|
if(targetStatement.returntypes.size==1)
|
||||||
errors.warn("result values of subroutine call are discarded (use void?)", functionCallStatement.position)
|
errors.warn("result value of subroutine call is discarded (use void?)", functionCallStatement.position)
|
||||||
|
else
|
||||||
|
errors.warn("result values of subroutine call are discarded (use void?)", functionCallStatement.position)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(functionCallStatement.target.nameInSource.last() == "sort") {
|
if(functionCallStatement.target.nameInSource.last() == "sort") {
|
||||||
|
@ -697,6 +697,7 @@ class AsmGenInfo {
|
|||||||
var usedRegsaveY = false
|
var usedRegsaveY = false
|
||||||
var usedFloatEvalResultVar1 = false
|
var usedFloatEvalResultVar1 = false
|
||||||
var usedFloatEvalResultVar2 = false
|
var usedFloatEvalResultVar2 = false
|
||||||
|
val removals = mutableListOf<Statement>()
|
||||||
|
|
||||||
class ArrayIndexerInfo(val name: String, val replaces: ArrayIndex)
|
class ArrayIndexerInfo(val name: String, val replaces: ArrayIndex)
|
||||||
}
|
}
|
||||||
|
@ -50,6 +50,7 @@ internal class AsmGen(private val program: Program,
|
|||||||
private val assignmentAsmGen = AssignmentAsmGen(program, this, expressionsAsmGen)
|
private val assignmentAsmGen = AssignmentAsmGen(program, this, expressionsAsmGen)
|
||||||
internal val loopEndLabels = ArrayDeque<String>()
|
internal val loopEndLabels = ArrayDeque<String>()
|
||||||
private val blockLevelVarInits = mutableMapOf<Block, MutableSet<VarDecl>>()
|
private val blockLevelVarInits = mutableMapOf<Block, MutableSet<VarDecl>>()
|
||||||
|
internal val slabs = mutableMapOf<String, Int>()
|
||||||
|
|
||||||
override fun compileToAssembly(): IAssemblyProgram {
|
override fun compileToAssembly(): IAssemblyProgram {
|
||||||
assemblyLines.clear()
|
assemblyLines.clear()
|
||||||
@ -63,6 +64,7 @@ internal class AsmGen(private val program: Program,
|
|||||||
throw AssemblyError("first block should be 'main'")
|
throw AssemblyError("first block should be 'main'")
|
||||||
for(b in program.allBlocks())
|
for(b in program.allBlocks())
|
||||||
block2asm(b)
|
block2asm(b)
|
||||||
|
slaballocations()
|
||||||
footer()
|
footer()
|
||||||
|
|
||||||
val outputFile = outputDir.resolve("${program.name}.asm").toFile()
|
val outputFile = outputDir.resolve("${program.name}.asm").toFile()
|
||||||
@ -152,6 +154,14 @@ internal class AsmGen(private val program: Program,
|
|||||||
out(" jmp main.start ; start program / force start proc to be included")
|
out(" jmp main.start ; start program / force start proc to be included")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun slaballocations() {
|
||||||
|
out("; memory slabs")
|
||||||
|
out("prog8_slabs\t.block")
|
||||||
|
for((name, size) in slabs)
|
||||||
|
out("$name\t.fill $size")
|
||||||
|
out("\t.bend")
|
||||||
|
}
|
||||||
|
|
||||||
private fun footer() {
|
private fun footer() {
|
||||||
// the global list of all floating point constants for the whole program
|
// the global list of all floating point constants for the whole program
|
||||||
out("; global float constants")
|
out("; global float constants")
|
||||||
@ -834,6 +844,12 @@ internal class AsmGen(private val program: Program,
|
|||||||
|
|
||||||
out("; statements")
|
out("; statements")
|
||||||
sub.statements.forEach{ translate(it) }
|
sub.statements.forEach{ translate(it) }
|
||||||
|
|
||||||
|
for(stmt in sub.asmGenInfo.removals) {
|
||||||
|
sub.remove(stmt)
|
||||||
|
}
|
||||||
|
sub.asmGenInfo.removals.clear()
|
||||||
|
|
||||||
out("; variables")
|
out("; variables")
|
||||||
out("; register saves")
|
out("; register saves")
|
||||||
if(sub.asmGenInfo.usedRegsaveA)
|
if(sub.asmGenInfo.usedRegsaveA)
|
||||||
|
@ -108,10 +108,40 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
|
|||||||
else
|
else
|
||||||
asmgen.out(" lda #<prog8_program_end | ldy #>prog8_program_end")
|
asmgen.out(" lda #<prog8_program_end | ldy #>prog8_program_end")
|
||||||
}
|
}
|
||||||
|
"memory" -> funcMemory(fcall, discardResult, resultToStack)
|
||||||
else -> TODO("missing asmgen for builtin func ${func.name}")
|
else -> TODO("missing asmgen for builtin func ${func.name}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun funcMemory(fcall: IFunctionCall, discardResult: Boolean, resultToStack: Boolean) {
|
||||||
|
if(discardResult || fcall !is FunctionCall)
|
||||||
|
throw AssemblyError("should not discard result of memory allocation at $fcall")
|
||||||
|
val scope = fcall.definingScope()
|
||||||
|
val nameRef = fcall.args[0] as IdentifierReference
|
||||||
|
val name = (nameRef.targetVarDecl(program.namespace)!!.value as StringLiteralValue).value
|
||||||
|
val size = (fcall.args[1] as NumericLiteralValue).number.toInt()
|
||||||
|
|
||||||
|
val existingSize = asmgen.slabs[name]
|
||||||
|
if(existingSize!=null && existingSize!=size)
|
||||||
|
throw AssemblyError("memory slab '$name' already exists with a different size ($size) at ${fcall.position}")
|
||||||
|
|
||||||
|
val slabname = IdentifierReference(listOf("prog8_slabs", name), fcall.position)
|
||||||
|
slabname.linkParents(fcall)
|
||||||
|
val src = AsmAssignSource(SourceStorageKind.EXPRESSION, program, asmgen, DataType.UWORD, expression = AddressOf(slabname, fcall.position))
|
||||||
|
val target =
|
||||||
|
if(resultToStack)
|
||||||
|
AsmAssignTarget(TargetStorageKind.STACK, program, asmgen, DataType.UWORD, null)
|
||||||
|
else
|
||||||
|
AsmAssignTarget.fromRegisters(RegisterOrPair.AY, null, program, asmgen)
|
||||||
|
val assign = AsmAssignment(src, target, false, fcall.position)
|
||||||
|
asmgen.translateNormalAssignment(assign)
|
||||||
|
|
||||||
|
// remove the variable for the name, it's not used as a variable only as a tag for the assembler.
|
||||||
|
val nameDecl = scope.statements.single { it is VarDecl && it.name==nameRef.nameInSource.single() }
|
||||||
|
(scope as Subroutine).asmGenInfo.removals.add(nameDecl)
|
||||||
|
asmgen.slabs[name] = size
|
||||||
|
}
|
||||||
|
|
||||||
private fun funcMemSetCopy(fcall: IFunctionCall, func: FSignature, scope: Subroutine) {
|
private fun funcMemSetCopy(fcall: IFunctionCall, func: FSignature, scope: Subroutine) {
|
||||||
if(CompilationTarget.instance is Cx16Target) {
|
if(CompilationTarget.instance is Cx16Target) {
|
||||||
when(func.name) {
|
when(func.name) {
|
||||||
|
@ -143,10 +143,11 @@ private val functionSignatures: List<FSignature> = listOf(
|
|||||||
FSignature("clear_carry" , false, emptyList(), null),
|
FSignature("clear_carry" , false, emptyList(), null),
|
||||||
FSignature("set_irqd" , false, emptyList(), null),
|
FSignature("set_irqd" , false, emptyList(), null),
|
||||||
FSignature("clear_irqd" , false, emptyList(), null),
|
FSignature("clear_irqd" , false, emptyList(), null),
|
||||||
FSignature("read_flags" , false, emptyList(), DataType.UBYTE),
|
FSignature("read_flags" , true, emptyList(), DataType.UBYTE),
|
||||||
FSignature("progend" , true, emptyList(), DataType.UWORD),
|
FSignature("progend" , true, emptyList(), DataType.UWORD),
|
||||||
FSignature("target" , true, emptyList(), DataType.UBYTE, ::builtinTarget),
|
FSignature("target" , true, emptyList(), DataType.UBYTE, ::builtinTarget),
|
||||||
FSignature("swap" , false, listOf(FParam("first", NumericDatatypes), FParam("second", NumericDatatypes)), null),
|
FSignature("swap" , false, listOf(FParam("first", NumericDatatypes), FParam("second", NumericDatatypes)), null),
|
||||||
|
FSignature("memory" , false, listOf(FParam("name", setOf(DataType.STR)), FParam("size", setOf(DataType.UWORD))), DataType.UWORD),
|
||||||
FSignature("memcopy" , false, listOf(
|
FSignature("memcopy" , false, listOf(
|
||||||
FParam("from", IterableDatatypes + DataType.UWORD),
|
FParam("from", IterableDatatypes + DataType.UWORD),
|
||||||
FParam("to", IterableDatatypes + DataType.UWORD),
|
FParam("to", IterableDatatypes + DataType.UWORD),
|
||||||
|
@ -931,6 +931,14 @@ target()
|
|||||||
- 16 = compiled for CommanderX16 with 65C02 CPU
|
- 16 = compiled for CommanderX16 with 65C02 CPU
|
||||||
- 64 = compiled for Commodore-64 with 6502/6510 CPU
|
- 64 = compiled for Commodore-64 with 6502/6510 CPU
|
||||||
|
|
||||||
|
memory(name, size)
|
||||||
|
Statically allocates a fixed portion of memory of the given size in bytes, and returns its address.
|
||||||
|
Slabs are considered identical if their name and size are the same.
|
||||||
|
This can be used to allocate parts of the memory where a normal byte array would
|
||||||
|
not suffice for instance if you need more than 256 bytes, and/or don't want to work
|
||||||
|
with fixed memory addresses for buffers.
|
||||||
|
The portion of memory cannot be used as an array, you only have the address of the first byte.
|
||||||
|
|
||||||
progend()
|
progend()
|
||||||
Returns the last address of the program in memory + 1.
|
Returns the last address of the program in memory + 1.
|
||||||
Can be used to load dynamic data after the program, instead of hardcoding something.
|
Can be used to load dynamic data after the program, instead of hardcoding something.
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
TODO
|
TODO
|
||||||
====
|
====
|
||||||
|
|
||||||
|
- detect variables that are written but never read - mark those as unused too and remove them, such as uword unused = memory("unused222", 20) - also remove the memory slab allocation
|
||||||
- hoist all variable declarations up to the subroutine scope *before* even the constant folding takes place (to avoid undefined symbol errors when referring to a variable from another nested scope in the subroutine)
|
- hoist all variable declarations up to the subroutine scope *before* even the constant folding takes place (to avoid undefined symbol errors when referring to a variable from another nested scope in the subroutine)
|
||||||
- make it possible to use cpu opcodes such as 'nop' as variable names by prefixing all asm vars with something such as '_'
|
- make it possible to use cpu opcodes such as 'nop' as variable names by prefixing all asm vars with something such as '_'
|
||||||
- option to load the built-in library files from a directory instead of the embedded ones (for easier library development/debugging)
|
- option to load the built-in library files from a directory instead of the embedded ones (for easier library development/debugging)
|
||||||
|
@ -1,19 +1,42 @@
|
|||||||
;%import test_stack
|
%import test_stack
|
||||||
;%import textio
|
%import textio
|
||||||
%import gfx2
|
|
||||||
%zeropage basicsafe
|
%zeropage basicsafe
|
||||||
%option no_sysinit
|
%option no_sysinit
|
||||||
|
|
||||||
main {
|
main {
|
||||||
|
|
||||||
sub start () {
|
sub start () {
|
||||||
; txt.lowercase()
|
|
||||||
; txt.print_ub(txt.width())
|
thing()
|
||||||
; txt.chrout('\n')
|
thing()
|
||||||
; txt.print_ub(txt.height())
|
thing()
|
||||||
; txt.chrout('\n')
|
thing()
|
||||||
gfx2.text(0,0,2, "sdafsdf")
|
thing()
|
||||||
; test_stack.test()
|
test_stack.test()
|
||||||
|
|
||||||
|
sub thing() -> ubyte {
|
||||||
|
uword buffer = memory("buffer", 512)
|
||||||
|
uword buffer2 = memory("buffer", 512)
|
||||||
|
uword buffer3 = memory("cache", 20)
|
||||||
|
|
||||||
|
txt.print_uwhex(buffer, true)
|
||||||
|
txt.chrout('\n')
|
||||||
|
txt.print_uwhex(buffer2, true)
|
||||||
|
txt.chrout('\n')
|
||||||
|
txt.print_uwhex(buffer3, true)
|
||||||
|
txt.chrout('\n')
|
||||||
|
buffer+=$1111
|
||||||
|
buffer2+=$1111
|
||||||
|
buffer3+=$1111
|
||||||
|
txt.print_uwhex(buffer, true)
|
||||||
|
txt.chrout('\n')
|
||||||
|
txt.print_uwhex(buffer2, true)
|
||||||
|
txt.chrout('\n')
|
||||||
|
txt.print_uwhex(buffer3, true)
|
||||||
|
txt.chrout('\n')
|
||||||
|
txt.chrout('\n')
|
||||||
|
return 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -11,10 +11,10 @@
|
|||||||
<option name="HAS_PARENS" value="true" />
|
<option name="HAS_PARENS" value="true" />
|
||||||
<option name="HAS_STRING_ESCAPES" value="true" />
|
<option name="HAS_STRING_ESCAPES" value="true" />
|
||||||
</options>
|
</options>
|
||||||
<keywords keywords="&;->;@;\$;and;as;asmsub;break;clobbers;continue;do;downto;else;false;for;goto;if;if_cc;if_cs;if_eq;if_mi;if_ne;if_neg;if_nz;if_pl;if_pos;if_vc;if_vs;if_z;in;not;or;repeat;return;romsub;step;sub;to;true;until;when;while;xor;~" ignore_case="false" />
|
<keywords keywords="&;->;@;\$;and;as;asmsub;break;clobbers;continue;do;downto;else;false;for;goto;if;if_cc;if_cs;if_eq;if_mi;if_ne;if_neg;if_nz;if_pl;if_pos;if_vc;if_vs;if_z;in;inline;not;or;repeat;return;romsub;step;sub;to;true;until;when;while;xor;~" ignore_case="false" />
|
||||||
<keywords2 keywords="%address;%asm;%asmbinary;%asminclude;%breakpoint;%import;%launcher;%option;%output;%target;%zeropage;%zpreserved" />
|
<keywords2 keywords="%address;%asm;%asmbinary;%asminclude;%breakpoint;%import;%launcher;%option;%output;%target;%zeropage;%zpreserved" />
|
||||||
<keywords3 keywords="byte;const;float;str;struct;ubyte;uword;void;word;zp" />
|
<keywords3 keywords="byte;const;float;str;struct;ubyte;uword;void;word;zp" />
|
||||||
<keywords4 keywords="abs;acos;all;any;asin;atan;avg;ceil;clear_carry;clear_irqd;cos;cos16;cos16u;cos8;cos8u;deg;exit;floor;leftstr;len;ln;log2;lsb;lsl;lsr;max;memcopy;memset;memsetw;min;mkword;msb;progend;rad;read_flags;reverse;rightstr;rnd;rndf;rndw;rol;rol2;ror;ror2;round;rrestore;rsave;set_carry;set_irqd;sgn;sin;sin16;sin16u;sin8;sin8u;sizeof;sort;sqrt;sqrt16;strcmp;strlen;substr;sum;swap;tan" />
|
<keywords4 keywords="abs;acos;all;any;asin;atan;avg;ceil;clear_carry;clear_irqd;cos;cos16;cos16u;cos8;cos8u;deg;exit;floor;leftstr;len;ln;log2;lsb;lsl;lsr;max;memcopy;memory;memset;memsetw;min;mkword;msb;progend;rad;read_flags;reverse;rightstr;rnd;rndf;rndw;rol;rol2;ror;ror2;round;rrestore;rsave;set_carry;set_irqd;sgn;sin;sin16;sin16u;sin8;sin8u;sizeof;sort;sqrt;sqrt16;strcmp;strcopy;strlen;substr;sum;swap;tan;target" />
|
||||||
</highlighting>
|
</highlighting>
|
||||||
<extensionMap>
|
<extensionMap>
|
||||||
<mapping ext="p8" />
|
<mapping ext="p8" />
|
||||||
|
Loading…
Reference in New Issue
Block a user