Contents |
Introduction |
Module interface files |
Syntax |
Semantics |
The ByteWide file |
APCS to SWI |
Implementation notes |
The grammar |
An example file |
Future possibilities |
Revision history |
DefMod is the tool for generating all sorts of different files from module interface files. A module interface file (with the conventional file extension .swi) contains enough information to specify, in a language-independent form, the interface to a RISC OS module. This can be used to generate suitable files to enable the module to be called from any high-level language. The whole of OSLib (apart from "types.h" and "macros.h") is derived from a set of modules interface files and these DefMod options:
For other options, see DefMod -help.
DefMod can be most useful when used at the start of a project: it can be used to specify the whole of the module interface before any of the module is written. The header files it generates can then be used during actual development of the module. This means that all the resources used by the module are defined in one place only---the module interface file---which will then be the master for things like SWI numbers, command numbers, error numbers, structures and SWI calling conventions for development of the module itself and its clients.
The format of a module interface file is described completely by the grammar which accompanies this document. A brief outline follows.
There is no separate lexical analyser: the grammar goes all the way to the individual character level. A consequence of this is that a convention is needed to keep reserved words grammatically distinct from user-defined identifiers: since the grammar should be case-insensitive but case-preserving (at least in the area of SWI names), case is not used as the mechanism: instead, reserved words start with a full stop.
There are some conventions (metarules, really) used in the grammar:
Case in the interface file is important, because it is used to decide where to break up a name. SWI names must always be specified exactly in the form used by the system. All symbols should begin with the module prefix, or Error_, Event_, Message_, Service_, UpCall_ or else should end in V (for vectors).
There is an example module interface file for the ColourPicker module (see An example file).
A file consists of a series of declarations. There are 6 different types of declaration. Each type may occur as many times as necessary. The way in which commas and semi-colons are used may be a bit confusing: they are separators, not terminators as in C, so, for example, a CONST section might be
CONST a = T: 0, b = T: 1, c = T: 2
and there is no comma at the end. If there were multiple sections in a file, then semi-colons appear between them, but not at the end, like this:
CONST section; TYPE section; SWI section; another CONST section
This will all be familiar to users of Pascal or ALGOL.
A type_defn with no type defines an "abstract type". A structure type may end with ..., in which case various extra macros will be generated. An abstract type name is often a single letter (as in wimp_w, os_f).
A SWI number may be followed with a textual description or with a star (in which case a description will be made up). A reason code will be created (instead of a standalone SWI) when the SWI number does not contain a description (nor a star) and there is at least one constant register definition with a non-empty text description or star. When there is more than one constant register definition with a non-empty test description or star, the first one mentioned will be considered to be the reason code and its description (or the made one up in case of a star) will be used to describe this SWI entry. A warning is given when the SWI entry does not contain any description nor star, or when the SWI number and one or more constant register definitions do have a textual description (and no star).
One output register may be marked with a pling, in which case the non-x form will return it as its result.
Constants may be provided in decimal, hex (& or 0x) or binary (% or 0b) or as a character value of up to 4 characters (e g, "TASK").
This gives the module a title. It is used to produce a comment in output, and should be the same as the module prefix. There can only be one of these.
This gives a string which appears in the output, also as a comment. There can only be one of these.
Contains the names of other module interfaces on which this one depends. This does not cause the named module interface file to be read by DefMod, but may cause it to emit some kind of include directive in the output.
Contains constant definitions. Constants may be of a built-in type or one defined in this or another interface file.
Defines types. Types are built-in types (Int, Short, Byte, Char, Bits, Bool, String, Asm, Data) or derived types. They are classified into "register", "non-register fixed-length" and "non-register variable-length" types. The register types are: Int, Short, Byte, Char, Bits, Bool, Asm, Ref anything, and unions of these; non-register fixed-length types are: arrays, structures containing no ..., and unions of anything so far; and non-register variable-length types are: String, Data, Struct with ..., and unions not so far mentioned.
In fact, not all the checking that would be desirable can be done, since DefMod deals with only one file at a time.
The reasons for the distinctions are (a) that only register types may be arguments of SWI calls; (b) special treatment is given to structures whose last component is a repeating fixed-length element, in the form of extra macros to deal with objects of those types.
The built-in types must be provided by the target language. For C, they are in the file "types.h", included by all headers.
Within unions only, the type Void is allowed, signifying that the union may be "empty".
Contains the registers needed on input, and produced on output, by each SWI the module defines. For details of how the algorithm for producing the APCS veneers works, see the section APCS to SWI. Registers may be specified as
The two forms
Rx = .Ref Thing: thing
(Rx contains a pointer to a Thing called thing) and
Rx -> Thing: thing
(Rx points to a Thing called thing) are closely related: the difference is one of intent only. The second form is used when the argument must be valid on input; so the SWI is accepting a value of type Thing as an argument, represented by a pointer to it ("input" arguments); the first form is used when the value is not present, but the SWI will fill it in ("output" arguments). (A third form of syntax could be provided for "update" arguments, but this has not been done.) In C, the first form generates an ordinary pointer, the second a pointer-to-constant.
The .swi file contains the whole of the module interface. This includes modules SWI's, structures and constants, as expected; but also other resources defined by the module: service calls, vectors, error numbers, upcalls, Wimp messages (numbers and structures), events, etc. The vector, upcall and service entries are useful when making the call, typically done within the module rather than by a client. Even so, they are part of the module interface and logically belong in the interface file.
We assume that a non-x form will only be called in user mode: therefore, no attempt is made to save LR over the SWI instruction.
The output arguments are not written if a SWI fails.
The case of PSR flags being required on input is not supported. The only two calls where this is necessary are RemV and CnpV, which are obsolescent anyway.
If a call has no output arguments, and exactly one input argument which is a pointer to an unnamed structure with no ... part, then the structure elements are passed in in separate registers. See Wimp_SetIconState for an example.
If a SWI call happens also to be APCS-compliant, this information can be passed to the compiler, which can then generate an inline SWI instruction, by using the __swi() directive provided with ARM C release 5. To disable this feature for use with earlier or non-ARM compilers (e.g., CFront) requires a header file containing the lines
#ifdef __swi #undef __swi #define __swi(x) extern #endif
and the -D__swi compiler flag must be provided when using the header files. "Types.h" contains these lines.
In order to generate correct code, the width of all types used for output needs to be known. (Bytes must be stored with byte-store instructions.) In order to avoid having to read all NEEDS files, a separate list of byte-wide types must be provided. All other undefined types will be assumed to be register-wide, and a warning will be given. For OSLib, the byte-wide file is
Font_F OS_Action OS_F OS_GCOL OS_Tint Wimp_Colour
There is no support for 2-byte quantities on output.
"APCS to SWI" is what DefMod does when generating library files: it generates a veneer that assumes the C function has been called via APCS (in other words, the first 4 arguments are in R0, ..., R3, and the rest are on the stack), and sets the registers up as they should be for calling the SWI; that calls the SWI; and that then puts all the registers back where they should be for the APCS-conformant exit conditions (result in R0, other output values written to the addresses supplied on input).
This section describes how it does it.
To simplify the discussion, we refer to the registers by 2 sets of names. Considered as input to and output from the SWI, we call them R0, ..., R9; considered as APCS entry registers, we call them A1, ..., A4 (the "argument registers") and V1, ..., V6 (the "variable registers"); also, when considered as the APCS result register, we call R0 just R. The remaining 6 registers are always called SL, FP, IP, SP, LR, PC.
Let i be the number of registers provided on input, and let the registers be I0, ..., Ii-1; let o be the number of results required, and let the registers be O0, ..., Oo-1; let c be the number of registers corrupted, and let the registers be C0, ..., Cc-1; let k be the number of registers to be loaded with constants, and let the registers be K0, ..., Kk-1. Also, let f be 1 if flags are to be supplied on output, 0 if not.
Recall that on entry
The 1st argument | is in | R0 (A1) | |
The 2nd argument | is in | R1 (A2) | |
The 3rd argument | is in | R2 (A3) | |
The 4th argument | is in | R3 (A4) | |
The ith argument | is at | [SP, #4*(i-4)] | (i > 4) |
So on entry, RI0, ..., RIi-1 must be copied from the 0th, ..., (i-1)th arguments and RK0, ..., RKk-1 must be set to their values; and on exit,
If V is set | R must be set to an error block pointer (and V cleared) |
If V is clear | RO0, ..., ROo-1 must be copied to (the addresses in) the ith, ..., (i+o-1)th arguments; and if flags are required, they must be written to (the address in) the (i+o)th argument, and R cleared. |
Consider those variable registers V which will have to be preserved by this whole function: these are the ones that APCS requires to be preserved which we will be using ourselves, or which the SWI corrupts:
V = {4 < r < 10: there is an x such that r = Ix or r = Ox or r = Cx or r = Kx}
Also consider those registers A which are going to have to be saved over the call, because they contain addresses to be used for output. These are those of the ith, ..., (i+o+f-1)th arguments which are passed in R0, ..., R3:
A = {0 < r < 4: i < r < i+sup(inf(o+f,4)-i,0)}
Very easy:
;keep current SP safe---it points at the tail of the argument list MOV IP, SP ;save registers that need it over the call (SP -= 4*|V|) STMFD SP!, {V} ;save registers that contain output addresses (SP -= 4*|A|) STMFD SP!, {A} ;load registers for SWI that are in the argument tail LDM IP, {I4, ..., I(i - 1)} ;load registers for SWI that are in registers already MOV I3, A3 MOV I2, A2 MOV I1, A1 MOV I0, A0 ;set up constants MOV K(k - 1), whatever ... MOV K0, whatever
(In fact, STMFD SP!, {V, A} will do rather than the two instructions above.)
After all this,
[SP, #4|A|+4|V|] | contains | saved arguments (as set up by APCS) | |
[SP, #4|A|] | contains | saved variables (saved by us) | |
[SP] | contains | saved output addresses (also saved by us where not already saved by APCS) |
In fact, 2 variants are possible: first, if i < 4, we do not need IP before the SWI is called, so we can use it to save LR in. After the SWI, LR is corrupted anyway, so we can use it as we see fit. Second, if i > 4, we stack LR along with V, A. In the first case, on exit we have to do MOVS PC, IP (or MOV PC, IP for a 32-bit APCS). In the second, we just add PC to the list of registers to be restored on return.
;do the call SWI (swi)
Harder, though the V-set case is easy:
;do error return BVS exit
If V is clear, we have to retrieve the addresses passed in the (i+1)th, ..., (i+o-1)th arguments. These have been saved in 2 different places: argument i+x is at [SP, #4x] (i+x < 4), or at [SP, #4|V|+4|A|+4*(i+x-4)] (otherwise).
Initially, assume only that i > 4:
;get address for first argument LDR IP, [SP, #4*|V| + 4|A| + 4*(i - 4)] STR O0, [IP] ... repeat for other arguments ... ;get address for last argument LDR IP, [SP, #4*|V| + 4|A| + 4*((i + o - 1) - 4)] STR O(o - 1), [IP] ;if flags are required, do them too LDR IP, [SP, #4*|V| + 4|A| + 4*((i + o) - 4)] STR PC, [IP]
In fact, it may be the case that i+o+f-1 < 4. In this case, we have to replace any
LDR IP, [SP, #4*|A| + 4|S| + 4*((i + x) - 4)] STR O(x), [IP]
sequences for which i+x < 4 by sequences that go
LDR IP, [SP, #4*x] STR O(x), [IP]
where [SP, #4x] is the value that R(i+x) had on entry to the code, as stacked at the beginning.
If any of the output addresses were in registers that have been preserved, we do not need to reload them from memory. And we can supply an extra (very useful!) facility by checking for NULL pointers before writing to them.
There is one trick which is missed: we could use registers which are preserved by the call, but which we do not need to set to any particular value, to keep addresses in. This is left as an exercise for the reader. :-)
Restore everthing to its initial state:
MOV R, #0 exit ;skip over saved output addresses ADD SP, SP, 4|A| ;restore saved variables LDMFD SP!, {V} MOV PC, LR
A piece of cake!
The DefMod file has its own set of types, which must be mapped to C types. The match is close, but DefMod allows structure types with arbitrarily repeated final members. These are not representable with standard C, but we use knowledge of how all ARM C compilers work to generate some macros that help with these.
To convert (CVT) a type from the DefMod form to the C form,
Int | int |
Short | short |
Byte | unsigned char (is also byte) |
Char | char |
Bits | unsigned int (is also bits) |
Bool | int (is also osbool) |
Asm | asm_routine |
String | char |
Data | unsigned char (is also byte) |
Ref type | CVT(type) * |
Struct (..., type, ...} | struct {..., CVT(type), ...} |
Union (..., type, ...} | union {..., CVT(type), ...} |
[const] type | CVT(type) [VAL(const)] |
id | Convert_To_Extern (id) |
and in writing prototypes
= type | becomes | CVT(type) on input, CVT(type) * on output |
-> type | becomes | CVT(type) const * on input, CVT(type) ** on output |
# num | disappears | |
| type | becomes | CVT(type) |
? | disappears | |
FLAGS | becomes | unsigned * (output only) |
DefMod works by reading the interface file using a Yacc-generated parser derived and producing an internal form of the data in memory; it then emits this data in the required form. It is not written with speed or low memory-use in mind, but rather with robustness, correctness and ease of coding:
The parser uses string-valued variables for various purposes. Rather than construct some objects on the heap with malloc(), I have simply used a Yacc object big enough to hold a string of the largest possible length N. In combination with the point above, this means that building up a string of length l involves lN byte-copies.
There is a small bootstrapping problem: DefMod is actually a client of OSLib. In order to build DefMod, there is therefore an implementation of the parts of OSLib that DefMod needs, as macros (using _swix()). This is called SWILib. In principal, these could now be replaced with the output of DefMod -l, but this would be to introduce a potentially lethal feedback loop.
Yacc requires an input file containing the complete grammar with C code to apply at each reduction. Here we have only the grammar itself, with rules derived from the conventions above (see Syntax) deleted.
file: ws decl_SERIES_OPTION; decl: title_decl | author_decl | needs_decl | const_decl | type_decl | swi_decl; title_decl: TITLE ID DESCRIPTION_OPTION; author_decl: AUTHOR DESCRIPTION; needs_decl: NEEDS needs_LIST; needs: ID; const_decl: CONST const_defn_LIST; const_defn: ID EQUALS type COLON const DESCRIPTION_OPTION; const: NUM | ID; type_decl: TYPE type_defn_LIST; type_defn: ID DESCRIPTION_OPTION | ID EQUALS type DESCRIPTION_OPTION; base_type: COLON ID type: INT | SHORT | BYTE | CHAR | BITS | BOOL | REF type | STRING | ASM | DATA | STRUCT base_type_OPTION OPEN typed_var_LIST ellipsis_OPTION CLOSE | UNION OPEN toided_var_LIST CLOSE | SUB const BUS type | ID; toid: type | VOID; typed_var: type COLON ID DESCRIPTION_OPTION; toided_var: toid COLON ID DESCRIPTION_OPTION; swi_decl: SWI swi_defn_LIST; swi_defn: ID EQUALS swi; swi: OPEN number_part condition_part_OPTION CLOSE; number_part: NUMBER NUM description_OPTION; condition_part: entry_part | entry_part exit_part | entry_part absent_part | exit_part | absent_part; entry_part: COMMA ENTRY OPEN entry_condition_LIST CLOSE; exit_part: COMMA EXIT OPEN exit_condition_LIST CLOSE; absent_part: COMMA ABSENT; entry_condition: REG CONTAINS typed_var | REG REFERENCES typed_var | REG CONSTANT NUM description_OPTION | REG DISJOINS typed_var | REG CONJOINS typed_var | REG ADDS typed_var | REG EXCLUSIVELY_DISJOINS typed_var | FLAGS; exit_condition: REG pling_OPTION CONTAINS typed_var | REG pling_OPTION REFERENCES typed_var | REG CORRUPTED | REG PLING | FLAGS pling_OPTION; description: DESCRIPTION | STAR; ws: ws_item_SEQUENCE_OPTION; nl: '\n' | '\r'; space: spacechar | nl; ws_item: space | comment; comment: '/' '/' commentchar_SEQUENCE_OPTION nl; TITLE: t i t l e ws; AUTHOR: a u t h o r ws; NEEDS: n e e d s ws; CONST: c o n s t ws; TYPE: t y p e ws; SWI: s w i ws; NUMBER: n u m b e r ws; ENTRY: e n t r y ws; EXIT: e x i t ws; ABSENT: a b s e n t ws; FLAGS: f l a g s ws; CONTAINS: '=' ws; REFERENCES: '-' '>' ws; CONSTANT: '#' ws; DISJOINS: '|' ws; CONJOINS: '&' ws; ADDS: '+' ws; EXCLUSIVELY_DISJOINS: '^' ws; CORRUPTED: '?' ws; STAR: '*' ws; PLING: '!' ws; INT: '.' i n t ws; SHORT: '.' s h o r t ws; BYTE: '.' b y t e ws; CHAR: '.' c h a r ws; BITS: '.' b i t s ws; BOOL: '.' b o o l ws; DATA: '.' d a t a ws; VOID: '.' v o i d ws; STRING: '.' s t r i n g ws; ASM: '.' a s m ws; STRUCT: '.' s t r u c t ws; UNION: '.' u n i o n ws; REF: '.' r e f ws; ELLIPSIS: '.' '.' '.' ws; SEMICOLON: ';' ws; COMMA: ',' ws; EQUALS: '=' ws; OPEN: '(' ws; CLOSE: ')' ws; COLON: ':' ws; SUB: '[' ws; BUS: ']' ws; ID: id_start id_cont_SEQUENCE_OPTION ws; NUM: num ws; REG: r digit ws; DESCRIPTION: '"' wordchar_SEQUENCE word_SEQUENCE_OPTION '"' ws; word: space_SEQUENCE wordchar_SEQUENCE; wordchar: simplechar | '\\' | '\''; letter: a | b | c | d | e | f | g | h | i | j | k | l | m | n | o | p | q | r | s | t | u | v | w | x | y | z; bit: '0' | '1'; digit: bit | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'; hexit: digit | a | b | c | d | e | f; id_start: letter; id_cont: letter | digit | '_'; num: dec_num | hex_num | bin_num | char_num; dec_num: digit_SEQUENCE | '-' digit_SEQUENCE; hex_num: '0' x hexit_SEQUENCE | '&' hexit_SEQUENCE; bin_num: '0' b bit_SEQUENCE | '%' bit_SEQUENCE; char_num: '\'' numchars '\''; numchars: numchar | numchar numchar | numchar numchar numchar | numchar numchar numchar numchar; numchar: simplechar | compoundchar | spacechar | '"'; commentchar: simplechar | spacechar | '\\' | '"' | '\''; spacechar: ' ' | '\xA0' | '\t'; simplechar: letter | digit | '!' | '#' | '$' | '%' | '&' | '(' | ')' | '*' | '+' | ',' | '-' | '.' | '/' | ':' | ';' | '<' | '=' | '>' | '?' | '@' | '[' | ']' | '^' | '_' | '`' | ' | '|' | '}' | '~' | '\x8C' | '\x8D' | '\x8E' | '\x8F' | '\x90' | '\x91' | '\x92' | '\x93' | '\x94' | '\x95' | '\x96' | '\x97' | '\x98' | '\x99' | '\x9C' | '\x9D' | '\xA1' | '\xA2' | '\xA3' | '\xA4' | '\xA5' | '\xA6' | '\xA7' | '\xA8' | '\xA9' | '\xAA' | '\xAB' | '\xAC' | '\xAD' | '\xAE' | '\xAF' | '\xB0' | '\xB1' | '\xB9' | '\xB2' | '\xB3' | '\xB4' | '\xB5' | '\xB6' | '\xB7' | '\xB8' | '\xBA' | '\xBB' | '\xBC' | '\xBD' | '\xBE' | '\xBF' | '\xD7' | '\xF7'; compoundchar: '\\' escapedchar | '\\' x hexit hexit; escapedchar: '\'' | '"' | '\\' | n | '0';
TITLE ColourPicker; NEEDS OS, Wimp; CONST //Error numbers Error_ColourPickerUninit = .Bits: &20D00, Error_ColourPickerBadModel = .Bits: &20D01, Error_ColourPickerBadHandle = .Bits: &20D02, Error_ColourPickerBadFlags = .Bits: &20D03, Error_ColourPickerInUse = .Bits: &20D04, Error_ColourPickerModelInUse = .Bits: &20D05, Error_ColourPickerBadReason = .Bits: &20D06; CONST //Colour model entry numbers ColourPicker_EntryDialogueStarting = .Int: 0, ColourPicker_EntryDialogueFinishing = .Int: 1, ColourPicker_EntryRedrawArea = .Int: 2, ColourPicker_EntryUpdateArea = .Int: 3, ColourPicker_EntryReadValues = .Int: 4, ColourPicker_EntrySetValues = .Int: 5, ColourPicker_EntryProcessEvent = .Int: 6, ColourPicker_EntrySetColour = .Int: 7, //more here ... ColourPicker_EntryLimit = .Int: 8; TYPE ColourPicker_D, ColourPicker_Colour = .Struct ( OS_Colour: colour, .Int: size, //of the 'info' array .Int: info ... ); TYPE ColourPicker_DialogueFlags = .Bits; CONST //Flag bits for ColourPicker_Dialogue ColourPicker_DialogueOffersTransparent = ColourPicker_DialogueFlags: %1, ColourPicker_DialogueTransparent = ColourPicker_DialogueFlags: %10, ColourPicker_DialogueType = ColourPicker_DialogueFlags: %1100, ColourPicker_DialogueTypeShift = .Int: 2, ColourPicker_DialogueTypeNever = .Bits: 0, ColourPicker_DialogueTypeClick = .Bits: 1, ColourPicker_DialogueTypeClickDrag = .Bits: 2, ColourPicker_DialogueIgnoreHelp = ColourPicker_DialogueFlags: %10000, ColourPicker_DialogueIgnoreKeyPressed = ColourPicker_DialogueFlags: %100000; TYPE ColourPicker_Dialogue = .Struct ( ColourPicker_DialogueFlags: flags, .Ref .String: title, OS_Box: visible, .Int: xscroll, .Int: yscroll, OS_Colour: colour, .Int: size, //of the 'info' array .Int: info ... ); TYPE ColourPicker_ModelFlags = .Bits; TYPE ColourPicker_Model = .Struct ( ColourPicker_ModelFlags: flags, .Ref .String: name, .Ref .String: description, .Int: info_size, OS_Coord: pane_size, [ColourPicker_EntryLimit] .Ref .Asm: entries ); CONST //Colour model numbers (for 'size') ColourPicker_ModelSizeRGB = .Int: 16, ColourPicker_ModelSizeCMYK = .Int: 20, ColourPicker_ModelSizeHSV = .Int: 16; CONST //Colour model numbers (for 'info + 0') ColourPicker_ModelRGB = .Int: 0, ColourPicker_ModelCMYK = .Int: 1, ColourPicker_ModelHSV = .Int: 2; CONST //WIMP message numbers Message_ColourPickerColourChoice = .Bits: &47700, Message_ColourPickerColourChanged = .Bits: &47701, Message_ColourPickerCloseDialogueRequest = .Bits: &47702, Message_ColourPickerOpenParentRequest = .Bits: &47703, Message_ColourPickerResetColourRequest = .Bits: &47704; CONST //for the various messages ColourPicker_ColourTransparent = ColourPicker_ColourFlags: %1, ColourPicker_ColourDragging = ColourPicker_ColourFlags: %10; TYPE //Types for message blocks ColourPicker_MessageColourChoice = .Struct ( ColourPicker_D: d, ColourPicker_ColourFlags: flags, OS_Colour: colour, .Int: size, //of the 'info' array (in bytes !) .Int: info ... ), ColourPicker_MessageColourChanged = .Struct ( ColourPicker_D: d, ColourPicker_ColourFlags: flags, OS_Colour: colour, .Int: size, //of the 'info' array .Int: info ... ), ColourPicker_MessageOpenParentRequest = .Struct ( ColourPicker_D: d ), ColourPicker_MessageCloseDialogueRequest = .Struct ( ColourPicker_D: d ), ColourPicker_MessageResetColourRequest = .Struct ( ColourPicker_D: d ); SWI ColourPicker_RegisterModel = ( NUMBER &47700 "For internal use only", ENTRY ( R0 = .Int: model_no, R1 -> ColourPicker_Model: model, R2 = .Ref Void: workspace ) ), ColourPicker_DeregisterModel = ( NUMBER &47701 "For internal use only", ENTRY ( R0 = .Int: model_no ) ); TYPE ColourPicker_OpenFlags = .Bits; CONST //for ColourPicker_OpenDialogue ColourPicker_OpenTransient = ColourPicker_OpenFlags: %1, ColourPicker_OpenSubMenu = ColourPicker_OpenFlags: %10, //only relevant if Transient ColourPicker_OpenToolbox = ColourPicker_OpenFlags: %10; //only relevant if Permanent SWI ColourPicker_OpenDialogue = ( NUMBER &47702 "Creates and opens a colour picker dialogue", ENTRY ( R0 = ColourPicker_OpenFlags: flags, R1 -> ColourPicker_Dialogue: dialogue ), EXIT ( R0! = ColourPicker_D: d, R1 = Wimp_W: w ) ); TYPE ColourPicker_CloseFlags = .Bits; SWI ColourPicker_CloseDialogue = ( NUMBER &47703 "Closes a colour picker dialogue which is in progress", ENTRY ( R0 = ColourPicker_CloseFlags: flags, R1 = ColourPicker_D: d ) ); TYPE ColourPicker_UpdateFlags = .Bits; CONST //for ColourPicker_UpdateDialogue ColourPicker_UpdateOffersTransparent = ColourPicker_UpdateFlags: %1, ColourPicker_UpdateTransparent = ColourPicker_UpdateFlags: %10, ColourPicker_UpdateType = ColourPicker_UpdateFlags: %100, ColourPicker_UpdateVisible = ColourPicker_UpdateFlags: %1000, ColourPicker_UpdateScroll = ColourPicker_UpdateFlags: %10000, ColourPicker_UpdateTitle = ColourPicker_UpdateFlags: %100000, ColourPicker_UpdateColour = ColourPicker_UpdateFlags: %1000000, ColourPicker_UpdateModel = ColourPicker_UpdateFlags: %10000000, ColourPicker_UpdateIgnoreHelp = ColourPicker_UpdateFlags: %100000000, ColourPicker_UpdateIgnoreKeyPressed = ColourPicker_UpdateFlags: %1000000000; SWI ColourPicker_UpdateDialogue = ( NUMBER &47704 "Updates some or all of the contents of a colour picker dialogue", ENTRY ( R0 = ColourPicker_UpdateFlags: flags, R1 = ColourPicker_D: d, R2 -> ColourPicker_Dialogue: dialogue ) ); TYPE ColourPicker_ReadFlags = .Bits; SWI ColourPicker_ReadDialogue = ( NUMBER &47705 "Reads the current state of a colour picker dialogue without changing it", ENTRY ( R0 = ColourPicker_ReadFlags: flags, R1 = ColourPicker_D: d, R2 = .Ref ColourPicker_Dialogue: dialogue ), EXIT ( R1 = Wimp_W: w, R2 = .Int: size ) ); TYPE ColourPicker_SetFlags = .Bits; SWI ColourPicker_SetColour = ( NUMBER &47706 "Reserved for future expansion", ENTRY ( R0 = ColourPicker_SetFlags: flags, R1 -> ColourPicker_Colour: colour ) ); TYPE ColourPicker_HelpFlags = .Bits; SWI ColourPicker_HelpReply = ( NUMBER &47707 "Makes a colour picker respond to a Message_HelpRequest with its own help text", ENTRY ( R0 = ColourPicker_HelpFlags: flags, R1 -> Wimp_Message: help_request ) ); SWI ColourPicker_ModelSWI = (NUMBER &47708 "For internal use only", ABSENT), ColourPickerModelSWI_ColourChanged = ( NUMBER &47708, ENTRY ( R0 # 0 "Informs the front end to send a message to the client, if required", R1 -> ColourPicker_Colour: colour ) ), //Cause the Picker to send a message to the application. if required. ColourPickerModelSWI_ColourChangedByDragging = ( NUMBER &47708, ENTRY ( R0 # 1 "Informs the front end to send a dragging message to the client, if required", R1 -> ColourPicker_Colour: colour ) ), ColourPickerModelSWI_ClaimEvent = ( NUMBER &47708, ENTRY ( R0 # 2 "Informs the front end that the back end wants an event type", R1 = .Int: event, R2 -> ColourPicker_Colour: colour ) ), ColourPickerModelSWI_ReleaseEvent = ( NUMBER &47708, ENTRY ( R0 # 3 "Informs the front end that the back end no longer wants an event type", R1 = .Int: event, R2 -> ColourPicker_Colour: colour ) ), ColourPickerModelSWI_ProcessKey = ( NUMBER &47708, ENTRY ( R0 # 4 "Passes an unhandled key press on to the front end", R1 = .Int: c, R2 -> ColourPicker_Colour: colour ) ); SWI Service_ColourPickerLoaded = ( NUMBER 0x30, ENTRY ( R1 # &93 "For internal use only", R2 -> .Asm: loaded_service, R3 = .Ref Void: workspace ) )
Could have an UPDATE category, optional between ENTRY and EXIT categories. This would allow 1 argument to be saved on calls that use a value and then update it.
Could have more knowledge about buffers and buffer lengths, and provide a more consistent interface. (SWI's that fill buffers have two arguments, usually called buffer and size, and may return one of: a pointer to the next free byte (called end); a number of bytes written (called used); or a count of buffer bytes not used (called spare). More consistency could be derived by having a cleverer veneer.
Alternatively (or additionally), these calls couild always return the pointer to the filled-in buffer, so you could nest calls as with C string functions.
It would be good to have support for enum's, so you could have cross-references generated in the help files from the type name to allowable values of that type. We could also have support for sets of enumerated types.
Some SWI's have two or more registers that are equally likely to be needed as results. Could they be persuaded to return a structure-valued result? Under C release 5, it's easy for the non-x case, but it would have to work for all cases to be useful.
More info in C help (register <=> arg mappings, other notes).
Put the text for x and non-x forms into the same help page, indexed by both words.
Modify everything in sight so that when an array is sized by a constant, the manifest makes it through to the help text, highlighted so you can find its value.
Use registers that are otherwise unused by the veneer code as an alternative to the stack in order to save on memory accesses.
1st Jul 1992 | J R C | Started. |
5th Jul 1992 | J R C | Added Handling of FLAGS arguments, handling of constant arguments, handling of SWI's that corrupt random registers. |
6th Jul 1992 | J R C | Changed the way reason codes are handled, implemented them. |
7th Jul 1992 | J R C | Save LR over calls, in case we are in SVC mode. |
10th Jul 1992 | J R C | Added type conversion notes. |
J R C | Handling of BLOCK arguments. (If there is no EXIT clause, and the last ENTRY argument is of the form Rx -> .Struct ... then the constructed interface assumes that the structure is passed by value, i e, its fields are passed in order. See wimp_set_icon_state() for an instance of this.) | |
24th Oct 1994 | J R C | Updated for release to those that ask. |
20th Jul 1997 | J R C | Updated for general release on http://www.doves.demon.co.uk. |
26th Mar 1999 | T V | Amended definition of conversion types for String and Data for Free OSLib 5.4. |
4th Mar 2000 | T J H | Added base types for structures to the grammar definition. |