Google Groups no longer supports new usenet posts or subscriptions. Historical content remains viewable.
Dismiss

A faster way to delete all the icons in a window

115 views
Skip to the first unread message

Andrew Pullan

unread,
17 Aug 2003, 13:30:5917/08/2003
to
Hi All

Anyone know a fast way of deleting allthe icons in a window? Whe there are
several hundred icons. (if not several thousand)

Deleting them one at a time using Wimp_DeleteIcon takes for ever.

Deleting the window and recreating it is nice and quick. But it causes real
problem as the wimp moves the window arround when its reopened. The only way
round this is to open the window twice, forcing it to a specific place
everytime. But even this doesnt seem to work eveyrtime!!

Any other methods that I've not thought of?

--
Andrew J Pullan
For replies by Email please use my fullname :-)
Worse things happen in C.

Tony Houghton

unread,
17 Aug 2003, 13:53:2417/08/2003
to
In <a6c87e234c...@pudy.websterxl.co.uk>,
Andrew Pullan <a.pu...@zetnet.co.uk> wrote:

> Hi All
>
> Anyone know a fast way of deleting allthe icons in a window? Whe there are
> several hundred icons. (if not several thousand)
>
> Deleting them one at a time using Wimp_DeleteIcon takes for ever.
>
> Deleting the window and recreating it is nice and quick. But it causes real
> problem as the wimp moves the window arround when its reopened. The only way
> round this is to open the window twice, forcing it to a specific place
> everytime. But even this doesnt seem to work eveyrtime!!
>
> Any other methods that I've not thought of?

Don't create them in the first place and use Wimp_PlotIcon instead. I
wrote a Minewsweeper clone years ago and found the redraw was also much
faster with Wimp_PlotIcon drawing the cells than with real icons for
some reason.

--
Use Reply-To and DO NOT remove .nospam when replying

Andrew Pullan

unread,
17 Aug 2003, 15:11:0317/08/2003
to
On 17 Aug Tony Houghton wrote:

> In <a6c87e234c...@pudy.websterxl.co.uk>,
> Andrew Pullan <a.pu...@zetnet.co.uk> wrote:
>
> > Hi All
> >
> > Anyone know a fast way of deleting allthe icons in a window? Whe there are
> > several hundred icons. (if not several thousand)
> >
> > Deleting them one at a time using Wimp_DeleteIcon takes for ever.
> >
> > Deleting the window and recreating it is nice and quick. But it causes
> > real problem as the wimp moves the window arround when its reopened. The
> > only way round this is to open the window twice, forcing it to a specific
> > place everytime. But even this doesnt seem to work eveyrtime!!
> >
> > Any other methods that I've not thought of?

Should have said...

This is from Basic.

> Don't create them in the first place and use Wimp_PlotIcon instead.

Seem to remember trying this actually. For small numbers of icons where all
can be plotted every time then it was faster. When you get to 1000+ icons
it's a bit slow in basic, Especially when you have to work out which 'icons'
you need to draw first!

Another problem is that the rest of the code is based arround detecting
clicks on the icons. (In case you havent guessed this is WebsterXL I'm
talking about)

> I wrote a Minewsweeper clone years ago and found the redraw was also much
> faster with Wimp_PlotIcon drawing the cells than with real icons for some
> reason.

Snap! I found that with my Kye clone. It was unusable using real icons.

--
Andrew J Pullan
For replies by Email please put my middle initial in :-)
Computers are like air conditioners. They stop working when you open windows.

Justin Fletcher

unread,
17 Aug 2003, 16:25:5017/08/2003
to
On Sun, 17 Aug 2003, Andrew Pullan wrote:

> On 17 Aug Tony Houghton wrote:
>
> > In <a6c87e234c...@pudy.websterxl.co.uk>,
> > Andrew Pullan <a.pu...@zetnet.co.uk> wrote:
> >
> > > Hi All
> > >
> > > Anyone know a fast way of deleting allthe icons in a window? Whe there are
> > > several hundred icons. (if not several thousand)
> > >
> > > Deleting them one at a time using Wimp_DeleteIcon takes for ever.
> > >
> > > Deleting the window and recreating it is nice and quick. But it causes
> > > real problem as the wimp moves the window arround when its reopened. The
> > > only way round this is to open the window twice, forcing it to a specific
> > > place everytime. But even this doesnt seem to work eveyrtime!!
> > >
> > > Any other methods that I've not thought of?
>
> Should have said...
>
> This is from Basic.

Don't think it really makes a lot of difference what language you use; the
algorithms will be the same.

> > Don't create them in the first place and use Wimp_PlotIcon instead.
>
> Seem to remember trying this actually. For small numbers of icons where all
> can be plotted every time then it was faster. When you get to 1000+ icons
> it's a bit slow in basic, Especially when you have to work out which 'icons'
> you need to draw first!

Write up a chunk of assembler... or, better still - don't be surprised
when you find that your web browsers written in BASIC ends up slow :-)

> Another problem is that the rest of the code is based arround detecting
> clicks on the icons. (In case you havent guessed this is WebsterXL I'm
> talking about)

I'd be terrified if I had 100s of icons in a window, never mind thousands.
Neither the redraw, nor the click handling should be particularly painful
if you just use some simple logic around things.

How about partitioning your virtual work area into regions and having
separate lists of known positions for icons within each region. Regions of
'icons' of a couple of hundred OS units would be a simple proposition for
searching during redraw and for clicks.

Or, since a web browser is a implicitly a nested environment and
those regions are rectangular in shape, you can easily group by their
nesting - in fact for parts of the propgation of messages this is implicit
(IIRC).

Or using a binary tree to represent the vertical positions of the icons
(on the assumptions that almost all pages are taller than they are wide).

A (very brief) test I've just done to check how quickly you might be able
to test the positioning of regions in a list in BASIC with 1000 regions
has shown that this can be done relatively speedily. Using as a reference,
a lump of code from some time in the past that had 17 comparisons to
compare two rectangles I've produced the following test (which actually
only uses 14 comparisons because of BASIC line length limitations)...

[Create a simple list of 1001 regions]
>DIM head% 4
>!head%=0
>FORI=0TO1000:DIM new% 20:!new%=!head%:!head%=new%:N.

[traverse the entire list, performing comparisons on the regions to ensure
that we're exercising the list fully]
>p%=!head%
>t%=TIME:REP.:x%=(p%!4<p%!4)AND(p%!4<p%!4)AND(p%!4<p%!4)AND(p%!4<p%!4)AND(p%!4<p
%!4)AND(p%!4<p%!4)AND(p%!4<p%!4)AND(p%!4<p%!4)AND(p%!4<p%!4)AND(p%!4<p%!4)AND(p%
!4<p%!4)AND(p%!4<p%!4)AND(p%!4<p%!4)AND(p%!4<p%!4):p%=!p%:U.p%=0:t%=TIME-t%

This is /slightly/ biased because it's only comparing the +4 offset, not
all the way up to the +16 offset which might have caused more data to be
read into the cache but we're only trying to get a feel for the timings
here. We also use the fact that BASIC has no lazy evaluation and will
therefore evaluate every single one of the data reads and logical
operations. In practice these could easily be structured such that there
were early failure cases. The use of 14 comparisons here will be different
to an actual use case, but again should give a feel for the sort of
timings to expect. If you were doing only point comparisons, you'd only
have 4 comparisons.

StrongARM traverses the list in 4-9cs in a taskwindow (well, it's easier
to type in there).

StrongARM with cache off traverses the list in an amusing 5885
centi-seconds (58.9 seconds).

Fortunately we're not bothered about non-SA systems, so this won't matter.
Or if it does, we wouldn't write it in BASIC.

Of course, this'll really depend on what you're doing.

--
Gerph {djf0-.3w6e2w2.226,6q6w2q2,2.3,2m4}
URL: http://www.movspclr.co.uk/
... Into that point of silence, where we cry without sound.

Tony Houghton

unread,
17 Aug 2003, 18:50:3317/08/2003
to
In <cef187234c...@pudy.websterxl.co.uk>,
Andrew Pullan <a.pu...@zetnet.co.uk> wrote:

> On 17 Aug Tony Houghton wrote:
>
>> In <a6c87e234c...@pudy.websterxl.co.uk>,
>> Andrew Pullan <a.pu...@zetnet.co.uk> wrote:

[Deleting hundreds or thousands of icons is slow]

> Should have said...
>
> This is from Basic.
>
>> Don't create them in the first place and use Wimp_PlotIcon instead.
>
> Seem to remember trying this actually. For small numbers of icons where all
> can be plotted every time then it was faster. When you get to 1000+ icons
> it's a bit slow in basic, Especially when you have to work out which 'icons'
> you need to draw first!
>
> Another problem is that the rest of the code is based arround detecting
> clicks on the icons. (In case you havent guessed this is WebsterXL I'm
> talking about)
>
>> I wrote a Minewsweeper clone years ago and found the redraw was also much
>> faster with Wimp_PlotIcon drawing the cells than with real icons for some
>> reason.
>
> Snap! I found that with my Kye clone. It was unusable using real icons.

My Minesweeper was written in BASIC too IIRC. It was one of my first
Wimp experiments before I could afford Acorn C. It was easy to work out
which icons needed redrawing or had been clicked on because they were in
a grid.

Devise some way of doing a quick lookup of an element by its position eg
a binary tree or a hash, or even just a 2D array sorted by X and Y. The
Wimp probably just uses a simple 1D array sorted by icon number; it
isn't designed to cope with many icons. I would have thought even in
BASIC you'd be able to come up with something faster than that.

Stewart Brodie

unread,
18 Aug 2003, 03:47:0918/08/2003
to
Andrew Pullan <a.pu...@zetnet.co.uk> wrote:

> Hi All
>
> Anyone know a fast way of deleting allthe icons in a window? Whe there are
> several hundred icons. (if not several thousand)
>
> Deleting them one at a time using Wimp_DeleteIcon takes for ever.
>
> Deleting the window and recreating it is nice and quick. But it causes
> real problem as the wimp moves the window arround when its reopened. The
> only way round this is to open the window twice, forcing it to a specific
> place everytime. But even this doesnt seem to work eveyrtime!!
>
> Any other methods that I've not thought of?

Assuming that you do want real icons:

* Make sure you delete the highest numbered icon last.

* Try using Wimp_SetIconState to set the 'deleted' bit (+ bit 7)

* Remember the current 'behind' window of your window, and temporarily
re-open your window behind the backdrop before doing the deletions,
then bring it back to the front again. This should preserve the
positioning as you are not closing the window


--
Stewart Brodie

Martin Wuerthner

unread,
18 Aug 2003, 06:52:5918/08/2003
to
In message <a6c87e234c...@pudy.websterxl.co.uk>
Andrew Pullan <a.pu...@zetnet.co.uk> wrote:

Hi Andrew,

> Deleting the window and recreating it is nice and quick. But it causes real
> problem as the wimp moves the window arround when its reopened. The only way
> round this is to open the window twice, forcing it to a specific place
> everytime. But even this doesnt seem to work eveyrtime!!

If you record the coordinates of the window and create the new one with
exactly the same coords, the only thing the Wimp does to your window is to
force it on screen as always happens with newly opened windows.

So, if you can afford for the window to be hidden until the next Null
event you can open the new window with arbitrary coordinates behind the
backdrop, then wait for the next Null event (by which time the Wimp has
stopped messing with the window), then reopen it with the recorded
coordinates. Only then close the old window (if you tried closing the old
window immediately when creating the new one, the Wimp will redraw its
area before your new window finally covers it again, which will cause
flicker at best or a long delay at worst).

There is probably an even better method, but I have not tried this: The
reason why you have to wait for a Null event in the above solution is
because the Wimp does not open the window immediately when you call
Wimp_OpenWindow for the new window. The opening of the window is pending
until you call Wimp_Poll and only then the Wimp messes with your
coordinates if the window is partly off screen. However, there is a trick
to force the window to be opened immediately: Call Wimp_UpdateWindow with
suitable coordinates (e.g., the whole visible area) followed by the usual
GetRectangle loop (you know you will not get any rectangles because the
window is behind the backdrop, but just in case...). Of course, this will
not display anything because you opened the new window behind the
backdrop, but it should force the Wimp to process the open request. So, if
you then reopen the window with the correct coordinates as taken from the
old window, that should do it.

Martin
--
---------------------------------------------------------------------
Martin Wuerthner MW Software mar...@invalidMW-software.com
remove "invalid" to reply
---------------------------------------------------------------------

Martin Wuerthner

unread,
18 Aug 2003, 06:59:2018/08/2003
to
In message <gemini.3f40847d00168031%stewart...@ntlworld.com>
Stewart Brodie <stewart...@ntlworld.com> wrote:

The first and third point are not necessary if you go for the second since
the Wimp will neither attempt to shrink the block nor to redraw the
deleted icons if you just set the deleted bit.

So, you can simply set the deleted bit in each icon and then force a
redraw for the whole window.

This does not release the memory the Wimp used for the icon blocks, but
this is not a problem since the memory will be released when the window is
finally deleted and the memory can also be reused when you start creating
new icons in the window. If you really want the Wimp to shrink the memory
block used to hold the window, you can try setting the deleted bit for all
but the last icons and then call Wimp_DeleteIcon for the last one.
However, I think it might be better to hold on to the memory because you
are likely to want many icons again in this window at some later stage.

druck

unread,
18 Aug 2003, 15:54:0718/08/2003
to
On 17 Aug 2003 Andrew Pullan <a.pu...@zetnet.co.uk> wrote:
> Anyone know a fast way of deleting allthe icons in a window? Whe there are
> several hundred icons. (if not several thousand)
>
> Deleting them one at a time using Wimp_DeleteIcon takes for ever.
>
> Deleting the window and recreating it is nice and quick.

This has the disadvantage that any utilities tracking the window will loose
the information on it when it is recreated. For example if you are using my
!WorkSpace multiple desktop utility and have set the window to appear on more
than one workspace, deleting and recreating will cause it to only appear on
the current workspace subsequently. The user will not appreciate such
behaviour.

---druck

--
The ARM Club Free Software - http://www.armclub.org.uk/free/
The 32bit Conversions Page - http://www.quantumsoft.co.uk/druck/

Andrew Pullan

unread,
20 Aug 2003, 16:28:0420/08/2003
to
On 17 Aug Tony Houghton wrote:

> In <cef187234c...@pudy.websterxl.co.uk>,
> Andrew Pullan <a.pu...@zetnet.co.uk> wrote:
>
>
> [Deleting hundreds or thousands of icons is slow]

[snip]

> >> Don't create them in the first place and use Wimp_PlotIcon instead.

[snip]


> > > I wrote a Minewsweeper clone years ago and found the redraw was also
> > > much faster with Wimp_PlotIcon drawing the cells than with real icons
> > > for some reason.
> >
> > Snap! I found that with my Kye clone. It was unusable using real icons.
>
> My Minesweeper was written in BASIC too IIRC. It was one of my first
> Wimp experiments before I could afford Acorn C. It was easy to work out
> which icons needed redrawing or had been clicked on because they were in
> a grid.

Hmm! Rich! I still couldn't afford the C compiler so wrote a simple compiler.
Well more of a very high level assembler really! That was quick! (It's even
probably still on the hard disc somewhere!)

> Devise some way of doing a quick lookup of an element by its position eg
> a binary tree or a hash, or even just a 2D array sorted by X and Y.

For a regular grid you dont need to store anything if the icons are
consecutive as you can work out the icon from the x and y position divided by
the width and height of the icons.

> The
> Wimp probably just uses a simple 1D array sorted by icon number; it
> isn't designed to cope with many icons.

Dont know about that, but it does seem to cope quite well. At least on RISC
PC's etc. A310's are a little slow, but theyre slow anyway!

> I would have thought even in
> BASIC you'd be able to come up with something faster than that.

True! (See other replies)

>

--
Andrew J Pullan
For replies by Email please put my middle initial in :-)

