Many peripheral modules are written in assembler, and you may wish to convert one to C. Below are some pointers to help you do so.
Of the existing C components in the system, some use swix, and some use OSLib. A discussion of the differences can be found here.
When starting out, for a softloadable module, it is feasible to create your first version using GCC if this is what you are familiar with, changing to use the DDE later. Note however that if using OSLib, the version in the OS source is currently different to the latest release, so some minor tweaks may have to be made; this could be avoided by setting things up to using OSLib from the OS source tree from the start.
When you create the cmhg file for your module, call it YourModuleHdr
, so that later on when you integrate your source into the OS, the makefile will do some things for you automatically.
If you are writing a module task, and wish to use no wimpslot, you’ll need to use a
library-enter-code: ...
line, so that you can setup/destroy a stack before/after entering the C code (for an example of how to do this, look at AcornURI). This syntax is not available in cmunge, but you can do this with the GNU tools as
objcopy --redefine-sym _clib_entermodule=_my_entermodule YourModuleHdr.o
In some situations you’ll need to create custom veneers over and above those provided by cmhg; to understand these, look here. Note that you might be able to avoid work by shuffling registers around in assembler and then calling one of the usual cmhg veneers.
Many modules contain a handler for the service call Service_Reset (&27 – a.k.a. Service_PostReset). You do not need to write any code for this, as the OS no longer uses this call.
As the system is uninterruptable in supervisor mode (SVC32), it is good to prototype ideas as a user-mode application. You can then also use tools such as DDT.
Your module will likely include one or more pieces of “pure” logic; remember that you may develop these on any system you like, and that keeping them well separated from the rest of the module code will help anybody investigating your work in the future.
Fortify (which you will need to find yourself) can be used during development for debugging memory allocation problems, overruns etc.
Write tests as you go along, or even before you start. This helps to avoid embarrassment for you, and to again make maintenance easier.
When you run into problems, make a post in the Community Support forum. If you’re unsure about an approach you’re taking, or need someone to look over your work, drop by the Code Review forum.
We will also be happy to give advice in the forums on which modules are suitable for looking at as a starter.
People have taken different approaches to this task: you can read about some of them here and here.
Now you’ve got a working module, and a copy of the DDE, what next?
$
here means the root directory of the component you are working on (e.g. if you are converting the window manager, then this is RiscOS.Sources.Desktop.Wimp
).
Change from “ASM” to “C”. This is required to successfully build as ROM (since an extra linking step must be performed), and to cause the CI script to be created automatically.
Remove $.rm./gitignore
if present and update $./gitignore
to ignore
/aof/
/h/YourModuleHdr
/linked/
/Makefile.d
/o/
/objs/
/od/
/rm/
with lines
include:
- project: 'Support/CI'
file: '/YourModule.yml'
Note that CI will only happen once your change to ModuleDB has been merged. The results appear on your fork of the component.
Add lines
c/** gitlab-language=c linguist-language=c linguist-detectable=true
h/** gitlab-language=c linguist-language=c linguist-detectable=true
cmhg/** gitlab-language=cmhg linguist-language=cmhg linguist-detectable=true
If you used objcopy as mentioned above, now is the time to add a
library-enter-code: ...
line instead.
#include "VersionNum"
then your help string can be
help-string: YourModule Module_MajorVersion_CMHG Module_MinorVersion_CMHG
Bring in
#include "Global/Services.h"
for service call numbers and
#include "Global/SWIs.h"
for your SWI chunk base.
Remove any old assembler source.
The makefile will look something like this
# Makefile for YourModule
COMPONENT = YourModule CMHGDEPENDS = module INCLUDE_OSLIB ?= -IOS: CINCLUDES = ${INCLUDE_OSLIB} LIBS = ${OSLIB} ${ASMUTILS} OBJS = module swis HDRS = ASMHDRS = YourModule
include CModule
# Dynamic dependencies:
CMHGDEPENDS is a list of objects that reference anything from the cmhg header h.YourModuleHdr
. Obviously if you aren’t using a library, don’t include it. AsmUtils provides the base address of the module. Fill out OBJS with all the object files.
Every source file you create must have a license summary as a comment at the start. Most of the OS source is licensed under Apache 2.0, so you could use the following for your C source:
/* Copyright <Year> <Your name or organisation>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
Follow the git cheatsheet.
Having done the CI setup above, once you push your work to your fork on GitLab, the CI will run automatically. You can see the result by clicking on “CI/CD” on the left hand pane when viewing your repository (N.B. your fork). Click on the icons in the “Status” column. Each time you push you will get two pipelines that run.
N.B. Currently none of the “rom_” jobs will pass, and neither will “softload_gnu”. Once “softload” passes there will be available in the far right-hand column of the pipelines screen an option for anybody to download the softload module.