Menu

#453 __sdcc_external_startup return checking for STM8 and Z80 platforms

None
closed-accepted
5
2023-01-19
2023-01-14
No

Here is a patch to the behaviour for __sdcc_external_startup on STM8 and Z80-derivative platforms to unify their behaviour with that documented for the existing MCS51 implementation.

Init code will now check the return value from __sdcc_external_startup and when it is non-zero, the initialisation of global variables will be skipped.

The following platforms have been changed:

  • STM8
  • Z80
  • Z80N
  • Z180
  • eZ80
  • SM83
  • R2K
  • R2KA
  • R3KA
  • TLCS-90

Changes to Z80 platforms have been done in their respective standard library crt0.s code, and STM8 changes are to init code generated in stm8/main.c.

The modifications assume the use of the documented default calling convention version when handling the return value from __sdcc_external_startup. That is, specifically, on Z80 platforms whether the return value is in A or L.

All changes have been tested with uCsim, with the exception of SM83, as uCsim does not appear to support that platform (neither specifically nor using the Z80 emulator).

1 Attachments

Related

Feature Requests: #859
Patches: #455
Wiki: NGI0-Entrust-SDCC

Discussion

  • Basil Hussain

    Basil Hussain - 2023-01-14

    Attached are the test program and scripts I used to validate these changes.

    Using a version of SDCC installed with the patch applied, build the test program using build.sh. A number of sub-folders, one per platform, will be created. Each will contain two compiled test .ihx programs: one to test 1 being returned from __sdcc_external_startup ('skip'); one to test 0 being returned ('no_skip').

    Run the tests using test.sh. This will run each compiled test program in turn using the relevant uCsim executable. All the 'skip' programs should print INIT SKIPPED on the console, and all the 'no_skip' programs should print INIT NOT SKIPPED.

    I thought maybe it would be a good idea for similar tests to be added to the regression testing set, if there were any possibility?

     

    Last edit: Basil Hussain 2023-01-14
  • Philipp Klaus Krause

    uCsim supports the GameBoy, which uses the sm83 architecture.

     
  • Basil Hussain

    Basil Hussain - 2023-01-14

    It seems SDCC does not build the gbz80 simulator by default. I don't have it from my own builds on Linux, nor is it in a recent Windows snapshot.

    But this confusing, because running ./configure --help from within the ucsim folder shows that you specifically have to disable ports (e.g. --disable-gbz80-port), and I can't find any suggestion that SDCC's build process configures or makes uCsim with any of those options.

    I will try to build uCsim with all ports enabled and test SM83 with ucsim_gbz80.

     
  • Basil Hussain

    Basil Hussain - 2023-01-14

    Wait, I'm an idiot. I was expecting a separate ucsim executable. There is none. I just need to run ucsim_z80 with a -t GB80 argument.

    I have stepped through the new init code and can confirm it works properly for SM83.

    However, I don't seem to able to get the ucsim-if working to allow printing to the simulator console from test code. Must be something about the GB's memory layout I'm missing. Seems like whatever memory location I choose for the ucsim-if virtual register nothing works, and I get no output.

     
    • Philipp Klaus Krause

      I suggest to have a look at how the printing is done in the regression tests (support/regression/ports/ucgbz80).

       
      • Basil Hussain

        Basil Hussain - 2023-01-14

        Thank you. I got it working now.

        Updated test scripts attached.

         
  • Basil Hussain

    Basil Hussain - 2023-01-16

    Updated patch attached, now with mos6502 port support as well.

     
    • Philipp Klaus Krause

      I've had a quick look at this patch; it mostly works fine, but I see regressions for mos6502:

      Summary for 'uc6502': 5 failures, 23883 tests, 3352 test cases, 6395338 bytes, 289057384 ticks
         Failure: cases/gte_loop-ivopts-1.c
         Failure: cases/tst_gcc-torture-execute-20020615-1.c
         Failure: cases/tst_gcc-torture-execute-20031204-1.c
         Failure: cases/zeropad/zeropad_storage___idata.c
         Failure: cases/zeropad/zeropad_storage___pdata.c
      
       
      • Basil Hussain

        Basil Hussain - 2023-01-18

        I ran the regressions tests for uc6502 myself. All the failures mentioned were linking errors, and all were identical:

        ?ASlink-Warning-Byte PCR relocation error
                 file              module            area              offset
          Refby  ../../device/l    crt0              GSINIT                   0007
          Defin  ../../device/l    crt0              GSFINAL                  0000
        

        The ASxxxx documentation describes that error as "caused by exceeding the pc relative byte branch range". It would appear that is indeed the case in these failures. If I look at the .map file from the first test, the start addresses for the aforementioned sections were as follows:

             00000200  s_GSINIT                        
             000002FC  s_GSFINAL                       
        

        From what I have found, bne instructions using relative addressing can only specify an offset in the range of -128 to +127. And of course, trying to jump +0xFC bytes (or some value approximate to that) doesn't fit in that range!

        This raises the question: why is GSFINAL so far away from GSINIT? And why only in these particular tests? The GSINIT code in crt0 isn't that large (only 0x33 bytes). According to the .map file there are no other sections inserted between either. Some other stuff must have been appended to GSINIT - but what? How can I find out?

        I suppose the solution here is one of two things:

        • Don't use a relative bne instruction to skip init. Use an absolute jmp instead.
        • Don't attempt to branch to __sdcc_program_startup in GSFINAL, but simply skip over just the init code, and let execution proceed through to there.
         
      • Basil Hussain

        Basil Hussain - 2023-01-18

        Ahh, I think I found out where the extra stuff in GSINIT came from.

        These tests have a bunch of data in static/global variables (e.g. arrays of floats) that need to be initialised. But for some reason this is done with additional generated code (e.g. streams of stx) rather than letting the init code copy the data. I was not aware that this was how the mos6502 port operated.

        The only solution will be to use an absolute jump to skip init, because it will need to skip all this potential extra stuff in GSINIT too, whereas skipping to the end of the init code in crt0 will still allow that to run.

        I don't believe any of the Z80-based ports should suffer from this problem, as they perform the skip by not making a subroutine call, and it appears anything added to GSINIT falls within that subroutine.

        I don't believe the STM8 port ever does any code-based init, so nothing is likely to be added to GSINIT (correct me if I'm wrong), but I may also modify that to use an absolute jump too, just in case. Maybe simply do a jump to __sdcc_program_startup in HOME?

         
  • Basil Hussain

    Basil Hussain - 2023-01-16

    Updated test scripts also.

     
    • Philipp Klaus Krause

      I don't really know what to do with this.
      Converting it to a regression test would be problematic: It would require the regression test infrastructure to not rely on the initialization of global/static variables (after all the return value from __sdcc_external_startup affects the global/static variables from all files).

       
      • Basil Hussain

        Basil Hussain - 2023-01-17

        No worries, was just an idea. I primarily included the tests to prove that all the changes work as intended. They are incidental to the patch.

         
  • Philipp Klaus Krause

    • assigned_to: Philipp Klaus Krause
    • Group: -->
     
  • Basil Hussain

    Basil Hussain - 2023-01-18

    Regression test failures are now fixed:

    Summary for 'uc6502': 1 failures, 23930 tests, 3348 test cases, 6412747 bytes, 237747113 ticks
       Failure: cases/tst_gcc-torture-execute-arith-rand-ll
    

    That single remaining failure is same as I got before: a "CPU time limit exceeded" error. Not sure why I'm getting it and you didn't, Philipp.

    Updated patch attached.

    While I was looking again at the STM8 port, I also fixed a potential deficiency in the way __sdcc_program_startup was being jumped to from GSFINAL in the normal course of operations. A jp instruction was always used, regardless of memory model. I have changed the code to use a jpf instruction when --model-large is used. That will cope with the case of user ever deciding to relocate HOME >32kB in flash.

     
    • Philipp Klaus Krause

      Thanks. Applied in [r13796].

       

      Related

      Commit: [r13796]

  • Philipp Klaus Krause

    • status: open --> closed-accepted
     

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.