Shop OBEX P1 Docs P2 Docs Learn Events
COGNAC - Cog Native Asm Compiler — Parallax Forums

COGNAC - Cog Native Asm Compiler

heaterheater Posts: 3,370
edited 2009-02-18 16:46 in Propeller 1
There has been discussion here and there in the forum of a high level language compiler that would generate native assembler for COGs. The consensus is that this is not really practical for languages like C that rely on a stack and would like a lot more room than 496 instructions to do anything useful.

So the discussion turns this around to "Can we define a high level language that suits the COG instruction set?"

Lets assume that COGs are the only computers in the world and we have yet to invent the stack !

What are the consequences of this?

1. No stack means recursive function calls are not allowed. This is no loss as nobody ever uses recursion anyway and when you do you probably need more stack space than we have available.

2. No stack means no temporary store on the stack for local variables. This is no loss as it is only required for recursive calls which are not allowed by 1)

3. No stack means no parameter passing on the stack. Again no loss as per 2)

4. No stack means no operator precedence in expressions. Well what the hell, I can never remember the precedence of operators in C let alone SPIN which has so many more. Always end up using parenthesis.

5. No stack means no parenthesis in expression evaluation. Ah, well why can't we live with in order evaluation. If we want operations to happen in a specific order use more than one expression.

6. Don't know. Can anyone think of what else we loose without a stack? Possibly things like nested array indexing
x := a[noparse]/noparse]a[noparse][[/noparse]j for example. Haven't thought about arrays yet.

Expanding on points 2 and 3. Functions could still have variables that are local in scope and valid only during their "lifetime" and function calls with parameters could look syntactically like they do in C or Pascal or whatever. BUT locals and parameters would have to exist in some shared global store. That is, any given memory location from the shared pool could be used as a parameter or local for different functions at different times during execution.

Given that we have no recursion, the call graph for any program is a simple tree structure. So it must be possible for the compiler to workout which params and locals are in likely in use at any point in the code and reuse their memory space for other params/locals when they definitely are not.

So far so good. We can define a C-like or Pascal-like language with no stack and still be able to write useful code.

This morning I woke up to find my self thinking about what high level language constructs we could use or invent to make use of all the available COG opcodes. Firstly we can use all/most the operators of the operators of SPIN to make use of stuff like REV etc.

What about signed and unsigned arithmetic with or without carry/borrow? ADD, ADDS, ADDSX etc. And what about getting access to the carry and zero flags for conditional execution ?

Well what about an expression syntax like:

COGNAC Source:

ulong   foo, bar;                                            
slong   sfoo, sbar;                         

result := foo + bar;

result, carry := sfoo + sbar;

result, carry, zero := foo - bar - carry;

result := sfoo + sbar + carry;

carry, zero := sfoo + sbar;

foo, zero += bar

Which generates:

foo     long  0         'Signed
bar     long  0         'Signed
sfoo    long  0         'Unsigned
sbar    long  0         'Unsigned

        mov   rslt, foo               'Get foo
        add   rslt, bar               'Unsigned add bar

        mov   rslt, sfoo              'Get sfoo
        adds  rslt, sbar wc           'Signed add sbar

        mov   rslt, foo               'Get foo
        subx  rslt, foo wc, wz        'Unsigned subtract bar with carry

        mov   rslt, sfoo              'Get sfoo
        addsx sbar                    'Signed add bar with carry

        adds  sfoo, sbar wc, wz, nr   'NO result so may as well work into sfoo

        add   foo, bar wz             'Unsigned add to self





Where result, carry, and zero are set as you would expect if they exist on the right hand side. This would compile to ADD/SUB or ADDS/SUBS depending on the variables being signed or unsigned (slong/ulong) types. If the carry is a term on the left hand side the ADDSX/SUBSX is used. "carry" and "zero" are of course reserved identifiers.

Notice I have not declared "result" above. No idea yet what to do with mixed type expressions. Perhaps automatic type conversion is not allowed and casts will have to be specified like: "result := sfoo + slong(bar);

Note also the use of the X. It allows extended arithmetic, 64 bit say. I for sure don't want to have a LONG LONG type. Extended types will have to be created in COGNAC source as they are in PASM. Going the other way I'm not sure I want the complexity in COGNAC to handle WORD and BYTE types. The whole deal with types and compilers is horrible[noparse]:)[/noparse]

