This chapter describes the functions which permit LyME to call arbitrary machine code. This may be useful to access features which are not implemented directly in LyME, such as direct calls to Palm OS functions or support for hardware.
Warning 1: Calling machine code is potentially dangerous. It easily leads to crashes which may need soft or hard resets. You should backup your device first. The use of an emulator, if available, should be considered.
Warning 2: Presenting Palm device hardware and software architecture is far beyond the scope of this reference manual.
Warning 3: Functions described in this chapter are experimental and subject to change without notice.
To support calls to machine code, a new data type is provided, binarydata. Variables of this type contain a vector of 16-bit words. Functions are provided to convert a string of hexadecimal digits or a vector of numbers to binarydata, binarydata to a vector of integer numbers or a string of bytes, and to execute as a machine-code subroutine the contents of binarydata using another binarydata as data.
As an example, we will develop a subroutine which fills some binarydata with the numbers n, n-1, ..., 2, 1. Before the subroutine is executed, the following registers are set:
Register | Value |
---|---|
A5 | Beginning of the data |
D0 | Length of the data in words |
Here is the code of the subroutine:
moveq.w #0, d1 loop: tst.w d0 beq end move.w d0, (a5,d1) subq.w #1, d0 addq.w #2, d1 bra loop end: rts
The data offset of the next word to set is stored in D1. As long as D0 is not 0, D0 is stored in the data at offset D1 and decremented, and D1 is incremented by 2. The subroutine ends with rts. Note that absolute addresses must be avoided; only relative jumps must be used.
An assembler converts this assembly code to the following machine code:
72004A40670A3B8010005340544160F24E75
To store this code in a binarydata variable, we enter in LyME
> code = binarydata('72004A40670A3B8010005340544160F24E75');
To execute this code with data initialized to 10 null 16-bit words, we use feval:
> dataout = feval(code, binarydata(zeros(10, 1)));
The result can be converted to a vector of numbers and displayed:
> double(dataout) 10 9 8 7 6 5 4 3 2 1
Words in binary data can also be accessed with subscripts, which must be integer values based on 0. In subscript expressions, beginning gives 0 (the first valid index) and end gives the number of words minus one. Logical values are not supported.
> dataout(end-2:end) 3 2 1 > dataout(0:2) = 555; > dataout(0:5) 555 555 555 7 6 5
Create binary code or data.
d = binarydata(vec) d = binarydata('hexa')
binarydata(vec) creates a block of binary data from the elements of vector vec converted to words (16-bits values). If vec is a vector of class double, its elements converted directly to 16-bit words. If it is a vector of integer numbers, the conversion takes their size into account, with the most-significant word first: for instance, binarydata(uint8([0,0,1,0]), binarydata(int16([0,256]), and binarydata(uint32(256)) all produce the same binary data containing the 16-bit words 0 and 256.
binarydata(str) creates a block of binary data whose value is given by the string of hexadecimal digits str. The length of str must be a multiple of 4, so that the block has an integer number of words.
double, uint8, uint16, uint32, int8, int16, int32, char, feval
Convert binary data to a string of characters.
str = char(d)
char(d) converts binary data to a a string of characters. Each character corresponds to one byte.
binarydata, double, uint8, uint16, uint32, int8, int16, int32
Convert binary data to a vector of double.
vec = double(d)
double(d) converts binary data to a column vector of double numbers.
char, uint8, uint16, uint32, int8, int16, int32, binarydata
Call machine language in binary data.
feval(code) dataout = feval(code, datain)
feval(code) calls code in binary data code with the following instructions:
movea #0, a5 clr.w d0 jsr code
feval(code,data) calls code in binary data code with the following instructions:
lea (data), a5 move.l dataSize, d0 jsr code
The binary data data (possibly modified) is returned. In both cases, the code should be a subroutine and end with rts.
feval has the potential of crashing LyME if its arguments do not correspond to valid code and data.
Convert binary data to a vector of integer numbers.
vec = int8(d) vec = int16(d) vec = int32(d) vec = uint8(d) vec = uint16(d) vec = uint32(d)
int8(d), int16(d), and int32(d) convert binary data d to a column vector of signed integer numbers of size 8, 16, or 32 respectively. uint8(d), uint16(d), and uint32(d) convert binary data d to a column vector of unsigned integer numbers of size 8, 16, or 32 respectively. Each 16-bit word in the binary data d corresponds to 2 8-bit integers, 1 16-bit integer, or half a 32-bit integer.
Number of words in a binary data object.
n = length(d)
length(d) gives the number of words in a binary data object.
Call native (ARM) machine language in binary data.
dataout = pcenativecall(code, data) (dataout, result) = pcenativecall(code, datain)
pcenativecall(code, datain) calls native ARM code in binary data code with an argument pointing to datain. It returns the same block of memory corresponding to datain, possibly modified by the execution of the code. This call is available only on handhelds with an ARM micro-processor. It relies on Palm OS function PceNativeCall.
The native function should have the following prototype, where datain points to the argument of pcenativecall:
unsigned long fun(const void *emulStateP, void *datain, Call68KFuncType *call68KFuncP);
Please refer to Palm OS documentation at http://www.palmos.com for more informations.
pcenativecall has the potential of crashing LyME if its arguments do not correspond to valid code and data.
binarydata, feval, processorname
Get a word anywhere in memory.
value = peek(address)
peek(address) reads a short word (two bytes) of memory at the address specified, which must be even. Several words may be read in one command if the argument is a vector or a matrix.
Store a word anywhere in memory.
poke(address, value)
poke(address,value) stores a short word (two bytes) of memory at the address specified, which must be even. Several words may be stored in one command if the arguments are vectors or matrices. The size both arguments must be the same, or the second argument value must be a scalar.
Get the name of the microprocessor.
shortname = processorname (shortname, fullname) = processorname
processorname gets the name of the microprocessor of the handheld. The first output argument is the short name, such as '68328' or 'ARM720T'; the second output argument, if it exists, is the full name, such as 'Motorola 68328 (Dragonball)' or 'ARM 720T'.