|
Podule access |
|
A complete description is beyond the scope of this article. If you would like details (39 pages
of it, PostScript or DrawFiles), then you will find it at
the Acorn ftp site, in the directory
/documents/products/expspec/.
Alternatively, try the mirror archive site.
Address: %000000110aabbcccaaaaaaaaaddddd00
Where: aa..aa is the device address in the memory map
bb is the access type:
%00 slow
%01 medium
%10 fast
%11 synchronous
ccc is the bank:
0 - IOC control registers
1 - Floppy disc controller (fast)
2 - Econet (sync)
3 - Serial port (sync)
4 - Expansion cards (slow/med/fast/sync)
5 - Harddisc (med)
5 - Printer (fast)
7 - Expansion cards (slow)
ddd is an offset in the device
Thus, basically, the I/O memory map looks like:
&3310000 Floppy disc controller
&33A0000 Econet ADLC
&33B0000 Serial port controller
&3240000 Internal expansion cards (slow)
&32C0000 Internal expansion cards (medium)
&3340000 Internal expansion cards (fast)
&33C0000 Internal expansion cards (sync)
&32D0000 Harddisc interface
&3350010 Printer Data
&3270000 External expansion cards (slow)
THIS IS FOR THE ARCHIMEDES; THINGS ARE DIFFERENT ON THE RISCPC
This area is not accessible in USR mode. For an example:
>SYS "Parallel_HardwareAddress" TO addr% >P. ~addr% 30109E0 >P. !addr% Internal error: abort on data transfer at &022B1254 >As BASIC runs in USR mode, it fails.
10 DIM code% 128 20 P% = code% 30 [ OPT 2 40 SWI "Parallel_HardwareAddress" ; address is in R0 50 SWI "OS_EnterOS" 60 MOV R2, #&FE 70 STR R2, [R0] 80 LDR R0, [R0] ; load R0 with word pointed to by R0 90 TEQP PC, #0 100 MOV R0, R0 110 MOV PC, R14 120 ] 130 PRINT ~USR(code%)The result of this is
FE00FE.
SYS "Podule_ReturnNumber" TO podcnt%
FOR podule% = 0 TO (podcnt%-1)
SYS "XPodule_HardwareAddresses",,,, podule% TO baseaddress% ; err%
IF (err% AND 1) THEN
PRINT "Podule "+STR$(podule%)+" is empty"
ELSE
PRINT "Podule "+STR$(podule%)+" base &"+STR$~(baseaddress%)
ENDIF
NEXT
The program above returns the address used for synchronous access. The podule identity stuff is
always accessed synchronous.
REM >visioncode
ON ERROR PRINT REPORT$+" at "+STR$(ERL/10) : END
PROCassemble
visionbase% = 0
SYS "Podule_ReturnNumber" TO podcnt%
FOR podule% = 0 TO (podcnt%-1)
SYS "XPodule_HardwareAddresses",,,, podule% TO baseaddress% ; err%
IF (err% AND 1) THEN
PRINT "Podule "+STR$(podule%)+" not installed"
ELSE
PRINT "Podule "+STR$(podule%)+" base &"+STR$~(baseaddress%);
B% = baseaddress%
IF USR(find_podule%) = 1 THEN
visionbase% = baseaddress%
PRINT "...this is a Vision."
ELSE
PRINT
ENDIF
ENDIF
NEXT
REM Once we know our base address, we can set up some offsets.
REM The down conversion changes our podule access methods.
visionheader% = visionbase% - &180000 : REM Base, slow access
visionctrl% = visionheader% + &102800 : REM Control, fast access
visiondata% = visionheader% + &103800 : REM Data, fast access
visionstat% = visionheader% + &100080 : REM Status, fast access
visionrst% = visionheader% + &2000 : REM Reset, slow access
REM Code to reset, check, and fetch image removed
REM not necessary for this example
END
DEFPROCassemble
DIM code% 76
FOR loop% = 0 TO 2 STEP 2
P% = code%
[ OPT loop%
\ On entry, R1 = base address
\ On exit, R2 = 1 if Vision, else 0
.find_podule%
; Stash R14 and enter SVC mode.
STMFD R13!, {R14}
SWI "OS_EnterOS"
; Set flag to TRUE. If a test fails, flag will be FALSified. <g>
MOV R0, #1
; Is +12 &AF?
LDRB R2, [R1, #12]
CMP R2, #&AF
MOVNE R0, #0
; Is +16 &00?
LDRB R2, [R1, #16]
CMP R2, #&00
MOVNE R0, #0
; Is +20 &2D?
LDRB R2, [R1, #20]
CMP R2, #&2D
MOVNE R0, #0
; Is +24 &00?
LDRB R2, [R1, #24]
CMP R2, #&00
MOVNE R0, #0
TEQP PC, #0
MOV R0, R0
LDMFD R13!, {PC}
]
NEXT
ENDPROC
The name may not make much sense to you, but if you are using a RiscPC then it is a very
important name. The 37C665 (pictured) is the device that handles your parallel port, serial port,
floppy disc, IDE bus...In order to read the configuration of the 37C665, we need to write &55 (85) to port &3F0. However, we don't yet know where in memory the device is located. There are two ways to determine the location of the device:
&30109E0.&278 << 2
which is &9E0.
So, port &3F0 (which becomes &FC0 when shifted) is where we write &55 to set the
device into configuration mode. Two consecutive writes must be made, so it is worth switching
off interrupts.
This will only work on the RiscPC, and you MUST release yourself from configuration
mode before attempting to use your computer. It goes without saying that you ONLY read the
configuration registers, never write to them!
Once we are in configuration mode, we write a register number (0-15) to &3F0 and we can then read the value of that register from &3F1. It is simple to whizz through the registers, dumping the contents to memory as we go.
To leave configuration mode, we write &AA to &3F0. This must be done or your computer's I/O will just cease to function.
This code will ONLY work on the 37C665 fitted into the RiscPC. It is worth noting that the 37C666 (basically a 665 but uses hardware links to configure it, the sort of thing you'd find on a cheap ISA combo-card) uses the magic value &66 to enter configuration mode. If your machine has a different I/O chip, like the RiscStation or A7000, you might like to try a different machine value if &55 doesn't work. Maybe &99? This is speculation though, as my data sheet doesn't cover the 37C669. Please email me if you discover a sequence that works.
This takes place in SVC mode, with interrupts disabled. The code is pretty basic really. I rather
suspect that the final TEQP could be combined into the MOVS PC, R14 to
restore the flags and interrupt state. But doing it this way makes sure... The code is not
32bit compliant.
ON ERROR PRINT REPORT$+" at line "+STR$(ERL/10) : END
DIM code% 128
FOR l% = 0 TO 2 STEP 2
P% = code%
[ OPT l%
STR R14, [R13, #-4]!
SWI "OS_EnterOS"
TEQP PC, #&0C000003 ; interrupts disabled
LDR R0, base_address
MOV R1, #&55
STRB R1, [R0, #&FC0] ; port &3F0
STRB R1, [R0, #&FC0]
; Now in 37C665 software configuration mode
ADR R2, registers ; Where to store registers
MOV R3, #0 ; Register number (& offset)
.read_loop
; Write desired register number to address &3F0
STRB R3, [R0, #&FC0]
; Now read register contents from address &3F1
LDRB R1, [R0, #&FC4]
; Store it in our register block
STRB R1, [R2, R3]
ADD R3, R3, #1
CMP R3, #16
BLT read_loop
MOV R1, #&AA
STRB R1, [R0, #&FC0]
; Now out of software configuration mode
TEQP PC, #&08000000 ; interrupts enabled, USR mode
MOV R0, R0
LDR R14, [R13], #4
MOVS PC, R14
.base_address
EQUD &03010000
.registers
EQUD 0
EQUD 0
EQUD 0
EQUD 0
]
NEXT
PRINT "Examining multi-I/O chip configuration...";
CALL code%
PRINT "done."''
PRINT "Device identification ";
CASE registers?13 OF
WHEN &65 : PRINT "FDC37C665GT";
WHEN &66 : PRINT "FDC37C666GT"; : REM Different magic value, so should not happen!
OTHERWISE : PRINT "Error! Device ID "+STR$~(registers?13)+" unrecognised!" : END
ENDCASE
PRINT ", revision "+STR$(registers?14)
END
Briefly, the registers are: