Commit 3e9f9f3a authored by ROOL's avatar ROOL 🤖
Browse files

This commit was manufactured by cvs2git to create tag 'Kernel- 5_35-4_79_2_60'.

Sprout from HAL 2003-04-15 20:18:37 UTC Kevin Bracey <kbracey@gitlab.riscosopen.org> 'Version increased to dizzy 5.03'
Delete:
    Docs/HAL/ADisNote
    Docs/HAL/ARMop_API
    Docs/HAL/Entries
    Docs/HAL/HAL_API
    Docs/HAL/Init
    Docs/HAL/MoreEnts
    Docs/HAL/NewAPI
    Docs/HAL/NewCDV
    Docs/HAL/Notes
    Docs/HAL/OS_Hardware
    Docs/HAL/OpenBusAdapter
    Docs/HAL/Serial
    Docs/MemMaps/+Access,ffd
    Docs/MemMaps/+SrcIndex
    Docs/MemMaps/+SrcIndexO
    Docs/MemMaps/130
    Docs/MemMaps/258
    Docs/PrivDoc/+Access,ffd
    Docs/PrivDoc/+SrcIndex
    Docs/PrivDoc/+SrcIndexO
    Docs/PrivDoc/5thColumn/+Access,ffd
    Docs/PrivDoc/5thColumn/+SrcIndex
    Docs/PrivDoc/5thColumn/+SrcIndexO
    Docs/PrivDoc/5thColumn/Concept
    Docs/PrivDoc/MMPM
    Docs/PrivDoc/ScreenMode
    NewModes/Make,feb
    NewModes/NEWF2
    NewModes/NEWFORMAT
    NewModes/OldFormat
    NewModes/OldPSSrc
    NewModes/OldToNew,ffb
    NewModes/PSSrc
    Resources/UK/CmdHelp
    Resources/UK/Messages
    Resources/UK/Morris4/Messages
    Resources/UK/Omega/Messages
    Resources/UK/Ursula/Messages
    TestSrc/A600tlb
    TestSrc/Arm3
    TestSrc/Begin
    TestSrc/Cmos
    TestSrc/ErrorCount,ffb
    TestSrc/ExtCmd
    TestSrc/ExtIO
    TestSrc/InitModule
    TestSrc/Ioc
    TestSrc/LEDDelay
    TestSrc/MEMC1
    TestSrc/Mem1IOMD
    TestSrc/Mem1MEMC1
    TestSrc/Mem2
    TestSrc/Mem3
    TestSrc/Mem4
    TestSrc/Mem5
    TestSrc/ROMCard
    TestSrc/ShowIOMDRs
    TestSrc/TestMain
    TestSrc/ToggleLED
    TestSrc/Vidc
    h/HALDevice
    hdr/ARMops
    hdr/Copro15ops
    hdr/EnvNumbers
    hdr/ExportVals/!HowTo
    hdr/ExportVals/Makefile
    hdr/ExportVals/Mk,fd7
    hdr/ExportVals/s/GetVals
    hdr/ExportVals/values
    hdr/HALDevice
    hdr/HALEntries
    hdr/KernelWS
    hdr/KeyWS
    hdr/ModHand
    hdr/OSEntries
    hdr/Old/Arthur/PublicWS
    hdr/Old/Arthur/Space200
    hdr/Old/NewSpace
    hdr/Old/VickySpace
    hdr/Options
    hdr/PublicWS
    hdr/RISCOS
    hdr/Variables
    hdr/VduExt
    s/AMBControl/AMB
    s/AMBControl/Memory
    s/AMBControl/Options
    s/AMBControl/Workspace
    s/AMBControl/allocate
    s/AMBControl/deallocate
    s/AMBControl/growp
    s/AMBControl/growshrink
    s/AMBControl/main
    s/AMBControl/mapslot
    s/AMBControl/mapsome
    s/AMBControl/memmap
    s/AMBControl/readinfo
    s/AMBControl/service
    s/AMBControl/shrinkp
    s/ARM600
    s/ARMops
    s/Arthur2
    s/Arthur3
    s/ArthurSWIs
    s/ChangeDyn
    s/Convrsions
    s/End
    s/ExtraSWIs
    s/FlashROM
    s/GetAll
    s/HAL
    s/HeapMan
    s/HeapSort
    s/KbdResA1
    s/KbdResPC
    s/KbdResRCMM
    s/Kernel
    s/LibKern
    s/MEMC1
    s/MEMC2
    s/MOSDict
    s/MemInfo
    s/Middle
    s/ModHand
    s/MoreComms
    s/MoreSWIs
    s/Morris
    s/MsgCode
    s/NewIRQs
    s/NewReset
    s/Oscli
    s/PMF/Buffer
    s/PMF/Def
    s/PMF/IIC
    s/PMF/Internat
    s/PMF/KbdDrA1
    s/PMF/convdate
    s/PMF/i2cutils
    s/PMF/key
    s/PMF/mouse
    s/PMF/osbyte
    s/PMF/oseven
    s/PMF/osinit
    s/PMF/osword
    s/PMF/oswrch
    s/PMF/realtime
    s/SWINaming
    s/Super1
    s/SysComms
    s/TickEvents
    s/UnSqueeze
    s/Utility
    s/vdu/vdu23
    s/vdu/vdu5
    s/vdu/vducursoft
    s/vdu/vdudecl
    s/vdu/vdudriver
    s/vdu/vdufont
    s/vdu/vdufontl1
    s/vdu/vdugrafa
    s/vdu/vdugrafb
    s/vdu/vdugrafc
    s/vdu/vdugrafd
    s/vdu/vdugrafdec
    s/vdu/vdugrafe
    s/vdu/vdugraff
    s/vdu/vdugrafg
    s/vdu/vdugrafh
    s/vdu/vdugrafi
    s/vdu/vdugrafj
    s/vdu/vdugrafk
    s/vdu/vdugrafl
    s/vdu/vdugrafv
    s/vdu/vduhint
    s/vdu/vdumodes
    s/vdu/vdupal10
    s/vdu/vdupal20
    s/vdu/vdupalette
    s/vdu/vdupalxx
    s/vdu/vduplot
    s/vdu/vdupointer
    s/vdu/vduswis
    s/vdu/vduttx
    s/vdu/vduwrch
parent e187fb9f

Too many changes to show.

