home *** CD-ROM | disk | FTP | other *** search
/ Acorn User 10 / AU_CD10.iso / Updates / Perl / Non-RPC / !Perl / riscos / RISCOS / SWI.pm < prev    next >
Text File  |  1998-07-26  |  10KB  |  287 lines

  1. package RISCOS::SWI;
  2.  
  3. require Exporter;
  4. use Carp;
  5. use strict;
  6.  
  7. use vars qw ($VERSION @ISA @EXPORT @EXPORT_OK @in @out $string2num $num2string
  8.          $num2string_mask $string2num_mask);
  9. $VERSION = 0.07;
  10. @ISA = qw(Exporter);
  11. @EXPORT = qw(swi swix kernelswi regmask SWINumberFromString SWINumberToString);
  12. @EXPORT_OK = qw(&V_Flag &C_Flag &Z_Flag &N_Flag &XOS_Bit);
  13.  
  14. # 0.04
  15. # Tidied up error handling on SWINumberToString (ie it can now return undef)
  16. # 0.05
  17. # Prototypes
  18. # Can now return register 15 (but not 'PC' - hmm).
  19. # Can do block
  20. # 0.06
  21. # Added SWI number in hex for SWINumberToString if SWI is 'User' or 'XUser'
  22. # and decode on OS_WriteI
  23. # 0.07
  24. # foreach rather than shift in regmask
  25.  
  26. for my $i (0..9) { $in[$i] = 1<<$i; $out[$i] = 1<<(31-$i); }
  27. $out[15] = 1 << 21;    # PC out is hardcoded
  28.  
  29. sub V_Flag ()    {return 1 << 28;}
  30. sub C_Flag ()    {return 1 << 29;}
  31. sub Z_Flag ()    {return 1 << 30;}
  32. sub N_Flag ()    {return 1 << 31;}
  33. sub XOS_Bit ()    {return 1 << 17;}
  34.  
  35. sub regmask {
  36.     my $ir = shift;
  37.     my $or = shift;
  38.     my $block = shift;
  39.     my $mask = 0;
  40.     if (defined $ir) { foreach (@$ir) { $mask |= $in[$_]; } }
  41.     if (defined $or) { foreach (@$or) { $mask |= $out[$_]; } }
  42.     if (defined $block)
  43.     {
  44.         if ($block & 0xFFFFFFF0) {
  45.         carp "Block register $block out of range 0-15" if $^W;
  46.         $block &= 0xF;
  47.         }
  48.         $mask |= 1 << 11;
  49.         $mask |= $block << 12;
  50.     }
  51.     $mask;
  52. }
  53.  
  54. $string2num_mask = regmask ([1]);
  55. $_ = 'XOS_SWINumberFromString';        # Can't pass in a string constant
  56. $string2num =  swix ('XOS_SWINumberFromString', $string2num_mask, $_);
  57.  
  58. sub SWINumberFromString ($) {
  59.     my $name = shift;
  60.     if ($name =~ /^(X?)OS_WriteI\+(.+)/) {
  61.     my $base = $1 ? (1 << 17 + 256) : 256;
  62.     my $num = $2;
  63.     return $base + $num unless $num =~ /^"(.)"/;
  64.     return $base + ord $1;
  65.     } elsif ($name =~ /^X?User \((.+)\)$/) {
  66.     my $num = $2;
  67.     return ($num =~ /^&(.+)/) ? oct "0x$1" : $num;
  68.     }
  69.  
  70.     RISCOS::SWI::swix(57, $string2num_mask, $name);
  71. }
  72.  
  73. $num2string = SWINumberFromString ('XOS_SWINumberToString');
  74. $num2string_mask = regmask([0..2],[2]);
  75.  
  76. sub SWINumberToString ($) {
  77.     return undef unless defined (my $num = shift);
  78.     my $len = 'xxxx';
  79.     my $buffer = ' ' x 255;
  80.  
  81.     return undef
  82.       unless defined RISCOS::SWI::swix($num2string, $num2string_mask, 0+$num,
  83.                        $buffer, 255, $len);
  84.  
  85.     $len = unpack('i', $len) - 1;    # Interpret the result as an integer
  86.     $buffer = substr($buffer, 0, $len);
  87.     $buffer = sprintf "$buffer (&%06X)", $num if ($buffer =~ /^X?User$/);
  88.     $buffer;
  89. }
  90.  
  91. sub swi {
  92.     my $result = &swix;
  93.     croak (sprintf "Unexpected OS error number &%X: $^E", $^E)
  94.       unless defined $result;
  95.     0 + $result;            # To be consistent with perl5.001
  96. }
  97.  
  98. $num2string && $string2num;    # True if we got the SWIs
  99.  
  100. __END__
  101.  
  102. =head1 NAME
  103.  
  104. RISCOS::SWI -- perl interface to SWI calls
  105.  
  106. =head1 SYNOPSIS
  107.  
  108.     use RISCOS::SWI;
  109.     $number = RISCOS::SWI::swix ('OS_SWINumberFromString', regmask([1]), $name);
  110.     @regs = unpack 'I10', kernelswi ('OS_File', 5, $filename);
  111.  
  112. =head1 DESCRIPTION
  113.  
  114. This module provides a SWI interface for perl. There are two alternative
  115. interfaces supported - B<kernelswi> and B<swi>/B<swix>. Both take the SWI to
  116. call as the first parameter, which can be specified by name or number. Although
  117. calling a SWI by name makes for highly readable code, the name lookup itself
  118. often takes longer than the actual SWI, so for production code it is wise to
  119. perform the name lookup once at initialisation using C<SWINumberFromString> and
  120. cache the number in a variable.
  121.  
  122. C<kernelswi> and C<swix> both automatically call the C<X> (error returning)
  123. version of the SWI, return undefined on error and copy the error block number
  124. and message to C<$^E>. C<swi> calls C<swix>, but will terminate the script with
  125. the error number and message if an error occurs.
  126.  
  127. For both interfaces registers are initialised from perl variables according to
  128. the following rules:
  129.  
  130. =over 4
  131.  
  132. =item the undefined value is passed as zero
  133.  
  134. =item "numbers" are passed as integers
  135.  
  136. =item "strings" are passed as pointers to the strings - perl automatically adds
  137. a C<"\0"> at the end to create null terminated strings.
  138.  
  139. Overwriting the contents alters the variable's value - it is up to the script to
  140. ensure that the perl scalar value is made long enough before calling the SWI.
  141. Note also that B<string constants> are treated as B<read only> so attempting to
  142. call
  143.  
  144.     $number = RISCOS::SWI::swix ('OS_SWINumberFromString', regmask([1]),
  145.                  'OS_SWINumberFromString');
  146.  
  147. would cause a fatal runtime error.
  148.  
  149. =back
  150.  
  151. "strings" and "numbers" are in quotes because the internals rely on perl's flags
  152. to determine whether a scalar is a number or string. The trouble comes when perl
  153. has been implicitly converting between the two and thinks that the result of
  154. S<C<6*7> is C<"42">>, which it will try to pass in as a pointer to a string.
  155. The work around is to add zero to parameters that must be numeric, and
  156. concatenate C<''> to parameters that are strings:
  157.  
  158.     $number += 0;
  159.     
  160.     $string = "0";    # This may be interpreted as the number zero
  161.     kernelswi ($swi, 0, $string . '')        # Not now.
  162.  
  163. The latter is, to quote Paul Moore, "fairly obscure magic (deliberately
  164. invalidating the flag which says that the string has a valid numeric value, and
  165. then using the string before perl has a chance to notice that the numeric value
  166. is still OK), but works fine."
  167.  
  168. The two interfaces are both built into the perl binary and so are always
  169. available, with or without this module. They differ in the method of passing in
  170. and returning results from registers.
  171.  
  172. =over 4 
  173.  
  174. =item kernelswi <name>|<number>, [<R0 value>, [<R1 value], ...
  175.  
  176. is similar to the C library function of the same name. It takes as parameters
  177. the SWI to call and optionally up to 10 more values assigned to C<R0> - C<R9>
  178. in order. Unassigned registers have undefined values (B<not> zero, unlike
  179. C<BASIC>). If the SWI generates an error then undefined is returned, and C<$^E>
  180. is set to the error number and message from the error block (I<c.f.> C<$!>). If
  181. there is no error then C<kernelswi> returning a single scalar block of length
  182. 40, the packed return results from C<R0> - C<R9>. For example, these may be
  183. converted to an array of integers with code of the form
  184.  
  185.     @regs = unpack 'I10', $kernelswi_result;
  186.  
  187. =item B<swix> <name>|<number>, [<mask>, [<value> ...
  188.  
  189. is similar to the alternative C veneer written by Edward Nevill and Jonathan
  190. Roach and supplied with Acorn C versions 4 and later.
  191.  
  192. Like C<kernelswi>, S<swix> returns undefined and sets C<$^E> if an error is
  193. generated. If there is no error, S<swix> returns the contents of C<R0>
  194.  
  195. I<mask> is a bitmask that describes the interpretation to place on the remaining
  196. parameters. If it is omitted it is treated as zero (no parameters). Otherwise it
  197. is best generated by the C<regmask> function. I<mask> B<must> be numeric -
  198. string values are reserved and cause a fatal error at runtime.
  199.  
  200. =over 4
  201.  
  202. =item regmask <in>, [<out>, [<block>]]
  203.  
  204. I<in> and I<out> are references to arrays of register numbers to respectively
  205. pass B<in>to and B<out> from the SWI. If either is undefined it is treated as
  206. an empty array. Registers 0 to 9 can be passed in, 0 to 9 and 15 returned.
  207.  
  208. If present, I<block> is the number of register to set up to point to any
  209. remaining parameters "left over". This provides a convenient way of generating
  210. parameter blocks for SWIs such as C<Wimp_CreateWindow>.
  211.  
  212. =back
  213.  
  214. values follow in register number order - first values to pass in, then scalars
  215. in which the value of registers out are returned. The script must ensure that
  216. these scalars are at least 4 bytes long, as the assembler C<swix> veneer makes
  217. no checks.
  218.  
  219. Although this interface seems considerably more complex than C<kernelswi>, it
  220. does allow much greater flexibility in exactly which registers are wanted.
  221.  
  222. Integer results can be retrieved with code such as
  223.  
  224.     unpack('i', $len)
  225.  
  226. string results by dereferencing pointers
  227.  
  228.     unpack('p', $addr)
  229.  
  230. =item swi
  231.  
  232. calls C<swix>, returning C<R0 + 0> to ensure a number, or C<die>s with the
  233. numeric and string values of C<$^E> if there was an error.
  234.  
  235. =back
  236.  
  237. C<RISCOS::SWI> also provides conversion functions between SWI names and numbers,
  238. and symbolic constants for the 4 ARM flags and the OS 'X' bit.
  239.  
  240. =over 4
  241.  
  242. =item V_Flag
  243.  
  244. =item C_Flag
  245.  
  246. =item Z_Flag
  247.  
  248. =item N_Flag
  249.  
  250. return the bit corresponding to the position of flag in the C<PC/PSR>.
  251.  
  252. =item XOS_Bit
  253.  
  254. returns 0x20000 - which when set marks the error returning form of a SWI.
  255.  
  256. =item SWINumberToString <SWI number>
  257.  
  258. converts a SWI number to a name using the SWI C<OS_SWINumberToString>.
  259. Returns the name of the SWI, or undefined if there was an error. Unknown
  260. SWI numbers which the SWI C<OS_SWINumberToString> converts to 'C<User>'
  261. or 'C<XUser>' are returned as 'C<User (&C00FEE)>' or 'C<XUser (&0B100D)>'.
  262.  
  263. =item SWINumberFromString <SWI name>
  264.  
  265. provides a full inverse to C<SWINumberToString>. "User" SWIs described above
  266. are recognised, as are C<OS_WriteI> variants. Other SWIs numbers are
  267. converted using the SWI C<OS_SWINumberFromString>.
  268.  
  269. =back
  270.  
  271. =head1 BUGS
  272.  
  273. C<swix> doesn't automatically ensure that scalars for return values exist and
  274. are long enough. Additionally the current mask system doesn't allow the script
  275. to specify whether it wants a number, string or fixed length block to be
  276. returned, and let the perl internals convert and assign the return values
  277. automatically. String "masks" are reserved for this purpose.
  278.  
  279. =head1 AUTHOR
  280.  
  281. Nicholas Clark <F<nick@unfortu.net>>, based on the previous perl ports.
  282.  
  283. The C<swi> interface is C<syscall> from the perl 5.001 port. The C<kernelswi>
  284. interface is C<syscall> from the perl 3 port.
  285.  
  286. =cut
  287.