Computer: a device designed to speed and automate errors.

Andrew Pullan

unread,
20 Aug 2003, 16:02:1720/08/2003
to
On 17 Aug Justin Fletcher wrote:

> On Sun, 17 Aug 2003, Andrew Pullan wrote:
>
> > On 17 Aug Tony Houghton wrote:
> >
> > > In <a6c87e234c...@pudy.websterxl.co.uk>,
> > > Andrew Pullan <a.pu...@zetnet.co.uk> wrote:
> > >
> > > > Hi All
> > > >
> > > > Anyone know a fast way of deleting allthe icons in a window? Whe
> > > > there are several hundred icons. (if not several thousand)
> > > >
> > > > Deleting them one at a time using Wimp_DeleteIcon takes for ever.
> > > >
> > > > Deleting the window and recreating it is nice and quick. But it
> > > > causes real problem as the wimp moves the window arround when its
> > > > reopened. The only way round this is to open the window twice,
> > > > forcing it to a specific place everytime. But even this doesnt seem
> > > > to work eveyrtime!!
> > > >
> > > > Any other methods that I've not thought of?
> >
> > Should have said...
> >
> > This is from Basic.
>
> Don't think it really makes a lot of difference what language you use; the
> algorithms will be the same.

True. But looping in basic is much slower than looping in C if you've
significant code inside the loop. However...

> > > Don't create them in the first place and use Wimp_PlotIcon instead.
> >
> > Seem to remember trying this actually. For small numbers of icons where
> > all can be plotted every time then it was faster. When you get to 1000+
> > icons it's a bit slow in basic, Especially when you have to work out
> > which 'icons' you need to draw first!
>
> Write up a chunk of assembler... or, better still - don't be surprised
> when you find that your web browsers written in BASIC ends up slow :-)

:-) More assembler :-( Last tim I did some I corrupted my Harddisc!

If I'd know my HTML Viewer would end up as a proper Web Browser then I've ave
written in in C to start with :-) Pity the Basic wont compile!

> > Another problem is that the rest of the code is based arround detecting
> > clicks on the icons. (In case you havent guessed this is WebsterXL I'm
> > talking about)
>
> I'd be terrified if I had 100s of icons in a window, never mind thousands.

1106 icons when I just checked www.iconbar.com All created automatically of
course. :-)

> Neither the redraw, nor the click handling should be particularly painful
> if you just use some simple logic around things.
>

> How about partitioning your virtual work area into regions [snip]

> and
> those regions are rectangular in shape, you can easily group by their
> nesting - in fact for parts of the propgation of messages this is implicit
> (IIRC).

Good point! e.g. table cells are guaranteed to the rectangles. Areas of text
usually arent. well I guess they are, but with large chunks taken out for
images and tables etc.

> Or using a binary tree to represent the vertical positions of the icons
> (on the assumptions that almost all pages are taller than they are wide).

Yeah! for some reason I've always been thinking of a simple list! Silly! WXL
already has all sorts of lists including lists linked to other type of lists!

> A (very brief) test I've just done to check how quickly you might be able
> to test the positioning of regions in a list in BASIC with 1000 regions

> [snip]


> [Create a simple list of 1001 regions]

[snip!]

> This is /slightly/ biased because it's only comparing the +4 offset, not
> all the way up to the +16 offset which might have caused more data to be
> read into the cache but we're only trying to get a feel for the timings
> here.

Must more data would be read into the cache I think. Dont forget you dont
know how many regions there are at the start so you cant allocate a big block
of contigious memory. You have to allocate it as you go and there will be
allocations inbetween these block for images, text etc.

WXL's heap when displaying www.iconbar.com expands by approx 500k (41k of
page, 249k of image)!

Therefore the search will probably be through 500K of memory, so several
caches full. Possibly loading the same bit repeatedly due to the way memory
allocation works.

> StrongARM traverses the list in 4-9cs in a taskwindow (well, it's easier
> to type in there).
>
> StrongARM with cache off traverses the list in an amusing 5885
> centi-seconds (58.9 seconds).
>
> Fortunately we're not bothered about non-SA systems, so this won't matter.

So that's RPC600's and A310's out then! as well as Iyonix :-)

> Or if it does, we wouldn't write it in BASIC.

True. But if the data structures dont change often (and they shouldnt) then a
bit of assembler codl come to the rescue (WXL already has lots of assembler
bits, most of it is 32 bit compatibe as well)

>

Might give this idea a try after the next release.

--
Andrew J Pullan
For replies by Email please put my middle initial in :-)

Operating System not Found? = Another windows user!

Andrew Pullan

unread,
20 Aug 2003, 15:15:5420/08/2003
to
On 18 Aug druck wrote:

> On 17 Aug 2003 Andrew Pullan <a.pu...@zetnet.co.uk> wrote:
> > Anyone know a fast way of deleting allthe icons in a window? Whe there
> > are several hundred icons. (if not several thousand)

> > Deleting the window and recreating it is nice and quick.

>
> This has the disadvantage that any utilities tracking the window will loose
> the information on it when it is recreated.

Another point against deleting and recreating the window!

> For example if you are using my !WorkSpace multiple desktop utility and
> have set the window to appear on more than one workspace, deleting and
> recreating will cause it to only appear on the current workspace
> subsequently. The user will not appreciate such behaviour.

Well I'd not noticed that behaviour, but then I dont often use WorkSpace.
However that might explain some problems people have reported with that kind
of utility :-)

--
Andrew J Pullan


For replies by Email please put my middle initial in :-)

Andrew Pullan

unread,
20 Aug 2003, 17:05:1520/08/2003
to
On 18 Aug Martin Wuerthner wrote:

> In message <a6c87e234c...@pudy.websterxl.co.uk>
> Andrew Pullan <a.pu...@zetnet.co.uk> wrote:
>
> Hi Andrew,
>
> > Deleting the window and recreating it is nice and quick. But it causes
> > real problem as the wimp moves the window arround when its reopened. The
> > only way round this is to open the window twice, forcing it to a specific
> > place everytime. But even this doesnt seem to work eveyrtime!!
>
> If you record the coordinates of the window and create the new one with
> exactly the same coords, the only thing the Wimp does to your window is to
> force it on screen as always happens with newly opened windows.

Yes that's the problem I found. There's a flag to for the next open to be on
screen (under the nested wimp, bit 21), but nothing to force it open where
you tell it!

> So, if you can afford for the window to be hidden until the next Null
> event you can open the new window with arbitrary coordinates behind the
> backdrop, then wait for the next Null event (by which time the Wimp has
> stopped messing with the window), then reopen it with the recorded
> coordinates. Only then close the old window

Yeah! that might work. Bit complicated though. There's already all sort of
delays and things that get triggered in the wimp_poll loop on null events.
Hmm! Complicated even more really as these windows may be frame windows as
well!

-8<-


> The opening of the window is pending
> until you call Wimp_Poll and only then the Wimp messes with your
> coordinates if the window is partly off screen.

Under the nested wimp I've found it does actually update the wimp_openwindow
block with the coordinates it is going to use. Another open with the original
coordinates seems to work on RISC OS Select, not tried it on any other wimp
version yet

> However, there is a trick
> to force the window to be opened immediately: Call Wimp_UpdateWindow with

> suitable coordinates -8<-

Problem with all this is I still have to delete the old window and create a
new one. Actually this could create more problems as the new window will be a
differant winow handle to the old (See justins email). Mostly if you do a
delete and an immediate create you get the same window handle. (I dont rely
on this of course)

Having said that, Ill bare it in mind if Nothin else works :-)

> Martin

TTFN

--
Andrew J Pullan


For replies by Email please put my middle initial in :-)

10 REPEAT PRINT "Hello world!":UNTIL FALSE

Tony Houghton

unread,
20 Aug 2003, 20:00:1120/08/2003
to
In <992418254c...@pudy.websterxl.co.uk>,
Andrew Pullan <a.pu...@zetnet.co.uk> wrote:

> If I'd know my HTML Viewer would end up as a proper Web Browser then I've ave
> written in in C to start with :-) Pity the Basic wont compile!

I'm surprised you didn't rewrite in C for Webster XL. As well as making
the handling of complex data structures easier, giving you less work in
the long run, it would probably have been a lot more competitive with
Fresco and Oregano and sold better.

Justin Fletcher

unread,
20 Aug 2003, 18:23:0620/08/2003
to
On Wed, 20 Aug 2003, Andrew Pullan wrote:

> On 17 Aug Justin Fletcher wrote:
>
> > On Sun, 17 Aug 2003, Andrew Pullan wrote:
> >
> > > On 17 Aug Tony Houghton wrote:
> > >
> > > > In <a6c87e234c...@pudy.websterxl.co.uk>,
> > > > Andrew Pullan <a.pu...@zetnet.co.uk> wrote:
> > > >
> > > Another problem is that the rest of the code is based arround detecting
> > > clicks on the icons. (In case you havent guessed this is WebsterXL I'm
> > > talking about)
> >
> > I'd be terrified if I had 100s of icons in a window, never mind thousands.
>
> 1106 icons when I just checked www.iconbar.com All created automatically of
> course. :-)

Christ, are you using one icon per word or something ?

> > This is /slightly/ biased because it's only comparing the +4 offset, not
> > all the way up to the +16 offset which might have caused more data to be
> > read into the cache but we're only trying to get a feel for the timings
> > here.
>
> Must more data would be read into the cache I think. Dont forget you dont
> know how many regions there are at the start so you cant allocate a big block
> of contigious memory. You have to allocate it as you go and there will be
> allocations inbetween these block for images, text etc.
>
> WXL's heap when displaying www.iconbar.com expands by approx 500k (41k of
> page, 249k of image)!
>
> Therefore the search will probably be through 500K of memory, so several
> caches full. Possibly loading the same bit repeatedly due to the way memory
> allocation works.

I'm not sure that that's relevant (or even true). If during your redraw
loop whilst deciding what to redraw you're intending on searching through
the image data then I think you're doing something wrong with it. You
should only be looking through the region data whilst deciding what you
are redrawing.

1100 icons, 20 bytes per read, that's 17600 bytes, with potentially two
uncached reads per entry would be 2200 reads from memory. But you're using
BASIC, so the overhead on using a single named variable is higher than
that of the algorithm so it's not really important what you're doing with
it - if you're /that/ bothered about the speed don't use BASIC for it.
Christ, write it in C and call if from your BASIC if you have to - it'll
be easier to maintain than either BASIC or assembler and it sets you on
the road for your long awaited (yawn) C version of WXL.

Best case with a perfect binary tree would be an average of 11 reads
(rather than 1100). Given, as I said, you can separate the rendering of
the window into horizontal strips this could be sped up hugely. Even if
you're using one icon per word (quick glance at iconbar as example),
that's ~100 icons per 128 OS unit high strip (value found by counting and
estimation). That would be reduced because you're in tables and the redraw
of each table can be left to the table with each component of the table
knowing how to redraw itself.

Of course, that really does depend on how structured your code is.

> > StrongARM traverses the list in 4-9cs in a taskwindow (well, it's easier
> > to type in there).
> >
> > StrongARM with cache off traverses the list in an amusing 5885
> > centi-seconds (58.9 seconds).
> >
> > Fortunately we're not bothered about non-SA systems, so this won't matter.
>
> So that's RPC600's and A310's out then! as well as Iyonix :-)

Fortunately such old machines we don't care about. Or if we did, we
wouldn't be writing in BASIC.

> > Or if it does, we wouldn't write it in BASIC.

(Oh, I said that)

--
Gerph {djf0-.3w6e2w2.226,6q6w2q2,2.3,2m4}
URL: http://www.movspclr.co.uk/

[ All information, speculation, opinion or data within, or attached to,
this email is private and confidential. Such content may not be
disclosed to third parties, or a public forum, without explicit
permission being granted. ]

Andrew Pullan

unread,
21 Aug 2003, 15:31:4121/08/2003
to
On 21 Aug Tony Houghton wrote:

> In <992418254c...@pudy.websterxl.co.uk>,
> Andrew Pullan <a.pu...@zetnet.co.uk> wrote:
>
> > If I'd know my HTML Viewer would end up as a proper Web Browser then I've
> > ave written in in C to start with :-) Pity the Basic wont compile!
>
> I'm surprised you didn't rewrite in C for Webster XL.

If I'd started with WXL then I would have, but I didn't. When I originally
wrote it it was for my own use. Then it expanded and was possibly going to be
part of an Internet package. It was still basic because thats what I started
in and it could be compiled using !ABC. It was three times faster, but 4
times the size! Not having a C compiler at the time, it was way too
expensive, !ABC worked fine.

Now of course its to big for !ABC, or something. After 7 hours compiling on a
StrongARM RPC it was still only approx 20% of the way through. An Iyonix does
much much better, but then the compiler address exceptions :-(


> As well as making the handling of complex data structures easier, giving
> you less work in the long run, it would probably have been a lot more
> competitive with Fresco and Oregano and sold better.

I wish I had written it in C of course! It would have taken longer but it
would make things a lot easier.

--
Andrew J Pullan
For replies by Email please put my middle initial in :-)

Andrew Pullan

unread,
21 Aug 2003, 18:29:0321/08/2003
to
On 20 Aug Justin Fletcher wrote:

> > > I'd be terrified if I had 100s of icons in a window, never mind
> > > thousands.
> >
> > 1106 icons when I just checked www.iconbar.com All created automatically
> > of course. :-)
>
> Christ, are you using one icon per word or something ?

Nope! Well not intentionally. It's usually one icon per text line line.
Except each HTML tag also causes a new icon to be used. iconbar is probably
the worst cos its all tables I think. Most sites are a few hundred.

> > > [ example thingy]
> >
> > Much more data would be read into the cache I think.
> > -8<-


>
> I'm not sure that that's relevant (or even true). If during your redraw
> loop whilst deciding what to redraw you're intending on searching through
> the image data then I think you're doing something wrong with it. You
> should only be looking through the region data whilst deciding what you
> are redrawing.

Well I was basing my figuesses on your coded example which looked like a
simple top to bottom search. But Yes your right in reality there are lots of
easy ways to cur the search time down if you get your data structures right.

> it - if you're /that/ bothered about the speed don't use BASIC for it.

As it's redrawing is speed critical (or I consider it so), therefore once the
code was worked out it would become ARM code somehow.

> Best case with a perfect binary tree would be an average of 11 reads
> (rather than 1100). Given, as I said, you can separate the rendering of
> the window into horizontal strips this could be sped up hugely.

Would probably be like that more or less. Although there are complications as
always. e.g. column1 row1 in a table could be 2 screens high, column2 row1
could be 1 text row high. There then may not be anymore in column 1. As on
iconbar actually. The page is written top to bottom gradually workin left to
right. Splitting the page into horizontal strips then becomes soemthing of a
problem.

You'd have to decide if a part of the table cell requires rendering, then
decide which bits of the cell need rendering. (Actually you already said
that I think!)

> Of course, that really does depend on how structured your code is.

varies a lot. Pre C code, erm no! Though there's not a lot of that left now
apart from the bit that creates all them icons.

> > > Fortunately we're not bothered about non-SA systems, so this won't
> > > matter.
> >
> > So that's RPC600's and A310's out then! as well as Iyonix :-)
>
> Fortunately such old machines we don't care about. Or if we did, we
> wouldn't be writing in BASIC.

Good Grief! Someone who already considers an Iyonix an old machine!! :-)

TTFN

--
Andrew J Pullan
For replies by Email please put my middle initial in :-)

Tony Houghton

unread,
21 Aug 2003, 19:16:2321/08/2003
to
In <782d99254c...@pudy.websterxl.co.uk>,
Andrew Pullan <a.pu...@zetnet.co.uk> wrote:

> On 21 Aug Tony Houghton wrote:
>
>> In <992418254c...@pudy.websterxl.co.uk>,
>> Andrew Pullan <a.pu...@zetnet.co.uk> wrote:
>>
>> > If I'd know my HTML Viewer would end up as a proper Web Browser then I've
>> > ave written in in C to start with :-) Pity the Basic wont compile!
>>
>> I'm surprised you didn't rewrite in C for Webster XL.
>
> If I'd started with WXL then I would have, but I didn't. When I originally
> wrote it it was for my own use. Then it expanded and was possibly going to be
> part of an Internet package. It was still basic because thats what I started
> in and it could be compiled using !ABC. It was three times faster, but 4
> times the size! Not having a C compiler at the time, it was way too
> expensive, !ABC worked fine.

But now you're talking about Webster aren't you? At some point you must
have decided to do a load of work on it to make it into the commercial
Webster XL. That's when I would have rewritten it in C IIWY.

> Now of course its to big for !ABC, or something. After 7 hours compiling on a
> StrongARM RPC it was still only approx 20% of the way through. An Iyonix does
> much much better, but then the compiler address exceptions :-(

I didn't know !ABC was that slow. Or is it usually fast enough and it's
hit some sort of pain barrier with WXL?

Colin Granville

unread,
22 Aug 2003, 05:51:5822/08/2003
to
Andrew Pullan <a.pu...@zetnet.co.uk> wrote:

>On 17 Aug Tony Houghton wrote:

>This is from Basic.
>
>> Don't create them in the first place and use Wimp_PlotIcon instead.
>
>Seem to remember trying this actually. For small numbers of icons where all
>can be plotted every time then it was faster. When you get to 1000+ icons

>it's a bit slow in basic,Especially when you have to work out which 'icons'


>you need to draw first!

Surely if you wrote an assembler routine that took the list of icons
and plotted them using WimpPlotIcon, using the RedrawWindowBlock to
decide which to draw, it wouldn't be slower than the wimp - the
wimp must do this already. Writing your own plot routine also has
the advantage that you could initially use Wimp_PlotIcon to get you
program working but you could replace Wimp_PlotIcon later if you
wanted.

>
>Another problem is that the rest of the code is based arround detecting
>clicks on the icons. (In case you havent guessed this is WebsterXL I'm
>talking about)

Again you could do an assembler routine which you call after
Wimp_GetPointerInfo or mouse click event that searches the list in
reverse order (icons on the top are plotted last - though this
probably doesn't matter in this case as HTML is tiled) until the
click point is inside an icons bounding box and return a number
(the equivalent of an icon number) of some sort for your other
routines. You are saving the wimp doing this so I wouldn't expect
this to slow things down.

Both of these routines would be only a few lines of C and I wouldn't
expect them to be too long in assember.

You then just need to replace Wimp_CreateIcon so that it just adds
an icon to the plot list and Wimp_DeleteIcon to remove an Icon from
the list the way you want.


--
Colin

Dave Higton

unread,
22 Aug 2003, 17:02:2922/08/2003
to
In message <5f6aa9254c...@pudy.websterxl.co.uk>
Andrew Pullan <a.pu...@zetnet.co.uk> wrote:

> On 20 Aug Justin Fletcher wrote:
>
> > Christ, are you using one icon per word or something ?
>
> Nope! Well not intentionally. It's usually one icon per text line line.
> Except each HTML tag also causes a new icon to be used.

So... you're only using icons to make links and so on sensitive to
clicks?

Is that really the best way? How about making the whole window
sensitive, then working out whether the click falls on a link or other
bit that you want sensitive?

Dave

Jeremy C B Nicoll

unread,
23 Aug 2003, 07:28:4823/08/2003
to
In article <c65325264c...@dsl.pipex.com>,
Dave Higton <daveh...@dsl.pipex.com> wrote:

> Is that really the best way? How about making the whole window
> sensitive, then working out whether the click falls on a link or
> other bit that you want sensitive?

How does the logic that changes a mouse pointer when you move the
epointer over different parts of a window work? Does th app have to
monitor every mouse movement pixel-by-pixel, or does the wimp tell the
app when the mouse crosses the edge of an icon?

--
Jeremy C B Nicoll - my opinions are my own.

Ralph Corderoy

unread,
23 Aug 2003, 07:40:0323/08/2003
to
Hi Andrew,

> Would probably be like that more or less. Although there are
> complications as always. e.g. column1 row1 in a table could be 2
> screens high, column2 row1 could be 1 text row high. There then may
> not be anymore in column 1. As on iconbar actually. The page is
> written top to bottom gradually workin left to right. Splitting the
> page into horizontal strips then becomes soemthing of a problem.

Would an N-way tree of non-overlapping rectangles be a suitable data
structure for turning an (x, y) into `this image in this paragraph in
this table data in this table row, etc.'? And also for determining what
items overlap the redraw rectangle?

Normally, with the right data structure the code because easier to think
about, write, and get right.

Cheers,

--
Ralph Corderoy. http://inputplus.co.uk/ralph/ http://troff.org/

Dave Higton

unread,
23 Aug 2003, 13:50:0623/08/2003
to
In message <4c2674a4...@omba.demon.co.uk>

I was only thinking of clicks, where you only have to check position
when there is a click.

If you have to do something else like change the colour of some part
when the pointer moves onto or off it, that's a different matter -
lots of work on null polls, which makes the icons more a attractive
proposition.

Dave

druck

unread,
23 Aug 2003, 15:06:0823/08/2003
to

But remember the Wimp doesn't work by magic. It is not optimised for a large
number of icons and does a straight forward linear search on each of the icon
rectangles. This may be quicker than BASIC, but will still be slow for a
large number of icons.

The best way is to plot everything yourself and handle the rectangle
detection yourself. I would build an two arrays of pointers to your data
structures sorted on x & y coordinates as its created, binary search these
for the target coordinates, and then do rectange compares on the common
matches from both arrays. This will handle both overlapping an non
overlapping rectangles.

Martin Wuerthner

unread,
23 Aug 2003, 17:17:0723/08/2003
to
In message <18b8.3f47...@blake.inputplus.co.uk>
ra...@inputplus.co.uk (Ralph Corderoy) wrote:

> Hi Andrew,
>
> > Would probably be like that more or less. Although there are
> > complications as always. e.g. column1 row1 in a table could be 2
> > screens high, column2 row1 could be 1 text row high. There then may
> > not be anymore in column 1. As on iconbar actually. The page is
> > written top to bottom gradually workin left to right. Splitting the
> > page into horizontal strips then becomes soemthing of a problem.
>
> Would an N-way tree of non-overlapping rectangles be a suitable data
> structure for turning an (x, y) into `this image in this paragraph in
> this table data in this table row, etc.'? And also for determining what
> items overlap the redraw rectangle?

Yes, this is a typical example of a geometric problem that can be solved
with O(n*log n) preprocessing time (to create the segment tree data
structure) and O(log n) query time per sample, so rather more efficiently
than the Wimp's linear search.

In fact, even if the rectangles are overlapping, you can still solve the
problem in O(max(log n, m)) time where m is the number of rectangles the
sample point falls into. So, basically, O(log n) again but of course, if
the sample falls into m rectangles with m > log n, the query time has to
be at least m, just to write the result.

Martin Wuerthner

unread,
23 Aug 2003, 17:10:0223/08/2003
to
In message <4c2674a4...@omba.demon.co.uk>
Jeremy C B Nicoll <Jer...@omba.demon.co.uk> wrote:

If you use icons you can tell the Wimp to change the pointer automatically
so the app does not have to do anything.

If you do not use icon, then the app is on its own anyway. It would simply
check the mouse position on each null event while the pointer is over one
of its windows. This is not as bad as it sounds. The Wimp does not know by
magic either. In fact, the application can do it far more efficiently than
the Wimp because it knows certain properties about the rectangles and it
can hold them in a suitable data structure.

Tony Houghton

unread,
23 Aug 2003, 17:24:5123/08/2003
to
In <88daa926...@mw-software.com>,
Martin Wuerthner <mar...@invalidMW-software.com.invalid> wrote:

> If you use icons you can tell the Wimp to change the pointer automatically
> so the app does not have to do anything.
>
> If you do not use icon, then the app is on its own anyway. It would simply
> check the mouse position on each null event while the pointer is over one
> of its windows. This is not as bad as it sounds. The Wimp does not know by
> magic either. In fact, the application can do it far more efficiently than
> the Wimp because it knows certain properties about the rectangles and it
> can hold them in a suitable data structure.

It's a pity the Wimp doesn't generate pointer movement events (IIRC).
That's what you really need to do it efficiently, although claiming null
events doesn't effect things too badly. I wonder how much a filter would
help.

I've had another idea though. How about creating and deleting icons as
necessary on open window and/or scrolling events so that only enough to
handle visible links are in use at any one time? Or is that likely to
slow down scrolling too much?

druck

unread,
23 Aug 2003, 18:33:4523/08/2003
to
On 23 Aug 2003 Tony Houghton <to...@realh.co.uk> wrote:
> In <88daa926...@mw-software.com>, Martin Wuerthner
> <mar...@invalidMW-software.com.invalid> wrote:
>
>> If you use icons you can tell the Wimp to change the pointer automatically
>> so the app does not have to do anything.
>>
>> If you do not use icon, then the app is on its own anyway. It would simply
>> check the mouse position on each null event while the pointer is over one
>> of its windows. This is not as bad as it sounds. The Wimp does not know by
>> magic either. In fact, the application can do it far more efficiently than
>> the Wimp because it knows certain properties about the rectangles and it
>> can hold them in a suitable data structure.
>
> It's a pity the Wimp doesn't generate pointer movement events (IIRC).
> That's what you really need to do it efficiently, although claiming null
> events doesn't effect things too badly. I wonder how much a filter would
> help.

Make sure you don't just claim NULL events as this will slow down all
applications and affect the responsiveness of the desktop.

* Only set the wimp mask for returning NULL events after you have receiced an
enter reason code for your window and unset it after.

* Use Wimp_PollIdle with an interval of not less than 10cs for this purpose.

* Take extra care to make the NULL handling routine as efficent as possible.

Tony Houghton

unread,
23 Aug 2003, 19:50:5123/08/2003
to
In <e484b126...@druck.freeuk.net>,
druck <ne...@druck.freeuk.com> wrote:

> On 23 Aug 2003 Tony Houghton <to...@realh.co.uk> wrote:
>>
>> It's a pity the Wimp doesn't generate pointer movement events (IIRC).
>> That's what you really need to do it efficiently, although claiming null
>> events doesn't effect things too badly. I wonder how much a filter would
>> help.
>
> Make sure you don't just claim NULL events as this will slow down all
> applications and affect the responsiveness of the desktop.

Although ISTR that running the odd app that receives null events but
does nothing much with them is barely noticeable. It's justifiable in a
browser, provided you do as you say below.

> * Only set the wimp mask for returning NULL events after you have receiced an
> enter reason code for your window and unset it after.
>
> * Use Wimp_PollIdle with an interval of not less than 10cs for this purpose.

Both good bits of advice.

> * Take extra care to make the NULL handling routine as efficent as possible.

That's why I was wondering about filters - as in the Wimp's Filter
Manager. Does the Wimp delay paging in a task until it's sure no filters
have blocked an event? If so I think a filter would be the most
efficient way by far of doing this. But if the app is paged in
prematurely I'd be inclined to leave it to a user-mode handler: it's
simpler, and some of the gain in efficiency of handling the event before
it gets to your application would be offset by having the filter
installed.

druck

unread,
23 Aug 2003, 20:51:5323/08/2003
to
On 24 Aug 2003 Tony Houghton <to...@realh.co.uk> wrote:

> In <e484b126...@druck.freeuk.net>,
> druck <ne...@druck.freeuk.com> wrote:
> > Make sure you don't just claim NULL events as this will slow down all
> > applications and affect the responsiveness of the desktop.
>
> Although ISTR that running the odd app that receives null events but
> does nothing much with them is barely noticeable. It's justifiable in a
> browser, provided you do as you say below.

Its very noticeable when you have other large tasks doing background
processing. I've had to modify dozens of applications to use Wimp_PollIdle
in order to gain efficency.

RISC OS is not very good at background processing, and it is very important
that all applications avoid claiming null from Wimp_Poll instead of
Wimp_PollIdle.

The only justification is in a real time user interaction, such as drawing on
the screen.

JP. Baker

unread,
24 Aug 2003, 05:06:5124/08/2003
to
In article <6e80aa26...@mw-software.com>,

Martin Wuerthner <mar...@invalidMW-software.com.invalid> wrote:
>In fact, even if the rectangles are overlapping, you can still solve the
>problem in O(max(log n, m)) time where m is the number of rectangles the
>sample point falls into. So, basically, O(log n) again but of course, if
>the sample falls into m rectangles with m > log n, the query time has to
>be at least m, just to write the result.

If I have followed this thread correctly: In a modern web browser you *would*
be looking for overlapping rectangles anyway and probably couldn't get the
wimp to handle mouse clicks. Things like ':hover' and 'onmouseover' apply
at lots of levels.

<style type="text/css">
div:hover {background-color: #eeeeee}
</style>
...
<div>...<p onclick="...">....<img src="..." />...</p>...</div>

The wimp isn't going to give the correct events or you are going to have
to traverse the DOM anyway.

nhoJ
--
John P Baker

druck

unread,
24 Aug 2003, 09:59:5924/08/2003
to
On 24 Aug 2003 cc...@shark.cse.bris.ac.uk (JP. Baker) wrote:
> In article <6e80aa26...@mw-software.com>, Martin Wuerthner
> <mar...@invalidMW-software.com.invalid> wrote:
>> In fact, even if the rectangles are overlapping, you can still solve the
>> problem in O(max(log n, m)) time where m is the number of rectangles the
>> sample point falls into. So, basically, O(log n) again but of course, if
>> the sample falls into m rectangles with m > log n, the query time has to
>> be at least m, just to write the result.
>
> If I have followed this thread correctly: In a modern web browser you
> *would* be looking for overlapping rectangles anyway and probably couldn't
> get the wimp to handle mouse clicks. Things like ':hover' and 'onmouseover'
> apply at lots of levels.

You wont be able to use icons for overlapping rectangles as there will be
redraw (unless user drawn) and click detection issues. Another reasons to
DIY.

Christopher Bazley

unread,
26 Aug 2003, 15:09:0926/08/2003
to
In message <4e2abe26...@druck.freeuk.net>
druck <ne...@druck.freeuk.com> wrote:

> On 24 Aug 2003 Tony Houghton <to...@realh.co.uk> wrote:
>
> > In <e484b126...@druck.freeuk.net>,
> > druck <ne...@druck.freeuk.com> wrote:
> > > Make sure you don't just claim NULL events as this will slow down all
> > > applications and affect the responsiveness of the desktop.
> >
> > Although ISTR that running the odd app that receives null events but
> > does nothing much with them is barely noticeable. It's justifiable in a
> > browser, provided you do as you say below.
>
> Its very noticeable when you have other large tasks doing background
> processing. I've had to modify dozens of applications to use Wimp_PollIdle
> in order to gain efficency.
>
> RISC OS is not very good at background processing, and it is very important
> that all applications avoid claiming null from Wimp_Poll instead of
> Wimp_PollIdle.
>
> The only justification is in a real time user interaction, such as drawing on
> the screen.
>
> ---druck

I disagree.

A long time ago I modified various programs of mine that do background
processing to use Wimp_PollIdle rather than Wimp_Poll; partly on the
basis of statements such as the above. However, quite recently I have
changed them back. My reasoning was as follows:

1) Neither TaskWindow nor Filer_Action use Wimp_PollIdle. If you wish
your task to compete on even terms with other background tasks then it
is best to follow suit.

2) So long as your task is not paged in for an unreasonable length of
time (I pre-empt mine after a maximum of 10cs) then the effect on
responsiveness to events such as mouse clicks is negligable. In fact I
would argue that it is better that this latency be predictable, instead
of varying apparently at random (depending on whether your task happens
to be paged in at the time).

3) More often than not there is only ONE background task going on. If
that task is using Wimp_PollIdle with a delay of 10cs and doing 10cs of
processing every null event, then it is using approximately 50% of CPU
time. What is happening during the other 50% of time? Absolutely
nothing; the CPU is just kicking its heels. This is not a gain in
efficency - in fact it is quite the reverse.

