Forums » Programming with the ECS »
armt32semihostrun.obf : take into account size of globals
Added by Runar Tenfjord about 1 year ago
With reference to the runtime for armt32 I wonder how to
take into account the global variables which will be placed
in ram?
I adjusted a bit the initialization of the heap, but this ony takes
into account what is in the assembler file:
; heap start .data _heap_start .alignment 4 .reserve 4 .require _init_heap .initdata _init_heap .alignment 4 ldr r0, [pc, offset (heap)] ldr r1, [pc, offset (start)] str r1, [r0, 0] b skip heap: .qbyte @_heap_start start: .qbyte extent (@ram) skip:
I run this test code:
MODULE Test; IMPORT SYSTEM; TYPE STRING = POINTER TO ARRAY OF CHAR; VAR global, a, b, c, d : INTEGER; PROCEDURE Run ; VAR s : STRING; BEGIN global := 123456789; NEW(s, 25); TRACE(s); DISPOSE(s); TRACE(s); TRACE(global); TRACE(SYSTEM.ADR(global)); TRACE(SYSTEM.ADR(a)); TRACE(SYSTEM.ADR(b)); TRACE(SYSTEM.ADR(c)); TRACE(SYSTEM.ADR(d)); END Run; BEGIN Run; END Test.
The allocation works fine, but there is an overlap with the globals:
qemu-system-arm -M mps2-an386 -semihosting -nographic -device loader,file=build/test.rom,addr=0x00000000 test.mod:17:11: note: 's' = 20000004 test.mod:19:11: note: 's' = 00000000 test.mod:20:11: note: 'global' = 25 test.mod:21:21: note: 'SYSTEM.ADR (global)' = 20000000 test.mod:22:21: note: 'SYSTEM.ADR (a)' = 20000004 test.mod:23:21: note: 'SYSTEM.ADR (b)' = 20000008 test.mod:24:21: note: 'SYSTEM.ADR (c)' = 2000000C test.mod:25:21: note: 'SYSTEM.ADR (d)' = 20000010
Is there some obvious fix for this?
Replies (14)
RE: armt32semihostrun.obf : take into account size of globals - Added by Florian Negele about 1 year ago
The _ram
data section only exists such that the linker knows where to place all following data sections for global variables. With the attached patch, the heap initialisation can reference the _trailer
section instead, which will be placed at the end of all other data sections, see map file.
linker.patch (434 Bytes) linker.patch |
RE: armt32semihostrun.obf : take into account size of globals - Added by Runar Tenfjord about 1 year ago
Thank you.
Now about 400 tests run on the simulated QEMU armt32 environment.
I have only some small test failures to investigate, which could likely
be error in the code.
The modified runtime:
; Only works on Cortex-M profile ARMv6-M and ARMv7-M ; Uses only Thumb1 16bit instructions to support Coretex-M0/M0+ ; Flash/memory origin and size must be changed to values for target device. .code vector .required .origin 0x00000000 ; flash .qbyte 0x20004000 ; stack = ram top .qbyte extent (@vector) + 1 ; +1 for Thumb flag #repeat 15 .qbyte @handle + 1 ; +1 for Thumb flag #endrep .code handle .alignment 4 loop: b.n loop .data ram .required .origin 0x20000000 ; ram start ; last section .trailer _trailer ; standard abort function .code abort .alignment 4 ldr.n r0, offset (SYS_EXIT) + offset (SYS_EXIT) % 4 ldr.n r1, offset (ADP_Stopped_ApplicationExit) + offset (ADP_Stopped_ApplicationExit) % 4 bkpt.n 0xab loop: b.n loop .align 4 SYS_EXIT: .qbyte 0x18 ADP_Stopped_ApplicationExit: .qbyte 0x20026 ; standard _Exit function .code _Exit .alignment 4 bl @abort ; standard getchar function .code getchar .alignment 4 ldr.n r0, offset (SYS_READC) + offset (SYS_READC) % 4 mov r1, 0x00 bkpt.n 0xab bx.n lr .align 4 SYS_READC: .qbyte 0x07 ; standard free function .code free .alignment 4 bx.n lr ; standard malloc function .code malloc .alignment 4 ldr.n r2, offset (heap) + offset (heap) % 4 ldr.n r0, [r2, 0] ldr.n r3, [sp, 0] add.n r3, r3, r0 str.n r3, [r2, 0] bx.n lr heap: .qbyte @_heap_start ; heap start .data _heap_start .alignment 4 .reserve 4 .require _init_heap .initdata _init_heap .alignment 4 ldr r0, [pc, offset (heap)] ldr r1, [pc, offset (start)] str r1, [r0, 0] b skip heap: .qbyte @_heap_start start: .qbyte extent (@_trailer) skip: ; standard putchar function .code putchar .alignment 4 ldr.n r0, offset (SYS_WRITEC) + offset (SYS_WRITEC) % 4 mov r1, sp bkpt.n 0xab ldr.n r0, [r1] bx.n lr .align 4 SYS_WRITEC: .qbyte 0x03
RE: armt32semihostrun.obf : take into account size of globals - Added by Florian Negele about 1 year ago
I have successfully tested your runtime against the test suites provided by the ECS. Out of interest, could you provide an example of a failing test?
RE: armt32semihostrun.obf : take into account size of globals - Added by Runar Tenfjord about 1 year ago
Good.
I need to dig a bit and reduce this to smaller examples
if this should not be related to a code error from my side.
RE: armt32semihostrun.obf : take into account size of globals - Added by Runar Tenfjord about 1 year ago
Not sure this is an error or not.
But the following code behaves somewhat different
when comparing values:
MODULE test; IMPORT SYSTEM, Out IN OBL; TYPE WORD = SYSTEM.ADDRESS; WSET = SYSTEM.SET; CONST WORDSIZE = SIZE(WORD); (** Hash value of string (64/32bit FNV-1a) *) PROCEDURE Hash* (src- : ARRAY OF CHAR): LENGTH; CONST HSTART = SEL(WORDSIZE = 4, 0811C9DC5H, 0CBF29CE484222325H); HFACTOR = SEL(WORDSIZE = 4, 01000193H, 0100000001B3H); VAR i : LENGTH; hash : LENGTH; BEGIN hash := LENGTH(HSTART); i := 0; WHILE (i < LEN(src)) & (src[i] # 00X) DO hash := LENGTH(WSET(src[i]) / WSET(hash)); (* XOR *) hash := hash * LENGTH(HFACTOR); INC(i) END; RETURN hash END Hash; BEGIN IF SIZE(SYSTEM.ADDRESS) = 8 THEN Out.Address(Hash('foobar')); Out.Ln; (* Expec 085944171F73967E8H *) TRACE(Hash('foobar') = 085944171F73967E8H); ELSE Out.Address(Hash('foobar')); Out.Ln; (* Expec 0BF9CF968H *) TRACE(Hash('foobar') = 0BF9CF968H); (* FALSE? *) TRACE(Hash('foobar') = LENGTH(0BF9CF968H)); END; END test.
The constant 0BF9CF968H on 32bit platforms is perhaps evaluated as 64bit
and the sign bit created the difference?
RE: armt32semihostrun.obf : take into account size of globals - Added by Florian Negele about 1 year ago
Yes exactly. A binary operation like the equal relation always uses the smallest numeric type that includes both operands.
RE: armt32semihostrun.obf : take into account size of globals - Added by Runar Tenfjord about 1 year ago
This goes into infinite loop on the armt32 platform, but works OK and prints the expected
output of '-123' on the 64bit Win10 platform:
MODULE test; IMPORT SYSTEM, Out IN OBL; TYPE STRING = POINTER TO ARRAY OF CHAR; Writer = RECORD END; StringWriter = RECORD(Writer) str : STRING; pos : LENGTH; END; VAR s : STRING; PROCEDURE Length (str-: ARRAY OF CHAR) : LENGTH; VAR i: LENGTH; BEGIN i := 0; WHILE (i < LEN(str)) & (str[i] # 00X) DO INC(i) END; RETURN i END Length; PROCEDURE (VAR w : Writer) WriteChar*(ch : CHAR); BEGIN END WriteChar; PROCEDURE (VAR s : StringWriter) WriteChar(ch : CHAR); VAR n: LENGTH; BEGIN ASSERT(s.pos < LEN(s.str^) - 1); n := Length(s.str^); s.str^[n + 0] := ch; s.str^[n + 1] := 00X; INC(s.pos, 1); END WriteChar; PROCEDURE Format(VAR Writer : Writer; value : HUGEINT; width: LENGTH); VAR val, x : HUGECARD; i, len, digits, left : LENGTH; str : ARRAY 20 OF CHAR; BEGIN IF value = MIN(HUGEINT) THEN (* -MIN(HUGEINT) does not exists *) val := 9223372036854775808 ELSE val := ABS(value); END; len := 0; x := val; REPEAT INC(len); x := x DIV 10 UNTIL x = 0; digits := len; IF value < 0 THEN INC(len) END; left := width - len; WHILE left > 0 DO Writer.WriteChar(' '); DEC(left) END; IF value < 0 THEN Writer.WriteChar('-') END; i := digits; REPEAT DEC(i); str[i] := CHR(ORD('0') + val MOD 10); val := val DIV 10; UNTIL val = 0; i := 0; WHILE (i < digits) DO Writer.WriteChar(str[i]); INC(i) END; END Format; PROCEDURE FormatInteger(VAR dst: STRING; value : HUGEINT; width: LENGTH); VAR writer : StringWriter; BEGIN writer.str := dst; writer.pos := Length(dst^); Format(writer, value, width); dst := writer.str; END FormatInteger; BEGIN NEW(s, 25); s[0] := 00X; FormatInteger(s, -123, 0); TRACE(s^); DISPOSE(s); END test.
RE: armt32semihostrun.obf : take into account size of globals - Added by Florian Negele about 1 year ago
There was an alignment issue regarding HUGEINT
types. The attached patch should fix it. Thanks for reporting.
align.patch (629 Bytes) align.patch |
RE: armt32semihostrun.obf : take into account size of globals - Added by Runar Tenfjord about 1 year ago
Confirmed to fix the problem.
This goes into infinite loop on the armt32 platform, but works OK on the 64bit Win10 platform:
MODULE test; IMPORT SYSTEM, Out IN OBL; TYPE DATETIME = HUGEINT; CONST ERROR = MIN(HUGEINT); VAR dt : DATETIME; MonthDays: ARRAY 2, 12 OF INTEGER; ShiftedMonthDays: ARRAY 12 OF INTEGER; PROCEDURE IsLeapYear (year : INTEGER) : BOOLEAN; BEGIN RETURN (year MOD 4 = 0) & ((year MOD 100 # 0) OR (year MOD 400 = 0)) END IsLeapYear; PROCEDURE RataDie (year, month, day : INTEGER): HUGEINT; VAR mdays : INTEGER; BEGIN IF month < 3 THEN DEC(year) END; mdays := ShiftedMonthDays[month - 1]; RETURN day + mdays + 365*year + year DIV 4 - year DIV 100 + year DIV 400 - 306; END RataDie; PROCEDURE TryEncodeDate (VAR date : DATETIME; year,month,day : INTEGER) : BOOLEAN; VAR ret : BOOLEAN; BEGIN ret := (year > 0) & (year < 10000) & (month > 0) & (month < 13) & (day > 0) & (day <= MonthDays[INTEGER(IsLeapYear(year)), month - 1]); IF ret THEN date := 86400000 * RataDie(year, month, day); END; RETURN ret; END TryEncodeDate; PROCEDURE EncodeDate (year, month, day : INTEGER): DATETIME; VAR date : DATETIME; BEGIN IF ~TryEncodeDate(date, year, month, day) THEN date := ERROR END; RETURN date; END EncodeDate; PROCEDURE TryEncodeDateTime (VAR datetime : DATETIME; year, month, day, hour, min, sec, msec : INTEGER) : BOOLEAN; VAR ret : BOOLEAN; BEGIN ret := TryEncodeDate(datetime, year, month, day); IF ret THEN ret := (hour >= 0) & (hour < 24) & (min >= 0) & (min < 60) & (sec >= 0) & (sec < 60) & (msec >= 0) & (msec < 1000); IF ret THEN datetime := datetime + msec + 1000*(sec + 60*min + 3600*hour); END; END; RETURN ret; END TryEncodeDateTime; PROCEDURE EncodeDateTime(year, month, day, hour, min, sec, msec: INTEGER): DATETIME; VAR datetime : DATETIME; BEGIN IF ~TryEncodeDateTime(datetime, year, month, day, hour, min, sec, msec) THEN datetime := ERROR; END; RETURN datetime; END EncodeDateTime; BEGIN MonthDays[0,0] := 31; MonthDays[0,1] := 28; MonthDays[0,2] := 31; MonthDays[0,3] := 30; MonthDays[0,4] := 31; MonthDays[0,5] := 30; MonthDays[0,6] := 31; MonthDays[0,7] := 31; MonthDays[0,8] := 30; MonthDays[0,9] := 31; MonthDays[0,10] := 30; MonthDays[0,11] := 31; MonthDays[1,0] := 31; MonthDays[1,1] := 29; MonthDays[1,2] := 31; MonthDays[1,3] := 30; MonthDays[1,4] := 31; MonthDays[1,5] := 30; MonthDays[1,6] := 31; MonthDays[1,7] := 31; MonthDays[1,8] := 30; MonthDays[1,9] := 31; MonthDays[1,10] := 30; MonthDays[1,11] := 31; ShiftedMonthDays[0] := 306; ShiftedMonthDays[1] := 337; ShiftedMonthDays[2] := 0; ShiftedMonthDays[3] := 31; ShiftedMonthDays[4] := 61; ShiftedMonthDays[5] := 92; ShiftedMonthDays[6] := 122; ShiftedMonthDays[7] := 153; ShiftedMonthDays[8] := 184; ShiftedMonthDays[9] := 214; ShiftedMonthDays[10] := 245; ShiftedMonthDays[11] := 275; dt := EncodeDateTime(2019,11,15,16,43,20,0); TRACE(dt); END test.
RE: armt32semihostrun.obf : take into account size of globals - Added by Florian Negele about 1 year ago
Thanks for reporting. This is an issue that needs a little more time to fix. Use this in the mean time:
INC (datetime, msec + 1000*(sec + 60*min + 3600*hour));
RE: armt32semihostrun.obf : take into account size of globals - Added by Runar Tenfjord about 1 year ago
Very good. With the fixes now in place 494 test
runs successful. Some 20 tests due to the issue
above where disabled.
On the todo list is floating point support which need
more work.
You might consider adding this runtime to the next
release, as this could be very useful and would cover
a large number of MCUs in use today.
I there is something I need to do formally to
make that happen, just give me a note.
RE: armt32semihostrun.obf : take into account size of globals - Added by Florian Negele about 1 year ago
We might consider it. How would you call such a runtime? Please note that it should support physical hardware, but apart from the semihosting routines and the simplistic memory management there is nothing much left except for the boot vector.
RE: armt32semihostrun.obf : take into account size of globals - Added by Runar Tenfjord about 1 year ago
It could be called "armt32v7mrun.obf" after the identification
ARMv7-M, which is the ARMv7 architecture and M profile
covering M3, M4 & M7 MCUs and supporting Thumb-1 & Thumb-2.
If later Thumb-1 only is supported by the compiler there could be
a runtime called "armt32v6mrun.obf" after the identification ARMv6-M,
which is the ARMv6 architecture and M profile covering M0 & M0+ MCUs
The instruction to call the semihost interface "BKPT 0xAB" is tied to
ARMv6-M & ARMv7-M.
RE: armt32semihostrun.obf : take into account size of globals - Added by Runar Tenfjord about 1 year ago
If you want to tie the runtime/examples to a specific board the STM32F407G-DISC1
from ST is a great and accessible board.
This board has the possibility to be simulated with graphics, led and buttons
by the qemu-system-gnuarmeclipse emulator (legacy version) which emulates
a lot of peripherals not covered by mainstream QEMU.