mirror of
https://github.com/irmen/prog8.git
synced 2025-12-19 20:17:17 +00:00
always put all struct types as .struct in asm code to make them all accessible for size and offsets
This commit is contained in:
@@ -412,10 +412,9 @@ internal class ProgramAndVarsGen(
|
||||
|
||||
|
||||
asmgen.out("; struct types")
|
||||
symboltable.allStructInstances.distinctBy { it.structName }.forEach {
|
||||
val structtype: StStruct = symboltable.lookup(it.structName) as StStruct
|
||||
symboltable.allStructTypes().distinctBy { it.name }.forEach { structtype ->
|
||||
val structargs = structtype.fields.withIndex().joinToString(",") { field -> "f${field.index}" }
|
||||
asmgen.out("${it.structName} .struct $structargs\n")
|
||||
asmgen.out("${structtype.scopedNameString} .struct $structargs\n")
|
||||
structtype.fields.withIndex().forEach { (index, field) ->
|
||||
val dt = field.first
|
||||
val varname = "f${index}"
|
||||
@@ -425,7 +424,7 @@ internal class ProgramAndVarsGen(
|
||||
asmgen.out(" .endstruct\n")
|
||||
}
|
||||
|
||||
val (instancesNoInit, instances) = symboltable.allStructInstances.partition { it.initialValues.isEmpty() }
|
||||
val (instancesNoInit, instances) = symboltable.allStructInstances().partition { it.initialValues.isEmpty() }
|
||||
asmgen.out("; struct instances without initialization values, as BSS zeroed at startup\n")
|
||||
asmgen.out(" .section BSS\n")
|
||||
asmgen.out("${StStructInstanceBlockName}_bss .block\n")
|
||||
|
||||
@@ -514,5 +514,37 @@ main {
|
||||
compileText(Cx16Target(), false, src, outputDir, writeAssembly = false) shouldNotBe null
|
||||
}
|
||||
|
||||
|
||||
test("const struct sizes and offsets, also available in assembly code") {
|
||||
val src = """
|
||||
main {
|
||||
|
||||
struct Node {
|
||||
ubyte type
|
||||
uword value
|
||||
bool flag
|
||||
}
|
||||
|
||||
sub start() {
|
||||
const ubyte size = sizeof(Node)
|
||||
const ubyte offset1 = offsetof(Node.type)
|
||||
const ubyte offset2 = offsetof(Node.value)
|
||||
const ubyte offset3 = offsetof(Node.flag)
|
||||
|
||||
%asm {{
|
||||
lda p8c_size
|
||||
lda p8c_offset1
|
||||
lda p8c_offset2
|
||||
lda p8c_offset3
|
||||
lda #size(p8t_Node)
|
||||
lda #p8t_Node.p8v_type
|
||||
lda #p8t_Node.p8v_value
|
||||
lda #p8t_Node.p8v_flag
|
||||
}}
|
||||
}
|
||||
}"""
|
||||
compileText(Cx16Target(), false, src, outputDir, writeAssembly = true) shouldNotBe null
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
|
||||
@@ -261,3 +261,40 @@ Address-Of: untyped vs typed
|
||||
``&`` still returns an untyped (uword) pointer, as it did in older Prog8 versions. This is for backward compatibility reasons so existing programs don't break.
|
||||
The new *double ampersand* operator ``&&`` returns a *typed* pointer to the value. The semantics are slightly different from the old untyped address-of operator, because adding or subtracting
|
||||
a number from a typed pointer uses *pointer arithmetic* that takes the size of the value that it points to into account.
|
||||
|
||||
|
||||
Accessing struct definitions in Assembly code
|
||||
---------------------------------------------
|
||||
|
||||
Prog8 lets you query the size of a struct type, and the offsets of a field.
|
||||
You can do the same in assembly code if needed: the struct definition gets written as `.struct` into the assembly file::
|
||||
|
||||
; prog8 struct declaration:
|
||||
struct Node {
|
||||
ubyte type
|
||||
uword value
|
||||
bool flag
|
||||
}
|
||||
|
||||
; generates this assembly code:
|
||||
; (the symbol prefixes are explained in the 'Technical details' chapter)
|
||||
p8b_main.p8t_Node .struct f0,f1,f2
|
||||
p8v_type .byte \f0
|
||||
p8v_value .word \f1
|
||||
p8v_flag .byte \f2
|
||||
.endstruct
|
||||
|
||||
|
||||
64tass then lets you query that information::
|
||||
|
||||
; prog8 code:
|
||||
ubyte size = sizeof(Node)
|
||||
ubyte offset1 = offsetof(Node.type)
|
||||
ubyte offset2 = offsetof(Node.value)
|
||||
ubyte offset3 = offsetof(Node.flag)
|
||||
|
||||
; assembly equivalents (64tass syntax):
|
||||
lda #size(p8t_Node)
|
||||
lda #p8t_Node.p8v_type
|
||||
lda #p8t_Node.p8v_value
|
||||
lda #p8t_Node.p8v_flag
|
||||
|
||||
@@ -4,28 +4,28 @@
|
||||
|
||||
main {
|
||||
|
||||
struct Node {
|
||||
ubyte type
|
||||
uword value
|
||||
bool flag
|
||||
}
|
||||
|
||||
sub start() {
|
||||
uword @shared string = 20000
|
||||
ubyte[200] barray
|
||||
uword[100] @nosplit warray
|
||||
ubyte @shared length
|
||||
uword @shared lengthw
|
||||
const ubyte size = sizeof(Node)
|
||||
const ubyte offset1 = offsetof(Node.type)
|
||||
const ubyte offset2 = offsetof(Node.value)
|
||||
const ubyte offset3 = offsetof(Node.flag)
|
||||
|
||||
cx16.r0L = string[length]
|
||||
cx16.r1L = string[lengthw]
|
||||
cx16.r0bL = string[length]!=0
|
||||
cx16.r1bL = string[lengthw]!=0
|
||||
while string[length]!=0
|
||||
break
|
||||
while string[lengthw]!=0
|
||||
break
|
||||
|
||||
|
||||
string[length] = 42
|
||||
string[lengthw] = 42
|
||||
|
||||
;cx16.r1L = barray[length]
|
||||
;cx16.r2 = warray[length]
|
||||
%asm {{
|
||||
lda p8c_size
|
||||
lda p8c_offset1
|
||||
lda p8c_offset2
|
||||
lda p8c_offset3
|
||||
lda #size(p8t_Node)
|
||||
lda #p8t_Node.p8v_type
|
||||
lda #p8t_Node.p8v_value
|
||||
lda #p8t_Node.p8v_flag
|
||||
}}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -81,18 +81,32 @@ class SymbolTable(astProgram: PtProgram) : StNode(astProgram.name, StNodeType.GL
|
||||
vars
|
||||
}
|
||||
|
||||
val allStructInstances: Collection<StStructInstance> by lazy {
|
||||
fun allStructInstances(): Collection<StStructInstance> {
|
||||
val vars = mutableListOf<StStructInstance>()
|
||||
fun collect(node: StNode) {
|
||||
for(child in node.children) {
|
||||
if(child.value.type== StNodeType.STRUCTINSTANCE)
|
||||
if(child.value.type == StNodeType.STRUCTINSTANCE)
|
||||
vars.add(child.value as StStructInstance)
|
||||
else
|
||||
collect(child.value)
|
||||
}
|
||||
}
|
||||
collect(this)
|
||||
vars
|
||||
return vars
|
||||
}
|
||||
|
||||
fun allStructTypes(): Collection<StStruct> {
|
||||
val vars = mutableListOf<StStruct>()
|
||||
fun collect(node: StNode) {
|
||||
for(child in node.children) {
|
||||
if(child.value.type == StNodeType.STRUCT)
|
||||
vars.add(child.value as StStruct)
|
||||
else
|
||||
collect(child.value)
|
||||
}
|
||||
}
|
||||
collect(this)
|
||||
return vars
|
||||
}
|
||||
|
||||
override fun lookup(scopedName: String) = flat[scopedName]
|
||||
|
||||
Reference in New Issue
Block a user