4) Many programs use Wimp_PollIdle as a simple method of controlling
the proportion of CPU time that they use, yet this method falls down
completely under even moderate processing loads. It doesn't require many
background tasks running before the Wimp becomes incapable of keeping to
the earliest return time passed to Wimp_PollIdle. In this situation
the requested return times (and hence the relative task 'priorities')
rapidly become meaningless.

It is much better to regulate the time taken inside our task (which we
*do* have some control over) rather than attempting to second-guess
what is going on outside. The '-nice' parameter introduced in the
latest version of the TaskWindow module allows relative task priorities
to be specified in terms of time before task switching (e.g. between
returning from Wimp_Poll and calling it again).

The bottom line is that Wimp knows whether or not it is busy; a single
task cannot know this. DO use Wimp_PollIdle if you genuinely have
nothing useful to do in the near future (e.g. a desktop clock). BUT if
you are performing intensive processing then using Wimp_PollIdle will
just frustrate your users, who will probably want to know why the hell
whatever-it-is takes so much longer under RISC OS.

--
Chris Bazley
===================================================================
My corner of the web: http://www.bigfoot.com/~chrisbazley/
Star Fighter 3000 web home: http://www.starfighter.acornarcade.com/

druck

unread,
26 Aug 2003, 21:34:1026/08/2003
to
On 26 Aug 2003 Christopher Bazley <chris...@bigfoot.com> wrote:
> A long time ago I modified various programs of mine that do background
> processing to use Wimp_PollIdle rather than Wimp_Poll; partly on the
> basis of statements such as the above. However, quite recently I have
> changed them back. My reasoning was as follows:

No, you've misunderstood, or I didn't put it well. Applications should not be
using Wimp_Null routinely for performing checking operations and returning
immediately, as this imposes a high task thrash on the machine. The they
should use Wimp_PollIdle for this purpose.

If an application has a serious amount of justifiable work to do on either
forground interaction or background processing, then it is acceptible to use
null's as long as they yield on regular basis as you've said.

Christopher Bazley

unread,
27 Aug 2003, 18:56:4827/08/2003
to
In message <278b4d28...@druck.freeuk.net>
druck <ne...@druck.freeuk.com> wrote:

> On 26 Aug 2003 Christopher Bazley <chris...@bigfoot.com> wrote:
> > A long time ago I modified various programs of mine that do background
> > processing to use Wimp_PollIdle rather than Wimp_Poll; partly on the
> > basis of statements such as the above. However, quite recently I have
> > changed them back. My reasoning was as follows:
>
> No, you've misunderstood, or I didn't put it well. Applications
> should not be using Wimp_Null routinely for performing checking
> operations and returning immediately, as this imposes a high task

> thrash on the machine. They should use Wimp_PollIdle for this purpose.


>
> If an application has a serious amount of justifiable work to do on
> either forground interaction or background processing, then it is
> acceptible to use null's as long as they yield on regular basis as
> you've said.

Fair enough; I just felt that your earlier statement that "...it is very
important that ALL applications avoid claiming null from Wimp_Poll..."
(my emphasis) was a bit over the top.

Actually the PRM gives out a similar message "...you should use
Wimp_PollIdle rather than Wimp_Poll unless the user is directly
involved...". I see this mantra about user interaction repeated all the
time, yet the legitimacy of intensive background processing (as per
TaskWindow and Filer_Action) is rarely defended.

Perhaps this paragraph of the PRM could be amended in future editions?

Andrew Pullan

unread,
29 Aug 2003, 15:20:3229/08/2003
to
On 22 Aug Tony Houghton wrote:

> In <782d99254c...@pudy.websterxl.co.uk>,
> Andrew Pullan <a.pu...@zetnet.co.uk> wrote:
>
> >> I'm surprised you didn't rewrite in C for Webster XL.
> >
> > If I'd started with WXL then I would have, but I didn't. When I
> > originally wrote it it was for my own use. Then it expanded and was
> > possibly going to be part of an Internet package. It was still basic
> > because thats what I started in and it could be compiled using !ABC. It
> > was three times faster, but 4 times the size! Not having a C compiler at
> > the time, it was way too expensive, !ABC worked fine.
>
> But now you're talking about Webster aren't you?

No. WebsterXL. Think it was about version 1.89 or so.

Since then the Core of WXL hasn't changed much at all. Mostly fixes in how
HTML is decoded and adding bits of Javascript.

> > Now of course its to big for !ABC, or something. After 7 hours compiling
> > on a StrongARM RPC it was still only approx 20% of the way through. An
> > Iyonix does much much better, but then the compiler address exceptions
> > :-(
>
> I didn't know !ABC was that slow. Or is it usually fast enough and it's
> hit some sort of pain barrier with WXL?

!ABC isn't very slow, it's that WXL is 800k of basic when blank lines and
comments are removed. I suspect the number of variables etc means it's almost
100% memory bound so the greater memory bandwidth on an Iyonix makes a lot of
differance.

--
Andrew J Pullan
For replies by Email please put my middle initial in :-)

Andrew Pullan

unread,
29 Aug 2003, 16:08:4629/08/2003
to
On 22 Aug Dave Higton wrote:

> > > are you using one icon per word or something ?
> >
> > Nope! Well not intentionally. It's usually one icon per text line line.
> > Except each HTML tag also causes a new icon to be used.
>
> So... you're only using icons to make links and so on sensitive to
> clicks?

Nope pointer changes as well. (done via the icon validation string) Also use
the icon number to discover the url's etc for displaying on the infobar. Plus
table borders image place holders etc etc.

> Is that really the best way? How about making the whole window
> sensitive, then working out whether the click falls on a link or other
> bit that you want sensitive?

It's certainly not the best way when used with such large numbers of icons.
But it is simple from the programming point of view. This was my prime
concern only at the beginning of course.

--
Andrew J Pullan
For replies by Email please put my middle initial in :-)

Andrew Pullan

unread,
29 Aug 2003, 16:25:5329/08/2003
to
On 22 Aug Colin Granville wrote:

> Andrew Pullan <a.pu...@zetnet.co.uk> wrote:
>
> >On 17 Aug Tony Houghton wrote:
>
> >This is from Basic.
> >
> >> Don't create them in the first place and use Wimp_PlotIcon instead.
> >
> > Seem to remember trying this actually. For small numbers of icons where
> > all can be plotted every time then it was faster. When you get to 1000+
> > icons it's a bit slow in basic,Especially when you have to work out which
> > 'icons' you need to draw first!
>
> Surely if you wrote an assembler routine that took the list of icons
> and plotted them using WimpPlotIcon, using the RedrawWindowBlock to
> decide which to draw, it wouldn't be slower than the wimp - the
> wimp must do this already.

Quite possible to do, but WXL uses the icons for other things as well (e.g.
image and plugin placemarkers) so I'd need to add code to search the list for
thing like clicking on links.

I think I'll have to do this at some point, but as WXL is fairly dependant on
using icons I think I'll keep em until I can work out the best data
structures etc to support all the current requirements and all the
additional CSS requirements. I've also foudn that the wimp can be quite slow
at returning window+icon numbers when here are hundereds of icons, especially
on older machines.

> Writing your own plot routine also has
> the advantage that you could initially use Wimp_PlotIcon to get you
> program working but you could replace Wimp_PlotIcon later if you
> wanted.

Quite hard to replace Wimp_PlotIcon also quite likely to make it incompatible
with Iyonix or Viewfinders I think.

> >Another problem is that the rest of the code is based arround detecting
> >clicks on the icons. (In case you havent guessed this is WebsterXL I'm
> >talking about)
>
> Again you could do an assembler routine which you call after
> Wimp_GetPointerInfo or mouse click event that searches the list in
> reverse order

See bit above. Nothing I havent thought of, it's quite a lare change though!

TTFN

druck

unread,
29 Aug 2003, 18:32:3029/08/2003
to
On 29 Aug 2003 Andrew Pullan <a.pu...@zetnet.co.uk> wrote:
> On 22 Aug Colin Granville wrote:
> > Surely if you wrote an assembler routine that took the list of icons
> > and plotted them using WimpPlotIcon, using the RedrawWindowBlock to
> > decide which to draw, it wouldn't be slower than the wimp - the
> > wimp must do this already.
>
> Quite possible to do, but WXL uses the icons for other things as well (e.g.
> image and plugin placemarkers) so I'd need to add code to search the list
> for thing like clicking on links.
>
> I think I'll have to do this at some point, but as WXL is fairly dependant
> on using icons I think I'll keep em until I can work out the best data
> structures etc to support all the current requirements and all the
> additional CSS requirements

I think that last comment is the root of your problem. BASIC does not support
complex and interrelated dynamic data structures, which makes what you are
trying to do very difficult. As a consequence of you are trying to move the
work on to the Wimp to simplify your data handling.

This will work up to a point, but with the complexity of web pages you will
be required to handle, its going to vastly exceed the ability of the Wimp to
handle the window efficently. Its also going to make extending the program
very tricky.

If you used a language such as C or preferably C++, you have the ability to
create structures directly reflecting the requirements of represending the
rendering of parsed HTML. It is then possible to write very efficent routines
to scan the data structures work out the coordinates of mouse clicks and
invalidation rectangles. You can then handle the drawing, and mouse overs
yourself far better than the Wimp can.

Ahthough all this is probably not much help if you are still using BASIC.

cfe...@freeremoveuk.com.invalid

unread,
30 Aug 2003, 06:11:5330/08/2003
to
In message <28d8b6294c...@pudy.websterxl.co.uk>
Andrew Pullan <a.pu...@zetnet.co.uk> wrote:

> On 22 Aug Tony Houghton wrote:
>
> > In <782d99254c...@pudy.websterxl.co.uk>,
> > Andrew Pullan <a.pu...@zetnet.co.uk> wrote:
> >

[snip]


>
> !ABC isn't very slow, it's that WXL is 800k of basic when blank lines
> and comments are removed. I suspect the number of variables etc means
> it's almost 100% memory bound so the greater memory bandwidth on an
> Iyonix makes a lot of differance.
>

M Seifert has a BASIC compiler, it might be worth asking if you could
use a demo?

If you are going to stay with BASIC would it be any gain to use WimpExt
module?
--
Colin Ferris Cornwall UK

Andrew Pullan

unread,
30 Aug 2003, 15:27:0930/08/2003
to
On 29 Aug druck wrote:

> On 29 Aug 2003 Andrew Pullan <a.pu...@zetnet.co.uk> wrote:
> > On 22 Aug Colin Granville wrote:
> > > Surely if you wrote an assembler routine that took the list of icons

> > > and plotted them using WimpPlotIcon,[snip]
> > [--8<--]


> > I think I'll have to do this at some point, but as WXL is fairly
> > dependant on using icons I think I'll keep em until I can work out the
> > best data structures etc to support all the current requirements and all
> > the additional CSS requirements
>
> I think that last comment is the root of your problem. BASIC does not
> support complex and interrelated dynamic data structures,

Not entirely true. It certainly doesnt support them easily as C does, but you
can use ! and | etc to simulate them. I wouldn't reccommend it though as
changing them is a pain!

> which makes what you are trying to do very difficult. As a consequence of
> you are trying to move the work on to the Wimp to simplify your data
> handling.

Kind of true at the start. However the changes since have introduced 36+
datastructures ofvarious sorts, not counting those that would be unions in
C.

Now I'm still using icons cos I dont really want the hastle of changing it
unless I'm certain what I'm changing it to is going to work in the future.

> If you used a language such as C or preferably C++, you have the ability to
> create structures directly reflecting the requirements of represending the
> rendering of parsed HTML.

If I was 100% sure a representation of the rendering of the HTML would allow
everything else to work correctly (CSS2, Javascript etc) then I'd use that.