At first I assumed COGNAC would allow use of GOTO. Despite what Dijkstra says GOTO s damn useful in confined spaces and after all we want JMP instructions on demand. However I realize now it would not allow the use of recycling of memory locations for params/locals as described above. It would become impossible for the compiler to predict when particular variable is really not needed at a point in the code can can be reused. Same goes for jumping though a vector. We either don't use memory recycling or we don't have GOTO and vectored jumps.

Constants will have to be dealt with according to size for less than 10 bits put hem in the instruction with "#" for bigger create a literal pool.

For "rdlong" etc we could use a function like syntax "read_long(foo)" where foo is just a ulong or perhaps a type modifier in declarations "hub ulong foo" and generate rdlongs as required.

DJNZ could be pressed into service when coming across constructs like "for foo = bar to 0 step 1". Which looks a bit BASIC to me. Perhaps we need a "for all foo", there, much simpler.

OK that's enough speculation for now.

The idea is to define a dead simple language. Simple enough that a rank amateur compiler writer such as myself can possibly implement it in less than 100 years. The syntax has to be tailored to simple parsing. Traditional language features that don't fit the COG model have to go. New constructs that extract the best from the COG must be invented. By "define" I mean I'd like to at least a BNF description of COGNAC before even thinking about implementing it.

This may never be implemented but it's an interesting Gedankenexperiment anyway.

Any one have any ideas ?

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
For me, the past is not over yet.
«134

