diff options
author | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
---|---|---|
committer | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
commit | e611b132f9b8abe35b362e5870b74bce94a1e58e (patch) | |
tree | a5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/ntos/fw/mips/d4reset.s | |
download | NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2 NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip |
Diffstat (limited to 'private/ntos/fw/mips/d4reset.s')
-rw-r--r-- | private/ntos/fw/mips/d4reset.s | 3046 |
1 files changed, 3046 insertions, 0 deletions
diff --git a/private/ntos/fw/mips/d4reset.s b/private/ntos/fw/mips/d4reset.s new file mode 100644 index 000000000..ab4c2ecea --- /dev/null +++ b/private/ntos/fw/mips/d4reset.s @@ -0,0 +1,3046 @@ +#if defined(DUO) && defined(R4000) +/*++ + +Copyright (c) 1991 Microsoft Corporation + +Module Name: + + d4reset.s + +Abstract: + + This module is the start of the flash prom code. This code will + be the first run upon reset. It contains the self-test and + initialization. + +Author: + + Lluis Abello (lluis) 8-Jan-91 + +Environment: + + Executes in kernal mode. + +Notes: + + ***** IMPORTANT ***** + + This module must be linked such that it resides in the + first page of the rom. + +Revision History: + + +--*/ +// +// include header file +// +#include <ksmips.h> +#include <duoprom.h> +#include "dmaregs.h" +#include "selfmap.h" +#include "led.h" +#include "j4reset.h" + + +#define TlbInit PROM_ENTRY(10) + + + +//TEMPTEMP + +#define COPY_ENTRY 6 + +.text +.set noreorder +.set noat + + + ALTERNATE_ENTRY(ResetVector) +/*++ + +Routine Description: + + This routine will provide the jump vectors located + at the targets of the processor exception vectors. + + N.B. This routine must be located at the start of ROM which + is the location of the reset vector. + +Arguments: + + None. + +Return Value: + + None. + +--*/ +// +// this instruction must be loaded at location 0 in the +// rom. This will appear as BFC00000 to the processor +// + b ResetException + nop + +// +// This is the jump table for rom routines that other +// programs can call. They are placed here so that they +// will be unlikely to move. +// +// +// This becomes PROM_ENTRY(2) as defined in ntmips.h +// + .align 4 + nop +// +// Entries 4 to 7 are used for the ROM Version and they +// must be zero in this file. +// + +// +// This becomes PROM_ENTRYS(8,9...) +// + .align 6 + nop // entry 8 + nop + nop // entry 9 + nop + b InvalidateDCache // entry 10 + nop + b InvalidateSCache // entry 11 + nop + b InvalidateICache // entry 12 + nop + nop // entry 13 + nop + b PutLedDisplay // entry 14 + nop + nop // entry 15 + nop + nop // entry 16 + nop + +RomRemoteSpeedValues: +// +// This table contains the default values for the remote speed regs. +// + .byte REMSPEED1 // ethernet + .byte REMSPEED2 // SCSI + .byte REMSPEED3 // SCSI + .byte REMSPEED4 // RTC + .byte REMSPEED5 // Kbd/Mouse + .byte REMSPEED6 // Serial port 1 + .byte REMSPEED7 // Serial port 2 + .byte REMSPEED8 // Parallel + .byte REMSPEED9 // NVRAM + .byte REMSPEED10 // Int src reg + .byte REMSPEED11 // PROM + .byte REMSPEED12 // New dev + .byte REMSPEED13 // New dev + .byte REMSPEED14 // LED + + .align 4 + +// +// New TLB Entries can be added to the following table +// The format of the table is: +// entryhi; entrylo0; entrylo1; pagemask +// +#define TLB_HI 0 +#define TLB_LO0 4 +#define TLB_LO1 8 +#define TLB_MASK 12 + +TlbEntryTable: + +// +// 256KB Base PROM Read only +// 256KB Flash PROM Read/Write +// + + .word ((PROM_VIRTUAL_BASE >> 13) << ENTRYHI_VPN2) + .word ((PROM_PHYSICAL_BASE >> 12) << ENTRYLO_PFN) + \ + (1 << ENTRYLO_G) + (1 << ENTRYLO_V) + (2 << ENTRYLO_C) + + + .word (((PROM_PHYSICAL_BASE+0x40000) >> 12) << ENTRYLO_PFN) + \ + (1 << ENTRYLO_G) + (1 << ENTRYLO_V) + \ + (2 << ENTRYLO_C) + (1 << ENTRYLO_D) + + .word (PAGEMASK_256KB << PAGEMASK_PAGEMASK) + +// +// I/O Device space non-cached, valid, dirty +// + .word ((DEVICE_VIRTUAL_BASE >> 13) << ENTRYHI_VPN2) + .word ((DEVICE_PHYSICAL_BASE >> 12) << ENTRYLO_PFN) + (1 << ENTRYLO_G) + \ + (1 << ENTRYLO_V) + (1 << ENTRYLO_D) + (2 << ENTRYLO_C) + .word (1 << ENTRYLO_G) // set global bit even if page not used + .word (PAGEMASK_64KB << PAGEMASK_PAGEMASK) +// +// video control 2MB non-cached read/write. +// + .word ((VIDEO_CONTROL_VIRTUAL_BASE >> 13) << ENTRYHI_VPN2) + .word ((VIDEO_CONTROL_PHYSICAL_BASE >> 12) << ENTRYLO_PFN) + \ + (1 << ENTRYLO_G) + (1 << ENTRYLO_V) + \ + (1 << ENTRYLO_D) + (2 << ENTRYLO_C) + .word (((VIDEO_CONTROL_PHYSICAL_BASE+0x100000) >> 12) << ENTRYLO_PFN) + \ + (1 << ENTRYLO_G) + (1 << ENTRYLO_V) + \ + (1 << ENTRYLO_D) + (2 << ENTRYLO_C) + .word (PAGEMASK_1MB << PAGEMASK_PAGEMASK) +// +// extended video control 2MB non-cached read/write. +// + .word ((EXTENDED_VIDEO_CONTROL_VIRTUAL_BASE >> 13) << ENTRYHI_VPN2) + .word ((EXTENDED_VIDEO_CONTROL_PHYSICAL_BASE >> 12) << ENTRYLO_PFN) + \ + (1 << ENTRYLO_G) + (1 << ENTRYLO_V) + \ + (1 << ENTRYLO_D) + (2 << ENTRYLO_C) + + .word (((EXTENDED_VIDEO_CONTROL_PHYSICAL_BASE+0x100000) >> 12) << ENTRYLO_PFN) + \ + (1 << ENTRYLO_G) + (1 << ENTRYLO_V) + \ + (1 << ENTRYLO_D) + (2 << ENTRYLO_C) + .word (PAGEMASK_1MB << PAGEMASK_PAGEMASK) +// +// video memory space 8Mb non-cached read/write +// + .word ((VIDEO_MEMORY_VIRTUAL_BASE >> 13) << ENTRYHI_VPN2) + .word ((VIDEO_MEMORY_PHYSICAL_BASE >> 12) << ENTRYLO_PFN) + (1 << ENTRYLO_G) + \ + (1 << ENTRYLO_V) + (1 << ENTRYLO_D) + (2 << ENTRYLO_C) + .word (((VIDEO_MEMORY_PHYSICAL_BASE+0x400000) >> 12) << ENTRYLO_PFN) + \ + (1 << ENTRYLO_G) + (1 << ENTRYLO_V) + \ + (1 << ENTRYLO_D) + (2 << ENTRYLO_C) + .word (PAGEMASK_4MB << PAGEMASK_PAGEMASK) +// +// EISA I/O 16Mb non-cached read/write +// EISA MEM 16Mb non-cached read/write +// + .word ((EISA_IO_VIRTUAL_BASE >> 13) << ENTRYHI_VPN2) + .word ((EISA_IO_PHYSICAL_BASE >> 12) << ENTRYLO_PFN) + (1 << ENTRYLO_G) + \ + (1 << ENTRYLO_V) + (1 << ENTRYLO_D) + (2 << ENTRYLO_C) + .word ((0x100000) << ENTRYLO_PFN) + (1 << ENTRYLO_G) + \ + (1 << ENTRYLO_V) + (1 << ENTRYLO_D) + (2 << ENTRYLO_C) + .word (PAGEMASK_16MB << PAGEMASK_PAGEMASK) +// +// EISA I/O page 0 non-cached read/write +// EISA I/O page 1 non-cached read/write +// + .word ((EISA_EXTERNAL_IO_VIRTUAL_BASE >> 13) << ENTRYHI_VPN2) + .word ((0 >> 12) << ENTRYLO_PFN) + (1 << ENTRYLO_G) + \ + (1 << ENTRYLO_V) + (1 << ENTRYLO_D) + (2 << ENTRYLO_C) + .word (((EISA_IO_PHYSICAL_BASE + 1 * PAGE_SIZE) >> 12) << ENTRYLO_PFN) + \ + (1 << ENTRYLO_G) + (1 << ENTRYLO_V) + \ + (1 << ENTRYLO_D) + (2 << ENTRYLO_C) + .word (PAGEMASK_4KB << PAGEMASK_PAGEMASK) +// +// EISA I/O page 2 non-cached read/write +// EISA I/O page 3 non-cached read/write +// + .word (((EISA_EXTERNAL_IO_VIRTUAL_BASE + 2 * PAGE_SIZE) >> 13) << ENTRYHI_VPN2) + .word (((EISA_IO_PHYSICAL_BASE + 2 * PAGE_SIZE) >> 12) << ENTRYLO_PFN) + \ + (1 << ENTRYLO_G) + (1 << ENTRYLO_V) + \ + (1 << ENTRYLO_D) + (2 << ENTRYLO_C) + .word (((EISA_IO_PHYSICAL_BASE + 3 * PAGE_SIZE) >> 12) << ENTRYLO_PFN) + \ + (1 << ENTRYLO_G) + (1 << ENTRYLO_V) + \ + (1 << ENTRYLO_D) + (2 << ENTRYLO_C) + .word (PAGEMASK_4KB << PAGEMASK_PAGEMASK) +// +// EISA I/O page 4 non-cached read/write +// EISA I/O page 5 non-cached read/write +// + .word (((EISA_EXTERNAL_IO_VIRTUAL_BASE + 4 * PAGE_SIZE) >> 13) << ENTRYHI_VPN2) + .word (((EISA_IO_PHYSICAL_BASE + 4 * PAGE_SIZE) >> 12) << ENTRYLO_PFN) + \ + (1 << ENTRYLO_G) + (1 << ENTRYLO_V) +\ + (1 << ENTRYLO_D) + (2 << ENTRYLO_C) + .word (((EISA_IO_PHYSICAL_BASE + 5 * PAGE_SIZE) >> 12) << ENTRYLO_PFN) + \ + (1 << ENTRYLO_G) + (1 << ENTRYLO_V) + \ + (1 << ENTRYLO_D) + (2 << ENTRYLO_C) + .word (PAGEMASK_4KB << PAGEMASK_PAGEMASK) +// +// EISA I/O page 6 non-cached read/write +// EISA I/O page 7 non-cached read/write +// + .word (((EISA_EXTERNAL_IO_VIRTUAL_BASE + 6 * PAGE_SIZE) >> 13) << ENTRYHI_VPN2) + .word (((EISA_IO_PHYSICAL_BASE + 6 * PAGE_SIZE) >> 12) << ENTRYLO_PFN) + \ + (1 << ENTRYLO_G) + (1 << ENTRYLO_V) + \ + (1 << ENTRYLO_D) + (2 << ENTRYLO_C) + .word (((EISA_IO_PHYSICAL_BASE + 7 * PAGE_SIZE) >> 12) << ENTRYLO_PFN) + \ + (1 << ENTRYLO_G) + (1 << ENTRYLO_V) + (1 << ENTRYLO_D) + (2 << ENTRYLO_C) + .word (PAGEMASK_4KB << PAGEMASK_PAGEMASK) +// +// EISA I/O pages 8,9,a,b non-cached read/write +// EISA I/O pages c,d,e,f non-cached read/write +// + .word (((EISA_EXTERNAL_IO_VIRTUAL_BASE + 8 * PAGE_SIZE) >> 13) << ENTRYHI_VPN2) + .word (((EISA_IO_PHYSICAL_BASE + 8 * PAGE_SIZE) >> 12) << ENTRYLO_PFN) + \ + (1 << ENTRYLO_G) + (1 << ENTRYLO_V) + (1 << ENTRYLO_D) + (2 << ENTRYLO_C) + .word (((EISA_IO_PHYSICAL_BASE + 12 * PAGE_SIZE) >> 12) << ENTRYLO_PFN) + \ + (1 << ENTRYLO_G) + (1 << ENTRYLO_V) + (1 << ENTRYLO_D) + (2 << ENTRYLO_C) + .word (PAGEMASK_16KB << PAGEMASK_PAGEMASK) +// +// Map 64KB of memory for the video prom code&data cached. +// + .word ((VIDEO_PROM_CODE_VIRTUAL_BASE >> 13) << ENTRYHI_VPN2) + .word ((VIDEO_PROM_CODE_PHYSICAL_BASE >> 12) << ENTRYLO_PFN) + (1 << ENTRYLO_G) + \ + (1 << ENTRYLO_V) + (1 << ENTRYLO_D) + (3 << ENTRYLO_C) + .word (1 << ENTRYLO_G) // set global bit even if page not used + .word (PAGEMASK_64KB << PAGEMASK_PAGEMASK) + +// +// Map 4kb of exclusive memory and 4Kb of shared +// + .word ((EXCLUSIVE_PAGE_VIRTUAL_BASE >> 13) << ENTRYHI_VPN2) + .word ((EXCLUSIVE_PAGE_PHYSICAL_BASE >> 12) << ENTRYLO_PFN) + (1 << ENTRYLO_G) + \ + (1 << ENTRYLO_V) + (1 << ENTRYLO_D) + (4 << ENTRYLO_C) + .word ((SHARED_PAGE_PHYSICAL_BASE >> 12) << ENTRYLO_PFN) + (1 << ENTRYLO_G) + \ + (1 << ENTRYLO_V) + (1 << ENTRYLO_D) + (5 << ENTRYLO_C) + .word (PAGEMASK_4KB << PAGEMASK_PAGEMASK) + + +// +// Map PCR for kernel debugger. +// + .word ((PCR_VIRTUAL_BASE >> 13) << ENTRYHI_VPN2) + .word (1 << ENTRYLO_G) // set global bit even if page not used + .word ((PCR_PHYSICAL_BASE >> 12) << ENTRYLO_PFN) + (1 << ENTRYLO_G) + \ + (1 << ENTRYLO_V) + (1 << ENTRYLO_D) + (2 << ENTRYLO_C) + .word (PAGEMASK_4KB << PAGEMASK_PAGEMASK) + +TlbEntryEnd: + .byte 0 + + + +// +// these next vectors should be loaded at PROM_BASE + 0x200, 0x300, +// and 0x380. They are for the TLBmiss, cache_error, and +// common exceptions respectively. +// + .align 9 + LEAF_ENTRY(UserTlbMiss200) +UserTlbMiss: + li k0,KSEG1_BASE + lw k0,0x1018(k0) // Load address of UTBMiss handler + nop + jal k1,k0 // jump to handler saving return + nop // address in k1 + mtc0 k0,epc // Handler returns return address in K0 + nop // 2 cycle Hazard + nop + eret // restore from exception + .end UserTlbMiss200 + + +ParityError: +// +// Change kseg0 coherency to non cached. +// + mfc0 k0,config // get config register + li k1,~(7 << CONFIG_K0) // mask to clear Kseg0 coherency bits + and k0,k0,k1 // clear bits + ori k0,(2 << CONFIG_K0) // make kseg0 non cached + mtc0 k0,config // +// +// Copy the copy routines to memory +// + la a0,MemoryRoutines // source + la a1,MemoryRoutines-LINK_ADDRESS+KSEG1_BASE // destination location + la t2,EndMemoryRoutines // end + bal DataCopy // copy code to memory + subu a2,t2,a0 // length of code +// +// Copy the firmware from PROM to memory. +// + la s0,Decompress-LINK_ADDRESS+KSEG1_BASE + // address of decompression routine in cached space + la a0,end // end of this file is start of selftest + li a1,RAM_TEST_DESTINATION_ADDRESS + // destination is uncached link address. + jal s0 // jump to decompress + nop + +// +// Initialize the stack to the low memory and Call Rom tests. +// + li t0,RAM_TEST_DESTINATION_ADDRESS // address of copied code + li sp,RAM_TEST_STACK_ADDRESS | KSEG1_BASE // init stack non cached + move a1,s5 // Pass cacheerr register as 2nd arg + jal t0 // jump to self-test in memory + li a0,3 // pass cause of exception as argument. + +// +// This becomes the entry point of a Cache Error Exception. +// It should be located at offset 0x300 +// + .align 8 +/*++ +ParityHandler(); +Routine Description: + + This routine is called as a result of a Cache Error exception + It copies the firmware to memory and jumps to it where error + information is printed. + +Arguments: + + None. + +Return Value: + + Does not return + +--*/ + LEAF_ENTRY(ParityHandler300) + // + // Should save state. + // + li k0,(1<<PSR_BEV) | (1 << PSR_CU1) | (1<<PSR_ERL) + mtc0 k0,psr // initialize psr + nop + li k0,(1<<PSR_BEV) | (1 << PSR_CU1) + nop + mtc0 k0,psr // Clear ERL bit + +// +// TMPTMP +// Reinitialize tlb. Should save state somewhere. +// Copy the tlb table to memory. And call the map routine in the base prom. +// + la t0, TlbEntryTable // Load address of table in prom + la t1, TlbEntryEnd // + li a1, KSEG1_BASE+0x400 // Destination address. +10: + lw v0,0(t0) // Load from prom + sw v0,0(a1) // store into memory + addiu t0,t0,4 // next source + bne t0,t1,10b // branch if not end + addiu a1,a1,4 // next dest address + + li a0,KSEG1_BASE+0x400 // base of table in memory + li k0,TlbInit // Get address of TLB init in base prom + jal k0 // Go to reinitialize the tlb + li a2,COPY_ENTRY+1 // tlb index + li t0,TRANSFER_VECTOR // get address of transfer vector + sw v0,4(t0) // set next free TB entry index. + mfc0 s5,cacheerr // Load cache error register + bal PutLedDisplay + ori a0,zero,LED_PARITY // + b ParityError + nop + + .end ParityHandler300 +// +// This becomes the entry point of a General Exception. +// It should be located at offset 380 +// +/*++ +GeneralExceptionHandler(); +Routine Description: + + This routine is called as a result of a General Exception + The address of the General Exception Handler is loaded from the + ArcVector and the handler is called. + + For DUO. A DBE can mean memory ECC error. + +Arguments: + + None + +Return Value: + + None + +--*/ + .align 7 + LEAF_ENTRY(GeneralException380) + mfc0 k0,cause // read cause register. + li k1,XCODE_DATA_BUS_ERROR // + andi k0,R4000_XCODE_MASK // Extract xcode bits + beq k1,k0,BusError // Branch if DBE + li k1,XCODE_INSTRUCTION_BUS_ERROR // + beq k1,k0,BusError // Branch if IBE +CallArcGEHandler: // + li k0,KSEG1_BASE + lw k0,0x1014(k0) // Load address of GE handler + nop + jal k1,k0 // jump to handler saving return + nop // address in k1 + mtc0 k0,epc // Handler returns return address in K0 + nop // 2 cycle Hazard + nop + eret // restore from exception + nop +BusError: + // + // If this is actually an ECC Error then call the Cache Error Handler + // Otherwise call the ARC GE Exception Handler. + // + li k0,DMA_VIRTUAL_BASE // load base address of MCT_ADR + lw k0,DmaNMISource(k0) // Read the interrupt source register. + li k1,1 // Memory Error bit + bne k0,k1,CallArcGEHandler // If Bit Not set Call the Arc Handler + +// +// This is an ECC error. +// +DuoEccHandler: + li k0,DMA_VIRTUAL_BASE // load base address of MCT_ADR + lw k1,DmaMemoryFailedAddress(k0) // read MFAR to clear bit + lw k1,DmaEccDiagnostic(k0) // clear error in parity diag reg. + mfc0 k0,epc // get address of exception + li k1,0xFFFFFFF0 // mask to align address of exception + and k0,k1,k0 // align epc + la k1,ExpectedParityException // get address where exception is expected + bne k0,k1,CallArcGEHandler // if not equal call ARC handler + addiu k1,0x10 // set exception return address 4 instructions further + mtc0 k1,epc // move into epc + addiu v1,zero,1 // set return value to 1. + nop // fill second cycle hazard + eret // return + // Return. + .end GeneralException380 + + ALTERNATE_ENTRY(ResetException) +/*++ + +Routine Description: + + This is the handler for the reset exception. It first checks the cause + of the exception. If it is an NMI, then control is passed to the + exception dispatch routine. Otherwise the machine is initialized. + + The basic are: + 1) Map the I/O devices. + 2) Test the processor. + 3) Test the MCTADR + 4) Map ROM. Perform a ROM checksum. + 5) Test a portion of Memory + 6) Test TLB + 7) Copy routines to memory + 8) Initialize caches + 9) Initialize stack for C language calls and other stack operations + 10) Copy selftest and firmware code to memory and jump to it. + + N.B. This routine must be loaded into the first page of rom. + +Arguments: + + None. + +Return Value: + + None. + +--*/ + +// +// If the exception is a hard reset, the TLB has been initialized by the +// base prom to map all the system resources. +// If it's a soft reset, the only device we know is mapped is the flash prom +// since this code is being fetched from it. +// + +// +// Check cause of exception, if SR bit in PSR is set treat it as a soft reset +// or an NMI, otherwise it's a cold reset. +// + mfc0 k0,psr // get cause register + li k1,(1<<PSR_SR) // bit indicates soft reset. + mtc0 zero,watchlo // initialize the watch + mtc0 zero,watchhi // address registers + and k1,k1,k0 // mask PSR with SR bit + li k0,(1<<PSR_BEV) | (1 << PSR_CU1) | (1<<PSR_ERL) + mtc0 k0,psr // Clear interrupt bit while ERL still set + nop + beq k1,zero,10f // branch if cold reset + move s5,zero // clear s5 to indicate cold reset + ori s5,zero,1 // set s5 to 1 to indicate soft reset +10: + li k0,(1<<PSR_BEV) | (1 << PSR_CU1) + nop + mtc0 k0,psr // Clear ERL bit + +// +// TMPTMP +// Reinitialize tlb. Should save state somewhere. +// Copy the tlb table to memory. And call the map routine in the base prom. +// + la t0, TlbEntryTable // Load address of table in prom + la t1, TlbEntryEnd // + li a1, KSEG1_BASE+0x400 // Destination address. +10: + lw v0,0(t0) // Load from prom + sw v0,0(a1) // store into memory + addiu t0,t0,4 // next source + bne t0,t1,10b // branch if not end + addiu a1,a1,4 // next dest address + + li a0,KSEG1_BASE+0x400 // base of table in memory + li k0,TlbInit // Get address of TLB init in base prom + jal k0 // Go to reinitialize the tlb + li a2,COPY_ENTRY+1 // tlb index + + li t0,TRANSFER_VECTOR // get address of transfer vector + sw v0,4(t0) // set next free TB entry index. + beq s5,zero,Reset // branch if cold reset + li k0,DMA_VIRTUAL_BASE // load base address of MCT_ADR + lw k1,DmaNMISource(k0) // Read the interrupt source register. + andi k0,k1,(1<<3) // test for NMI + beq k0,zero,Reset // if bit not set this is a Soft Reset + // otherwise is an NMI + + // + // Nmi Handler jump to firmware to print message. + // + li k0,DMA_VIRTUAL_BASE // load base address of MCT_ADR + lw k1,DmaWhoAmI(k0) // Read who am I + beq k1,zero,ProcessorANMI // Processor B dies here in a loop. + lw zero,DmaIpInterruptAcknowledge(k0)// read IP Ack register to clear pending interrupts + li k1,(1 << 4) // IP interrupt enable bit + sw k1,DmaInterruptEnable(k0) // Enable IP interrupts. +5: + mfc0 k0,cause // get cause register + li k1,1<<14 // mask to test IP interrupt + and k0,k1 // and them + beq k0,zero,5b // Keep looping if not set + li k1,DMA_VIRTUAL_BASE // load DMA base + lw k1,DmaIpInterruptAcknowledge(k1)// read IP Ack register to clear it +30: + mfc0 k0,cause // get cause register + li k1,1<<14 // mask to test IP interrupt + and k0,k1 // and them + bne k0,zero,30b // Keep looping if still set + + bal InvalidateICache // Invalidate the instruction cache + nop + bal FlushDCache // Flush the data cache + nop + + li k0,RAM_TEST_LINK_ADDRESS // address of copied code + li sp,RAM_TEST_STACK_ADDRESS_B // init stack + mfc0 a1,errorepc // pass cause of exception as argument. + jal k0 // jump to self-test in memory + li a0,2 // set exception cause to 2=NMI + +ProcessorANMI: + + bal PutLedDisplay // set a dash in the LED + ori a0,zero,LED_NMI // + + // + // Copy the copy routines to memory + // + + la a0,MemoryRoutines // source + la a1,MemoryRoutines-LINK_ADDRESS+KSEG1_BASE // destination location + la t2,EndMemoryRoutines // end + bal DataCopy // copy code to memory + sub a2,t2,a0 // length of code + + la t2,InvalidateICache-LINK_ADDRESS+KSEG1_BASE // non-cached space + jal t2 // Invalidate the instruction cache + nop + la k0,NMI // Join common code + mfc0 s6,errorepc // get error epc + j k0 // running at PROM Vaddress. + li s5,2 + +Reset: +// +// Initialize PSR to BEV and COP1 enabled. It's important to clear ERL since +// the ErrorEPC is undefined and further exceptions will set ERL or EXL +// according to the nature of the exception. +// + li k0,(1<<PSR_BEV) | (1 << PSR_CU1) + mtc0 k0,psr + nop + nop + +// +// Set the primary instruction cache block size to 32 bytes +// Set the primary data cache block size to 32 bytes +// +// + + mfc0 t0,config + li t1, (1 << CONFIG_IB) + (1 << CONFIG_DB) + (0 << CONFIG_CU) + \ + (3 << CONFIG_K0) + li t2, 0xFFFFFFC0 + and t0,t0,t2 // clear soft bits in config + or t0,t0,t1 // set soft bits in config + mtc0 t0,config + nop + nop + + bal PutLedDisplay // BLANK the LED + ori a0,zero,LED_BLANK<<TEST_SHIFT + + beq s5,1,SkipProcessorTest // Skip processor test if softreset + nop + bal PutLedDisplay // Show processor test is staring + ori a0,zero,LED_PROCESSOR_TEST + bal ProcessorTest // Test the processor + nop + move s5,zero // clear s5 to indicate cold reset + +SkipProcessorTest: + li t0,DMA_VIRTUAL_BASE // load base address of MCT_ADR + lw s6,DmaWhoAmI(t0) // s6 = processor number. + bne s6,zero,ProcessorBReset + nop + bal PutLedDisplay // Show MCT_ADR reset test is starting + ori a0,zero,LED_MCTADR_RESET + bal MctadrResetTest + nop + + bal PutLedDisplay // Show MCT_ADR register test is starting + ori a0,zero,LED_MCTADR_REG + bal MctadrRegisterTest + nop + + beq s5,1,SkipRomChecksum // Skip checksum if softreset + nop +// +// Perform a ROM Checksum. +// + bal PutLedDisplay // Display in the LED that + ori a0,zero,LED_ROM_CHECKSUM // ROM Checksum is being executed + li a0,PROM_VIRTUAL_BASE // address of PROM + li t0,ROM_SIZE + add a1,a0,t0 // end of loop address + move t0,zero // init sum register + +RomCheckSum: + lw t1,0(a0) // fetch word + lw t2,4(a0) // fetch second word + addu t0,t0,t1 // calculate checksum add from ofs 0 + lw t1,8(a0) + addu t0,t0,t2 // calculate checksum add from ofs 4 + lw t2,0xC(a0) + addu t0,t0,t1 // calculate checksum add from ofs 8 + addiu a0,a0,16 // compute next address + bne a0,a1,RomCheckSum // check end of loop condition + addu t0,t0,t2 // calculate checksum add from ofs c + +// +// if test passes, jump to next part of initialization code. +// + beq t0,zero,TestMemory // Branch if calculated checksum is correct + move s5,zero // clear s5 this tells to run selftest + lui a0,LED_BLINK // otherwise hang + bal PutLedDisplay // by calling PutLedDisplay + ori a0,a0,LED_ROM_CHECKSUM // blinking the test number + +SkipRomChecksum: +TestMemory: + bal PutLedDisplay // call PutLedDisplay to show that + ori a0,zero,LED_MEMORY_TEST_1 // Mem test is starting + + bal SizeMemory // start by sizing the memory. + nop // + +// +// Call memory test routine to test small portion of memory. +// a0 is start of tested memory. a1 is length in bytes to test +// +// +// Disable Parity exceptions for the first memory test. Otherwise +// if something is wrong with the memory we jump to the moon. +// +// DUO ECC diag register resets to zero which forces good ecc to be +// written during read modify write cycles. +// + li t0, (1<<PSR_DE) | (1 << PSR_CU1) | (1 << PSR_BEV) + mtc0 t0,psr + nop + + li a0,KSEG1_BASE // start of mem test + ori a1,zero,MEMTEST_SIZE // length to test in bytes + ctc1 zero,fsr // clear floating status + nop + bal WriteNoXorAddressTest + move a2,zero // xor pattern zero + bal CheckNoXorAddressTest + ori a3,zero,LED_MEMORY_TEST_1 // set Test/Subtest ID +// +// Do the same flipping all bits +// + bal WriteAddressTest + li a2,-1 // Xor pattern = FFFFFFFF + bal CheckAddressTest + nop +// +// Do the same flipping some bits to be sure parity bits are flipped in each byte +// + lui a2,0x0101 + bal WriteAddressTest + ori a2,a2,0x0101 // Xor pattern = 01010101 + bal CheckAddressTest + nop + +// +// The next step is to copy a number of routines to memory so they can +// be executed more quickly. Calculate the arguments for DataCopy call: +// a0 is source of data, a1 is dest, a2 is length in bytes +// + la a0,MemoryRoutines // source + la a1,MemoryRoutines-LINK_ADDRESS+KSEG1_BASE // destination location + la t2,EndMemoryRoutines // end + bal DataCopy // copy code to memory + sub a2,t2,a0 // length of code + +// +// Call cache initialization routine in non-cached memory +// + bal PutLedDisplay // display that cache init + ori a0,zero,LED_CACHE_INIT // is starting + la s1,R4000CacheInit-LINK_ADDRESS+KSEG1_BASE // non-cached address + jal s1 // initialize caches + nop + +/* +// +// TMPTMP +// +// li t0, (1<<PSR_DE) | (1 << PSR_CU1) | (1 << PSR_BEV) +// mtc0 t0,psr + + bal PutLedDisplay + ori a0,zero,0x11 + li a0,KSEG1_BASE+(1<<20) // start of memory to write non cached + li a1,KSEG1_BASE+(2<<20) // start of memory to write non cached + li t0,0xF0F0F0F0 // + li t1,0xAAAAAAAA // + li t2,0x55555555 // + li t3,0x0F0F0F0F // +10: + sw t0,0x0(a0) + sw t1,0x4(a0) + sw t2,0x8(a0) + sw t3,0xC(a0) + addiu a0,a0,0x10 + bne a0,a1,10b + nop + + bal PutLedDisplay + ori a0,zero,0x22 + + li t0,0xF0F0F0F0 // + li t1,0xAAAAAAAA // + li t2,0x55555555 // + li t3,0x0F0F0F0F // + + li a0,KSEG0_BASE+(1<<20) // start of memory to write non cached + li a1,KSEG0_BASE+(2<<20) // start of memory to write non cached +10: + lw v0,0x0(a0) + bne v0,t0,20f + move v1,v0 + lw v0,0x4(a0) + bne v0,t1,20f + move v1,v0 + lw v0,0x8(a0) + bne v0,t2,20f + move v1,v0 + lw v0,0xC(a0) + bne v0,t3,20f + move v1,v0 + addiu a0,a0,0x10 + bne a0,a1,10b + nop + b 30f + nop + +20: + li t0,KSEG1_BASE + sw v1,0(t0) + sw v1,8(t0) + sw v1,0x10(t0) + sw v1,0x18(t0) + lui a0,LED_BLINK // otherwise hang + bal PutLedDisplay // by calling PutLedDisplay + ori a0,a0,0x69 // blink a 69 + +30: + +// lui a0,LED_BLINK // otherwise hang +// bal PutLedDisplay // by calling PutLedDisplay +// ori a0,a0,0xFF // blink a FF +*/ + +/* + bal PutLedDisplay + ori a0,zero,0x11 + li a0,KSEG1_BASE+(1<<20) // start of memory to write non cached + li a1,(1<<20) // start of memory to write non cached + la s1,WriteNoXorAddressTest-LINK_ADDRESS+KSEG1_BASE // address of routine in memory non cached + jal s1 // Write and therefore init mem. + move a2,zero + + bal PutLedDisplay + ori a0,zero,0x22 + li a0,KSEG0_BASE+(1<<20) // start of memory to write non cached + li a1,(1<<20) // start of memory to write non cached + la s1,WriteNoXorAddressTest-LINK_ADDRESS+KSEG1_BASE // address of routine in memory non cached + jal s1 // Write and therefore init mem. + move a2,zero + + bal PutLedDisplay + ori a0,zero,0x33 + li a0,KSEG0_BASE+(1<<20) // start of memory to write non cached + li a1,(1<<20) // start of memory to write non cached + la s1,CheckNoXorAddressTest-LINK_ADDRESS+KSEG1_BASE // address of routine in memory non cached + jal s1 // Write and therefore init mem. + move a2,zero + bal PutLedDisplay + ori a0,a0,0x44 +*/ + +// +// End TMPTMP +// + +// +// call routine now in cached memory to test bigger portion of memory +// + bal PutLedDisplay // display that memory test + ori a0,zero,LED_WRITE_MEMORY_2 // is starting + li a0,KSEG1_BASE+MEMTEST_SIZE // start of memory to write non cached + li a1,FW_TOP_ADDRESS-MEMTEST_SIZE // test the memory needed to copy the code + // to memory, the stack and the video prom. + la s1,WriteNoXorAddressTest-LINK_ADDRESS+KSEG0_BASE // address of routine in memory cached + jal s1 // Write and therefore init mem. + move a2,zero // xor pattern + la s2,CheckNoXorAddressTest-LINK_ADDRESS+KSEG0_BASE // address of routine in memory + jal s2 // Check written memory + ori a3,zero,LED_READ_MEMORY_2 // load LED value if memory test fails + la s1,WriteAddressTest-LINK_ADDRESS+KSEG0_BASE // address of routine cached + li a0,KSEG0_BASE+MEMTEST_SIZE // start of memory now cached + li a2,0xDFFFFFFF // to flipp all bits + jal s1 // Write second time now cached. + la s2,CheckAddressTest-LINK_ADDRESS+KSEG0_BASE // address of routine in memory + jal s2 // check also cached. + nop + lui a2,0x0101 + jal s1 // Write third time cached. + ori a2,a2,0x0101 // flipping some bits + jal s2 // check also cached. + nop + +// +// if we come back, the piece of memory is tested and therefore initialized. +// + + // + // Do not force Correct ECC Data to be written during Read Modify + // Write Cycles any more. Since from now on memory is always cached. + // Or already initialized. + // + li t1,0xEE0000 // Do not Force Correct ECC on rmw + // ECC correction Enabled. + // ECC correction occurs without notification + mtc1 t1,f0 // + mtc1 zero,f1 // zero error bits + li t0,DMA_VIRTUAL_BASE // Get base address of MCTADR + sdc1 f0,DmaEccDiagnostic(t0) // Write ECC Diagnostic register + +// +// If an NMI occurred. s6 contains the erorrepc. +// the Tlb has already been initialized and the I cache flushed. +// Copy the firmware to memory and display a message from there. +// + +NMI: +// +// Invalidate the data caches so that the firmware can be copied to +// noncached space without a conflict. +// + + bal InvalidateDCache + nop + bal InvalidateSCache + nop + +// +// Copy the firmware. +// + la s0,Decompress-LINK_ADDRESS+KSEG0_BASE + // address of decompression routine in cached space + la a0,end // end of this file is start of selftest + li a1,RAM_TEST_DESTINATION_ADDRESS + // destination is uncached link address. + jal s0 // jump to decompress + nop + bal InvalidateICache // Invalidate the instruction cache + nop + +// +// Flush the data cache +// + bal FlushDCache + nop + +// +// Initialize the stack to the low memory and Call Rom tests. +// + li t0,RAM_TEST_LINK_ADDRESS // address of copied code + li sp,RAM_TEST_STACK_ADDRESS // init stack + move a1,s6 // pass cause of exception as argument. + jal t0 // jump to self-test in memory + move a0,s5 // pass cause of exception as argument. +99: + b 99b // hang if we get here. + nop // + + +// +// This is the initialization code for processor B. +// At this point the processor has: +// +// - Initialized the TLB. +// - Initialized the config register. +// - Run the processor selftest +// +// The system has already been initialized by processor A. +// Only the caches need to be initialized. +// +// +ProcessorBReset: + +// +// Call cache initialization routine in non-cached memory +// + bal PutLedDisplay // display that cache init + ori a0,zero,LED_CACHE_INIT // is starting + la s1,R4000CacheInit-LINK_ADDRESS+KSEG1_BASE // non-cached address + jal s1 // initialize caches + nop + li t0,RAM_TEST_LINK_ADDRESS // address of copied code + li sp,RAM_TEST_STACK_ADDRESS_B // init stack + move a1,s6 + jal t0 // jump to self-test in memory + move a0,s5 // pass cause of exception as argument. +99: + b 99b // hang if we get here. + nop // + + +// +// Routines between MemoryRoutines and EndMemoryRoutines are copied +// into memory to run them cached. +// + + .align 4 // Align it to 16 bytes boundary so that + ALTERNATE_ENTRY(MemoryRoutines) // DataCopy doesn't need to check alignments +/*++ +VOID +PutLedDisplay( + a0 - display value. + ) +Routine Description: + + This routine will display in the LED the value specified as argument + a0. + + bits [31:16] specify the mode. + bits [7:4] specify the Test number. + bits [3:0] specify the Subtest number. + + The mode can be: + + LED_NORMAL Display the Test number + LED_BLINK Loop displaying Test - Dot - Subtest + LED_LOOP_ERROR Display the Test number with the dot iluminated + + N.B. This routine must reside in the first page of ROM because it is + called before mapping the rom!! + +Arguments: + + a0 value to display. + + Note: The value of the argument is preserved + +Return Value: + + If a0 set to LED_BLINK does not return. + +--*/ + LEAF_ENTRY(PutLedDisplay) + li t0,DIAGNOSTIC_VIRTUAL_BASE // load address of display +LedBlinkLoop: + srl t1,a0,16 // get upper bits of a0 in t1 + srl t3,a0,4 // get test number + li t4,LED_LOOP_ERROR // + bne t1,t4, DisplayTestID + andi t3,t3,0xF // clear other bits. + ori t3,t3,LED_DECIMAL_POINT // Set decimal point +DisplayTestID: + li t4,LED_BLINK // check if need to hung + sb t3,0(t0) // write test ID to led. + beq t1,t4, ShowSubtestID + nop + j ra // return to caller. + nop + +ShowSubtestID: + li t2,LED_DELAY_LOOP // get delay value. +TestWait: + bne t2,zero,TestWait // loop until zero + addiu t2,t2,-1 // decrement counter + li t3,LED_DECIMAL_POINT+LED_BLANK + sb t3,0(t0) // write decimal point + li t2,LED_DELAY_LOOP/2 // get delay value. +DecPointWait: + bne t2,zero,DecPointWait // loop until zero + addiu t2,t2,-1 // decrement counter + andi t3,a0,0xF // get subtest number + sb t3,0(t0) // write subtest in LED + li t2,LED_DELAY_LOOP // get delay value. +SubTestWait: + bne t2,zero,SubTestWait // loop until zero + addiu t2,t2,-1 // decrement counter + b LedBlinkLoop // go to it again + nop + .end PutLedDisplay + + LEAF_ENTRY(InvalidateICache) +/*++ + +Routine Description: + + This routine invalidates the contents of the instruction cache. + + The instruction cache is invalidated by writing an invalid tag to + each cache line, therefore nothing is written back to memory. + +Arguments: + + None. + +Return Value: + + None. + +--*/ +// +// invalid state +// + mfc0 t5,config // read config register + li t0,(PRIMARY_CACHE_INVALID << TAGLO_PSTATE) + mtc0 t0,taglo // set tag registers to invalid + mtc0 zero,taghi + + srl t0,t5,CONFIG_IC // compute instruction cache size + and t0,t0,0x7 // + addu t0,t0,12 // + li t6,1 // + sll t6,t6,t0 // t6 = I cache size + srl t0,t5,CONFIG_IB // compute instruction cache line size + and t0,t0,1 // + li t7,16 // + sll t7,t7,t0 // t7 = I cache line size +// +// store tag to all icache lines +// + li t1,KSEG0_BASE+(1<<20) // get virtual address to index cache + addu t0,t1,t6 // get last index address + subu t0,t0,t7 +WriteICacheTag: + cache INDEX_STORE_TAG_I,0(t1) // store tag in Instruction cache + bne t1,t0,WriteICacheTag // loop + addu t1,t1,t7 // increment index + j ra + nop + .end InvalidateICache + + + LEAF_ENTRY(InvalidateDCache) +/*++ + +Routine Description: + + This routine invalidates the contents of the D cache. + + Data cache is invalidated by writing an invalid tag to each cache + line, therefore nothing is written back to memory. + +Arguments: + + None. + +Return Value: + + None. + +--*/ +// +// invalid state +// + mfc0 t5,config // read config register for cache size + li t0, (PRIMARY_CACHE_INVALID << TAGLO_PSTATE) + mtc0 t0,taglo // set tag to invalid + mtc0 zero,taghi + srl t0,t5,CONFIG_DC // compute data cache size + and t0,t0,0x7 // + addu t0,t0,12 // + li t6,1 // + sll t6,t6,t0 // t6 = data cache size + srl t0,t5,CONFIG_DB // compute data cache line size + and t0,t0,1 // + li t7,16 // + sll t7,t7,t0 // t7 = data cache line size + +// +// store tag to all Dcache +// + li t1,KSEG0_BASE+(1<<20) // get virtual address to index cache + addu t2,t1,t6 // add cache size + subu t2,t2,t7 // adjust for cache line size. +WriteDCacheTag: + cache INDEX_STORE_TAG_D,0(t1) // store tag in Data cache + bne t1,t2,WriteDCacheTag // loop + addu t1,t1,t7 // increment index by cache line + j ra + nop + .end InvalidateDCache + + + LEAF_ENTRY(FlushDCache) +/*++ + +Routine Description: + + This routine flushes the whole contents of the Dcache + +Arguments: + + None. + +Return Value: + + None. + +--*/ + mfc0 t5,config // read config register + li t1,KSEG0_BASE+(1<<20) // get virtual address to index cache + srl t0,t5,CONFIG_DC // compute data cache size + and t0,t0,0x7 // + addu t0,t0,12 // + li t6,1 // + sll t6,t6,t0 // t6 = data cache size + srl t0,t5,CONFIG_DB // compute data cache line size + and t0,t0,1 // + li t7,16 // + sll t7,t7,t0 // t7 = data cache line size + addu t0,t1,t6 // compute last index address + subu t0,t0,t7 +FlushDCacheTag: + cache INDEX_WRITEBACK_INVALIDATE_D,0(t1) // Invalidate data cache + bne t1,t0,FlushDCacheTag // loop + addu t1,t1,t7 // increment index + +// +// check for a secondary cache. +// + + li t1,(1 << CONFIG_SC) + and t0,t5,t1 + bne t0,zero,10f // if non-zero no secondary cache + + li t6,SECONDARY_CACHE_SIZE // t6 = secondary cache size + srl t0,t5,CONFIG_SB // compute secondary cache line size + and t0,t0,3 // + li t7,16 // + sll t7,t7,t0 // t7 = secondary cache line size +// +// invalidate all secondary lines +// + li t1,KSEG0_BASE+(1<<20) // get virtual address to index cache + addu t0,t1,t6 // get last index address + subu t0,t0,t7 +FlushSDCacheTag: + cache INDEX_WRITEBACK_INVALIDATE_SD,0(t1) // invalidate secondary cache + bne t1,t0,FlushSDCacheTag // loop + addu t1,t1,t7 // increment index +10: + j ra + nop + .end FlushDCache + + + LEAF_ENTRY(InvalidateSCache) +/*++ + +Routine Description: + + This routine invalidates the contents of the secondary cache. + + The secondary cache is invalidated by writing an invalid tag to + each cache line, therefore nothing is written back to memory. + +Arguments: + + None. + +Return Value: + + None. + +--*/ + mfc0 t5,config // read config register + +// +// check for a secondary cache. +// + + li t1,(1 << CONFIG_SC) + and t0,t5,t1 + bne t0,zero,NoSecondaryCache // if non-zero no secondary cache + + li t0,(SECONDARY_CACHE_INVALID << TAGLO_SSTATE) + mtc0 t0,taglo // set tag registers to invalid + mtc0 zero,taghi + + li t6,SECONDARY_CACHE_SIZE // t6 = secondary cache size + srl t0,t5,CONFIG_SB // compute secondary cache line size + and t0,t0,3 // + li t7,16 // + sll t7,t7,t0 // t7 = secondary cache line size +// +// store tag to all secondary lines +// + li t1,KSEG0_BASE+(1<<20) // get virtual address to index cache + addu t0,t1,t6 // get last index address + subu t0,t0,t7 +WriteSICacheTag: + cache INDEX_STORE_TAG_SD,0(t1) // store tag in secondary cache + bne t1,t0,WriteSICacheTag // loop + addu t1,t1,t7 // increment index + +NoSecondaryCache: + j ra + nop + .end InvalidateSCache + + + LEAF_ENTRY(InitDataCache) +/*++ + +Routine Description: + + This routine initializes the data fields of the primary and + secondary data caches. + +Arguments: + + None. + +Return Value: + + None. + +--*/ + mfc0 t5,config // read config register + +// +// check for a secondary cache. +// + + li t1,(1 << CONFIG_SC) + and t0,t5,t1 + bne t0,zero,NoSecondaryCache1 // if non-zero no secondary cache + + li t6,SECONDARY_CACHE_SIZE // t6 = secondary cache size + srl t0,t5,CONFIG_SB // compute secondary cache line size + and t0,t0,3 // + li t7,16 // + sll t7,t7,t0 // t7 = secondary cache line size +// +// store tag to all secondary lines +// + li t1,KSEG0_BASE+(1<<20) // get virtual address to index cache + addu t0,t1,t6 // get last index address + subu t0,t0,t7 + +WriteSCacheTag: + cache CREATE_DIRTY_EXCLUSIVE_SD,0(t1) // store tag in secondary cache + bne t1,t0,WriteSCacheTag // loop + addu t1,t1,t7 // increment index + +// +// store data to all secondary lines. 1MB +// + mtc1 zero,f0 // zero f0 + mtc1 zero,f1 // zero f1 + li t1,KSEG0_BASE+(1<<20) // get virtual address to index cache + addu t0,t1,t6 // get last index address + subu t0,t0,t7 + +WriteSCacheData: + // + // Init Data 64 bytes per loop. + // + + // TMPTMP + move t2,t1 + // TMPTMP + + + // TMPTMP + mtc1 t2,f0 + mtc1 t2,f1 + // TMPTMP + + sdc1 f0,0(t1) // write + + // TMPTMP + addiu t2,t2,8 + mtc1 t2,f0 + mtc1 t2,f1 + // TMPTMP + + sdc1 f0,8(t1) // write + + // TMPTMP + addiu t2,t2,8 + mtc1 t2,f0 + mtc1 t2,f1 + // TMPTMP + + sdc1 f0,16(t1) // write + + // TMPTMP + addiu t2,t2,8 + mtc1 t2,f0 + mtc1 t2,f1 + // TMPTMP + + sdc1 f0,24(t1) // write + + // TMPTMP + addiu t2,t2,8 + mtc1 t2,f0 + mtc1 t2,f1 + // TMPTMP + + sdc1 f0,32(t1) // write + + // TMPTMP + addiu t2,t2,8 + mtc1 t2,f0 + mtc1 t2,f1 + // TMPTMP + + sdc1 f0,40(t1) // write + + // TMPTMP + addiu t2,t2,8 + mtc1 t2,f0 + mtc1 t2,f1 + // TMPTMP + + sdc1 f0,48(t1) // write + + // TMPTMP + addiu t2,t2,8 + mtc1 t2,f0 + mtc1 t2,f1 + // TMPTMP + + sdc1 f0,56(t1) // write + bne t1,t0,WriteSCacheData // loop + addu t1,t1,t7 // increment index + +// +// TMPTMP +// + + li t1, (1 << PSR_CU1) | (1 << PSR_BEV) + mtc0 t1,psr + nop + nop + + li t1,KSEG0_BASE+(1<<20) // get virtual address to index cache + addu t0,t1,t6 // get last index address + subu t0,t0,t7 + +10: + ldc1 f0,0(t1) + ldc1 f0,8(t1) + ldc1 f0,16(t1) + ldc1 f0,24(t1) + ldc1 f0,32(t1) + ldc1 f0,40(t1) + ldc1 f0,48(t1) + ldc1 f0,56(t1) + + bne t1,t0,10b // loop + addu t1,t1,t7 // increment index + + +// +// END +// + +// +// Flush the primary data cache to the secondary cache +// + li t1,KSEG0_BASE+(1<<20) // get virtual address to index cache + srl t0,t5,CONFIG_DC // compute data cache size + and t0,t0,0x7 // + addu t0,t0,12 // + li t6,1 // + sll t6,t6,t0 // t6 = data cache size + srl t0,t5,CONFIG_DB // compute data cache line size + and t0,t0,1 // + li t7,16 // + sll t7,t7,t0 // t7 = data cache line size + addu t0,t1,t6 // compute last index address + subu t0,t0,t7 +FlushPDCacheTag: + cache INDEX_WRITEBACK_INVALIDATE_D,0(t1) // Invalidate data cache + bne t1,t0,FlushPDCacheTag // loop + addu t1,t1,t7 // increment index + + j ra // return + nop + +NoSecondaryCache1: + + srl t0,t5,CONFIG_DC // compute data cache size + and t0,t0,0x7 // + addu t0,t0,12 // + li t6,1 // + sll t6,t6,t0 // t6 = data cache size + srl t0,t5,CONFIG_DB // compute data cache line size + and t0,t0,1 // + li t7,16 // + sll t7,t7,t0 // t7 = data cache line size + +// +// create dirty exclusive to all Dcache +// + mtc1 zero,f0 // zero f0 + mtc1 zero,f1 // zero f1 + li t1,KSEG0_BASE+(1<<20) // get virtual address to index cache + addu t2,t1,t6 // add cache size + subu t2,t2,t7 // adjust for cache line size. +WriteDCacheDe: + cache CREATE_DIRTY_EXCLUSIVE_D,0(t1) // store tag in Data cache + nop + sdc1 f0,0(t1) // write + sdc1 f0,8(t1) // write + bne t1,t2,WriteDCacheDe // loop + addu t1,t1,t7 // increment index by cache line + + j ra // return + nop + .end InitDataCache + + LEAF_ENTRY(R4000CacheInit) +/*++ + +Routine Description: + + This routine will initialize the cache tags and data for the + primary data cache, primary instruction cache, and the secondary cache + (if present). + + Subroutines are called to invalidate all of the tags in the + instruction and data caches. + +Arguments: + + None. + +Return Value: + + None. + +--*/ + move s0,ra // save ra. + +// +// Disable Cache Error exceptions. +// + + li t0, (1<<PSR_DE) | (1 << PSR_CU1) | (1 << PSR_BEV) + mtc0 t0,psr + +// +// Invalidate the caches +// + + bal InvalidateICache + nop + + bal InvalidateDCache + nop + + bal InvalidateSCache + nop + +// +// Initialize the data cache(s) +// + + bal InitDataCache + nop + +// +// Fill the Icache, all icache lines +// + + mfc0 t5,config // read config register + nop + srl t0,t5,CONFIG_IC // compute instruction cache size + and t0,t0,0x7 // + addu t0,t0,12 // + li s1,1 // + sll s1,s1,t0 // s1 = I cache size + srl t0,t5,CONFIG_IB // compute instruction cache line size + and t0,t0,1 // + li s2,16 // + sll s2,s2,t0 // s2 = I cache line size + + li t1,KSEG0_BASE+(1<<20) // get virtual address to index cache + addu t0,t1,s1 // add I cache size + subu t0,t0,s2 // sub line size. +FillICache: + cache INDEX_FILL_I,0(t1) // Fill I cache from memory + bne t1,t0,FillICache // loop + addu t1,t1,s2 // increment index + +// +// Invalidate the caches again +// + bal InvalidateICache + nop + + bal InvalidateDCache + nop + + bal InvalidateSCache + nop + +// +// Enable cache error exception. +// + mfc0 t0,config + li t1, (1 << CONFIG_IB) + (1 << CONFIG_DB) + (0 << CONFIG_CU) + \ + (5 << CONFIG_K0) + li t2, 0xFFFFFFC0 + and t0,t0,t2 // clear soft bits in config + or t0,t0,t1 // set soft bits in config + mtc0 t0,config + nop + + li t1, (1 << PSR_CU1) | (1 << PSR_BEV) + mtc0 t1,psr + nop + nop + nop + move ra,s0 // move return address back to ra + j ra // return from routine + nop + .end R4000CacheInit + + +/*++ +VOID +WriteAddressTest( + StartAddress + Size + Xor pattern + ) +Routine Description: + + This routine will store the address of each location xored with + the Pattern into each location. + +Arguments: + + a0 - supplies start of memory area to test + a1 - supplies length of memory area in bytes + a2 - supplies the pattern to Xor with. + + Note: the values of the arguments are preserved. + +Return Value: + + This routine returns no value. +--*/ + LEAF_ENTRY(WriteAddressTest) + add t1,a0,a1 // t1 = last address. + xor t0,a0,a2 // t0 value to write + move t2,a0 // t2=current address +writeaddress: + sw t0,0(t2) // store + addiu t2,t2,4 // compute next address + xor t0,t2,a2 // next pattern + sw t0,0(t2) + addiu t2,t2,4 // compute next address + xor t0,t2,a2 // next pattern + sw t0,0(t2) + addiu t2,t2,4 // compute next address + xor t0,t2,a2 // next pattern + sw t0,0(t2) + addiu t2,t2,4 // compute next address + bne t2,t1, writeaddress // check for end condition + xor t0,t2,a2 // value to write + j ra + nop + .end WriteAddressTest + +/*++ +VOID +WriteNoXorAddressTest( + StartAddress + Size + ) +Routine Description: + + This routine will store the address of each location + into each location. + +Arguments: + + a0 - supplies start of memory area to test + a1 - supplies length of memory area in bytes + + Note: the values of the arguments are preserved. + +Return Value: + + This routine returns no value. +--*/ + LEAF_ENTRY(WriteNoXorAddressTest) + nop + nop + nop + nop + add t1,a0,a1 // t1 = last address. + addiu t1,t1,-4 + move t2,a0 // t2=current address +writenoXoraddress: + sw t2,0(t2) // store first address + addiu t2,t2,4 // compute next address + sw t2,0(t2) // store first address + addiu t2,t2,4 // compute next address + sw t2,0(t2) // store first address + addiu t2,t2,4 // compute next address + sw t2,0(t2) // store + bne t2,t1, writenoXoraddress // check for end condition + addiu t2,t2,4 // compute next address + j ra + nop + .end WriteNoXorAddressTest + + +/*++ +VOID +CheckAddressTest( + StartAddress + Size + Xor pattern + LedDisplayValue + ) +Routine Description: + + + This routine will check that each location contains it's address + xored with the Pattern as written by WriteAddressTest. The memory + is read cached or non cached according to the address specified by a0. + if WriteAddressTest used a KSEG1_ADR to write the data and this + routine is called to read KSEG0_ADR in order to read the data cached, + then the XOR_PATTERN Must be such that: + + KSEG0_ADR ^ KSEG0_XOR = KSEG1_ADR ^ KSEG1_XOR + + Examples: + + If XorPattern with which WriteAddressTest was called is KSEG1_XOR + then the XorPattern this routine needs is KSEG0_XOR: + + KSEG1_XOR Written KSEG0_XOR So that + 0x00000000 0xA00000000 0x20000000 0x8000000 ^ 0x2000000 = 0xA0000000 + 0xFFFFFFFF 0x5F0000000 0xDFFFFFFF 0x8000000 ^ 0xDF00000 = 0x5F000000 + 0x01010101 0xA10000000 0x21010101 0x8000000 ^ 0x2100000 = 0xA1000000 + + This allows to write non cached to initialize memory and check the same + data trough cached addresses. + +Arguments: + + a0 - supplies start of memory area to test + a1 - supplies length of memory area in bytes + a2 - supplies the pattern to Xor with. + a3 - suplies the value to display in the led in case of failure + + Note: the values of the arguments are preserved. + +Return Value: + + Returns a zero if no error is found. + + If errors are found, this routine behaves different depending + on where the caller resides: + - If the caller is executing in KSEG0 or KSEG1 returns 1 + - If the caller is executing im ROM_VIRT addresses the + routine hangs blinking the LED or looping if the loop on error + bit is set in the config register. + +--*/ + LEAF_ENTRY(CheckAddressTest) + move t3,a0 // t3 first address. + add t2,t3,a1 // last address. +checkaddress: + lw t1,0(t3) // load from first location + xor t0,t3,a2 // first expected value + bne t1,t0,PatternFail + addiu t3,t3,4 // compute next address + lw t1,0(t3) // load from first location + xor t0,t3,a2 // first expected value + bne t1,t0,PatternFail + addiu t3,t3,4 // compute next address + lw t1,0(t3) // load from first location + xor t0,t3,a2 // first expected value + bne t1,t0,PatternFail + addiu t3,t3,4 // compute next address + lw t1,0(t3) // load from first location + xor t0,t3,a2 // first expected value + bne t1,t0,PatternFail // check last one. + addiu t3,t3,4 // compute next address + bne t3,t2, checkaddress // check for end condition + move v0,zero // set return value to zero. + j ra // return a zero to the caller + +PatternFail: + // + // check if we are in loop on error + // + li t0,DIAGNOSTIC_VIRTUAL_BASE // get base address of diag register + lb t0,0(t0) // read register value. + li t1,LOOP_ON_ERROR_MASK // get value to compare + andi t0,DIAGNOSTIC_MASK // mask diagnostic bits. + li v0,PROM_ENTRY(14) // load address of PutLedDisplay + beq t1,t0,10f // brnach if loop on error. + move s8,a0 // save register a0 + lui t0,LED_BLINK // get LED blink code + jal v0 // Blink LED and hang. + or a0,a3,t0 // pass a3 as argument in a0 +10: + lui t0,LED_LOOP_ERROR // get LED LOOP_ERROR code + jal v0 // Set LOOP ON ERROR on LED + or a0,a3,t0 // pass a3 as argument in a0 + b CheckAddressTest // Loop back to test again. + move a0,s8 // restoring arguments. + .end CheckAddressTest + +/*++ +VOID +CheckNoXorAddressTest( + StartAddress + Size + not used + LedDisplayValue + ) +Routine Description: + + This routine will check that each location contains it's address. + as written by WriteNoXorAddressTest. + +Arguments: + + Note: the values of the arguments are preserved. + + a0 - supplies start of memory area to test + a1 - supplies length of memory area in bytes + a2 - Not used + a3 - suplies the value to display in the led in case of failure + +Return Value: + + This routine returns no value. + The routine hangs blinking the LED or looping if the loop on error + bit is set in the config register. +--*/ + LEAF_ENTRY(CheckNoXorAddressTest) + addiu t3,a0,-4 // t3 first address-4 + add t2,a0,a1 // last address. + addiu t2,t2,-8 // adjust + move t1,t3 // get copy of t3 just for first check +checkaddressNX: + bne t1,t3,PatternFailNX + lw t1,4(t3) // load from first location + addiu t3,t3,4 // compute next address + bne t1,t3,PatternFailNX + lw t1,4(t3) // load from next location + addiu t3,t3,4 // compute next address + bne t1,t3,PatternFailNX + lw t1,4(t3) // load from next location + addiu t3,t3,4 // compute next address + bne t1,t3,PatternFailNX // check + lw t1,4(t3) // load from next location + bne t3,t2, checkaddressNX // check for end condition + addiu t3,t3,4 // compute next address + bne t1,t3,PatternFailNX // check last + nop + j ra // return a zero to the caller + move v0,zero // +PatternFailNX: + // + // check if we are in loop on error + // + li t0,DIAGNOSTIC_VIRTUAL_BASE // get base address of diag register + lb t0,0(t0) // read register value. + li t1,LOOP_ON_ERROR_MASK // get value to compare + andi t0,DIAGNOSTIC_MASK // mask diagnostic bits. + li v0,PROM_ENTRY(14) // load address of PutLedDisplay + beq t1,t0,10f // brnach if loop on error. + move s8,a0 // save register a0 + lui t0,LED_BLINK // get LED blink code + jal v0 // Blink LED and hang. + or a0,a3,t0 // pass a3 as argument in a0 +10: + lui t0,LED_LOOP_ERROR // get LED LOOP_ERROR code + jal v0 // Set LOOP ON ERROR on LED + or a0,a3,t0 // pass a3 as argument in a0 + b CheckNoXorAddressTest // Loop back to test again. + move a0,s8 // restoring arguments. + .end CheckNoXorAddressTest + + +/*++ +VOID +ZeroMemory( + ULONG StartAddress + ULONG Size + ); +Routine Description: + + This routine will zero a range of memory. + +Arguments: + + a0 - supplies start of memory + a1 - supplies length of memory in bytes + +Return Value: + + None. + +--*/ + LEAF_ENTRY(ZeroMemory) + add a1,a1,a0 // Compute End address + addiu a1,a1,-4 // adjust address +ZeroMemoryLoop: + sw zero,0(a0) // zero memory. + bne a0,a1,ZeroMemoryLoop // loop until done. + addiu a0,a0,4 // compute next address + j ra // return + nop + ALTERNATE_ENTRY(ZeroMemoryEnd) + nop + .end ZeroMemory + +//++ +// +//PULONG +//Decompress( +// IN PULONG InputImage, +// IN PULONG OutputImage +// ) +// +// +//Routine Description: +// +// This routine decompresses the input image. +// +//Arguments: +// +// InputImage (a0) - byte pointer to the image to be decompressed. +// OutputImage (a1) - byte pointer to the area to write decompressed image. +// +// N.B. The first ULONG of the InputImage contains the decompressed length in bytes. +// See romcomp.c for a description of method. +// +//Return Value: +// +// None. +// +//-- + +.set reorder + LEAF_ENTRY(Decompress) + + lw a2,(a0) // get the target size. + srl a2,a2,2 // get size of output in words/symbols. + addiu a0,a0,4 // address of next word + move a3,a1 // stash output image base + +// +// Calculate the offset width from the size. Assume size > 2 ULONG. +// +#define SHORT_INDEX_WIDTH 10 + + li t8,1 // start at two + srl t0,a2,1 // offset must only span half the image. +5: + addiu t8,t8,1 // next bit + srl t1,t0,t8 // shift off low bits + bgtz t1,5b // quit when we find the highest set bit. + +// +// Set the symbol register bit count to zero so that on the first iteration of the loop we will +// get the first symbol longword. Add one to the symbol count to allow for first loop entry. +// + + li t1,0 // number of valid bits + addiu a2,a2,1 // increment symbol count + +// +// Loop, decompressing the data. There is always at least one bit in the register at this point. +// + +10: + +// +// Decrement the symbol count and exit the loop when done. +// + + addiu a2,a2,-1 // decrement symbol count + beq zero,a2,99f // return + +// +// Load symbol register if it is empty. +// + + bne zero,t1,12f // check for lack of bits + lw t0,(a0) // get the next word + addiu a0,a0,4 // address of next word + li t1,32 // number of valid bits +12: + +// +// Test first bit of symbol +// + + andi t2,t0,0x1 // test the low bit + addiu t1,t1,-1 // decrement bit count + srl t0,t0,1 // shift symbol + bne zero,t1,20f // check for lack of bits + lw t0,(a0) // get the next word + addiu a0,a0,4 // address of next word + li t1,32 // number of valid bits +20: + bne zero,t2,50f // if not zero then this is an index + +30: + +// +// First bit of symbol is zero, this is the zero or unique case. Check the next bit. +// + + andi t2,t0,0x1 // test the low bit + addiu t1,t1,-1 // decrement bit count + srl t0,t0,1 // shift symbol + bne zero,t2,40f // if not zero then this is a unique word symbol + +// +// This is the zero case. 0b00 +// + + sw zero,(a1) // store the zero + addiu a1,a1,4 // increment the output image pointer + b 10b // go get the next symbol. + +// +// The symbol is a unique word. 0b10. Get the next 32 bits and write them to the output. +// +// The symbol register contains 0 to 31 bits of the word to be written. Get the next +// word, shift and merge it with the existing symbol to produce a complete word. The remainder +// of the new word becomes the next symbol register contents. +// +// Note that since we read a new word we don't have to decrement the bit counter since it runs +// mod 32. +// + +40: + lw t3,(a0) // get next word + addiu a0,a0,4 // address of next word + + sll t2,t3,t1 // shift it by the bit count + or t0,t0,t2 // put it in with the existing contents of the symbol register + + sw t0,(a1) // store the word + addiu a1,a1,4 // increment the output image pointer + + li t2,32 // get shift count for new word to make new symbol register + subu t2,t2,t1 // + srl t0,t3,t2 // new contents of symbol register. For bit count zero case + // this is a nop + + b 10b // go get the next symbol. + +// +// This is the index case. 0bX1. Now the next bit determines whether the offset is relative(1) or +// absolute(0). Stash the next bit for when we use the offset. +// + +50: + andi t4,t0,0x1 // get the relative/absolute bit + addiu t1,t1,-1 // decrement bit count + srl t0,t0,1 // shift symbol + bne zero,t1,55f // check for lack of bits + lw t0,(a0) // get the next word + addiu a0,a0,4 // address of next word + li t1,32 // number of valid bits +55: + +// +// Get the next bit. This tells us whether we have a long(0) or a short(1) index. +// + + andi t2,t0,0x1 // test the low bit + addiu t1,t1,-1 // decrement bit count + srl t0,t0,1 // shift symbol + bne zero,t1,60f // check for lack of bits + lw t0,(a0) // get the next word + addiu a0,a0,4 // address of next word + li t1,32 // number of valid bits +60: + li t5,SHORT_INDEX_WIDTH // preload with short index width + bne zero,t2,70f // if not zero then this is a short index. + move t5,t8 // use long index width + +// +// Get the index based on the width. If the currently available bits are less than the +// number that we need then we must read another word. +// +70: + li t7,0 // zero the remainder + sub t2,t5,t1 // get difference between what we need and what we have + blez t2,75f // if we got what we need + + lw t6,(a0) // get next word + addiu a0,a0,4 // address of next word + sll t7,t6,t1 // shift new bits into position + or t0,t0,t7 // move new bits into symbol register + srl t7,t6,t2 // adjust remainder + addiu t1,t1,32 // pre-bias the bit count for later decrement. + +75: + li t3,1 // grab a one + sll t3,t3,t5 // shift it by number of bits we will extract + addiu t3,t3,-1 // make a mask + and t2,t0,t3 // grab the index + sll t2,t2,2 // make it a byte index + srl t0,t0,t5 // shift out bits we used. + or t0,t0,t7 // merge in remainder if any. + sub t1,t1,t5 // decrement the bit count, correct regardless + +// +// Use index to write output based on the absolute(0)/relative(1) bit. +// +80: + bne zero,t4,85f // test for the relative case. + addu t3,a3,t2 // address by absolute + b 87f // go move the word +85: + subu t3,a1,t2 // address by relative + +// +// Move the byte. +// +87: + lw t2,(t3) // get the word + sw t2,(a1) // store the word + addiu a1,a1,4 // increment output pointer + b 10b // go do next symbol + +// +// Return +// + +99: + + j ra // return + + .end Decompress +.set noreorder + +/*++ +VOID +DataCopy( + ULONG SourceAddress + ULONG DestinationAddress + ULONG Length + ); +Routine Description: + + This routine will copy data from one location to another + Source, destination, and length must be dword aligned. + + For DUO since 64 bit reads from the prom are not supported, the + reads and writes are done word by word. + +Arguments: + + a0 - supplies source of data + a1 - supplies destination of data + a2 - supplies length of data in bytes + +Return Value: + + None. +--*/ + + + LEAF_ENTRY(DataCopy) + + add a2,a2,a0 // get last address +CopyLoop: + lw t0, 0(a0) // load 1st word + lw t1, 4(a0) // load 2nd word + lw t2, 8(a0) // load 3rd word + lw t3,12(a0) // load 4th word + addiu a0,a0,16 // increment source pointer + sw t0, 0(a1) // load 1st word + sw t1, 4(a1) // load 2nd word + sw t2, 8(a1) // load 3rd word + sw t3,12(a1) // load 4th word + bne a0,a2,CopyLoop // loop until address=last address + addiu a1,a1,16 // increment destination pointer + j ra // return + nop + .align 4 // Align it to 16 bytes boundary so that + ALTERNATE_ENTRY(EndMemoryRoutines) // DataCopy doesn't need to check alignments + nop + .end DataCopy + +/*++ +VOID +ProcessorTest( + VOID + ); + +Routine Description: + + This routine tests the processor. Test uses all registers and almost all + the instructions. + + N.B. This routine destroys the values in all of the registers. + +Arguments: + + None. + +Return Value: + + None, but will hang flashing the led if an error occurs. + +--*/ + LEAF_ENTRY(ProcessorTest) + lui a0,0x1234 // a0=0x12340000 + ori a1,a0,0x4321 // a1=0x12344321 + add a2,zero,a0 // a2=0x12340000 + addiu a3,zero,-0x4321 // a3=0xFFFFBCDF + subu AT,a2,a3 // AT=0x12344321 + bne a1,AT,ProcessorError // branch if no match match + andi v0,a3,0xFFFF // v0=0x0000BCDF + ori v1,v0,0xFFFF // v1=0x0000FFFF + sll t0,v1,16 // t0=0xFFFF0000 + xor t1,t0,v1 // t1=0xFFFFFFFF + sra t2,t0,16 // t2=0xFFFFFFFF + beq t1,t2,10f // if eq good + srl t3,t0,24 // t3=0x000000FF + j ProcessorError // if wasn't eq error. +10: sltu s0,t0,v1 // S0=0 because t0 > v1 + bgtz s0,ProcessorError // if s0 > zero error + or t4,AT,v0 // t4=X + bltz s0,ProcessorError // if s0 < zero error + nor t5,v0,AT // t5=~X + and t6,t4,t5 // t6=0 + move s0,ra // save ra in s0 + bltzal t6,ProcessorError // if t6 < 0 error, load ra in case + nop +RaAddress: + //la t7,RaAddress - LINK_ADDRESS + RESET_VECTOR // get expected address in ra + la t7,RaAddress // get expected address in ra + bne ra,t7,ProcessorError // error if don't match + move ra,s0 // put ra back + ori s1,zero,0x100 // load constant + mult s1,t3 // 0x100*0xFF + mfhi s3 // s3=0 + mflo s2 // s2=0xFF00 + blez s3,10f // branch if correct + sll s4,t3,zero // move t3 into s4 + addiu s4,100 // change value in s4 to produce an error +10: divu s5,s2,s4 // divide 0xFF00/0xFF + nop + nop + mfhi s6 // remainder s6=0 + bne s5,s1,ProcessorError + nop + blez s6,10f // branch if no error + nop + j ProcessorError +10: sub s7,s5,s4 // s7=1 + mthi s7 + mtlo AT + xori gp,s5,0x2566 // gp=0x2466 + move s0,sp // save sp for now + srl sp,gp,s7 // sp=0x1233 + mflo s8 // s8=0x12344321 + mfhi k0 // k0=1 + ori k1,zero,16 // k1=16 + sra k1,s8,k1 // k1=0x1234 + add AT,sp,k0 // AT=0x1234 + bne k1,AT,ProcessorError // branch on error + nop +#ifdef R4001 + // + // Some extra stuff added to verify that the R4000 bug is fixed + // If it hangs a minus sign will be displayed in the LED + // + li t0,DIAGNOSTIC_VIRTUAL_BASE + li t1,0xB // value to display '-' in the LED + sw t1,0(t0) // write to the LED should be sb + lw t2,8(t0) // do something + sll t5,t0,t1 // 2 cycle instruction +#endif + j ra // return + nop +ProcessorError: + lui a0,LED_BLINK // blink also means that + bal PutLedDisplay // the routine hangs. + ori a0,LED_PROCESSOR_TEST // displaying this value. + .end ProcessorTest + + +/*++ +VOID +MctadrReset( + VOID + ); + +Routine Description: + + This routine tests the reset values of the MP_ADR asic. + +Arguments: + + None. + +Return Value: + + None, but will hang flashing the led if an error occurs. + +--*/ + LEAF_ENTRY(MctadrResetTest) + move s0,ra // save return address. +// +// Test the mctadr reset values. +// +MctadrReset: + li t0,DMA_VIRTUAL_BASE // Get base address of MP_ADR + lw v0,DmaConfiguration(t0) // Check Config reset value + li t1,CONFIG_RESET_MP_ADR_REV1 // Check for REV1 ASIC, i.e. DUO + bne v0,t1,MctadrResetError + lw v0,DmaRevisionLevel(t0) // Get revision level register + bne v0,zero,MctadrResetError // If not REV1 Error + + addiu t1,t0,DmaInterruptEnable // + // enable register in REV2 + li v0,0x1f // MCTADR interrupt enable mask + sw v0,0(t1) // Enable all interrupts in MCTADR + +10: + lw v0,DmaInvalidAddress(t0) + lw v1,DmaTranslationBase(t0) + bne v0,zero,MctadrResetError // Check LFAR reset value + lw v0,DmaTranslationLimit(t0) + bne v1,zero,MctadrResetError // Check Ttable base reset value + lw v1,DmaRemoteFailedAddress(t0) + bne v0,zero,MctadrResetError // Check TT limit reset value + lw v0,DmaMemoryFailedAddress(t0) + bne v1,zero,MctadrResetError // Check RFAR reset value + lw v1,DmaChannelInterruptAcknowledge(t0) + bne v0,zero,MctadrResetError // Check MFAR reset value + addiu t1,t0,DmaRemoteSpeed0 // address of REM_SPEED 0 + bne v1,zero,MctadrResetError // Check Channel Interrup Ack reset value + addiu t2,t0,DmaRemoteSpeed14 // address of REM_SPEED 14 + lw v0,0(t1) // read register + li t3,REMSPEED_RESET // + addiu t1,t1,8 // next register address. +NextRemSpeed: + bne v0,t3,MctadrResetError // Check Rem speed reg reset value + lw v0,0(t1) // read next rem speed + bne t1,t2,NextRemSpeed + addiu t1,t1,8 // next register address. + bne v0,t3,MctadrResetError // Check last Rem speed reg reset value + addiu t1,t0,DmaChannel0Mode // address of first channel register + addiu t2,t0,DmaChannel3Address // address of last channel register + lw v0,0(t1) // read register + addiu t1,t1,8 // next register address. +NextChannelReg: + bne v0,zero,MctadrResetError // Check channel reg reset value + lw v0,0(t1) // read next channel + bne t1,t2,NextChannelReg + addiu t1,t1,8 // next register address. + bne v0,zero,MctadrResetError // Check last channel reg reset value + + lw v0,DmaArbitrationControl(t0) + bne v0,zero,MctadrResetError // check IO arbitration reset value + lw v1,DmaErrortype(t0) // read eisa/ethernet error reg + lw v0,DmaRefreshRate(t0) + bne v1,zero,MctadrResetError // check Eisa error type reset value + li t1,REFRRATE_RESET + bne v0,t1,MctadrResetError // check Refresh rate reset value + lw v0,DmaSystemSecurity(t0) + li t1,SECURITY_RESET + bne v0,t1,MctadrResetError // check Security reg reset value + lw v0,DmaEisaInterruptAcknowledge(t0) // read register but don't check + + addiu t1,t0,DmaIoCacheLowByteMask0// address of first bytemask register + addiu t2,t0,DmaIoCacheHighByteMask7// address of last Byte Mask register. + lw v0,0(t1) // read register + addiu t1,t1,8 // next register address. +NextByteMaskReg: + bne v0,zero,MctadrResetError // Check ByteMask reg reset value + lw v0,0(t1) // read next register + bne t1,t2,NextByteMaskReg // Loop + addiu t1,t1,8 // next register address. + j s0 // return to caller +MctadrResetError: + li t0,DIAGNOSTIC_VIRTUAL_BASE // get base address of diag register + lb t0,0(t0) // read register value. + li t1,LOOP_ON_ERROR_MASK // get value to compare + andi t0,DIAGNOSTIC_MASK // mask diagnostic bits. + beq t1,t0,10f // branch if loop on error. + ori a0,zero,LED_MCTADR_RESET// load LED display value. + lui t0,LED_BLINK // get LED blink code + bal PutLedDisplay // Blink LED and hang. + or a0,a0,t0 // pass argument in a0 +10: + lui t0,LED_LOOP_ERROR // get LED LOOP_ERROR code + bal PutLedDisplay // Set LOOP ON ERROR on LED + or a0,a0,t0 // pass argument in a0 + b MctadrReset + nop + .end MctadrResetTest + +/*++ +VOID +MctadrRegisterTest( + VOID + ); + +Routine Description: + + This routine tests the MP_ADR registers. + +Arguments: + + None. + +Return Value: + + None, but will hang flashing the led if an error occurs. + +--*/ + LEAF_ENTRY(MctadrRegisterTest) + move s0,ra // save return address. +// +// Check the data path between R4K and Mctadr by writing to Byte mask reg. +// +MctadrReg: + li t0,DMA_VIRTUAL_BASE + li t1,0x5 // 2Mb Video Map Prom + sw t1,DmaConfiguration(t0) // Init Global Config + lw v0,DmaConfiguration(t0) // Read Configuration + bne v0,t1,MctadrRegError // check GLOBAL CONFIG + li t1,1 + sw t1,DmaIoCacheLogicalTag0(t0) // Set LFN=zero, Offset=0 , Direction=READ from memory, Valid + li t2,0x55555555 + sw t2,DmaIoCacheLowByteMask0(t0) // write pattern to LowByte mask + li t3,0xAAAAAAAA + sw t3,DmaIoCacheHighByteMask0(t0) // write pattern to HighByte mask + lw v0,DmaIoCacheLowByteMask0(t0) // Read LowByte mask + lw v1,DmaIoCacheHighByteMask0(t0) // Read HighByte mask + bne v0,t2,MctadrRegError // + sw t1,DmaIoCachePhysicalTag0(t0) // PFN=0 and Valid + bne v1,t3,MctadrRegError // + sw t3,DmaIoCacheLowByteMask0(t0) // write pattern to LowByte mask + sw t2,DmaIoCacheHighByteMask0(t0) // write pattern to HighByte mask + li t2,0xFFFFFFFF // expected value + lw v0,DmaIoCacheLowByteMask0(t0) // Read LowByte mask + bne v0,t2,MctadrRegError // Check byte mask + lw v1,DmaIoCacheHighByteMask0(t0) // Read HighByte mask + bne v1,t2,MctadrRegError // Check byte mask + li a0,0xA0000000 // get memory address zero. + sw zero,0(a0) // write address zero -> flushes buffers + lw v0,DmaIoCacheLowByteMask0(t0) // Read LowByte mask + bne v0,zero,MctadrRegError // Check byte mask was cleared. + lw v1,DmaIoCacheHighByteMask0(t0) // Read HighByte mask + bne v1,zero,MctadrRegError // Check byte mask was cleared. + + li t4,MEMORY_REFRESH_RATE // + sw t4,DmaRefreshRate(t0) // + li t2,0x15555000 // + sw t2,DmaTranslationBase(t0) // write base of Translation Table + li t3,0xAAA0 + sw t3,DmaTranslationLimit(t0) // write to TT_limit + lw v1,DmaTranslationBase(t0) // read TT Base + lw v0,DmaTranslationLimit(t0) // read TT_limit + bne v1,t2,MctadrRegError // check TT-BASE + lw v1,DmaRefreshRate(t0) + bne v0,t3,MctadrRegError // check TT-LIMIT + li t2,0x5550 + bne v1,t4,MctadrRegError // check REFRESH Rate + li t1,0xAAAA000 + sw t1,DmaTranslationBase(t0) // write to Translation Base + sw t2,DmaTranslationLimit(t0) // write to Translation Limit + lw v0,DmaTranslationBase(t0) // read TT Base + lw v1,DmaTranslationLimit(t0) // read TT limit + bne v0,t1,MctadrRegError // check TT Base + li t1,TT_BASE_ADDRESS // Init translation table base address + sw t1,DmaTranslationBase(t0) // Initialize TT Base + bne v1,t2,MctadrRegError // check TT Limit + nop + sw zero,DmaTranslationLimit(t0) // clear TT Limit + +// +// Initialize remote speed registers. +// + addiu t1,t0,DmaRemoteSpeed1 // address of REM_SPEED 1 + la a1,RomRemoteSpeedValues // - LINK_ADDRESS + RESET_VECTOR // + addiu t2,a1,14 // addres of last value +WriteNextRemSpeed: + lbu v0,0(a1) // load init value for rem speed + addiu a1,a1,1 // compute next address + sw v0,0(t1) // write to rem speed reg + bne a1,t2,WriteNextRemSpeed // check for end condition + addiu t1,t1,8 // next register address + addiu a1,t2,-14 // address of first value for rem speed register + addiu t1,t0,DmaRemoteSpeed1 // address of REM_SPEED 1 + lbu v1,0(a1) // read expected value +CheckNextRemSpeed: + lw v0,0(t1) // read register + addiu a1,a1,1 // address of next value + bne v0,v1,MctadrRegError // check register + addiu t1,t1,8 // address of next register + bne a1,t2,CheckNextRemSpeed // check for end condition + lbu v1,0(a1) // read expected value + +// +// Initialize the IO Arb register +// + li v0,2 + sw v0,DmaArbitrationControl(t0) +// +// Now test the DMA channel registers +// + addiu t1,t0,DmaChannel0Mode // address of channel 0 + addiu t2,t1,4*DMA_CHANNEL_GAP // last address of channel regs + li a0,0x15 // Mode + li a1,0x2 // enable + li a2,0xAAAAA // byte count + li a3,0x555555 // address +WriteNextChannel: + sw a0,0(t1) // write mode + sw a1,0x8(t1) // write enable + sw a2,0x10(t1) // write byte count + sw a3,0x18(t1) // write address + addiu t1,t1,DMA_CHANNEL_GAP // compute address of next channel + addiu a2,a2,1 // change addres + bne t1,t2,WriteNextChannel + addiu a3,a3,-1 // change Byte count +// +// Check channel regs. +// + addiu t1,t0,DmaChannel0Mode // address of channel 0 + addiu t2,t1,4*DMA_CHANNEL_GAP // last address of channel regs + li a2,0xAAAAA // byte count + li a3,0x555555 // address +CheckNextChannel: + lw t4,0x0(t1) // read mode + lw t5,0x8(t1) // read enable + bne t4,a0,MctadrRegError // check mode + lw t4,0x10(t1) // read byte count + bne t5,a1,MctadrRegError // check enable + lw t5,0x18(t1) // read address + bne t4,a2,MctadrRegError // check abyte count + addiu a2,a2,1 // next expected byte count + bne t5,a3,MctadrRegError // check address + addiu t1,t1,DMA_CHANNEL_GAP // next channel address + bne t1,t2,CheckNextChannel + addiu a3,a3,-1 +// +// Now do a second test on DMA channel registers +// + addiu t1,t0,DmaChannel0Mode // address of channel 0 + addiu t2,t1,4*DMA_CHANNEL_GAP // last address of channel regs + li a0,0x2A // Mode + li a2,0x55555 // byte count + li a3,0xAAAAAA // address +WriteNextChannel2: + sw a0,0(t1) // write mode + sw a2,0x10(t1) // write byte count + sw a3,0x18(t1) // write address + addiu t1,t1,DMA_CHANNEL_GAP // compute address of next channel + addiu a2,a2,1 // change addres + bne t1,t2,WriteNextChannel2 + addiu a3,a3,-1 // change Byte count +// +// Check channel regs. +// + addiu t1,t0,DmaChannel0Mode // address of channel 0 + addiu t2,t1,4*DMA_CHANNEL_GAP // last address of channel regs + li a2,0x55555 // byte count + li a3,0xAAAAAA // address +CheckNextChannel2: + lw t4,0x0(t1) // read mode + lw t5,0x10(t1) // read byte count + bne t4,a0,MctadrRegError // check mode + lw t4,0x18(t1) // read address + bne t5,a2,MctadrRegError // check abyte count + addiu a2,a2,1 // next expected byte count + bne t4,a3,MctadrRegError // check address + addiu t1,t1,DMA_CHANNEL_GAP // next channel address + bne t1,t2,CheckNextChannel2 + addiu a3,a3,-1 +// +// Now zero the channel registers +// + addiu t1,t0,DmaChannel0Mode // address of channel 0 + addiu t2,t1,4*DMA_CHANNEL_GAP // last address of channel regs +ZeroChannelRegs: + addiu t1,t1,8 + sw zero,-8(t1) // clear reg + bne t1,t2,ZeroChannelRegs + nop //R4KFIX + addiu t1,t0,DmaChannel0Mode // address of channel 0 + addiu t2,t1,4*DMA_CHANNEL_GAP // last address of channel regs +CheckZeroedChannelRegs: + lw a0,0(t1) + bne a0,zero,MctadrRegError // check + addiu t1,t1,8 // next channel + bne t1,t2,CheckZeroedChannelRegs + nop + j s0 // return to caller. +MctadrRegError: + li t0,DIAGNOSTIC_VIRTUAL_BASE // get base address of diag register + lb t0,0(t0) // read register value. + li t1,LOOP_ON_ERROR_MASK // get value to compare + andi t0,DIAGNOSTIC_MASK // mask diagnostic bits. + beq t1,t0,10f // branch if loop on error. + ori a0,zero,LED_MCTADR_REG // load LED display value. + lui t0,LED_BLINK // get LED blink code + bal PutLedDisplay // Blink LED and hang. + or a0,a0,t0 // pass argument in a0 +10: + lui t0,LED_LOOP_ERROR // get LED LOOP_ERROR code + bal PutLedDisplay // Set LOOP ON ERROR on LED + or a0,a0,t0 // pass argument in a0 + b MctadrReg + nop + .end MctadrRegisterTest + +/* + + LEAF_ENTRY(SizeMemory) + .set noat + .set noreorder + li t0,DMA_VIRTUAL_BASE+DmaMemoryConfig0 + li t1,0x5 + sw t1,0x0(t0) + li t1,0x1000005 + sw t1,0x8(t0) + li t1,0x2000005 + sw t1,0x10(t0) + li t1,0x3000005 + sw t1,0x18(t0) + j ra + nop +ExpectedParityException: + .end + LEAF_ENTRY(SizeMemory) + .set noat + .set noreorder + li t0,DMA_VIRTUAL_BASE+DmaMemoryConfig0 + li t1,0xD + sw t1,0x0(t0) + li t1,0x200000D + sw t1,0x8(t0) + li t1,0x400000D + sw t1,0x10(t0) + li t1,0x600000D + sw t1,0x18(t0) + j ra + nop +ExpectedParityException: + .end +*/ + +/*++ +SizeMemory( + ); +Routine Description: + + This routine sizes the memory and writes the proper value into + the GLOBAL CONFIG register. The way memory is sized is the following: + + For Each of the four Memory Groups: + ConfigurationRegister is set to 0xE + + ID0 is written to offset 0 from base of bank + ID4 is written to offset 4MB from base of bank + ID20 is written to offset 20MB from base of bank + if ID20 is found at offset 0 the current bank has 1MB SIMMs. + if ID0 is found at offset 0 and ID20 is found at offset 4, + the current bank has 4MB SIMMs. + if ID0 is found at offset 0 and ID4 is found at offset 4 + and ID20 is found at offset 20, the current bank has 16MB SIMMs. + if data does not match or a parity exception is taken + then memory is not present in that bank. + + Once The size of the first side is determined, the second side + is checked. + + +Arguments: + + None. + +Return Value: + + If the installed memory is inconsistent, does not return + and the LED flashes A.E + +--*/ + +#define MEM_ID0 0x0A0A0A0A +#define MEM_ID4 0xF5F5F5F5 +#define MEM_ID20 0xA0A0A0A0 + + LEAF_ENTRY(SizeMemory) + .set noat + .set noreorder + +// +// Size Memory for DUO +// +#define SIZE_1MBIT 0x0000 // Low byte. Shift value +#define SIZE_4MBIT 0x0102 // High byte configuration value. +#define SIZE_16MBIT 0x0204 +// +// Size memory for duo. +// + li t1,MEM_ID0 // get ID0 + li t3,MEM_ID4 // get ID4 + li t5,MEM_ID20 // get ID20 + li s0,8 // counts how many banks left to check + li s1,DMA_VIRTUAL_BASE+DmaMemoryConfig0 + + +DSizeGroup: + li t0,0xA0000000 // get address 0MB + li t2,0xA0400000 // get address 4MB + li t4,0xA1400000 // get address 20MB + li a2,0xE // Memory Config Full Enable Value + sw a2,0(s1) // Store it. + +DSizeBank: + li a1,SIZE_1MBIT // set current bank to 1 MB by default + sw t1,0x0(t0) // fill whole memory line at base of bank + sw t1,0x4(t0) + sw t1,0x8(t0) + sw t1,0xC(t0) + sw t3,0x0(t2) // fill whole memory line at base of bank + 4MB + sw t3,0x4(t2) + sw t3,0x8(t2) + sw t3,0xC(t2) + sw t5,0x0(t4) // fill whole memory line at base of bank + 20MB + sw t5,0x4(t4) + sw t5,0x8(t4) + sw t5,0xC(t4) + // + // Check written data + // + move v1,zero // init v1 to zero + .align 4 // align address so that Parity Handler + // can easily determine if it happened here +ExpectedParityException: + lw t6,0x0(t0) // read whole memory line. + lw t7,0x4(t0) // the four words must be identical + lw t8,0x8(t0) // + lw t9,0xC(t0) // +ParityExceptionReturnAddress: + bne v1,zero,10f // if v1!=0 Parity exception occurred. + move a0,zero // tells that bank not present + bne t6,t7,10f // check for consistency + nop + bne t6,t8,10f // check for consistency + nop + bne t6,t9,10f // check for consistency + nop + beq t6,t5,10f // If ID20 is found at 0MB + li a0,0x4 // bank is present and SIMMS are 1 MB + bne t6,t1,10f // if neither ID20 nor ID0 is found we are in trouble + move a0,zero // no memory in bank + li a0,0x4 // bank is present + + // + // ID written at Address 0 has been correctly checked + // Now check the ID written at address 4MB + // + lw t6,0x0(t2) // read the whole memory line. + lw t7,0x4(t2) // the four words must be identical + bne t6,t7,WrongMemory // check for consistency + lw t8,0x8(t2) // + bne t6,t8,WrongMemory // check for consistency + lw t9,0xC(t2) // + bne t6,t9,WrongMemory // check for consistency + nop + beq t6,t5,10f // If ID20 is found at 4MB + li a1,SIZE_4MBIT // bank is present and SIMMS are 4 MB + bne t6,t3,WrongMemory // if neither ID20 nor ID4 is found we are in trouble + nop + // + // ID written at Address 4MB has been correctly checked + // Now check the ID written at address 20MB + // + lw t6,0x0(t4) // read the whole memory line. + lw t7,0x4(t4) // the four words must be identical + bne t6,t7,WrongMemory // check for consistency + lw t8,0x8(t4) // + bne t6,t8,WrongMemory // check for consistency + lw t9,0xC(t4) // + bne t6,t9,WrongMemory // check for consistency + nop + bne t6,t5,WrongMemory // if ID20 is not found we are in trouble + nop + li a1,SIZE_16MBIT // If all matches SIMMs are 16MB + +10: // + // a0 has the value 0 if no memory in bank, 4 if memory in bank + // + // The lower byte of a1 has the amount the constant 4MB should be + // left shifted by to get the nex address. + // The second byte of a12 has the matching value for the SIMM + // size bits of the Configuration register. + // + + andi AT,s0,1 // Check if first side + bne AT,zero,GroupDone // Branch if second side + addiu s0,s0,-1 // Decrement Bank counter + + // + // First Side. + // + beq a0,zero,GroupNotPresent // No memory present in this group + + move a3,a0 // Save bank presence bit. + move v0,a1 // Save first side SIMM size + + // + // Increment Base addresses by half the maximum size of a bank. + // + li AT,0x4000000 // 64MB + addu t0,AT // get Next bank address + 0MB + addu t2,AT // get Next bank address + 4MB + addu t4,AT // get Next bank address +20MB + b DSizeBank // Repeat for second side. + nop + +GroupNotPresent: + sw zero,0x0(s1) // Disable current bank + b NextGroup + addiu s0,s0,-1 // Skip 2nd side of non exitent Group. + + +GroupDone: + + // + // We are done with the current group. + // a1 and v0 have the SIMM size. + // a3 has first side presence bit a0 has second size presence bit. + // + beq a0,zero,SingleSidedBank // if a0 is zero no memory found in + nop // the second side. Don't check + // consistency between sizes. + bne a1,v0,WrongMemory // Both sides must have same size. +SingleSidedBank: + sll a0,1 // shift enable second side bit. + or a3,a0,a3 // or in first side presence. + srl v0,8 // Get SIMM size config value. + or a3,v0 // or in with bank presence + + // + // Set base of the sized bank up so that next bank + // can be sized as if it started at offset zero. + // When code gets here s0 has the value 6,4,2,0 + // shift it left by 26 bits to make the base of the bank + // at address 6*64MB,4*64Mb,2*64MB,0MB + // + sll AT,s0,26 // set base of bank to avoid colision between banks + or a3,AT,a3 // or physical base address. + sw a3,0x0(s1) // Store into config register + +NextGroup: + bne s0,zero,DSizeGroup // Repeat for next group. + addiu s1,s1,8 // Next configuration register. + + // + // The four groups have been sized and it's SIMM type and size + // value stored in the configuration register. + // Set their base addresses sorting them from big to small + // + // Mask = 0; + // BaseAddress = 0; + // do { + // BiggestSize = 0; + // BiggestIndex = 0; + // for (t2=0; t2 < 4; t2++) { + // if (Mask & (1 << t2)) { + // continue; + // } + // if (GroupSize[Config[t2]] == 0) { + // Mask |= 1 << t2; + // continue; + // } + // if (GroupSize[Config[t2]] > BiggestSize) { + // BiggestSize = GroupSize[Config[t2]]; + // BiggestIndex = t2; + // } + // } + // Config[BiggestIndex] = Config[BiggestIndex]&0xF + BaseAddress; + // Mask |= 1 << BiggestIndex; + // BaseAddress += BiggestSize; + // } while (Mask != 0xF); + // + // + // t0 = BiggestSize + // a3 = Biggest index + // a1 = Mask. Each bit indicates that group has been dealth with + // a2 = BaseAddress + // + + la v0,MemoryGroupSize // Address of table + li v1,DMA_VIRTUAL_BASE+DmaMemoryConfig0 // Address of first config register + move a2,zero // base address of group + move a1,zero // mask register +Loop: + move t2,zero // loop count + move a3,zero // biggest group index + move t0,zero // size of biggest group + +ReadNextGroup: + li t4,1 + sll t4,t4,t2 // set Nth bit for iteration N + nop + and t5,a1,t4 // test if bit set in mask + beq t5,zero,10f // if not set read current group config + nop + b ForEachGroup + addiu t2,t2,1 // Increment group index + +10: + sll t3,t2,3 // multiply loop count by 8 + addu t3,t3,v1 // add to base of config registers + lw a0,0x0(t3) // read config register + andi a0,0xF // extract SIMM type bits + addu a0,a0,v0 // add to base of table + lbu a0,0(a0) // index table to get size in MB + beq a0,zero,SizeZeroGroup // if zero set mask bit for this group + sltu t1,t0,a0 // Branch if the size of the biggest group is + bne t1,zero,BiggerFound // smaller than the current group + nop + b ForEachGroup // Go for next group + addiu t2,t2,1 // Increment index + +BiggerFound: + // + // The current group is the biggest found so far + // + move t0,a0 // set biggest group to current + move a3,t2 // save biggest group index + b ForEachGroup + addiu t2,t2,1 // next group index. + + +SizeZeroGroup: + // + // Or Nth bit to tell that this group doesn't + // need to be dealth with since it's size is zero + // + or a1,a1,t4 + addiu t2,t2,1 // increment group index + +ForEachGroup: + li t1,4 // last group + bne t2,t1,ReadNextGroup // if not last group repeat + + // + // The four groups where checked. + // t0 has the size of the biggest found. + // a3 has the index of the biggest found. + // Set the current base to the config register + // Increment the base by the size of the register + // + sll t3,a3,3 // multiply index by 8 + addu t3,t3,v1 // add to base of config registers + lw a0,0x0(t3) // read config register + andi a0,0xF // extract SIMM type bits + or a0,a2 // or in the current base address + sw a0,0(t3) // store + sll t0,20 // shift size in MB to address + addu a2,a2,t0 // add size to current base + + li t4,1 // get a 1 + sll t4,t4,a3 // set Nth bit for biggest found N + or a1,a1,t4 // or into mask of processed groups + li t1,0xF // + bne t1,a1,Loop // if not all bits set in the mask Loop + nop + j ra // return to caller. + nop + +WrongMemory: + // + // Control reaches here if the memory can't be sized. + // + lui a0,LED_BLINK // Hang + bal PutLedDisplay // blinking the error code + ori a0,a0,LED_WRONG_MEMORY // in the LED + .end SizeMemory + + +// +// This table indexed with the low 4 bits of the MemoryGroup config register, +// returns the size of memory installed in the group in Megabytes. +// +// +MemoryGroupSize: +.byte 0 // No SIMM installed +.byte 0 // No SIMM installed +.byte 0 // No SIMM installed +.byte 0 // No SIMM installed +.byte 4 // Single Sided 4MB +.byte 16 // Single Sided 16MB +.byte 64 // Single Sided 64MB +.byte 0 // Single Sided reserved +.byte 0 // Reserved +.byte 0 // Reserved +.byte 0 // Reserved +.byte 0 // Reserved +.byte 8 // Double Sided 4MB +.byte 32 // Double Sided 16MB +.byte 128 // Double Sided 64MB +.byte 0 // Double Sided reserved + +#endif // DUO && R4000 |