Need to look at CSS and DOM documnts in detail before I can be certain of
that.

> Ahthough all this is probably not much help if you are still using BASIC.

Actually once I've got the data structures fixed, I can then do it in ARM
code. WXL already has several bits of ARM code to scan data structures, so
another one or two wont make much differance :-)

--
Andrew J Pullan
For replies by Email please put my middle initial in :-)

Tony Houghton

unread,
30 Aug 2003, 16:37:2330/08/2003
to
In <72493b2a4c...@pudy.websterxl.co.uk>,
Andrew Pullan <a.pu...@zetnet.co.uk> wrote:

> Now I'm still using icons cos I dont really want the hastle of changing it
> unless I'm certain what I'm changing it to is going to work in the future.

Wimp_PlotIcon will never go away, and even if you still use the
guaranteed-to-work font, sprite and plot calls inyour redraw loop I
reckon you can make a big performance improvement over the Wimp. It's
the scanning through huge numbers of icons to find which one to plot or
that's been clicked on that's the problem, not the actual plotting.

Or if you really want to stick to icons, how about my other idea of
dynamically creating just enough to handle the current visible area on
open/scroll events?

Justin Fletcher

unread,
30 Aug 2003, 19:26:1930/08/2003
to
On Thu, 21 Aug 2003, Andrew Pullan wrote:

> On 20 Aug Justin Fletcher wrote:
>

> > > > I'd be terrified if I had 100s of icons in a window, never mind
> > > > thousands.
> > >
> > > 1106 icons when I just checked www.iconbar.com All created automatically
> > > of course. :-)
> >
> > Christ, are you using one icon per word or something ?


>
> Nope! Well not intentionally. It's usually one icon per text line line.

> Except each HTML tag also causes a new icon to be used. iconbar is probably
> the worst cos its all tables I think. Most sites are a few hundred.

So<jkhdf> you're<randomtag> going<jshdk> to <dfss>be<sdfsd> hit (sorry,
that's too tiresome to keep up) rather badly by spam emails that do that
kind of thing ?

> > > > [ example thingy]
> > >
> > > Much more data would be read into the cache I think.
> > > -8<-
> >
> > I'm not sure that that's relevant (or even true). If during your redraw
> > loop whilst deciding what to redraw you're intending on searching through
> > the image data then I think you're doing something wrong with it. You
> > should only be looking through the region data whilst deciding what you
> > are redrawing.
>
> Well I was basing my figuesses on your coded example which looked like a
> simple top to bottom search. But Yes your right in reality there are lots of
> easy ways to cur the search time down if you get your data structures right.

Yeah; my code was really rudimentary just so that I could bung it on one
line - I wasn't being too thorough with my example because it really does
depend on what structures which are already present as to what exactly the
search would entail :-)

> > it - if you're /that/ bothered about the speed don't use BASIC for it.
>
> As it's redrawing is speed critical (or I consider it so), therefore once the
> code was worked out it would become ARM code somehow.
>
> > Best case with a perfect binary tree would be an average of 11 reads
> > (rather than 1100). Given, as I said, you can separate the rendering of
> > the window into horizontal strips this could be sped up hugely.


>
> Would probably be like that more or less. Although there are complications as
> always. e.g. column1 row1 in a table could be 2 screens high, column2 row1
> could be 1 text row high. There then may not be anymore in column 1. As on
> iconbar actually. The page is written top to bottom gradually workin left to
> right. Splitting the page into horizontal strips then becomes soemthing of a
> problem.
>

> You'd have to decide if a part of the table cell requires rendering, then
> decide which bits of the cell need rendering. (Actually you already said
> that I think!)

If you offload the rendering on a per-cell basis then (because cells are
rectangular in nature) then yeah that would be the best thing to do.
Doesn't help you for huge paragraphs of text. But then who actually
provides huge amounts of actual /content/ on the Internet anyhow :-)

> > Of course, that really does depend on how structured your code is.
>
> varies a lot. Pre C code, erm no! Though there's not a lot of that left now
> apart from the bit that creates all them icons.
>
> > > > Fortunately we're not bothered about non-SA systems, so this won't
> > > > matter.
> > >
> > > So that's RPC600's and A310's out then! as well as Iyonix :-)
> >
> > Fortunately such old machines we don't care about. Or if we did, we
> > wouldn't be writing in BASIC.
>
> Good Grief! Someone who already considers an Iyonix an old machine!! :-)

The former, rather than the latter.

--
Gerph {djf0-.3w6e2w2.226,6q6w2q2,2.3,2m4}
URL: http://www.movspclr.co.uk/
... Does anybody want to take me on ?

Justin Fletcher

unread,
30 Aug 2003, 19:35:0230/08/2003
to

TaskWindow does use PollIdle. When it's idle.

> 3) More often than not there is only ONE background task going on. If
> that task is using Wimp_PollIdle with a delay of 10cs and doing 10cs of
> processing every null event, then it is using approximately 50% of CPU
> time. What is happening during the other 50% of time? Absolutely
> nothing; the CPU is just kicking its heels. This is not a gain in
> efficency - in fact it is quite the reverse.

If you're using 50% of processor time rather than 10% then that's 50% of
the time that it needs to be running. Where power consumption is an issue
you don't want this to be the case. When the Wimp is idling (as it will be
if tasks have correctly specified their PollIdles) it will use less power.
So if you're not doing anything you should ALWAYS use PollIdle. If you're
polling continually for Nulls and processing on nulls you're going to hurt
the user. And if it's a laptop that may mean that they're going to
actually get burnt :-)

> 4) Many programs use Wimp_PollIdle as a simple method of controlling
> the proportion of CPU time that they use, yet this method falls down
> completely under even moderate processing loads. It doesn't require many
> background tasks running before the Wimp becomes incapable of keeping to
> the earliest return time passed to Wimp_PollIdle. In this situation
> the requested return times (and hence the relative task 'priorities')
> rapidly become meaningless.

They're requests. The user could have pressed F12 even. There's nothing
you can do about that and never has been. Even callbacks can affect the
time that the return takes place. This is why it's a request rather than a
guarenteed return time, same as OS_CallAfter.

--
Gerph {djf0-.3w6e2w2.226,6q6w2q2,2.3,2m4}
URL: http://www.movspclr.co.uk/

... Gentle voice that talks to you, won't talk forever.

Justin Fletcher

unread,
30 Aug 2003, 19:41:3830/08/2003
to
On Sat, 30 Aug 2003, Andrew Pullan wrote:

> On 29 Aug druck wrote:
>
> > On 29 Aug 2003 Andrew Pullan <a.pu...@zetnet.co.uk> wrote:
> > > On 22 Aug Colin Granville wrote:

[snip]

> > Ahthough all this is probably not much help if you are still using BASIC.
>
> Actually once I've got the data structures fixed, I can then do it in ARM
> code. WXL already has several bits of ARM code to scan data structures, so
> another one or two wont make much differance :-)

Surely that's just making more work for yourself ?

Write it in C, compile it up and link it as bin, then call the bits you
need from your BASIC as you see fit. Changing the structures is easier,
you've got a solid C basis for you code, should you decide you ever want
to use that in the future, and you can stop messing around with assembler
where you could use a compiled language to do the work for you. Then you
can worry about algorithms rather than register allocations, or unnamed
references to anonymous blocks of memory in BASIC.

--
Gerph {djf0-.3w6e2w2.226,6q6w2q2,2.3,2m4}
URL: http://www.movspclr.co.uk/

... Now, for some reason this feels wrong. Didn't I use to have a wall there ?

Andrew Pullan

unread,
2 Sept 2003, 16:27:2602/09/2003
to
On 30 Aug Tony Houghton wrote:

> In <72493b2a4c...@pudy.websterxl.co.uk>,
> Andrew Pullan <a.pu...@zetnet.co.uk> wrote:
>
> > Now I'm still using icons cos I dont really want the hastle of changing
> > it unless I'm certain what I'm changing it to is going to work in the
> > future.
>
> Wimp_PlotIcon will never go away, and even if you still use the
> guaranteed-to-work font, sprite and plot calls inyour redraw loop I
> reckon you can make a big performance improvement over the Wimp. It's
> the scanning through huge numbers of icons to find which one to plot or
> that's been clicked on that's the problem, not the actual plotting.

Actually it wasnt the future of wimp_ploticon i was concerned about, but
ensuring that wha I move to will cope with eveyrthing I'm going to have to do
with WebsterXL in future. (CSS2, layers, javascript 3.7) e.g. When I
originally wrote WXL there was no javascript so I didn't cater for it. It's
been a bit of a difficult fit!

> Or if you really want to stick to icons, how about my other idea of
> dynamically creating just enough to handle the current visible area on
> open/scroll events?

Erm! I suspect that would be harder than using a full windows worth. Eveyr
scroll would involve the creation and deletion of icons!!

--
Andrew J Pullan
For replies by Email please put my middle initial in :-)

dawn chorus(n): Nature's way of telling the programmer to go to sleep.

Andrew Pullan

unread,
2 Sept 2003, 16:22:0302/09/2003
to
On 31 Aug Justin Fletcher wrote:

> > > Ahthough all this is probably not much help if you are still using
> > > BASIC.
> >
> > Actually once I've got the data structures fixed, I can then do it in ARM
> > code. WXL already has several bits of ARM code to scan data structures,
> > so another one or two wont make much differance :-)
>
> Surely that's just making more work for yourself ?
>
> Write it in C, compile it up and link it as bin, then call the bits you
> need from your BASIC as you see fit.

Didn't think you could call C from basic. Unless it was a module or a
separate application.

Sounds like a goo idea, but I've no idea how to do it so I'm not inclined to
experiment. I crash the machin enough as it is!

--
Andrew J Pullan
For replies by Email please put my middle initial in :-)

Computers are like air conditioners. They stop working when you open windows.

Justin Fletcher

unread,
3 Sept 2003, 00:14:3903/09/2003
to
On Tue, 2 Sep 2003, Andrew Pullan wrote:

> On 31 Aug Justin Fletcher wrote:
>
> > > > Ahthough all this is probably not much help if you are still using
> > > > BASIC.
> > >
> > > Actually once I've got the data structures fixed, I can then do it in ARM
> > > code. WXL already has several bits of ARM code to scan data structures,
> > > so another one or two wont make much differance :-)
> >
> > Surely that's just making more work for yourself ?
> >
> > Write it in C, compile it up and link it as bin, then call the bits you
> > need from your BASIC as you see fit.
>
> Didn't think you could call C from basic. Unless it was a module or a
> separate application.
>
> Sounds like a goo idea, but I've no idea how to do it so I'm not inclined to
> experiment. I crash the machin enough as it is!

Compiled C's just normal machine code.

Justin's super-quick guide to creating code to use from other languages in
C... [probably inaccurate in a lot of places and glossing over specific
details in many others - be prepared to skip dull or plainly wrong
sections]

APCS allows for a number of variants. Lack of stack limits and stack
checking is one of them. This is what we want to use for our example C
code because it's a lot easier to work with from other languages (and
because you know what you're doing if you're linking in from other
languages). As a switch to the compiler this is -apcs 3/noswst (no
software stack checking). And because we want our code to be nicely
compatible with all systems, we build it as 32bit, so the switch becomes
-apcs 3/32/noswst.

Now, the 32bit switch means many things which you already know - mostly
that you're not preserving the state of flags over the call to your C
code from outside. It also means that internally it's not being maintained
over the function calls, but the bits inside that code you're not caring
about because... well that's the Compiler's business and you assume that
it knows what its doing.

For the purposes of this quick guide, I'm going to assume that you're in
USR mode for your code. It doesn't really change much but just use -fz if
you're building for use in SVC mode (don't worry, it's not likely to bite
you but it's just a little safer should you ever be clever).

So you're nearly set on /how/ to compile the code. You need the normal C
compiler command...
cc -c -apcs 3/32/noswst -o o.code c.output

Notice that I'm not using an include path here. The default include path
for system includes will still be present and we're not really all that
worried about that. However, you're NOT going to be using the C library.
Well, you might. But you'd have to re-write it, find another, or do
cunning things to link with SharedCLibrary.

If at this point you're asking yourself why you're not using the C
library, you may be looking at the problem from the wrong point of view.
The purpose here, is to produce some code in C that takes the work out of
maintaining it. C is easier than assembler to maintain. It's faster than
BASIC. The C library provides a lot of useful stuff, but you don't need a
lot if you're just manipulating algorithms.

So, then... lets look at what the C code has to be...

The C code itself is has to do what you want it to do. That's the crux of
this. So, lets assume for the sake of argument that you're wanting a
little routine that checks whether you're inside a polygon or not. Why am
I giving this as an example ? Because that's exactly what I use in my
little ImageMap checking module and I've got the code to hand. I'm going
to cite the entire code infact. It's small and anyone who wants to bitch
about posting code to the group can just fire away...

-------- c.poly
int InPolygon(int polygon[],int mx,int my,int points)
{
int lastx=polygon[points*2];
int lasty=polygon[points*2+1];
int yflag0=(lasty >= my);
int thisx,thisy;
int j,inside_flag,yflag1;

inside_flag = 0;
for (j=0; j<points+1; j++)
{
thisx=polygon[j*2];
thisy=polygon[j*2+1];
yflag1 = (thisy >= my);
if (yflag0 != yflag1)
if ( ((thisy-my) * (lastx-thisx) >=
(thisx-mx) * (lasty-thisy)) == yflag1 )
inside_flag = !inside_flag;

yflag0 = yflag1;
lastx=thisx; lasty=thisy;
}

return (inside_flag);
}
--------

Um... that's not commented, I'm afraid. Basically you pass in three
parameters.
polygon = A pointer to an array of points (x then y) which describe the
polygon we're checking
mx = mouse x position that we're checking
my = mouse y position that we're checking
points = number of points in the polygon - 1
... and you get back a flag to indicate if you're inside or not.

The maths behind this algorithm aren't amazingly complex but I couldn't
explain them - consult a text book or online guide for more details, but
this isn't really relevant to our example here.

So, you've got your little chunk of code and you've compiled it up. Using
something like :

cc -c -apcs 3/32/noswst -depend !Depend -throwback -o o.poly c.poly

And then we need to get this code to a state that we can use it. So we
create a binary image of the code...

link -bin -o bin o.poly

And from this we have a binary file that we can call directly. You can
look at the bin file at this point and see that what it's compiled to and
whether you could have written it better by hand. If you're reasonable at
assembler the answer should be 'yes' at this point. But you should also be
thinking to yourself how much easier the C is. If you're not seeing the
point then you might want to wander off and do something else at this
point. If not then lets roll on...

The code to this point can be found at :

http://homepage.ntlworld.com/justin.fletcher/CGuide/1/

which you might want to look at to see how this pans out rather than doing
it all yourself.

====


We're not wanting to call this code directly though. Because we're in
BASIC. Here's where you might need to know your APCS bits.

APCS (or ATPCS if you're wanting to bring Thumb into this, which I'm not)
defines the register bindings used by compiled code in order to interwork
different compiled code lumps. For each variant of the APCS standard the
code is (generally) incompatible. There's a few that are compatible so
long as you observe some restrictions but you'll want to go and read the
right specs if you're that bothered by what is and what isn't compatible.

Skip the next paragraph if you don't care about the description of the
APCS variant we use.

I mentioned above that we're not using stack checking. That changes the
variant of the APCS we use. We're also using the 32bit variant which makes
it easier to move the code around. We're implicitly using the
non-reentrant form of the APCS standard. If you want to know more about
that, against the right specs will help but suffice to say that this
allows a single block of code to be safely used by multiple clients. For
*this* example, I'm not dealing with the reentrant variant because it
makes the whole process a lot more fun and this is really only intended as
a quick guide. We're also using the variant of the FP code that the
compiler is shipped with (that's FPE2 for CC's up to around 5.30 or
something, and FPE3 for later ones; version numbers might be a little out,
off the top of my head). In this example we don't use FP code so it's not
an issue. Depending on who you target, you might want to retain FPE2
compatibility, or only support the later FPE3 code. That's not something
you should worry about right now though. We're using the frame pointer,
because it makes the code a little easier to follow (if you would prefer
to use the stack pointer instead, /nofp will do this - I've not tried this
so I can't say how readable or reliable the code produced is in this
form). And we're using the standard of passing floating point arguments on
the stack. This is the default for normal C code so it makes sense to
follow it. Again, if you're not using FP then it doesn't matter.

So, that's the APCS we're using.

What's that mean ?

Well... in terms of the registers we have the first 4 registers as general
purpose registers. These are used within the compiled for lots of
transfers and calculations, and they're also the registers that are used
to pass parameters to functions. More about this later. It is important to
know that these registers are corrupted when a function returns, though.

The next 7 registers (r4-r10) are treated as register variables within the
function. These are preserved over function calls and can therefore be
used as the compiler wishes for preserving results over the calls, etc.

r11 is the first register with a dedicated roll for this variant of APCS.
It is called the frame pointer and is used to reference arguments passed
on the stack and local storage on the stack.

r12 is a general purpose register, like r0-r3 and can also be corrupt on
return from a function call.

r13 is your stack pointer as you might expect.

r14 is the link address to return to, or a general purpose register. As
with most other assembler, it is assumed that this is corrupt on return
from function calls.

r15 is your program counter. As normal.

In APCS the registers have different names (r1-r3 => a1-a4, r4-r10 =>
v1-v7, etc) but you shouldn't worry too much at this second. You'll find
docs on these in good time.

So, there you have your registers that your C code uses. Let's quickly run
over what the APCS does about calling functions from a machine code point
of view...

If you want to pass no arguments there's nothing you need do. You just
call the function. And you get your result back in R0. For all versions of
the APCS you get your result back in R0. If you're returning a structure
things change slightly but we'll ignore that for this quick guide.

If you want to pass 1-4 arguments you put them in r0-r3. So a function
that passed two parameters would put the first in r0 and the second in r1.

If you want to pass more than 4 arguments then you pass the first 4 in
r0-r3 and the remainder are placed on the stack. So, lets say you're
passing 6 arguments. You place args 1-4 in r0-r3. You drop the stack by 8
bytes (4 * 2 because you're passing two more registers). You store arg 5
at sp+0 and arg 6 at sp+4. Then you call the function. When it returns,
you increment the stack by 8 to reclaim the space (of course you could
leave the stack lowered so that you can use it for other things, but
that's up to you).

For the sake of sanity, pass all your arguments as pointers in your
external-facing C interfaces. You can pass structures to the code if you
want, but you're going to have to do more work. Same as if you return
structures - easier to pass a pointer to a structure to fill in. Inter-C
calls can pass structures around quite happily and you can examine the
code produced to see how to do this, but don't worry for now.

Similarly, variadic functions may make your life tricky for external
facing code so don't bother for now.

So we've coverted how to call the C code from outside and what will
happen when it returns. Basically:
Stick your parameters in r0-r3 (and extra args on the stack).
Call the function.
Get back your result in r0.
r1,r2,r3,r12,r14 corrupt.

If you look back about at the binary output you got when you compiled it
(or downloaded from my site) you'll be able to see some parts of this
description in place for the entry and exit sequences.

However, we do want to use this with BASIC because, after all, we've
written our web browser in BASIC so obviously that's our preferred
language :-)

So we need to look at the what BASIC gives us when we call it. There's two
ways of calling machine code from BASIC. One is CALL. The other is USR.
CALL can pass parameters to the routines using variables, strings, etc- I
wouldn't worry about this because it's not as useful to the C coder as it
is to the assembler coder (you could always write routines to access the
variables from the C code once you're handy with integrating C and
assembler). USR can get a result back. Both can pass in 8 registers in
r0-r7.

The registers passed in by BASIC are :

R0-R7 A% - H%
R8 Pointer to BASIC's workspace
R9 Pointer to list of parameters (for CALL)
R10 Number of parameters (for CALL)
R11 Pointer to BASIC's string accumulator
R12 BASIC's LINE pointer (points to the current statement)
R13 Pointer to BASIC's full, descending stack
R14 Link back to BASIC and environment information pointer

As you can see, this is a little different to that expected by the C code.
What we can do here is to write a tiny little veneer to call our C code
from the BASIC. Because we know our little routine has 4 parameters and we
can pass them very easily in A%-D%, that's what we'll do. Which means that
we just have to preserve the flags around the call to ensure that we
return with V clear. If V is set on return an error will be generated and
it is easier for us if this doesn't happen.

So we have a nice simple veneer...

IMPORT InPolygon
call_InPolygon
STMFD sp!,{r14}
BL InPolygon
CMP r0,r0 ; clear V (don't care about other flags)
LDMFD sp!,{pc}

So, that's simple enough. The only bit that might be unclear is the use
of the 'IMPORT'. This ensures that the symbol 'InPolygon' which is
provided by the C code is able to be used in this file. If you don't
import the symbol, you can't use it. Similarly if you wanted to use a
routine in this file somewhere else in the C code, you'd have to EXPORT
it. We'll come to that later.

That's just one routine which was obviously quite simple. As a quick
example, say you had a function that took 6 arguments and you wanted to
pass them in A%-F%...

IMPORT SixParamsFunc
call_SixParamsFunc
STMFD sp!,{r4,r5,r14} ; push the 5th and 6th argument on to stack
BL SixParamsFunc
ADD sp, sp, #8
CMP r0,r0
LDMFD sp!,{pc}

We have to put this in an assembler file so that it can be called and that
means we need to use objasm. The parameters for objasm are very similar to
those for cc actually...

objasm -apcs 3/32/noswst -depend !Depend -throwback -o o.asm_poly s.asm_poly

However, if you try this with the snippet above you'll find it doesn't
work. Firstly objasm has to have an 'END' command at the end of the file
to ensure it doesn't just run off the end (that's just what it needs,
ok?). And secondly it needs to know what the stuff it's assembling is for
the output file, and what it's 'called'.

The object files we produce - that AOF files, that is - can contain a
number of areas within them which are named and have particular
attributes. The attributes we have to give are code are 'CODE' and
'READONLY' (well, because it is!). These attributes, together with the
name determine where in the output file the data will be placed. The names
are sorted alphabetically, and the C compiler puts code in 'C$$Code'. We
need (for reasons that will be obvious in a moment) to place our assembled
code before the C code. So we call the area '!!!!First' by placing the
following at the top of the file :

AREA |!!!!First|, CODE, READONLY

The | characters are to ensure that the name is treated as a string rather
than being terminated at the first non-symbol character. Just use them
like that for now.

So at this point you may want to compile and assemble the code and link it
with something like :

link -o bin -bin o.poly o.asm_poly

If you look at the bin file you'll see that this contains both the C code
and our little assembler veneer. And that the veneer is first in the file
- that's why we used the alphabetically earlier name for the area.

If you're lazy, skip to :

http://homepage.ntlworld.com/justin.fletcher/CGuide/2/

and you can save yourself actually doing any of that lot.

====

Now you've got your code to the point at which you can see how to call it.
All that remains to complete this little example is to actually do that.

First we want to set up a random shape to use as our test... That's nice
and easy because it's just a number of points stored in a block. We'll
even draw it so that we can see what we're doing...

----
REM Setup and draw a polygon
points%=5
DIM poly% points%*8
FORI=0TOpoints%-1
x%=RND(1024):y%=RND(1024)
poly%!(I*8)=x%
poly%!(I*8+4)=y%
IF I=0 THEN MOVE x%,y% ELSE DRAW x%,y%
NEXT
DRAW poly%!0,poly%!4
-----

All that does is just populate the memory block with a number of different
random positions so that we can pass it to the polygon routine. In a real
situation you'd actually put real data in there, otherwise you might
as well use RND(2)-1 instead of this polygon routine.

We load the code into memory from our binary file...
-----
REM Load code
SYS "OS_File",5,"bin" TO ,,,,len%
DIM mc% len%
SYS "OS_File",255,"bin",mc%,1<<31
-----

The little thing that might not be obvious there is the use of 1<<31 to
say that this file is Code so it should be synchronised. This ensures that
we don't try executing what was there before hand on a StrongARM (and
similar) system. Refer to SH for the definitions of the above SWIs (read
file info and load file).

Finally we use the stonkingly simple code to read where the mouse is and
then call the nice code we loaded to process it.

-----
REM Now, lets test the code
REPEAT
MOUSE B%,C%,b%
A%=poly%
D%=points%-1
in%=USR mc%
VDU30:PRINT"Inside polygon: ";in%
UNTIL 0
-----

And that, as they say, is it.

Well, for that example anyhow.

http://homepage.ntlworld.com/justin.fletcher/CGuide/3/

will catch you up at this point.

======

Now you need to know some things about what you can and can't do in C code
like this.

* You can't call the C library. Ok, so that may seem restrictive, but is
it really ? Not in general. You're using C as effectively a mechanism for
getting maintainable code and not just to get C library support. You want
standard C functions, you implement them.

What do you want ? strcpy ? well that's just a set of byte operations.
Write it in C or write it in assembler and call it... either way it's not
too complicated to implement.

printf ? Well, you're on ropier grounds here, but you can easily knock up
a little assembler routine to call XOS_WriteC or whatever and use that.
We'll come to SWIs in a little bit.

malloc ? yeah, that's a tricky one. Create a heap at the top of your BASIC
stack (hell, JFShared does this and it's not so complicated). If you're
writing a web browser then you've probably got your own little assembler
veneers for memory allocation so you just reuse them - you probably don't
even have to wrap them up in much; they'll probably already be compatible
unless they return results in r14 or r3 or something.


* You can't just reuse functions from the standard C usage in a
different form. If you think that redefining memcpy to draw a rectangle
you may find that calling it still copies some memory. The compiler can
make some assumptions. If you find things going a little odd and you've
redefined a standard function differently, check this before going on.


* You may have to provide some 'standard' functions yourself if you want
to do certain things. Division, for example. This is implemented by a
separate function, so you'll have to provide that function if you want
to divide two numbers. No big deal for a lot of things 'cos you can easily
avoid division when doing a lot of things in your code anyhow. Similarly,
you may find that structure assignments (copying a structure to another
structure) will invoke a function (_memcpy, IIRC) if the copy is large
(otherwise it'll do the copy inline).


* You don't get abort handling. If you access invalid memory, you get a
data abort. You don't get a stack backtrace. If you want it, you write it.
But that shouldn't matter too much, 'cos you didn't use the C you'd be
using assembler and be in the same state. You could always track back -
the method is the same as if you were in C; there's some old backtrace
bits I posted up at

http://homepage.ntlworld.com/justin.fletcher/SCL-BackTrace/

which I put up for Chris Bazley quite a few moons ago. You'd need to rip
out bits from that, but you could have something there.


* You don't get allocations of zero-init data areas. This may not mean
much to you, but avoid leaving areas unassigned if possible. That is, a
global variable declaration such as :

char buffer[256];

would allocate 256 bytes of zero-initialised data. However when you get
your binary image this space won't actually be allocated in the area, so
it'll corrupt anything after the allocated space if you tried to use it.
In this case, you could use something like :

char buffer[256]="";

to avoid this. Just remember to initialise your declared
non-local variables and you should avoid this problem.


So having gone through what you can't do, lets look at a problem that
we've caused by building the code as '-bin'.

Consider the simple code fragment :

----
static const char *version="v1.00 (03 Sep 2003)";

const char *get_version(void)
{
return version;
}
----

Nice and easy, don't you think ? Yes ? Well. It is, but this is binary
code we've built. So it's all based around being run from 0 (or from -base
if you had specified that when linking). Look at the bin produced by this
code.

http://homepage.ntlworld.com/justin.fletcher/CGuide/4/

has this bit done for you. Note that this is without the polygon bits I
was doing earlier.

You'll notice first that the code isn't at the start of the file. That's
one minor thing - if you used a little veneer like the BASIC example we
had then this won't matter so lets ignore that for now (we'll throw one
around it in a second). However, the code that loads the instruction
merely returns the value at address &24 back to the caller. This isn't
right - none of the code is relocated.

What's this mean ? Surely ARM is generally relocatable ? Well, most of it
is, but absolute references to memory aren't. Any references to global
or static data will be referenced through absolute addresses. So in this
case, the absolute address is &24 because we've not relocated it for where
it will be loaded in memory.

You probably won't care about the mechanisms and the method in which
addresses are constructed so I'm not going to go in to this. It's not
hard, but not worth it either. Suffice to say we need a relocation to be
performed before the code can be used. And this can be achieved quite
easily. We pretend the code is a relocatable module. Relocatable modules
have their relocation code appended to their end, along with the logical
addresses at which they will be relocated (a list of /what/ needs
relocating). This is quite simple to achieve because it just means we need
to link it as a module and then call the relocatable code before we use
the rest of the object.

Which is about the time at which we need to rethink how we provide our
assembler. If we want to jump lots of little lumps of C code then it will
be easier if we have a table of branch points at the start of our image.
This way we can just do something like...

CALL mc%+8

(or even have the 8 as a symbolic constant which will be compressed away
by the BASIC compression tools) to call the 3rd entry point in our C
code. So, that's what we'll do. We'll make the following entry points
available ...

+0 - relocation entry point for our code
+4 - return the version of this code

So, we have a little bit of assembler that does this :

----- s.asm
;
; Veneer for our C code
;

AREA |!!!!First|, CODE, READONLY

; Start of the output file
B doreloc
B call_get_version

IMPORT __RelocCode
doreloc
STMFD sp!,{r14}
BL __RelocCode
CMP r0,r0
LDMFD sp!,{pc}

IMPORT get_version
call_get_version
STMFD sp!,{r14}
BL get_version
CMP r0,r0 ; clear V (don't care about other flags)
LDMFD sp!,{pc}

END
-----

This is really quite simple - notice the same veneer for the BASIC
interface to that which we used earlier. The branch points have been
placed at the start so that they're based at the beginning of the image.

Once we link these bits of code together we get an object that is typed
as a module. In my example makefiles I settype this as Data so that if
its double clicked you get a message telling you that nothing handles it
(or in my case, it loads into Zap), rather than that the module is
corrupt. Not an important thing, but it might be frustrating if the
header for the module didn't look like it was corrupt and it blew the
machine up.

In order to test this little bit of code, we can reuse the code that
loaded our bin object. Immediately after that load, we call the relocation
code.

-----
REM Relocate it
CALL mc%
-----

and finally print out the message :

-----
REM Now, lets test the code
msg%=USR (mc%+4)
PRINT"Version: ";
REM Remember, this is a 0-terminated string, not CR-terminated
WHILE ?msg% <>0
VDU ?msg%
msg%+=1
ENDWHILE
PRINT
-----

The note is important - you'll probably be handling strings that are
zero-terminated in C. This makes life easier should you finally transfer
the bulk of the code to C-proper eventually. However, it may make things
more complex for your BASIC that expects CR terminated strings.
Alternatively you could deal with all strings as CR terminated in your C
code and make BASIC's life easier. That's really a design decision you'll
have to make yourself.

Yup, you've guessed it... you can find the bits up to now at :

http://homepage.ntlworld.com/justin.fletcher/CGuide/5/

=====

Let's quickly look at the assembler veneers we've got there... they're
bulky and awkward. So, we'll make a little macro of them. We can do this
quite simply with a little thought. It's important to make the veneers
simple so that we're not going to end up getting more tied up in ourselves
than we need be. I've taken a slightly complicated, but (I think) quite
sensible route of allowing the veneers to take up to 8 parameters (A%-H%)
and to pass these on to the C code as necessary. Rather than cite it here
and then give you a blow-by-blow description of it, just look at :

http://homepage.ntlworld.com/justin.fletcher/CGuide/6/

It's not much different to /5/ but it makes the assembler simpler and will
be much more usable if you were to have quite a few veneers to provide.

=====

At this point you're probably getting to the point where you'd wished I'd
not bothered with this 'quick' guide. However, there's a couple of further
things to point out about the use of C like this. If you've got your hands
on the ARM cookbook then you may have seen it before. The __swi extension
is specific to the Norcroft compiler and can be used for debugging and
real code to save time. It must be used with care, but it can save you a
lot of effort in re-writing veneers. It's not useful for all cases of SWIs
so it doesn't remove the effort completely but it makes things a lot
easier in some cases.

The syntax for this extension is simple :

<return type> __swi(<number>) <function name>(<parameters);

That is, you declare the function just like any other, except for the use
of the __swi extension. Instead of calling the named function, the
compiler will just inline the SWI you specified. Right there. To hell
with the side effects. So you'd better be sure that there aren't any
that'll affect APCS. Because you're using 32bit APCS you don't have to
worry about register corruption. You will probably want to call the non-X
variant versions of the SWIs however. This will cause an error to be
generated instead of V being set. Why is this useful ? Well, you can't
tell if V was set on return had you set the X bit.

-----
void __swi(0x3) os_newline(void);
void __swi(0x104) vdu4(void);
void __swi(0x2) os_write0(const char *str);

void debug0(const char *str)
{
vdu4();
os_write0(str);
os_newline();
}
----

Now if you call debug0 with a string it'll print it to the VDU4 cursor
followed by a newline. Printing to VDU4 is just my way of debugging, 'cos
it's all captured to my !Console application which makes it nice. For me.
Obviously you'll want to do something else. Well, probably. That's just an
example anyhow.

http://homepage.ntlworld.com/justin.fletcher/CGuide/7/

has the bits for this, showing a debug message printed when get_version is
called. Go on, have a look at the little function debug0. You should
notice the 3 SWIs placed inline.

Now, the limitations of __swi. As you know, you shouldn't have side
effects. That's not too hard to ensure. More difficult, though are the
input and output restrictions. Because it just sticks the SWI in place of
a Branch Link instruction, you are constrained by APCS. The only return
parameter is in r0. The only input parameters are in r0-r3. This means
that if you want to get out an answer from r1, you can't. Or if you need
to pass 5 parameters, you can't.

However, there is an alternative solution to this problem. Well an
alternative other than to write your own veneers, that is. I don't like
OSLib. The main reason I don't like it is the friggin' huge length of time
it takes to build. Twice. And then the time it takes to link anything
against it. But, for this purpose it's utterly ideal and wonderful to use.
Even given its huge size when you link against it. Really, its nice. OSLib
provides you with those SWI veneers you can directly link against. Those
which it can inline it will. You can't ask for more :-) Well you could,
but Peace On Earth and A Safe Full of Gold isn't going to happen.

You're going to have to think back to about 2:10 am when I wrote about the
-fz switch now... If you were compiling this code for SVC mode those SWI
calls would be corrupting R14. By default, the compiler 'knows' that SWIs
don't corrupt R14. However, -fz tells it that they do. This ensures that
the SWIs preserve R14 around themselves. This may not be too important for
many functions, but if the function were to be optimised without this
knowledge you might end up with something like :
SWI OS_Write0
MOV pc,r14

which would be fine in USR mode, but fatal in SVC mode. With -fz, r14 will
be preserved around such usage. All my examples use -fz just to ensure
that this is safe for whatever use you put it to.

So there you have simple SWI calls. You probably won't care too much about
SWIs most of the time, because you're dealing in algorithms, etc. Unless
of course you're implementing (say) a redraw loop in C. Then you need a
few SWI calls for the actual operations you do during that loop - plotting
text, locating sprites to render, etc, etc.

=====

Finally - really finally - there's the issue of global data. As I've
mentioned, the global data requires that you use relocation. That's all
great and that but if you're not keeping your 'main' data in the C then
that doesn't help you much. Invariably you have a lot of BASIC structures
that you keep assigned together and manipulate from BASIC alone. The
simplest way to make your structures from BASIC available to C is to place
them in a block of memory and pass this to the C code as a parameter.

Let's for the sake of argument say that we've got a linked list of
'things' that we want to pass to the C code. Usually it lives in a
variable 'list%'. We want to move this into the C so that we don't have to
mess in the C code as much. We have two choices. Change all occurances of
'list%' to directly manipulate a structure that we pass to C. Or assign
the value of list% into that structure before we call the C code that uses
it. The former can be painful if there's a lot of use in the BASIC. The
latter however can be slower if a lot of variables need to migrate across
to the C representation.

This is just an example of how you might implement a function to sort the
list through C. We'll assume that the C code needs the global memory for
something else as well, although in this case we'll just use it to return
the number of entries as a side effect.

----
DIM globalmem% 8
REM +0 = list% value
REM +4 = number of items in list (after sorting)

DEFPROCsort_list(list%)
!globalmem%=list%:REM Set up the global memory for the C code
A%=globalmem%
CALL mc%+mc_sort%
list%=!globalmem%:REM Read back the value from the C code
PRINT "Sorted ";globalmem%!4;" items"
ENDPROC
----

Strictly the return parameters would have been better returned using USR
but I'm trying to demonstrate something, ok ?

The C code would look something like this :

----
typedef struct globalmem_s {
listdata_t *list;
int nitems;
} globalmem_t;

void sort(globalmem_t *globalmem)
{
int counted=0;
/* Stuff... */
globalmem->nitems = counted;
}
----

This is simple but can be made even simpler. Or more complex, depending on
how you think of it. The Norcroft extension __global_reg can be used to
declare that a register /always/ contains a variable value. Code compiled
like this can be more complicated in some regards but it can get you some
performance gains as well as making it look cleaner to the eye reading the
code produced.

In our case, you might want r7 to always contain a pointer to some global
structure. That's H% from your BASIC code. That restricts the number of
parameters you can pass, but you also shouldn't need as many parameters.

You might achieve this something like this :

----
DIM globalmem% 8
H%=globalmem%
REM +0 = list% value
REM +4 = number of items in list (after sorting)

DEFPROCsort_list(list%)
!globalmem%=list%:REM Set up the global memory for the C code
CALL mc%+mc_sort%
list%=!globalmem%:REM Read back the value from the C code
PRINT "Sorted ";globalmem%!4;" items"
ENDPROC
----

Notice that H% is initialised at the start of the code and we assume it is
never modified in the BASIC.

----
typedef struct globalmem_s {
listdata_t *list;
int nitems;
} globalmem_t;

globalmem_t __global_reg(4) *globalmem;

void sort(void)
{
int counted=0;
/* Stuff... */
globalmem->nitems = counted;
}
----

Here you see that there isn't any parameter passed to sort; globalmem is
treated as a global value which does not need to be loaded from memory.
The register is used directly instead.

I've not done you an example for this one. You might like to play with it
yourself. It's really quite

There is a further method of sharing the data between BASIC and C -
implement a way to call the BASIC functions off the r14 to read the
variables directly. However this is a little more complex and deserves a
whole article in its own right :-)

=====

Ok, I lied. This is the finally. When you're debugging your code you might
find that leaving the function signatures active is a good idea - you can
see which function is where and what you're doing when things go bang.
When you're done, I'd like to suggest that leaving them in is useful even
in the field. You might disagree, so use -ff to remove them from
production code. Up to you. I prefer them being left in.

And also the methods described in this document also apply to linking C
code in to assembler-based code. You just write it in your C with nice
structures and then stick a few veneers between your BASIC and Assembler
to make it all gel nicely.

=====

Obviously this post will be complained at for being overlong and I
wouldn't doubt that there are technical inaccuracies in it, so if you want
to shoot it down over these things, feel free. Probably typos and
gramatical mistakes too. You could complain about them as well, but you'd
do better to complain about the technical bits, 'cos otherwise it's a bit
pointles this being csa.programmer and it might as well be csa.pedants.

Apologise to all who didn't care... I ramble and I don't describe things
well, so feel free to complain about that, too :-)

--
Gerph {djf0-.3w6e2w2.226,6q6w2q2,2.3,2m4}
URL: http://www.movspclr.co.uk/

... So I will light a candle for you. Keep it burning in the night.
And pray that you are alright.

Jeremy C B Nicoll

unread,
3 Sept 2003, 04:33:5903/09/2003
to
In article <Pine.LNX.4.55.0309030028420.3671@buttercup>,
Justin Fletcher <justin....@ntlworld.com> wrote:

> Justin's super-quick guide to creating code .....

Fascinating! This is definitely an article to keep.

I was puzzled by one thing. In the example:


> So, we have a little bit of assembler that does this :

> ----- s.asm
> ;
> ; Veneer for our C code
> ;

> AREA |!!!!First|, CODE, READONLY

> ; Start of the output file
> B doreloc
> B call_get_version

> IMPORT __RelocCode
> doreloc
> STMFD sp!,{r14}
> BL __RelocCode
> CMP r0,r0
> LDMFD sp!,{pc}

What would one actually need to have at __RelocCode for the code
concerned to achieve relocation? [My experience of this sort of thing
is only in ibm mainframe code where relocatable code has this done for
it by the OS when code is loaded into storage - the idea of an
un-relocated module doing it itself is alien to me.]

[chomp]

> Obviously this post will be complained at for being overlong

Not by me - we don't all know all of this already.

--
Jeremy C B Nicoll - my opinions are my own.

Stewart Brodie

unread,
3 Sept 2003, 05:35:1603/09/2003
to
Jeremy C B Nicoll <Jer...@omba.demon.co.uk> wrote:

> I was puzzled by one thing. In the example:
>
> > So, we have a little bit of assembler that does this :
>
> > ----- s.asm
> > ;
> > ; Veneer for our C code
> > ;
>
> > AREA |!!!!First|, CODE, READONLY
>
> > ; Start of the output file
> > B doreloc
> > B call_get_version
>
> > IMPORT __RelocCode
> > doreloc
> > STMFD sp!,{r14}
> > BL __RelocCode
> > CMP r0,r0
> > LDMFD sp!,{pc}
>
> What would one actually need to have at __RelocCode for the code
> concerned to achieve relocation? [My experience of this sort of thing
> is only in ibm mainframe code where relocatable code has this done for
> it by the OS when code is loaded into storage - the idea of an
> un-relocated module doing it itself is alien to me.]

The linker adds the __RelocCode function and necessary relocation
information to the linked binary output if you IMPORT the __RelocCode symbol
into the AOF file.

There are lots of extra symbols created by the linker at link-time which you
can IMPORT and use, but very few of these are code - mostly these are just
data like *$$Base and *$$Limit for each area of code. Usually you see
C$$Code$$Base, C$$Data$$Base etc., but for the code above you'd have
!!!!First$$Base and !!!!First$$Limit, which you could import and use if you
needed to know the address range occupied by the veneer.


--
Stewart Brodie

Tony van der Hoff

unread,
3 Sept 2003, 05:58:5803/09/2003
to
On 3 Sep 2003, in message <Pine.LNX.4.55.0309030028420.3671@buttercup>,
Justin Fletcher <justin....@ntlworld.com> wrote:

[snip]


>
> Justin's super-quick guide to creating code to use from other languages in
> C... [probably inaccurate in a lot of places and glossing over specific
> details in many others - be prepared to skip dull or plainly wrong
> sections]
>

[snip]


>
> Obviously this post will be complained at for being overlong and I
> wouldn't doubt that there are technical inaccuracies in it, so if you want
> to shoot it down over these things, feel free. Probably typos and
> gramatical mistakes too. You could complain about them as well, but you'd
> do better to complain about the technical bits, 'cos otherwise it's a bit
> pointles this being csa.programmer and it might as well be csa.pedants.
>
> Apologise to all who didn't care... I ramble and I don't describe things
> well, so feel free to complain about that, too :-)
>


Thank you, Justin, for an extremely useful and informative article.

Shame there's no opposite to a death-threat (life-threat?); you deserve all
plaudits.

Cheers,

--
Tony van der Hoff | MailTo:to...@mk-net.demon.co.uk
Buckinghamshire, England | http:www.mk-net.demon.co.uk

Justin Fletcher

unread,
3 Sept 2003, 08:05:5903/09/2003
to
On Wed, 3 Sep 2003, Jeremy C B Nicoll wrote:

> In article <Pine.LNX.4.55.0309030028420.3671@buttercup>,
> Justin Fletcher <justin....@ntlworld.com> wrote:
>
> > Justin's super-quick guide to creating code .....
>
> Fascinating! This is definitely an article to keep.

Thanks. I expect that the URLs referenced will remain for quite a while -
they're only small. I might zip up the content at some point though.

