Source code for Stopwatch
=========================

The source code for this program is split between seven files for ease of
editing, named SW_Source and SW1 to SW6. The source code is written using
the ARM assembler built into the BBC BASIC interpreter within RISC OS; hence
all the files are BASIC files.

The master file is SW_Source. It is this file which is run to assemble the
program. The other files are added to it in memory using BASIC's LIBRARY
command.

2 1/2 pass assembly
===================

Within each file, the assembly language subroutines are contained in BASIC
procedures. This allows the use of BASIC local variables to represent those
labels that are only referenced from within the subroutine. By this means,
it is possible to give these labels simple names such as 'loop', 'exit' etc.
which may well be used elsewhere in the program. In order to use these local
variables, it is necessary to add a third pass to the assembly of the
subroutine. For this reason, some parts of the program are assembled with
two passes and some with three, which is why I call the technique "2 1/2
pass assembly". It is described in my article in RISC User 11:8.

The master source file first defines various parameters of the program.
These are at the start of the file so that they can easily be found and
altered. PROClibrary then adds the other files to the program and assembly
begins.

The main program loop is assembled first, as it includes the entry point
into the program, followed by all the subroutines in procedures, whose order
is not critical to the operation of the program. Finally, the Info box and
menu data codes are added to the end of the file. This is the end point of
the assembled file that is saved. The assembly pass then defines addresses
for the global variables, the Wimp poll data block, the sprite area, the
save area (used when switching the VDU output to the sprite) and the stack.
The global variables are defined by their offset from the start of the
global variables area and are loaded and saved using R12 which is given the
name vars.

The subroutines are contained in files SW3, SW4 and SW5. Each of these files
starts with a master procedure which calls all the procedures in the file
PROCassem_procs calls these master procedures and so assembles all the
subroutines.

Main program (file SW1)
============

This consists of a call to the initialisation subroutine, the Wimp_Poll
loop, routines to shut down the program and reopen the Info box if it is
dragged, together with a simple error handling routine.

All SWIs are called using their X-form and are followed by a BVS error
command in case any errors are returned by them. There is no other error
generation in this program and, in theory, no errors should occur when
calling SWIs so the program does not try to survive if an error occurs; all
errors result in a shutdown.

Note that the Wimp_Poll loop includes an emulation of BASIC's CASE ... OF
... ENDCASE structure, which occurs in several other places, notably when
dealing with mouse clicks. This is achieved by setting R14 to the required
return address (following 'ENDCASE'), checking the value of the variable in
question (the 'WHEN' lines) and calling appropriate subroutines with a
simple branch instruction, rather than a BL instruction.

File SW3
========

This file is mainly concerned with routines connected with Wimp operation.

During initialisation, the Wimp slot is reduced to the minimum that the
program needs using the SWI Wimp_SlotSize. This does the job usually done by
the WimpSlot command in the !Run file. On a Risc Pc or later machine, with
4k memory blocks, this will be 8k. On an older machine, it will be the size
of one memory block, usually 32k.

The icon contains a sprite which is created in a user sprite area within the
program Wimp slot and drawn by switching the VDU output to the sprite. This
is dealt with by routines in file SW4.

The various combinations of button presses and mode changes are handled by
the mouse_click subroutine. The mouse coordinates within the sprite have to
be calculated, partly to determine whether the click is on the centre or the
border, and partly to determine which digit is clicked on in countdown
pre-setting mode. Because the icon bar can be scrolled, the subroutine calls
Wimp_GetWindowState to get the x scroll offset (this call can only be made
under RISC OS 3 or later). Part of the stack is used as a temporary data
block for this call.

Following a check for a click on the menu button, the current mode number is
checked in one of three 'CASE ... OF ... ENDCASE'-type structures:

1. Adjust clicked on border
2. Select clicked on border
3. Select or Adjust clicked in centre.

Depending on which mode is currently in operation, an appropriate routine is
called, identified by a label such as 'border_adjust3', border_select1' or
'centre0'. Where an identical operation is carried out for several
combinations of parameters, all the appropriate labels reference the same
bit of code. The two labels 'select_count_down' and 'select_count_up' are
called by menu selections.

By moving these labels around, it is possible to modify the behaviour of the
program.

Most button presses change the operating mode; some do additional things.
When changing to mode 1 (stopwatch running), for example, the current
monotonic time is read and made the value of variable start_stop_time. When
starting the countdown mode, the preset time is added to the current
monotonic time and this becomes the value of start_stop_time.

Counting operations have Wimp_Poll null reason codes enabled; for all other
modes, they are masked out. When a null reason code is received, the current
monotonic time is read and either subtracted from the value of
start_stop_time or vice versa, depending on whether the count is down or up.

The subroutine set_mode is called with the mode number in R0. This
subroutine performs three tasks, setting the mode number variable, redrawing
the sprite with the appropriate colour border and either setting or clearing
bit 0 in the poll mask to enable or disable null reason codes. The colour
number is taken from individual bytes in a lookup table. Bit 7 of each byte
controls the state of bit 0 of the poll mask and hence whether the counter
runs or is frozen.

File SW4
========

This file handles creation and drawing of the sprite and the setting and
clearing of ticks on the menu.

Subroutine draw_sprite is called with the colour number of the border in R0.
If the mode is not being changed, this number is negative, in which case the
section of code that draws the border rectangle is skipped so that the
border is not redrawn unnecessarily.

The subroutine first draws a coloured rectangle covering the entire sprite
(if the border is being drawn), then a white rectangle to cover the centre
section and erase the previous digits. The time is then plotted, taken from
global variable time_bcd. This is in fact a word split into its four
individual bytes. The time count is stored in a semi-BCD form with one byte
each storing the values of hours, minutes, seconds and tenths. Subroutine
two_digit converts each of these values (except tenths) to two digits,
adding a leading zero if the value is less than ten.

Subroutine redraw_sprite draws the sprite and also ensures that the icon is
redrawn by calling SWI Wimp_SetIconState so that the change is visible
immediately.

Subroutine set_menu_ticks sets and clears the ticks on menu items 1 and 2
according to the current mode number by setting or clearing bit 0 of the
menu item flags. It is called before the menu is opened or when it is held
open by Adjust being clicked on it.

File SW5
========

Routines concerned with time are in this file.

Subroutine count_time is called each time control is returned from Wimp_Poll
with a null reason code. Current monotonic time is read and compared with
the start_stop_time variable, one being subtracted from the other depending
on the direction of the count. The result is the time to be displayed which
is passed to subroutine display_time.

If the timer is in countdown mode and the count has gone negative, the mode
is switched to mode 7 - timed out mode. In this mode, subroutine
display_time creates a beep once per second, when the seconds count has
changed since the previous call (this method was suggested by my son
Alexander as a way of ensuring that a beep occurs once every second,
irrespective of any tenths counts being missed due to slow processing). The
previous seconds count is held in global variable beep_time. When mode 7 is
first entered, this variable is set to 100 - an impossible value for the
seconds count - ensuring that a beep occurs as soon as the countdown times
out.

Subroutine display_time calls binary_to_time_bcd which converts the binary
time count to semi-bcd and stores it in time_bcd. The sprite and icon are
then redrawn without redrawing the border. If the program is in timed out
mode, the seconds count is then compared with the value at the time of the
previous call and, if different, a beep is created.

Subroutine resume_count_up is called when a count up is restarted by
clicking Adjust. In this case, the displayed time is converted to binary and
subtracted from current monotonic time and stored as the time value to count
from.

Subroutine time_bcd_to_binary, as its name implies, converts semi-BCD time
to its binary value, ready for comparing with monotonic time, by taking the
hours, minutes, seconds and tenths bytes, multiplying them by appropriate
values and adding them together.

Subroutine update_setting handles button presses over the digits in
countdown presetting mode where Select increments a digit and Adjust
decrements it. The x coordinate within the icon of the mouse click is
progressively reduced until it is negative and the appropriate digit
changed. To avoid too much repetitive coding, two routines are used for
updating tens and units digits respectively. When they are called, R5 points
to the byte to update, R3 contains the value at which tens are re-zeroed -
100 for hours, 60 for minutes and seconds - and R4 contains the button
pressed information.

Subroutine start_count_down is called when a countdown is started. Current
monotonic time is read and the displayed time converted to binary and added
to it. The result is stored as the time at which the counter will time out.

Subroutine binary_to_time_bcd converts a binary time value to semi-BCD by a
combination of MOD and DIV operations, using subroutine mod_div. The latter
subroutine converts the binary values to decimal strings with a 'MOD' or '/'
operator between them and obtains the result by calling SWI
OS_EvaluateExpression.

File SW6
========

This file contains data for the Info box and menu blocks.