mirror of
https://github.com/irmen/prog8.git
synced 2025-01-11 13:29:45 +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)
|
||||
if(targetStatement!=null)
|
||||
checkFunctionCall(targetStatement, functionCallStatement.args, functionCallStatement.position)
|
||||
if(!functionCallStatement.void && targetStatement is Subroutine && targetStatement.returntypes.isNotEmpty()) {
|
||||
if(targetStatement.returntypes.size==1)
|
||||
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.void) {
|
||||
// check for unused return values
|
||||
if (targetStatement is Subroutine && targetStatement.returntypes.isNotEmpty()) {
|
||||
if(targetStatement.returntypes.size==1)
|
||||
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") {
|
||||
|
@ -697,6 +697,7 @@ class AsmGenInfo {
|
||||
var usedRegsaveY = false
|
||||
var usedFloatEvalResultVar1 = false
|
||||
var usedFloatEvalResultVar2 = false
|
||||
val removals = mutableListOf<Statement>()
|
||||
|
||||
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)
|
||||
internal val loopEndLabels = ArrayDeque<String>()
|
||||
private val blockLevelVarInits = mutableMapOf<Block, MutableSet<VarDecl>>()
|
||||
internal val slabs = mutableMapOf<String, Int>()
|
||||
|
||||
override fun compileToAssembly(): IAssemblyProgram {
|
||||
assemblyLines.clear()
|
||||
@ -63,6 +64,7 @@ internal class AsmGen(private val program: Program,
|
||||
throw AssemblyError("first block should be 'main'")
|
||||
for(b in program.allBlocks())
|
||||
block2asm(b)
|
||||
slaballocations()
|
||||
footer()
|
||||
|
||||
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")
|
||||
}
|
||||
|
||||
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() {
|
||||
// the global list of all floating point constants for the whole program
|
||||
out("; global float constants")
|
||||
@ -834,6 +844,12 @@ internal class AsmGen(private val program: Program,
|
||||
|
||||
out("; statements")
|
||||
sub.statements.forEach{ translate(it) }
|
||||
|
||||
for(stmt in sub.asmGenInfo.removals) {
|
||||
sub.remove(stmt)
|
||||
}
|
||||
sub.asmGenInfo.removals.clear()
|
||||
|
||||
out("; variables")
|
||||
out("; register saves")
|
||||
if(sub.asmGenInfo.usedRegsaveA)
|
||||
|
@ -108,10 +108,40 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
|
||||
else
|
||||
asmgen.out(" lda #<prog8_program_end | ldy #>prog8_program_end")
|
||||
}
|
||||
"memory" -> funcMemory(fcall, discardResult, resultToStack)
|
||||
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) {
|
||||
if(CompilationTarget.instance is Cx16Target) {
|
||||
when(func.name) {
|
||||
|
@ -143,10 +143,11 @@ private val functionSignatures: List<FSignature> = listOf(
|
||||
FSignature("clear_carry" , false, emptyList(), null),
|
||||
FSignature("set_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("target" , true, emptyList(), DataType.UBYTE, ::builtinTarget),
|
||||
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(
|
||||
FParam("from", IterableDatatypes + DataType.UWORD),
|
||||
FParam("to", IterableDatatypes + DataType.UWORD),
|
||||
|
@ -931,6 +931,14 @@ target()
|
||||
- 16 = compiled for CommanderX16 with 65C02 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()
|
||||
Returns the last address of the program in memory + 1.
|
||||
Can be used to load dynamic data after the program, instead of hardcoding something.
|
||||
|
@ -2,6 +2,7 @@
|
||||
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)
|
||||
- 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)
|
||||
|
@ -1,19 +1,42 @@
|
||||
;%import test_stack
|
||||
;%import textio
|
||||
%import gfx2
|
||||
%import test_stack
|
||||
%import textio
|
||||
%zeropage basicsafe
|
||||
%option no_sysinit
|
||||
|
||||
main {
|
||||
|
||||
sub start () {
|
||||
; txt.lowercase()
|
||||
; txt.print_ub(txt.width())
|
||||
; txt.chrout('\n')
|
||||
; txt.print_ub(txt.height())
|
||||
; txt.chrout('\n')
|
||||
gfx2.text(0,0,2, "sdafsdf")
|
||||
; test_stack.test()
|
||||
|
||||
thing()
|
||||
thing()
|
||||
thing()
|
||||
thing()
|
||||
thing()
|
||||
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_STRING_ESCAPES" value="true" />
|
||||
</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" />
|
||||
<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>
|
||||
<extensionMap>
|
||||
<mapping ext="p8" />
|
||||
|
Loading…
x
Reference in New Issue
Block a user