Shop OBEX P1 Docs P2 Docs Learn Events
Porting the Oberon Compiler (ORP) to the P2 — Parallax Forums

Porting the Oberon Compiler (ORP) to the P2

I decided to start a new topic now that there is a starting point.
The code can be found here: https://github.com/raps500/Propberon. I decided to call it Propberon :), instead of AleOberon :).

For the time being produces RISC5 code but that will change soon.
It would be great if I could modularize the code generation :), then I don't have to drop support for RISC5 during development :).
The disassembler ignores a couple of flags for MOV, needs fixing.

Comments

  • jmgjmg Posts: 15,140
    Look forward to see how this goes.

    Would a Searchable name make more sense ? - the 'opberon' there will not find on an Oberon Search, and it probably should be clear it is Prop2, not Prop ?

    You may need to introduce segments, as VARs in COG will create much smaller and faster code than VAR in HUB.
    ie This is very similar to DATA and XDATA on the 8051, with LUT being maybe similar to IDATA.
    Then, some var overlay scheme with simple checking would help local vars in functions not waste COG memory. Because sometimes the tools cannot be certain one function does not call another indirectly, some means to disable this is needed for those rare cases.
  • AleAle Posts: 2,363
    You know, the code generator produces machine code and not assembly. It means that it produces ready (kind-of) to execute relocatable code.There is no byte access in COG memory, limiting what kind of variables can be put there, let's see how it goes. My approach is: make it work, make it good, make it better (fast is not something I really need, at this point).
    Segments are accessed differently... lots of fun !
  • kwinnkwinn Posts: 8,697
    Ale wrote: »
    I decided to start a new topic now that there is a starting point.
    The code can be found here: https://github.com/raps500/Propberon. I decided to call it Propberon :), instead of AleOberon :).

    For the time being produces RISC5 code but that will change soon.
    It would be great if I could modularize the code generation :), then I don't have to drop support for RISC5 during development :).
    The disassembler ignores a couple of flags for MOV, needs fixing.

    IMHO OberonAle would go down a lot better, and would be searchable ;-)
  • AleAle Posts: 2,363
    Is Propberon a bad name then ?
  • I say name it what you want. In your explanation and description text, mentions of Oberon and Parallax Propeller will get the search metrics done.
  • re:Propberon

    OberonP2
  • TorTor Posts: 2,010
    OPe2on ?
  • TubularTubular Posts: 4,620
    edited 2016-06-03 01:10
    kwinn wrote: »
    IMHO OberonAle would go down a lot better, and would be searchable ;-)

    Looks like Oberon Ale is already a beer (which may indeed "go down a lot better")
    http://mikesbrewreview.com/review-of-bells-oberon/

    I think Propberon is fine, Ale, full steam ahead!...
  • jmgjmg Posts: 15,140
    Tubular wrote: »
    Looks like Oberon Ale is already a beer ...

    I had presumed exactly that from the tone of Kwinn's post :)
  • Probably right jmg, often one step ahead...
  • kwinnkwinn Posts: 8,697
    jmg wrote: »
    Tubular wrote: »
    Looks like Oberon Ale is already a beer ...

    I had presumed exactly that from the tone of Kwinn's post :)

    Actually had no idea there was a brew by that name, just put Oberon and Ale together and thought it rolled off the tongue so well. Getting really hard to come up with a unique and memorable name for anything.

    Of course I will have to see if I can find an Oberon Ale to sample now.
  • jmgjmg Posts: 15,140
    kwinn wrote: »
    jmg wrote: »
    Tubular wrote: »
    Looks like Oberon Ale is already a beer ...

    I had presumed exactly that from the tone of Kwinn's post :)

    Actually had no idea there was a brew by that name, just put Oberon and Ale together and thought it rolled off the tongue so well. Getting really hard to come up with a unique and memorable name for anything.

    Of course I will have to see if I can find an Oberon Ale to sample now.

    Hehe, and that winky, & 'go down a lot better', had me thinking you had one in your hand !

  • kwinnkwinn Posts: 8,697
    jmg wrote: »
    kwinn wrote: »
    jmg wrote: »
    Tubular wrote: »
    Looks like Oberon Ale is already a beer ...

    I had presumed exactly that from the tone of Kwinn's post :)

    Actually had no idea there was a brew by that name, just put Oberon and Ale together and thought it rolled off the tongue so well. Getting really hard to come up with a unique and memorable name for anything.

    Of course I will have to see if I can find an Oberon Ale to sample now.

    Hehe, and that winky, & 'go down a lot better', had me thinking you had one in your hand !

    Wouldn't mind having one in hand to try but it's not available locally. Brewed in Kalamazoo Michigan which is a bit too far (624KM) to go for a beer, although I will keep it in mind if I am in the neighborhood.
  • AleAle Posts: 2,363
    Going back to porting, here is a schematic of the binary format. A couple of fields are a bit fuzzy at the time, I'm not really sure about their meaning.
    If we're (I'm) going to ultimately run Project Oberon on the P2, I'D like to keep everything as similar as possible. (I did make some changes in ORG, numbers are kind of packed, I'm using full 32 bits for all numbers, except the separators and strings. I think, at a later stage, strings and separators should be modulo 4 aligned, too.
    Binary format
     
    +----------------------------------+---------+------------
    | Section                          |  Size   | Start
    +----------------------------------+---------+------------
    | Module_name plus \0              |         | 0
    +----------------------------------+---------+------------
    | Key                              |    4    | N
    +----------------------------------+---------+------------
    | Version                          |    1    | N+4
    +----------------------------------+---------+------------
    | size                             |    4    | N+5
    +----------------------------------+---------+------------
    | Import name plus \0              |    I    | N+9
    |  repeated                        |         |
    +                                  +---------+------------
    | Address of import                |    4    | N+9+(I)
    |  repeated                        |         |
    +----------------------------------+---------+------------
    | Separator \0                     |    1    | N+9+(I+4)*n
    +----------------------------------+---------+------------
    | Number of Type descriptors       |    4    | N+9+(I+4)*n+1
    +----------------------------------+---------+------------
    | Type descriptor                  |    4    | N+9+(I+4)*n+5 
    |   repeated                       |         |   
    +----------------------------------+---------+------------
    | Data size                        |    4    | N+9+(I+4)*n+5+tdx*4  
    +----------------------------------+---------+------------
    | Strings size (SS in bytes)       |    4    | N+9+(I+4)*n+5+tdx*4+4  
    +----------------------------------+---------+------------
    | Strings                          |   SS    | N+9+(I+4)*n+5+tdx*4+8  
    +----------------------------------+---------+------------
    | Code length (CL in words)        |    4    | N+9+(I+4)*n+5+tdx*4+8+SS
    +----------------------------------+---------+------------
    | Code                             |   CL*4  | N+9+(I+4)*n+5+tdx*4+8+SS+4   
    +----------------------------------+---------+------------
    | Command string  repeated         |   CS    |  N+9+(I+4)*n+5+tdx*4+8+SS+4+CL 
    +                                  +---------+------------
    | Command value   repeated         |    4    |  N+9+(I+4)*n+5+tdx*4+8+SS+4+CL+(CS+4)*n
    +----------------------------------+---------+------------
    | Separator \0                     |    1    |   
    +----------------------------------+---------+------------
    | Number of exported procs (nofent)|    4    |   
    +----------------------------------+---------+------------
    | Entry point into code            |    4    |   
    +----------------------------------+---------+------------
    | Proc entries if any              |  4*e    |   
    +----------------------------------+---------+------------
    | Record entries if any            |  4*r    |   
    +----------------------------------+---------+------------
    | Pointer entries if any           |  4*p    |   
    +----------------------------------+---------+------------
    | Pointer variables if any         |  4*v    |   
    +----------------------------------+---------+------------
    | Marker  (FFFFFFFFH)              |    4    |   
    +----------------------------------+---------+------------
    | fixorgP                          |    4    |   
    +----------------------------------+---------+------------
    | fixorgD                          |    4    |   
    +----------------------------------+---------+------------
    | fixorgT                          |    4    |   
    +----------------------------------+---------+------------
    | entry                            |    4    |   
    +----------------------------------+---------+------------
    | Marker O                         |    1    |   
    +----------------------------------+---------+------------
    
  • AleAle Posts: 2,363
    edited 2016-06-04 05:13
    These notes are also checked in.
    Register usage
    
    R0..R11 as R0..R11 (in COG RAM)
    PTRA as stack pointer
    PTRB as SB
    
    due to the lack of 16 bit range in indexed memory access, a combination of opcodes 
    has to be implemented to achieve the same purpose:
    
    Proc Entry
    
    Code:  4EE9000C SUB   SP, SP, C
    
                    mov _SP, PTRA
                    sub _SP, #12    ' or its augmented version if range too short
                    
    This serves two purposes: if the arguments are outside the range of indexed mode
    the pseudo register _SP can be used instead
    
    Saving the link register is not needed because calla saves already the return address
    to the stack:
    
    Code:  AFE00000 ST    LNK, [SP + 0]
    
    Access to stack variable:
    
    Code:  A0E00008 ST    R0, [SP + 8]
    Code:  80E00004 LD    R0, [SP + 4]
    
    The limited range of the index argument (31 for bytes or 124 for longs)
    means that the stack pointer has to be used indirectly, adding 2 or three
    extra opcodes per access:
    
                    wrlong _R0,PTRA[2]   ' 2 will be scaled because argument is long
                    
                    mov   _TT, _SP
                    add   _TT, #508
                    rdlong _R0,_TT
    
                    mov   _TT, _SP
                    augs  #4096         ' really deep stack
                    add   _TT, #508
                    rdlong _R0,_TT
    
    Byte variables should be kept on lower addresses to use the shortest form.
    
    Opcode changes
     
    Some RISC5 opcodes can be directly be replaced by P2 opcodes but
    it has to be seen if the 3 register form is widely used or not, because the
    P2 only provides 2-operands opcodes:
     
     
    Code:  40080005 ADD   R0, R0, 5
     
                    add  _R0, #5    ' or ist augmented version if the operand is larger
    
    Exiting from a Procedure requires some house-keeping too:
    
    Code:  4EE8000C ADD   SP, SP, C
    Code:  C700000F BRA   LNK
    
                    add   _SP, #12
                    mov   PTRA, _SP
                    add   _SP, #4       ' re-adjust _SP to keep in sync with PTRA after reta
                    reta
    
    And 2 RISC5 opcodes become 4 :(, if variables are used.
    
    Arguments are passed in registers for less stack usage, when they fit:
    
    Code:  40000006 MOV   R0, R0, 6
    Code:  F7FFFFED BRAL  FFFFED
    
                    mov   _R0, #6   ' or its augmented version
                    calla _Proc
    
    
  • Hi Ale and All,
    Great work on Oberon compiler for the Prop2. Have you managed to compile any code to the FPGA Verilog implementation you have, AProp?
  • AleAle Posts: 2,363
    I have been thinking lately a lot on the Oberon problem: The code generator for the P2 as target needs a bit of work and what exactly is what I was asking myself the last months. Let me explains: the RISC5 has 3 argument opcodes and 16 bit offsets and here start the problems, the generated code is modified "on-the-fly" so to say. what brings the problem that the replacement opcodes (P2) or sequences do not have the same length or fields.
    As a solution I was thinking that a layer of abstraction could solve the problem:

    ORP generates an instructions file, a target generator reads it and process it outputting the necessary P2 code with the adjusted offsets. The library files need also to be modified because the offsets written there are no longer valid (I have to look into this again, it's been a while...). A pretty mess :(.

    What do you think ?

  • jmgjmg Posts: 15,140
    edited 2017-08-28 06:14
    Ale wrote: »
    I have been thinking lately a lot on the Oberon problem: The code generator for the P2 as target needs a bit of work and what exactly is what I was asking myself the last months. Let me explains: the RISC5 has 3 argument opcodes and 16 bit offsets and here start the problems, the generated code is modified "on-the-fly" so to say. what brings the problem that the replacement opcodes (P2) or sequences do not have the same length or fields.
    As a solution I was thinking that a layer of abstraction could solve the problem:

    ORP generates an instructions file, a target generator reads it and process it outputting the necessary P2 code with the adjusted offsets. The library files need also to be modified because the offsets written there are no longer valid (I have to look into this again, it's been a while...). A pretty mess :(.

    What do you think ?

    Do you mean like an intermediate assembler file, that takes one RSIC5 opcode, and generates what could be multiple P2 opcodes, or in extreme cases a call to a Lib-stub, which starts to merge/morph into a RISC5 emulator ?

    Oberon code is usually quite easy to read, another approach would be to try to modify the code generator to generate P2 code ?
    A first step could be to recode using RISC 5 so you can still test it, but limit the R5 opcodes to 2 arguments ?
    Code would get slightly larger, during this morph.

    A P2/R5 switch could then output P2-ASM ?


  • AleAle Posts: 2,363
    Do you mean like an intermediate assembler file, that takes one RSIC5 opcode, and generates what could be multiple P2 opcodes, or in extreme cases a call to a Lib-stub, which starts to merge/morph into a RISC5 emulator ?

    Maybe that is the best approach, but I thought about something like: Do you mean like an intermediate assembler file but without the R5 opcodes only the "commands" with the offset adjustments, so everything can be re-calculated and re-targetted (I also wanted to target the RISC-V).

    A direct ORP port is what I tried, that's why I was looking for an alternative. Maybe I have to look at the code generator again.
  • jmgjmg Posts: 15,140
    Ale wrote: »
    Maybe that is the best approach, but I thought about something like: Do you mean like an intermediate assembler file but without the R5 opcodes only the "commands" with the offset adjustments, so everything can be re-calculated and re-targetted (I also wanted to target the RISC-V).

    That could also work - I guess it depends on whether you prefer to work at MACRO-ASM or Code generator level, and which ASM levels tools you have too...
    I did play with FASMG, which seems a very powerful, general assembler (no linker), but that's also another tool chain, and not likely to be P2 self-hosting.



  • Does this help?
    'Using P2's register indirection to achieve 3 operands.
    
    '	ADD CX,AX,BX  'CX = AX + BX
    
    'would be
    
    	altr	zero,#cx
    	add	ax,bx
    '
    '
    '
    zero	long	0
    ax	long	1
    bx	long	7
    cx	long	0
    
    
  • evanhevanh Posts: 15,126
    Oz,
    I just tested that and yep it works as you say. I'd completely forgotten how the ALTx instructions work in detail. Here's my test code: (variables are in CogRAM)
    '*******************************************************************************
    '  Program Code  (HubExec)
    '*******************************************************************************
    _main
    		waitx   one_sec
    'Using P2's register indirection to achieve 3 operands.
    
    '	ADD CX,AX,BX  'CX = AX + BX
    
    'would be
    
    		altr	zero,#cx
    		add	ax,bx
    '
    '
    '
    		mov     parm, ##str_ax
    		call    #puts
    		mov     parm, ax
    		call    #itoa
    		mov     parm, ##str_bx
    		call    #puts
    		mov     parm, bx
    		call    #itoa
    		mov     parm, ##str_cx
    		call    #puts
    		mov     parm, cx
    		call    #itoa
    		mov     parm, ##str_zero
    		call    #puts
    		mov     parm, zero
    		call    #itoa
    		call    #putnl
    		jmp	#$
    
    str_ax		byte    "  ax = ",0
    str_bx		byte    "  bx = ",0
    str_cx		byte    "  cx = ",0
    str_zero	byte    "  zero = ",0
    
    Terminal output is as follows:
    ax = 00000001 bx = 00000007 cx = 00000008 zero = 00000000

    I had to think about why "zero" had to be referenced like that and why the shorter ALTR D instruction wasn't used. I worked it out but wasn't happy I couldn't find a cheaper solution that didn't need an additional variable reference like that.
  • jmg wrote: »
    Do you mean like an intermediate assembler file, that takes one RSIC5 opcode, and generates what could be multiple P2 opcodes, or in extreme cases a call to a Lib-stub, which starts to merge/morph into a RISC5 emulator ?

    There's already a RISC-V emulator for both P1 and P2, so another solution would be just to output RISC-V binaries and then run those. The P2 version does a JIT compilation from RISC-V binaries to P2 binaries. Sources are found at
    github.com/totalspectrum/riscvemu.git.

    Eric
  • ersmith - just in case you were't aware this RISC5 is different than RISC-V.

    https://www.inf.ethz.ch/personal/wirth/FPGA-relatedWork/RISC-Arch.pdf
  • Heater.Heater. Posts: 21,230
    Confusing. But there seems to be an actual RISC V compiler http://oberon.wikidot.com/rop2compiler

  • jmgjmg Posts: 15,140
    So combining these two posts, is a solution ?
    Heater. wrote: »
    ... there seems to be an actual RISC V compiler http://oberon.wikidot.com/rop2compiler
    +
    ersmith wrote: »
    There's already a RISC-V emulator for both P1 and P2, so another solution would be just to output RISC-V binaries and then run those. The P2 version does a JIT compilation from RISC-V binaries to P2 binaries. Sources are found at
    github.com/totalspectrum/riscvemu.git.

  • KeithEKeithE Posts: 957
    edited 2017-08-29 23:05
    I didn't notice that RISC-V compiler. Could be nice to have a simple Oberon based RISC-V compiler that could be downloaded and installed in a few minutes. I destroyed an SD card when I tried to build the GNU RISC-V tools on a Pi - the infamous read-only problem.
  • AleAle Posts: 2,363
    If, I'm not mistaken it is based on an earlier, simplified version of Oberon. The compiler structure is also a bit different.
Sign In or Register to comment.