Last visit was: Sat Dec 21, 2024 2:20 pm
|
It is currently Sat Dec 21, 2024 2:20 pm
|
Porting the C64 compiler to target OPC5 (or OPC6)
Author |
Message |
robfinch
Joined: Sat Feb 02, 2013 9:40 am Posts: 2231 Location: Canada
|
The compiler is now updated for OPC6. It spits out jsr's, pushes, pops and inc's / dec's.
I've just been eyeballing the output so far without actually running it through the assembler and simulator.
Dave, you're welcome to try the compiler at any time, but I don't guarantee the code will work. It might be a few days yet before I've run things in the simulator. It's built on Windows as a console app using the MS Visual Studio 10 Express (free) edition. the target machine was set to X86. It looks like it might be a 32 bit app. It also needs FPP.exe (or something called fpp.exe) which it shells out to perform the pre-processing.
_________________Robert Finch http://www.finitron.ca
|
Thu Aug 03, 2017 8:01 am |
|
|
robfinch
Joined: Sat Feb 02, 2013 9:40 am Posts: 2231 Location: Canada
|
Quote: Have you, or anyone else, ever tried building FPP or C64 on Linux?
I've not tried building it in Linux. About the closest is Bloodshed and gcc IIRC. It should build without too many hiccups because it's a console app not a gui app and most of the code doesn't use any unusual features ( I believe it doesn't use .NET for instance). Some of the int types are defined in stdafx.h I think for building with gcc instead of MSC. In stdafx.h: Code: #ifdef _MSC_VER typedef __int8 int8_t; typedef __int16 int16_t; typedef __int64 int64_t;
typedef unsigned __int8 uint8_t; typedef unsigned __int16 uint16_t; typedef unsigned __int64 uint64_t; #else #include <inttypes.h> #endif
_________________Robert Finch http://www.finitron.ca
|
Thu Aug 03, 2017 6:24 pm |
|
|
robfinch
Joined: Sat Feb 02, 2013 9:40 am Posts: 2231 Location: Canada
|
I cleaned up some of the extra code that wasn't needed for OPC6. Also "fixed" a bug having to do with multi-dimensional arrays. Arrays with more than 4 dimensions are not supported. 4 dimensional array may not work, but there's code for it. I'm pretty sure arrays of one and two dimension are working.
_________________Robert Finch http://www.finitron.ca
|
Fri Aug 04, 2017 4:23 am |
|
|
hoglet
Joined: Tue Feb 10, 2015 7:07 am Posts: 52
|
Rob, robfinch wrote: I've not tried building it in Linux. About the closest is Bloodshed and gcc IIRC. It should build without too many hiccups because it's a console app not a gui app and most of the code doesn't use any unusual features ( I believe it doesn't use .NET for instance). Some of the int types are defined in stdafx.h I think for building with gcc instead of MSC.
I've been successful in building and running C64 on Linux: Code: dmb@quadhog:~/atom/robfinch/Cores/test$ ls -l total 4 lrwxrwxrwx 1 dmb dmb 33 Aug 5 18:51 c64 -> ../software/C64 - OPC5/source/c64 lrwxrwxrwx 1 dmb dmb 23 Aug 5 18:51 fpp -> ../software/fpp/src/fpp -rw-rw-r-- 1 dmb dmb 50 Aug 5 18:47 test.c
dmb@quadhog:~/atom/robfinch/Cores/test$ cat test.c min(int a, int b) { return a < b ? a : b; }
dmb@quadhog:~/atom/robfinch/Cores/test$ c64 test.c
-- 0 errors found.
dmb@quadhog:~/atom/robfinch/Cores/test$ ls -l total 24 lrwxrwxrwx 1 dmb dmb 33 Aug 5 18:51 c64 -> ../software/C64 - OPC5/source/c64 lrwxrwxrwx 1 dmb dmb 23 Aug 5 18:51 fpp -> ../software/fpp/src/fpp -rw-rw-r-- 1 dmb dmb 50 Aug 5 18:47 test.c -rw-rw-r-- 1 dmb dmb 4828 Aug 5 19:13 test.c.xml -rw-rw-r-- 1 dmb dmb 50 Aug 5 19:13 test.fpp -rw-rw-r-- 1 dmb dmb 286 Aug 5 19:13 test.lis -rw-rw-r-- 1 dmb dmb 358 Aug 5 19:13 test.s
dmb@quadhog:~/atom/robfinch/Cores/test$ cat test.s # code _min: push r12 mov r12,r14 ld r1,r12,1 ld r2,r12,2 cmp r1,r2 mi.inc r15,test_4-PC ld r1,r12,1 inc r15,test_5-PC test_4: ld r1,r12,2 test_5: mov r14,r12 pop r12 mov r15,r13 # rodata # extern _min
I'll clean up my code and check it into a fork tomorrow so you can see what changes I have made. One thing I really struggled with was the case of filenames, especially in the fpp source directory. I know in Windows this doesn't matter, but in Linux it does, and gcc assumes a file with a .C suffix is C++. Would it be a lot of trouble to rename these files? Anyway, let me check my changes into a fork tomorrow and you can see what I needed to do. Dave
|
Sat Aug 05, 2017 8:46 pm |
|
|
hoglet
Joined: Tue Feb 10, 2015 7:07 am Posts: 52
|
Hi Rob, I've checked my changes that allow building with gcc into a fork (and I can generate a pull request when you are ready): https://github.com/hoglet67/Cores/commits/OPC_gcc_fixesMost of the changes are in a new file compat.h which provides static inline wrappers to non-standard MS library calls. I've also added a Makefile, so to build all you need to is: Code: cd 'software/C64 - OPC5/source' make clean c64
I followed your suggestion of using "cpp -P" as a preprocessor, so that avoided having to port FPP. There are a few warnings that it would be nice to get rid of, so I can drop the -fpermissive flag. Log file attached. A couple of things I wasn't sure about: - I had some problems with duplicate definitions of OptimizationDesireability() - one in Analyze.cpp the other on OPC6.cpp. Is the one in Analyzer.cpp superfluous? - There is a empty declaration of Statement in C.h that was also causing lots of warnings. Both of these I effectively ifdefed out, but thought it best to check with you that's the right thing to do. Dave
You do not have the required permissions to view the files attached to this post.
|
Sun Aug 06, 2017 12:16 pm |
|
|
hoglet
Joined: Tue Feb 10, 2015 7:07 am Posts: 52
|
Rob, I have a couple of further questions... 1. Can you give me an example showing the correct syntax for the asm keyword? 2. I see in the generated code there are references to external functions like _mul, _mod, _div. Is this the full list of these? - _mod
- _modu
- _div
- _divu
- _mul
- _mulu
- memcpy_
Do any of them exist yet? Would they need to be need to be 32 bit? 3. Is there anything like libc (i.e. a standard library) for C64? Dave
|
Sun Aug 06, 2017 1:29 pm |
|
|
robfinch
Joined: Sat Feb 02, 2013 9:40 am Posts: 2231 Location: Canada
|
A sample of the asm keyword in use: Quote: int TestAsm(register int a, register int b) { asm __leafs { push r8 push r9 jsr a_sub inc r14,2 }; }
The __leafs is optional but it tells the compiler that the routine isn't a leaf routine. It should be used if there is a jsr to other code. Otherwise the compiler doesn't know to save and restore the link register. Note leading spaces are allowed. I see they've been eliminated for posting. for _mod, _mul, _div etc. none of them exist yet. They are currently expected to be 16 bit. _mulu is probably a priority as it's used to calculate array indexes. There are a few simple functions collected in something called c64libc. It's just enough for some simple programs. I haven't ported over the standard C library yet. I will place them on GitHub, but they may be somewhat specific to a different processing core.
_________________Robert Finch http://www.finitron.ca
|
Sun Aug 06, 2017 4:07 pm |
|
|
BigEd
Joined: Wed Jan 09, 2013 6:54 pm Posts: 1808
|
Excellent! That doesn't seem too intrusive and is a big leap forward for those of us without Windows.
|
Mon Aug 07, 2017 10:14 am |
|
|
robfinch
Joined: Sat Feb 02, 2013 9:40 am Posts: 2231 Location: Canada
|
Looks good to me. I've not handled a pull request before so I may be a bit sluggish on the uptake. I'm assuming a pull request will allow me to incorporate your changes. Please create a pull request. One thing I changed was I got rid of the duplicate OptimizationDesirability() - moved it into a class method.
_________________Robert Finch http://www.finitron.ca
|
Mon Aug 07, 2017 4:55 pm |
|
|
hoglet
Joined: Tue Feb 10, 2015 7:07 am Posts: 52
|
Rob, robfinch wrote: Looks good to me. I've not handled a pull request before so I may be a bit sluggish on the uptake. I'm assuming a pull request will allow me to incorporate your changes. Please create a pull request. One thing I changed was I got rid of the duplicate OptimizationDesirability() - moved it into a class method. I've updated and retested my patch against your latest code (as things have moved on and there were conflicts....) You should now see a pull request: https://github.com/robfinch/Cores/pull/1At the moment it will clean merge, as I just rebased it off you latest master. Separately, I am now seeing a line ending issue with the following files, which makes them look like they are always modified locally: Code: software/C64 - OPC5/test/ClassTest.cpp.xml software/C64 - OPC5/test/ClassTest.s software/C64 - OPC5/test/TestArrayAssign.s software/C64 - OPC5/test/TestFor.s software/C64 - OPC5/test/TestFunccall.s
Can you see anything wrong with them at your end? Edit: It looks like these files have managed to get checked in with CRLF terminators, where as all the others have been normalized. This is unrelated to my changes as far as I can tell. Dave
|
Mon Aug 07, 2017 6:10 pm |
|
|
robfinch
Joined: Sat Feb 02, 2013 9:40 am Posts: 2231 Location: Canada
|
I've merged the changes into the base code. It rebuilds fine in VS10 express too. I'll go through the code and convert any CRLF pairs into just LF's just to be safe. DOS days are long gone.
_________________Robert Finch http://www.finitron.ca
|
Mon Aug 07, 2017 9:55 pm |
|
|
hoglet
Joined: Tue Feb 10, 2015 7:07 am Posts: 52
|
Hi Rob, I'm in the process of testing the output of the C Compiler, with the goal of seeing if I can actually get a small piece of C to run on some real hardware. I thought I would use this post to log issues as I encounter them. I'll edit this post as I discover issues. Note, these are not necessarily compiler issues. It may be the correct solution is to extend the assembler. Issues: 1. Push/Pop don't assembleCurrently: Code: push r13 ... pop r13
Should be: Code: push r13, r14 ... pop r13, r14
(i.e. the register being used as the stack pointer, by convention r14, needs to be made explicit) 2. align pseudo-op does not exist (and probably isn't needed in OPC)3. word pseudo-op should be WORD (i.e. upper case)4. Incorrect code generation - the first character of the string is missedCode: void print(char *ptr) { while (*ptr) { outch(*ptr++); } }
Code: 010d _print: 010d 28ed push r13,r14 010e 28ec push r12,r14 010f 00ec mov r12,r14 0110 test_12: 0110 17c5 0002 ld r5,r12,2 0112 0755 ld r5,r5 0113 0405 add r5,r0 0114 4cef z.inc r15,test_13-PC 0115 17c5 0002 ld r5,r12,2 # ptr++ is happening too early 0117 0c15 inc r5,1 0118 16c5 0002 sto r5,r12,2 011a 17c5 0002 ld r5,r12,2 011c 0755 ld r5,r5 011d 28e5 push r5,r14 011e 190d 0106 jsr r13,r0,_outch 0120 0c1e inc r14,1 0121 100f 0110 mov r15,r0,test_12 0123 test_13: 0123 00ce mov r14,r12 0124 29ec pop r12,r14 0125 29ed pop r13,r14 0126 00df mov r15,r13
5. Incorrect code generation - nothing is outputCode: void print(char *ptr) { while (*ptr) { outch(*ptr); ptr++; } } void main() { print("Hello world\r\n"); }
Code: 010d _print: 010d 28ed push r13,r14 010e 28e3 push r3,r14 010f test_12: 010f 0735 ld r5,r3 # r3 doesn't contain anything at this point 0110 0405 add r5,r0 0111 4c7f z.inc r15,test_13-PC 0112 0735 ld r5,r3 0113 28e5 push r5,r14 0114 190d 0106 jsr r13,r0,_outch 0116 0c1e inc r14,1 0117 0c13 inc r3,1 0118 -091 dec r15,test_12-PC 0119 test_13: 0119 29e3 pop r3,r14 011a 29ed pop r13,r14 011b 00df mov r15,r13 011c _main: 011c 28ed push r13,r14 011d 1005 0125 mov r5,r0,test_15 011f 28e5 push r5,r14 0120 190d 010d jsr r13,r0,_print 0122 0c1e inc r14,1 0123 29ed pop r13,r14 0124 00df mov r15,r13
6. Assembler bug in the above code at address 0118:Looking at the above assembler listing, it appears the assembler has barfed at 0118: Code: 0118 -091 dec r15,test_12-PC
What's actually been placed in memory is: Code: >> dis 110 0118 0912 : jsr r2, r1
I think what's happening here is that test_12-PC is negative, and this is confusing the assembler. I think the correct results are obtained with: Code: 0118 0eaf inc r15,test_12-PC
i.e. the assembler has noticed the negative offset and switched the opcode to dec: Code: >> dis 110 0118 0eaf : dec r15, 10
Honestly I'm not sure if this is a compiler bug, an assembler bug or both! 7. Trailing ,r0 is sometimes omittedCode: int bug7(int d) { return (d / 1000) % 10; }
Code: _bug7: push r12 mov r12,r14 ld r6,r12,1 mov r1,r6 mov r2 # error here push r3 push r4 mov r3,1000 mov r4 # error here jsr r13,r0,__div32 pop r4 pop r3 mov r5,r1 mov # error here mov r1,r5,0 mov r2,r0,10 mov r13,r15,2 jsr r13,r0,__mod mov r14,r12 pop r12 mov r15,r13
8. Failing to save link register (r13) when using built-in functions like _mul Code: int bug8(int a, int b) { return a*b; }
Code: _bug8: push r12 mov r12,r14 ld r5,r12,1 ld r6,r12,2 mov r1,r5 mov r2,r6 jsr r13,r0,__mul # r13 used but not saved mov r14,r12 pop r12 mov r15,r13
9. Sometimes dec is used for loops with too large an offsetQuote: while (nines) { putchar('0'); nines--; }
Code: pi_32: ld r5,r12,-4 add r5,r0 z.inc r15,pi_33-PC mov r5,r0,48 push r5,r14 jsr r13,r0,_putchar inc r14,1 ld r5,r12,-4 dec r5,1 sto r5,r12,-4 dec r15,pi_32-PC # offset here here is
10. Array writing using wrong registerCode: #define LEN 333 void bug10() { int x; int pi[LEN + 1]; for (x = LEN; x > 0; x--) { pi[x] = 2; } }
Code: _bug10: push r12 mov r12,r14 sub r14,r0,335 push r3 mov r3,r0,333 bug10_4: cmp r3,r0 mi.inc r15,bug10_5-PC cmp r3,r0 z.inc r15,bug10_5-PC mov r1,r12,-335 mov r5,r3 add r3,r1 # should used r5 not r3 mov r1,r0,2 sto r1,r3 # should used r5 not r3 dec r3,1 dec r15,bug10_4-PC bug10_5: pop r3 mov r14,r12 pop r12 mov r15,r13
Dave
|
Thu Aug 10, 2017 11:13 am |
|
|
Revaldinho
Joined: Tue Apr 25, 2017 7:33 pm Posts: 32
|
On Number 6 above ... Quote: Looking at the above assembler listing, it appears the assembler has barfed at 0118:
0118 -091 dec r15,test_12-PC
What's actually been placed in memory is:
>> dis 110 0118 0912 : jsr r2, r1
I think what's happening here is that test_12-PC is negative, and this is confusing the assembler.
I think the correct results are obtained with:
0118 0eaf inc r15,test_12-PC
... Dave is right, of course. Originally only positive offsets were legal for both inc and dec operations, and error checking was lamentably absent. I updated only inc to be able to take positive and negative values thinking that there was no longer a need to ever use dec in assembly source, but I've now corrected that. In the latest version on GitHub you can use either inc or dec with an offset in the range -15 ..+15 and the assembler will switch the instruction as required. So, no compiler changes here and just look on it as an assembler bug which is fixed now. R
|
Thu Aug 10, 2017 7:57 pm |
|
|
hoglet
Joined: Tue Feb 10, 2015 7:07 am Posts: 52
|
Revaldinho wrote: ... Dave is right, of course. Originally only positive offsets were legal for both inc and dec operations, and error checking was lamentably absent. I updated only inc to be able to take positive and negative values thinking that there was no longer a need to every use dec in assembly source, but I've now corrected that. In the latest version on GitHub you can use either inc or dec with an offset in the range -15 ..+15 and the assembler will switch the instruction as required. So, no compiler changes here and just look on it as an assembler bug which is fixed now.
Actually, I think a compiler change is needed as well. Consider: This is a backwards branch, yet test_12-PC is negative. I think the compiler should emit: or Rob, we are making excellent progress here. Most of these issues are very localized to the Code Generation, and should be easy to resolve. This is all very cool indeed! Dave
|
Thu Aug 10, 2017 8:07 pm |
|
|
robfinch
Joined: Sat Feb 02, 2013 9:40 am Posts: 2231 Location: Canada
|
Okay, I have updated the compiler. I got little side-tracked trying to add a color-graphing register allocator. It's just a bit too complex for me to understand So I've been researching and scratching my head. Bug #4 isn't fixed yet. It maybe an issue with the 'C' standard. 'C' does not guarantee the order in which the auto-inc and auto-dec operations take place. Different compilers support them differently. If one does something like p[ndx++] the index may be updated either before or after it's used to index the element depending on the compiler. I think not even brackets are respected. When I found this out I started writing all the inc/dec operations as separate instructions with a semi-colon. So I write p[ndx]; ndx++; to guarantee the order and it's portable between compilers. (Yes I got burned on this issue before). Something like the example isn't guaranteed to work in the order one expects. I will have a look at it however.
_________________Robert Finch http://www.finitron.ca
|
Fri Aug 11, 2017 8:36 am |
|
Who is online |
Users browsing this forum: AhrefsBot, claudebot, SemrushBot and 0 guests |
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot post attachments in this forum
|
|