Detailed Listing from OpenSpin

Like a number of people before me, I found myself in need of understanding where my Propeller code is located in memory. However, I seem to have taken a different approach to the problem. Instead of disassembling the generated binary, I have instrumented the OpenSpin compiler.

This has the disadvantage that it can only be applied to code assembled with OpenSpin.

Conversely, it enables the listing to refer directly to the source code. An abbreviated example output is given below.

My additions to OpenSpin can be found at: https://github.com/Memotech-Bill/OpenSpin

The code probably needs further testing, but it does everything that I want, and I can go back to trying to work out what is wrong with my Propeller code.
0000     03D09000      Frequency 64000000
0004     67            Clock Mode
0005     D9            Check Sum
0006     0010          Base of Program
0008     6D9C          Base of Variables
000A     75D4          Base of Stack
000C     01C4          Initial Program Counter
000E     75D8          Initial Stack Pointer
                       File "MTX_Monitor_11.spin"
0010     1580 0417     Link to Next Object
0014     01B4 0000     Link to MAIN
0018     0235 0000     Link to GETPOS

<<< Many lines omitted >>>

                       PUB Main
                               BufIn := 0
01C4     35            ; Push_0
01C5     41            ; Pop_Varmem_Long_0
                               BufOut := 0
01C6     35            ; Push_0
01C7     45            ; Pop_Varmem_Long_1
                               inp.Start (@Buffer, @BufIn, @BufOut)
01C8     01            ; Frame_Call_Noreturn
01C9     8B 20         ; Reference_Variablemem_Byte, $0020
01CB     43            ; Reference_Varmem_Long_0
01CC     47            ; Reference_Varmem_Long_1
01CD     06 1801 061A  ; Objcall, $1801, $061A
                               Text  := vdp.GetBuffer
01D0     00            ; Frame_Call_Return
01D1     06 1A02 0006  ; Objcall, $1A02, $0006
                               FontAddr := vga.FontLoc
01D5     00            ; Frame_Call_Return
01D6     06 1703 0148  ; Objcall, $1703, $0148

<<< Many lines omitted >>>

                       File "MTX_Video_8.spin"
1590     2BA0 0004     Link to Next Object
1594     2B30 0008     Link to START
1598     2B84 0004     Link to STOP
159C     2B9B 0000     Link to FONTLOC
                       DAT
     000                               org
15A0 000 5C7C00A5      video           jmp     #init0
15A4 001 A2BD47F0      vsync           mov     tpage1, par     wz      ' Test for first cog
15A8 002 A0BD47F1                      mov     tpage1, cnt             ' Get current time
15AC 003 082946A2              if_z    wrlong  tpage1, pagead          ' Save time for first cog to hub ram
15B0 004 A0FD4E02                      mov     line_cnt, #vs           ' Number of lines of vertical sync
15B4 005 5CFD0E7B                      call    #blank_vsync            ' Output sync pulse
15B8 006 08BD48A2                      rdlong  tpage2, pagead          ' Fetch time of first cog
15BC 007 84BD48A3                      sub     tpage2, tpage1          ' Time difference between cogs
15C0 008 A0FD4E1A      vb_lines        mov     line_cnt, #vb - 8       ' Number of lines in vertical back porch (cog 0 starts 8 lines early)
15C4 009 5CFD0E7B                      call    #blank_vsync            ' Output back porch

<<< Many lines omitted >>>

                       Variables for TOP (MTX_Monitor_11.spin)
6D9C                   long BUFIN
6DA0                   long BUFOUT
6DA4                   long TEXT
6DA8                   long TTOP
6DAC                   long DATPTR
6DB0                   long PATPART
6DB4                   long FONTADDR
6DB8                   long DATCTR
6DBC                   byte BUFFER[2048]
75BC                   byte GDAT[6]
                       Variables for TOP.VGA (MTX_Video_8.spin)
75C4                   byte COG[3]
                       Variables for TOP.INP (MTX_Input_2.spin)
75C8                   byte NCOG
75CC                   Reserved 8 bytes.
75D4                   Base of stack.
75E4                   Top of stack.