To preserve performance only 117 of 117+ files are displayed.
hdr/** gitlab-language=armasm linguist-language=armasm linguist-detectable=true
s/** gitlab-language=armasm linguist-language=armasm linguist-detectable=true
**/s/** gitlab-language=armasm linguist-language=armasm linguist-detectable=true
*,ffb gitlab-language=bbcbasic linguist-language=bbcbasic linguist-detectable=true
h/** gitlab-language=c linguist-language=c linguist-detectable=true
0 STATE (X) 0->X (8)
1 nWAIT 1->9
2 BRST 2->X (2)
3 nFIQ 3->X (13)
4 nIRQ 4->X (12)
5 nc (MAS[0]) 5->6
6 nMREQ 1 6->1
7 SEQ (X) 7->0
8 nRW 8->3
9 nBW (MAS[1]) 9->7
10 LOCK 10->X (10)
11 nTRANS (X) 11->5
12 nOPC (X) 12->4
13 nc 13->11 (DMA low)
14 ABE
15 DBE
Master clock: (MCLK down)
0 SEQ 0->7
1 nMREQ 1->6
2 nEXEC
Slave clock: (MCLK up)
3 nRW 16->8
4 nOPC 17->12
5 nTRANS 18->11
6 MAS[0] 19->5
7 MAS[1] 20->9
8 DBGACK
9 nWAIT 22->1
10 ABORT
11 DMA
12 BIGEND
13 CS0
14 CS1
15 CS2
16 CS3
17 CS4
18 CS5
19 CS6
20 CS7
0
0->X
\ No newline at end of file
12345678901234567890123456789012345678901234567890123456789012345678901234567890
mjs 12 Jan 2001 Early Draft
mjs 14 Feb 2001 XScale survey revised, ARMop reentrancy defined
RISC OS Kernel ARM core support
===============================
This document is concerned with the design of open ended support for
multiple ARM cores within the RISC OS kernel, as part of the work loosely
termed hardware abstraction. Note that the ARM core support is part of the
OS kernel, and so is not part of the hardware abstraction layer (HAL)
itself.
Background
----------
ARM core support (including caches and MMU) has historically been coded in a
tailored way for one or two specific variants. Since version 3.7 this has
meant just two variants; ARM 6/7 and StrongARM SA110. A more generic
approach is required for the next generation. This aims both to support
several cores in a more structured way, and to cover minor variants (eg.
cache size) with the same support code. The natural approach is to set up
run-time vectors to a set of ARM support routines.
Note that it is currently assumed that the ARM MMU architecture will not
change radically in future ARM cores. Hence, the kernel memory management
algorithms remain largely unchanged. This is believed to be a reasonable
assumption, since the last major memory management change was with Risc PC
and ARM 610 (when the on-chip MMU was introduced).
Note that all ARM support code must be 32-bit clean, as part of the 32-bit
clean kernel.
Survey of ARM core requirements
-------------------------------
At present, five broad ARM core types can be considered to be of interest;
ARM7 (and ARM6), ARM9, ARM10, StrongARM (SA1) and XScale. These divide
primarily in terms of cache types, and cache and TLB maintenance
requirements. They also span a range of defined ARM architecture variants,
which introduced variants for system operations (primarily coprocessor 15
instructions).
The current ARM architecture is version 5. This (and version 4) has some
open ended definitions to allow code to determine cache size and types from
CP15 registers. Hence, the design of the support code can hope to be at
least tolerant of near future variations that are introduced.
ARM7
----
ARM7 cores may be architecture 3 or 4. They differ in required coprocessor
15 operations for the same cache and TLB control. ARM6 cores are much the
same as architecture 3 ARM7. The general character of all these cores is of
unified write-through caches that can only be invalidated on a global basis.
The TLBs are also unified, and can be invalidated per entry or globally.
ARM9
----
ARM9 cores are architecture 4. We ignore ARM9 variants without an MMU. The
kernel can read cache size and features. The ARM 920 or 922 have harvard
caches, with writeback and writethrough capable data caches (on a page or
section granularity). Data and instruction caches can be invalidated by
individual lines or globally. The data cache can be cleaned by virtual
address or cache segment/index, allowing for efficient cache maintenance.
Data and instruction TLBs can be invalidated by entry or globally.
ARM10
-----
ARM 10 is architecture 5. Few details available at present. Likely to be
similar to ARM9 in terms of cache features and available operations.
StrongARM
---------
StrongARM is architecture 4. StrongARMs have harvard caches, the data cache
being writeback only (no writethrough option). The data cache can only be
globally cleaned in an indirect manner, by reading from otherwise unused
address space. This is inefficient because it requires external (to the
core) reads on the bus. In particular, the minimum cost of a clean, for a
nearly clean cache, is high. The data cache supports clean and invalidate by
individual virtual lines, so this is reasonably efficient for small ranges
of address. The data TLB can be invalidated by entry or globally.
The instruction cache can only be invalidated globally. This is inefficient
for cases such as IMBs over a small range (dynamic code). The instruction
TLB can only be invalidated globally.
Some StrongARM variants have a mini data cache. This is selected over the
main cache on a section or page by using the cachable/bufferable bits set to
C=1,B=0 in the MMU (this is not standard ARM architecture). The mini data
cache is writeback and must be cleaned in the same manner as the main data
cache.
XScale
------
XScale is architecture 5. It implements harvard caches, the data cache being
writeback or writethrough (on a page or section granularity). Data and
instruction caches can be invalidated by individual lines or globally. The
data cache can be fully cleaned by allocating lines from otherwise unused
address space. Unlike StrongARM, no external reads are needed for the clean
operation, so that cache maintenance is efficient.
XScale has a mini data cache. This is only available by using extension bits
in the MMU. This extension is not documented in the current manual for
architecture 5, but will presumably be properly recognised by ARM. It should
be a reasonably straightforward extension for RISC OS. The mini data cache
can only be cleaned by inefficient indirect reads as on StrongARM.
For XScale, the whole mini data cache can be configured as writethrough. The
most likely use for RISC OS is to map screen memory as mini cacheable, so
writethrough caching will be selected to prevent problems with delayed
screen update (and hence intricate screen/cache management code as in Ursula
for StrongARM). With writethrough configured, most operations can ignore the
mini cache, because invalidation by virtual address will invalidate mini or
main cache entries as appropriate.
Unfortunately, for global cache invalidatation, things are very awkward.
RISC OS cannot use the global cache invalidate operation (which globally
invalidates both data caches), unless it is very careful to 100% clean the
main cache with all interrupts (IRQs and FIQs) disabled. This is to avoid
fatal loss of uncleaned lines from the writeback main cache. Disabling
interrupts for the duration of a main cache clean is an unacceptable
latency. Therefore, reluctantly, RISC OS must do the equivalent of cleaning
the mini cache (slow physical reads) in order to globally invalidate it as a
side effect.
The instruction and data TLBs can each be invalidated by entry or globally.
Kernel ARM operations
---------------------
This section lists the definitions and API of the set of ARM operations
(ARMops) required by the kernel for each major ARM type that is to be
supported. Some operations may be very simple on some ARMs. Others may need
support from the kernel environment - for example, readable parameters that
have been determined at boot, or address space available for cache clean
operations.
The general rules for register usage and preservation in calling these
ARMops iare:
- any parameters are passed in r0,r1 etc. as required
- r0 may be used as a scratch register
- the routines see a valid stack via sp, at least 16 words are available
- lr is the return link as required
- on exit, all registers except r0 and lr must be preserved
Note that where register values are given as logical addresses, these are
RISC OS logical addresses. The equivalent ARM terminology is virtual address
(VA), or modified virtual address (MVA) for architectures with the fast
context switch extension.
Note also that where cache invalidation is required, it is implicit that any
associated operations for a particular ARM should be performed also. The
most obvious example is for an ARM with branch prediction, where it may be
necessary to invalidate a branch cache anywhere where instruction cache
invalidation is to be performed.
Any operation that is a null operation on the given ARM should be
implemented as a single return instruction:
MOV pc, lr
ARMop reentrancy
----------------
In general, the operations will be called from SVC mode with interrupts
enabled. However, some use of some operations from interrupt mode is
expected. Notably, it is desirable for the IMB operations to be
available from interrupt mode. Therefore, it is intended that all
implementations of all ARMops be reentrant. Most will be so with no
difficulty. For ARMs with writeback data caches, the cleaning algorithm
may have to be constructed carefully to handle reentrancy (and to avoid
turning off interrupts for the duration of a clean).
Cache ARMops
------------
-- Cache_CleanInvalidateAll
The cache or caches are to be globally invalidated, with cleaning of any
writeback data being properly performed.
entry: -
exit: -
Note that any write buffer draining should also be performed by this
operation, so that memory is fully updated with respect to any writeaback
data.
The OS only expects the invalidation to be with respect to instructions/data
that are not involved in any currently active interrupts. In other words, it
is expected and desirable that interrupts remain enabled during any extended
clean operation, in order to avoid impact on interrupt latency.
-- Cache_CleanAll
The unified cache or data cache are to be globally cleaned (any writeback data
updated to memory). Invalidation is not required.
entry: -
exit: -
Note that any write buffer draining should also be performed by this
operation, so that memory is fully updated with respect to any writeaback
data.
The OS only expects the cleaning to be with respect to data that are not
involved in any currently active interrupts. In other words, it is expected
and desirable that interrupts remain enabled during any extended clean
operation, in order to avoid impact on interrupt latency.
-- Cache_InvalidateAll
The cache or caches are to be globally invalidated. Cleaning of any writeback
data is not to be performed.
entry: -
exit: -
This call is only required for special restart use, since it implies that
any writeback data are either irrelevant or not valid. It should be a very
simple operation on all ARMs.
-- Cache_RangeThreshold
Return a threshold value for an address range, above which it is advisable
to globally clean and/or invalidate caches, for performance reasons. For a
range less than or equal to the threshold, a ranged cache operation is
recommended.
entry: -
exit: r0 = threshold value (bytes)
This call returns a value that the kernel may use to select between strategies
in some cache operations. This threshold may also be of use to some of the
ARM operations themselves (although they should typically be able to read
the parameter more directly).
The exact value is unlikely to be critical, but a sensible value may depend
on both the ARM and external factors such as memory bus speed.
-- WriteBuffer_Drain
Any writebuffers are to be drained so that any pending writes are guaranteed
completed to memory.
entry: -
exit: -
TLB ARMops
----------
-- TLB_InvalidateAll
The TLB or TLBs are to be globally invalidated.
entry: -
exit: -
-- TLB_InvalidateEntry
The TLB or TLBs are to be invalidated for the entry at the given logical
address.
entry: r0 = logical address of entry to invalidate (page aligned)
exit: -
The address will always be page aligned (4k).
IMB ARMops
----------
-- IMB_Full
A global instruction memory barrier (IMB) is to be performed.
entry: -
exit: -
An IMB is an operation that should be performed after new instructions have
been stored and before they are executed. It guarantees correct operation
for code modification (eg. something as simple as loading code to be
executed).
On some ARMs, this operation may be null. On ARMs with harvard architecture
this typically consists of:
1) clean data cache
2) drain write buffer
3) invalidate instruction cache
There may be other considerations such as invalidating branch prediction
caches.
-- IMB_Range
An instruction memory barrier (IMB) is to be performed over a logical
address range.
entry: r0 = logical address of start of range
r1 = logical address of end of range (exclusive)
Note that r0 and r1 are aligned on cache line boundaries
exit: -
An IMB is an operation that should be performed after new instructions have
been stored and before they are executed. It guarantees correct operation
for code modification (eg. something as simple as loading code to be
executed).
On some ARMs, this operation may be null. On ARMs with harvard architecture
this typically consists of:
1) clean data cache over the range
2) drain write buffer
3) invalidate instruction cache over the range
There may be other considerations such as invalidating branch prediction
caches.
Note that the range may be very large. The implementation of this call is
typically expected to use a threshold (related to Cache_RangeThreshold) to
decide when to perform IMB_Full instead, being faster for large ranges.
MMU mapping ARMops
------------------
-- MMU_Changing
The global MMU mapping is about to be changed.
entry: -
exit: -
The operation must typically perform the following:
1) globally clean and invalidate all caches
2) drain write buffer
3) globally invalidate TLB or TLBs
Note that it should not be necessary to disable IRQs. The OS ensures that
remappings do not affect currently active interrupts.
-- MMU_ChangingEntry
The MMU mapping is about to be changed for a single page entry (4k).
entry: r0 = logical address of entry (page aligned)
exit: -
The operation must typically perform the following:
1) clean and invalidate all caches over the 4k range of the page
2) drain write buffer
3) invalidate TLB or TLBs for the entry
Note that it should not be necessary to disable IRQs. The OS ensures that
remappings do not affect currently active interrupts.
-- MMU_ChangingUncached
The MMU mapping is about to be changed in a way that globally affects
uncacheable space.
entry: -
exit: -
The operation must typically globally invalidate the TLB or TLBs. The OS
guarantees that cacheable space is not affected, so cache operations are not
required. However, there may still be considerations such as fill buffers
that operate in uncacheable space on some ARMs.
-- MMU_ChangingUncachedEntry
The MMU mapping is about to be changed for a single uncacheable page entry
(4k).
entry: r0 = logical address of entry (page aligned)
exit: -
The operation must typically invalidate the TLB or TLBs for the entry. The
OS guarantees that cacheable space is not affected, so cache operations are
not required. However, there may still be considerations such as fill
buffers that operate in uncacheable space on some ARMs.
-- MMU_ChangingEntries
The MMU mapping is about to be changed for a contiguous range of page
entries (multiple of 4k).
entry: r0 = logical address of first page entry (page aligned)
r1 = number of page entries ( >= 1)
exit: -
The operation must typically perform the following:
1) clean and invalidate all caches over the range of the pages
2) drain write buffer
3) invalidate TLB or TLBs over the range of the entries
Note that it should not be necessary to disable IRQs. The OS ensures that
remappings do not affect currently active interrupts.
Note that the number of entries may be large. The operation is typically
expected to use a reasonable threshold, above which it performs a global
operation instead for speed reasons.
-- MMU_ChangingUncachedEntries
The MMU mapping is about to be changed for a contiguous range of uncacheable
page entries (multiple of 4k).
entry: r0 = logical address of first page entry (page aligned)
r1 = number of page entries ( >= 1)
exit: -
The operation must typically invalidate the TLB or TLBs over the range of
the entries. The OS guarantees that cacheable space is not affected, so
cache operations are not required. However, there may still be
considerations such as fill buffers that operate in uncacheable space on
some ARMs.
Note that the number of entries may be large. The operation is typically
expected to use a reasonable threshold, above which it performs a global
operation instead for speed reasons.
RISC OS and the "HAL"
=====================
RISC OS currently is tied to the IOMD20 and VIDC20 peripheral set,
descendents of the original IOC, MEMC and VIDC devices designed in parallel
with the original ARM. These devices provide a close fit with RISC OS, and
their functionality is well suited to general purpose and embedded systems,
but the continuing drive to reduce cost requires us to support other
peripheral sets on off-the-shelf ARM system on chips.
First targets for support are L7205/L7210 for Customer L and CL92xx (the new
ARM920T based devices) for Customer A. Enclosed are a summary of their
advantages and disadvantages over the ARM7500FE for our Information
Appliance designs.
L7205 CL92xx
+ Faster (50% or so) + Faster (400%+)
+ SDRAM support + SDRAM support
+ USB + USB
+ EIDE interface
+ Lots of GPIO
- No hardware cursor
- No floating point - Incompatible floating point
- No video DACs - No video DACs
- No PS/2 - No PS/2
- Bizarre MS-Windows video system
To support these devices, and others in the future, a simple HAL is to be
inserted underneath RISC OS. This will provide two functions. Firstly, it
will be responsible for initial system bootstrap, much like a PC BIOS, and
secondly it will provide simple APIs to allow hardware access.
The HAL APIs are a thin veneer on top of the hardware. They are designed to
act as replacements for all the hardware knowledge and manipulation performed
by the RISC OS Kernel, together with some APIs that will allow RISC OS driver
modules to become more hardware independent. No attempt will be made (at this
stage) to perform such tasks as separating the video drivers from the Kernel,
for example.
One tricky design decision is the amount of abstraction to aim for. Too
little, and the system is not flexible enough; too much and HAL design is
needlessly complicated for simple hardware. The present design tries to
err on the side of too little abstraction. Extra, more abstract APIs can
always be added later. So, initially, for example, the serial device API
will just provide discovery, some capability flags and the base address
of the UART register set. This will be sufficient for the vast majority
of devices. If new hardware comes along later that isn't UART compatible,
a new API can be defined. Simple hardware can continue to just report
UART base addresses.
The bulk of device driver implementation remains in RISC OS modules - the
difference is that the HAL will allow many device drivers to no longer
directly access hardware. For example, PS2Driver can now use HAL calls to
send and receive bytes through the PS/2 ports, and thus is no longer tied to
IOMD's PS/2 hardware. Similarly, interrupt masking and unmasking, as
performed by any device vector claimant, is now a HAL call. Note that HAL
calls are normally performed via a Kernel SWI - alternatively the Kernel
can return the address of specific Kernel routines. There is nothing to stop
specific drivers talking to hardware directly, as long as they accept that
this will tie them to specific devices.
This dividing line between the HAL and RISC OS driver modules is crucial. If
the HAL does everything, then we have achieved nothing - we have just as much
hardware dependent code - it's just in a different place. It is important to
place the dividing line as close to the hardware as possible, to make it easy
to design a HAL and to prevent large amounts of code duplication between
HALs for different platforms.
The Kernel remains responsible for the ARM's MMU and all other aspects of the
CPU core. The HAL requires no knowledge of details of ARM implementations,
and thus any HAL implementation should work on any processor from the ARM610
to the ARM940T or XScale.
OS independence
===============
Notionally, the HAL implementation is OS independent. It makes no assumptions
about the virtual memory map of the OS, and only uses the defined HAL->OS
entries. The HAL should not call RISC OS SWIs.
In practice, however, the HALs are unlikely to be used on anything other
than RISC OS, and many HALs are likely to be written. This makes it sensible
to place as much intelligence as possible within RISC OS itself, to prevent
duplicated effort.
Calling standards
=================
RISC OS and the HAL are two separate entities, potentially linked separately.
Thus some simple dynamic linking is required. This occurs via a hybrid of the
RISC OS module header and Shared C Library stubs. Each RISC OS/HAL entry is
given a unique (arbitrary) number, starting at 0. The offset to each entry is
given in an entry table. Calls can be made manually through this table, or
stubs could be created at run-time to allow high-level language calls.
Every entry (up to the declared maximum) must exist. If not implemented, a
failure response must be returned, or the call ignored, as appropriate.
To permit high-level language use in the future, the procedure call standard
in both directions is ATPCS, with no use of floating point, no stack limit
checking, no frame pointers, and no Thumb interworking. HAL code is expected
to be ROPI and RWPI (hence it is called with its static workspace base in
sb). The OS kernel is neither ROPI nor RWPI (except for the pre-MMU calls,
which are ROPI).
The HAL will always be called in a privileged mode - if called in an
interrupt mode, the corresponding interrupts will be disabled. The HAL should
not change mode. HAL code should work in both 26-bit and 32-bit modes (but
should assume 32-bit configuration).
Header formats
==============
The OS is linked to run at a particular base address. At present, the address
will be at <n>MB + 64KB. This allows a HAL of up to 64K to be placed at the
bottom of a ROM below the OS, and the whole thing to be section-mapped.
However, if a different arrangement is used, the system will still work
(albeit slightly less efficiently).
The OS starts with a magic word - this aids probing and location of images.
Following that is a defined header format:
Word 0: Magic word ("OSIm" - &6D49534F)
Word 1: Flags (0)
Word 2: Image size
Word 3: Offset from base to entry table
Word 4: Number of entries available
The HAL itself may have whatever header is required to start the system. For
example on ARM7500 16->32 bit switch code is required, and on the 9500 parts
a special ROM header and checksum must be present. Instead of a header,
a pointer to the HAL descriptor is passed to the OS in the OS_Start call:
Word 0: Flags
bit 0 => uncachable workspace (32K) required
bits 1-31 reserved
Word 1: Offset from descriptor to start of HAL (will be <= 0)
Word 2: HAL size
Word 3: Offset from descriptor to entry table
Word 4: Number of entries available
Word 5: Static workspace required
Each of the HAL and the OS must be contiguous within physical memory.
RISC OS entry points from HAL init
==================================
Entry 0:
void RISCOS_InitARM(unsigned int flags)
flags: reserved - sbz
On entry:
SVC mode
MMU and caches off
IRQs and FIQs disabled
No RAM or stack used
On exit:
Instruction cache may be on
Usage:
This routine must be called once very early on in the HAL start-up, to accelerate the
CPU for the rest of HAL initialisation. Typically, it will just enable the instruction
cache (if possible on the ARM in use), and ensure that the processor is in 32-bit
configuration and mode.
Some architecture 4 (and later) ARMs have bits in the control register that affect
the hardware layer - eg the iA and nF bits in the ARM920T. These are the HAL's
responsibility - the OS will not touch them. Conversely, the HAL should not touch the
cache, MMU and core configuration bits (currently bits 0-14).
On architecture 3, the control register is write only - the OS will set bits 11-31 to
zero.
Likewise, such things as the StrongARM 110's register 15 (Test, Clock and Idle Control)
are the HAL's responsibility. The OS does not know about the configuration of the
system, so cannot program such registers.
This entry may not be called after RISCOS_Start.
Entry 1:
void *RISCOS_AddRAM(unsigned int flags, void *start, void *end, uintptr_t sigbits, void *ref)
flags
bit 0: video memory (only first contiguous range will be used)
bits 8-11: speed indicator (arbitrary, higher => faster)
other bits reserved (SBZ)
start
start address of RAM (inclusive) (no alignment requirements)
end
end address of RAM (exclusive) (no alignment requirements, but must be >= start)
sigbits
significant address bit mask (1 => this bit of addr decoded, 0 => this bit ignored)
ref
reference handle (NULL for first call)
Returns ref for next call
On entry:
SVC32 mode
MMU and data cache off
IRQs and FIQs disabled
Other notes:
This entry point must be the first call from the HAL to RISC OS following a hardware
reset. It may be called as many times as necessary to give all enumerate RAM that
is available for general purpose use. It should only be called to declare video
memory if the video memory may be used as normal RAM when in small video modes.
To permit software resets:
The HAL must be non-destructive of any declared RAM outside the first 4K of the first
block.
The stack pointer should be initialised 4K into the first block, or in some non-
declared RAM.
Must present memory in a fixed order on any given system.
Current limitations:
The first block must be at least 256K and 16K aligned. (Yuck)
Block coalescing only works well if RAM banks are added in ascending address order.
RISC OS will use RAM at the start of the first block as initial workspace. Max usage
is 16 bytes per block + 32 (currently 8 per block + 4). This limits the number of
discontiguous blocks (although RISC OS will concatanate contiguous blocks where
possible).
This call must not be made after RISCOS_Start.
Entry 2:
void RISCOS_Start(unsigned int flags, int *riscos_header, int *hal_entry_table, void *ref)
flags
bit 0: power on reset
bit 1: CMOS reset inhibited (eg protection link on Risc PC)
bit 2: perform a CMOS reset (if bit 1 clear and bit 0 set - eg front panel
button held down on an NC)
On entry:
SVC32 mode
MMU and data cache off
IRQs and FIQs disabled
Usage:
This routine must be called after all calls to RISCOS_AddRAM have been completed.
It does not return. Future calls back to the HAL are via the HAL entry table, after
the MMU has been enabled.
Entry 3:
void *RISCOS_MapInIO(unsigned int flags, void *phys, unsigned int size)
flags: bit 2 => make memory bufferable
phys: physical address to map in
size: number of bytes of memory to map in
Usage:
This routine is used to map in IO memory for the HAL's usage. Normally it would
only be called during HAL_Init(). Once mapped in the IO space cannot be released.
It returns the resultant virtual address corresponding to phys, or 0 for failure.
Failure can only occur if no RAM is available for page tables, or if the virtual
address space is exhausted.
void *RISCOS_AccessPhysicalAddress(unsigned int flags, void *phys, void **oldp)
flags: bit 2 => make memory bufferable
other bits must be zero
phys: physical address to access
oldp: pointer to location to store old state (or NULL)
On entry:
Privileged mode
MMU on
FIQs on
Re-entrant
On exit:
Returns logical address corresponding to phys
Usage:
Arranges for the physical address phys to be mapped in to logical memory.
In fact, the whole megabyte containing "phys" is mapped in (ie if phys =
&12345678, then &12300000 to &123FFFFF become available). The memory is
supervisor access only, non-cacheable, non-bufferable by default, and will
remain available until the next call to RISCOS_Release/AccessPhysicalAddress
(although interrupt routines or subroutines may temporarily map in something
else).
When finished, the user should call RISCOS_ReleasePhysicalAddress.
void RISCOS_ReleasePhysicalAddress(void *old)
old: state returned from a previous call to RISCOS_AccessPhysicalAddress
On entry:
MMU on
FIQs on
Re-entrant
Usage:
Call with the a value output from a previous RISCOS_ReleasePhysicalAddress.
Example:
void *old;
unsigned int *addr = (unsigned int *) 0x80005000;
unsigned int *addr2 = (unsigned int *) 0x90005000;
addr = (unsigned int *) RISCOS_AccessPhysicalAddress(addr, &old);
addr[0] = 3; addr[1] = 5;
addr2 = (unsigned int *) RISCOS_AccessPhysicalAddress(addr2, NULL);
*addr2 = 7;
RISCOS_ReleasePhysicalAddress(old);
HAL entries
===========
void HAL_Start(int *riscos_header)
12345678901234567890123456789012345678901234567890123456789012345678901234567890
2001 - a HAL API
----------------
mjs 12 Jan 2001 Early Draft (mjs,kjb)
RISC OS Hardware Abstraction
============================
Background
----------
This document is concerned with low level developments of RISC OS in order
to support future ARM based platforms. Loosely, this has been considered as
creating a hardware abstraction layer, or HAL. This term is a useful
shorthand, but with the following caveats. Firstly, the HAL work is only
envisaged to provide a modest level of low level abstraction (at least for
the next OS generation). Secondly, significant non-HAL work, at all levels,
is required to make a useful next generation RISC OS.
Note that most of the hardware dependence of the OS is already confined to
low level code (essentially, the kernel and device drivers). Here we assume
that the OS is only expected to run on an ARM processor, and with somewhat
restricted choices of I/O hardware (eg. friendly video pixel formats).
Up to now (version 4), RISC OS has evolved while closely coupled to an ARM
processor core and to an Acorn proprietary chip set (video, memory, I/O). It
has remained highly hardware specific. For the purposes of further
investment in RISC OS, three key areas of hardware dependence must be
addressed; 32-bit clean operation, support for new ARM cores, support for
various video, memory and I/O configurations. Without all of these, the OS
is essentially useless on forseeable future hardware.
32-bit clean code
-----------------
All RISC OS code must run 32-bit clean on future releases. This is because
all ARM cores from ARM9 onwards (and also some ARM7 variants) have entirely
removed support for RISC OS's native 26-bit modes. Note that 32-bit clean
code is not precluded from working on the older ARM cores (back to ARM 610).
With more care, 32/26-bit agnostic code can be written to work back to ARM
2. This may be of interest to module and application code, but note that the
OS kernel itself is only expected to work back to ARM 610, since an MMU is
required.
Much of the work required is routine and has been done for the OS itself
(though long term weeding of consequent bugs is required). A 32-bit
compatible shared C library has been released in order to encourage
conversion of application code by third parties. This work is not part of
hardware abstraction and is not considered further in this document.
Support for newer ARM cores
---------------------------
ARM core support (including caches and MMU) has historically been coded in a
tailored way for one or two specific variants. Since version 3.7 this has
meant just two variants; ARM 6/7 and StrongARM SA110. A more generic
approach is required for the next generation. This aims both to support
several cores in a more structured way, and to cover minor variants (eg.
cache size) with the same support code. The natural approach is to set up
run-time vectors to a set of ARM support routines.
Note that it is currently assumed that the ARM MMU architecture will not
change radically in future ARM cores. Hence, the kernel memory management
algorithms remain largely unchanged. This is believed to be a reasonable
assumption, since the last major memory management change was with Risc PC
and ARM 610 (when the on-chip MMU was introduced).
ARM core support is confined almost entirely to the kernel, and is therefore
not strictly part of the HAL. The HAL will only be concerned with any
external factors such as clock selection. Only HAL aspects are considered
further in this document.
Hardware abstraction layer
--------------------------
A simple HAL is to be inserted underneath RISC OS. This will provide two
functions. Firstly, it will be responsible for initial system bootstrap,
much like a PC BIOS, and secondly it will provide simple APIs to allow
hardware access.
The HAL APIs are a thin veneer on top of the hardware. They are designed to
act as replacements for all the hardware knowledge and manipulation
performed by the RISC OS Kernel, together with some APIs that will allow
RISC OS driver modules to become more hardware independent. No attempt will
be made (at this stage) to perform such tasks as separating the video
drivers from the Kernel, for example.
One tricky design decision is the amount of abstraction to aim for. Too
little, and the system is not flexible enough; too much and HAL design is
needlessly complicated for simple hardware. The present design tries to err
on the side of too little abstraction. Extra, more abstract APIs can always
be added later. So, initially, for example, the serial device API will just
provide discovery, some capability flags and the base address of the UART
register set. This will be sufficient for the vast majority of devices. If
new hardware comes along later that isn't UART compatible, a new API can be
defined. Simple hardware can continue to just report UART base addresses.
The bulk of device driver implementation remains in RISC OS modules - the
difference is that the HAL will allow many device drivers to avoid direct
access to hardware. For example, PS2Driver can now use HAL calls to send and
receive bytes through the PS/2 ports, and thus is no longer tied to IOMD's
PS/2 hardware. Similarly, interrupt masking and unmasking, as performed by
any device vector claimant, is now a HAL call. Note that HAL calls are
normally performed via a Kernel SWI - alternatively the Kernel can return
the address of specific HAL routines. There is nothing to stop specific
drivers talking to hardware directly, as long as they accept that this will
tie them to specific devices.
This dividing line between the HAL and RISC OS driver modules is crucial. If
the HAL does everything, then we have achieved nothing - we have just as
much hardware dependent code - it's just in a different place. It is
important to place the dividing line as close to the hardware as possible,
to make it easy to design a HAL and to prevent large amounts of code
duplication between HALs for different platforms.
The Kernel remains responsible for the ARM's MMU and all other aspects of
the CPU core. The HAL requires no knowledge of details of ARM
implementations, and thus any HAL implementation should work on any
processor from the ARM610 onwards.
HAL/OS layout and headers
-------------------------
The OS is linked to run at a particular base address. Pre-HAL OS's were
linked to run at <n>MB, that is on a MB alignment to allow efficient MMU
section mapping. For simplicity, the HAL/OS layout can allow a fixed maximum
size for the HAL, currently set at 64k. Then the OS base address will be
<n>MB+64k. This allows a HAL of up to 64K to be placed at the bottom of a
ROM below the OS, and the HAL/OS combination to still be section-mapped. A
ROM should be portable to hardware variants merely by replacing the 64k HAL
block.
A more flexible system would only sacrifice MMU mapping efficiency. The HAL
and OS could be placed in any desired way, provided that each is contiguous
in physical memory.
The OS starts with a header including a magic word - this aids probing and
location of images. The OS header format is defined as:
Word 0: Magic word ("OSIm" - &6D49534F)
Word 1: Flags (currently should be 0)
Word 2: Image size (bytes)
Word 3: Offset (bytes) from OS base to table of OS routine entry points
Word 4: Number of entries in table
The HAL itself should have whatever header is required to start the system.
For example on ARM7500 16->32 bit switch code is required, and on the
9500 parts a special ROM header and checksum must be present. A HAL
descriptor block, instead of a header, can be placed somewhere in the HAL. A
pointer to this block is passed by the HAL to the OS in the OS_Start call:
Word 0: Flags
bit 0 => uncachable workspace (32K) required
bits 1-31 reserved
Word 1: Offset (bytes) from descriptor to start of HAL (will be <= 0)
Word 2: HAL size (bytes)
Word 3: Offset (bytes) from descriptor to table of HAL routine entry points
Word 4: Number of entries in table
Word 5: Size of HAL static workspace required (bytes)
Calling standards
-----------------
RISC OS and the HAL are two separate entities, potentially linked
separately. The OS and the HAL are each defined with a set of callable
routines for the OS/HAL interface. Each HAL entry or each OS entry is given
a unique (arbitrary) number, starting at 0. The offset to each entry is
given in an entry table. Calls can be made manually through this table, or
stubs could be created at run-time to allow high-level language calls.
Every entry (up to the declared maximum) must exist. If not implemented, a
failure response must be returned, or the call ignored, as appropriate. Note
that the OS interface for the HAL should not be confused with standard OS
calls (SWIs) already defined for use in the OS itself.
To permit high-level language use in the future, the procedure call standard
in both directions is the ARM-Thumb Procedure Call Standard (ATPCS) as
defined by ARM, with no use of floating point, no stack limit checking, no
frame pointers, and no Thumb interworking. HAL code is expected to be ROPI
and RWPI (ie. all its read-only segments and read-write segments are
position-independent). Hence the HAL is called with its static workspace
base (sb) in r9. The OS kernel is neither ROPI nor RWPI (except for the
pre-MMU calls, which are ROPI). OS calls from the HAL do not use r9 as a
static base.
The HAL will always be called in a privileged mode - if called in an
interrupt mode, the corresponding interrupts will be disabled. The HAL
should not change mode. HAL code should work in both 26-bit and 32-bit modes
(but should assume 32-bit configuration).
Routines can be conveniently specified in C language syntax. Typically they
will be written in assembler. In detail, the ATPCS register usage for HAL
calls is as follows:
ATPCS ARM use at exit
a1 r0 argument 1/return value undefined or return value
a2 r1 argument 2/return value undefined or return value
a3 r2 argument 3/return value undefined or return value
a4 r3 argument 4/return value undefined or return value
v1 r4 var 1 preserved
v2 r5 var 2 preserved
v3 r6 var 3 preserved
v4 r7 var 4 preserved
v5 r8 var 5 preserved
sb r9 static workspace base preserved
v7 r10 var 7 preserved
v8 r11 var 8 preserved
ip r12 scratch undefined
sp r13 stack pointer preserved
lr r14 return link undefined
The static workspace base points to the HAL workspace.
Note that HAL calls must be assumed to corrupt all of r0-r3,r12,r14. A
function return value may be in r0, or (less commonly) multiple return
words in two or more of r0-r3.
If there are more than 4 arguments to a HAL call, arguments 5 onwards must
be pushed onto the stack before the call, and discarded after return. (The
order of arguments is with argument 5 at top of stack, ie. first to be
pulled.)
The register usage for the OS entry points is the same, except that r9 is
not used as a static base (it is preserved).
When using assembler, the register usage may seem somewhat restricted, and
cumbersome for more than 4 arguments. However, it is typically a reasonable
balance for function calls (as a PCS would aim to be), and does not preclude
implementation in C for example. Old kernel code may require register
preserving overhead to insert HAL calls easily, but for most calls this is
insignificant, compared to hardware access costs.
Initialisation sequence
-----------------------
After system reset, bootstrap code in the HAL will do minimal hardware
set-up ... blah blah
HAL entry points
----------------
These routines are expected to be called from the OS (Kernel). See the
'Calling standards' section for general information on register usage and so
forth.
Interrupts
----------
The HAL must provide the ability to identify, prioritise and mask IRQs, and the ability
to mask FIQs. RISC OS supplies the ARM's processor vectors, and on an IRQ calls the HAL
to request the identity of the highest priority interrupt.
IRQ and FIQ device numbers are arbitrary, varying from system to system. They should be
arranged to allow quick mappings to and from hardware registers, and should ideally
be packed, starting at 0.
Timers
------
The HAL must supply at least one timer capable of generating periodic
interrupts. Each timer should generate a separate logical interrupt, and the
interrupt must be latched. The timers must either be variable rate (period is
a multiple of a basic granularity), or be fixed rate (period = 1*granularity).
Optionally, the timer should be capable of reporting the time until the
next interrupt, in units of the granularity.
Counter
-------
The HAL must supply a counter that varies rapidly, appropriate for use for
sub-millisecond timing. On many systems, this counter will form part of
timer 0 - as such it is not required to operate when timer 0 is not running.
On other systems, the periodic timers may have no readable latch, and a
separate unit will be required.
The counter should count down from (period-1) to 0 continuously.
Non-volatile memory
-------------------
The HAL should provide at least 240 bytes of non-volatile memory. If no
non-volatile memory is available, the HAL may provide fake NVRAM contents
suitable for RISC OS - however, it is preferable that the HAL just state
that NVRAM is not available, and RISC OS will act as though a CMOS reset has
been performed every reset.
NVRAM is typically implemented as an IIC device, so the calls are permitted
to be slow, and to enable interrupts. The HAL is not expected to cache
contents.
If the HAL has no particular knowledge of NVMemory, then it may just say
that "NVMemory is on IIC", and the OS will probe for CMOS/EEPROM devices on
the IIC bus.
IIC bus
-------
Many hardware designs have an IIC bus. Often, it is used only to support
non-volatile memory, but in other systems TV tuners, TV modulators,
microcontrollers, and arbitrary expansion cards may be fitted.
Low-level and high level APIs are defined. An arbitrary number of buses is
supported, and each can be controlled by either the low or high level API.
The OS should normally only use one fixed API on each bus - mixing APIs is
unpredictable.
The low-level API requires the OS to control the two lines of the bus
directly. The high-level API currently covers version 2.1 of the IIC
protocol, and allows high-level transactions to be performed.
It is expected that a HAL will always provide the low-level API on each bus,
where possible in hardware. Using this, the OS can provide Fast mode single
or multi-master operation. The HAL may wish to provide the high-level API
where a dedicated IIC port with hardware assistance is available; this will
further permit High-speed and slave operation.
As it is possible that some HAL APIs (eg NVMemory), although abstracted at
this API layer, are still actually an IIC device, a matching set of
high-level IIC calls are provided in the OS. These give the HAL access to
the OS IIC engine, which will make low-level HAL calls. This saves the HAL
from implementing the full IIC protocol. To illustrate this diagramatically:
+----------+ NVMem_Read +------------+ NVMemoryRead +------------+
| | ---------> | | ------------> | |
| App | | OS | IICTransmit | HAL |
| | | | <------------ | |
| | | | IICSetLines | |
| | | | ------------> | |
+----------+ +------------+ +------------+
The low-level calls should be fast. Interrupt status may not be altered.
The following structure is used:
typedef struct { int SDA, SCL } IICLines;
High level API to be defined ...
Video
-----
The HAL only attempts to abstract the hardware controller aspects of the OS
video. It does not (yet) consider pixel formats, framestore layout, hardware
graphics acceleration. All these would affect a great deal of RISC OS
graphics code that forms much of the value of the OS. This means that the
envisaged HAL/RISC OS combination makes some specific assumptions about
graphics framestore layout as follows:
- memory mapped framestore
- expected to be contiguous physical memory, can be specific memory (eg. VRAM)
- mapped as contiguous logical memory
- progressive raster scan in logical memory from top left pixel to bottom right
- start of each raster row must be word aligned
- number of pixels in a row should be such that row is a whole number of words
- spacing between start of each row is a constant number of words, possibly
greater than row length (via mode variable, LineLength)
- 1,2,4,8,16 or 32 bits per pixel (bpp)
- little endian pixel packing for 1,2,4 bpp (least significant bits are
leftmost pixels)
- presence of palette assumed for 1,2,4,8 bpp (8-bits per r,g,b component in
each entry)
- 16 bpp format:
bits 0-4 Red
5-9 Green
10-14 Blue
15 Supremacy (0=solid, 1=transparent)
- 32 bpp format:
bits 0-7 Red
8-15 Green
16-23 Blue
24-31 Supremacy (0=solid, 255=transparent)
- palette words are 32 bits:
bits 0-7 Reserved (0), or Supremacy (0=solid, 255=transparent)
8-15 Red
16-23 Green
24-31 Blue
- pointer/cursor is assumed supported in hardware, 32x32 pixels,
each pixel either transparent or one of 3 paletted colours
- support for physically interlaced, logically progressive framestore via
MMU tricks and use of LineLength mode variable, currently not fully
integrated into kernel
Note that it is possible to support hardware where only some pixel depths
are available, or only some fit the RISC OS assumptions. Also some hardware
has some configurability for 'arbitrary' choices like RGB versus BGR
ordering. Hence, the restrictions are typically much less severe than might
first be thought.
Supporting a software only pointer/cursor is feasible (much less work than
new pixel formats) but not yet considered.
Aside: RISC OS video interlace trick
------------------------------------
Has been used in NC/STB variants. Makes a physically interlaced framestore
(two distinct field stores) appear as logically progressive framestore,
using MMU to map many logical copies, and using freedom to choose a constant
logical increment between rows in RO mode definition. For 576 rows say, uses
576M of logical space. Each 1M (section mapped) supports a row and allows
logical address to increment monotonically, as physical address alternates
between (increasing rows of) physical field stores. Currently not integrated
into kernel, so fudges address space allocation and poking of video
variables. Also has drawback of thrashing data TLBs (one entry per row).
The trick requires the physical field stores to be separated by 1M plus half
a row. The logical spacing between rows is also set to 1M plus half a row.
The 1M logical sections are set to map alternately to the even and odd
physical fields (the second field being offset by half a row relative to 1M
alignment). Then the logical incrementing of rows maps alternately between
fields, incrementing physically by 1 row between visits to the same field.
Note that the multiple logical mapping implies uncached screen to avoid
coherency worries, but RO uses uncached screen anyway (with exception of
Ursula/Phoebe, now defunct).
Routines in detail
------------------
[Note, plonking all routines here possibly only temporarily. May want
routines listed in relevant sections with overview. eg. video routines
with video section, etc.]
-- HAL_Init(unsigned int *riscos_header, void *uncacheable_ws)
The OS will call HAL_Init after enabling the MMU, and initialising the HAL
workspace (filled with 0). At this point any initialisation for the main HAL
routines (rather than the early bootstrap code in the HAL) can be done.
-- HAL_IRQEnable
????
-- HAL_IRQDisable
????
-- HAL_IRQClear
????
-- HAL_IRQSource
????
-- HAL_Reset
This resets the board depending on the value in a1
a1 = 0 hard reset and turn the power off (ie.just turn the power off)
a1 = 1 hard reset and leave the power on
a1 > 1 reserved
Asking HAL_PlatformInfo will tell you if the hardware allows the power to be turned off by software,if it doesn't then behaviour is per a1 = 1
-- int HAL_Timers(void)
Returns number of timers. Timers are numbered from 0 upwards. Timer 0 must
exist.
-- int HAL_TimerDevice(int timer)
Returns device number of timer n. A device number refers to the IRQ device
number for interrupt calls.
-- unsigned int HAL_TimerGranularity(int timer)
Returns basic granularity of timer n in ticks per second.
-- unsigned int HAL_TimerMaxPeriod(int timer)
Returns maximum period of the timer, in units of Granularity. Will be 1 for
a fixed rate timer.
-- void HAL_TimerSetPeriod(int timer, unsigned int period)
Sets period of timer n. If period > 0, the timer will generate interrupts
every (period / granularity) seconds. If period = 0, the timer may be
stopped. This may not be possible on some hardware, so the corresponding
interrupt should be masked in addition to calling this function with period
0. If period > maxperiod, behaviour is undefined.
-- unsigned int HAL_TimerPeriod(int timer)
Reads period of timer n. This should be the actual period in use by the
hardware, so if for example period 0 was requested and impossible, the
actual current period should be reported.
-- unsigned int HAL_TimerReadCountdown(int timer)
Returns the time until the next interrupt in units of granularity, rounded
down. If not available, 0 is returned.
-- unsigned int HAL_CounterRate(void)
Returns the rate of the counter in ticks per second. Typically will equal
HAL_TimerGranularity(0).
-- unsigned int HAL_CounterPeriod(void)
Returns the period of the counter, in ticks. Typically will equal
HAL_TimerPeriod(0).
-- unsigned int HAL_CounterRead(void)
Reads the current counter value. Typically will equal
HAL_TimerReadCountdown(0).
-- unsigned void HAL_CounterDelay(unsigned int microseconds)
Delay for at least the specified number of microseconds.
-- unsigned int HAL_NVMemoryType(void)
Returns a flags word describing the NVMemory
bits 0-7: 0 => no NVMemory available
1 => NVMemory may be available on the IIC bus
2 => NVMemory is available on the IIC bus, and the
device characteristics are known
3 => the HAL provides NVMemory access calls.
bit 8: NVMemory has a protected region at the end
bit 9: Protected region is software deprotectable
bit 10: Memory locations 0-15 are readable
bit 11: Memory locations 0-15 are writeable
If bits 0-7 are 0 or 1 no other NVMemory calls need be available, and bits
8-31 should be zero.
If bits 0-7 are 2, Size, ProtectedSize, Protection and IICAddress calls must
be available.
If bits 0-7 are 3, all calls except IICAddress must be available.
-- unsigned int HAL_NVMemorySize(void)
Returns the number of bytes of non-volatile memory available. Bytes 0-15
should be included in the count, so for example a Philips PCF8583 CMOS/RTC
device (as used in the Archimedes and Risc PC) would be described as a
256-byte device, with locations 0-15 not readable. More complex arrangements
would have to be abstracted out by the HAL providing its own NVMemory access
calls.
This is to suit the current RISC OS Kernel, which does not use bytes 0-15.
-- unsigned int HAL_NVMemoryProtectedSize(void)
Returns the number of bytes of NVMemory that are protected. These should be
at the top of the address space. The OS will not attempt to write to those
locations without first requesting deprotection (if available). Returns 0 if
bit 8 of the flags is clear.
-- void HAL_NVMemoryProtection(bool)
Enables (if true) or disables if (false) the protection of the software
protectable region. Does nothing if bits 8 and 9 not both set.
-- unsigned int HAL_NVMemoryIICAddress(void)
Returns a word describing the addressing scheme of the NVRAM.
bits 0-7: IIC address
This will always be on bus zero.
-- int HAL_NVMemoryRead(unsigned int addr, void *buffer, unsigned int n)
Reads n bytes of memory from address addr onwards into the buffer supplied.
Returns the number of bytes successfully read. Under all normal
circumstances the return value will be n - if it is not, a hardware failure
is implied. Behaviour is undefined if the address range specified is outside
the NVMemory, or inside bytes 0-15, if declared unavailable.
-- int HAL_NVMemoryWrite(unsigned int addr, void *buffer, unsigned int n)
Write n bytes of memory into address addr onwards from the buffer supplied.
Returns the number of bytes successfully written. Under all normal
circumstances the return value will be n - if it is not, a hardware failure
is implied. Behaviour is undefined if the address range specified is outside
the NVMemory. Writes inside the a protected region should be ignored.
-- int HAL_IICBuses(void)
Returns the number of IIC buses on the system.
-- unsigned int HAL_IICType(int bus)
Returns a flag word describing the specified IIC bus.
bit 0: Bus supplies the low-level API
bit 1: Bus supplies the high-level API
bit 2: High-level API supports multi-master operation
bit 3: High-level API supports slave operation
bit 16: Bus supports Fast (400kbps) operation
bit 17: Bus supports High-speed (3.4Mbps) operation
bits 20-31: Version number of IIC supported by high-level API, * 100.
-- __value_in_regs IICLines HAL_IICSetLines(int bus, IICLines lines)
Sets the SDA and SCL lines on the specified bus. A 0 value represents logic
LOW, 1 logic HIGH. The function then reads back and returns the values
present on the bus, to permit arbitration.
Note the "__value_in_regs" keyword, which signifies that the binary ABI
expects SDA and SCL to be returned in registers a1 and a2.
-- __value_in_regs IICLines HAL_IICReadLines(int bus)
Reads the state of the IIC lines on the specified bus, without changing
their state.
Note the "__value_in_regs" keyword, which signifies that the binary ABI
expects SDA and SCL to be returned in registers a1 and a2.
-- int HAL_VideoFlybackDevice(void)
Returns the device number of the video flyback interrupt. [Note: HAL
interrupt API possibly subject to change, may affect this call.]
-- void HAL_Video_SetMode(const void *VIDCList3)
Programs the video controller to initialise a display mode. RISC OS passes a
standard VIDC List Type 3 as specified in PRM 5a-125. Note that this is a
generic video controller list, and so VIDC in this context does not refer to
any specific devices such as Acorn VIDC20.
The HAL is expected to set the video controller timings on this call. Any
palette, pixel DMA and hardware cursor settings are controlled via other
calls.
-- void HAL_Video_WritePaletteEntry(uint type, uint pcolour, uint index)
Writes a single palette entry to the video controller.
type = 0 for normal palette entry
1 for border colour
2 for pointer colour
>= 3 reserved
pcolour = palette entry colour in BBGGRRSS format (Blue,Green,Red,Supremacy)
index = index of entry
Indices are in the range 0..255 for normal, 0 for border, 0..3 for pointer
colours. Note that RISC OS only makes calls using 1..3 for the pointer, and
pointer colour 0 is assumed to be transparent.
-- void HAL_Video_WritePaletteEntries(uint type, const uint *pcolours,
uint index, uint Nentries)
Writes a block of palette entries to the video controller.
type = 0 for normal palette entry
1 for border colour
2 for pointer colour
>= 3 reserved
pcolours = pointer to block of palette entry colours in BBGGRRSS format
(Blue,Green,Red,Supremacy)
index = start index in palette (for first entry in block)
Nentries = number of entries in block (must be >= 1)
Indices are in the range 0..255 for normal, 0 for border, 0..3 for pointer
colours. Note that RISC OS only makes calls using 1..3 for the pointer, and
pointer colour 0 is assumed to be transparent.
-- uint HAL_Video_ReadPaletteEntry(uint type, uint pcolour, uint index)
Returns the effective palette entry after taking into account any hardware
restrictions in the video controller, assuming it was originally programmed
with the value pcolour.
type = 0 for normal palette entry
1 for border colour
2 for pointer colour
>= 3 reserved
pcolour = palette entry colour in BBGGRRSS format (Blue,Green,Red,Supremacy)
index = index of entry
returns : effective BBGGRRSS
Indices are in the range 0..255 for normal, 0 for border, 0..3 for pointer
colours. Note that RISC OS only makes calls using 1..3 for the pointer, and
pointer colour 0 is assumed to be transparent.
Depending on harwdware capabilities, HALs may have to remember current
settings (eg. bits per pixel) or keep soft copies of entries. Because this
call supplies the original pcolour, this need is minimised (some HALs can
just return pcolour or a directly modified pcolour).
-- void HAL_Video_SetInterlace(uint interlace)
Sets the video interlaced sync.
interlace = 0 or 1 for interlace off or on
(all other values reserved)
-- void HAL_Video_SetBlank(uint blank, uint DPMS)
blank = 0 or 1 for unblank or blank
(all other values reserved)
DMPS = 0..3 as specified by monitor DPMSState (from mode file)
0 for no DPMS power saving
The HAL is expected to attempt to turn syncs off according to DPMS, and to
turn video DMA off for blank (and therefore on for unblank) if possible. The
HAL is not expected to do anything else, eg. blank all palette entries. Such
things are the responsibility of the OS, and also this call is expected to
be fast. May be called with interrupts off.
-- void HAL_Video_SetPowerSave(uint powersave)
powersave = 0 or 1 for power save off or on
(all other values reserved)
The HAL is expected to perform any reasonable measures on the video
controller to save power (eg. turn off DACs), when the display is assumed
not to be required. Blanking is handled by a separate call.
[What does this really mean. What is acceptable and safe for displays? ]
-- void HAL_Video_UpdatePointer(uint flags, int x, int y, const shape_t *shape)
Update the displayed position of the current pointer shape (or turn shape
off). This call is made by the OS at a time to allow smoothly displayed
changes (on a VSync).
flags:
bit 0 = pointer display enable (0=off, 1=on)
bit 1 = pointer shape update (0=no change, 1=updated)
bits 2..31 reserved (0)
xpos = x position of top left of pointer (xpos = 0 for left of display)
ypos = y position of top left of pointer (ypos = 0 for top of display)
shape points to shape_t descriptor block:
typedef struct shape_t
{
uint8 width; /* unpadded width in bytes (see notes) */
uint8 height; /* in pixels */
uint8 padding[2]; /* 2 bytes of padding for field alignment */
void *buffLA; /* logical address of buffer holding pixel data */
void *buffPA; /* corresponding physical address of buffer */
}
Notes:
1) if flags bit 0 is 0 (pointer off), x, y, shape are undefined
2) the shape data from RISC OS is always padded with transparent pixels
on the rhs, to a width of 32 pixels (8 bytes)
3) pointer clipping is the responsibility of the HAL (eg. may be able to
allow display of pointer in border region on some h/w)
4) buffer for pixel data is aligned to a multiple of 256 bytes or better
The HAL may need to take note of the shape updated flag, and make its own
new copies if true. This is to handle cases like dual scan LCD pointer,
which typically needs two or more shape buffers for the hardware, or
possibly to handle clipping properly. This work should only be done when the
updated flag is true.
A simple HAL, where hardware permits, can use the shape data in the buffer
directly, ignoring the updated flag. The OS guarantees that the buffer data
is valid for the whole time it is to be displayed.
-- void HAL_Video_SetDAG(uint DAG, uint paddr)
Set the video DMA address generator value to the given physical address.
DAG = 0 set start address of current video display
1 set start address of total video buffer
2 set end address (exclusive) of total video buffer
all other values reserved
paddr = physical address for given DAG
The OS has a video buffer which is >= total display size, and may be using
bank switching (several display buffers) or hardware scroll within the total
video buffer.
DAG=1 will be start address of current total video buffer
DAG=2 will be end address (exclusive) of current total video buffer
DAG=0 will be start address in buffer for current display
HALs should respond differently depending on whether hardware scroll is
supported or not. (The OS will already know this from HAL_Video_Features).
No hardware scroll:
Only DAG=0 is significant, and the end address of the current display is
implied by the size of the current mode. Calls with DAG=1,2 should be
ignored.
Hardware scroll:
DAG=0 again defines display start. DAG=2 defines the last address
(exclusive) that should be displayed before wrapping back (if reached within
display size), and DAG=1 defines the address to which accesses should wrap
back.
-- int HAL_Video_VetMode(const void *VIDClist, const void *workspace)
Allows HAL to vet a proposed mode.
[What does this really do, and what can HAL do. Are we going to allow
changes to VIDCList by HAL, ie. not const. Is mode workspace really ok to
pass to HAL ???]
VIDClist -> generic video controller list (VIDC list type 3)
workspace -> mode workspace (if mode number), or 0
returns 0 if OK (may be minor adjusts to VIDClist and/or workspace values)
non-zero if not OK
-- uint HAL_Video_Features(void)
Determine key features supported by the video hardware.
returns a flags word:
bit 0 hardware scroll is supported
bit 1 hardware pointer/cursor is supported
bit 2 interlace is supported with progressive framestore
other bits reserved (returned as 0)
Bits are set for true. If bit 2 is true, then the OS assumes that a simple
progressive framestore layout is sufficient for an interlaced display (ie.
that the hardware implements the interlaced scan).
-- uint HAL_Video_PixelFormats(void)
Determine the pixel formats that are supported by the hardware.
returns flags word:
bit 0 1 bpp is supported
bit 1 2 bpp is supported
bit 2 4 bpp is supported
bit 3 8 bpp is supported
bit 4 16 bpp is supported
bit 5 32 bpp is supported
other bits reserved (returned as 0)
Bits are set for true. Bits 0-5 refer to support with standard RISC OS pixel
layout. (such as little endian packing for 1,2,4 bpp, 5-5-5 RGB for 16 bpp,
etc). See the section discussing Video for more information. Other formats
may be introduced when/if RO supports them.
-- uint HAL_Video_BufferAlignment(void)
Determine the framestore buffer alignment required by the hardware.
returns an unsigned integer:
the required alignment for the framestore buffer, in bytes
(expected to be a power of 2)
-- HAL_MatrixColumns
???
-- HAL_MatrixScan
???
-- HAL_TouchscreenType
???
-- HAL_TouchscreenRead
???
-- unsigned int64 HAL_MachineID(void)
Returns a 64-bit unique machine identifier,this may later be used to
form the ethernet MAC address but otherwise has no great significance on non
networked machines.
The top 8 bits are a CRC,based on the same algorithm the original DS2401
used - if the CRC fails zero will be substituted
-- void *HAL_ControllerAddress(unsigned controller)
Asks the HAL where various controllers might or might not be.
Podule manager uses this information to determine at run time whether or not
to bother doing anything.
Returns r0=logical address of the chosen controller,or zero
0 = EASI card access speed control
1 = EASI space(s)
2 = VIDC1
3 = VIDC20
4 = S space base (IOMD,podules,NICs,blah blah)
5 = Extension ROM(s)
-- HALEntry HAL_HardwareInfo
See OS_ReadSysInfo reason code 2
-- HALEntry HAL_SuperIOInfo
See OS_ReadSysInfo reason code 3
RISC OS entry points from HAL init
----------------------------------
These are entry points into the OS, called from the HAL.
-- void RISCOS_InitARM(unsigned int flags)
flags: reserved - sbz
On entry:
SVC mode
MMU and caches off
IRQs and FIQs disabled
No RAM or stack used
On exit:
Instruction cache may be on
This routine must be called once very early on in the HAL start-up, to
accelerate the CPU for the rest of HAL initialisation. Typically, it will
just enable the instruction cache (if possible on the ARM in use), and
ensure that the processor is in 32-bit configuration and mode.
Some architecture 4 (and later) ARMs have bits in the control register that
affect the hardware layer - eg the iA and nF bits in the ARM920T. These are
the HAL's responsibility - the OS will not touch them. Conversely, the HAL
should not touch the cache, MMU and core configuration bits (currently bits
0-14).
On architecture 3, the control register is write only - the OS will set bits
11-31 to zero.
Likewise, such things as the StrongARM 110's register 15 (Test, Clock and
Idle Control) are the HAL's responsibility. The OS does not know about the
configuration of the system, so cannot program such registers.
This entry must not be called after RISCOS_Start.
-- void *RISCOS_AddRAM(unsigned int flags, void *start, void *end,
uintptr_t sigbits, void *ref)
flags
bit 0: video memory (only first contiguous range will be used)
bit 1: video memory is not suitable for general use
bits 8-11: speed indicator (arbitrary, higher => faster)
other bits reserved (SBZ)
start
start address of RAM (inclusive) (no alignment requirements)
end
end address of RAM (exclusive) (no alignment requirements, but must be >= start)
sigbits
significant address bit mask (1 => this bit of addr decoded, 0 => this bit ignored)
ref
reference handle (NULL for first call)
Returns ref for next call
On entry:
SVC32 mode
MMU and data cache off
IRQs and FIQs disabled
This entry point must be the first call from the HAL to RISC OS following a hardware
reset. It may be called as many times as necessary to give all enumerate RAM that
is available for general purpose use. It should only be called to declare video
memory if the video memory may be used as normal RAM when in small video modes.
To permit software resets:
The HAL must be non-destructive of any declared RAM outside the first 4K of the first
block.
The stack pointer should be initialised 4K into the first block, or in some non-
declared RAM.
Must present memory in a fixed order on any given system.
The first block must be at least 256K and 16K aligned.
Block coalescing only works well if RAM banks are added in ascending address order.
RISC OS will use RAM at the start of the first block as initial workspace.
Max usage is 16 bytes per block + 32 (currently 8 per block + 4). This
limits the number of discontiguous blocks (although RISC OS will concatanate
contiguous blocks where possible).
This call must not be made after RISCOS_Start.
-- void RISCOS_Start(unsigned int flags, int *riscos_header,
int *hal_entry_table, void *ref)
flags
bit 0: power on reset
bit 1: CMOS reset inhibited (eg protection link on Risc PC)
bit 2: perform a CMOS reset (if bit 1 clear and bit 0 set - eg front panel
button held down on an NC)
bit 3: there is no CMOS (the Kernel must use a RAM cache)
bit 4: the RAM has already been cleared to zero
On entry:
SVC32 mode
MMU and data cache off
IRQs and FIQs disabled
This routine must be called after all calls to RISCOS_AddRAM have been
completed. It does not return. Future calls back to the HAL are via the HAL
entry table, after the MMU has been enabled.
-- void *RISCOS_MapInIO(unsigned int flags, void *phys, unsigned int size)
flags: bit 2 => make memory bufferable
phys: physical address to map in
size: number of bytes of memory to map in
This routine is used to map in IO memory for the HAL's usage. Normally it
would only be called during HAL_Init(). Once mapped in the IO space cannot
be released.
It returns the resultant virtual address corresponding to phys, or 0 for
failure. Failure can only occur if no RAM is available for page tables, or
if the virtual address space is exhausted.
-- void *RISCOS_AccessPhysicalAddress(unsigned int flags, void *phys, void **oldp)
flags: bit 2 => make memory bufferable
other bits must be zero
phys: physical address to access
oldp: pointer to location to store old state (or NULL)
On entry:
Privileged mode
MMU on
FIQs on
Re-entrant
On exit:
Returns logical address corresponding to phys
Arranges for the physical address phys to be mapped in to logical memory. In
fact, the whole megabyte containing "phys" is mapped in (ie if phys =
&12345678, then &12300000 to &123FFFFF become available). The memory is
supervisor access only, non-cacheable, non-bufferable by default, and will
remain available until the next call to RISCOS_Release/AccessPhysicalAddress
(although interrupt routines or subroutines may temporarily map in something
else).
When finished, the user should call RISCOS_ReleasePhysicalAddress.
-- void RISCOS_ReleasePhysicalAddress(void *old)
old: state returned from a previous call to RISCOS_AccessPhysicalAddress
On entry:
MMU on
FIQs on
Re-entrant
Usage:
Call with the a value output from a previous RISCOS_ReleasePhysicalAddress.
Example:
void *old;
unsigned int *addr = (unsigned int *) 0x80005000;
unsigned int *addr2 = (unsigned int *) 0x90005000;
addr = (unsigned int *) RISCOS_AccessPhysicalAddress(addr, &old);
addr[0] = 3; addr[1] = 5;
addr2 = (unsigned int *) RISCOS_AccessPhysicalAddress(addr2, NULL);
*addr2 = 7;
RISCOS_ReleasePhysicalAddress(old);
Arrange correct ROM image
POST
Initialise memory system
ROM timings, width
Reset screen
Disable interrupts
Start timers
Size memory
Set up table describing memory layout
Set up video DMA
Time CPU
CONT / CONT_Break
InitMEMC (in: r1 = 0 -> Reset, 1 -> Break)
Check for 7500 vs IOMD
Program CPU, MEM and IO clocks
Set ROM timings
Set ROM width
Set up VRAM refresh
Set up peripheral timings
Set up sound format
Ensure MMU off and caches
Set up VIDC
Disable interrupts in IOC
Start timer 0
MemSize (out: r0 = page size, r1 = memory size, r2 = MEMC CR)
Set up RAM width
Find memory - create a table of (addr,len) pairs (in first memory found)
Find VRAM - if none take from first block
Start filling in page zero (in first block)
Set up video DMA registers
Allocate L1PT, and some L2PT, and soft CAM
Turn on MMU and caches
TimeCPU (out: r0 = peak RAM speed in kHz)
Put in extra pages: cursor, system heap
Start keyboard scanning
If POR or FX 200
Clear memory
Check processor type
Fill in processor vectors
Read CMOS
Fill in SWI dispatch table
Wait for keyboard (up to two seconds)
If (POR AND R/T/Del/Copy)
Reset CMOS
Goto Hard Reset
IF (POR or CannotReset or SysHeapCorrupt or CAM map nonsense or Ctrl pressed)
Clear the CAM
Set it up
InitDynamicAreas
Create system dynamic areas
InitVectors
Clear SWI hash table
Clear POR bit
Else
Do the soft reset stuff
Re-initialise kernel
If (hard reset)
Init variables
Initialise modules
PostInit
Set mode
Print "RISC OS"
Service_Reset
Shut all files
Beep if hard reset
If numpad key down
reconfigure monitor, change mode
print "monitor type reconfigured"
Check shift
Do boot
Else check *
Else enter language
\ No newline at end of file
Initialisation
==============
HAL_Init(unsigned int *riscos_header)
Will be called after the MMU is turned on, before any other entries points.
The HAL workspace will be filled with zeroes.
Interrupts
==========
The HAL must provide the ability to identify, prioritise and mask IRQs, and the ability
to mask FIQs. RISC OS supplies the ARM's processor vectors, and on an IRQ calls the HAL
to request the identity of the highest priority interrupt.
IRQ and FIQ device numbers are arbitrary, varying from system to system. They should be
arranged to allow quick mappings to and from hardware registers, and should ideally
be packed, starting at 0.
HAL_IRQEnable
HAL_IRQDisable
HAL_IRQClear
HAL_IRQSource (get highest priority asserted IRQ)
HAL_IRQDisableAll
HAL_FIQEnable
HAL_FIQDisable
HAL_FIQClear
HAL_FIQDisableAll
Interrupt specifications are generally described by a 3-word structure.
The 3 words correspond directly to the contents of registers R0,R3 and R4
on entry to OS_ClaimDeviceVector.
typedef struct irq_descriptor
{
int device;
union {
struct {
unsigned char *addr;
int maskandpolarity;
} bit;
struct {
int (*forme)(void *handle);
void *handle;
} func;
} sub;
} irq_descriptor;
OS_ClaimDeviceVector changes:
R3 and R4 must always be supplied. Set R3=R4=0 to claim "all" of an interrupt.
Bit 31 of the device number indicates that a routine is being supplied instead
of an address and a mask.
When supplying a bit mask, your handler is called if
([addr] AND maskandpolarity) EOR (maskandpolarity >> 8)
is nonzero. This is a RISC OS 3.8+ backwards-compatible extension to the original
check:
[addr] AND maskandpolarity
When supplying a routine, your handler is called if
forme(handle)
returns nonzero.
if
Timers
======
The HAL must supply at least one timer capable of generating periodic
interrupts. Each timer should generate a separate logical interrupt, and the
interrupt must be latched. The timers must either be variable rate (period is
a multiple of a basic granularity), or be fixed rate (period = 1*granularity).
Optionally, the timer should be capable of reporting the time until the
next interrupt, in units of the granularity.
int HAL_Timers(void)
Returns number of timers. Timers are numbered from 0 upwards. Timer 0
must exist.
int HAL_TimerDevice(int timer)
Returns device number of timer n
unsigned int HAL_TimerGranularity(int timer)
Returns basic granularity of timer n in ticks per second.
unsigned int HAL_TimerMaxPeriod(int timer)
Returns maximum period of the timer, in units of Granularity. Will be 1
for a fixed rate timer.
void HAL_TimerSetPeriod(int timer, unsigned int period)
Sets period of timer n. If period > 0, the timer will generate interrupts every
(period / granularity) seconds. If period = 0, the timer may be stopped.
This may not be possible on some hardware, so the corresponding interrupt
should be masked in addition to calling this function with period 0.
If period > maxperiod, behaviour is undefined.
unsigned int HAL_TimerPeriod(int timer)
Reads period of timer n. This should be the actual period in use by the
hardware, so if for example period 0 was requested and impossible, the
actual current period should be reported.
unsigned int HAL_TimerReadCountdown(int timer)
Returns the time until the next interrupt in units of granularity, rounded down.
If not available, 0 is returned.
Counter
=======
The HAL must supply a counter that varies rapidly, appropriate for use for
sub-millisecond timing. On many systems, this counter will form part of
timer 0 - as such it is not required to operate when timer 0 is not running.
On other systems, the periodic timers may have no readable latch, and a
separate unit will be required.
The counter should count down from (period-1) to 0 continuously.
unsigned int HAL_CounterRate(void)
Returns the rate of the counter in ticks per second. Typically will
equal HAL_TimerGranularity(0).
unsigned int HAL_CounterPeriod(void)
Returns the period of the counter, in ticks. Typically will equal
HAL_TimerPeriod(0).
unsigned int HAL_CounterRead(void)
Reads the current counter value. Typically will equal
HAL_TimerReadCountdown(0).
unsigned void HAL_CounterDelay(unsigned int microseconds)
Delay for at least the specified number of microseconds.
Non-volatile memory
===================
The HAL should provide at least 240 bytes of non-volatile memory. If no
non-volatile memory is available, the HAL may provide fake NVRAM contents
suitable for RISC OS - however, it is preferable that the HAL just state that
NVRAM is not available, and RISC OS will act as though a CMOS reset has been
performed every reset.
NVRAM is typically implemented as an IIC device, so the calls are permitted
to be slow, and to enable interrupts. The HAL is not expected to cache
contents.
If the HAL has no particular knowledge of NVMemory, then it may
just say that "NVMemory is on IIC", and the OS will probe for CMOS/EEPROM
devices on the IIC bus.
unsigned int HAL_NVMemoryType(void)
Returns a flags word describing the NVMemory
bits 0-7: 0 => no NVMemory available
1 => NVMemory may be available on the IIC bus
2 => NVMemory is available on the IIC bus, and the
device characteristics are known
3 => the HAL provides NVMemory access calls.
bit 8: NVMemory has a protected region at the end
bit 9: Protected region is software deprotectable
bit 10: Memory locations 0-15 are readable
bit 11: Memory locations 0-15 are writeable
If bits 0-7 are 0 or 1 no other NVMemory calls need be available,
and bits 8-31 should be zero.
If bits 0-7 are 2, Size, ProtectedSize, Protection and IICAddress calls must
be available.
If bits 0-7 are 3, all calls except IICAddress must be available.
unsigned int HAL_NVMemorySize(void)
Returns the number of bytes of non-volatile memory available. Bytes 0-15
should be included in the count, so for example a Philips PCF8583
CMOS/RTC device (as used in the Archimedes and Risc PC) would be described
as a 256-byte device, with locations 0-15 not readable. More complex
arrangements would have to be abstracted out by the HAL providing its own
NVMemory access calls.
This is to suit the current RISC OS Kernel, which does not use bytes 0-15.
unsigned int HAL_NVMemoryProtectedSize(void)
Returns the number of bytes of NVMemory that are protected. These should
be at the top of the address space. The OS will not attempt to write
to those locations without first requesting deprotection (if available).
Returns 0 if bit 8 of the flags is clear.
void HAL_NVMemoryProtection(bool)
Enables (if true) or disables if (false) the protection of the software
protectable region. Does nothing if bits 8 and 9 not both set.
unsigned int HAL_NVMemoryIICAddress(void)
Returns a word describing the addressing scheme of the NVRAM.
bits 0-7: IIC address
This will always be on bus zero.
int HAL_NVMemoryRead(unsigned int addr, void *buffer, unsigned int n)
Reads n bytes of memory from address addr onwards into the buffer supplied.
Returns the number of bytes successfully read. Under all normal circumstances
the return value will be n - if it is not, a hardware failure is implied.
Behaviour is undefined if the address range specified is outside the NVMemory,
or inside bytes 0-15, if declared unavailable.
int HAL_NVMemoryWrite(unsigned int addr, void *buffer, unsigned int n)
Write n bytes of memory into address addr onwards from the buffer supplied.
Returns the number of bytes successfully written. Under all normal circumstances
the return value will be n - if it is not, a hardware failure is implied.
Behaviour is undefined if the address range specified is outside the NVMemory.
Writes inside the a protected region should be ignored.
I²C bus
=======
Many hardware designs have an I²C bus. Often, it is used only to place non-
volatile memory on, but in other systems TV tuners, TV modulators,
microcontrollers, and arbitrary expansion cards may be fitted.
Low-level and high level APIs are defined. An arbitrary number of buses are
supported, and each can be controlled by either the low or high level API.
The OS should normally only use one fixed API on each bus - mixing APIs may
not have good results.
The low-level API requires the OS to control the two lines of the bus
directly. The high-level API currently covers version 2.1 of the I²C
protocol, and allows high-level transactions to be performed.
It is expected that a HAL will always provide the low-level API on each
bus, where possible in hardware. Using this, the OS can provide Fast mode
single or multi-master operation. The HAL may wish to provide the high-level API
where a dedicated I²C port with hardware assistance is available; this will
further permit High-speed and slave operation.
As it is possible that some HAL APIs (eg NVMemory), although abstracted at
this API layer, are still actually an I²C device, a matching set of high-level
I²C calls are provided in the OS. These give the HAL access to the OS I²C engine,
which will make low-level HAL calls. This saves the HAL from implementing the
full I²C protocol. To illustrate this diagramatically:
+----------+ NVMem_Read +------------+ NVMemoryRead +------------+
| | ---------> | | ------------> | |
| App | | OS | IICTransmit | HAL |
| | | | <------------ | |
| | | | IICSetLines | |
| | | | ------------> | |
+----------+ +------------+ +------------+
int HAL_IICBuses(void)
Returns the number of IIC buses on the system.
unsigned int HAL_IICType(int bus)
Returns a flag word describing the specified IIC bus.
bit 0: Bus supplies the low-level API
bit 1: Bus supplies the high-level API
bit 2: High-level API supports multi-master operation
bit 3: High-level API supports slave operation
bit 4: High-level API supports background operation
bit 16: Bus supports Fast (400kbps) operation
bit 17: Bus supports High-speed (3.4Mbps) operation
bits 20-31: Version number of I²C supported by high-level API, * 100.
Low level API
-------------
The low-level calls should be instantaneous. Interrupt status may not be altered.
The following structure is used:
typedef struct { int SDA, SCL } IICLines;
Note the "__value_in_regs" keyword, which signifies that the binary ABI expects
SDA and SCL to be returned in registers a1 and a2.
__value_in_regs IICLines HAL_IICSetLines(int bus, IICLines lines)
Sets the SDA and SCL lines on the specified bus. A 0 value represents
logic LOW, 1 logic HIGH. The function then reads back and returns
the values present on the bus, to permit arbitration.
__value_in_regs IICLines HAL_IICReadLines(int bus);
Reads the state of the IIC lines on the specified bus, without changing
their state.
High level API
--------------
The high-level interface process a single transfer at a time (from the
initial START to the STOP). It is designed to support background operations.
irq_descriptor HAL_IICDevice(int bus);
Returns the interrupt specification for the bus. This is not meaningful
if bit 4 of the flags word above is not set. The OS will claim the interrupt
and call HAL_IICMonitorTransfer() each time it occurs.
#define IICSTATUS_COMPLETED 0
#define IICSTATUS_INPROGRESS 1 /* transfer proceeding in background */
#define IICSTATUS_NOACK 2 /* slave failed to acknowledge */
#define IICSTATUS_BUSY 3 /* IIC system busy (call back later) */
#define IICSTATUS_SLAVE 4 /* reserved for slave operations */
#define IICSTATUS_ERROR 5 /* other error prevented completion */
typedef struct iic_transfer
{
unsigned addr:8;
unsigned :22;
unsigned checksumonly:1;
unsigned nostart:1;
union
{ unsigned checksum;
void *data;
} d;
unsigned len;
} iic_transfer;
int HAL_IICTransfer(int bus, unsigned n, iic_transfer transfer[static n]);
Initiates an IIC transfer. The transfer shall progress in the background
if bit 4 is set, in which case the normal return should be IICSTATUS_INPROGRESS.
The OS will call HAL_IICMonitorTransfer each time an interrupt occurs - this
will allow the HAL to progress through the transfer if it's not totally automatic.
If the transfer happens in the foreground, return values are as for
IICMonitorTransfer (see below).
If an IIC transfer is currently in progress, the call may return BUSY and the
caller should retry later - although if background transfers are supported it may
queue the transfer and return INPROGRESS. If another master is driving the bus,
it should silently wait until the bus is free (in the background or foreground as
appropriate). If we lose arbitration, the transfer should be retried when the bus
becomes free.
transfer[] is an array of n transfer descriptors. Each descriptor describes part
of the transfer. The direction of the subtransfer is determined by the least
significant bit of addr. If nostart is 0, a START is first transmitted followed
by addr, otherwise the data flow continues where the previous subtransfer
left off. nostart must be 0 for the first subtransfer.
For writes, len bytes of data are read from "data" and transmitted. For reads,
len bytes are received and written to "data", unless "checksumonly" is 1, in which
case the len received bytes are summed and the (32-bit) sum stored in checksum.
If background transfers are in use, the transfer[] array and the data blocks must
remain available in unpaged memory for the duration of the transfer.
IICTransfer is re-entrant, but may return BUSY if re-entered (see above).
int HAL_IICMonitorTransfer(int bus);
Will be called on every interrupt, and should return the status of the transfer
currently in progress. If no transfer is in progress, the call should return
COMPLETED.
If the transfer is still in progress, INPROGRESS is returned.
If the slave failed to acknowledge (either the address or any later transmitted
byte), NOACK is returned.
If we have been addressed as a slave, the call returns SLAVE. More details to
be confirmed.
BUSY is not a valid response.
This will only be called in response to an IIC interrupt, with interrupts disabled.
The interrupt shall be cleared by this call.
Unknown return codes will be ignored.
Machine ID
==========
unsigned int64 HAL_MachineID(void)
Returns a 64-bit unique machine identifier,this may later be used to
form the ethernet MAC address but otherwise has no great significance on non
networked machines.
The top 8 bits are a CRC,based on the same algorithm the original DS2401
used - if the CRC fails zero will be substituted
ControllerAddress
=================
void *HAL_ControllerAddress(unsigned controller)
Asks the HAL where various controllers might or might not be.
Podule manager uses this information to determine at run time whether or not
to bother doing anything.
Returns r0=logical address of the chosen controller,or zero
0 = EASI card access speed control
1 = EASI space(s)
2 = VIDC1
3 = VIDC20
4 = S space base (IOMD,podules,NICs,blah blah)
5 = Extension ROM(s)
Matrix Keyboard
===============
Many devices provide a matrix keyboard interface. The following calls
provide access to it. Interrupt driven operation, or high-level calls will be
defined later.
int HAL_MatrixColumns(void)
Returns the number of columns available via the matrix interface.
Columns are numbered from 0 to <num columns>-1.
unsigned int HAL_MatrixScan(int column).
Returns a bitfield describing which rows are active on the specified column.
Any timing issues, or the driving of the matrix between calls are left to
the HAL.
Touchscreen
===========
PDA-type devices usually have a touchscreen as their primary pointing device.
This API provides a simple interface to a touchscreen. The calls are described
in terms of a resistive touchscreen, but other technologies should be mappable
onto it. Interrupt operation is yet to be defined.
unsigned int HAL_TouchscreenType(void)
Returns a flags word indicating the type of touchscreen.
bits 0-7: Touchscreen type 0=>none, 1=>resistive
bit 8: Interrupt operation supported
bit 9: Calibration not required
bits 10-15: Reserved
bits 16-21: Bits of precision available
bits 22-31: Reserved
"Calibration not required" indicates that the raw values returned map linearly
onto the screen display area to a usable accuracy as follows:
X,Y (00000000,00000000) = bottom left of display area
X,Y (FFFFFFFF,FFFFFFFF) = top right of display area
Pres 00000000-1FFFFFFF = no touch
Pres 20000000-3FFFFFFF = light touch
Pres 3FFFFFFF-7FFFFFFF = touch
Pres 80000000-FFFFFFFF = firm touch
unsigned int HAL_TouchscreenMeasure(int meas)
Performs a touchscreen measurement. Measurements are:
0 = X position
1 = Y position
2 = pressure
3 = X resistance
4 = Y resistance
"X" and "Y" need not actually be X and Y - rotation can be dealt with by
calibration.
All values are returned as unsigned 32-bit values in the range &00000000-&FFFFFFFF.
If using, for example, a 10-bit DAC, the 10-bit value read should be placed at the
top of the returned word. Ideally, the 10 bits should be replicated in lower bits
(ABCDEFGH IJABCDEF GHIJABCD EFGHIJAB) to ensure the returned values fully span
the 32-bit range.
Resistance measurements can be used to compensate for large pressed areas causing
shorts - subtract the instantaneous resistance from the instantaneous precision.
(I think).
Serial ports
============
The RS232 serial UART is a fundamental peripheral on most current hardware. All
Overview
========
The HAL introduces the new concept of a "device". A device is a logical
representation of a component of hardware. Each active devices is uniquely
identified by a constant pointer to a device descriptor. The descriptor is
a structure which contains information about the device and a series of entry
points to perform usually simple operations on the device. Devices can be
provided by the Bootloader, or by RISC OS modules.
Devices provided outside the Bootloader are, in principle, hot swappable,
although it is up to device drivers using it whether they can support this.
Throughout this document, device descriptors are described in terms of C,
although the scheme maps naturally to assembler or C++. All device calls use
the base ATPCS calling standard (R0-R3 arguments/return values, R4-R11
preserved, R12 corrupted), to permit straightforward use from C or assembler.
From C:
XXXDevice->Activate(XXXDevice);
A simple call to a activate a device from assembler might look like:
LDR R0, XXXDevice
MOV LR, PC
LDR PC, [R0, #DevEntry_Activate] ; R0-R3,R12 corrupted
If an assembler device driver module is using a lot of device calls, it
might be preferable to move the workspace pointer from the traditional R12
to R11.
The device descriptor
=====================
The device descriptor starts with a fixed format header, as described
below. Following this header are more function pointers providing device-specific
calls.
struct device
{
uint16_t type;
uint16_t id;
uint32_t location;
uint32_t version;
const char *description;
void *address;
uint32_t reserved[3];
bool (*Activate)(struct device *);
void (*Deactivate)(struct device *);
void (*Reset)(struct device *);
int32_t (*Sleep)(struct device *, int32_t state);
int32_t devicenumber;
bool (*TestIRQ)(struct device *);
uint32_t reserved[2];
};
struct serial
{
struct device dev;
uint8_t (*ReadByte)(struct serial *);
void (*WriteByte)(struct serial *, uint8_t c);
// private data
}
Hence, the first device specific function pointer is offset 32 bytes from the
device pointer.
Type
----
The type word describes what the device is.
Bits 15-8: Top level type (eg video, sound, system peripheral, comms port)
Defined values are: 1 = video
2 = sound
3 = system peripheral
4 = comms port
Bits 7-0: Second level type (eg VDU display, 16-bit PCM sound output,
interrupt controller, UART). Allocated independently within each top
level type.
This half-word, together with the version number, indicate which device specific calls
are available.
ID
--
16-bit product code - a unique identifier for this particular device.
Location
--------
The location describes the location of the device in terms of the bus architecture
of the computer. Again, it is grouped by bytes.
Bits 31-28: Bus type
0 => processor (0 = core, 1 = coprocessor)
1 => main system bus (0 = AHB, 1 = ASB, 2 = PXBus)
2 => peripheral bus (0 = APB)
3 => expansion bus (0 = Acorn Expansion Card, 1 = ISA, 2 = PCI)
4 => serial bus (0 = AC-Link)
Bits 27-24: Bus sub-type (see above)
Bits 23-16: Bus number
Bits 15-8: Card number (PCI, expansion card etc) / chip select number
Bits 7-0: Unit number
Version
-------
The version describes the version of the device API implemented. It consists of a
major version number (bits 31-16) and a minor version number (bits 15-0). A change in
major version number indicates an incompatible change of API. An increase in the
minor version number indicates backwards-compatible extensions to the API (eg
extra functions).
Description
-----------
A textual description of the device. This should be English, human-readable and
Basic Latin (characters &20-&7E). Descriptors along the lines of those output by
*Podules are expected. For example:
National Semiconductor 16C550 UART
Philips ISP1160 USB host controller
Acorn IOMD21 PS/2 keyboard
Acorn VIDC20
Intel SA-1110 DMA controller
Address
-------
This field may either be 0, or may be a pointer to the base address of the
memory-mapped registers of the device in question. Drivers should not
normally use this field to directly poke the device. If they do, they must be
absolutely certain that there is no other way to achieve the effect, and that
the device type word is known to them. What exactly the address points to
depends on the exact device in question.
Activate
--------
A device driver must call the Activate entry point before using a device. A
success/failure indication is returned: 1 indicates successful activation, 0 indicates
unsuccessful. Devices may ignore activate/deactivate calls, count them, or
may alternatively provide full locking to allow only one activation. Typically this
would be called by in a driver's module initialisation routine. Alternatively, it might
be called just before a DeviceFS device is opened for access.
Deactivate
----------
A device driver must call the Deactivate entry point when it has finished
using a device.
Reset
-----
The Kernel will call the Reset entry point of every device on the system
before performing a software reset (eg OS_Reset or Ctrl-Break), after it has
issued Service_PreReset. All devices must enter a quiescent state.
Sleep
-----
This call reads or sets a device's power-down state. If the second parameter is -1,
then the current state is returned; otherwise the second parameter must be a value in
the range 0-255 giving sleepiness (0 = full power, 255 = off) and the old sleepiness
is returned. Note that the value returned does not have to match the last value
programmed: for example, if a device cannot power down, it will always return 0.
DeviceNumber
------------
If this is -1, then the device has no associated interrupt. Otherwise, bits 0-30 give
the device number and bit 31 flags that the device vector is shared, ie this is the R0
that should be passed to OS_ClaimDeviceVector. If bit 31 is set then the TestIRQ
routine must be used to determine whether the vector should be claimed or passed on.
TestIRQ
-------
Returns 0 if the device is not interrupting, or 1 if the device is interrupting.
When DeviceNumber is -1, this must be a null pointer.
Creation and removal of devices
===============================
Devices are declared by calling the HAL->OS call OS_AddDevice or SWI OS_Hardware 2.
SWI OS_Hardware 2 (SWI &7A)
---------------------------
On entry: R0 -> device descriptor
R8 = 2
On exit: All registers preserved
void OS_AddDevice(uint32_t flags, struct device *d);
void HAL_InitDevices(uint32_t flags);
Declare a new device to the system. OS_AddDevice must not be called until
HAL_InitDevices is called.
Devices are removed by calling OS_Hardware 3. There is no HAL->OS equivalent.
SWI OS_Hardware 3 (SWI &7A)
---------------------------
On entry: R0 -> device descriptor
R8 = 3
On exit: All registers preserved
The Kernel tracks all present devices, issuing service calls as devices come and go, and
providing a call to enumerate devices of a particular type.
SWI OS_Hardware 4 (SWI &7A)
---------------------------
On entry: R0 bits 0-15 = type to match
bits 16-31 = maximum major version number to match
R1 = 0 to start an enumeration, else preserved from last call
R8 = 4
On exit: R1 = -1 if there are no (more) devices of this type
R2 -> device descriptor (undefined if R1 = -1)
Other registers preserved
Service_Hardware (Service Call &D9)
------------------------------------
On entry: R0 bits 0-7 = sub-reason code, bits 8-31 flags (undefined, ignore)
R1 = reason code (&D9)
R2 -> device
On exit: Depends on sub-reason code
Sub-reason code 0: Device added
On exit: All registers must be preserved
Sub-reason code 1: Device being removed
On exit: R1 = 0 => we object to device being removed
R0 -> error block
other registers must be preserved
else all registers must be preserved
New ClaimDeviceVector behaviour
R3 and R4 are meaningless, except for podule IRQ and FIQ-as-IRQ, which
keep the same behaviour as previously. (This is currently done in the Kernel,
but should be deferred to the Podule Manager).
For other claimants, if bit 31 of the R0 is set in the OS_ClaimDeviceVector
call, the interrupt will be passed on to earlier claimants unless your
routine claims the vector. This behaviour is then the same as IrqV claimants.
It is up to you to determine whether your device has interrupted. If it has,
you should service it, and claim the vector (by pulling the return address
off the stack). If not, pass the vector along. If no handlers claim the
vector, then the OS knows that there is no device driver able to handle the
interrupt being asserted, so it will mask off that line.
If you do not claim the vector, you must preserve R0 and R3. R1,R2,R12 may
be corrupted.
It is critical that your claiming or not is purely on the basis of whether
your card is interrupting, and is accurate. Not claiming when your card is
interrupting, or claiming when it isn't can both cause incorrect system
behaviour.
Entry into RISC OS:
POST check (if any) complete
CPU & memory systems at full speed
MMU off, SVC32 mode, IRQs+FIQs disabled
All interrupts masked
I/O timings set up
DRAM refresh running
Video system stabilised (off?)
Information passed:
Table of (addr,len) pairs of RAM
Address + amount of VRAM
Memory speed?
CPU speed?
Entry point to HAL
Questions:
How to clear RAM without logical copy? Do we NEED a logical copy?
Yes we do - but logical copy will NOT be contiguous.
Physical Size Logical - offset
F0000000 01000000 80000000 70000000
F1000000 01000000 81000000 70000000
60000000 00001000 82000000 22000000 - fast SRAM - how to signal?
02000000 00200000 80000000 7FE00000
10000000 01700000 80200000 70200000
11B00000 02500000 81900000 6FE00000
14000000 04000000 83E00000 6FE00000
02000000 00200000 82000000 80000000
10000000 01700000 90000000 80000000
11B00000 02500000 91B00000 80000000
14000000 04000000 94000000 80000000
Memory Map
00000000 16K Kernel workspace
00004000 16K Scratch space
00008000 Mem-32K Application memory
0xxxxxxx 3840M-Mem Dynamic areas
F0000000 160M I/O space (growing downwards if necessary)
FA000000 1M HAL workspace
FA100000 8K IRQ stack
FA200000 32K SVC stack
FA300000 8K ABT stack
FA400000 8K UND stack
FAE00000 1M Reserved for physical memory accesses
FAF00000 256k reserved for DCache cleaner address space (eg. StrongARM)
FAF40000 64k kernel buffers (for long command lines, size defined by KbuffsMaxSize)
FAFE8000 32K HAL workspace
FAFF0000 32K "Cursor/System/Sound" block (probably becoming just "System")
FAFF8000 32K "Nowhere"
FB000000 4M L2PT
FB400000 16K L1PT
FB404000 4M-16K System heap
FB800000 8M Soft CAM
FC000000 64M ROM
26-bit system:
00000000 16K Kernel workspace
00004000 16K Scratch space
00008000 28M-32K Application memory
01C00000 32K SVC stack
01C08000 2M-32K System heap
01F00000 32K Cursor/System/Sound
01F08000 32K "Nowhere"
02100000 15M Module area
03000000 8M I/O space
03800000 8M ROM
04000000 2G-64M Dynamic areas
80000000 512M Logical copy of physical space
A0000000 1280M Dynamic areas
F0000000 224M I/O space (growing downwards if necessary)
FE000000 1M HAL workspace
FE100000 8K ABT stack
FE200000 8K UND stack
FF000000 4M L2PT + embedded L1PT
FF800000 8M Soft CAM
"Soft" resets
Entry through HAL - full HAL initialisation.
HAL must not destroy (much) memory.
RISC OS detects intact memory and makes the reset "soft".
RAM page tables reconstructed from CAM.
Other page tables reconstructed through HAL.
"Break"
RISC OS calls HAL to shut down, then shuts off MMU, and calls HAL_Reset code.
HAL then re-enters RISC OS in the usual fashion.
SWI OS_Hardware (SWI &7A)
-------------------------
On entry: R0-R7 parameters
R8 = reason code (bits 0-7) and flags (bits 8-31)
R9 = hardware call number
On exit: depends on flags
This SWI provides access to the hardware layer. Conceptually, it is
similar to accessing the hardware registers directly in earlier versions
of RISC OS - whereever possible OS routines should be used in preference.
This call is primarily designed for the use of device drivers - for example
the PS2Driver module makes PS2 hardware calls using this interface.
Making hardware calls to devices normally managed by the Kernel is liable to
cause the same problems as poking the hardware. However, making hardware
calls is of course preferable to actually accessing the hardware directly.
Use this interface with caution.
SWI OS_Hardware 0 (SWI &7A)
---------------------------
On entry: R0-R7 parameters for hardware routine
R8 = 0
R9 = hardware call number
On exit: R0-R3 updated by call
R4-R9 preserved.
This SWI calls a HAL routine. HAL routines internally are ATPCS, so R0-R3 are
passed in as a1-a4, and R4-R7 are pushed on to the stack. The a1-a4 on exit
from the routine are passed back in R0-R3.
If the HAL routine is not available, an error is returned. Actual HAL
routines do not return RISC OS errors - any possible failure will be
indicated in a call-specific manner.
SWI OS_Hardware 1 (SWI &7A)
---------------------------
On entry: R8 = 1
R9 = hardware call number
On exit: R0 = routine address
R1 = static base value for routine
This call looks up the address of a HAL routine. If it does not exist, an
error is returned. Otherwise, the address of the routine is returned in R0.
Calls made to the routine should be in a privileged mode, with R9 (sb) set to
the static base value returned by this SWI. Refer to the HAL documentation
for more details of calling conditions.
G F D B 9 7 5 3 1 Gnd?
G J E C A 8 6 4 2 0
Aux
X
X
G 1 3 5 7 9 B D F x
0 2 4 6 8 A C E J x
FIQ
aux
14 pfiq
12 preq
15 pirq
13 rclk
Cont
3 Fiq
14 abe
9 nbw
15 dBE
1 wait
4 irq
8 nrw
2 brst
10 lock
clk mclk
0 state? (lk1)
7 seq? lk2
12 nopc? lk3
11 ntrans lk4
6 mreq
5 n/c
13 n/c
CLK to AUX link connects MCLK to AUX clock
Features
Bit 0: FIFOs available
int ReceiveByte(int port, int *status)
Returns the next byte from the FIFO (if enabled) or the holding register.
If status is non-NULL, the line status associated with the byte is
read (see LineStatus). The return value is only meaningful if a
received byte is available (bit 0 of *status will be set).
void TransmitByte(int port, int byte)
int LineStatus(int port)
Bit 0: Receiver Data Ready
Bit 1: Overrun Error
Bit 2: Parity Error
Bit 3: Framing Error
Bit 4: Break Error
Bit 5: Transmitter Holding Register Empty
Bit 6: Transmitter Empty (including FIFO)
Bit 7: FIFO contains a Parity, Framing or Break error
Parity, Framing and Break errors are associated with each byte received.
Whether the values reported here are associated with the last byte
read using ReceiveByte or with the next byte to be read is undefined.
You should request the status using ReceiveByte to ensure accurate
identification of bytes with errors.
Error bits are cleared whenever status is read, using either LineStatus
or ReceiveByte with status non-NULL.
int InterruptEnable(int port, int eor, int mask)
Enables interrupts. Bits are:
Bit 0: Received Data Available (and Character Timeout)
Bit 1: Transmitter Holding Register Empty
Bit 2: Received Line Status
Bit 3: Modem Status
Returns previous state.
int Rate(int port, int baud16)
Sets the rate, in units of 1/16 of a baud. Returns the previous rate.
Use -1 to read.
int Format(int port, int format)
Bits 0-1: Bits per word 0=>5, 1=>6, 2=>7, 3=>8
Bit 2: Stop length 0=>1, 1=>2 (1.5 if 5 bits)
Bit 3: Parity enabled
Bits 4-5: Parity: 0 => Odd (or disabled)
1 => Even
2 => Mark (parity bit = 1)
3 => Space (parity bit = 0)
Returns previous format. -1 to read.
void FIFOSize(int *rx, int *tx)
Returns the size of the RX and TX FIFOs. Either parameter may be NULL.
Note that the size of the TX FIFO is the total amount of data that can
be sent immediately when the Transmitter Holding Register Empty
status holds. (So an unusual UART that had a transmit threshold
should return total FIFO size minus threshold).
void FIFOClear(int port, int flags)
Clears the input FIFO (if bit 0 set) and the output FIFO (if bit 1 set).
int FIFOEnable(int port, int enable)
Enables or disables the RX and TX FIFOs: 0 => disable, 1 => enable
-1 => read status. Returns previous status.
int FIFOThreshold(int port, int threshold)
Sets the receive threshold level for the FIFO RX interrupt. Normally
available values are 1,4,8 and 14 bytes. Returns previous value.
-1 to read.
int InterruptID(int port)
Returns the highest priority interrupt currently asserted. In order
of priority:
3 => Receiver Line Status (Cleared by ReceiveByte/LineStatus)
2 => Received Data Available (Cleared by reading enough data)
6 => Character Timeout (received data waiting)
1 => Transmitter Holding Register Empty (Cleared by this call)
0 => Modem Status (Cleared by ModemStatus)
-1 => No Interrupt
The Modem Status interrupt occurs when the CTS, DSR or DCD inputs
change, or when RI goes from high to low (ie bits 0 to 3 of ModemStatus
are set).
int Break(int port, int enable)
Activates (1) or deactivates (0) a break condition. -1 to read,
returns previous state.
int ModemControl(int port, int eor, int mask)
Modifies the modem control outputs.
Bit 0: DTR
Bit 1: RTS
Note that these are logical outputs, although the physical pins may be inverted.
So 1 indicates a request to send.
int ModemStatus(int port)
Reads the modem status inputs.
Bit 0: CTS changed since last call
Bit 1: DSR changed since last call
Bit 2: RI changed from high to low since last call
Bit 3: DCD changed since last call
Bit 4: CTS
Bit 5: DSR
Bit 6: RI
Bit 7: DCD
Note that these are logical inputs, although the physical pins may be inverted.
So 1 indicates a Clear To Send condition.
int Device(int port)
File deleted
directory
130 fff 0 Mike_Stephens 2bf39672 31060a66 0
258 fff 0 Mike_Stephens 2bf395c1 31060a66 0
directory
130 fff 1 Mike_Stephens 2bf39672 31060a66 0
258 fff 1 Mike_Stephens 2bf395c1 31060a66 0
000 App space
01C System heap/svc stack
01E Soft CAM copy/und stack
01F Sound/pointer/random
020 RMA
02C L2PT and L1PT
030 I/O
038 ROM
040 Screen
060 Free pool
0E2 Sprites
164 Font cache
1E6 RAM disc
268 Another area 1
2EA Another area 2
36C Another area 3
3EE Another area 4
470 Another area 5
4F2 Another area 6
574 Another area 7
5F6 Another area 8
678 Another area 9
6FA Another area 10
77C Another area 11
7FE Nothing
800 Phys space copy
A00 Another area 12
A82 Another area 13
B04 Another area 14
B86 Another area 15
C08 Another area 16
C8A Another area 17
D0C Another area 18
D8E Another area 19
E10 Another area 20
E92 Another area 21
F14 Another area 22
F96 Nothing
000 App space
01C System heap/svc stack
01E Soft CAM copy/und stack
01F Sound/pointer/random
020 RMA
02C L2PT and L1PT
030 I/O
038 ROM
040 Screen
060 Free pool
162 Sprites
264 Font cache
366 RAM disc
468 Another area 1
56A Another area 2
66C Another area 3
76E Nothing
800 Phys space copy
A00 Another area 4
B02 Another area 5
C03 Another area 6
D04 Another area 7
E05 Another area 8
F06 Nothing
File deleted
directory
5thColumn 1000 0 Mike_Stephens 2e05be22 30fd2d55 0
MMPM fff 0 Mike_Stephens 2c53f7f8 31060a6b 0
ScreenMode fff 0 Mike_Stephens 2c4d19fc 31060a6b 0
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment