Getting ready to program in C with GCC on RISC OS
Patrick M (2888) 115 posts |
Hello, Over the past two years I’ve built up some experience writing programs for Linux in C, and now I’m ready to start writing programs for RISC OS in C. What’s the correct way to go about installing GCC on RISC OS? What sorts of thing should I be aware of when going into this? The version of RISC OS I’m using is a bit out of date (I think it’s from 2015), will that cause trouble? In the future I’m planning on writing a game that does a lot of maths for rotating and scaling and stuff like that, so I would need the compiler to use the VFP/floating point instructions. I’ve heard that can be a problem on RISC OS, so I’m wondering, would I need to give gcc some specific command line options to enable the use of these instructions? Sorry if these questions are already answered somewhere. |
Steffen Huber (91) 1953 posts |
See http://www.riscos.info/index.php/GCC
Writing C is dangerous for your sanity. Apart from that – just do it!
Unlikely, but you never know. I hope you have very good reasons not to update. Updating is a bit of work, but chasing bugs that result from using out-of-date versions is a lot more work.
By default, GCC compiles for ARM6 (i.e. APCS-32 with ARM6xx/ARM7xx as default target), so no VFP. If you find out the necessary details, please update http://www.riscos.info/index.php/GCC_for_RISC_OS which is not really up-to-date (he said, after recommending that very link above…). Some people should already know the answer, but haven’t updated the riscos.info Wiki. |
Patrick M (2888) 115 posts |
Thanks, I’ve just managed to compile and run a test “hello world” program. I’m ready to Press SPACE or click mouse to continue. While we’re at it, how would you use SWIs from C? I’ll need to use OS_SpriteOp in my next project. Also, how do you change MODE? |
Rick Murray (539) 13850 posts |
I’m not at all familiar with GCC, however the best way to use normal SWIs from C is to use a library that provides the SWIs as veneer functions. Take a look at DeskLib and OSLib – both should offer a number of functions to handle SpriteOp for you. |
Rick Murray (539) 13850 posts |
Wouldn’t ELF2AIF permit you to use UnixLib and have an AIF executable at the end? |
Chris Mahoney (1684) 2165 posts |
In the DDE, you can use _swi and _swix. For example:
This will call Some_SWI, passing the first three parameters (1, 2, 3) into the first three registers (IN Range 0-2). The result in R0 (OUT 0) would be stored into abc. Hopefully GCC has something similar. For the “simpler” SWIs you can actually map them to C functions:
You can then call All of this code is untested :) |
Rick Murray (539) 13850 posts |
DavidS: Your code is broken and this will never work: Wimp_CreateIcon SWI &400C2 MOVVS R0,#0 MOV R15,R14 The reason it won’t work (and the rest will crash your program should anything go wrong) is that you are not calling the X form of the SWIs, so an error will be raised. If the CreateIcon call should fail, the VS will never be executed, it’ll have gone to the most recent error handler. And by that I mean the program environment error handler. The usual way to write this sort of thing is to always call the X form of the SWI, and specify that R0 on exit is either NULL or a pointer to an error block. With that the calling function can know the state of the call (if it worked, or not) and take appropriate action.
Don’t use either. Look at the reams of code involved and know that potentially a hundred instructions to call a SWI is utterly taking the…. In later versions of the DDE compiler: __asm { MOV R0, 'a' SWI (OS_WriteC + XOS_Bit), {R0}, {}, {PSR} } Which will inline the SWI directly into the code generated by the compiler. Quick and simple. The curly brackets are: registers used on entry, registers used on exit, registers that are not used but are corrupted by the SWI call. As the code interacts with the compiler and its optimisations, it’s important to get the last one correct. No help for GCC, mind you……. ;-) |
Steffen Huber (91) 1953 posts |
Please forget all the other advise and just use OSLib. It has a proper, typesafe veneer for every SWI under the sun. It has meaningful structs to help you get the parameters right. It works with GCC and DDE. And you can even use it from Assembler. |
Rick Murray (539) 13850 posts |
As was suggested, by me, in the very first reply to that question. ;-)
Sorry, I didn’t get as far as reading all of that. I looked at the code and spotted you trying to test a conditional flag after not calling an X form SWI. I look at the code first, because that’s the important part.
[…]
Indeed, as you yourself acknowledge… […]
There are two ways to write code. A way where one attempts to do it properly the first time (I say attempt, because we aren’t gods, we make mistakes, and computers are not forgiving) or the way where one bodges together something that appears to work but will fall over at the slightest provocation. I see you’ve changed some of your SWIs to be X form. Do the rest and you’ll have the makings of another basic Wimp library (but look at all those magic numbers!). In fact you have magic numbers all over the place, no attempt to report an error (so if the templates file is missing the program will just vanish). Oh my… But, then, there’s this:
It’s extremely recommended to use a prewritten library because no matter how simple you think such things are, it’s tedious and stupid to reinvent the same code others have already created especially when you make peculiar design decisions that equate to not doing the job properly. In other words, you’ve gone to all that effort. All of the rest of us would just #include our library of choice, and then call the routines provided… |
GavinWraith (26) 1563 posts |
If you use the X form of SWIs and catch errors signalled by the V flag I do not think you can claim to be out of the woods and safe. All sorts of nasty things may have happened in supervisor mode before the SWI returned. The PRMs do their best to tell you what sort of state each SWI expects on entry, but they are silent, for the most part, on what can happen as a side-effect when those expectations are not met. This is what makes debugging wimp programs so difficult. Lua has something analogous to the X form of SWIs. If you replace a function call by a protected call the Boolean value status is analogous to the V flag, allowing you to control errors completely, so long as the functions are pure Lua. If status is not true then result is an error object. But once you start using SWIs, handing control over to RISC OS, things are not so cosy.
|
Timothy Baldwin (184) 242 posts |
In the DDE, you can use _swi and _swix. On the Linux Port I’m working on there actually About 10 years ago I wrote a fast C++ implementation of _swi |
Rick Murray (539) 13850 posts |
Interesting idea, to do it via a smart macro. BTW, is it you or f2s silently setting the cookie |
Patrick M (2888) 115 posts |
Thanks everyone. I’m going to go with OSLib, since it seems like the best and most convenient method. |
Steve Fryatt (216) 2105 posts |
This. Very much this. |
Timothy Baldwin (184) 242 posts |
It’s f2s, now TalkTalk Business. The website is free with home broadband, we closed our account with them in 2011 and switch broadband providers after they made our account uncontrollable. I no longer have any control over the web site. |
Richard Walker (2090) 431 posts |
Steffen and Steve are right on the money. Use OSLib – it is excellent. It harnesses the power of the compiler to help you read and write the code. I think a sensible aim is for zero assembler (it’s just unmaintainable) and write your code for a human to read, not the machine. It is very unlikely that most of your code will be genuinely speed-critical, so aim for increased development time and a lower barrier to entry for another developer. If you are truly an expert, and can demonstrate a performance issue, that is when you start to write the funny-looking stuff! If you use other example code or libraries, you may find them using _swix, so don’t be afraid to roll with that too, as necessary. |
Rick Murray (539) 13850 posts |
Wimp poll flags and the stuff put into the menu block – just a bunch of meaningless hex digits. Magic numbers.
That’s why I like DeskLib. It isn’t as type safe as OSLib, but it does offer the expected range of low level functions, along with a nice higher level event dispatch mechanism. The boring grunt work of Wimp functions is pleasantly simple with DeskLib, but it’s possible to tweak and twiddle if special behaviour is desired (like the in-scrollbar-tools in Manga). You see, libraries aren’t about taking away control (no, that’s Brexit…), they’re about making the programmer’s life simpler. Your code to create the menu block could be replaced with something like: ibarmenu = Menu_Create(MyAppName, "Info>,Quit"); And a menu block will be created and a handle returned. Whether or not I wrote that library function is not even remotely relevant. All that matters is that it works.
Says the person who wrote their own strcmp instead of using the CLib version (which will copy words when it can). For everybody else reading – I use DeskLib for my applications. It’s significantly less code than if I did everything by hand. But, then, that’s kind of the point of libraries isn’t it?
I said a while back that when one writes code, they’re in an interesting position of writing for two entirely different audiences at the same time.
None of my code is speed critical. I use inline assembler simply to call SWIs. To me it doesn’t make much difference if I have a short assembler function to call the SWI, or if I inline it. At any rate, libraries are to be embraced, not feared; and there’s no sensible reason to write everything in assembler. |
Patrick M (2888) 115 posts |
Apart from you, who else? I’ve noticed you’ve been saying a lot of stuff like this in various threads across the forum, and to be honest it confuses me a bit. I honestly think you’re the only person I’ve ever encountered who’s said that assembly language is easier to understand and maintain. Absolutely everything else I’ve heard from everyone else has been the opposite. Now of course I don’t really know any assembly language so that’s probably a big part of why, but, whenever I look at assembly code it’s really opaque looking to me. With nicely written and indented C code you can get a quick sense of how a program is structured from how it looks, just by skimming over it with your eyes. And there are symbols with clear meanings, like + / *, etc. In contrast, all the assembly language code I’ve seen just looks like a long list of very terse acronyms. I don’t find it intuitive at all. |
Steve Pampling (1551) 8172 posts |
I think the thing with assembler is that you can see the minute detail and sometimes miss the big picture. With something like C I would expect to see the bigger picture and miss detail. After all at that level you care less about how it was done and more that it produced a specific result.
Terse like text speak (but not re-invented on the fly), which I’m told is quite efficient but despite its similarity to English it seems quite opaque. |
David Feugey (2125) 2709 posts |
Correction:
The real question is: are you sure to be able to optimise your code more than the hundred of people who worked on the optimisations in the machine code generation of DDE or GCC? Take a very complex problem, code it in C and ASM, and you’ll have the answer.
Not for me. |
Rick Murray (539) 13850 posts |
This. Do you seriously think Manga, Koi-Koi, etc would exist if I had to write it all in assembler and had to keep precise track of the locations of every single array, every single register put into and pulled off of the stack? I have no desire to be overly concerned with such trivial things.
That’s not really the big issue though, is it? The big issue is that all of the ARM architectural changes were “minor” issues to code written in C. (and, yes, no issue at all to BASIC but then since BASIC is a tokenised script…). Now, the important thing here is that I did not have to delve into reams of code to start analysing it all to look for problematic statements (in the first case, a few small veneers needed the restore-flags opcode altered). Instead, I just updated the compiler and rebuilt. Job done. Assuming a 64 bit version of RISC OS and assuming a mostly-compatible API, the hard part in making my software compatible will not be the software itself. No, the hard part will be porting DeskLib. However, once that has been done (remember, I rolled my own 32 bit port), everything that uses it should continue working more or less as expected. As mentioned before, OvationPro exists on a Windows incarnation. Now the venerable Mr Pilling may have had to jump through many hoops to get something running under Windows that presented an API not unlike the RISC OS one. That done, the main body of code that comprised OvationPro was just rebuilt as an x86 executable. Best ever example? Linux. Some small boot/helper functions in assembler. The rest in C. Available for just about every useful processor on the planet. Compiled language versus “doing it the hard way”. It’s really no contest. DavidS, we’re driving on the motorway, ring roads, even little country lanes. |
Rick Murray (539) 13850 posts |
Wait… you’re American aren’t you? So that’ll be freeway/interstate, beltway, and “West Virginia”. ;-) |
GavinWraith (26) 1563 posts |
Back in 1992 Nick Craig-Wood gave, via Acorn User magazine, the Numbers module, to demonstrate the RSA algorithm and to let users play with big integers. In the same year Michael J. Fromberger wrote an arbitrary precision maths library, Imath, in C. I am about to release an application, !Zahl, using it for the same purpose. But it is instructive to compare the two: 1. Numbers module ARM assembler 2. !Zahl application C + Lua |
Steve Pampling (1551) 8172 posts |
Move mouse using a keypress1. Right, now update those values and put the new values back to update the position, oh OS_Mouse is read only. Move to the OS_Word 21 info where we find that we can read and write the positions but we have to deal with providing a memory block (somewhere that other things won’t trample on it) and the LSB and MSB of the x (and same for y) position is held in two elements of the block so there’s some manipulation to deal with human type values or simply modify the retrieved values up and down. OK, shift to BASIC (nice and familiar for folks)
MOUSE TO and x,y value being the hardest bit you do after telling BASIC to drop the current pointer posn & button state in the buffer block you named but never specified where, just leave that to the higher level capabilities of BASIC. Did BASIC ever want to know anything about which bit of the x (or y) value was where? No doubt the assembler is quicker, but the moves only need to be human speed anyway. 1 Who cares? Well, 22 years ago the CVS had this document labelled feasibility inserted. At line 434 we have “Keypress mouse movement as a general facility.” cost 1 week. So, 22 years on and we have some limited shortcuts, we don’t have keypress mouse control. |
Rick Murray (539) 13850 posts |
This. And as you note:
If this was C, just call a function if the mouse is clicked. In that function, define a struct for the mouse position info. Assembler? You could do the same but you’d have to bugger around with R13 to make some space either side of your OS_Word stuff. And, of course, forget one single word (error exit early?) and it all blow up. You can write bad, incomprehensible, crashy, or just plain ridiculous code in C; however should you decide to do the same in assembler, it is largely indistinguishable from good code! Indeed, the only benefit you get when dealing with assembler are your backtraces and dumps look like the source. ;-) |