Comments

  • Neat, listings were like the one major feature missing from OpenSpin, but I hope you were/are aware that both BSTC and HomeSpun have has listing support for a long time already.
  • Welcome to the forum. Great first post!
  • Nice!
    I hope we can get that 'officially' soon.

    Where can I sign the e-petition?
    :-D
  • If Bill thinks is solid enough to pull into the main OpenSpin repo, then I am willing to do that.
    Just need to fixup the changes he made to the banner when you run it and the readme
  • Awesome, this is really a good, and long awaited, addition.

    I have compiled your source on Linux and found a couple of issues:

    1. Without the new -l on the command line it gives a segmentation error (missing some null checks ?)
    2. Compiling one of my projects, the listing is a bit weird, I tried to reproduce on a smaller source without success, here is an excerpt:
    0000     04C4B400      Frequency 80000000
    0004     6F            Clock Mode
    0005     1E            Check Sum
    0006     0010          Base of Program
    0008     45CC          Base of Variables
    000A     6630          Base of Stack
    000C     0C1B          Initial Program Counter
    000E     6640          Initial Stack Pointer
                           File "terminal.spin"
    0010     15F0 060C     Link to Next Object
    0014     0C0B 000C     Link to MAIN
    0018     0F93 0000     Link to GET_NRCS_MAP
    001C     0FC9 000C     Link to DECODE
    0020     10A7 000C     Link to KEYPRESSED
    0024     12D6 0000     Link to ENTERSETTINGS
    0028     12FD 0000     Link to EXITSETTINGS
    002C     13A2 0000     Link to UPDATESETTINGS
    0030     1511 0000     Link to UPDATEKEYCONFIG
    0034     1569 0004     Link to PRINTAT
    0038     1585 000C     Link to OVERLAYPARAMS
    003C     15A5 0004     Link to GET_MAP
                            cursor_save
    0040     15F0 1FE0     r_save
    0044     23CC 1FE0       usb_buf[64]
    0048     257C 2048     usb_report[8]
    004C     2B8C 2048       kb_last
    0050     3F98 2048     if
    0054     43A4 2048     long  kb_str_table
                           S_LOCK)
         000               K)
    0058 000 A0BFEC87       $20)
    005C 001 5CFCC659      ar(c)
    0060 002 867D2607      peat i from 0 to 11
    0064 003 5C680037      ble][i]
    0068 004 867D2608      te[@nrcs][i]
    006C 005 5C68003E               ' Do nothing
    0070 006 867D2609      #KeyCapsLock:
    0074 007 5C680040      llLock:
    0078 008 867D260A              kb#KeySpace..kb#KeyMaxCode:
    007C 009 5C680044      _str_table][c - kb#KeySpace]
    0080 00A 867D260C              repeat strsize(ptr)
    0084 00B 5C680048                      ptr++
    0088 00C 867D260D      RI enterSettings
    008C 00D 5C680057          cursor.byte[CY] := 0
    0090 00E 867D261B      or.byte{CM} := (cursor.byte{CM} & constant(!CURSOR_MASK)) | CURSOR_OFF
    0094 00F A0A9428D      | CURSOR_OFF
    0098 010 5C6800A4       1
    009C 011 08BD2C91      sor.byte & constant(!CURSOR_MASK)) | CURSOR_ON | ee_config[4]
    00A0 012 A0BD2A90      e_config[4]
    00A4 013 A0FD2E0C      (ee_config[2])
    00A8 014 00BD2495      ]
    00AC 015 80FD2A01      ble_1 := @strTable
    00B0 016 863D2493             kb_str_table_1 := @strTableApp
    00B4 017 00BD2496      
    00B8 018 80FD2C01      le_1 := @strTableWS
    00BC 019 E4D52E14      nfig[6]
    00C0 01A A0A92692      _table_2 := @strTable
    00C4 01B E1FD1650         2:
    00C8 01C 5C4C0020      
    00CC 01D 877D1818      _1
    00D0 01E 80F11801      2])
    00D4 01F 5CCCF464      s_table_1
    00D8 020 A0BD2A8C      _nrcs_table_2
    00DC 021 2CFD2A04      
    00E0 022 A0BD2C95      ettings
    00E4 023 2CFD2C02          0:
    00E8 024 80BD2C95      F0, string("US"))
    00EC 025 80BD2C8B            printAt(7, 44, $F0, string("IT"))
    00F0 026 2CFD2C01      tAt(7, 44, $F0, string("UK"))
    00F4 027 A0BD2A83        3:
    00F8 028 80BD2A96      ng("FR"))
    

    I tried the same command line on other projects and doesn't seems to have issues. This particular source uses conditional compiles (#ifdef, etc.), maybe an incompatibility with that feature ?

    A suggestion: allow to write the listing on a file instead of stdout.

    Keep up the good work!
  • @Wuerfel_21
    Thank you for the pointers. I am still fairly new to the Propeller community, and dit not know what to search for.

    @Roy Eltham
    Flattered. My main concern at the moment would be the translation of the binary into byte-code mnemonics. In particular the interpretation of the op_Effect and op_Unsigned_Effected_Offset parameters of some byte-codes.

    @macca
    I will look into this.
  • @macca
    Segfault resolved by latest commit.

    With the example you show
    0040     15F0 1FE0     r_save
    
    is being listed in Object Link format, and then
                           S_LOCK)
         000               K)
    0058 000 A0BFEC87       $20)
    
    is being listed in PASM format.

    Without a copy of the source code I am unable to determine the cause. Are you able to post the source?
  • The source is a bit big and complex, however I did some other tests and was able to reproduce with a smaller source.
    Looks like an issue with the conditional compilation, I modified a sample hello world in the spin standard library as follows:
    CON
        _clkmode = xtal1 + pll16x
        _xinfreq = 5_000_000
    
    OBJ
        ser : "com.serial"
    
    PUB Main
    
        ser.Start(115200)
    
    #ifdef TEST
        ser.Char("H")
        ser.Char("e")
        ser.Char("l")
        ser.Char("l")
        ser.Char("o")
        ser.Char(" ")
    #endif
        ser.Char("w")
        ser.Char("o")
        ser.Char("r")
        ser.Char("l")
        ser.Char("d")
        ser.Char("!")
        ser.Char(10)
    

    And the listing shows this:
    PUB Main
                               ser.Start(115200)
    001C     01            ; Frame_Call_Noreturn
    001D     3A 01C200     ; Push_Mid_Lit, $01C200
    0021     06 0201 3877  ; Objcall, $0201, $3877
                           EST
    0024     01            ; Frame_Call_Noreturn
    0025     38 77         ; Push_Byte_Lit, $77
    0027     06 0206 386F  ; Objcall, $0206, $386F
                           H")
    002A     01            ; Frame_Call_Noreturn
    002B     38 6F         ; Push_Byte_Lit, $6F
    002D     06 0206 3872  ; Objcall, $0206, $3872
                           e")
    0030     01            ; Frame_Call_Noreturn
    0031     38 72         ; Push_Byte_Lit, $72
    0033     06 0206 386C  ; Objcall, $0206, $386C
                           l")
    0036     01            ; Frame_Call_Noreturn
    0037     38 6C         ; Push_Byte_Lit, $6C
    0039     06 0206 3864  ; Objcall, $0206, $3864
                           l")
    003C     01            ; Frame_Call_Noreturn
    003D     38 64         ; Push_Byte_Lit, $64
    003F     06 0206 3821  ; Objcall, $0206, $3821
                           o")
    0042     01            ; Frame_Call_Noreturn
    0043     38 21         ; Push_Byte_Lit, $21
    0045     06 0206 380A  ; Objcall, $0206, $380A
                            ")
    0048     01            ; Frame_Call_Noreturn
    0049     38 0A         ; Push_Byte_Lit, $0A
    004B     06 0206 0008  ; Objcall, $0206, $0008
                           File "com.serial.spin"
    

    Attached is a zip file with the sources. Compile with and without -DTEST to see the difference.

  • Memotech_BillMemotech_Bill Posts: 14
    edited 2020-05-03 - 12:24:39
    macca wrote: »
    Looks like an issue with the conditional compilation,

    Quite right. In order to generate the listing I re-load the source files, and I was not pre-processing them correctly so my text pointers were not pointing to the correct place in the source. Should be corrected by my latest commit.

    An alternative would have been to keep an in-memory copy of the source code when it is first loaded by the compiler, however that could have resulted in a substantial increase in memory usage.

    You suggested re-directing the listing to a file. I can see some advantages to that, however I am not sure how best to do that on the command line. Possibilities:

    * Listing could always go to <source name>.lst

    * -l switch could always take a file name, with "-" to select stdout.

    * Could use the syntax -l=<filename>

    Which would be preferred?
  • Quite right. In order to generate the listing I re-load the source files, and I was not pre-processing them correctly so my text pointers were not pointing to the correct place in the source. Should be corrected by my latest commit.

    Very good, works perfectly now, even with the other bigger project. Thank you!

    While you are at it, check also if there is a similar issue with the -u (unused method elimination), I don't have evidence of any, just to be sure.
    An alternative would have been to keep an in-memory copy of the source code when it is first loaded by the compiler, however that could have resulted in a substantial increase in memory usage.

    With today's available memory I don't see it as a problem, after all OpenSpin won't run on a 64k system and the sources are few hundreths kbytes at most, on complex projects.
    You suggested re-directing the listing to a file. I can see some advantages to that, however I am not sure how best to do that on the command line.

    For me, a listing should always be written to a file, since it is intended as a way to see what the compiler actually has produced so in my opinion doesn't make sense to have it on stdout at all. Maybe try with multi-letter parameter: -l write to file <output>.lst, -lc write to console output. Also I think it would be better to use the output file name (as specified by -o or default) instead of the source file so it is possible to compile projects with conditional compilation and save the related listing.
  • Homespun (and I think BSTC,too) writes it's listings to <output>.lst
  • macca wrote: »
    While you are at it, check also if there is a similar issue with the -u (unused method elimination), I don't have evidence of any, just to be sure.

    Good call. Unused method elimination also causes problems, although for different reasons. This is going to take a bit more work.
  • Memotech_Bill,
    Unused method elimination basically does 2 compiles of everything. The first one compiles as "normal" but tracks the info needed to know what's used and what's not, then the second one uses the info while compiling to skip unused stuff.
    If you can have your stuff "off" during the first compile, then on for the second one, that should work out I think.
  • Memotech_BillMemotech_Bill Posts: 14
    edited 2020-05-03 - 20:27:44
    That s what I am working on. Unfortunately the unused methods are not entirely skipped in the final pass, so some additional identification is required.
  • Latest commit resolves the problem with unused method elimination.

    There are now three listing options:

    -lc Lists to stdout
    -lo Lists to <output>.lst
    -lf <filename> Lists to named file.

    Other minor changes:

    * Variables are now listed with their relative address from the top of the current variables block as well as their absolute address. Spin byte-code references variables by their relative address.

    * Minor improvements to the interpretation of the Spin byte-code
  • Latest commit resolves the problem with unused method elimination.

    There are now three listing options:

    -lc Lists to stdout
    -lo Lists to <output>.lst
    -lf <filename> Lists to named file.

    Excellent, thank you very much!
  • There is also duplicate object removal, which is causing similar problems to unused method removal :(

    Working on it.
  • Latest commit should resolve the duplicate object removal issue.

    The only outstanding item I am aware of is possible incorrect translation of some of the more obscure byte-codes. Even then the bytes listed on the left hand side will be correct, and the translation will recover at the next source code line.

    Does anyone have an example of Spin code which generates byte-codes $86, $8A or similar? If I understand correctly these could in principle be followed by an address (1 or 2 bytes), an effects byte and another address (1 or 2 bytes), giving a maximum instruction length of 6 bytes.
  • With the latest checked-out openspin from https://github.com/Memotech-Bill/OpenSpin, compiling the attached code, results in a compiled binary, a listing, but also a segmentation fault (with any of the; "-l", "-lc", OR "-lf" options):
    % openspin -lf list.lst -I "/Users/myUserName/Library/Documents/PropSpinCode/SpinObjects" VocalTractDemo_mama.spin
    Propeller Spin/PASM Compiler 'OpenSpin' (c)2012-2018 Parallax Inc. DBA Parallax Semiconductor.
    Fork by Memotech Bill to add "Annotated Listing" of generated binary.
    https://github.com/Memotech-Bill/OpenSpin
    Version 1.01.00 Compiled on May  4 2020 11:39:40
    Compiling...
    VocalTractDemo_mama.spin
    |-VocalTract.spin
    Done.
    Program size is 2220 bytes
    zsh: segmentation fault  openspin -lf list.lst -I  VocalTractDemo_mama.spin
    
    % openspin -lo -I "/Users/myUserName/Library/Documents/PropSpinCode/SpinObjects" VocalTractDemo_mama.spin
    Propeller Spin/PASM Compiler 'OpenSpin' (c)2012-2018 Parallax Inc. DBA Parallax Semiconductor.
    Fork by Memotech Bill to add "Annotated Listing" of generated binary.
    https://github.com/Memotech-Bill/OpenSpin
    Version 1.01.00 Compiled on May  4 2020 11:39:40
    Compiling...
    VocalTractDemo_mama.spin
    |-VocalTract.spin
    Done.
    Program size is 2220 bytes
    zsh: segmentation fault  openspin -lo -I  VocalTractDemo_mama.spin
    
    % openspin -lc -I "/Users/myUserName/Library/Documents/PropSpinCode/SpinObjects" VocalTractDemo_mama.spin
    Propeller Spin/PASM Compiler 'OpenSpin' (c)2012-2018 Parallax Inc. DBA Parallax Semiconductor.
    Fork by Memotech Bill to add "Annotated Listing" of generated binary.
    https://github.com/Memotech-Bill/OpenSpin
    Version 1.01.00 Compiled on May  4 2020 11:39:40
    Compiling...
    VocalTractDemo_mama.spin
    |-VocalTract.spin
    Done.
    Program size is 2220 bytes
    0000     04C4B400      Frequency 80000000
    0004     6F            Clock Mode
    ...
    ...
    ...
    0988     002C          long CNT_
    098C     0030          long FRAMES[32]
    zsh: segmentation fault  openspin -lc -I  VocalTractDemo_mama.spin
    
    The attached code is just Chip's Vocal Tact Demo and driver. I'm running on macOS 10.15.4 (Catalina).

    dgately



  • @dgately

    Thank you for your error report. There was a typo in the code for listing the variables for an array of objects, which I have corrected in the latest commit. Hopefully this will resolve the problem.
  • I listed the spin bytecode over on the P2 thread a couple of days ago.
    See the punt/spin latest version (v34r)
  • @Cluso99 Thanks for that.

    I think this is similar to your SpinBytecodeDoc_600_260C_007F.spin from forums.parallax.com/discussion/111684/spin-bytecode which I have been using in conjunction with https://github.com/rosco-pc/propeller-wiki/wiki/Spin-Byte-Code

    I just wanted to check my understanding.
    '                                .---.---.---.---.---.---.---.---.    
    '$80-DF Access MEM, OBJ,         | 1 | s   s | i | b   b | o   o |  (96 stack load / save opcodes)  
    '           VAR and LOC          `---^---^---^---^---^---^---^---'
    '                                        |     |     |       |
    '                                    00= Byte  |     |      00= PUSH   Read  - push result in stack
    '                                    01= Word  |     |      01= POP    Write - pop value from stack
    '                                    10= Long  |     |      10= USING  2nd opcode (assignment) executed, result in target
    '                                 (11= mathop) |     |      11= PUSH # Push address of destination onto stack
    '                                              |  00= MEM  base popped from stack, if i=1 add offset
    '                                              |  01= OBJ  base is object base   , if i=1 add offset
    '                                              |  10= VAR  base is variable base , if i=1 add offset
    '                                              |  11= LOC  base is stack base    , if i=1 add offset
    '                                             0= no offset
    '                                             1=[]= add offset (indexed)
    

    So if the "i" bit is set this is followed by a one or two byte offset. Then if "oo" = %10, this is followed by a "using" or "effects" byte:
    ' Assignment Operators (p=push, ss=size: 00=bit, 01=byte, 10=word, 11=long)
    '
    ' This is an additional bytecode and follows a USING bytecode.
    '
    '       p000000-                write
    '       -0000s1-                repeat-var loop (s = pop step) +1..2 address
    '       p00010--        ?var    random forward (long)
    '       p00011--        var?    random reverse (long)
    '       p00100--        ~var    sign-extend byte
    '       p00101--        ~~var   sign-extend word
    '       p00110--        var~    post-clear
    '       p00111--        var~~   post-set
    '       p0100ss-        ++var   pre-inc (mask by size)
    '       p0101ss-        var++   post-inc (mask by size)
    '       p0110ss-        --var   pre-dec (mask by size)
    '       p0111ss-        var--   post-dec (mask by size)
    '       p1sxxxxx                math operator (!s = swap binary args)
    

    So if this has the value %-0000s1- this is followed by another address.

    Is this plausible or is this a pathological case that would never occur in practice?

    What I was really looking for is some short examples of Spin code, which when compiled generated the various forms of byte-code. Is there a test suite for the openspin compiler?
  • maccamacca Posts: 244
    edited 2020-05-05 - 15:20:52
    Found a small bug: seems that the filler bytes used to align the code to a long boundary are not interpreted correctly.

    This is your listing:
    02FE     8781                                  word    TOKEN_DEV1_EP15, 0
    0300 017 0000
                           DAT
                           heap_begin    ' Begin recyclable memory heap
    0302     F1140000                    org
    0306     BF A0
    0308 001 A0BFF513      t1            mov       frqa, frqa_value
    030C 002 A0BFFD15      l_cmd         mov       vcfg, vcfg_value
    0310 003 A0BFFF16      codec_buf     mov       vscl, vscl_value
    0314 004 5CFDA6CE      codec_cnt     call      #enc_reset
    

    This is the listing produced by bstc:
    02FE(0016) 81 87       |                         word    TOKEN_DEV1_EP15, 0
    0300(0017) 00 00       | 
    0302(0017)             | heap_begin    ' Begin recyclable memory heap
    0302(0017)             |               org
    0304(0000)             | controller_cog
    0304(0000) 14 F1 BF A0 | tx_count      mov       ctra, ctra_value
    0308(0001) 13 F5 BF A0 | t1            mov       frqa, frqa_value
    030C(0002) 15 FD BF A0 | l_cmd         mov       vcfg, vcfg_value
    0310(0003) 16 FF BF A0 | codec_buf     mov       vscl, vscl_value
    0314(0004) CE A6 FD 5C | codec_cnt     call      #enc_reset
    

    As you can see, at address 0302 there are two filler bytes needed to align the dat section to a long boundary, your listing consider them as part of the following dat section and interpret them as the first instruction, which is wrong. Note also that the controller_cog and tx_count labels are missing. The bstc listing dosn't show the filler bytes but the following instruction is correct.

    I'm attaching the source here, it is part of the usb-host controller code from
    https://github.com/SaucySoliton/propeller-usb-host/

    Best regards,
    Marco
  • @macca Thank you, I will look into it.
  • The problem was caused by my formatting the org statement as an opcode rather than a directive.

    I have revised this and openspin now produces:
    02F4 014 0000
    02F6     AE81                                  word    TOKEN_DEV1_EP13, 0
    02F8 015 0000
    02FA     3701                                  word    TOKEN_DEV1_EP14, 0
    02FC 016 0000
    02FE     8781                                  word    TOKEN_DEV1_EP15, 0
    0300 017 0000
    0302                   DAT
    0302                   heap_begin    ' Begin recyclable memory heap
    0302                                 org
    0302     00 00
    0304                   controller_cog
    0304 000 A0BFF114      tx_count      mov       ctra, ctra_value
    0308 001 A0BFF513      t1            mov       frqa, frqa_value
    030C 002 A0BFFD15      l_cmd         mov       vcfg, vcfg_value
    0310 003 A0BFFF16      codec_buf     mov       vscl, vscl_value
    0314 004 5CFDA6CE      codec_cnt     call      #enc_reset
    0318                   cmdret
    0318 005 FC3E311D                    waitvid   v_palette, v_idle
    

    As an aside note, a slightly modified version of the USB code can be found here.
  • Cluso99Cluso99 Posts: 16,147
    edited 2020-05-06 - 04:47:01
    @Cluso99 Thanks for that.

    I think this is similar to your SpinBytecodeDoc_600_260C_007F.spin from forums.parallax.com/discussion/111684/spin-bytecode which I have been using in conjunction with https://github.com/rosco-pc/propeller-wiki/wiki/Spin-Byte-Code

    I just wanted to check my understanding.
    '                                .---.---.---.---.---.---.---.---.    
    '$80-DF Access MEM, OBJ,         | 1 | s   s | i | b   b | o   o |  (96 stack load / save opcodes)  
    '           VAR and LOC          `---^---^---^---^---^---^---^---'
    '                                        |     |     |       |
    '                                    00= Byte  |     |      00= PUSH   Read  - push result in stack
    '                                    01= Word  |     |      01= POP    Write - pop value from stack
    '                                    10= Long  |     |      10= USING  2nd opcode (assignment) executed, result in target
    '                                 (11= mathop) |     |      11= PUSH # Push address of destination onto stack
    '                                              |  00= MEM  base popped from stack, if i=1 add offset
    '                                              |  01= OBJ  base is object base   , if i=1 add offset
    '                                              |  10= VAR  base is variable base , if i=1 add offset
    '                                              |  11= LOC  base is stack base    , if i=1 add offset
    '                                             0= no offset
    '                                             1=[]= add offset (indexed)
    

    So if the "i" bit is set this is followed by a one or two byte offset. Then if "oo" = %10, this is followed by a "using" or "effects" byte:
    ' Assignment Operators (p=push, ss=size: 00=bit, 01=byte, 10=word, 11=long)
    '
    ' This is an additional bytecode and follows a USING bytecode.
    '
    '       p000000-                write
    '       -0000s1-                repeat-var loop (s = pop step) +1..2 address
    '       p00010--        ?var    random forward (long)
    '       p00011--        var?    random reverse (long)
    '       p00100--        ~var    sign-extend byte
    '       p00101--        ~~var   sign-extend word
    '       p00110--        var~    post-clear
    '       p00111--        var~~   post-set
    '       p0100ss-        ++var   pre-inc (mask by size)
    '       p0101ss-        var++   post-inc (mask by size)
    '       p0110ss-        --var   pre-dec (mask by size)
    '       p0111ss-        var--   post-dec (mask by size)
    '       p1sxxxxx                math operator (!s = swap binary args)
    

    So if this has the value %-0000s1- this is followed by another address.

    Is this plausible or is this a pathological case that would never occur in practice?

    What I was really looking for is some short examples of Spin code, which when compiled generated the various forms of byte-code. Is there a test suite for the openspin compiler?
    I never completely understood the bytecodes. I verified my code with small changes at a time.

    You should look at using the listings from homespun and bst (they each have advantages). Hopefully then you can contrive some examples to generate the required bytescodes and look at their generation. Sorry I can't be of much help.
  • Is this plausible or is this a pathological case that would never occur in practice?

    It turns out that yes it is possible to have two addresses, one preceding and one following the "using" byte:
    0010     0074 0002     Link to Next Object
    0014     0064 0000     Link to PUB Demo
    0018                   DAT
    0018 000 00000000      pad     long    0[20]       ' Push subsequent variables down
    001C 001 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
    005C 011 00000000 00000000 00000000
    0068 014 00000000      sum     long    0
    006C 015 00000000      index   long    0
    0070 016 0000000A      count   long    10
    0074                   PUB Demo
    0074                           repeat index from 1 to count
    0074     36            ; Push_1
    0075     C5 5C         ; Pop_ObjectMem_Long, $005C
    0077                               sum += index
    0077     C4 5C         ; Push_ObjectMem_Long, $005C
    0079     C6 58 4C      ; Effect_ObjectMem_Long, $0058, Add, swap
    007C     36            ; Push_1
    007D     C4 60         ; Push_ObjectMem_Long, $0060
    007F     C6 5C 02 74   ; Effect_ObjectMem_Long, $005C, repeat-var loop, $FFF4
    0083     32            ; Return
    

    The line at 007F illustrates this: The first address is the location (relative to the start of the object) of the loop variable, and the second address is the offset to the start of the loop ($0083 + $FFF4 = $0077 in signed arithmetic).

    In this case, because the addresses are small they have been encoded as single bytes.

    @Cluso99, one tiny piece of new information, the address following a "using" code of "-0000s1-" is a signed offset.
Sign In or Register to comment.