Comments

  • Ken PetersonKen Peterson Posts: 806
    edited 2009-02-10 16:30
    Wow... If you can make this work, perhaps BradC can roll this into BST! roll.gif

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    ·"I have always wished that my computer would be as easy to use as my telephone.· My wish has come true.· I no longer know how to use my telephone."

    - Bjarne Stroustrup
  • AleAle Posts: 2,363
    edited 2009-02-10 16:33
    Idea I have loads. I assume you want something small to fit into 496 longs maximum, and not another lmm language.
    I do not think it has to be that different from what we know already. I think it can be C or Pascal or even BASIC. Just no local variables, no recursion, no operator precedence and mono operation:

    A = B + C - D

    shoudl be written:

    A = B + C

    A = A - D

    or something like that. With those elements even I can write something wink.gif
  • mctriviamctrivia Posts: 3,772
    edited 2009-02-10 16:47
    GW Basic would be perfect if you think about it.
    Replace line numbers with labels and you have a very easy to convert to assembly language.

    Arrays can be done through self modified code and or using rdbyte for hub memory. would need to define a method of reading hub vs cog memory maybe defining all hub addresses as part of 3 arrays BYTE[noparse][[/noparse]x], WORD[noparse][[/noparse]x], LONG[noparse][[/noparse]x] they all have same info but different size grouping
  • mctriviamctrivia Posts: 3,772
    edited 2009-02-10 16:49
    the problem comes when compiling multiply and divide functions. do you let the user chose to use inline multiply if space of subroutine if not?
  • heaterheater Posts: 3,370
    edited 2009-02-10 16:52
    That's the idea. Cog Native Asm.

    What's wrong with multiple terms?

    A := B + C - D

    generates:

    MOV A,B
    ADD C
    SUB D

    Or

    A += C + D + E + F

    Generates:

    ADD A, C
    ADD A, D
    ADD A, E
    ADD A, F


    Of course if you want to propagate carry around that may be a problem as I defined it so far:

    A := A + B + carry - D - carry

    where the "+ carry" means use ADDX for the first "+" and the "- carry"means use SUBX for the first "-".
    Starts to get weird. You have to parse ahead away to find out what operation you really want. Not good.

    What about using a tick for "with carry":

    A := J + K' + L'


    Easy to miss in source code I suppose.

    Or I might be the first this century to define a language that uses this "¤" [noparse]:)[/noparse]

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    For me, the past is not over yet.
  • mctriviamctrivia Posts: 3,772
    edited 2009-02-10 16:56
    where do you get that simble on a keyboard. How often do you need a cary bit in 32bit math? why not leave the option to inline sudo assembly for tighter rotines and odd ball extras.
  • jazzedjazzed Posts: 11,803
    edited 2009-02-10 16:58
    Cognac [noparse]:)[/noparse] VO or XO ?

    Seems I understand what you are doing with multiple L values ... it would save having to do special carry/zflag statements for example, but is there a familiar precedent or other reason (beyond think different ...) ? Added: I like the post-tick idea:· A = b + c'· except that ' is a comment (ugh).

    Have you considered a VB like BASIC or PBASIC with (for/do/while and labels rather than the 20 goto 10 variety)?
    I'm a fan of foreach loops ... foreach index of arrayblah ....

    Recursion is useful in "series" calculations, but I agree it is not very useful in an tiny embedded environment.

    It seems that a priority would be tight resultant code otherwise the compiler might go unused. The great egos or proficients would not bother anyway.

    Having something simple regardless of how tight may draw more regular users to your compiler and maybe using pasm assuming list files are available.

    It would be prudent to plan for an LMM variant if you continue developing this.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    --Steve
  • mctriviamctrivia Posts: 3,772
    edited 2009-02-10 17:04
    the compiler should generate the pasm code with notes denoting what the higher level functioning is. this would allow for quicker writing. write your code in cognac compile then tweek in pasm.

    therefor
    loop:
    A := B + C - D
    c += B + A
    goto loop
    
    



    generates:

    'A := B + C - D
    loop     MOV A,B    
    ADD A,C
    SUB A,D
    
    'c += B + A
    ADD C,B
    ADD C,A
    
    'goto loop
    JMP loop
    
    
  • heaterheater Posts: 3,370
    edited 2009-02-10 17:05
    Let's not think in terms of GW BASIC would be perfect. Or any other language. For sure it might end up looking BASIC like. Personally I would prefer a C style.

    Lets think about what's in a COG a how to get at it in a higher level than PASM. Language design seems to be a very subtle thing. Seemingly simple little one line changes to the specification can make the whole thing a thousand times harder to implement (or easier).

    Inline or subroutine multiply and divide. NO PROBLEM I forgot to mention, multiply and divide only work for powers of 2.
    Well seriously I haven't thought about it. Haven't needed either in PASM yet.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    For me, the past is not over yet.
  • mctriviamctrivia Posts: 3,772
    edited 2009-02-10 17:10
    multiply of power of 2 really easy. multiplying a non power of 2 just a matter of making a loop and breakng t down in to powers of 2.

    for each bit that is a 1 in second number shift over and add.:

    I.E

    5*7 = 101*111
    101+1010+10100=

    5*9=101*1001
    101+101000=
  • mctriviamctrivia Posts: 3,772
    edited 2009-02-10 17:13
    i sugest gw basic because it has no subroutines, is layed out linearly, and uses conditional jumps to create loops just like assembly does. obviously if we want to make the compiler more complicated you could use spin since we have all been learning it and just restrict the usage of subroutines.
  • heaterheater Posts: 3,370
    edited 2009-02-10 18:15
    @mctrivia: The "¤" symbol is on all Scandinavian keyboards. SHIFT-4. Seems it was used on some Swedish Z80 computer in the 70s and has stuck around ever since. Always wanted to find a use for it.

    Funnily enough I used the Props carry bit to propagate into Add With Carry (ADC) in my 8080 emulator:

    test flags, #carry_bit wc 'Set prop's carry from 8080 carry flag
    addx alu, operand 'Do the op

    Saves an instruction there.

    Inline assembler statements is definitely a good idea. And so is the listing of generated code with the source statements. I used to use PL/M on Intel micros that did that very nicely.

    This whole multiply/divide thing needs thinking about. For example what if your program only ever multiplies by a constant?. In that case one could in line a customized multiplier with the minimum number of shift/adds for the constant.
    Or what if you only ever need a 24 bit result?

    I might want to borrow from Spin. for example "repeat" by itself is a wonderful thing and all the operators that everyone has now learned. BUT I will not use indenting to delimit blocks. I want by braces "{" and "}" or DO/END or IF....ENDIF. Whatever.

    @jazzed: "VO or XO ?" Some times I just don't care[noparse]:)[/noparse]

    The multiple L values I have only ever seen in a small but elegant and powerful language called Lua.
    Where you can write:
    sum, diff, z = x+y, x-y, 3
    for example. You can also swap the order of things like:
    a,b,c,d = d,c,b,a

    Seemed like just what we need to get what effectively multiple results out of an expression.

    I really want a syntax that looks Cish or Pacalish, block structured. Tight code is the aim but I have no illusions about anyóne actually wanting to use this seriously. Unless we do better at it than I suspect at the moment. LMM...Let me think on that.

    On thing I forgot to mention and for which the Prop is special is parallelism. We need to cater for getting data between running COGs. Perhaps just by implementing protected regions of code:

    protected lockname
    a := bla bla
    b := bla bla
    unprot

    How we get the locks distributed to COGs I don't know.

    Or a system of remote procedure calls.....

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    For me, the past is not over yet.
  • mctriviamctrivia Posts: 3,772
    edited 2009-02-10 18:19
    locks can be dealt with in several ways. so far I have always just used a block of cog memory with the lock number as a read only address. At initialization i store the lock number that device is using then any cog using that device reads that memory address.

    You can also hard code the lock numbers. You do not need the locknew command if you manually assign the lock numbers yourself.
  • mctriviamctrivia Posts: 3,772
    edited 2009-02-10 18:22
    I agree about indexing. I think it strange but very easy to use since the tool shows the lines of what is indexed where. I have goten use to it and truth be told it does cost less errors from forgeting a }
  • heaterheater Posts: 3,370
    edited 2009-02-10 18:33
    I haven't written much code that uses multiple cogs and never had to use locks. My 8080 4 COG emulator does not share much data, and never actually has two COGS working at he same time.

    Seems a lot of inter COG communication, to drivers for example, uses a pattern of having a block of data in which there is a command word. When the command is set the "slave" cog does whatever it should with the data in the block and then sets the command back to zero. In which case no locks are required.

    Now this pattern is normally wrapped up in Spin interface functions so you write, for example, "TV.out(13)".

    Given that we don't necessarily have or want any Spin involved we should be able to write something similar in COGNAC such that "TV" is used to determine which remote COG this command is for "out" is the command word that gets written to the shared data block and "13" is the data that gets written.

    Actual shared memory data structures with locks looks more like it needs protected regions of code.

    Any one with ides on this?

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    For me, the past is not over yet.
  • Ken PetersonKen Peterson Posts: 806
    edited 2009-02-10 18:53
    Why not use SPIN (or a subset of SPIN) for the COGNAC compiler? Most users are using SPIN anyway, and it would be easier to port existing SPIN routines to run faster in PASM.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    ·"I have always wished that my computer would be as easy to use as my telephone.· My wish has come true.· I no longer know how to use my telephone."

    - Bjarne Stroustrup
  • mctriviamctrivia Posts: 3,772
    edited 2009-02-10 18:57
    one reason locks are so important as hardware concept is you can read and write a lock in the same hub instruction. reading a ram address to see if free then writing on next loop around may run into errors because the next cog in the loop may have done the same thing and writen when it was there turn.

    Locks are not needed if 1 cog is doing the writing and the rest just read but if like in my graphics display object(not posted because specialized to my hardware) i have multiple cogs writing and only 1 reading i need to use locks so only 1 can write at a time.
  • Cluso99Cluso99 Posts: 18,069
    edited 2009-02-10 19:01
    Great idea smile.gif

    I think the audience is the beginner who wants an intro into pasm without the complexities. So, keep it simple.
    I suggest you discard the carry/signed numbers and just work with 32 bit integers.

    Have two global variable types, one in cog, one in hub.
    Always declare a cog variable "result".
    You will also need to cater for strings.
    I like each line to be listed with it's pasm translation following in a listing.
    Allow inline pasm coding.

    Keep the syntax simple (a basic style is simpler in my opinion)
    Allow labels
    A simple repeat and for would be nice.

    Just my 2c

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Links to other interesting threads:

    · Home of the MultiBladeProps (SixBladeProp)
    · Prop Tools under Development or Completed (Index)
    · Emulators (Micros eg Altair, and Terminals eg VT100) - index
    · Search the Propeller forums (via Google)

    My cruising website is: ·www.bluemagic.biz
  • heaterheater Posts: 3,370
    edited 2009-02-10 19:41
    Simple for sure it has to be. Or it will never get done. The parser will have to know what the thing is it is looking at without to much looking ahead, backtracking or having to have read the whole program before anything makes sense. Oh yeah, and simple for the user as well.

    Perhaps we can loose signed numbers. At least in a first pass at it.

    Can we live without access to CARRY and ZERO?. Well perhaps ZERO. I've always wanted access to carry in C for checking bits shifted out or detecting unsigned overflow/underflow.

    Can we live without control over when they are set? It's quite fundamental to PASM.

    Oh, and I forgot about parity. Sometimes very useful. My emulator likes it anyway.

    Global variables declared as "hub" is a must. As is the listing format and in line asm.

    Sadly "result" is a Prop Tool reserved word.

    I guess a good way to look at it is could I write my emulator in COGNAC and be getting anywhere near that code density? And how pretty or ugly would the COGNAC source be to do it.

    For sure the single COG emulator would be a challenge here, that code is really contorted to fit.

    We need some form of "case" statement that generates self modifying code. Same for array indexing.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    For me, the past is not over yet.
  • SapiehaSapieha Posts: 2,964
    edited 2009-02-10 19:55
    Hi heater.

    One question on "COGNAC"
    Can that compiled PASM routines be compatible to load on upper half on eeprom in ProtoBoard and loaded on fly?

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Nothing is impossible, there are only different degrees of difficulty.
    For every stupid question there is at least one intelligent answer.
    Don't guess - ask instead.
    If you don't ask you won't know.
    If your gonna construct something, make it·as simple as·possible yet as versatile as posible.


    Sapieha
  • heaterheater Posts: 3,370
    edited 2009-02-10 20:34
    Good question Sapieha. I hadn't really got around to thinking about the actual output yet!

    What I had in mind was to just emit a .spin file containing the generated PASM together with a minimal SPIN section to start it such that it can just be dropped into a Propeller Tool Project. That is, leave the actual assembling to binary to the Prop tool or other Prop compiler.

    If we wanted to output a compiled and assembled binary blob that could be stored in EEPROM or SD card or whatever then I would need an assembler also. Or I believe someone has a technique for extracting the PASM from the DAT section of a .spin file. Can't remember who or where to find it.

    I do have a 70% complete PASM assembler that I could use I guess. I was really looking forward to not having to finish it. In a fit of dementia I wrote the thing in ADA. It not only assembles PASM but understands the SPIN syntax for constant declarations, enumerations etc. Which is quite a pain to get right. Not to mention the weird stuff you can do in DAT like:

    foo long 0[noparse][[/noparse]20]

    and

    foo long "abc" + "xyz" 'Which in no way does what you might expect.

    which I think are really odd and will not be in COGNAC.

    When Bradc and mpark came out with their full featured Spin compilers I kind of lost interest in my monstrosity of an assembler.

    Anyway I think you have an excellent idea.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    For me, the past is not over yet.
  • SapiehaSapieha Posts: 2,964
    edited 2009-02-10 20:50
    Hi heater.

    My idea is to have COG Routines/Programs that only reside on eeprom and load from this place and not reside in HUB at al.
    And only use Buffers on High HUB addresses then litle Loader in SPIN loads them and Starts.
    After Load it starts MAIN Spin program. With that I can have more fre memory in HUB.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Nothing is impossible, there are only different degrees of difficulty.
    For every stupid question there is at least one intelligent answer.
    Don't guess - ask instead.
    If you don't ask you won't know.
    If your gonna construct something, make it·as simple as·possible yet as versatile as posible.


    Sapieha
  • heaterheater Posts: 3,370
    edited 2009-02-10 21:00
    I'm totally with you on that idea, Sapieha. EEPROM or SD card or whatever. Having all that DAT space wasted after the COG is launched annoys me also. The Prop Tool itself could do with a way of handling as well.

    As I say, it's an excellent idea. Lets see what we can do.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    For me, the past is not over yet.
  • hippyhippy Posts: 1,981
    edited 2009-02-10 21:42
    I hated PICmicro assembler so much, unable to get my head round "SUBWF fred,F" etc, that I designed a simple language which looks similar to what you have; "fred = fred-W" for the above. Worked well enough that it got a commercial product developed in a tenth of the time it would have taken me.

    No reason to be tied to one line is one opcode or to get hung up on not having a stack. It's reasonably easy to code an expression parser which can re-jig things to use temporaries and the Prop has two Cog temps as OUTB and DIRB which most people never use. Go as far as you can then emit "OMG ! Expression too complicated. L33t h4xr alert!", and leave it to the programmer to simplify smile.gif

    I'd also say don't get hung up on efficient code generation. Get it right but leave it to a separate optimisation pass to start with. Choose an intermediate opcode representation suitable for the high-level and PASM and you should be able to have a simple parser and simple back-end code generation. Plus, don't worry about specifying whether result is written whether carry is set or not in the source. Never used it any any other language I've coded in. Always store the result, always update carry and zero, then you can simply test the flag, set or clear it, in source whenever you feel like it. I'd argue to get something simple but useful working then worry about bells and whistles and clever tweakings.

    After all, any high-level language is there to make writing and reading it easier, not primarily to allow the most efficient hand-optimised code to be created. Give those who want it a #asm directive. Maybe that's the first thing; be clear about what it is you wish to achieve, what problem you are trying to overcome.

    Key to usefulness IMO is being able to generate LMM PASM as well as native PASM. Get that and other compiler writers can target yours as their intermediate language. I'd also say consider LMM-Thumb ( 16-bit ) to maximise memory capacity. I don't personally see a problem with data being all 32-bit but then I don't do much data processing.

    Good luck with it. Maybe take a look at CC5X from B Knudsen Data, that's a pretty nice ( non-ANSI ) C for PICmicros which don't have stacks and is excellent when used as a high-level assembler, very tight code generation, deals with function parameter passing and all that.
  • heaterheater Posts: 3,370
    edited 2009-02-10 22:05
    I was just having second thoughts about being able to declare variables as being in COG or HUB as suggested by Cluso.

    If COGNAC generated code were the only code to exist in the Propeller the having HUB variables would be great. Especially when writing code for multiple COGs, which I think is a must. It would make it dead easy for COGs to find each others shared variables and communication/control blocks. Basically linking COG code together.

    BUT In general we are not alone in the COG. Perhaps the COGNAC output a .spin source file and is dropped into a Propeller tool project, now we have no control over where our HUB variables are in memory. We end up having to somehow pass pointers from COG to COG at run time to get everything "linked".

    Or perhaps, as Spieha suggests, the COGNAC out put is just a binary blob that gets pulled in from some media and loaded into a COG. In which case we don't even have the possibility to reserve anything in HUB.

    So actually having declarations for HUB variables try to reserve space in HUB is not possible. This all has to be resolved at run time through pointers arriving via "par".

    So should we:

    A) Forget HUB declarations, assume we get some pointers to HUB variables via "par" which are basically just LONGs in our COG code and then just use them as as parameters to built in functions like "readword(some_pointer)". Basically what we do in PASM anyway.

    B) Have HUB variable declarations, but rather than reserving space in HUB they are normal LONGS that will be somehow set up to point to HUB data via "par" When these longs are used they appear as normal variables, "a := some_hub_variable + 6" but the code generated uses rdlong etc to access them.

    I kind of like b)

    Speaking of "par" we need somewhere to start execution and get users parameters in. I'm thinking that the main line for a COG would something like:

    cog uart (par)
    {
    ' All code for a UART COG goes here.
    ...
    }

    or

    cog led_flasher(par)
    begin
    'All code for a LED flasher goes here.
    ....
    end

    Or as "par" is a global anyway perhaps it does not need to be a parameter to the main line anyway. Just let the programmer sort out his parameters as he chooses.

    Or should we have some smarter way formalize the getting and setting up of those HUB declarations from whatever "par" points to. In which case the cog entry function would have many parameters:

    cog uart (long pins, long buad_rate, hub long control_block_ptr,...)


    I choose to call the COGs main enty point "COG" because a COGNAC program may use several COGS. What the "main" for the whole "gearbox" looks like I don't know.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    For me, the past is not over yet.
  • SapiehaSapieha Posts: 2,964
    edited 2009-02-10 22:16
    Hi heater.

    You said " Or perhaps, as Spieha suggests, the COGNAC out put is just a binary blob that gets pulled in from some media and loaded into a COG. In which case we don't even have the possibility to reserve anything in HUB. "

    In my idea I have thinking abaut one else more BYTE/LONG in start of that blob that describe for LOADER how many Variables to reserve in HIGH HUB ram

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Nothing is impossible, there are only different degrees of difficulty.
    For every stupid question there is at least one intelligent answer.
    Don't guess - ask instead.
    If you don't ask you won't know.
    If your gonna construct something, make it·as simple as·possible yet as versatile as posible.


    Sapieha
  • heaterheater Posts: 3,370
    edited 2009-02-10 22:44
    Hippy, some sound high level advice there. I was not really aiming at "one line one op code" rather limiting things to in order evaluation.

    if a := ina >> 8 & $FF
    count += a
    endif

    for example becomes:

    mov a, ina
    shr a, #8
    and a, #$FF wz
    if_nz jmp lab_1
    add count, a
    lab_1....

    Or some such, which of course is not optimal but without a stack to worry about far more efficient code seems to just fall out. I like the idea of "re-jigging temporaries" brings back some use of parenthesis.

    I take my inspiration from Jack Crenshaw here so, as I say, it will have to be simple and any idea of optimization may have to come from those who know more about compilers than I do. When you speak of "intermediate opcode representation" and "back-end code generation" that may be more tan I can fathom at this time. Jack elegantly shows how you can compile straight to asm in one pass with tokenizer, no intermediate representations and back end generators etc. That is about the level I was pitching this at. I'm open to suggestions though.

    Good advice about "be clear about what it is you wish to achieve". First thing I want to do is write out a spec. for all this complete with BNF definition. Such that anyone inclined to can tell me where it is screwy or how to do things better or what may be to complicate to implement in any reasonable time.

    High on the wants list is that programs in COGNAC are pretty, or at least easy on the eye. That might not be so easy as I want to borrow all the funky operators from SPIN. Unlike some Perl I've seen[noparse]:)[/noparse] More like Pascal.

    LMM...Hmm... I already have something that compiles stack based functions with parameters and local variables to LMM. It's pretty crude though.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    For me, the past is not over yet.
  • heaterheater Posts: 3,370
    edited 2009-02-10 23:30
    Not a bad idea Sapieha. I was just wondering how the parameters passed to such a binary blob are matched up. Apart from the user of the blob just knowing how many there are, what they are and what order they are in and coding to it manually.

    In a typical case nowadays we have something like:

    DAT
    command_block LONG
    command LONG 0
    data_length LONG 0
    buffer LONG 0[noparse][[/noparse]16]

    parameters LONG
    pins LONG 33
    baud_rate LONG 40
    command_block_ptr LONG @command_block
    ...

    PAR start
    cognew(@enter, @parameters)

    Then we code our PASM to use get those parms from "par"

    But in COGNAC shouldn't we have a main entry point something like:

    cog (pins, baud_rate, command_block_ptr...)


    And the COGNAC compiler should generate that Spin start up stub (in a separate .spin file) for the user to put in his code. Even if the actual compiled PASM binary blob has no Spin in it.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    For me, the past is not over yet.
  • SapiehaSapieha Posts: 2,964
    edited 2009-02-10 23:57
    Hi heater.

    It is near that I think.
    This DAT must reside in eeprom as header.
    LOADER places it in HUB with any place and generate "command_block_ptr" for my Spin.
    And Spin calculates rest if necessary.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Nothing is impossible, there are only different degrees of difficulty.
    For every stupid question there is at least one intelligent answer.
    Don't guess - ask instead.
    If you don't ask you won't know.
    If your gonna construct something, make it·as simple as·possible yet as versatile as posible.


    Sapieha
  • jazzedjazzed Posts: 11,803
    edited 2009-02-11 00:01
    heater, I like the direction this going. A par interface can be defined without hub visiblity. The user can define a feature signature "cookie" if interfaces really need to be library API-able. At some point one might formalize interfaces by language definition with spin sections or whatever, but not at the start (think background consideration kind of like LMM-ability).

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    --Steve
Sign In or Register to comment.