dschmenk / PLASMA

Proto Language AsSeMbler for All (formerly Apple)
MIT License
189 stars 26 forks source link

Add divmod() function? #26

Closed ZornsLemma closed 6 years ago

ZornsLemma commented 6 years ago

I just knocked this up for my Acorn port and I thought it might be of interest to you; it just reuses the existing _DIV and _NEG code to avoid doing the same calculation twice where you want both the result and the remainder. This code fragment just needs adding to each version's cmd.pla and including in the symbol table and cmdsys.plh:

//                                                                               
// result, remainder = divmod(dividend, divisor)                                 
//                                                                               
asm divmod(dividend, divisor)#2                                                  
        JSR     _DIV                                                             
        LSR     DVSIGN                                                           
        BCC     DIVMODNONEG1                                                     
        JSR     _NEG                                                             
DIVMODNONEG1                                                                     
        DEX                                                                      
        LDA     TMPL            ; REMNDRL                                        
        STA     ESTKL,X                                                          
        LDA     TMPH            ; REMNDRH                                        
        STA     ESTKH,X                                                          
        ASL     DVSIGN                                                           
        BPL     CPYMEX                                                           
        JMP     _NEG                                                             
end

Obviously it does bloat the VM slightly (34 bytes on my port, including symbol table entry); because it needs to know the address of the _DIV and _NEG subroutines I don't think it can be implemented as a module and loaded only when needed, unfortunately.

dschmenk commented 6 years ago

I like it. I had a DIVMOD opcode when I first attempted multiple return values. This is better as a function. Let me make sure there aren't any issues with the other VM implementations.

dschmenk commented 6 years ago

So I implemented it in a combination of assembly and byte code. I made a slight change to the MOD implementation to save the result of the DIV. Its VM agnostic (mostly). I haven't really tested this yet, FYI.

ZornsLemma commented 6 years ago

Thanks Dave. I've pulled your recent changes and merged them into my port; I'll give it a bit of testing over the next week or so.

On 6 December 2017 at 17:31, David Schmenk notifications@github.com wrote:

So I implemented it in a combination of assembly and byte code. I made a slight change to the MOD implementation to save the result of the DIV. Its VM agnostic (mostly). I haven't really tested this yet, FYI.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/dschmenk/PLASMA/issues/26#issuecomment-349715149, or mute the thread https://github.com/notifications/unsubscribe-auth/AHnkEALKrfV-bGbvV1mHqpm38rOFyP0yks5s9s92gaJpZM4PSWxo .

dschmenk commented 6 years ago

I gave up trying to hack this into all the versions. Since I got rid of a couple of byte codes, I repurposed one as a divmod opcode. Incompatible with older modules, so I changed the magic number (again!) but it's much cleaner and smaller - I needed the bytes for CMDSYS. Ready for Developer Preview 1.0. It's still exported as a function, but the function is in bytecodes.

ZornsLemma commented 6 years ago

Thanks Dave. I've just pulled the latest master from your repo - looks like you've been busy! It will probably be a couple of weeks before I get a chance to try to merge these changes into my port, unfortunately.

Just a quick thought - could the peephole optimiser recognise a CALL to the divmod() function and replace it with the DIVMOD opcode? (You'd still need to keep the divmod() function itself in case any code takes its address to call it through a function pointer.) I haven't tried to implement this myself yet, I may take a look at it later unless you beat me to it or tell me it's not possible. :-) )

dschmenk commented 6 years ago

Hi Steve-

Interesting idea. Intrinsic functions could be quite useful, like memcpy(), memset(), sext() (A new sign extend for bytes), and others. I won’t get to it until post 1.0, but it would be cool to see what you can come up with.

You have some VM changes to contend with, but they’re pretty simple. Note that PUSHESP, POPESP have been eradicated. Also, ENTER and LEAVE have been subtly modified - the frame size isn’t saved on the stack for LEAVE. LEAVE just gets it as an immediate parameter. Eases the HW stack usage somewhat. I also flattened the (IP),Y into IP for CALL,ICAL. Again, to relieve HW stack usage. So the compiler/loader now uses a new magic # for module loading: $6502 ;-)

Dave...