Shop OBEX P1 Docs P2 Docs Learn Events
New BASIC compiler for Prop1 and Prop2 - Page 17 — Parallax Forums

New BASIC compiler for Prop1 and Prop2

11415171920

Comments

  • jmgjmg Posts: 15,175
    msrobots wrote: »
    ... That would provide the ability to watch and even manipulate a running program.
    ..

    Surely a proper debugger that can single step, is the best way to 'watch and even manipulate a running program' ?
    Most MCU users expect to load just their pgm (nothing else apart from a possible debug switch), and then break/step/watch all their variables.
    ie the best debuggers are as invisible as technically possible.

  • There are other ways. "Best" is always a relative thing.

  • jmg wrote: »
    msrobots wrote: »
    ... That would provide the ability to watch and even manipulate a running program.
    ..

    Surely a proper debugger that can single step, is the best way to 'watch and even manipulate a running program' ?
    Most MCU users expect to load just their pgm (nothing else apart from a possible debug switch), and then break/step/watch all their variables.
    ie the best debuggers are as invisible as technically possible.

    Sure and @Cluso99 has put that into the ROM as callable functions. But watching your program while running, without adding debug statements might be helpful too, I met errors disappearing when run in 'debug mode'.

    And on a Propeller with 8 cores running a Monitor COG does not influence the 'user pgm' at all. That is quite invisible.

    But to be able to compile with fastspin to a given start address could also be useful for overlays or chained programs leaving some lower ram undisturbed.

    My end goal here is to even call that parallel running TAQOZ sub system to be able to use TAQOZ one liners from any language.

    Sadly @"Peter Jakacki" is also not interested in this idea, but basically TAQOZ does support input and output redirection, say VGA/PS2 instead of serial. So it should be possible to get some redirection done to a standard mailbox schema as used on a P1.

    And then it is just a callable object like any other...

    Enjoy!

    Mike
  • jmgjmg Posts: 15,175
    msrobots wrote: »
    Sure and @Cluso99 has put that into the ROM as callable functions. But watching your program while running, without adding debug statements might be helpful too,

    Here we hit differing semantics around 'watch'.
    Sure, being able to stimulate and test a running pgm will be great in P2, but mention debug and watch to most users, and they expect a Variable Watch screen, in a MCU Debugger.
    msrobots wrote: »
    And on a Propeller with 8 cores running a Monitor COG does not influence the 'user pgm' at all. That is quite invisible.

    and more semantics around Monitor.
    Where Monitor is used in the English sense, to Observe, the P2 will be very good at, but there is also Monitor Software, which is like a poor mans debugger.
    Usually, Monitor Software does influence the user pgm/resources, tho it tries to keep out of the way.
    msrobots wrote: »
    .. I met errors disappearing when run in 'debug mode'.
    That depends on the 'debug mode' - P2 hardware should allow quite low intrusion software step/debug.
    It will likely need some serial pins, and modest memory.


    Self Test/Stimulate and Measure using other cogs, can be almost invisible to the tested COG, but you also have limited crash recovery, and any variable watch has to be by co-operation.
  • msrobots wrote: »
    there is something else I am thinking about. I still want to somehow coexist with TACOZ while programming but it might have other uses too.

    To coexist with TAQOZ one would need to compile and load the binary behind TAQOZ so not starting at HUB $0 but starting at HUB $10000 leaving the first 64K free for TAQOZ.

    The basic Idea would be to run TAQOZ on COG0 and the 'user' program on cog1-7. That would provide the ability to watch and even manipulate a running program.

    Hmmm, that's an interesting idea. I think it should be possible to add a command line option to fastspin to change the base address for P2 from $400 to whatever the user wants. The only tricky part is what to do with the COG code; probably move most of it up to the new base address as well, and leave only a "coginit" stub at address 0.

    We'd then have to add another option to strip the first part of the output data from the binary. That is, we'd want to remove the "coginit stub" from 0, and also all of the padding, to get just the raw program that can run at the new address.

    Eventually it'd be nice to have an option to produce relocatable binaries that can run at any address. The P2 architecture should make this possible in principle, but I think getting it right would be tricky.

  • With the HOT chip, and the simple monitor Chip did, I was able to examine a running program, and even change displays. Kill the VGA COG, load a TV COG, start, and the other parts of the program were unaware. Those displays were simple bitmaps, so no display flags to worry about, but the concept was there anyway.

  • Dave HeinDave Hein Posts: 6,347
    edited 2019-01-08 01:56
    I have a few random comments, which may help, or may not. loadp2 has a -s option that allows setting a different start address than zero. It assumes that the code is structured the same way as if it were loaded at zero, meaning that the cog image is at the beginning of the code. In the p2gcc source tree I have a demo program called shell.c. It is built to run at location $8000. The shell program can run binaries that are located on an SD card. The binaries are just the other sample programs that are built to run from location zero. You can build and run the shell program using the script file load_shell.

    At one time p2gcc did support a relocatable binary mode. Most of the jumps and calls use relative addressing, so they are already position-independent. However, accesses to data uses absolute addresses, which require relocating when running from a different addresses. I accomplished this by putting all the data addresses in a table in cog RAM. When the program started up it would add a memory offset to all the values in the address table if the program stated at a address other than zero. I removed this feature because I felt the address table in cog RAM was to limiting, and I also ran into a few other technical issues.

    I plan on supporting a relocatable mode in the future by including a symbol table in the binary file, and adjust all the data accesses at load time.


  • Dave Hein wrote: »
    I plan on supporting a relocatable mode in the future by including a symbol table in the binary file, and adjust all the data accesses at load time.

    Maybe this would be a good time to add ELF/DWARF support?

  • @"Dave Hein",

    oh this is interesting, I will try it out if that does what I think it does, very helpful.

    Thanks,

    Mike


  • David Betz wrote: »
    Dave Hein wrote: »
    I plan on supporting a relocatable mode in the future by including a symbol table in the binary file, and adjust all the data accesses at load time.

    Maybe this would be a good time to add ELF/DWARF support?

    Maybe. I started looking at it a few months ago, and I began writing a utility that would convert a p2gcc object file to ELF/DWARF. Needless to say, it didn't take me too long to find something more interesting to work on. :)

    It's probably time to look at it again.
  • Dave Hein wrote: »
    David Betz wrote: »
    Dave Hein wrote: »
    I plan on supporting a relocatable mode in the future by including a symbol table in the binary file, and adjust all the data accesses at load time.

    Maybe this would be a good time to add ELF/DWARF support?

    Maybe. I started looking at it a few months ago, and I began writing a utility that would convert a p2gcc object file to ELF/DWARF. Needless to say, it didn't take me too long to find something more interesting to work on. :)

    It's probably time to look at it again.
    Yeah, it's probably not the most exciting project to work on. It would be great to have ELF support for your assembler though.

  • Cluso99Cluso99 Posts: 18,069
    msrobots wrote: »
    @ersmith,

    there is something else I am thinking about. I still want to somehow coexist with TACOZ while programming but it might have other uses too.

    To coexist with TAQOZ one would need to compile and load the binary behind TAQOZ so not starting at HUB $0 but starting at HUB $10000 leaving the first 64K free for TAQOZ.

    The basic Idea would be to run TAQOZ on COG0 and the 'user' program on cog1-7. That would provide the ability to watch and even manipulate a running program.

    Currently I see 2 ways to archive that, one way would be to boot into TAQOZ and then load a binary compiled for ORGH $10000 from TACOZ and start it then in COG1, this would just require to compile as you do now with a different start address.

    The second way would be a binary having most of the first 64 k empty except some code to start cog1 with the program and then gently jmp COG0 into TAQOZ start in ROM.

    And that will overwrite the first 64K HUB out of the ROM.

    COG0 would then run TAQOZ and @Cluso99's Monitor/Debugger in parallel to the user program.

    short:

    could you add some ORGH to your compiler name it BASEADDRESS or something else?

    Mike

    Already works. Just write your program with TAQOZr2 starting at hub $0 (less 1 long to jmp to your code in HUB to do whatever, including running TAQOZr2).

    You see, when you write your program it starts at hub $0 and expands upwards. If you have say 5KB of code and then do an ORGH $1_0000 the compiler will zero fill between the 5KB and $1_0000. Your program can actually be 1MB long but you will of course have problems with our 512KB P2. That's how we tested the ROM code in the first place.
  • Dave Hein wrote: »
    loadp2 has a -s option that allows setting a different start address than zero. It assumes that the code is structured the same way as if it were loaded at zero, meaning that the cog image is at the beginning of the code.
    Thanks Dave! That sounds like it will be very useful for testing.
    At one time p2gcc did support a relocatable binary mode. Most of the jumps and calls use relative addressing, so they are already position-independent. However, accesses to data uses absolute addresses, which require relocating when running from a different addresses.
    It'd be interesting to look at what GCC does for the various -fPIC and -fPIE modes to produce relocatable code for other processors. Perhaps some of that could be leveraged. With the P2 "loc" instruction it is possible to find data in a PC-relative way. We'd still need some kind of base register + offset to handle statically initialized pointers though, so probably your suggestion of load time relocation is a better one.

    For fastspin I just realized that there is some primitive relocation code present already (I wrote it to allow the "wrapped" Spin version of the COG PASM to work with openspin; in order to do this in Spin in a portable way it's necessary to fix up addresses, since standard spin doesn't support @ @ @). I might be able to leverage this to get relocatable code relatively easily.
  • twm47099twm47099 Posts: 867
    edited 2019-01-09 23:26
    I'm not sure if this goes here or in the other thread.

    I wrote a BASIC function "asc3204" for the P2-ES. It reads the voltage on one of the 4 channels of an MCP3204 and returns the raw ADC value to a BASIC program. In my program I test each of the 4 channels and print the results to the terminal and repeat. Channels 0 and 1 are connected to potentiometers so I can vary the voltage. Channel 2 is connected to 3.3volts and channel 3 is connected to ground.

    The function works. I would like to run the function in a different cog than the calling program. I tried using the "cpu" command, but I don't think that is for calling functions. I tried recasting the function as a subroutine, but that also did not work, the values reported for the ADC value were all 4095.

    (I have written basic programs that do use sub's in other cogs, including one that increments a global variable (dim in the main program) in a different cog, and prints the number from the main program. That program is not as complicated as the ADC one and there is no synchronization between the cog. )

    I'm not sure where variables & constants need to be declared (in the sub or in the main). I'm also not sure how the pin commands should be used. I did try a version where I put the direction statements in the sub, but that didn't fix the result. I attempted some debugging by printing some of the sub's variables in the main program (such as "command") and that worked.

    Any suggestions? Is it possible to call a function (as opposed to a sub) in another cog, and if so how can a value be returned to the calling program?

    The program that runs in one cog is listed below.
    ' 3204_function.bas
    
    '    Initialize
    ' clock will be set to 180MHz  At 180MHz, needed 1ms delay in sub clockbit
    ' set terminal baud to 2000000
    
      'const _mode = 0x010C1F08
      'const _clkfreq = 80_000_000	' 2,000,000 Baud
      const _mode = 0x010C4708
      const _clkfreq = 180_000_000	' 2,000,000 Baud
      clkset(_mode, _clkfreq)
      _setbaud(2000000)
    
         '  Pin assignments
    const SCLK = 8
    const MISO = 9
    const MOSI = 10
    const CS = 11
    
    dim command
    dim raw
    dim volts#
    
    direction(SCLK) = output
    direction(MISO) = input
    direction(MOSI) = output
    direction(CS) = output
    
    sub clockbit		' send clock high-low
      output(SCLK) = 1
    pausems 1		' needed to get correct results at 180 MHz
      output(SCLK) = 0
    end sub
    
    ' ****************************
    function adc3204(z)
    '	in: z = channel number
    '	needs: "sub clockbit" outside of function
    '	returns: raw ADC value
    ' ****************************
    dim raw1
    	' make reversed command for MSBFIRST xmit to 3204
    select case z
    case 0 : command = 0b00011
    case 1 : command = 0b10011
    case 2 : command = 0b01011
    case 3 : command = 0b11011
    end select
    
    	' initialize 3204
    output(CS) = 1 
    output(SCLK) = 0
    output(CS) = 0				' chip select low = make MCP3204 active
    
    	' send command 1 startbit high, 4 command bits, 1 don't care bit
    for j = 1 to 5
      output(MOSI) = command and 1  : clockbit
      command = command / 2			' shift right
    next j
    output(MOSI) = 0  : clockbit		' send dont care bit
    
    	' Get 13 bit Data from 3204
    raw1 = 0
    for k = 1 to 13
      raw1 = raw1 * 2			' shift left 1 bit
      raw1 = raw1 or (input(MISO) and 1) : clockbit 
    next k
    
    raw1 = raw1 and 4095	' make 12 bit raw
    output(CS) = 1		' deselect 3204
    return raw1
    end function
    ' *************************
    
    ' ***** Test adc3204 function
    for m = 1 to 1000
      for i = 0 to 3
        raw = adc3204(i)
    
    	' calculate volts and print results
        volts# =  raw * 500 / 4096
        volts# = volts# / 100
        print " ch# "; i; " raw = "; raw; "  "; volts#; " V" 
        pausems(100)
      next i
      pausems(500)
      print : print "-------"
    next m
    
    
  • twm47099twm47099 Posts: 867
    edited 2019-01-10 05:17
    I did some tests and got the function running in both the calling cog and in a new cog. It seems to work.

    However,
    I am still having a problem with synchronization of the results.
    When run in a new cog I get the following for one "for i= 0 to 3 ... next i" loop:
    -------
     ch# 3 raw = 0  0.0000 V
     ch# 0 raw = 3746  4.5700 V
     ch# 1 raw = 1764  2.1500 V
     ch# 2 raw = 2780  3.3900 V
    -------
    
    The values are correct for the channels listed, but ch#3 should be at the end of a loop.

    When run in the same cog as the calling function the results print out in channel order as expected.

    Commenting out the "for i...." and next i statements and uncommenting dim i and setting i = 0, 1, 2, or 3 gives
    ch# 0 raw = 0  0.0000 V
    
    for the first time through the "for m" loop and then the correct value for the selected channel every subsequent time .

    I recall that with the P1, I had to be careful when sending data pairs between cogs, so if the numbers were bytes or words, I would pack them into one integer in the sending cog and unpack in the receiving cog. I've done the same thing here, and that resulted in getting voltage data that corresponded to the correct channel, but didn't resolve the issue with channel 3 being first in the listing.

    Any ideas?
    The code I'm using:
    ' 3204_function.bas
    
    '    Initialize
    ' clock will be set to 180MHz  At 180MHz, needed 1ms delay in sub clockbit
    ' set terminal baud to 2000000
    
      'const _mode = 0x010C1F08
      'const _clkfreq = 80_000_000	' 2,000,000 Baud
      const _mode = 0x010C4708
      const _clkfreq = 180_000_000	' 2,000,000 Baud
      clkset(_mode, _clkfreq)
      _setbaud(2000000)
    
    const SCLK = 8
    const MISO = 9
    const MOSI = 10
    const CS = 11
    
    dim stack(256)
    dim command
    dim raw
    dim volts#
    dim aaa
    
    sub clockbit		' send clock high-low
      output(SCLK) = 1
    pausems 1		' needed to get correct results at 180 MHz
      output(SCLK) = 0
    end sub
    
    ' ****************************
    function adc3204(z, raw1 =0)
    '	in: z = channel number
    '	needs: "sub clockbit" outside of function
    '	returns: raw ADC value
    ' ****************************
    'dim raw1
    direction(SCLK) = output
    direction(MISO) = input
    direction(MOSI) = output
    direction(CS) = output
    	' make reversed command for MSBFIRST xmit to 3204
    select case z
    case 0 : command = 0b00011
    case 1 : command = 0b10011
    case 2 : command = 0b01011
    case 3 : command = 0b11011
    end select
    aaa = command
    	' initialize 3204
    output(CS) = 1 
    output(SCLK) = 0
    output(CS) = 0				' chip select low = make MCP3204 active
    
    	' send command 1 startbit high, 4 command bits, 1 don't care bit
    for j = 1 to 5
      output(MOSI) = command and 1  : clockbit
      command = command / 2			' shift right
    next j
    output(MOSI) = 0  : clockbit		' send dont care bit
    
    	' Get 13 bit Data from 3204
    raw1 = 0
    for k = 1 to 13
      raw1 = raw1 * 2			' shift left 1 bit
      raw1 = raw1 or (input(MISO) and 1) : clockbit 
    next k
    
    raw1 = (raw1 * 4) or z 	' shift left 2 bits and put channel num in b0 and b1
    
    aaa = raw1
    output(CS) = 1		' deselect 3204
    return raw1		
    end function
    ' *************************
    
    ' ***** Test adc3204 function
    for m = 1 to 1000
    
      for i = 0 to 3
      'dim i : i = 1
       var a = cpu(adc3204(i), @stack(1))	' comment out if function NOT in new cog
       'aaa = adc3204(i)			' comment out if function in new cog
    raw = aaa
    var chanum = raw and 3
    raw = raw / 4
    
    	' calculate volts and print results
        volts# =  raw * 500 / 4096
        volts# = volts# / 100
    
        print " ch# "; chanum; " raw = "; raw; "  "; volts#; " V" 
        pausems(300)
      next i
      pausems(500)
      print : print "-------"
    next m
    
    
  • I found the problem. I needed a time delay of at least 20ms between calling the function in the new cog and collecting the result.
    for i = 0 to 3
      'dim i : i = 1                                    
       var a = cpu(adc3204(i), @stack(1))	   ' comment out if function NOT in new cog
       'aaa = adc3204(i)			' comment out if function in new cog
        pausems(50)             ' ***** This pause is needed when function is run in new cog *****
    raw = aaa
    var chanum = raw and 3
    raw = raw / 4
    
    	' calculate volts and print results
        volts# =  raw * 500 / 4096
        volts# = volts# / 100
    
        print " ch# "; chanum; " raw = "; raw; "  "; volts#; " V" 
        pausems(300)
      next i
    
  • Glad you got it sorted out. A few general tips for using code in multiple COGs:

    (1) Any pin setup you want to do (setting direction, for example) has to be done in the COG that's actually using the PINs. So if you're running a sub on another COG you'll have to set that up there.

    (2) There isn't any way (yet) to run a function on another COG and get its result back. You'll have to do what you've been doing, run the sub and store the result in a global, and provide some kind of synchronization. Pausing is one way, but you could also make the sub set a flag to indicate that the result is ready and test for that flag in the main program.

    (3) If you're sharing variables between COGs it might be helpful to declare them as "dim shared".
  • RaymanRayman Posts: 14,755
    This might be a bug. But, could also be that I'm abusing something...
    I'm trying to see if I can get this spin only version of FSRW to work on P2.
    Getting an error that I can't figure out:
  • @Rayman : looks like somewhere along the way the abort / catch code for P2 got broken. I'm working on a fix for it.
  • RaymanRayman Posts: 14,755
    Ok, thanks. BTW: I never use abort in my own code. I might just remove it from this one...
  • RaymanRayman Posts: 14,755
    That was it, changed all aborts to returns and now it compiles.
  • RaymanRayman Posts: 14,755
    edited 2019-01-16 15:12
    Just looking at multest.spin2 sample...
    Is there a multiply.spin file somewhere? I'm not seeing it...
    It compiles so must exist somewhere, right?

    Never mind, found it in the samples folder...
  • RaymanRayman Posts: 14,755
    ersmith: Was C support for FastSpin something of an experiment?
    Or, do plan to still work on it? I think it's not really an advertised feature right now, right?

    Was just thinking about adding C mode to SpinEdit...
  • Rayman wrote: »
    ersmith: Was C support for FastSpin something of an experiment?
    Or, do plan to still work on it? I think it's not really an advertised feature right now, right?

    Was just thinking about adding C mode to SpinEdit...

    It's not an advertised feature because it's still so incomplete, but I do plan to finish it (I'm still working on it). So a C mode for SpinEdit would be useful!
  • RaymanRayman Posts: 14,755
    edited 2019-01-19 22:38
    I'm adding a C mode now...
    Tried to compile an example but get can't find files error for stdio.h and propeller.h.

    I'm guessing that I need to add a library folder option for this mode and copy the "include" folder from spin2gui to it.
    Or, maybe just look for an include folder wherever fastspin.exe is...

    I think I see that fastspin will search subfolders for include files, so I can just use the library -L option.

    Can you have both -L and -I? Or, multiples of each?
  • Rayman wrote: »
    I'm adding a C mode now...
    Tried to compile an example but get can't find files error for stdio.h and propeller.h.

    I'm guessing that I need to add a library folder option for this mode and copy the "include" folder from spin2gui to it.

    That's probably the best option. You can pass multiple -L parameters (they get searched in the order they're given on the command line).
    Or, maybe just look for an include folder wherever fastspin.exe is...

    The default include path is based on the binary where fastspin.exe is, but up one level. That is, if the fastspin executable is "MyDocuments\fastspin\bin\fastspin.exe", then the default search path for include files is "MyDocuments\fastspin\bin\..\include", which translates to "MyDocuments\fastspin\include". As always, -L overrides this.

    (The -L and -I options are identical at the moment.)



  • I was just looking through the docs pdf for flex basic, it looks like you finalized flex basic, the docs are excellent. The one thing that I saw missing, or maybe it will not be supported, are interrupts for the P2. When the P2 becomes available for the masses, I will probably use it for a project, but I am not sure if I will ever use interrupts. Not even sure as to how that could be used with flex basic and if there would be any benefit to use it. Just curious.

    Ray
  • Ray: I don't have any plans to support interrupt routines right now. That's not to say it'll never happen, just that I don't have any plans at the moment. I only have so much time in the day :) and a lot of it has to go to my real job.

  • jmgjmg Posts: 15,175
    ersmith wrote: »
    Ray: I don't have any plans to support interrupt routines right now. That's not to say it'll never happen, just that I don't have any plans at the moment. I only have so much time in the day :) and a lot of it has to go to my real job.

    There should be some basic INTERRUPT support possible already I think, even if the user has to manually preload these registers, it should work ?
    To set up an interrupt, you need to first point its IJMP register to your interrupt service routine (ISR). When the interrupt occurs, it will jump to where the IJMP register points and simultaneously store the C/Z flags and return address into the adjacent IRET register:
    
    $1F0		RAM / IJMP3		interrupt call   address for INT3
    $1F1		RAM / IRET3		interrupt return address for INT3
    $1F2		RAM / IJMP2		interrupt call   address for INT2
    $1F3		RAM / IRET2		interrupt return address for INT2
    $1F4		RAM / IJMP1		interrupt call   address for INT1
    $1F5		RAM / IRET1		interrupt return address for INT1
    

  • @jmg: Yes, you can manipulate the registers directly, but you'll have to write the interrupt service routines in assembly -- there's no direct support for making high level functions interrupt handlers. Doing so would require changes such as special entry code (to save registers that normally we don't need to save, like the multiply temporaries) and exit code (to use the IRET instruction instead of regular RETA). It's possible, but it will be work.

Sign In or Register to comment.