Menu

Trouble compiling a large program for the 18F15Q40

mkstevo
2022-11-29
2022-12-05
  • mkstevo

    mkstevo - 2022-11-29

    I've written a large program for the 16F1829. As it reached the point where it filled 98% of the device (with much work left to do) I switched to the larger and faster 18F15Q40.

    The program has been progressing until this afternoon when I added more features, the program was occupying 48% or so of the memory before I sat down after lunch. Having added some extra features, I attempted to compile and was surprised to see that many lines of the program showed errors:

    Dual_Hopper/ccTalk_Double_Pay_18F15Q40.gcb (1818): Error: Variable EVENTS(1)
    was not explicitly declared
    

    The above relating to line 1818: I've numbered the lines to make things a little clearer (I hope).

    1814       If CheckHopper = 1 Then
    1815           PollForHEvents(Payment1Address)
    1816           FetchHEvents
    1817          Let CheckHopper = 0
    1818           Let H1Events1 = Events(1)
    1819        Else
    1820            PollForHEvents(Payment2Address)
    1821            FetchHEvents
    1822            Let CheckHopper = 1
    1823            Let H2Events1 = Events(1)
    1825        End If
    1826
    1827        Let Events(1) = H1Events1 + H2Events1
    

    With the error(s) stating that the two lines 1818 and 1823, Events(1) being undeclared. There were other errors found, all in the same subroutine, all relating to variables being undeclared.

    I was very surprised as I had been using near identical code earlier in the day with zero problems.

    Looking at the produced .asm file shows that the references to Events(1) on lines 1818 and 1823 have not been substituted with their "system" variable names, but are referenced to as Events(1). The line 1827 "Let Events(1) = H1Events1 + H2Events1" is compiled correctly, and shows that Events(1) has been assigned the "system" variable name of "SYSEVENTS_1".

    .asm for the above code:

    ;If CheckHopper = 1 Then
        banksel SYSBITVAR0
        btfss   SYSBITVAR0,7,BANKED
        bra ELSE143_1
    ;PollForHEvents(Payment1Address)
        movff   PAYMENT1ADDRESS,POLLADDRESS
        banksel 0
        rcall   POLLFORHEVENTS
    ;FetchHEvents
        call    FETCHHEVENTS
    ;Let CheckHopper = 0
        banksel SYSBITVAR0
        bcf SYSBITVAR0,7,BANKED
    ;Let H1Events1 = Events(1)
        movff   EVENTS(1),H1EVENTS1
    ;Else
        bra ENDIF143
    ELSE143_1
    ;PollForHEvents(Payment2Address)
        movff   PAYMENT2ADDRESS,POLLADDRESS
        banksel 0
        rcall   POLLFORHEVENTS
    ;FetchHEvents
        call    FETCHHEVENTS
    ;Let CheckHopper = 1
        banksel SYSBITVAR0
        bsf SYSBITVAR0,7,BANKED
    ;Let H2Events1 = Events(1)
        movff   EVENTS(1),H2EVENTS1
    ;End If
    ENDIF143
    ;Let Events(1) = H1Events1 + H2Events1
        movf    H2EVENTS1,W,ACCESS
        addwf   H1EVENTS1,W,ACCESS
        banksel SYSEVENTS_1
        movwf   SYSEVENTS_1,BANKED
    

    I don't think this is down to my terrible coding skills, but have no idea how I can fix this.

     
  • mkstevo

    mkstevo - 2022-11-29

    I forgot to say that I downloaded the most recent version of GCStudio and it failed with the same errors flagged there too.

     
    • Anobium

      Anobium - 2022-11-29

      I would need the source to figure it out.

       
      • mkstevo

        mkstevo - 2022-11-29

        Thanks. I've had to email it as it was too large for me to send as a PM. If it doesn't turn up, let me know.

         
        • Anobium

          Anobium - 2022-11-29

          The email truncated the lines of code.

          Please send as an attachment.

           
          • mkstevo

            mkstevo - 2022-11-29

            Apologies, resent. Hopefully correctly this time.

             
  • Anobium

    Anobium - 2022-11-29

    As a workaround change the array Events() to Event_s() Just anything but Event

    and, add

    Dim PayingCoinAmount as Byte


    Seems that Events is reserved on the 18F.

     
  • mkstevo

    mkstevo - 2022-11-29

    Many, many, many thanks for that. It now, indeed, compiles.

    Really odd that I have been using "Events()" on the 18F15Q40 for well over a week (and on the 16F1829 on and off for 2 years or so) with no problems whatsoever. Program compiled and ran on the 18F15Q40 perfectly well up until this afternoon, the earlier version without the mods I made is still running now at work and it uses "Events()" in vast numbers of subroutines. I did a search and replace of "Events(" in the code, it found 66 statements referring to "Events(" all working normally. How very odd.

    It is an ambitious, untidy and rather unweildy set of code. I'm far from certain I will actually be able to to get it to work fully. It is for (yet) another Change Machine. In my opinion I've previously built and coded a much, much better design in every way. This is for a replacement PCB (and code) for one of our competitor's machines where their electronic design is electrically unreliable. I'm confident mine will be electrically reliable but not in the least confident I can get the complex software to be reliable. Still, it is a quiet period at work now so I've got time to sit and code 'till my head bursts - which it did today.

     
    • Anobium

      Anobium - 2022-11-30

      See my analysis.

      This is not coding related, not chip related, not memory related - see the details below.

       
  • Anobium

    Anobium - 2022-11-30

    I have spent all day trying to find the root cause to the issue.

    An update.

    Symptom

    Error message the an array or array element is not defined.

    Error: Variable EVENTS(1) was not explicitly declared.

    Examination

    The error message states a variable is not defined (not array element) and ASM shows variable usage for a byte variable. However, this is actually defined as an array element in the source program.

    H2Events1 = Events(1) movff EVENTS(1),H1EVENTS1

    The ASM also show the allocation of a byte memory address for a variable called EVENT(1)

    The use of EVENT(1) is a symptom that the program is meant to access an element with the array EVENT() but is it actually accessing a byte variable that has no relation to the array. :-(

    The user code is impacting the compilation process. The failure is a critical failure that should not occur.

    The specific user case follows:

    H2Events1 = Events(1) where the source array name is substring of the target variable AND the array element is a CONSTANT. In this case INSTR("H2EVENT1", "EVENT") <> 0 so, EVENT is within H2EVENT1.

    Example Code

    #CHIP 16F1829
    #OPTION EXPLICIT
    
    Dim Events(11)
    Dim H1Events1 
    
    Events(1)=1
    H1Events1 = Events (1)
    H1Events1 = Events (2)
    H1Events1 = Events (11)
    

    yields

    Errors have been found:
     first-start-sample.gcb (34): Error: Invalid variable name: EVENTS(1)
     first-start-sample.gcb (34): Error: Variable EVENTS(1) was not explicitly declared
     first-start-sample.gcb (35): Error: Invalid variable name: EVENTS(2)
     first-start-sample.gcb (35): Error: Variable EVENTS(2) was not explicitly declared
     first-start-sample.gcb (36): Error: Invalid variable name: EVENTS(11)
     first-start-sample.gcb (36): Error: Variable EVENTS(11) was not explicitly declared
    

    Workaround

    Ensure the source array name is not a substring of the target variable.

    Root Cause

    The root cause is deep inside the compiler within a function that examines if a string exists with another string. This is a complex comparison that needs to address maths functions, where a simple INSTR() will not cover the range of use cases.

    This specific use case of where the source array name is substring of the target variable ( the error case) does not return the correct value.

    The errant line of compiler source is:

    IF (( WholeINSTR(InLine, .Name ) = 2 AND INSTR(InLine, "(") <> 0)  THEN
    

    WholeINSTR() why it does not match the substring to 2 hence the failure to indentiify the EVENT(n) as an array element.

    The root cause is the function WholeINSTR() . There is no documentation in WholeINSTR() and it may take a many more hours to understand how this function operates to ensure any change does not break other users of WholeINSTR(). WholeINSTR() is used many times across the compiler, so, great care must be taken.


    End of report. I will try to fix asap.

     
  • mkstevo

    mkstevo - 2022-11-30

    Ah...

    So that's why it had previously worked well.

    All other references to "Events(1)" assigned the result or value to a variable which didn't incorporate the word 'Events" anywhere within the target variable name.

    I was trying to assign the variables returned in Events() to a new variable as I knew I would need to update Events() in the following lines of code and wanted to preserve them before they were overwritten. I named them "H1Events1" and H2Events1" (and H1Events2, H2Events2 and so on) so I could more easily recognise the values held by them. Earlier iterations of the code didn't need to reuse "Events()" and so didn't need to save the values in additional variables.

    I should add that the suggestion of changing "Events()" to "Event_s()" did work correctly. I've made some major changes to the code and it now is working as I wanted. Been on it all day (again) and the Change Machine is now able to pay the value of inserted coin distributed evenly across two hoppers, halving the time taken to dispense the coins, with any payment errors detected and then corrected where required.

     
    • Anobium

      Anobium - 2022-11-30

      The workaround is valid. As proven by my root cause analysis today.

      Well done on the great program!

       
  • Anobium

    Anobium - 2022-12-01

    Trying to fix this for the future is proving to be very hard. I need more eyes on this issue.

    I have expanded the function that test for a substring within a string, adding a load of debug, as this has ‘magic’ that is hard to understand what is actually going on.

    And, I have added ( between the change number #1199 ) a new test for that is meant to resolve H1Events1 = Events (1) or H1Events1 = Events(1) where the array string search would be Events.

    Findings/Assumption today.
    None of the original tests give a score where T > 0
    So, is it safe to assume the string exists twice as the 'No match at all - exit with 0 test have been passed – We have at least one match but failed all tests.
    So, replace with the FS (#0030) char, and, do it all again.
    For this specific use case if becomes H1?FS?1 = Events (1) or H1?FS?1 = Events(1), so, original now work.

    Your thoughts please?

    Evan

    FUNCTION WholeINSTR (DataIn As String, FindIn As String, SearchAgain As Integer = -1) As Integer
      Dim As String DataSource, Temp, Find
      Dim As Integer T
      DataSource = UCase(DataIn): Find = UCase(FindIn)
    
      if WholeINSTRdebug then print  "$"+DataSource+"$", "|"+Find+"|", " results ",
    
      IF INSTR(DataSource, Find) = 0 THEN 
        'No match at all - exit with 0
        WholeINSTR = 0
        if WholeINSTRdebug then print 0
        EXIT FUNCTION
      End If
    
      IF LEN(DataSource) = LEN(Find) THEN 
        'Perfect match - exit with 2
        WholeINSTR = 2
        if WholeINSTRdebug then print 2
        EXIT FUNCTION
      End If
    
      DoWholeINSTRAgain:
      T = 0
    
      IF INSTR(DataSource, Find) = 1 THEN 
        'MATCHED at the start of the line, so set T to 1 ( not sure why yet... )
        if WholeINSTRdebug then print "a";
        T = 1  
      End if
    
      IF T = 0 THEN
    
        'Only get here when the substring is NOT at the start of the line and NOT perfect match
        'So, extract a SINGLE character before the start of the find string, and see if is one of these, it is set T = 1
        '    " " ( ) , . : ; + - * / %
        '    = ! < > { } ~ & | #
        '    [ ]  9  160
        '
        '      
        '  the last character of the first match of find string 
        Temp = Mid(DataSource, INSTR(DataSource, Find) - 1, 1)
        IF IsDivider(Temp) THEN 
          T = 1
          if WholeINSTRdebug then print "b";
        END IF
      END IF
    
      IF INSTR(DataSource, Find) + LEN(Find) - 1 = LEN(DataSource) THEN 
        'If the find string and its location in the search string less 1 is the same as the search string then....
        'Is the a plural check?   Is this meant to be the end of string check?
        T = T + 1
        if WholeINSTRdebug then print "c";
      End If
    
      IF T < 2 THEN
        'So, at this point ..T could be 0 or 1
        'So, extract the next SINGLE character after the find position, and see if is one of these, it is increment T
        '    " " ( ) , . : ; + - * / %
        '    = ! < > { } ~ & | #
        '    [ ]  9  160
    
        Temp = Mid(DataSource, INSTR(DataSource, Find) + LEN(Find), 1)
        if WholeINSTRdebug then Print ":"+Temp+":";
        IF IsDivider(Temp) THEN 
          T = T + 1
          if WholeINSTRdebug then print "d";
        END IF
      END If
    
      'Found 1 condition matched, do it all again if there is another match after the first is removed.
      IF T = 1 And SearchAgain THEN
        'So, swap any FIND string for chr(30) and do it again.
        Replace DataSource, Find, Chr(30)
        IF INSTR(DataSource, Find) <> 0 THEN 
          if WholeINSTRdebug then print "e";
          GOTO DoWholeINSTRAgain
        END IF
      END IF
    
      'Start of #1199
      'So, no match for all the conditions
      'If there is duplicate search, remove the first occurance  
      IF T = 0 And SearchAgain THEN
        'So, swap any FIND string for chr(30) and do it again.
        Replace DataSource, Find, Chr(30)
        IF INSTR(DataSource, Find) <> 0 THEN 
          if WholeINSTRdebug then print "f";
          GOTO DoWholeINSTRAgain
        END IF
      END IF
      'End of #1199
    
      WholeINSTR = T
      if WholeINSTRdebug then print "g"+str(T)
    
    END FUNCTION
    
     
    • mkstevo

      mkstevo - 2022-12-01

      I'm sorry but I can't offer much by the way of thoughts on your comment as it has gone right over my head. It has gone way too deep for my skillset.

      As the resulting variable name of "H1?FS?1" would only be visible in the .asm, with my (more readable) H1Events1 remaining in the source file that would seem to be an elegant solution. {If I've not totally misunderstood that which you are patiently explaining to me}

      Or could a warning be generated stating that variable "Events()" has a duplicate declaration of "H1Events1" and requires renaming?

       
      • Anobium

        Anobium - 2022-12-01

        Steve - not to worry. This is intended for those that know the inner works of the compiler.

        FYI.. This whole test is just to ensure an (any) array element exists on any line of the user program. You do not see this in the asm as the result is used for this array element existence validation. This way way before any ASM. The area of the compiler that is broken by the functions failure is the part where the compiler optimises the array element when using a constant to an alias (which you do see in the ASM).

         
  • Anobium

    Anobium - 2022-12-01

    From Hugh. Documentation.

    WholeInstr is there to check if a string contains a substring within it, but with dividers.

    The returned value should be 0 if the substring is not in there by itself.
    The returned value should be 1 if the substring is in there, but has something before or after it.
    The returned value should be 2 if the string is in there with a divider at either side.

    Examples:
    WholeInstr("ABC", "B") = 0
    WholeInstr("AB C", "B") = 1
    WholeInstr("A BC", B") = 1
    WholeInstr("A B C", "B") = 2

    So WholeInstr("H1Events1", "Events") should be returning 0, because 1 is not a divider character.

    The well named T variable is the output. If the substring is there with a divider (or the start of the string) before it, 1 is added. If the substring is there with a divider (or the end of the string) after it, another 1 is added.

    A divider character should be anything that IsDivider says is a divider. The start or end of a string is also treated as a divider, hence the special case for if the substring is the entire string.

     
  • Anobium

    Anobium - 2022-12-01

    More insights to the issue:

    The program below shows the issue. It is not related to the chip family.

    #CHIP 18F16Q41
    #OPTION EXPLICIT
    
    Dim Events(11)
    Dim H1Events1 
    
    Events(1)=1
    H1Events1 = Events(1)
    H1Events1 = Events(2)
    H1Events1 = Events(11)
    
    Errors with array not defined
    

    The issue is in the function WholeINSTR.

    I have produced a new build 1199 that Steve can test. It has a revised function that should resolve. I am discussing with Hugh but I have submitted the build for release.

     
  • Anobium

    Anobium - 2022-12-02

    There is a new test compiler in the GC Studio Dev Channel.

    Steve please test. Revert the array naming that caused the issue and please test.

     
  • mkstevo

    mkstevo - 2022-12-05

    I have, as requested, re-named Event_s() back to Events() and recompiled using the release candidate and the program now compiles and runs normally.

    Great Cow BASIC (1.00.00 2022-12-02 (Windows 64 bit) : Build 1200)
    

    Thanks for all the suggestions given, they really helped.

     

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.