![]() |
Basic interaction with the
|
![]() |
So that is what this document is all about. Interacting with your Intel silicon. Please, do not ask why a person might want to do this. I'm in it for "hack value", others might see it as a way to make a 'More Impressive Demo' (the 80x86 processing data, the ARM managing, and displaying the data). If you are unable to think of any possible reason for talking to the co-processor, then you probably won't want to read the rest of this... :-)
Here's our destination:
And, of course, what we will NOT be covering:
Our objective is NOT to cobble together some form of DOS™ based system. Aleph1
have put a lot of work into getting a system capable of running DOS™, Windows™ 3.1x,
Windows™ 95, and Windows™ 98. It doesn't cost a lot when you consider what you're
getting. Go buy the real deal. Or if you're a sad cheapskate, there is the Acorn !PCx86
(which will screw up if you try to run Windows™ 95) on the old Acorn ftp site, and
countless Acorn User CD-ROMs...
As several ex-Acorn people might have said, making a stable DOS™ environment is
non-trivial.
PC Card Software
". So you can simply check
for a task of that name.
DIM block% 32 offset% = 0 REPEAT SYS "TaskManager_EnumerateTasks", offset%, block%, 16 TO offset% IF FNgetstring(block%!4) = "PC Card Software" THEN PRINT "PC CARD SOFTWARE IS LOADED" ENDIF UNTIL (offset% < 0) END DEFFNgetstring(ptr%) LOCAL out$ out$ = "" WHILE ( ((?ptr%)<>0) AND ((?ptr%)<>13) ) out$+=CHR$(?ptr%) ptr%+=1 ENDWHILE =out$Obviously, if the PC card software is running, we'll not want to continue with our software, but instead warn the user to shut down !PCx86/!PCPro before running our code. Modify the above program as necessary.
If the co-processor is not installed, you should fail at the first test (the one that asks if the co-processor is fitted).
REM >gemitype REM Detect Gemini 1 or Gemini 2 ON ERROR PRINT REPORT$+" at "+STR$(ERL/10):END asic_gemi2_base% = &37A0000 asic_gemi2_id% = &1000 asic_gemi2_rev2% = &8000 asic_masr_base% = &3730000 DIM code% 256 FOR loop% = 0 TO 2 STEP 2 P% = code% [ OPT loop% .write ; Entry: ; R0 = Address to write to ; R1 = Value to write ; Exit: ; Registers preserved ; SWI "OS_EnterOS" STR R1, [R0] TEQP PC, #0 MOV R0, R0 MOVS PC, R14 .read ; Entry: ; R0 = Address to read from ; Exit: ; R0 = Value read ; Other registers preserved ; SWI "OS_EnterOS" LDR R0, [R0] TEQP PC, #0 MOV R0, R0 MOVS PC, R14 ] NEXT REM First, clear the Gemini 2 ID bit A% = asic_gemi2_base% B% = asic_gemi2_id% CALL write REM Read the mailbox address/status register A% = asic_masr_base% value% = USR(read) IF (value% AND &7F00000) THEN PRINT "MASR read back was &"+STR$~(value%) PRINT "(bits 20...26 should be zero)" PRINT "[ ** IS THE CO-PROCESSOR FITTED? ** ]" END ENDIF REM Now set the Gemini 2 ID bit A% = asic_gemi2_base% B% = (asic_gemi2_id% OR asic_gemi2_rev2%) CALL write REM Read the mailbox again A% = asic_masr_base% value% = USR(read) IF ((value% AND &7F00000) = 0) THEN PRINT "Gemini 1 detected" END ENDIF IF ((value% AND &7F00000) = &7F00000) THEN PRINT "Gemini 2 detected" END ENDIF PRINT "Unknown Gemini version." PRINT "MASR bits 20...26 should be all zero or all one." ENDThere is no absolute need to know which ASIC is fitted unless you plan to do deep stuff. For our purposes, a co-processor card is a co-processor card. This check was included for interest.
You should not run into problems if you assume that the processor is a standard 80486SX, though if you plan to hive off FP intensive work to the processor you will be wanting to run a test to see if the 'DX' version is fitted.
A way to determine the processor type is...
This code is untested; it is based largely upon the information provided in one of Intel's data sheets. .data public _cpu_type public _fpu_type _cpu_type db 0 _fpu_type db 0 fp_status dw 0 ; the < 80386 tests have been omitted as the hardware is ; not available as a RiscPC co-processor. mov _cpu_type, 0 ; unkonwn processor ; The AC bit, bit #18, is a new bit introduced in the EFLAGS ; register on the Intel486 processor to generate alignment ; faults. This bit cannot be set on the Intel386 processor. .386 check_80386: pushfd ; push original EFLAGS pop eax ; get original EFLAGS mov ecx, eax ; save original EFLAGS xor eax, 40000h ; flip AC bit in EFLAGS push eax ; save new EFLAGS value on stack popfd ; replace current EFLAGS pushfd ; get new EFLAGS pop eax ; store new EFLAGS in EAX xor eax, ecx ; ca'nt toggle AC bit, processor is 80386 mov _cpu_type, 3 ; set processor type to 3 (80386) jz end_cpu_type ; jump if 80386 push ecx ; restore AC bit in EFLAGS popfd ; Checking for ability to set/clear ID flag (Bit 21) in EFLAGS ; which indicates the presence of a processor with the CPUID ; instruction. .486 check_80486: mov _cpu_type, 4 ; set processor type to 80486 mov eax, ecx ; get original EFLAGS xor eax, 200000h ; flip ID bit in EFLAGS push eax ; save new value on stack popfd ; replace current EFLAGS pushfd ; get new EFLAGS pop eax ; store new EFLAGS in EAX xor eax, ecx ; can't toggle ID bit... je end_cpu_type ; processor is an 80486 ; for further detection of processor type (SX, DX, etc) we ; would execute the CPUID instruction and examine the ; results... end_cpu_type: ; now we will check for FPU. If FP status and control words ; are present, an FPU exists - otherwise it doesn't. ; we are only interested in FPU/noFPU, there are further ; tests to determine what *type* of FPU is present. fninit ; reset FP status word mov fp_status, 5a5ah ; initialise temp word non-zero fnstsw fp_status ; save FP status word mov ax, fp_status ; check FP status word cmp al, 0 ; was correct information written? mov _fpu_type, 0 jne end_fpu_type ; incorrect information, no FPU fnstcw fp_status ; save FP control word mov ax, fp_status ; check FP control word and ax, 103fh ; selected parts to examine cmp ax, 3fh ; was control word correct? mov _fpu_type, 0 jne end_fpu_type ; incorrect control word, no FPU mov _fpu_type, 1 ; all correct, FPU present end_fpu_type: ; here: ; _cpu_type is 0, 3, or 4. ; _fpu_type is 0 or 1. ret
First, however, we need routines to initialise the co-processor...
REM >coprosetup REM Initialise the processor ON ERROR PRINT REPORT$+" at "+STR$(ERL/10):END MODE 12 PROCcoproc_setup PROChardware_initialise END : : DEFPROCcoproc_setup REM Gemini II ASIC asic_gemi2_base% = &37A0000 asic_gemi2_id% = &1000 asic_gemi2_rev2% = &8000 REM Configuration register cnfg_reg% = &3760000 REM Miscellaneous control register misc_ctrl_reg% = &3750000 misc_pwrgood% = 1 misc_a20gate% = &20 REM Processor/Interrupt control register picr_reg% = &3740000 REM Mailbox address/status register asic_masr_base% = &3730000 REM I/O map control register iomap_ctrl_reg% = &3720000 REM Memory map control register memmap_ctrl_reg% = &3710000 DIM code% 256 FOR loop% = 0 TO 2 STEP 2 P% = code% [ OPT loop% .write ; Entry: ; R0 = Address to write to ; R1 = Value to write ; Exit: ; Registers preserved ; SWI "OS_EnterOS" STR R1, [R0] TEQP PC, #0 MOV R0, R0 MOVS PC, R14 .read ; Entry: ; R0 = Address to read from ; Exit: ; R0 = Value read ; Other registers preserved ; SWI "OS_EnterOS" LDR R0, [R0] TEQP PC, #0 MOV R0, R0 MOVS PC, R14 ] NEXT ENDPROC : DEFPROChardware_initialise PRINT "Initialising hardware..." A% = asic_gemi2_base% B% = asic_gemi2_id% CALL write REM Put CPU in reset A% = misc_ctrl_reg% B% = misc_a20gate% CALL write REM (in case of new A20 modification) A% = &3770000 : REM External register B% = 1 CALL write REM Blank memory map A% = memmap_ctrl_reg% B% = 0 CALL write REM Blank I/O map A% = iomap_ctrl_reg% B% = &4000 OR &8000 CALL write REM Blank processor/interrupt control register A% = picr_reg% B% = 0 CALL write REM Disable caching for now A% = cnfg_reg% B% = 1 : REM Memory = 1Mb CALL write REM Disable general purpose I/O decodes FOR l% = 0 TO 3 A% = &3780000 + (l% << 2) B% = 0 CALL write NEXT REM Disable floppy disc control register A% = &3790004 B% = 0 CALL write REM Set test timing value A% = &37F0000 B% = 4 CALL write PROCwait(50) REM Clearing mailbox PROCclear_mbx PROCwait(10) REM Setting PWRGOOD A% = misc_ctrl_reg% B% = (misc_pwrgood% OR misc_a20gate%) CALL write PROCwait(20) PRINT "Done!" ENDPROC : : DEFPROCwait(for%) LOCAL now%, then% SYS "OS_ReadMonotonicTime" TO now% REPEAT SYS "OS_ReadMonotonicTime" TO then% UNTIL then% < (now% + for%) ENDPROC : DEFPROCclear_mbx LOCAL word% FOR loop% = 0 TO 99 A% = asic_masr_base% word% = USR(read) IF (word% AND &80000000) THEN ENDPROC IF (word% AND &20000000) THEN A% = asic_masr_base% word% = USR(read) ELSE A% = asic_masr_base% B% = 0 CALL write ENDIF NEXT ENDPROC :