> I was puzzled by one thing. In the example:
>
>
> > So, we have a little bit of assembler that does this :
>
> > ----- s.asm
> > ;
> > ; Veneer for our C code
> > ;
>
> > AREA |!!!!First|, CODE, READONLY
>
> > ; Start of the output file
> > B doreloc
> > B call_get_version
>
> > IMPORT __RelocCode
> > doreloc
> > STMFD sp!,{r14}
> > BL __RelocCode
> > CMP r0,r0
> > LDMFD sp!,{pc}
>
> What would one actually need to have at __RelocCode for the code
> concerned to achieve relocation? [My experience of this sort of thing
> is only in ibm mainframe code where relocatable code has this done for
> it by the OS when code is loaded into storage - the idea of an
> un-relocated module doing it itself is alien to me.]

Ah, this was obviously clear to me that I'd explained it at the time.

When you create relocatable code in a module with -rmf, the linker will
append a lump of code called __RelocCode which is used to relocate all the
references. It is immediately followed (at the end of the image) by...

* the current position at which the table is logically located
* a list of the addresses of all the addresses which need to be relocated

When you first link the module all the addresses will appear to be based
at &8000. So the 'current position' will be &8000 + offset from start of
code to the table. All the other addresses listed will have the same
offset applied to them. The relocation code loads this 'current position'
and replaces it with the actual address that it lives at. The
actual position is then subtracted from the position, giving an offset
that must be applied to all the addresses. The code then goes through the
table adding on this offset to all the addresses pointed at in the table.
Thus, the entire list of addresses is relocated.

Once relocated in this manner, the table itself is still consistent
because it now describes the logical position of the code as being its new
location - if you were to examine the table after the relocation has taken
place you would see all the addresses now refer to physical locations.
Should that code be then saved out and the reloaded elsewhere (or
whatever) the relocation code would still work. This only applies
immediately after the relocation code has been called - once you start
using the code itself you change its state and it's then dependant on your
design as to whether the code can be restarted in this manner.

IF you wanted it to be completely restartable you might use the
relocatable module method of compilation (-zM to the compiler) or the
reentrant variant of APCS (-apcs 3/reent). Neither is simple to describe
but they do have benefits. I wouldn't personally use either when linking
with another language unless I was very confident about them - I
understand them and have used them myself but they take a lot more
thinking about.

This is OTTOMH and I haven't double checked this one, so it's possible
that I'm ignoring flags and other special features of the table off the
top of my head. But that's the basic gist of it.

The code examples I've given apply to C and not to C++ - you need to do
more things to make the C++ code work but the quick notes I put together
were getting a little long. Plus it was getting close to 5.

--
Gerph {djf0-.3w6e2w2.226,6q6w2q2,2.3,2m4}
URL: http://www.movspclr.co.uk/

[ All information, speculation, opinion or data within, or attached to,
this email is private and confidential. Such content may not be
disclosed to third parties, or a public forum, without explicit
permission being granted. ]

Philip Ludlam

unread,
3 Sept 2003, 19:30:5803/09/2003
to
On 3 Sep, in message <Pine.LNX.4.55.0309030028420.3671@buttercup>
Justin Fletcher <justin....@ntlworld.com> wrote:

[snip]

>Justin's super-quick guide to creating code to use from other languages in
>C...

I'ld hate to see the long version :-) !

[snip]

>The registers passed in by BASIC are :
>
>R0-R7 A% - H%

[snip]

The one thing that got me when I read this was a bit near the end:

>In our case, you might want r7 to always contain a pointer to some global
>structure. That's H% from your BASIC code. That restricts the number of
>parameters you can pass, but you also shouldn't need as many parameters.
>
>You might achieve this something like this :
>
>----
>DIM globalmem% 8
>H%=globalmem%
>REM +0 = list% value
>REM +4 = number of items in list (after sorting)

[snip]

>----
>
>Notice that H% is initialised at the start of the code and we assume it is
>never modified in the BASIC.
>
>----
>typedef struct globalmem_s {
> listdata_t *list;
> int nitems;
>} globalmem_t;
>
>globalmem_t __global_reg(4) *globalmem;
>
>void sort(void)
>{
> int counted=0;
> /* Stuff... */
> globalmem->nitems = counted;
>}
>----

Not being able to find a definition of __global_reg() I am firstly
womdering where I might find it.

And secondly, shouldn't it be passed the value 7 to correspond with r7
and H% as H% is a ptr to globalmem?

Yours,

Phil L.
--
http://www.philipnet.com http://director.sourceforge.net

Justin Fletcher

unread,
3 Sept 2003, 20:17:1903/09/2003
to
On Thu, 4 Sep 2003, Philip Ludlam wrote:

> On 3 Sep, in message <Pine.LNX.4.55.0309030028420.3671@buttercup>

@buttercup ? Excuse me, that sucks. 'world unique' ? I don't think so :-(

> Justin Fletcher <justin....@ntlworld.com> wrote:
>
> [snip]
>
> >Justin's super-quick guide to creating code to use from other languages in
> >C...
>
> I'ld hate to see the long version :-) !

It'd be a lot drier and it'd probably make a lot more sense :-)
I did kinda get carried away there, though.

It's a Norcroft specific feature that you can find documented in some
versions of the ARM SDK documentation, and the Aquarius pre-release notes.
I don't remember if it's in the normal C manual itself but off the top of
my head I don't believe it is.

I have found a few references to the use of the __global_reg usage in a
quick google search, but the most useful has to be the ADS_CompilerGuide_D
PDF which is ARM DUI 0067D; see page 3-11 (PDF page 67).

> And secondly, shouldn't it be passed the value 7 to correspond with r7
> and H% as H% is a ptr to globalmem?

Registers 0-3 (a1-a4) are general purpose registers and therefore cannot
be remapped. The register we want to remap is r7, which is known - in APCS
- as v4, so '4' is the logical register we're using as our global
register. The use of the __global_reg is something you'll just have to be
careful with. It's very useful when you're integrating a load of C code
into an assembler module - all your veneers to the C code effectively
become :

Push "r1-r3,r10,r12"
MOV r10, r12
BL bit_of_c
Pull "r1-r3,r10,r12"

Or something similar (I use a macro that makes such things easier anyhow).
Here, I'm using r10 as the global register and in one of the .h files I
describe the entire module's workspace in terms of C structures, or at
least the bits that I need to access.

Do remember, though, that using the __global_reg directive will directly
affect the object code's compatibility with other APCS variants. You have
to ensure that the directive is used consistently in all the code you
link against. You can interwork the code with different usage of
__global_reg but you just need to keep yourself sane whilst doing so.
Still, it's simpler than following through reentrant code.

As an aside, I also recommend reading ARM DAI 0034A which, albeit quite
old, contains handy hints for writing C code that's ARM-friendly. It's not
huge, and you get used quite quickly to thinking about what you're doing
in terms of register allocations, etc anyhow. In general a better
algorithm always wins over a poor algorithm tailored for ARM, both in
readability and portability. But that doesn't mean you should be sloppy
:-)

Is that a little clearer ?

--
Gerph {djf0-.3w6e2w2.226,6q6w2q2,2.3,2m4}
URL: http://www.movspclr.co.uk/

... I can't seem to find myself again. My walls are closing in.

Jeremy C B Nicoll

unread,
4 Sept 2003, 03:25:2004/09/2003
to
In article <Pine.LNX.4.55.0309031240360.6861@buttercup>,
Justin Fletcher <justin....@ntlworld.com> wrote:

> Ah, this was obviously clear to me that I'd explained it at the time.

> When you create relocatable code in a module with -rmf, the linker
> will append a lump of code called __RelocCode which is used to
> relocate all the references. It is immediately followed (at the end
> of the image) by...

Ah, I see. That's good; I'd got the impression that the user had to
write the code to do this, but having it generated automatically makes
much more sense. Thanks again.

Jeremy C B Nicoll

unread,
4 Sept 2003, 03:28:1104/09/2003
to
In article <Pine.LNX.4.55.0309040040140.22204@buttercup>,
Justin Fletcher <justin....@ntlworld.com> wrote:

> ... ARM DUI 0067D ... ARM DAI 0034A

What are these?

Justin Fletcher

unread,
4 Sept 2003, 11:12:1204/09/2003
to
On Thu, 4 Sep 2003, Jeremy C B Nicoll wrote:

> In article <Pine.LNX.4.55.0309040040140.22204@buttercup>,
> Justin Fletcher <justin....@ntlworld.com> wrote:
>
> > ... ARM DUI 0067D ... ARM DAI 0034A
>
> What are these?

ARM documentation - see the ARM site; their documentation is mostly free
for download. DUI 0067D is 'ADS Compiler Guide release 1.2', and DAI 0034A
is 'Writing efficient C for ARM'.

--
Gerph {djf0-.3w6e2w2.226,6q6w2q2,2.3,2m4}
URL: http://www.movspclr.co.uk/

... I often wonder, how we look in other people's eyes.

Timothy Baldwin

unread,
4 Sept 2003, 19:27:3704/09/2003
to
In message <d2f3602c...@philipnet.com>, Philip Ludlam
<ne...@philipnet.com> wrote:


> Not being able to find a definition of __global_reg() I am firstly
> womdering where I might find it.

End of Chapter 6 "C implementation details" in the Acorn C/C++ manual.

--
Member AFFS, WYLUG, SWP, ANL, Leeds SA, Leeds Anti-war coalition
OpenPGP key fingerprint: D0A6 F403 9745 CED4 6B3B 94CC 8D74 8FC9 9F7F CFE4
No to software patents! No to DRM/EUCD - hands off our computers!

A.D.Hodgkinson

unread,
5 Sept 2003, 08:13:0105/09/2003
to
Andrew Pullan <a.pu...@zetnet.co.uk> wrote in message news:<a6c87e234c...@pudy.websterxl.co.uk>...

> Any other methods that I've not thought of?

1) Use Wimp_PlotIcon as suggested. Yes, you'll have to work out which
icons to plot. Many suggestions have been made as to how you could
get this to go reasonably fast. Give it a try, anyway.

For any icons that require a change when the pointer passes over
them, e.g. links, forms fields etc., create real icons. So on a
typical page you'll have tens of 'real' icons, allowing you to let
the Wimp handle all the click detection etc., and hundreds of
'virtual' icons, reducing the load.

2) Meanwhile, make your main window two windows. The main display area
in the parent window is a no-bounds-bit set, tool-less pane window.
Draw all your icons and plot into that pane window. When you delete
the page, just throw away your pane window and re-create it. Since
the pane is a tool-less no-bounds-bit window it should be easily
and reliably possible to move it into the relevant location for the
parent window. On the nested Wimp, you can even have the Wimp do all
the child/parent handling for you.

Now you've reduced the Wimp load by having few real icons, and made
the deletion of even those nice and fast by throwing away the whole
window in one lump. The trade-off is a slightly nasty use of a pane
which'll "lag" in the usual way on old non-nested Wimps, and a small
amount of thinking to do about how the scroll bar will work.

Personally I really do think you ought to move your redraw to custom made
routines. I now understand why Webster could ever had a bug that meant when
you changed fonts in the page, the Desktop font might get changed too! I'll
be honest with you - IMHO, doing the browser in the way you have is a really,
really hideous solution. Almost cunning in a twisted way :-) but doomed to
always work in a clunky way. The Wimp's just not designed to be treated like
that, and you know what RISC OS is like - program it in the way its intended
and it's great, but try and do something in a way it doesn't like, and it can
be a complete and utter pig.

If you're ever planning on re-writing the browser in 'C' or 'C++', then
presumably you would be dropping the odd icon-based implementation. Why not
make a start on your redraw routines now, effectively prototyping them in
BASIC? Or even start in C - see Justin's "super-quick" guide for details. I
would personally shy away from a hybrid approach as it'd waste a lot of time
in the short term on debugging the basic mechanics of the calling interface
and rewriting routines that would normally be available from the SCL. Still,
it's there if you want it.

--
TTFN, Andrew Hodgkinson (on behalf of myself, not my employer)

"Hold on tight, lad, and think of Lancashire Hotpot!" - A Grand Day Out

Philip Ludlam

unread,
5 Sept 2003, 06:53:3505/09/2003
to
On 5 Sep, in message <9cuk21-...@bfg.reinhouse.freeserve.co.uk>
Timothy Baldwin <t...@reinhouse.freeserve.co.uk> wrote:

>In message <d2f3602c...@philipnet.com>, Philip Ludlam
><ne...@philipnet.com> wrote:
>
>
>> Not being able to find a definition of __global_reg() I am firstly

>> wondering where I might find it.


>
>End of Chapter 6 "C implementation details" in the Acorn C/C++ manual.

And there I was looking for a prototype in the header files.
Silly me.
:-)

Yours,

i ou a uea i e a o ie e a o a a oue oae

Tim Rowledge

unread,
5 Sept 2003, 16:18:3705/09/2003
to
In message <Pine.LNX.4.55.0309040040140.22204@buttercup>
Justin Fletcher <justin....@ntlworld.com> wrote:

> On Thu, 4 Sep 2003, Philip Ludlam wrote:

> > Not being able to find a definition of __global_reg() I am firstly
> > womdering where I might find it.
>
> It's a Norcroft specific feature that you can find documented in some
> versions of the ARM SDK documentation, and the Aquarius pre-release notes.
> I don't remember if it's in the normal C manual itself but off the top of
> my head I don't believe it is.

I was the person that persuaded the Acorn guys (Lee Smith? Harry
something-or-other?) to add this feature back in '89 in order to help
support my work on Smalltalk. By keeping the virtual machine globals
that pointed t the v-pc, v-sp etc in global registers we got a roughly
30% speedup overall. I recently got the same optimisation working for
Squeak Smalltalk and got... the same sppedup :-)

It's pretty simple to use. You could take a look at the RISCOS specific
files in the Squeak sources to get an example of usage. See
http://squeak.sourceforge.net and fetch or browse the 'platforms'
module.


tim
--
Tim Rowledge, t...@sumeru.stanford.edu, http://sumeru.stanford.edu/tim
Strange OpCodes: BOZO: Use Multics operating system

David Mullard

unread,
5 Sept 2003, 18:06:1705/09/2003
to
In article <Pine.LNX.4.55.0309030028420.3671@buttercup>, Justin Fletcher
<justin....@ntlworld.com> wrote:
> lots - all snipped

Thanks for all of that Justin.

I think you may have solved a related problem I have been chasing around
for ages. Effectively, dynamically linking. What I want to do is, from a
module, load some C into application memory which would consist of
functions that can be called from the module. It would be a variant on
what you do here. A routine in the module could read the binary into
application memory, and call the relocation routine. The functions could
be either listed at the beginning, as you have done, or as an extra to the
relocation veneer, I could call a SWI back into the module to register
them. It's a pity I don't have the SharedClibrary functions though
because, in my case, I would be thinking of some fairly extensive code.
Is there no way to initialise Stubs just to get the function calls
working? What is needed is an independent library of the standard C
library functions. I wonder if they could be lifted from the Unixlib code
:) It is GPL I think.

BTW, don,t let the nutters get to you. Most of us know and appreciate
what you, and others like you, do for RiscOS.

--
Dave Mullard <Da...@mullard.net>

0 new messages