diff --git a/doc/ca65.sgml b/doc/ca65.sgml index 104c59bbd..c5c6893da 100644 --- a/doc/ca65.sgml +++ b/doc/ca65.sgml @@ -4086,7 +4086,9 @@ See: ,.TAG - Allocate space for a struct or union. + Allocate space for a struct or union. This is equivalent to + with the + of a struct. Example: @@ -4100,6 +4102,7 @@ See: , + See: .UNDEF, .UNDEFINE @@ -4865,10 +4868,15 @@ compiler, depending on the target system selected: Structs and unions are special forms of . They are, to some degree, comparable to their C counterparts. Both have a list of -members. Each member allocates storage, and optionally may have a name whose -value, in the case of a struct, usually is the storage offset from the -beginning, and in the case of a union, doesn't change, and usually is zero. +members. Each member allocates storage, and optionally may have a name. +Each named member has a constant value equal to the storage offset from the +beginning of the structure. In the case of a union, all members are placed at +the same offset, typically 0. + +Each named member also has a storage size which can be accessed with the + operator. The struct or union itself +also has a Declaration @@ -4895,8 +4903,9 @@ A struct or union may not necessarily have a name. If it is anonymous, no local scope is opened; the identifiers used to name the members are placed into the current scope instead. -A struct may contain unnamed members and definitions of local structs/unions. -The storage allocators may contain a multiplier, as in the example below: +Storage allocators may contain a multiplier. A struct may also contain members +and definitions of local structs/unions. Example: + .struct Circle .struct Point @@ -4905,7 +4914,8 @@ The storage allocators may contain a multiplier, as in the example below: Radius .word .endstruct -The size of the Circle struct is 6 (three words). + +In this example the size of the Circle struct is 6 (three words). The storage allocator keywords @@ -4915,7 +4925,7 @@ The size of the Circle struct is 6 (three words). @@ -4968,13 +4987,54 @@ name=".TAG"> directive. C: .tag Circle -Currently, members are just offsets from the start of the struct or union. To +Members are just offsets from the start of the struct or union. To access a field of a struct, the member offset must be added to the address of the struct variable itself: - lda C+Circle::Radius ; Load circle radius into A + lda C + Circle::Radius ; Load circle radius + lda C + Circle::Origin + Point::ycoord ; Load circle origin.ycoord -That may change in a future version of the assembler. + +Nested structures or unions are treated differently depending on whether they +are anonymous. If named, a new structure definition is created within the +enclosing scope, with its offsets beginning at 0. If anonymous, the members of +the new structure are added to the enclosing scope instead, with offsets +continuing through that scope. Example: + + + .struct Object + id .byte ; Object::id = 0 + target .struct Point ; Object::target = 1 + xcoord .word ; Object::Point::xcoord = 0 + ycoord .word ; Object::Point::ycoord = 2 + .endstruct + cost .struct ; Object::cost = 5 + price .word ; Object::price = 5 + tax .word ; Object::tax = 7 + .endstruct + .struct + radius .word ; Object::radius = 9 + .endstruct + .endstruct + +O: .tag Object + lda O + Object::target + Object::Point::ycoord ; Named struct + lda O + Object::tax ; Anonymous + lda O + Object::radius ; Anonymous + + ; Be careful not to use a named nested structure without also adding the + ; offset to the nested structure itself. + lda O + Object::Point::ycoord ; Incorrect! + lda O + Object::target + Object::Point::ycoord ; Correct + + +In this example, the first nested structure is named "Point", and its member +offsets begin at 0. On the other hand, the two anonymous structures simply +continue to add members to the enclosing "Object" structure. + +Note that an anonymous structure does not need a member name, since all of its +members become part of the enclosing structure. The "cost" member in the +example is redundantly the same offset as its first member "price". Limitations diff --git a/test/asm/val/struct.s b/test/asm/val/struct.s new file mode 100644 index 000000000..b6ef6f45d --- /dev/null +++ b/test/asm/val/struct.s @@ -0,0 +1,222 @@ +; test .struct and .union features + +.code + +; exit with 0 +.export _main +_main: + lda #0 + tax + rts + +; test storage allocator sizes and offsets + +.struct Storage + mb1 .byte + mb5 .byte 5 + mr1 .res 1 + mr5 .res 5 + mdb1 .dbyt + mdb5 .dbyt 5 + mw1 .word + mw5 .word 5 + ma1 .addr + ma5 .addr 5 + mf1 .faraddr + mf5 .faraddr 5 + mdw1 .dword + mdw5 .dword 5 +.endstruct + +.assert .sizeof(Storage::mb1) = 1, error, ".struct .byte member has unexpected .sizeof" +.assert .sizeof(Storage::mb5) = 5, error, ".struct .byte 5 member has unexpected .sizeof" +.assert .sizeof(Storage::mr1) = 1, error, ".struct .res 1 member has unexpected .sizeof" +.assert .sizeof(Storage::mr5) = 5, error, ".struct .res 5 member has unexpected .sizeof" +.assert .sizeof(Storage::mdb1) = 2, error, ".struct .dbyt member has unexpected .sizeof" +.assert .sizeof(Storage::mdb5) = 10, error, ".struct .dbyt 5 member has unexpected .sizeof" +.assert .sizeof(Storage::mw1) = 2, error, ".struct .word member has unexpected .sizeof" +.assert .sizeof(Storage::mw5) = 10, error, ".struct .word 5 member has unexpected .sizeof" +.assert .sizeof(Storage::ma1) = 2, error, ".struct .addr member has unexpected .sizeof" +.assert .sizeof(Storage::ma5) = 10, error, ".struct .addr 5 member has unexpected .sizeof" +.assert .sizeof(Storage::mf1) = 3, error, ".struct .faraddr member has unexpected .sizeof" +.assert .sizeof(Storage::mf5) = 15, error, ".struct .faraddr 5 member has unexpected .sizeof" +.assert .sizeof(Storage::mdw1) = 4, error, ".struct .dword member has unexpected .sizeof" +.assert .sizeof(Storage::mdw5) = 20, error, ".struct .dword 5 member has unexpected .sizeof" + +.assert Storage::mb1 = 0, error, ".struct storage offset is incorrect" +.assert Storage::mb5 = Storage::mb1 + .sizeof(Storage::mb1), error, ".struct storage offset is incorrect" +.assert Storage::mr1 = Storage::mb5 + .sizeof(Storage::mb5), error, ".struct storage offset is incorrect" +.assert Storage::mr5 = Storage::mr1 + .sizeof(Storage::mr1), error, ".struct storage offset is incorrect" +.assert Storage::mdb1 = Storage::mr5 + .sizeof(Storage::mr5), error, ".struct storage offset is incorrect" +.assert Storage::mdb5 = Storage::mdb1 + .sizeof(Storage::mdb1), error, ".struct storage offset is incorrect" +.assert Storage::mw1 = Storage::mdb5 + .sizeof(Storage::mdb5), error, ".struct storage offset is incorrect" +.assert Storage::mw5 = Storage::mw1 + .sizeof(Storage::mw1), error, ".struct storage offset is incorrect" +.assert Storage::ma1 = Storage::mw5 + .sizeof(Storage::mw5), error, ".struct storage offset is incorrect" +.assert Storage::ma5 = Storage::ma1 + .sizeof(Storage::ma1), error, ".struct storage offset is incorrect" +.assert Storage::mf1 = Storage::ma5 + .sizeof(Storage::ma5), error, ".struct storage offset is incorrect" +.assert Storage::mf5 = Storage::mf1 + .sizeof(Storage::mf1), error, ".struct storage offset is incorrect" +.assert Storage::mdw1 = Storage::mf5 + .sizeof(Storage::mf5), error, ".struct storage offset is incorrect" +.assert Storage::mdw5 = Storage::mdw1 + .sizeof(Storage::mdw1), error, ".struct storage offset is incorrect" +.assert .sizeof(Storage) = Storage::mdw5 + .sizeof(Storage::mdw5), error, ".struct has unexpected .sizeof" + +; test union offset and size + +.union UStorage + mb1 .byte + mb5 .byte 5 + mr1 .res 1 + mr5 .res 5 + mdb1 .dbyt + mdb5 .dbyt 5 + mw1 .word + mw5 .word 5 + ma1 .addr + ma5 .addr 5 + mf1 .faraddr + mf5 .faraddr 5 + mdw1 .dword + mdw5 .dword 5 +.endunion + +.assert .sizeof(UStorage::mb1) = 1, error, ".union .byte member has unexpected .sizeof" +.assert .sizeof(UStorage::mb5) = 5, error, ".union .byte 5 member has unexpected .sizeof" +.assert .sizeof(UStorage::mr1) = 1, error, ".union .res 1 member has unexpected .sizeof" +.assert .sizeof(UStorage::mr5) = 5, error, ".union .res 5 member has unexpected .sizeof" +.assert .sizeof(UStorage::mdb1) = 2, error, ".union .dbyt member has unexpected .sizeof" +.assert .sizeof(UStorage::mdb5) = 10, error, ".union .dbyt 5 member has unexpected .sizeof" +.assert .sizeof(UStorage::mw1) = 2, error, ".union .word member has unexpected .sizeof" +.assert .sizeof(UStorage::mw5) = 10, error, ".union .word 5 member has unexpected .sizeof" +.assert .sizeof(UStorage::ma1) = 2, error, ".union .addr member has unexpected .sizeof" +.assert .sizeof(UStorage::ma5) = 10, error, ".union .addr 5 member has unexpected .sizeof" +.assert .sizeof(UStorage::mf1) = 3, error, ".union .faraddr member has unexpected .sizeof" +.assert .sizeof(UStorage::mf5) = 15, error, ".union .faraddr 5 member has unexpected .sizeof" +.assert .sizeof(UStorage::mdw1) = 4, error, ".union .dword member has unexpected .sizeof" +.assert .sizeof(UStorage::mdw5) = 20, error, ".union .dword 5 member has unexpected .sizeof" +.assert .sizeof(UStorage) = 20, error, ".union has unexpected .sizeof" + +.assert UStorage::mb1 = 0, error, ".union storage offset is incorrect" +.assert UStorage::mb5 = 0, error, ".union storage offset is incorrect" +.assert UStorage::mr1 = 0, error, ".union storage offset is incorrect" +.assert UStorage::mr5 = 0, error, ".union storage offset is incorrect" +.assert UStorage::mdb1 = 0, error, ".union storage offset is incorrect" +.assert UStorage::mdb5 = 0, error, ".union storage offset is incorrect" +.assert UStorage::mw1 = 0, error, ".union storage offset is incorrect" +.assert UStorage::mw5 = 0, error, ".union storage offset is incorrect" +.assert UStorage::ma1 = 0, error, ".union storage offset is incorrect" +.assert UStorage::ma5 = 0, error, ".union storage offset is incorrect" +.assert UStorage::mf1 = 0, error, ".union storage offset is incorrect" +.assert UStorage::mf5 = 0, error, ".union storage offset is incorrect" +.assert UStorage::mdw1 = 0, error, ".union storage offset is incorrect" +.assert UStorage::mdw5 = 0, error, ".union storage offset is incorrect" + +; test tag + +storage: .tag Storage +.assert (*-storage)=.sizeof(Storage), error, ".tag reserved size incorrect" + +; test nested structures + +.struct Point + xc .word + yc .word +.endstruct + +.struct Nested + pad .res 13 + tag .tag Point + ch .struct Child + ca .word ; offset = 0 + gch .struct Grandchild + gca .word ; offset = 0 + gcb .byte + .endstruct + cb .byte + .endstruct + anon .struct + aa .dword ; offset = Nested::anon (anonymous .struct) + ab .dword + .endstruct + chu .union Chunion + ua .byte ; offset = 0 + ub .dword + .endunion + chanon .union + uc .byte ; offset = Nested::chanon + ud .dword + .endunion + last .byte +.endstruct + +.assert Nested::pad = 0, error, "Nested .struct has unexpected starting offset" +.assert Nested::Child::ca = 0, error, "Nested .struct has unexpected starting offset" +.assert Nested::Child::Grandchild::gca = 0, error, "Nested .struct has unexpected starting offset" + +.assert .sizeof(Nested::tag) = .sizeof(Point), error, ".tag in .struct has unexpected .sizeof" +.assert .sizeof(Nested::Child::Grandchild) = 2 + 1, error, "Nested .struct has unexpected .sizeof" +.assert .sizeof(Nested::Child) = 2 + 1 + .sizeof(Nested::Child::Grandchild), error, "Nested .struct has unpexpected .sizeof" +.assert .sizeof(Nested::ch) = .sizeof(Nested::Child), error, "Nested .struct has unexpected member .sizeof" +.assert .sizeof(Nested::Child::gch) = .sizeof(Nested::Child::Grandchild), error, "Nested .struct has unexpected member .sizeof" +.assert .sizeof(Nested::anon) = 8, error, "Nested anonymous member .struct has unexpected .sizeof" +.assert .sizeof(Nested::aa) = 4, error, "Nested anonymous .struct member has unexpected .sizeof" +.assert .sizeof(Nested::ab) = 4, error, "Nested anonymous .struct member has unexpected .sizeof" +.assert .sizeof(Nested::Chunion) = 4, error, "Nested .union has unexpected .sizeof" +.assert .sizeof(Nested::chu) = .sizeof(Nested::Chunion), error, "Nested member .union has unexpected .sizeof" +.assert .sizeof(Nested::chanon) = 4, error, "Nested anonymous member .union as unexpected .sizeof" + +.assert Nested::tag = Nested::pad + .sizeof(Nested::pad), error, ".tag within .struct has unexpected offset" +.assert Nested::ch = Nested::tag + .sizeof(Nested::tag), error, "Nested .struct has unexpected offset" +.assert Nested::anon = Nested::ch + .sizeof(Nested::ch), error, "Nested anonymous member .struct has unexpected offset" +.assert Nested::aa = Nested::anon, error, "Nested anonymous .struct member has unexpected offset" +.assert Nested::ab = Nested::aa + .sizeof(Nested::aa), error, "Nested anonymous .struct member has unexpected offset" +.assert Nested::chu = Nested::ab + .sizeof(Nested::ab), error, "Nested member .union has unexpected offset" +.assert Nested::chanon = Nested::chu + .sizeof(Nested::Chunion), error, "Nested anonymous member .union has unexpected offset" +.assert Nested::uc = Nested::chanon, error, "Nested anonymous .union member has unexpected offset" +.assert Nested::ud = Nested::chanon, error, "Nested anonymous .union member has unexpected offset" +.assert Nested::last = Nested::ud + .sizeof(Nested::ud), error, ".struct member has unexpected offset after anonymous nested .struct" + +; test .org + +start: + +.struct OrgStruct + ma .byte + mb .byte + .org $1234 + mc .byte + md .byte + .struct Nested + me .byte + .org $5678 + mf .byte + mg .byte + .endstruct + mh .byte +.endstruct + +.assert start <> (OrgStruct::mh+1), error, "Fatal test error: accidental code position conflict, move OrgStruct .org to another arbitrary address." +.assert * = start, error, ".org within .struct does not return to previous location at .endstruct" +.assert OrgStruct::ma = 0, error, ".struct with .org has unexpected offset" +.assert OrgStruct::mb = 1, error, ".struct with .org has unexpected offset" +.assert OrgStruct::mc = $1234, error, ".struct with .org has unexpected offset" +.assert OrgStruct::md = $1235, error, ".struct with .org has unexpected offset" +.assert OrgStruct::Nested::me = 0, error, "Nested .struct with .org has unexpected offset" +.assert OrgStruct::Nested::mf = $5678, error, "Nested .struct with .org has unexpected offset" +.assert OrgStruct::Nested::mg = $5679, error, "Nested .struct with .org has unexpected offset" +.assert OrgStruct::mh = $1239, error, ".struct with .org has unexpected offset" +.assert .sizeof(OrgStruct) = 8, error, ".struct with .org has unexpected .sizeof" + +.union OrgUnion + ma .byte + mb .word + .org $1234 + mc .byte + md .word +.endunion + +.assert start <> OrgUnion::md, error, "Fatal test error: accidental code position conflict, move OrgUnion .org to another arbitrary address." +.assert * = start, error, ".org within .union does not return to previous location at .endunion" +.assert OrgUnion::ma = 0, error, ".union with .org has unexpected offset" +.assert OrgUnion::mb = 0, error, ".union with .org has unexpected offset" +.assert OrgUnion::mc = $1234, error, ".union with .org has unexpected offset" +.assert OrgUnion::md = $1234, error, ".union with .org has unexpected offset" +.assert .sizeof(OrgUnion) = 2, error, ".union with .org has unexpected .sizeof"
- Allocate space for a struct or union. + Allocate space for a struct or union. This is equivalent to + with the + of a struct. Example: @@ -4100,6 +4102,7 @@ See: , + See: .UNDEF, .UNDEFINE @@ -4865,10 +4868,15 @@ compiler, depending on the target system selected: Structs and unions are special forms of . They are, to some degree, comparable to their C counterparts. Both have a list of -members. Each member allocates storage, and optionally may have a name whose -value, in the case of a struct, usually is the storage offset from the -beginning, and in the case of a union, doesn't change, and usually is zero. +members. Each member allocates storage, and optionally may have a name. +Each named member has a constant value equal to the storage offset from the +beginning of the structure. In the case of a union, all members are placed at +the same offset, typically 0. + +Each named member also has a storage size which can be accessed with the + operator. The struct or union itself +also has a Declaration @@ -4895,8 +4903,9 @@ A struct or union may not necessarily have a name. If it is anonymous, no local scope is opened; the identifiers used to name the members are placed into the current scope instead. -A struct may contain unnamed members and definitions of local structs/unions. -The storage allocators may contain a multiplier, as in the example below: +Storage allocators may contain a multiplier. A struct may also contain members +and definitions of local structs/unions. Example: + .struct Circle .struct Point @@ -4905,7 +4914,8 @@ The storage allocators may contain a multiplier, as in the example below: Radius .word .endstruct -The size of the Circle struct is 6 (three words). + +In this example the size of the Circle struct is 6 (three words). The storage allocator keywords @@ -4915,7 +4925,7 @@ The size of the Circle struct is 6 (three words). @@ -4968,13 +4987,54 @@ name=".TAG"> directive. C: .tag Circle -Currently, members are just offsets from the start of the struct or union. To +Members are just offsets from the start of the struct or union. To access a field of a struct, the member offset must be added to the address of the struct variable itself: - lda C+Circle::Radius ; Load circle radius into A + lda C + Circle::Radius ; Load circle radius + lda C + Circle::Origin + Point::ycoord ; Load circle origin.ycoord -That may change in a future version of the assembler. + +Nested structures or unions are treated differently depending on whether they +are anonymous. If named, a new structure definition is created within the +enclosing scope, with its offsets beginning at 0. If anonymous, the members of +the new structure are added to the enclosing scope instead, with offsets +continuing through that scope. Example: + + + .struct Object + id .byte ; Object::id = 0 + target .struct Point ; Object::target = 1 + xcoord .word ; Object::Point::xcoord = 0 + ycoord .word ; Object::Point::ycoord = 2 + .endstruct + cost .struct ; Object::cost = 5 + price .word ; Object::price = 5 + tax .word ; Object::tax = 7 + .endstruct + .struct + radius .word ; Object::radius = 9 + .endstruct + .endstruct + +O: .tag Object + lda O + Object::target + Object::Point::ycoord ; Named struct + lda O + Object::tax ; Anonymous + lda O + Object::radius ; Anonymous + + ; Be careful not to use a named nested structure without also adding the + ; offset to the nested structure itself. + lda O + Object::Point::ycoord ; Incorrect! + lda O + Object::target + Object::Point::ycoord ; Correct + + +In this example, the first nested structure is named "Point", and its member +offsets begin at 0. On the other hand, the two anonymous structures simply +continue to add members to the enclosing "Object" structure. + +Note that an anonymous structure does not need a member name, since all of its +members become part of the enclosing structure. The "cost" member in the +example is redundantly the same offset as its first member "price". Limitations diff --git a/test/asm/val/struct.s b/test/asm/val/struct.s new file mode 100644 index 000000000..b6ef6f45d --- /dev/null +++ b/test/asm/val/struct.s @@ -0,0 +1,222 @@ +; test .struct and .union features + +.code + +; exit with 0 +.export _main +_main: + lda #0 + tax + rts + +; test storage allocator sizes and offsets + +.struct Storage + mb1 .byte + mb5 .byte 5 + mr1 .res 1 + mr5 .res 5 + mdb1 .dbyt + mdb5 .dbyt 5 + mw1 .word + mw5 .word 5 + ma1 .addr + ma5 .addr 5 + mf1 .faraddr + mf5 .faraddr 5 + mdw1 .dword + mdw5 .dword 5 +.endstruct + +.assert .sizeof(Storage::mb1) = 1, error, ".struct .byte member has unexpected .sizeof" +.assert .sizeof(Storage::mb5) = 5, error, ".struct .byte 5 member has unexpected .sizeof" +.assert .sizeof(Storage::mr1) = 1, error, ".struct .res 1 member has unexpected .sizeof" +.assert .sizeof(Storage::mr5) = 5, error, ".struct .res 5 member has unexpected .sizeof" +.assert .sizeof(Storage::mdb1) = 2, error, ".struct .dbyt member has unexpected .sizeof" +.assert .sizeof(Storage::mdb5) = 10, error, ".struct .dbyt 5 member has unexpected .sizeof" +.assert .sizeof(Storage::mw1) = 2, error, ".struct .word member has unexpected .sizeof" +.assert .sizeof(Storage::mw5) = 10, error, ".struct .word 5 member has unexpected .sizeof" +.assert .sizeof(Storage::ma1) = 2, error, ".struct .addr member has unexpected .sizeof" +.assert .sizeof(Storage::ma5) = 10, error, ".struct .addr 5 member has unexpected .sizeof" +.assert .sizeof(Storage::mf1) = 3, error, ".struct .faraddr member has unexpected .sizeof" +.assert .sizeof(Storage::mf5) = 15, error, ".struct .faraddr 5 member has unexpected .sizeof" +.assert .sizeof(Storage::mdw1) = 4, error, ".struct .dword member has unexpected .sizeof" +.assert .sizeof(Storage::mdw5) = 20, error, ".struct .dword 5 member has unexpected .sizeof" + +.assert Storage::mb1 = 0, error, ".struct storage offset is incorrect" +.assert Storage::mb5 = Storage::mb1 + .sizeof(Storage::mb1), error, ".struct storage offset is incorrect" +.assert Storage::mr1 = Storage::mb5 + .sizeof(Storage::mb5), error, ".struct storage offset is incorrect" +.assert Storage::mr5 = Storage::mr1 + .sizeof(Storage::mr1), error, ".struct storage offset is incorrect" +.assert Storage::mdb1 = Storage::mr5 + .sizeof(Storage::mr5), error, ".struct storage offset is incorrect" +.assert Storage::mdb5 = Storage::mdb1 + .sizeof(Storage::mdb1), error, ".struct storage offset is incorrect" +.assert Storage::mw1 = Storage::mdb5 + .sizeof(Storage::mdb5), error, ".struct storage offset is incorrect" +.assert Storage::mw5 = Storage::mw1 + .sizeof(Storage::mw1), error, ".struct storage offset is incorrect" +.assert Storage::ma1 = Storage::mw5 + .sizeof(Storage::mw5), error, ".struct storage offset is incorrect" +.assert Storage::ma5 = Storage::ma1 + .sizeof(Storage::ma1), error, ".struct storage offset is incorrect" +.assert Storage::mf1 = Storage::ma5 + .sizeof(Storage::ma5), error, ".struct storage offset is incorrect" +.assert Storage::mf5 = Storage::mf1 + .sizeof(Storage::mf1), error, ".struct storage offset is incorrect" +.assert Storage::mdw1 = Storage::mf5 + .sizeof(Storage::mf5), error, ".struct storage offset is incorrect" +.assert Storage::mdw5 = Storage::mdw1 + .sizeof(Storage::mdw1), error, ".struct storage offset is incorrect" +.assert .sizeof(Storage) = Storage::mdw5 + .sizeof(Storage::mdw5), error, ".struct has unexpected .sizeof" + +; test union offset and size + +.union UStorage + mb1 .byte + mb5 .byte 5 + mr1 .res 1 + mr5 .res 5 + mdb1 .dbyt + mdb5 .dbyt 5 + mw1 .word + mw5 .word 5 + ma1 .addr + ma5 .addr 5 + mf1 .faraddr + mf5 .faraddr 5 + mdw1 .dword + mdw5 .dword 5 +.endunion + +.assert .sizeof(UStorage::mb1) = 1, error, ".union .byte member has unexpected .sizeof" +.assert .sizeof(UStorage::mb5) = 5, error, ".union .byte 5 member has unexpected .sizeof" +.assert .sizeof(UStorage::mr1) = 1, error, ".union .res 1 member has unexpected .sizeof" +.assert .sizeof(UStorage::mr5) = 5, error, ".union .res 5 member has unexpected .sizeof" +.assert .sizeof(UStorage::mdb1) = 2, error, ".union .dbyt member has unexpected .sizeof" +.assert .sizeof(UStorage::mdb5) = 10, error, ".union .dbyt 5 member has unexpected .sizeof" +.assert .sizeof(UStorage::mw1) = 2, error, ".union .word member has unexpected .sizeof" +.assert .sizeof(UStorage::mw5) = 10, error, ".union .word 5 member has unexpected .sizeof" +.assert .sizeof(UStorage::ma1) = 2, error, ".union .addr member has unexpected .sizeof" +.assert .sizeof(UStorage::ma5) = 10, error, ".union .addr 5 member has unexpected .sizeof" +.assert .sizeof(UStorage::mf1) = 3, error, ".union .faraddr member has unexpected .sizeof" +.assert .sizeof(UStorage::mf5) = 15, error, ".union .faraddr 5 member has unexpected .sizeof" +.assert .sizeof(UStorage::mdw1) = 4, error, ".union .dword member has unexpected .sizeof" +.assert .sizeof(UStorage::mdw5) = 20, error, ".union .dword 5 member has unexpected .sizeof" +.assert .sizeof(UStorage) = 20, error, ".union has unexpected .sizeof" + +.assert UStorage::mb1 = 0, error, ".union storage offset is incorrect" +.assert UStorage::mb5 = 0, error, ".union storage offset is incorrect" +.assert UStorage::mr1 = 0, error, ".union storage offset is incorrect" +.assert UStorage::mr5 = 0, error, ".union storage offset is incorrect" +.assert UStorage::mdb1 = 0, error, ".union storage offset is incorrect" +.assert UStorage::mdb5 = 0, error, ".union storage offset is incorrect" +.assert UStorage::mw1 = 0, error, ".union storage offset is incorrect" +.assert UStorage::mw5 = 0, error, ".union storage offset is incorrect" +.assert UStorage::ma1 = 0, error, ".union storage offset is incorrect" +.assert UStorage::ma5 = 0, error, ".union storage offset is incorrect" +.assert UStorage::mf1 = 0, error, ".union storage offset is incorrect" +.assert UStorage::mf5 = 0, error, ".union storage offset is incorrect" +.assert UStorage::mdw1 = 0, error, ".union storage offset is incorrect" +.assert UStorage::mdw5 = 0, error, ".union storage offset is incorrect" + +; test tag + +storage: .tag Storage +.assert (*-storage)=.sizeof(Storage), error, ".tag reserved size incorrect" + +; test nested structures + +.struct Point + xc .word + yc .word +.endstruct + +.struct Nested + pad .res 13 + tag .tag Point + ch .struct Child + ca .word ; offset = 0 + gch .struct Grandchild + gca .word ; offset = 0 + gcb .byte + .endstruct + cb .byte + .endstruct + anon .struct + aa .dword ; offset = Nested::anon (anonymous .struct) + ab .dword + .endstruct + chu .union Chunion + ua .byte ; offset = 0 + ub .dword + .endunion + chanon .union + uc .byte ; offset = Nested::chanon + ud .dword + .endunion + last .byte +.endstruct + +.assert Nested::pad = 0, error, "Nested .struct has unexpected starting offset" +.assert Nested::Child::ca = 0, error, "Nested .struct has unexpected starting offset" +.assert Nested::Child::Grandchild::gca = 0, error, "Nested .struct has unexpected starting offset" + +.assert .sizeof(Nested::tag) = .sizeof(Point), error, ".tag in .struct has unexpected .sizeof" +.assert .sizeof(Nested::Child::Grandchild) = 2 + 1, error, "Nested .struct has unexpected .sizeof" +.assert .sizeof(Nested::Child) = 2 + 1 + .sizeof(Nested::Child::Grandchild), error, "Nested .struct has unpexpected .sizeof" +.assert .sizeof(Nested::ch) = .sizeof(Nested::Child), error, "Nested .struct has unexpected member .sizeof" +.assert .sizeof(Nested::Child::gch) = .sizeof(Nested::Child::Grandchild), error, "Nested .struct has unexpected member .sizeof" +.assert .sizeof(Nested::anon) = 8, error, "Nested anonymous member .struct has unexpected .sizeof" +.assert .sizeof(Nested::aa) = 4, error, "Nested anonymous .struct member has unexpected .sizeof" +.assert .sizeof(Nested::ab) = 4, error, "Nested anonymous .struct member has unexpected .sizeof" +.assert .sizeof(Nested::Chunion) = 4, error, "Nested .union has unexpected .sizeof" +.assert .sizeof(Nested::chu) = .sizeof(Nested::Chunion), error, "Nested member .union has unexpected .sizeof" +.assert .sizeof(Nested::chanon) = 4, error, "Nested anonymous member .union as unexpected .sizeof" + +.assert Nested::tag = Nested::pad + .sizeof(Nested::pad), error, ".tag within .struct has unexpected offset" +.assert Nested::ch = Nested::tag + .sizeof(Nested::tag), error, "Nested .struct has unexpected offset" +.assert Nested::anon = Nested::ch + .sizeof(Nested::ch), error, "Nested anonymous member .struct has unexpected offset" +.assert Nested::aa = Nested::anon, error, "Nested anonymous .struct member has unexpected offset" +.assert Nested::ab = Nested::aa + .sizeof(Nested::aa), error, "Nested anonymous .struct member has unexpected offset" +.assert Nested::chu = Nested::ab + .sizeof(Nested::ab), error, "Nested member .union has unexpected offset" +.assert Nested::chanon = Nested::chu + .sizeof(Nested::Chunion), error, "Nested anonymous member .union has unexpected offset" +.assert Nested::uc = Nested::chanon, error, "Nested anonymous .union member has unexpected offset" +.assert Nested::ud = Nested::chanon, error, "Nested anonymous .union member has unexpected offset" +.assert Nested::last = Nested::ud + .sizeof(Nested::ud), error, ".struct member has unexpected offset after anonymous nested .struct" + +; test .org + +start: + +.struct OrgStruct + ma .byte + mb .byte + .org $1234 + mc .byte + md .byte + .struct Nested + me .byte + .org $5678 + mf .byte + mg .byte + .endstruct + mh .byte +.endstruct + +.assert start <> (OrgStruct::mh+1), error, "Fatal test error: accidental code position conflict, move OrgStruct .org to another arbitrary address." +.assert * = start, error, ".org within .struct does not return to previous location at .endstruct" +.assert OrgStruct::ma = 0, error, ".struct with .org has unexpected offset" +.assert OrgStruct::mb = 1, error, ".struct with .org has unexpected offset" +.assert OrgStruct::mc = $1234, error, ".struct with .org has unexpected offset" +.assert OrgStruct::md = $1235, error, ".struct with .org has unexpected offset" +.assert OrgStruct::Nested::me = 0, error, "Nested .struct with .org has unexpected offset" +.assert OrgStruct::Nested::mf = $5678, error, "Nested .struct with .org has unexpected offset" +.assert OrgStruct::Nested::mg = $5679, error, "Nested .struct with .org has unexpected offset" +.assert OrgStruct::mh = $1239, error, ".struct with .org has unexpected offset" +.assert .sizeof(OrgStruct) = 8, error, ".struct with .org has unexpected .sizeof" + +.union OrgUnion + ma .byte + mb .word + .org $1234 + mc .byte + md .word +.endunion + +.assert start <> OrgUnion::md, error, "Fatal test error: accidental code position conflict, move OrgUnion .org to another arbitrary address." +.assert * = start, error, ".org within .union does not return to previous location at .endunion" +.assert OrgUnion::ma = 0, error, ".union with .org has unexpected offset" +.assert OrgUnion::mb = 0, error, ".union with .org has unexpected offset" +.assert OrgUnion::mc = $1234, error, ".union with .org has unexpected offset" +.assert OrgUnion::md = $1234, error, ".union with .org has unexpected offset" +.assert .sizeof(OrgUnion) = 2, error, ".union with .org has unexpected .sizeof"
@@ -4865,10 +4868,15 @@ compiler, depending on the target system selected: Structs and unions are special forms of . They are, to some degree, comparable to their C counterparts. Both have a list of -members. Each member allocates storage, and optionally may have a name whose -value, in the case of a struct, usually is the storage offset from the -beginning, and in the case of a union, doesn't change, and usually is zero. +members. Each member allocates storage, and optionally may have a name. +Each named member has a constant value equal to the storage offset from the +beginning of the structure. In the case of a union, all members are placed at +the same offset, typically 0. + +Each named member also has a storage size which can be accessed with the + operator. The struct or union itself +also has a Declaration @@ -4895,8 +4903,9 @@ A struct or union may not necessarily have a name. If it is anonymous, no local scope is opened; the identifiers used to name the members are placed into the current scope instead. -A struct may contain unnamed members and definitions of local structs/unions. -The storage allocators may contain a multiplier, as in the example below: +Storage allocators may contain a multiplier. A struct may also contain members +and definitions of local structs/unions. Example: + .struct Circle .struct Point @@ -4905,7 +4914,8 @@ The storage allocators may contain a multiplier, as in the example below: Radius .word .endstruct -The size of the Circle struct is 6 (three words). + +In this example the size of the Circle struct is 6 (three words). The storage allocator keywords @@ -4915,7 +4925,7 @@ The size of the Circle struct is 6 (three words). @@ -4968,13 +4987,54 @@ name=".TAG"> directive. C: .tag Circle -Currently, members are just offsets from the start of the struct or union. To +Members are just offsets from the start of the struct or union. To access a field of a struct, the member offset must be added to the address of the struct variable itself: - lda C+Circle::Radius ; Load circle radius into A + lda C + Circle::Radius ; Load circle radius + lda C + Circle::Origin + Point::ycoord ; Load circle origin.ycoord -That may change in a future version of the assembler. + +Nested structures or unions are treated differently depending on whether they +are anonymous. If named, a new structure definition is created within the +enclosing scope, with its offsets beginning at 0. If anonymous, the members of +the new structure are added to the enclosing scope instead, with offsets +continuing through that scope. Example: + + + .struct Object + id .byte ; Object::id = 0 + target .struct Point ; Object::target = 1 + xcoord .word ; Object::Point::xcoord = 0 + ycoord .word ; Object::Point::ycoord = 2 + .endstruct + cost .struct ; Object::cost = 5 + price .word ; Object::price = 5 + tax .word ; Object::tax = 7 + .endstruct + .struct + radius .word ; Object::radius = 9 + .endstruct + .endstruct + +O: .tag Object + lda O + Object::target + Object::Point::ycoord ; Named struct + lda O + Object::tax ; Anonymous + lda O + Object::radius ; Anonymous + + ; Be careful not to use a named nested structure without also adding the + ; offset to the nested structure itself. + lda O + Object::Point::ycoord ; Incorrect! + lda O + Object::target + Object::Point::ycoord ; Correct + + +In this example, the first nested structure is named "Point", and its member +offsets begin at 0. On the other hand, the two anonymous structures simply +continue to add members to the enclosing "Object" structure. + +Note that an anonymous structure does not need a member name, since all of its +members become part of the enclosing structure. The "cost" member in the +example is redundantly the same offset as its first member "price". Limitations diff --git a/test/asm/val/struct.s b/test/asm/val/struct.s new file mode 100644 index 000000000..b6ef6f45d --- /dev/null +++ b/test/asm/val/struct.s @@ -0,0 +1,222 @@ +; test .struct and .union features + +.code + +; exit with 0 +.export _main +_main: + lda #0 + tax + rts + +; test storage allocator sizes and offsets + +.struct Storage + mb1 .byte + mb5 .byte 5 + mr1 .res 1 + mr5 .res 5 + mdb1 .dbyt + mdb5 .dbyt 5 + mw1 .word + mw5 .word 5 + ma1 .addr + ma5 .addr 5 + mf1 .faraddr + mf5 .faraddr 5 + mdw1 .dword + mdw5 .dword 5 +.endstruct + +.assert .sizeof(Storage::mb1) = 1, error, ".struct .byte member has unexpected .sizeof" +.assert .sizeof(Storage::mb5) = 5, error, ".struct .byte 5 member has unexpected .sizeof" +.assert .sizeof(Storage::mr1) = 1, error, ".struct .res 1 member has unexpected .sizeof" +.assert .sizeof(Storage::mr5) = 5, error, ".struct .res 5 member has unexpected .sizeof" +.assert .sizeof(Storage::mdb1) = 2, error, ".struct .dbyt member has unexpected .sizeof" +.assert .sizeof(Storage::mdb5) = 10, error, ".struct .dbyt 5 member has unexpected .sizeof" +.assert .sizeof(Storage::mw1) = 2, error, ".struct .word member has unexpected .sizeof" +.assert .sizeof(Storage::mw5) = 10, error, ".struct .word 5 member has unexpected .sizeof" +.assert .sizeof(Storage::ma1) = 2, error, ".struct .addr member has unexpected .sizeof" +.assert .sizeof(Storage::ma5) = 10, error, ".struct .addr 5 member has unexpected .sizeof" +.assert .sizeof(Storage::mf1) = 3, error, ".struct .faraddr member has unexpected .sizeof" +.assert .sizeof(Storage::mf5) = 15, error, ".struct .faraddr 5 member has unexpected .sizeof" +.assert .sizeof(Storage::mdw1) = 4, error, ".struct .dword member has unexpected .sizeof" +.assert .sizeof(Storage::mdw5) = 20, error, ".struct .dword 5 member has unexpected .sizeof" + +.assert Storage::mb1 = 0, error, ".struct storage offset is incorrect" +.assert Storage::mb5 = Storage::mb1 + .sizeof(Storage::mb1), error, ".struct storage offset is incorrect" +.assert Storage::mr1 = Storage::mb5 + .sizeof(Storage::mb5), error, ".struct storage offset is incorrect" +.assert Storage::mr5 = Storage::mr1 + .sizeof(Storage::mr1), error, ".struct storage offset is incorrect" +.assert Storage::mdb1 = Storage::mr5 + .sizeof(Storage::mr5), error, ".struct storage offset is incorrect" +.assert Storage::mdb5 = Storage::mdb1 + .sizeof(Storage::mdb1), error, ".struct storage offset is incorrect" +.assert Storage::mw1 = Storage::mdb5 + .sizeof(Storage::mdb5), error, ".struct storage offset is incorrect" +.assert Storage::mw5 = Storage::mw1 + .sizeof(Storage::mw1), error, ".struct storage offset is incorrect" +.assert Storage::ma1 = Storage::mw5 + .sizeof(Storage::mw5), error, ".struct storage offset is incorrect" +.assert Storage::ma5 = Storage::ma1 + .sizeof(Storage::ma1), error, ".struct storage offset is incorrect" +.assert Storage::mf1 = Storage::ma5 + .sizeof(Storage::ma5), error, ".struct storage offset is incorrect" +.assert Storage::mf5 = Storage::mf1 + .sizeof(Storage::mf1), error, ".struct storage offset is incorrect" +.assert Storage::mdw1 = Storage::mf5 + .sizeof(Storage::mf5), error, ".struct storage offset is incorrect" +.assert Storage::mdw5 = Storage::mdw1 + .sizeof(Storage::mdw1), error, ".struct storage offset is incorrect" +.assert .sizeof(Storage) = Storage::mdw5 + .sizeof(Storage::mdw5), error, ".struct has unexpected .sizeof" + +; test union offset and size + +.union UStorage + mb1 .byte + mb5 .byte 5 + mr1 .res 1 + mr5 .res 5 + mdb1 .dbyt + mdb5 .dbyt 5 + mw1 .word + mw5 .word 5 + ma1 .addr + ma5 .addr 5 + mf1 .faraddr + mf5 .faraddr 5 + mdw1 .dword + mdw5 .dword 5 +.endunion + +.assert .sizeof(UStorage::mb1) = 1, error, ".union .byte member has unexpected .sizeof" +.assert .sizeof(UStorage::mb5) = 5, error, ".union .byte 5 member has unexpected .sizeof" +.assert .sizeof(UStorage::mr1) = 1, error, ".union .res 1 member has unexpected .sizeof" +.assert .sizeof(UStorage::mr5) = 5, error, ".union .res 5 member has unexpected .sizeof" +.assert .sizeof(UStorage::mdb1) = 2, error, ".union .dbyt member has unexpected .sizeof" +.assert .sizeof(UStorage::mdb5) = 10, error, ".union .dbyt 5 member has unexpected .sizeof" +.assert .sizeof(UStorage::mw1) = 2, error, ".union .word member has unexpected .sizeof" +.assert .sizeof(UStorage::mw5) = 10, error, ".union .word 5 member has unexpected .sizeof" +.assert .sizeof(UStorage::ma1) = 2, error, ".union .addr member has unexpected .sizeof" +.assert .sizeof(UStorage::ma5) = 10, error, ".union .addr 5 member has unexpected .sizeof" +.assert .sizeof(UStorage::mf1) = 3, error, ".union .faraddr member has unexpected .sizeof" +.assert .sizeof(UStorage::mf5) = 15, error, ".union .faraddr 5 member has unexpected .sizeof" +.assert .sizeof(UStorage::mdw1) = 4, error, ".union .dword member has unexpected .sizeof" +.assert .sizeof(UStorage::mdw5) = 20, error, ".union .dword 5 member has unexpected .sizeof" +.assert .sizeof(UStorage) = 20, error, ".union has unexpected .sizeof" + +.assert UStorage::mb1 = 0, error, ".union storage offset is incorrect" +.assert UStorage::mb5 = 0, error, ".union storage offset is incorrect" +.assert UStorage::mr1 = 0, error, ".union storage offset is incorrect" +.assert UStorage::mr5 = 0, error, ".union storage offset is incorrect" +.assert UStorage::mdb1 = 0, error, ".union storage offset is incorrect" +.assert UStorage::mdb5 = 0, error, ".union storage offset is incorrect" +.assert UStorage::mw1 = 0, error, ".union storage offset is incorrect" +.assert UStorage::mw5 = 0, error, ".union storage offset is incorrect" +.assert UStorage::ma1 = 0, error, ".union storage offset is incorrect" +.assert UStorage::ma5 = 0, error, ".union storage offset is incorrect" +.assert UStorage::mf1 = 0, error, ".union storage offset is incorrect" +.assert UStorage::mf5 = 0, error, ".union storage offset is incorrect" +.assert UStorage::mdw1 = 0, error, ".union storage offset is incorrect" +.assert UStorage::mdw5 = 0, error, ".union storage offset is incorrect" + +; test tag + +storage: .tag Storage +.assert (*-storage)=.sizeof(Storage), error, ".tag reserved size incorrect" + +; test nested structures + +.struct Point + xc .word + yc .word +.endstruct + +.struct Nested + pad .res 13 + tag .tag Point + ch .struct Child + ca .word ; offset = 0 + gch .struct Grandchild + gca .word ; offset = 0 + gcb .byte + .endstruct + cb .byte + .endstruct + anon .struct + aa .dword ; offset = Nested::anon (anonymous .struct) + ab .dword + .endstruct + chu .union Chunion + ua .byte ; offset = 0 + ub .dword + .endunion + chanon .union + uc .byte ; offset = Nested::chanon + ud .dword + .endunion + last .byte +.endstruct + +.assert Nested::pad = 0, error, "Nested .struct has unexpected starting offset" +.assert Nested::Child::ca = 0, error, "Nested .struct has unexpected starting offset" +.assert Nested::Child::Grandchild::gca = 0, error, "Nested .struct has unexpected starting offset" + +.assert .sizeof(Nested::tag) = .sizeof(Point), error, ".tag in .struct has unexpected .sizeof" +.assert .sizeof(Nested::Child::Grandchild) = 2 + 1, error, "Nested .struct has unexpected .sizeof" +.assert .sizeof(Nested::Child) = 2 + 1 + .sizeof(Nested::Child::Grandchild), error, "Nested .struct has unpexpected .sizeof" +.assert .sizeof(Nested::ch) = .sizeof(Nested::Child), error, "Nested .struct has unexpected member .sizeof" +.assert .sizeof(Nested::Child::gch) = .sizeof(Nested::Child::Grandchild), error, "Nested .struct has unexpected member .sizeof" +.assert .sizeof(Nested::anon) = 8, error, "Nested anonymous member .struct has unexpected .sizeof" +.assert .sizeof(Nested::aa) = 4, error, "Nested anonymous .struct member has unexpected .sizeof" +.assert .sizeof(Nested::ab) = 4, error, "Nested anonymous .struct member has unexpected .sizeof" +.assert .sizeof(Nested::Chunion) = 4, error, "Nested .union has unexpected .sizeof" +.assert .sizeof(Nested::chu) = .sizeof(Nested::Chunion), error, "Nested member .union has unexpected .sizeof" +.assert .sizeof(Nested::chanon) = 4, error, "Nested anonymous member .union as unexpected .sizeof" + +.assert Nested::tag = Nested::pad + .sizeof(Nested::pad), error, ".tag within .struct has unexpected offset" +.assert Nested::ch = Nested::tag + .sizeof(Nested::tag), error, "Nested .struct has unexpected offset" +.assert Nested::anon = Nested::ch + .sizeof(Nested::ch), error, "Nested anonymous member .struct has unexpected offset" +.assert Nested::aa = Nested::anon, error, "Nested anonymous .struct member has unexpected offset" +.assert Nested::ab = Nested::aa + .sizeof(Nested::aa), error, "Nested anonymous .struct member has unexpected offset" +.assert Nested::chu = Nested::ab + .sizeof(Nested::ab), error, "Nested member .union has unexpected offset" +.assert Nested::chanon = Nested::chu + .sizeof(Nested::Chunion), error, "Nested anonymous member .union has unexpected offset" +.assert Nested::uc = Nested::chanon, error, "Nested anonymous .union member has unexpected offset" +.assert Nested::ud = Nested::chanon, error, "Nested anonymous .union member has unexpected offset" +.assert Nested::last = Nested::ud + .sizeof(Nested::ud), error, ".struct member has unexpected offset after anonymous nested .struct" + +; test .org + +start: + +.struct OrgStruct + ma .byte + mb .byte + .org $1234 + mc .byte + md .byte + .struct Nested + me .byte + .org $5678 + mf .byte + mg .byte + .endstruct + mh .byte +.endstruct + +.assert start <> (OrgStruct::mh+1), error, "Fatal test error: accidental code position conflict, move OrgStruct .org to another arbitrary address." +.assert * = start, error, ".org within .struct does not return to previous location at .endstruct" +.assert OrgStruct::ma = 0, error, ".struct with .org has unexpected offset" +.assert OrgStruct::mb = 1, error, ".struct with .org has unexpected offset" +.assert OrgStruct::mc = $1234, error, ".struct with .org has unexpected offset" +.assert OrgStruct::md = $1235, error, ".struct with .org has unexpected offset" +.assert OrgStruct::Nested::me = 0, error, "Nested .struct with .org has unexpected offset" +.assert OrgStruct::Nested::mf = $5678, error, "Nested .struct with .org has unexpected offset" +.assert OrgStruct::Nested::mg = $5679, error, "Nested .struct with .org has unexpected offset" +.assert OrgStruct::mh = $1239, error, ".struct with .org has unexpected offset" +.assert .sizeof(OrgStruct) = 8, error, ".struct with .org has unexpected .sizeof" + +.union OrgUnion + ma .byte + mb .word + .org $1234 + mc .byte + md .word +.endunion + +.assert start <> OrgUnion::md, error, "Fatal test error: accidental code position conflict, move OrgUnion .org to another arbitrary address." +.assert * = start, error, ".org within .union does not return to previous location at .endunion" +.assert OrgUnion::ma = 0, error, ".union with .org has unexpected offset" +.assert OrgUnion::mb = 0, error, ".union with .org has unexpected offset" +.assert OrgUnion::mc = $1234, error, ".union with .org has unexpected offset" +.assert OrgUnion::md = $1234, error, ".union with .org has unexpected offset" +.assert .sizeof(OrgUnion) = 2, error, ".union with .org has unexpected .sizeof"
@@ -4895,8 +4903,9 @@ A struct or union may not necessarily have a name. If it is anonymous, no local scope is opened; the identifiers used to name the members are placed into the current scope instead. -A struct may contain unnamed members and definitions of local structs/unions. -The storage allocators may contain a multiplier, as in the example below: +Storage allocators may contain a multiplier. A struct may also contain members +and definitions of local structs/unions. Example: + .struct Circle .struct Point @@ -4905,7 +4914,8 @@ The storage allocators may contain a multiplier, as in the example below: Radius .word .endstruct -The size of the Circle struct is 6 (three words). + +In this example the size of the Circle struct is 6 (three words). The storage allocator keywords @@ -4915,7 +4925,7 @@ The size of the Circle struct is 6 (three words). @@ -4968,13 +4987,54 @@ name=".TAG"> directive. C: .tag Circle -Currently, members are just offsets from the start of the struct or union. To +Members are just offsets from the start of the struct or union. To access a field of a struct, the member offset must be added to the address of the struct variable itself: - lda C+Circle::Radius ; Load circle radius into A + lda C + Circle::Radius ; Load circle radius + lda C + Circle::Origin + Point::ycoord ; Load circle origin.ycoord -That may change in a future version of the assembler. + +Nested structures or unions are treated differently depending on whether they +are anonymous. If named, a new structure definition is created within the +enclosing scope, with its offsets beginning at 0. If anonymous, the members of +the new structure are added to the enclosing scope instead, with offsets +continuing through that scope. Example: + + + .struct Object + id .byte ; Object::id = 0 + target .struct Point ; Object::target = 1 + xcoord .word ; Object::Point::xcoord = 0 + ycoord .word ; Object::Point::ycoord = 2 + .endstruct + cost .struct ; Object::cost = 5 + price .word ; Object::price = 5 + tax .word ; Object::tax = 7 + .endstruct + .struct + radius .word ; Object::radius = 9 + .endstruct + .endstruct + +O: .tag Object + lda O + Object::target + Object::Point::ycoord ; Named struct + lda O + Object::tax ; Anonymous + lda O + Object::radius ; Anonymous + + ; Be careful not to use a named nested structure without also adding the + ; offset to the nested structure itself. + lda O + Object::Point::ycoord ; Incorrect! + lda O + Object::target + Object::Point::ycoord ; Correct + + +In this example, the first nested structure is named "Point", and its member +offsets begin at 0. On the other hand, the two anonymous structures simply +continue to add members to the enclosing "Object" structure. + +Note that an anonymous structure does not need a member name, since all of its +members become part of the enclosing structure. The "cost" member in the +example is redundantly the same offset as its first member "price". Limitations diff --git a/test/asm/val/struct.s b/test/asm/val/struct.s new file mode 100644 index 000000000..b6ef6f45d --- /dev/null +++ b/test/asm/val/struct.s @@ -0,0 +1,222 @@ +; test .struct and .union features + +.code + +; exit with 0 +.export _main +_main: + lda #0 + tax + rts + +; test storage allocator sizes and offsets + +.struct Storage + mb1 .byte + mb5 .byte 5 + mr1 .res 1 + mr5 .res 5 + mdb1 .dbyt + mdb5 .dbyt 5 + mw1 .word + mw5 .word 5 + ma1 .addr + ma5 .addr 5 + mf1 .faraddr + mf5 .faraddr 5 + mdw1 .dword + mdw5 .dword 5 +.endstruct + +.assert .sizeof(Storage::mb1) = 1, error, ".struct .byte member has unexpected .sizeof" +.assert .sizeof(Storage::mb5) = 5, error, ".struct .byte 5 member has unexpected .sizeof" +.assert .sizeof(Storage::mr1) = 1, error, ".struct .res 1 member has unexpected .sizeof" +.assert .sizeof(Storage::mr5) = 5, error, ".struct .res 5 member has unexpected .sizeof" +.assert .sizeof(Storage::mdb1) = 2, error, ".struct .dbyt member has unexpected .sizeof" +.assert .sizeof(Storage::mdb5) = 10, error, ".struct .dbyt 5 member has unexpected .sizeof" +.assert .sizeof(Storage::mw1) = 2, error, ".struct .word member has unexpected .sizeof" +.assert .sizeof(Storage::mw5) = 10, error, ".struct .word 5 member has unexpected .sizeof" +.assert .sizeof(Storage::ma1) = 2, error, ".struct .addr member has unexpected .sizeof" +.assert .sizeof(Storage::ma5) = 10, error, ".struct .addr 5 member has unexpected .sizeof" +.assert .sizeof(Storage::mf1) = 3, error, ".struct .faraddr member has unexpected .sizeof" +.assert .sizeof(Storage::mf5) = 15, error, ".struct .faraddr 5 member has unexpected .sizeof" +.assert .sizeof(Storage::mdw1) = 4, error, ".struct .dword member has unexpected .sizeof" +.assert .sizeof(Storage::mdw5) = 20, error, ".struct .dword 5 member has unexpected .sizeof" + +.assert Storage::mb1 = 0, error, ".struct storage offset is incorrect" +.assert Storage::mb5 = Storage::mb1 + .sizeof(Storage::mb1), error, ".struct storage offset is incorrect" +.assert Storage::mr1 = Storage::mb5 + .sizeof(Storage::mb5), error, ".struct storage offset is incorrect" +.assert Storage::mr5 = Storage::mr1 + .sizeof(Storage::mr1), error, ".struct storage offset is incorrect" +.assert Storage::mdb1 = Storage::mr5 + .sizeof(Storage::mr5), error, ".struct storage offset is incorrect" +.assert Storage::mdb5 = Storage::mdb1 + .sizeof(Storage::mdb1), error, ".struct storage offset is incorrect" +.assert Storage::mw1 = Storage::mdb5 + .sizeof(Storage::mdb5), error, ".struct storage offset is incorrect" +.assert Storage::mw5 = Storage::mw1 + .sizeof(Storage::mw1), error, ".struct storage offset is incorrect" +.assert Storage::ma1 = Storage::mw5 + .sizeof(Storage::mw5), error, ".struct storage offset is incorrect" +.assert Storage::ma5 = Storage::ma1 + .sizeof(Storage::ma1), error, ".struct storage offset is incorrect" +.assert Storage::mf1 = Storage::ma5 + .sizeof(Storage::ma5), error, ".struct storage offset is incorrect" +.assert Storage::mf5 = Storage::mf1 + .sizeof(Storage::mf1), error, ".struct storage offset is incorrect" +.assert Storage::mdw1 = Storage::mf5 + .sizeof(Storage::mf5), error, ".struct storage offset is incorrect" +.assert Storage::mdw5 = Storage::mdw1 + .sizeof(Storage::mdw1), error, ".struct storage offset is incorrect" +.assert .sizeof(Storage) = Storage::mdw5 + .sizeof(Storage::mdw5), error, ".struct has unexpected .sizeof" + +; test union offset and size + +.union UStorage + mb1 .byte + mb5 .byte 5 + mr1 .res 1 + mr5 .res 5 + mdb1 .dbyt + mdb5 .dbyt 5 + mw1 .word + mw5 .word 5 + ma1 .addr + ma5 .addr 5 + mf1 .faraddr + mf5 .faraddr 5 + mdw1 .dword + mdw5 .dword 5 +.endunion + +.assert .sizeof(UStorage::mb1) = 1, error, ".union .byte member has unexpected .sizeof" +.assert .sizeof(UStorage::mb5) = 5, error, ".union .byte 5 member has unexpected .sizeof" +.assert .sizeof(UStorage::mr1) = 1, error, ".union .res 1 member has unexpected .sizeof" +.assert .sizeof(UStorage::mr5) = 5, error, ".union .res 5 member has unexpected .sizeof" +.assert .sizeof(UStorage::mdb1) = 2, error, ".union .dbyt member has unexpected .sizeof" +.assert .sizeof(UStorage::mdb5) = 10, error, ".union .dbyt 5 member has unexpected .sizeof" +.assert .sizeof(UStorage::mw1) = 2, error, ".union .word member has unexpected .sizeof" +.assert .sizeof(UStorage::mw5) = 10, error, ".union .word 5 member has unexpected .sizeof" +.assert .sizeof(UStorage::ma1) = 2, error, ".union .addr member has unexpected .sizeof" +.assert .sizeof(UStorage::ma5) = 10, error, ".union .addr 5 member has unexpected .sizeof" +.assert .sizeof(UStorage::mf1) = 3, error, ".union .faraddr member has unexpected .sizeof" +.assert .sizeof(UStorage::mf5) = 15, error, ".union .faraddr 5 member has unexpected .sizeof" +.assert .sizeof(UStorage::mdw1) = 4, error, ".union .dword member has unexpected .sizeof" +.assert .sizeof(UStorage::mdw5) = 20, error, ".union .dword 5 member has unexpected .sizeof" +.assert .sizeof(UStorage) = 20, error, ".union has unexpected .sizeof" + +.assert UStorage::mb1 = 0, error, ".union storage offset is incorrect" +.assert UStorage::mb5 = 0, error, ".union storage offset is incorrect" +.assert UStorage::mr1 = 0, error, ".union storage offset is incorrect" +.assert UStorage::mr5 = 0, error, ".union storage offset is incorrect" +.assert UStorage::mdb1 = 0, error, ".union storage offset is incorrect" +.assert UStorage::mdb5 = 0, error, ".union storage offset is incorrect" +.assert UStorage::mw1 = 0, error, ".union storage offset is incorrect" +.assert UStorage::mw5 = 0, error, ".union storage offset is incorrect" +.assert UStorage::ma1 = 0, error, ".union storage offset is incorrect" +.assert UStorage::ma5 = 0, error, ".union storage offset is incorrect" +.assert UStorage::mf1 = 0, error, ".union storage offset is incorrect" +.assert UStorage::mf5 = 0, error, ".union storage offset is incorrect" +.assert UStorage::mdw1 = 0, error, ".union storage offset is incorrect" +.assert UStorage::mdw5 = 0, error, ".union storage offset is incorrect" + +; test tag + +storage: .tag Storage +.assert (*-storage)=.sizeof(Storage), error, ".tag reserved size incorrect" + +; test nested structures + +.struct Point + xc .word + yc .word +.endstruct + +.struct Nested + pad .res 13 + tag .tag Point + ch .struct Child + ca .word ; offset = 0 + gch .struct Grandchild + gca .word ; offset = 0 + gcb .byte + .endstruct + cb .byte + .endstruct + anon .struct + aa .dword ; offset = Nested::anon (anonymous .struct) + ab .dword + .endstruct + chu .union Chunion + ua .byte ; offset = 0 + ub .dword + .endunion + chanon .union + uc .byte ; offset = Nested::chanon + ud .dword + .endunion + last .byte +.endstruct + +.assert Nested::pad = 0, error, "Nested .struct has unexpected starting offset" +.assert Nested::Child::ca = 0, error, "Nested .struct has unexpected starting offset" +.assert Nested::Child::Grandchild::gca = 0, error, "Nested .struct has unexpected starting offset" + +.assert .sizeof(Nested::tag) = .sizeof(Point), error, ".tag in .struct has unexpected .sizeof" +.assert .sizeof(Nested::Child::Grandchild) = 2 + 1, error, "Nested .struct has unexpected .sizeof" +.assert .sizeof(Nested::Child) = 2 + 1 + .sizeof(Nested::Child::Grandchild), error, "Nested .struct has unpexpected .sizeof" +.assert .sizeof(Nested::ch) = .sizeof(Nested::Child), error, "Nested .struct has unexpected member .sizeof" +.assert .sizeof(Nested::Child::gch) = .sizeof(Nested::Child::Grandchild), error, "Nested .struct has unexpected member .sizeof" +.assert .sizeof(Nested::anon) = 8, error, "Nested anonymous member .struct has unexpected .sizeof" +.assert .sizeof(Nested::aa) = 4, error, "Nested anonymous .struct member has unexpected .sizeof" +.assert .sizeof(Nested::ab) = 4, error, "Nested anonymous .struct member has unexpected .sizeof" +.assert .sizeof(Nested::Chunion) = 4, error, "Nested .union has unexpected .sizeof" +.assert .sizeof(Nested::chu) = .sizeof(Nested::Chunion), error, "Nested member .union has unexpected .sizeof" +.assert .sizeof(Nested::chanon) = 4, error, "Nested anonymous member .union as unexpected .sizeof" + +.assert Nested::tag = Nested::pad + .sizeof(Nested::pad), error, ".tag within .struct has unexpected offset" +.assert Nested::ch = Nested::tag + .sizeof(Nested::tag), error, "Nested .struct has unexpected offset" +.assert Nested::anon = Nested::ch + .sizeof(Nested::ch), error, "Nested anonymous member .struct has unexpected offset" +.assert Nested::aa = Nested::anon, error, "Nested anonymous .struct member has unexpected offset" +.assert Nested::ab = Nested::aa + .sizeof(Nested::aa), error, "Nested anonymous .struct member has unexpected offset" +.assert Nested::chu = Nested::ab + .sizeof(Nested::ab), error, "Nested member .union has unexpected offset" +.assert Nested::chanon = Nested::chu + .sizeof(Nested::Chunion), error, "Nested anonymous member .union has unexpected offset" +.assert Nested::uc = Nested::chanon, error, "Nested anonymous .union member has unexpected offset" +.assert Nested::ud = Nested::chanon, error, "Nested anonymous .union member has unexpected offset" +.assert Nested::last = Nested::ud + .sizeof(Nested::ud), error, ".struct member has unexpected offset after anonymous nested .struct" + +; test .org + +start: + +.struct OrgStruct + ma .byte + mb .byte + .org $1234 + mc .byte + md .byte + .struct Nested + me .byte + .org $5678 + mf .byte + mg .byte + .endstruct + mh .byte +.endstruct + +.assert start <> (OrgStruct::mh+1), error, "Fatal test error: accidental code position conflict, move OrgStruct .org to another arbitrary address." +.assert * = start, error, ".org within .struct does not return to previous location at .endstruct" +.assert OrgStruct::ma = 0, error, ".struct with .org has unexpected offset" +.assert OrgStruct::mb = 1, error, ".struct with .org has unexpected offset" +.assert OrgStruct::mc = $1234, error, ".struct with .org has unexpected offset" +.assert OrgStruct::md = $1235, error, ".struct with .org has unexpected offset" +.assert OrgStruct::Nested::me = 0, error, "Nested .struct with .org has unexpected offset" +.assert OrgStruct::Nested::mf = $5678, error, "Nested .struct with .org has unexpected offset" +.assert OrgStruct::Nested::mg = $5679, error, "Nested .struct with .org has unexpected offset" +.assert OrgStruct::mh = $1239, error, ".struct with .org has unexpected offset" +.assert .sizeof(OrgStruct) = 8, error, ".struct with .org has unexpected .sizeof" + +.union OrgUnion + ma .byte + mb .word + .org $1234 + mc .byte + md .word +.endunion + +.assert start <> OrgUnion::md, error, "Fatal test error: accidental code position conflict, move OrgUnion .org to another arbitrary address." +.assert * = start, error, ".org within .union does not return to previous location at .endunion" +.assert OrgUnion::ma = 0, error, ".union with .org has unexpected offset" +.assert OrgUnion::mb = 0, error, ".union with .org has unexpected offset" +.assert OrgUnion::mc = $1234, error, ".union with .org has unexpected offset" +.assert OrgUnion::md = $1234, error, ".union with .org has unexpected offset" +.assert .sizeof(OrgUnion) = 2, error, ".union with .org has unexpected .sizeof"
@@ -4915,7 +4925,7 @@ The size of the Circle struct is 6 (three words). @@ -4968,13 +4987,54 @@ name=".TAG"> directive. C: .tag Circle -Currently, members are just offsets from the start of the struct or union. To +Members are just offsets from the start of the struct or union. To access a field of a struct, the member offset must be added to the address of the struct variable itself: - lda C+Circle::Radius ; Load circle radius into A + lda C + Circle::Radius ; Load circle radius + lda C + Circle::Origin + Point::ycoord ; Load circle origin.ycoord -That may change in a future version of the assembler. + +Nested structures or unions are treated differently depending on whether they +are anonymous. If named, a new structure definition is created within the +enclosing scope, with its offsets beginning at 0. If anonymous, the members of +the new structure are added to the enclosing scope instead, with offsets +continuing through that scope. Example: + + + .struct Object + id .byte ; Object::id = 0 + target .struct Point ; Object::target = 1 + xcoord .word ; Object::Point::xcoord = 0 + ycoord .word ; Object::Point::ycoord = 2 + .endstruct + cost .struct ; Object::cost = 5 + price .word ; Object::price = 5 + tax .word ; Object::tax = 7 + .endstruct + .struct + radius .word ; Object::radius = 9 + .endstruct + .endstruct + +O: .tag Object + lda O + Object::target + Object::Point::ycoord ; Named struct + lda O + Object::tax ; Anonymous + lda O + Object::radius ; Anonymous + + ; Be careful not to use a named nested structure without also adding the + ; offset to the nested structure itself. + lda O + Object::Point::ycoord ; Incorrect! + lda O + Object::target + Object::Point::ycoord ; Correct + + +In this example, the first nested structure is named "Point", and its member +offsets begin at 0. On the other hand, the two anonymous structures simply +continue to add members to the enclosing "Object" structure. + +Note that an anonymous structure does not need a member name, since all of its +members become part of the enclosing structure. The "cost" member in the +example is redundantly the same offset as its first member "price". Limitations diff --git a/test/asm/val/struct.s b/test/asm/val/struct.s new file mode 100644 index 000000000..b6ef6f45d --- /dev/null +++ b/test/asm/val/struct.s @@ -0,0 +1,222 @@ +; test .struct and .union features + +.code + +; exit with 0 +.export _main +_main: + lda #0 + tax + rts + +; test storage allocator sizes and offsets + +.struct Storage + mb1 .byte + mb5 .byte 5 + mr1 .res 1 + mr5 .res 5 + mdb1 .dbyt + mdb5 .dbyt 5 + mw1 .word + mw5 .word 5 + ma1 .addr + ma5 .addr 5 + mf1 .faraddr + mf5 .faraddr 5 + mdw1 .dword + mdw5 .dword 5 +.endstruct + +.assert .sizeof(Storage::mb1) = 1, error, ".struct .byte member has unexpected .sizeof" +.assert .sizeof(Storage::mb5) = 5, error, ".struct .byte 5 member has unexpected .sizeof" +.assert .sizeof(Storage::mr1) = 1, error, ".struct .res 1 member has unexpected .sizeof" +.assert .sizeof(Storage::mr5) = 5, error, ".struct .res 5 member has unexpected .sizeof" +.assert .sizeof(Storage::mdb1) = 2, error, ".struct .dbyt member has unexpected .sizeof" +.assert .sizeof(Storage::mdb5) = 10, error, ".struct .dbyt 5 member has unexpected .sizeof" +.assert .sizeof(Storage::mw1) = 2, error, ".struct .word member has unexpected .sizeof" +.assert .sizeof(Storage::mw5) = 10, error, ".struct .word 5 member has unexpected .sizeof" +.assert .sizeof(Storage::ma1) = 2, error, ".struct .addr member has unexpected .sizeof" +.assert .sizeof(Storage::ma5) = 10, error, ".struct .addr 5 member has unexpected .sizeof" +.assert .sizeof(Storage::mf1) = 3, error, ".struct .faraddr member has unexpected .sizeof" +.assert .sizeof(Storage::mf5) = 15, error, ".struct .faraddr 5 member has unexpected .sizeof" +.assert .sizeof(Storage::mdw1) = 4, error, ".struct .dword member has unexpected .sizeof" +.assert .sizeof(Storage::mdw5) = 20, error, ".struct .dword 5 member has unexpected .sizeof" + +.assert Storage::mb1 = 0, error, ".struct storage offset is incorrect" +.assert Storage::mb5 = Storage::mb1 + .sizeof(Storage::mb1), error, ".struct storage offset is incorrect" +.assert Storage::mr1 = Storage::mb5 + .sizeof(Storage::mb5), error, ".struct storage offset is incorrect" +.assert Storage::mr5 = Storage::mr1 + .sizeof(Storage::mr1), error, ".struct storage offset is incorrect" +.assert Storage::mdb1 = Storage::mr5 + .sizeof(Storage::mr5), error, ".struct storage offset is incorrect" +.assert Storage::mdb5 = Storage::mdb1 + .sizeof(Storage::mdb1), error, ".struct storage offset is incorrect" +.assert Storage::mw1 = Storage::mdb5 + .sizeof(Storage::mdb5), error, ".struct storage offset is incorrect" +.assert Storage::mw5 = Storage::mw1 + .sizeof(Storage::mw1), error, ".struct storage offset is incorrect" +.assert Storage::ma1 = Storage::mw5 + .sizeof(Storage::mw5), error, ".struct storage offset is incorrect" +.assert Storage::ma5 = Storage::ma1 + .sizeof(Storage::ma1), error, ".struct storage offset is incorrect" +.assert Storage::mf1 = Storage::ma5 + .sizeof(Storage::ma5), error, ".struct storage offset is incorrect" +.assert Storage::mf5 = Storage::mf1 + .sizeof(Storage::mf1), error, ".struct storage offset is incorrect" +.assert Storage::mdw1 = Storage::mf5 + .sizeof(Storage::mf5), error, ".struct storage offset is incorrect" +.assert Storage::mdw5 = Storage::mdw1 + .sizeof(Storage::mdw1), error, ".struct storage offset is incorrect" +.assert .sizeof(Storage) = Storage::mdw5 + .sizeof(Storage::mdw5), error, ".struct has unexpected .sizeof" + +; test union offset and size + +.union UStorage + mb1 .byte + mb5 .byte 5 + mr1 .res 1 + mr5 .res 5 + mdb1 .dbyt + mdb5 .dbyt 5 + mw1 .word + mw5 .word 5 + ma1 .addr + ma5 .addr 5 + mf1 .faraddr + mf5 .faraddr 5 + mdw1 .dword + mdw5 .dword 5 +.endunion + +.assert .sizeof(UStorage::mb1) = 1, error, ".union .byte member has unexpected .sizeof" +.assert .sizeof(UStorage::mb5) = 5, error, ".union .byte 5 member has unexpected .sizeof" +.assert .sizeof(UStorage::mr1) = 1, error, ".union .res 1 member has unexpected .sizeof" +.assert .sizeof(UStorage::mr5) = 5, error, ".union .res 5 member has unexpected .sizeof" +.assert .sizeof(UStorage::mdb1) = 2, error, ".union .dbyt member has unexpected .sizeof" +.assert .sizeof(UStorage::mdb5) = 10, error, ".union .dbyt 5 member has unexpected .sizeof" +.assert .sizeof(UStorage::mw1) = 2, error, ".union .word member has unexpected .sizeof" +.assert .sizeof(UStorage::mw5) = 10, error, ".union .word 5 member has unexpected .sizeof" +.assert .sizeof(UStorage::ma1) = 2, error, ".union .addr member has unexpected .sizeof" +.assert .sizeof(UStorage::ma5) = 10, error, ".union .addr 5 member has unexpected .sizeof" +.assert .sizeof(UStorage::mf1) = 3, error, ".union .faraddr member has unexpected .sizeof" +.assert .sizeof(UStorage::mf5) = 15, error, ".union .faraddr 5 member has unexpected .sizeof" +.assert .sizeof(UStorage::mdw1) = 4, error, ".union .dword member has unexpected .sizeof" +.assert .sizeof(UStorage::mdw5) = 20, error, ".union .dword 5 member has unexpected .sizeof" +.assert .sizeof(UStorage) = 20, error, ".union has unexpected .sizeof" + +.assert UStorage::mb1 = 0, error, ".union storage offset is incorrect" +.assert UStorage::mb5 = 0, error, ".union storage offset is incorrect" +.assert UStorage::mr1 = 0, error, ".union storage offset is incorrect" +.assert UStorage::mr5 = 0, error, ".union storage offset is incorrect" +.assert UStorage::mdb1 = 0, error, ".union storage offset is incorrect" +.assert UStorage::mdb5 = 0, error, ".union storage offset is incorrect" +.assert UStorage::mw1 = 0, error, ".union storage offset is incorrect" +.assert UStorage::mw5 = 0, error, ".union storage offset is incorrect" +.assert UStorage::ma1 = 0, error, ".union storage offset is incorrect" +.assert UStorage::ma5 = 0, error, ".union storage offset is incorrect" +.assert UStorage::mf1 = 0, error, ".union storage offset is incorrect" +.assert UStorage::mf5 = 0, error, ".union storage offset is incorrect" +.assert UStorage::mdw1 = 0, error, ".union storage offset is incorrect" +.assert UStorage::mdw5 = 0, error, ".union storage offset is incorrect" + +; test tag + +storage: .tag Storage +.assert (*-storage)=.sizeof(Storage), error, ".tag reserved size incorrect" + +; test nested structures + +.struct Point + xc .word + yc .word +.endstruct + +.struct Nested + pad .res 13 + tag .tag Point + ch .struct Child + ca .word ; offset = 0 + gch .struct Grandchild + gca .word ; offset = 0 + gcb .byte + .endstruct + cb .byte + .endstruct + anon .struct + aa .dword ; offset = Nested::anon (anonymous .struct) + ab .dword + .endstruct + chu .union Chunion + ua .byte ; offset = 0 + ub .dword + .endunion + chanon .union + uc .byte ; offset = Nested::chanon + ud .dword + .endunion + last .byte +.endstruct + +.assert Nested::pad = 0, error, "Nested .struct has unexpected starting offset" +.assert Nested::Child::ca = 0, error, "Nested .struct has unexpected starting offset" +.assert Nested::Child::Grandchild::gca = 0, error, "Nested .struct has unexpected starting offset" + +.assert .sizeof(Nested::tag) = .sizeof(Point), error, ".tag in .struct has unexpected .sizeof" +.assert .sizeof(Nested::Child::Grandchild) = 2 + 1, error, "Nested .struct has unexpected .sizeof" +.assert .sizeof(Nested::Child) = 2 + 1 + .sizeof(Nested::Child::Grandchild), error, "Nested .struct has unpexpected .sizeof" +.assert .sizeof(Nested::ch) = .sizeof(Nested::Child), error, "Nested .struct has unexpected member .sizeof" +.assert .sizeof(Nested::Child::gch) = .sizeof(Nested::Child::Grandchild), error, "Nested .struct has unexpected member .sizeof" +.assert .sizeof(Nested::anon) = 8, error, "Nested anonymous member .struct has unexpected .sizeof" +.assert .sizeof(Nested::aa) = 4, error, "Nested anonymous .struct member has unexpected .sizeof" +.assert .sizeof(Nested::ab) = 4, error, "Nested anonymous .struct member has unexpected .sizeof" +.assert .sizeof(Nested::Chunion) = 4, error, "Nested .union has unexpected .sizeof" +.assert .sizeof(Nested::chu) = .sizeof(Nested::Chunion), error, "Nested member .union has unexpected .sizeof" +.assert .sizeof(Nested::chanon) = 4, error, "Nested anonymous member .union as unexpected .sizeof" + +.assert Nested::tag = Nested::pad + .sizeof(Nested::pad), error, ".tag within .struct has unexpected offset" +.assert Nested::ch = Nested::tag + .sizeof(Nested::tag), error, "Nested .struct has unexpected offset" +.assert Nested::anon = Nested::ch + .sizeof(Nested::ch), error, "Nested anonymous member .struct has unexpected offset" +.assert Nested::aa = Nested::anon, error, "Nested anonymous .struct member has unexpected offset" +.assert Nested::ab = Nested::aa + .sizeof(Nested::aa), error, "Nested anonymous .struct member has unexpected offset" +.assert Nested::chu = Nested::ab + .sizeof(Nested::ab), error, "Nested member .union has unexpected offset" +.assert Nested::chanon = Nested::chu + .sizeof(Nested::Chunion), error, "Nested anonymous member .union has unexpected offset" +.assert Nested::uc = Nested::chanon, error, "Nested anonymous .union member has unexpected offset" +.assert Nested::ud = Nested::chanon, error, "Nested anonymous .union member has unexpected offset" +.assert Nested::last = Nested::ud + .sizeof(Nested::ud), error, ".struct member has unexpected offset after anonymous nested .struct" + +; test .org + +start: + +.struct OrgStruct + ma .byte + mb .byte + .org $1234 + mc .byte + md .byte + .struct Nested + me .byte + .org $5678 + mf .byte + mg .byte + .endstruct + mh .byte +.endstruct + +.assert start <> (OrgStruct::mh+1), error, "Fatal test error: accidental code position conflict, move OrgStruct .org to another arbitrary address." +.assert * = start, error, ".org within .struct does not return to previous location at .endstruct" +.assert OrgStruct::ma = 0, error, ".struct with .org has unexpected offset" +.assert OrgStruct::mb = 1, error, ".struct with .org has unexpected offset" +.assert OrgStruct::mc = $1234, error, ".struct with .org has unexpected offset" +.assert OrgStruct::md = $1235, error, ".struct with .org has unexpected offset" +.assert OrgStruct::Nested::me = 0, error, "Nested .struct with .org has unexpected offset" +.assert OrgStruct::Nested::mf = $5678, error, "Nested .struct with .org has unexpected offset" +.assert OrgStruct::Nested::mg = $5679, error, "Nested .struct with .org has unexpected offset" +.assert OrgStruct::mh = $1239, error, ".struct with .org has unexpected offset" +.assert .sizeof(OrgStruct) = 8, error, ".struct with .org has unexpected .sizeof" + +.union OrgUnion + ma .byte + mb .word + .org $1234 + mc .byte + md .word +.endunion + +.assert start <> OrgUnion::md, error, "Fatal test error: accidental code position conflict, move OrgUnion .org to another arbitrary address." +.assert * = start, error, ".org within .union does not return to previous location at .endunion" +.assert OrgUnion::ma = 0, error, ".union with .org has unexpected offset" +.assert OrgUnion::mb = 0, error, ".union with .org has unexpected offset" +.assert OrgUnion::mc = $1234, error, ".union with .org has unexpected offset" +.assert OrgUnion::md = $1234, error, ".union with .org has unexpected offset" +.assert .sizeof(OrgUnion) = 2, error, ".union with .org has unexpected .sizeof"
diff --git a/test/asm/val/struct.s b/test/asm/val/struct.s new file mode 100644 index 000000000..b6ef6f45d --- /dev/null +++ b/test/asm/val/struct.s @@ -0,0 +1,222 @@ +; test .struct and .union features + +.code + +; exit with 0 +.export _main +_main: + lda #0 + tax + rts + +; test storage allocator sizes and offsets + +.struct Storage + mb1 .byte + mb5 .byte 5 + mr1 .res 1 + mr5 .res 5 + mdb1 .dbyt + mdb5 .dbyt 5 + mw1 .word + mw5 .word 5 + ma1 .addr + ma5 .addr 5 + mf1 .faraddr + mf5 .faraddr 5 + mdw1 .dword + mdw5 .dword 5 +.endstruct + +.assert .sizeof(Storage::mb1) = 1, error, ".struct .byte member has unexpected .sizeof" +.assert .sizeof(Storage::mb5) = 5, error, ".struct .byte 5 member has unexpected .sizeof" +.assert .sizeof(Storage::mr1) = 1, error, ".struct .res 1 member has unexpected .sizeof" +.assert .sizeof(Storage::mr5) = 5, error, ".struct .res 5 member has unexpected .sizeof" +.assert .sizeof(Storage::mdb1) = 2, error, ".struct .dbyt member has unexpected .sizeof" +.assert .sizeof(Storage::mdb5) = 10, error, ".struct .dbyt 5 member has unexpected .sizeof" +.assert .sizeof(Storage::mw1) = 2, error, ".struct .word member has unexpected .sizeof" +.assert .sizeof(Storage::mw5) = 10, error, ".struct .word 5 member has unexpected .sizeof" +.assert .sizeof(Storage::ma1) = 2, error, ".struct .addr member has unexpected .sizeof" +.assert .sizeof(Storage::ma5) = 10, error, ".struct .addr 5 member has unexpected .sizeof" +.assert .sizeof(Storage::mf1) = 3, error, ".struct .faraddr member has unexpected .sizeof" +.assert .sizeof(Storage::mf5) = 15, error, ".struct .faraddr 5 member has unexpected .sizeof" +.assert .sizeof(Storage::mdw1) = 4, error, ".struct .dword member has unexpected .sizeof" +.assert .sizeof(Storage::mdw5) = 20, error, ".struct .dword 5 member has unexpected .sizeof" + +.assert Storage::mb1 = 0, error, ".struct storage offset is incorrect" +.assert Storage::mb5 = Storage::mb1 + .sizeof(Storage::mb1), error, ".struct storage offset is incorrect" +.assert Storage::mr1 = Storage::mb5 + .sizeof(Storage::mb5), error, ".struct storage offset is incorrect" +.assert Storage::mr5 = Storage::mr1 + .sizeof(Storage::mr1), error, ".struct storage offset is incorrect" +.assert Storage::mdb1 = Storage::mr5 + .sizeof(Storage::mr5), error, ".struct storage offset is incorrect" +.assert Storage::mdb5 = Storage::mdb1 + .sizeof(Storage::mdb1), error, ".struct storage offset is incorrect" +.assert Storage::mw1 = Storage::mdb5 + .sizeof(Storage::mdb5), error, ".struct storage offset is incorrect" +.assert Storage::mw5 = Storage::mw1 + .sizeof(Storage::mw1), error, ".struct storage offset is incorrect" +.assert Storage::ma1 = Storage::mw5 + .sizeof(Storage::mw5), error, ".struct storage offset is incorrect" +.assert Storage::ma5 = Storage::ma1 + .sizeof(Storage::ma1), error, ".struct storage offset is incorrect" +.assert Storage::mf1 = Storage::ma5 + .sizeof(Storage::ma5), error, ".struct storage offset is incorrect" +.assert Storage::mf5 = Storage::mf1 + .sizeof(Storage::mf1), error, ".struct storage offset is incorrect" +.assert Storage::mdw1 = Storage::mf5 + .sizeof(Storage::mf5), error, ".struct storage offset is incorrect" +.assert Storage::mdw5 = Storage::mdw1 + .sizeof(Storage::mdw1), error, ".struct storage offset is incorrect" +.assert .sizeof(Storage) = Storage::mdw5 + .sizeof(Storage::mdw5), error, ".struct has unexpected .sizeof" + +; test union offset and size + +.union UStorage + mb1 .byte + mb5 .byte 5 + mr1 .res 1 + mr5 .res 5 + mdb1 .dbyt + mdb5 .dbyt 5 + mw1 .word + mw5 .word 5 + ma1 .addr + ma5 .addr 5 + mf1 .faraddr + mf5 .faraddr 5 + mdw1 .dword + mdw5 .dword 5 +.endunion + +.assert .sizeof(UStorage::mb1) = 1, error, ".union .byte member has unexpected .sizeof" +.assert .sizeof(UStorage::mb5) = 5, error, ".union .byte 5 member has unexpected .sizeof" +.assert .sizeof(UStorage::mr1) = 1, error, ".union .res 1 member has unexpected .sizeof" +.assert .sizeof(UStorage::mr5) = 5, error, ".union .res 5 member has unexpected .sizeof" +.assert .sizeof(UStorage::mdb1) = 2, error, ".union .dbyt member has unexpected .sizeof" +.assert .sizeof(UStorage::mdb5) = 10, error, ".union .dbyt 5 member has unexpected .sizeof" +.assert .sizeof(UStorage::mw1) = 2, error, ".union .word member has unexpected .sizeof" +.assert .sizeof(UStorage::mw5) = 10, error, ".union .word 5 member has unexpected .sizeof" +.assert .sizeof(UStorage::ma1) = 2, error, ".union .addr member has unexpected .sizeof" +.assert .sizeof(UStorage::ma5) = 10, error, ".union .addr 5 member has unexpected .sizeof" +.assert .sizeof(UStorage::mf1) = 3, error, ".union .faraddr member has unexpected .sizeof" +.assert .sizeof(UStorage::mf5) = 15, error, ".union .faraddr 5 member has unexpected .sizeof" +.assert .sizeof(UStorage::mdw1) = 4, error, ".union .dword member has unexpected .sizeof" +.assert .sizeof(UStorage::mdw5) = 20, error, ".union .dword 5 member has unexpected .sizeof" +.assert .sizeof(UStorage) = 20, error, ".union has unexpected .sizeof" + +.assert UStorage::mb1 = 0, error, ".union storage offset is incorrect" +.assert UStorage::mb5 = 0, error, ".union storage offset is incorrect" +.assert UStorage::mr1 = 0, error, ".union storage offset is incorrect" +.assert UStorage::mr5 = 0, error, ".union storage offset is incorrect" +.assert UStorage::mdb1 = 0, error, ".union storage offset is incorrect" +.assert UStorage::mdb5 = 0, error, ".union storage offset is incorrect" +.assert UStorage::mw1 = 0, error, ".union storage offset is incorrect" +.assert UStorage::mw5 = 0, error, ".union storage offset is incorrect" +.assert UStorage::ma1 = 0, error, ".union storage offset is incorrect" +.assert UStorage::ma5 = 0, error, ".union storage offset is incorrect" +.assert UStorage::mf1 = 0, error, ".union storage offset is incorrect" +.assert UStorage::mf5 = 0, error, ".union storage offset is incorrect" +.assert UStorage::mdw1 = 0, error, ".union storage offset is incorrect" +.assert UStorage::mdw5 = 0, error, ".union storage offset is incorrect" + +; test tag + +storage: .tag Storage +.assert (*-storage)=.sizeof(Storage), error, ".tag reserved size incorrect" + +; test nested structures + +.struct Point + xc .word + yc .word +.endstruct + +.struct Nested + pad .res 13 + tag .tag Point + ch .struct Child + ca .word ; offset = 0 + gch .struct Grandchild + gca .word ; offset = 0 + gcb .byte + .endstruct + cb .byte + .endstruct + anon .struct + aa .dword ; offset = Nested::anon (anonymous .struct) + ab .dword + .endstruct + chu .union Chunion + ua .byte ; offset = 0 + ub .dword + .endunion + chanon .union + uc .byte ; offset = Nested::chanon + ud .dword + .endunion + last .byte +.endstruct + +.assert Nested::pad = 0, error, "Nested .struct has unexpected starting offset" +.assert Nested::Child::ca = 0, error, "Nested .struct has unexpected starting offset" +.assert Nested::Child::Grandchild::gca = 0, error, "Nested .struct has unexpected starting offset" + +.assert .sizeof(Nested::tag) = .sizeof(Point), error, ".tag in .struct has unexpected .sizeof" +.assert .sizeof(Nested::Child::Grandchild) = 2 + 1, error, "Nested .struct has unexpected .sizeof" +.assert .sizeof(Nested::Child) = 2 + 1 + .sizeof(Nested::Child::Grandchild), error, "Nested .struct has unpexpected .sizeof" +.assert .sizeof(Nested::ch) = .sizeof(Nested::Child), error, "Nested .struct has unexpected member .sizeof" +.assert .sizeof(Nested::Child::gch) = .sizeof(Nested::Child::Grandchild), error, "Nested .struct has unexpected member .sizeof" +.assert .sizeof(Nested::anon) = 8, error, "Nested anonymous member .struct has unexpected .sizeof" +.assert .sizeof(Nested::aa) = 4, error, "Nested anonymous .struct member has unexpected .sizeof" +.assert .sizeof(Nested::ab) = 4, error, "Nested anonymous .struct member has unexpected .sizeof" +.assert .sizeof(Nested::Chunion) = 4, error, "Nested .union has unexpected .sizeof" +.assert .sizeof(Nested::chu) = .sizeof(Nested::Chunion), error, "Nested member .union has unexpected .sizeof" +.assert .sizeof(Nested::chanon) = 4, error, "Nested anonymous member .union as unexpected .sizeof" + +.assert Nested::tag = Nested::pad + .sizeof(Nested::pad), error, ".tag within .struct has unexpected offset" +.assert Nested::ch = Nested::tag + .sizeof(Nested::tag), error, "Nested .struct has unexpected offset" +.assert Nested::anon = Nested::ch + .sizeof(Nested::ch), error, "Nested anonymous member .struct has unexpected offset" +.assert Nested::aa = Nested::anon, error, "Nested anonymous .struct member has unexpected offset" +.assert Nested::ab = Nested::aa + .sizeof(Nested::aa), error, "Nested anonymous .struct member has unexpected offset" +.assert Nested::chu = Nested::ab + .sizeof(Nested::ab), error, "Nested member .union has unexpected offset" +.assert Nested::chanon = Nested::chu + .sizeof(Nested::Chunion), error, "Nested anonymous member .union has unexpected offset" +.assert Nested::uc = Nested::chanon, error, "Nested anonymous .union member has unexpected offset" +.assert Nested::ud = Nested::chanon, error, "Nested anonymous .union member has unexpected offset" +.assert Nested::last = Nested::ud + .sizeof(Nested::ud), error, ".struct member has unexpected offset after anonymous nested .struct" + +; test .org + +start: + +.struct OrgStruct + ma .byte + mb .byte + .org $1234 + mc .byte + md .byte + .struct Nested + me .byte + .org $5678 + mf .byte + mg .byte + .endstruct + mh .byte +.endstruct + +.assert start <> (OrgStruct::mh+1), error, "Fatal test error: accidental code position conflict, move OrgStruct .org to another arbitrary address." +.assert * = start, error, ".org within .struct does not return to previous location at .endstruct" +.assert OrgStruct::ma = 0, error, ".struct with .org has unexpected offset" +.assert OrgStruct::mb = 1, error, ".struct with .org has unexpected offset" +.assert OrgStruct::mc = $1234, error, ".struct with .org has unexpected offset" +.assert OrgStruct::md = $1235, error, ".struct with .org has unexpected offset" +.assert OrgStruct::Nested::me = 0, error, "Nested .struct with .org has unexpected offset" +.assert OrgStruct::Nested::mf = $5678, error, "Nested .struct with .org has unexpected offset" +.assert OrgStruct::Nested::mg = $5679, error, "Nested .struct with .org has unexpected offset" +.assert OrgStruct::mh = $1239, error, ".struct with .org has unexpected offset" +.assert .sizeof(OrgStruct) = 8, error, ".struct with .org has unexpected .sizeof" + +.union OrgUnion + ma .byte + mb .word + .org $1234 + mc .byte + md .word +.endunion + +.assert start <> OrgUnion::md, error, "Fatal test error: accidental code position conflict, move OrgUnion .org to another arbitrary address." +.assert * = start, error, ".org within .union does not return to previous location at .endunion" +.assert OrgUnion::ma = 0, error, ".union with .org has unexpected offset" +.assert OrgUnion::mb = 0, error, ".union with .org has unexpected offset" +.assert OrgUnion::mc = $1234, error, ".union with .org has unexpected offset" +.assert OrgUnion::md = $1234, error, ".union with .org has unexpected offset" +.assert .sizeof(OrgUnion) = 2, error, ".union with .org has unexpected .sizeof"