kerneltest/e32test/mmu/t_cache.cpp
author Slion
Tue, 08 Dec 2009 08:11:42 +0100
branchanywhere
changeset 19 f6d3d9676ee4
parent 0 a41df078684a
child 62 4a8fed1c0ef6
permissions -rw-r--r--
Trying to figure out how to implement my WINC like compatibility layer. Going the emulation way is probably not so smart. We should not use the kernel but rather hook native functions in the Exec calls.

// Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of the License "Eclipse Public License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
//
// Initial Contributors:
// Nokia Corporation - initial contribution.
//
// Contributors:
//
// Description:
// e32test\debug\t_cache.cpp
// Overview:
// Performs cache checking in order to ensure it is running correctly.
// Runs automatically or as manual test. (Type "t_cache help" for details.)
// API Information:
// class Cache
// class L2Cache
// Details:
// -Test1 - Displays cache properties.
// -Test2 - Gets thresholds.
// -Test3 - Sets thresholds.
// -Test4 - Compares different memory mappings of data.
// -Test5 - Compares different memory mappings of code.
// -Test6 - Tests Write Back mode.
// -Test7 - Tests cache maintenance functions
// It can also perform more specified tests if run manually:
// - t_cache info				Test1 only
// - t_cache data <size_hex>	Runs data chunk test (Test 4) with specified chunk size. For example,
// "t_cache data 10000" will run data chunk test against 64KB chunk.
// - t_cache code <size_hex>	Runs code chunk test (Test 5) for specified chink size. For example,
// "t_cache code 10000" will run code chunk test against 64KB chunk.
// - t_cache data+<size_hex>	Runs data chunk test for specified set of chunk sizes. For example,
// "t_cache data+1000" will perform data chunk test for sizes 4K, 8K,... up to 512K.
// - t_cache code+<size_hex>	Runs code chunk test for specified set of sizes. For example,
// "t_cache code+1000" will perform code chunk test for sizes 4K, 8K,... up to 512K.
// - t_cache threshold			Diplays thresholds for all caches on the platform.
// - t_cache threshold T P C H	Sets new values for cache thresholds:
// - "T" specifies the type of cache to whose threshould are to be chenged:
// 1  for Instruction (or Unified) Cache.
// 2  for Data Cache (for ARMv7 and later, this is Point-of-Coherency threshold.
// 4  for XScale AltData Cache.
// 8  for Point-of-Unification Data Cache Threshold for ARMv7 and later platforms.
// 10 for L2 (L210 or XScale L2 cache)
// - "P" "C" & "H" are hex values for purge, clean & flush thresholds.
// For example: "t_cache 1 10000 10000 10000" sets 64KB for all thresholds in Instruction Cache.
// - t_cache usecase			Runs particular use case tests.
// - t_cache help				Displays the list of manual commands.
// Platforms/Drives/Compatibility:
// Hardware - ARM only (Manual). Not supported on emulator.
// Assumptions/Requirement/Pre-requisites:
// Failures and causes:
// Base Port information:
// d_cache.mmp to be built from the baseport.
// 
//

#include <e32test.h>
#include "d_cache.h"

//------------globals---------------------
LOCAL_D RTest test(_L("T_CACHE"));
_LIT(KPrintCacheInfos,"info");
_LIT(KTestData,"data");
_LIT(KTestCode,"code");
_LIT(KHelp,"help");
_LIT(KThreshold,"threshold");
_LIT(KIncremental,"+");
_LIT(KUseCase,"usecase");

RCacheTestDevice Device;
RCacheTestDevice::TCacheInfo CacheInfo;
TBuf<KCacheDescSize> TempBuff;

const TInt KDefaultDataSize = 0x20000;	
const TInt KDefaultCodeSize = 0x804;	//2K+4. Should be <= TestCodeFuncSize(). Otherwise, code test won't run against rom image.
const TInt KMaxChunkSize 	= 0x80000;	//512KB Incremental tests limit
const TInt KWriteBackTestSizeSize = 0x4000; // Shouldn't go over cache thresholds (where purge becomes flush).

extern void DataSegmetTestFunct(void* aBase, TInt aSize);

/** Loads & opens LDD.*/
void StartDriver()
	{
	TInt r = User::LoadLogicalDevice(KCacheTestDriverName);
	test( r==KErrNone || r==KErrAlreadyExists);
	if((r = Device.Open())!=KErrNone)	
		{
		User::FreeLogicalDevice(KCacheTestDriverName);
		test.Printf(_L("Could not open LDD"));
		test(0);
		}
	}

/** Closes and unloads LDD.*/
void StopDriver()
	{
	Device.Close();
	User::FreeLogicalDevice(KCacheTestDriverName);
	}

/** Get cache info from device driver. This will update CacheInfo global variable.*/
void GetCacheInfo()
	{
	TInt r = Device.GetCacheInfo(CacheInfo);
	test(r==KErrNone);
	}

//---------------------------------------------
//! @SYMTestCaseID			MMU-T_CACHE-01
//! @SYMTestType 			ST
//! @SYMPREQ 				PREQ305
//! @SYMREQ 				REQ5795
//! @SYMTestCaseDesc 		Displays cache properties.
//! @SYMTestExpectedResults KErrNone 
//! @SYMTestPriority 		Low
//! @SYMTestStatus 			Implemented
//---------------------------------------------
void Test1()
	{
	TInt i;
	
	test.Printf(_L("General Info:\n"));
	TPtr ptr = CacheInfo.iDesc.Expand();
	test.Printf(ptr);
	test.Printf(_L("CacheCount:%d, MaxCacheSize:%xH, MemoryRemapping:%d, OuterCache:%d\n"),CacheInfo.iCacheCount, CacheInfo.iMaxCacheSize, CacheInfo.iMemoryRemapping, CacheInfo.iOuterCache);
	test.Printf(_L("DMAMemoryAlignement:%d\n"),CacheInfo.iDmaBufferAlignment);


	test.Printf(_L("Per Level Info:\n"));
	test.Printf(_L("Level\tData\tInstr\tSize(b)\tLine(b)\tWays\tSets\tDescription\n"));

	for (i = 0; i<CacheInfo.iCacheCount; i++)
		{
		TempBuff.SetLength(0);
		RCacheTestDevice::TCacheSingle& cs = CacheInfo.iCache[i];
		TempBuff.Format(_L("%d\t%d\t%d\t%xH\t%xH\t%xH\t%xH\t"), cs.iLevel, cs.iData, cs.iCode, cs.iSize, cs.iLineSize, cs.iWays, cs.iSets);
		ptr = cs.iDesc.Expand();
		TempBuff.Append(ptr);
		TempBuff.Append(_L("\n"));
		test.Printf(TempBuff);
		}
	}

//---------------------------------------------
//! @SYMTestCaseID			MMU-T_CACHE-02
//! @SYMTestType 			ST
//! @SYMPREQ 				PREQ1068
//! @SYMREQ 				REQ5909
//! @SYMTestCaseDesc 		Gets thresholds.
//! @SYMTestActions 		Fetches Cache Thresholds from the driver.
//! @SYMTestExpectedResults KErrNone 
//! @SYMTestPriority 		High
//! @SYMTestStatus 			Implemented
//---------------------------------------------
void Test2()
	{
	RCacheTestDevice::TThresholdInfo info;
	
	test.Printf(_L("Cache: Purge  Clear  Flush\n"));
	
	info.iCacheType=1;
	if (KErrNone == Device.GetThreshold(info))
		test.Printf(_L("Instr:%6x %6x %6x\n"),info.iPurge,info.iClean,info.iFlush);
	
	info.iCacheType=2;
	if (KErrNone == Device.GetThreshold(info))
		test.Printf(_L("Data: %6x %6x %6x\n"),info.iPurge,info.iClean,info.iFlush);
	
	info.iCacheType=4;
	if (KErrNone == Device.GetThreshold(info))
		test.Printf(_L("AltD: %6x %6x %6x\n"),info.iPurge,info.iClean,info.iFlush);
	
	info.iCacheType=8;
	if (KErrNone == Device.GetThreshold(info))
		test.Printf(_L("D_IMB:%6x %6x %6x\n"),info.iPurge,info.iClean,info.iFlush);
	
	info.iCacheType=16;
	if (KErrNone == Device.GetThreshold(info))
		test.Printf(_L("L2:   %6x %6x %6x\n"),info.iPurge,info.iClean,info.iFlush);
	}

//---------------------------------------------
//! @SYMTestCaseID			MMU-T_CACHE-03
//! @SYMTestType 			ST
//! @SYMPREQ 				PREQ1068
//! @SYMREQ 				REQ5909
//! @SYMTestCaseDesc 		Sets thresholds.
//! @SYMTestActions 		Sets new values forr Cache Thresholds. Then, sets back the old values.
//! @SYMTestExpectedResults KErrNone 
//! @SYMTestPriority 		High
//! @SYMTestStatus 			Implemented
//---------------------------------------------
void Test3()
	{
	TInt i, tested=0;
	RCacheTestDevice::TThresholdInfo info[5]; //for 5 types og cache
	TInt returned[5];
	

	//Get the old values
	for (i=0;i<5;i++)
		{
		info[i].iCacheType= 1<<i;
		returned[i] = Device.GetThreshold(info[i]);
		}

	//Double them all
	for (i=0;i<5;i++)
		{
		if (returned[i] != KErrNone) continue; //not a valid cache type for running platform
		tested++;
		info[i].iPurge <<=1;
		info[i].iClean <<=1;
		info[i].iFlush <<=1;
		test(KErrNone==Device.SetThreshold(info[i]));
		}

	//Put back the old values
	for (i=0;i<5;i++)
		{
		if (returned[i] != KErrNone) continue; //not a valid cache type for running platform
		info[i].iPurge >>=1;
		info[i].iClean >>=1;
		info[i].iFlush >>=1;
		test(KErrNone==Device.SetThreshold(info[i]));
		}
	test.Printf(_L(" ... %d caches present & tested\n"), tested);
	}



void DoTest4(RCacheTestDevice::TCacheAttr aCacheAttr, RCacheTestDevice::TChunkTest& aDC, TInt& aTime1, TInt& aTime2)
	{
	aDC.iCacheAttr = aCacheAttr;
	
	aDC.iShared = EFalse;
	test(KErrNone==Device.TestDataChunk(aDC));
	aTime1 = aDC.iTime;

	aDC.iShared = ETrue;
	test(KErrNone==Device.TestDataChunk(aDC));
	aTime2 = aDC.iTime;
	}
//---------------------------------------------
//! @SYMTestCaseID 			MMU-T_CACHE-04
//! @SYMTestType 			ST
//! @SYMPREQ 				PREQ305
//! @SYMREQ 				REQ5795
//! @SYMTestCaseDesc 		Compares different memory mappings of data.
//! @SYMTestActions 		Runs the same performance test against data in the chunks with different cache attributes.
//!							Also, runs the same test against data from user & kernel heaps.
//! @SYMTestExpectedResults KErrNone 
//! @SYMTestPriority 		Low
//! @SYMTestStatus 			Implemented
//---------------------------------------------
void Test4(TInt aSize)
	{
	RCacheTestDevice::TChunkTest dC;
	dC.iSize = aSize;
	dC.iUseCase = 0;  //not used
	dC.iLoops = 0; //not used
	TInt timeNS=0, timeS=0;

	test.Printf(_L("                                  	Time\n"));
	test.Printf(_L("Mem_Type      ActualMapAttr	NotShared	Shared\n"));
	test.Printf(_L("----------------------------------------------\n"));

	DoTest4(RCacheTestDevice::E_FullyBlocking, dC, timeNS, timeS);
	test.Printf(_L("FullyBlocking   %08xH\t%7d\t%7d\n"),dC.iActualMapAttr, timeNS, timeS);
	DoTest4(RCacheTestDevice::E_Buffered_NC, dC, timeNS, timeS);
	test.Printf(_L("Buffered_NC     %08xH\t%7d\t%7d\n"),dC.iActualMapAttr, timeNS, timeS);
	DoTest4(RCacheTestDevice::E_Buffered_C, dC, timeNS, timeS);
	test.Printf(_L("Buffered_C      %08xH\t%7d\t%7d\n"),dC.iActualMapAttr, timeNS, timeS);


	DoTest4(RCacheTestDevice::E_InnerWT, dC, timeNS, timeS);
	test.Printf(_L("InnerWT         %08xH\t%7d\t%7d\n"),dC.iActualMapAttr, timeNS, timeS);
	DoTest4(RCacheTestDevice::E_InnerWBRA, dC, timeNS, timeS);
	test.Printf(_L("InnerWBRA       %08xH\t%7d\t%7d\n"),dC.iActualMapAttr, timeNS, timeS);
	DoTest4(RCacheTestDevice::E_InnerWB, dC, timeNS, timeS);
	test.Printf(_L("InnerWB         %08xH\t%7d\t%7d\n"),dC.iActualMapAttr, timeNS, timeS);

	if(CacheInfo.iOuterCache)
		{
		DoTest4(RCacheTestDevice::E_OuterWT, dC, timeNS, timeS);
		test.Printf(_L("OuterWT         %08xH\t%7d\t%7d\n"),dC.iActualMapAttr, timeNS, timeS);
		DoTest4(RCacheTestDevice::E_OuterWBRA, dC, timeNS, timeS);
		test.Printf(_L("OuterWBRA       %08xH\t%7d\t%7d\n"),dC.iActualMapAttr, timeNS, timeS);
		DoTest4(RCacheTestDevice::E_OuterWB, dC, timeNS, timeS);
		test.Printf(_L("OuterWB         %08xH\t%7d\t%7d\n"),dC.iActualMapAttr, timeNS, timeS);

		DoTest4(RCacheTestDevice::E_InOutWT, dC, timeNS, timeS);
		test.Printf(_L("InOutWT         %08xH\t%7d\t%7d\n"),dC.iActualMapAttr, timeNS, timeS);
		DoTest4(RCacheTestDevice::E_InOutWBRA, dC, timeNS, timeS);
		test.Printf(_L("InOutWBRA       %08xH\t%7d\t%7d\n"),dC.iActualMapAttr, timeNS, timeS);
		DoTest4(RCacheTestDevice::E_InOutWB, dC, timeNS, timeS);
		test.Printf(_L("InOutWB         %08xH\t%7d\t%7d\n"),dC.iActualMapAttr, timeNS, timeS);
		}


	DoTest4(RCacheTestDevice::E_StronglyOrder, dC, timeNS, timeS);
	test.Printf(_L("StronglyOrder   %08xH\t%7d\t%7d\n"),dC.iActualMapAttr, timeNS, timeS);
	DoTest4(RCacheTestDevice::E_Device, dC, timeNS, timeS);
	test.Printf(_L("Device          %08xH\t%7d\t%7d\n"),dC.iActualMapAttr, timeNS, timeS);
	DoTest4(RCacheTestDevice::E_Normal_Uncached, dC, timeNS, timeS);
	test.Printf(_L("Normal_Uncached %08xH\t%7d\t%7d\n"),dC.iActualMapAttr, timeNS, timeS);
	DoTest4(RCacheTestDevice::E_Normal_Cached, dC, timeNS, timeS);
	test.Printf(_L("Normal_Cached   %08xH\t%7d\t%7d\n"),dC.iActualMapAttr, timeNS, timeS);

	if(CacheInfo.iMemoryRemapping)
		{
		DoTest4(RCacheTestDevice::E_KernelInternal4, dC, timeNS, timeS);
		test.Printf(_L("KernelInternal4 %08xH\t%7d\t%7d\n"),dC.iActualMapAttr, timeNS, timeS);
		DoTest4(RCacheTestDevice::E_PlatformSpecific5, dC, timeNS, timeS);
		test.Printf(_L("PlatSpecific5   %08xH\t%7d\t%7d\n"),dC.iActualMapAttr, timeNS, timeS);
		DoTest4(RCacheTestDevice::E_PlatformSpecific6, dC, timeNS, timeS);
		test.Printf(_L("PlatSpecific6   %08xH\t%7d\t%7d\n"),dC.iActualMapAttr, timeNS, timeS);
		DoTest4(RCacheTestDevice::E_PlatformSpecific7, dC, timeNS, timeS);
		test.Printf(_L("PlatSpecific7   %08xH\t%7d\t%7d\n"),dC.iActualMapAttr, timeNS, timeS);


		DoTest4(RCacheTestDevice::E_InnerWT_Remapped, dC, timeNS, timeS);
		test.Printf(_L("InnerWT_Remap   %08xH\t%7d\t%7d\n"),dC.iActualMapAttr, timeNS, timeS);
		DoTest4(RCacheTestDevice::E_InnerWBRA_Remapped, dC, timeNS, timeS);
		test.Printf(_L("InnerWBRA_Remap  %08xH\t%7d\t%7d\n"),dC.iActualMapAttr, timeNS, timeS);
		DoTest4(RCacheTestDevice::E_InnerWB_Remapped, dC, timeNS, timeS);
		test.Printf(_L("InnerWB_Remap    %08xH\t%7d\t%7d\n"),dC.iActualMapAttr, timeNS, timeS);

		if(CacheInfo.iOuterCache)
			{
			DoTest4(RCacheTestDevice::E_OuterWT_Remapped, dC, timeNS, timeS);
			test.Printf(_L("OuterWT_Remap    %08xH\t%7d\t%7d\n"),dC.iActualMapAttr, timeNS, timeS);
			DoTest4(RCacheTestDevice::E_OuterWBRA_Remapped, dC, timeNS, timeS);
			test.Printf(_L("OuterWBRA_Remap  %08xH\t%7d\t%7d\n"),dC.iActualMapAttr, timeNS, timeS);
			DoTest4(RCacheTestDevice::E_OuterWB_Remapped, dC, timeNS, timeS);
			test.Printf(_L("OuterWB_Remap    %08xH\t%7d\t%7d\n"),dC.iActualMapAttr, timeNS, timeS);

			DoTest4(RCacheTestDevice::E_InOutWT_Remapped, dC, timeNS, timeS);
			test.Printf(_L("InOutWT_Remap    %08xH\t%7d\t%7d\n"),dC.iActualMapAttr, timeNS, timeS);
			DoTest4(RCacheTestDevice::E_InOutWBRA_Remapped, dC, timeNS, timeS);
			test.Printf(_L("InOutWBRA_Remap  %08xH\t%7d\t%7d\n"),dC.iActualMapAttr, timeNS, timeS);
			DoTest4(RCacheTestDevice::E_InOutWB_Remapped, dC, timeNS, timeS);
			test.Printf(_L("InOutWB_Remap    %08xH\t%7d\t%7d\n"),dC.iActualMapAttr, timeNS, timeS);
			}
		}

	//Run against kernel heap - allow the test to fail due to OOM
	dC.iCacheAttr = RCacheTestDevice::E_Default;
	TInt r = Device.TestDataChunk(dC);
	if (r==KErrNone)			test.Printf(_L("Kernel Heap     ---------\t%7d\t-------\n"), dC.iTime);
	else if (r==KErrNoMemory)	test.Printf(_L("Kernel Heap     Cannot allocate memory\n"));
	else						test(0);//fail

	//Run against user heap - allow the test to fail due to OOM
	void* buffer = User::Alloc(dC.iSize);
	if (buffer == NULL)
		{
		test.Printf(_L("User Heap      Cannot allocate memory\n"));
		return;
		}
	TInt time = User::NTickCount();
	DataSegmetTestFunct(buffer , dC.iSize);
	time = User::NTickCount() - time;
	User::Free(buffer);
	test.Printf(_L("User Heap       ---------\t%7d\t-------\n"), time);

	}		


void DoTest5(RCacheTestDevice::TCacheAttr aCacheAttr, RCacheTestDevice::TChunkTest& aDC, TInt& aTime1, TInt& aTime2)
	{
	aDC.iCacheAttr = aCacheAttr;
	
	aDC.iShared = EFalse;
	test(KErrNone==Device.TestCodeChunk(aDC));
	aTime1 = aDC.iTime;

	aDC.iShared = ETrue;
	test(KErrNone==Device.TestCodeChunk(aDC));
	aTime2 = aDC.iTime;
	}
//---------------------------------------------
//! @SYMTestCaseID 			MMU-T_CACHE-05
//! @SYMTestType 			ST
//! @SYMPREQ 				PREQ305
//! @SYMREQ 				REQ5795
//! @SYMTestCaseDesc 		Compares different memory mappings of code.
//! @SYMTestActions 		Runs the same performance test against code in chunks with different cache attributes.
//!							Also, runs the same test against code from rom..
//! @SYMTestExpectedResults KErrNone 
//! @SYMTestPriority 		Low
//! @SYMTestStatus 			Implemented
//---------------------------------------------
void Test5(TInt aSize)
	{
	RCacheTestDevice::TChunkTest dC;
	dC.iSize = aSize;
	dC.iUseCase = 0;  //not used
	dC.iLoops = 0; //not used
	TInt timeNS=0, timeS=0;

	test.Printf(_L("                                  	Time\n"));
	test.Printf(_L("Mem_Type   AttemptedMapAttr	NotShared	Shared\n"));
	test.Printf(_L("----------------------------------------------\n"));

	DoTest5(RCacheTestDevice::E_FullyBlocking, dC, timeNS, timeS);
	test.Printf(_L("FullyBlocking   %08xH\t%7d\t%7d\n"),dC.iActualMapAttr, timeNS, timeS);
	DoTest5(RCacheTestDevice::E_Buffered_NC, dC, timeNS, timeS);
	test.Printf(_L("Buffered_NC     %08xH\t%7d\t%7d\n"),dC.iActualMapAttr, timeNS, timeS);
	DoTest5(RCacheTestDevice::E_Buffered_C, dC, timeNS, timeS);
	test.Printf(_L("Buffered_C      %08xH\t%7d\t%7d\n"),dC.iActualMapAttr, timeNS, timeS);


	DoTest5(RCacheTestDevice::E_InnerWT, dC, timeNS, timeS);
	test.Printf(_L("InnerWT         %08xH\t%7d\t%7d\n"),dC.iActualMapAttr, timeNS, timeS);
	DoTest5(RCacheTestDevice::E_InnerWBRA, dC, timeNS, timeS);
	test.Printf(_L("InnerWBRA       %08xH\t%7d\t%7d\n"),dC.iActualMapAttr, timeNS, timeS);
	DoTest5(RCacheTestDevice::E_InnerWB, dC, timeNS, timeS);
	test.Printf(_L("InnerWB         %08xH\t%7d\t%7d\n"),dC.iActualMapAttr, timeNS, timeS);

	if(CacheInfo.iOuterCache)
		{
		DoTest5(RCacheTestDevice::E_OuterWT, dC, timeNS, timeS);
		test.Printf(_L("OuterWT         %08xH\t%7d\t%7d\n"),dC.iActualMapAttr, timeNS, timeS);
		DoTest5(RCacheTestDevice::E_OuterWBRA, dC, timeNS, timeS);
		test.Printf(_L("OuterWBRA       %08xH\t%7d\t%7d\n"),dC.iActualMapAttr, timeNS, timeS);
		DoTest5(RCacheTestDevice::E_OuterWB, dC, timeNS, timeS);
		test.Printf(_L("OuterWB         %08xH\t%7d\t%7d\n"),dC.iActualMapAttr, timeNS, timeS);

		DoTest5(RCacheTestDevice::E_InOutWT, dC, timeNS, timeS);
		test.Printf(_L("InOutWT         %08xH\t%7d\t%7d\n"),dC.iActualMapAttr, timeNS, timeS);
		DoTest5(RCacheTestDevice::E_InOutWBRA, dC, timeNS, timeS);
		test.Printf(_L("InOutWBRA       %08xH\t%7d\t%7d\n"),dC.iActualMapAttr, timeNS, timeS);
		DoTest5(RCacheTestDevice::E_InOutWB, dC, timeNS, timeS);
		test.Printf(_L("InOutWB         %08xH\t%7d\t%7d\n"),dC.iActualMapAttr, timeNS, timeS);
		}


	DoTest5(RCacheTestDevice::E_StronglyOrder, dC, timeNS, timeS);
	test.Printf(_L("StronglyOrder   %08xH\t%7d\t%7d\n"),dC.iActualMapAttr, timeNS, timeS);
	DoTest5(RCacheTestDevice::E_Device, dC, timeNS, timeS);
	test.Printf(_L("Device          %08xH\t%7d\t%7d\n"),dC.iActualMapAttr, timeNS, timeS);
	DoTest5(RCacheTestDevice::E_Normal_Uncached, dC, timeNS, timeS);
	test.Printf(_L("Normal_Uncached %08xH\t%7d\t%7d\n"),dC.iActualMapAttr, timeNS, timeS);
	DoTest5(RCacheTestDevice::E_Normal_Cached, dC, timeNS, timeS);
	test.Printf(_L("Normal_Cached   %08xH\t%7d\t%7d\n"),dC.iActualMapAttr, timeNS, timeS);

	if(CacheInfo.iMemoryRemapping)
		{
		DoTest5(RCacheTestDevice::E_InnerWT_Remapped, dC, timeNS, timeS);
		test.Printf(_L("InnerWT_Remap   %08xH\t%7d\t%7d\n"),dC.iActualMapAttr, timeNS, timeS);
		DoTest5(RCacheTestDevice::E_InnerWBRA_Remapped, dC, timeNS, timeS);
		test.Printf(_L("InnerWBRA_Remap  %08xH\t%7d\t%7d\n"),dC.iActualMapAttr, timeNS, timeS);
		DoTest5(RCacheTestDevice::E_InnerWB_Remapped, dC, timeNS, timeS);
		test.Printf(_L("InnerWB_Remap    %08xH\t%7d\t%7d\n"),dC.iActualMapAttr, timeNS, timeS);

		if(CacheInfo.iOuterCache)
			{
			DoTest5(RCacheTestDevice::E_OuterWT_Remapped, dC, timeNS, timeS);
			test.Printf(_L("OuterWT_Remap    %08xH\t%7d\t%7d\n"),dC.iActualMapAttr, timeNS, timeS);
			DoTest5(RCacheTestDevice::E_OuterWBRA_Remapped, dC, timeNS, timeS);
			test.Printf(_L("OuterWBRA_Remap  %08xH\t%7d\t%7d\n"),dC.iActualMapAttr, timeNS, timeS);
			DoTest5(RCacheTestDevice::E_OuterWB_Remapped, dC, timeNS, timeS);
			test.Printf(_L("OuterWB_Remap    %08xH\t%7d\t%7d\n"),dC.iActualMapAttr, timeNS, timeS);

			DoTest5(RCacheTestDevice::E_InOutWT_Remapped, dC, timeNS, timeS);
			test.Printf(_L("InOutWT_Remap    %08xH\t%7d\t%7d\n"),dC.iActualMapAttr, timeNS, timeS);
			DoTest5(RCacheTestDevice::E_InOutWBRA_Remapped, dC, timeNS, timeS);
			test.Printf(_L("InOutWBRA_Remap  %08xH\t%7d\t%7d\n"),dC.iActualMapAttr, timeNS, timeS);
			DoTest5(RCacheTestDevice::E_InOutWB_Remapped, dC, timeNS, timeS);
			test.Printf(_L("InOutWB_Remap    %08xH\t%7d\t%7d\n"),dC.iActualMapAttr, timeNS, timeS);
			}
		}

	//Run against kernel heap - allow the test to fail due to OOM
		dC.iCacheAttr = RCacheTestDevice::E_Default;
		TInt r = Device.TestCodeChunk(dC);
		if (r==KErrNone)			test.Printf(_L("Run from rom   ---------\t%7d\t-------\n"), dC.iTime);
		else if (r==KErrNoMemory)	test.Printf(_L("Run from rom    Cannot allocate memory\n"));
		else						test(0);//fail

	}



//---------------------------------------------
//! @SYMTestCaseID 			MMU-T_CACHE-06
//! @SYMTestType 			ST
//! @SYMPREQ 				PREQ305
//! @SYMREQ 				REQ5795
//! @SYMTestCaseDesc 		Tests Write Back mode.
//! @SYMTestActions 		The driver allocates write back chunk, write data into it and invalidate (aka purge)
//							the chunk from the cache. Then, it counts the number of bytes of the chunk that
//							reached the physical memory.
//! @SYMTestExpectedResults KErrNone 
//! @SYMTestPriority 		Low
//! @SYMTestStatus 			Implemented
//---------------------------------------------

void Test6()
	{
	test.Printf(_L("Test4: Testing WriteBack cache mode...\n"));
	RCacheTestDevice::TChunkTest dC;


	test.Printf(_L("Cache\tMemType\tChecking\tSize\tBytesInRAM\tVerdict\n"));
	test.Printf(_L("-----\t-------\t--------\t----\t----------\t-------\n"));
//
	dC.iSize = KWriteBackTestSizeSize;
	if(CacheInfo.iMemoryRemapping)	dC.iCacheAttr = RCacheTestDevice::E_InnerWBRA_Remapped;
	else							dC.iCacheAttr = RCacheTestDevice::E_InnerWBRA;
	test(Device.TestWriteBackReadAllocate(dC)==KErrNone);
	if (dC.iSize<KWriteBackTestSizeSize)test.Printf(_L("Inner\tWBRA\tReadAlloc\t%xH\t%xH\tOK\n"), KWriteBackTestSizeSize, dC.iSize);
	else								test.Printf(_L("Inner\tWBRA\tReadAlloc\t%xH\t%xH\tWarning: Didn't pass\n"), KWriteBackTestSizeSize, dC.iSize);
//
	dC.iSize = KWriteBackTestSizeSize;
	if(CacheInfo.iMemoryRemapping)	dC.iCacheAttr = RCacheTestDevice::E_InnerWB_Remapped;
	else							dC.iCacheAttr = RCacheTestDevice::E_InnerWB;
	test(Device.TestWriteBackReadAllocate(dC)==KErrNone);
	if (dC.iSize<KWriteBackTestSizeSize)test.Printf(_L("Inner\tWBWA\tReadAlloc\t%xH\t%xH\tOK\n"), KWriteBackTestSizeSize, dC.iSize);
	else								test.Printf(_L("Inner\tWBWA\tReadAlloc\t%xH\t%xH\tWarning: Didn't pass\n"), KWriteBackTestSizeSize, dC.iSize);
//
	dC.iSize = KWriteBackTestSizeSize;
	if(CacheInfo.iMemoryRemapping)	dC.iCacheAttr = RCacheTestDevice::E_InnerWB_Remapped;
	else							dC.iCacheAttr = RCacheTestDevice::E_InnerWB;
	test(Device.TestWriteBackWriteAllocate(dC)==KErrNone);
	if (dC.iSize<KWriteBackTestSizeSize)test.Printf(_L("Inner\tWBWA\tWriteAlloc\t%xH\t%xH\tOK\n"), KWriteBackTestSizeSize, dC.iSize);
	else								test.Printf(_L("Inner\tWBWA\tWriteAlloc\t%xH\t%xH\tWarning: Didn't pass\n"), KWriteBackTestSizeSize, dC.iSize);
	
	if(!CacheInfo.iOuterCache) return;
		
	dC.iSize = KWriteBackTestSizeSize;
	if(CacheInfo.iMemoryRemapping)	dC.iCacheAttr = RCacheTestDevice::E_OuterWBRA_Remapped;
	else							dC.iCacheAttr = RCacheTestDevice::E_OuterWBRA;
	test(Device.TestWriteBackReadAllocate(dC)==KErrNone);
	if (dC.iSize<KWriteBackTestSizeSize)test.Printf(_L("Outer\tWBRA\tReadAlloc\t%xH\t%xH\tOK\n"), KWriteBackTestSizeSize, dC.iSize);
	else								test.Printf(_L("Outer\tWBRA\tReadAlloc\t%xH\t%xH\tWarning: Didn't pass\n"), KWriteBackTestSizeSize, dC.iSize);
//
	dC.iSize = KWriteBackTestSizeSize;
	if(CacheInfo.iMemoryRemapping)	dC.iCacheAttr = RCacheTestDevice::E_OuterWB_Remapped;
	else							dC.iCacheAttr = RCacheTestDevice::E_OuterWB;
	test(Device.TestWriteBackReadAllocate(dC)==KErrNone);
	if (dC.iSize<KWriteBackTestSizeSize)test.Printf(_L("Outer\tWBWA\tReadAlloc\t%xH\t%xH\tOK\n"), KWriteBackTestSizeSize, dC.iSize);
	else								test.Printf(_L("Outer\tWBWA\tReadAlloc\t%xH\t%xH\tWarning: Didn't pass\n"), KWriteBackTestSizeSize, dC.iSize);
//
	dC.iSize = KWriteBackTestSizeSize;
	if(CacheInfo.iMemoryRemapping)	dC.iCacheAttr = RCacheTestDevice::E_OuterWB_Remapped;
	else							dC.iCacheAttr = RCacheTestDevice::E_OuterWB;
	test(Device.TestWriteBackWriteAllocate(dC)==KErrNone);
	if (dC.iSize<KWriteBackTestSizeSize)test.Printf(_L("Outer\tWBWA\tWriteAlloc\t%xH\t%xH\tOK\n"), KWriteBackTestSizeSize, dC.iSize);
	else								test.Printf(_L("Outer\tWBWA\tWriteAlloc\t%xH\t%xH\tWarning: Didn't pass\n"), KWriteBackTestSizeSize, dC.iSize);
	}



//---------------------------------------------
//! @SYMTestCaseID 			MMU-T_CACHE-07
//! @SYMTestType 			UT
//! @SYMPREQ 				PREQ305
//! @SYMREQ 				REQ5795
//! @SYMTestCaseDesc 		Tests Cache Maintanence Functions.
//! @SYMTestActions 		Does not do any sort of functional test. Just makes sure nothing panics.
//! @SYMTestExpectedResults KErrNone 
//! @SYMTestPriority 		High
//! @SYMTestStatus 			Implemented
//---------------------------------------------
void Test7()
	{
	test(KErrNone== Device.TestL2Maintenance());
	}

// The main function of automatic test.
void AutoTestL()
	{
	test.Start(_L("Test1: Display cache attributes:"));
	test.Printf(_L("Starting Driver...\n"));
	StartDriver();	
	test.Printf(_L("Getting CacheInfo...\n"));
	GetCacheInfo();
	Test1();

	test.Next(_L("Test2:Thresholds (hex)..."));
	Test2();

	test.Next(_L("Test3:Setting Cache Thresholds..."));
	Test3();

	test.Next(_L("Test4: Data chunk test..."));
	test.Printf(_L("chunk size=%xH \n"),KDefaultDataSize);
	Test4(KDefaultDataSize);

	test.Next(_L("Test5: Code chunk test..."));
	test.Printf(_L("chunk size=%xH \n"),KDefaultCodeSize);
	Test5(KDefaultCodeSize);

	test.Next(_L("Test6: Testing WriteBack cache mode..."));
	Test6(); 

	test.Next(_L("Test7: Testing L2 cache maintenance..."));
	Test7();

	StopDriver();	
	test.End();
	}

//////////////////////Manual tests start here///////////////////////////////

// Gets the size of the chunk from the command line
TInt GetSizeFromCommandLine(TBuf<64>& command)
	{
	TUint arg;
	TInt length = command.Length()-5;
	if (length <=0)
		return KErrArgument;
	TPtrC ptr = command.Mid(5,length);
	TLex lex(ptr);
	lex.Val(arg, EHex);
	return arg;
	}

/** Invoked by "t_cache info"*/
void ManualCacheInfo()
	{
	
	test.Start(_L("Cache Info:"));
	StartDriver();	
	GetCacheInfo();
	Test1();
	test.Printf(_L("Press any key...\n"));
	test.Getch();
	StopDriver();
	test.End();		
	return;
	}

/** Invoked by "t_cache code threshold [<C> <P> <C> <F>]"*/
TInt ManualThresholds(TBuf<64>& command)
	{
	TUint arg[4];
	TInt argCurrent=0;
	TInt argStart = 9; //jump over "threshold"
	TInt argEnd;
	TChar c;

	test.Start(_L("Thresholds:"));
	StartDriver();	
	GetCacheInfo();


	// Decode input arguments from the command line
	while (argCurrent<4)
		{
		find_arg_start:
		if (argStart >= command.Length()) break;
		c = command[argStart];
		if (c.IsSpace())
			{
			argStart++;
			goto find_arg_start;
			}
		
		argEnd = argStart+1;
		find_arg_end:
		if (argEnd >= command.Length()) goto get_arg;
		c = command[argEnd];
		if (c.IsSpace()) goto get_arg;
		argEnd++;
		goto find_arg_end;

		get_arg:
		TPtrC ptr = command.Mid(argStart,argEnd-argStart);
		TLex lex(ptr);
		lex.Val(arg[argCurrent++], EHex);
		argStart=argEnd;
		}

	test.Printf(_L("%d argument(s) decoded\n"),argCurrent);
	
	RCacheTestDevice::TThresholdInfo info;

	//If te values are provided in the command line, set thresholds with the given paramaters.
	if (argCurrent == 4)
		{
		test.Printf(_L("Setting thresholds: ...\n"));
		test.Printf(_L("Cache Type:%xh P:%xh C:%xh F:%xh\n"),arg[0], arg[1], arg[2], arg[3]);
		info.iCacheType=arg[0];
		info.iPurge = arg[1];
		info.iClean = arg[2];
		info.iFlush = arg[3];
		TInt r = Device.SetThreshold(info);
		test.Printf(_L("... returned %d\n"),r);
		}

	//Read thresholds from Kernel.
	test.Printf(_L("Reading thresholds(hex)...\n"));
	Test2();

	test.Printf(_L("Press any key...\n"));
	test.Getch();
	StopDriver();
	test.End();		
	return 0;
	}


/** Invoked by "t_cache data <size>"*/
void ManualDataTest(TInt aSize)
	{
	StartDriver();	
	GetCacheInfo();

	Test4(aSize);

	test.Printf(_L("Press any key...\n"));
	test.Getch();
	StopDriver();	
	test.End();
	}

/** Invoked by "t_cache code <size>"*/
void ManualCodeTest(TInt aSize)
	{
	StartDriver();	
	GetCacheInfo();

	Test5(aSize);

	test.Printf(_L("Press any key...\n"));
	test.Getch();
	StopDriver();	
	test.End();
	}

void DoUseCase(TInt aUseCase, TInt aMaxSize, TInt aLoops )
	{
	RCacheTestDevice::TChunkTest dC(aUseCase, 0x1000, aLoops);
	
	TInt time[5];

	test.Printf(_L("size(H)\tloops\tNormal/NC\tNormal/WT\tFullyCached\n"));
	test.Printf(_L("-------\t-----\t---------\t---------\t-----------\n"));

	while (dC.iSize<=aMaxSize)
		{
		dC.iCacheAttr = RCacheTestDevice::E_Normal_Cached;
		test(Device.TestUseCase(dC)==KErrNone);
		time[2]=dC.iTime;

		if(time[2] < 20)
			{dC.iLoops *=2;	continue;} //Time too short. Double the loops and try the same chunk size.

		dC.iCacheAttr = RCacheTestDevice::E_Normal_Uncached;
		test(Device.TestUseCase(dC)==KErrNone);
		time[0]=dC.iTime;

		if(CacheInfo.iMemoryRemapping)	dC.iCacheAttr = RCacheTestDevice::E_InOutWT_Remapped;
		else							dC.iCacheAttr = RCacheTestDevice::E_InOutWT;
		test(Device.TestUseCase(dC)==KErrNone);
		time[1]=dC.iTime;


		test.Printf(_L("%6xH\t%5d\t%9d\t%9d\t%11d\n"),dC.iSize,dC.iLoops,time[0],time[1],time[2]);

		if ((time[2] > 100) && (dC.iLoops >= 8))
			dC.iLoops /=2; //Time too long. Half the loops.

		dC.iSize+=0x1000; // Next chunk size.
		}
	}		

/** Invoked by "t_cache usecase"*/
void ManualUseCase()
	{
	test.Start(_L("Use Case manual tests"));
	StartDriver();	
	GetCacheInfo();

	test.Printf(_L("\nUseCase: Read From Chunk\n"));
	DoUseCase(0,Min(CacheInfo.iMaxCacheSize*4, 0x40000),32);
	
	test.Printf(_L("\nUseCase: Read From Chunk & Read From Heap\n"));
	DoUseCase(1,Min(CacheInfo.iMaxCacheSize*4, 0x40000),32);

	test.Printf(_L("\nUseCase: Write To Chunk\n"));
	DoUseCase(2,Min(CacheInfo.iMaxCacheSize*4, 0x40000),32);
	
	test.Printf(_L("\nUseCase: Write To Chunk & Read From Heap\n"));
	DoUseCase(3,Min(CacheInfo.iMaxCacheSize*4, 0x40000),32);


	test.Printf(_L("Press any key...\n"));
	test.Getch();
	StopDriver();	
	test.End();
	}


// Invoked by "t_cache data+<size_hex>"
void ManualDataTestIncremental(TInt aIncrement)
	{
	TInt time[4];
	TInt r = KErrNone;
	TInt size = aIncrement;
	RCacheTestDevice::TChunkTest dC;

	StartDriver();	
	GetCacheInfo();

	test.Printf(_L("Chunk\t\tTime(KernelTicks):\n"));
	test.Printf(_L("Size(KB)\tUnCached\tInner\tOuter\tIn&Out\n"));

	while(size < KMaxChunkSize)
		{
		dC.iSize = size;

		dC.iCacheAttr = RCacheTestDevice::E_Buffered_C;
		r = Device.TestDataChunk(dC);
		if (r!=KErrNone) break;
		time[0] = dC.iTime;

		if(CacheInfo.iMemoryRemapping)	dC.iCacheAttr = RCacheTestDevice::E_InnerWB_Remapped;
		else							dC.iCacheAttr = RCacheTestDevice::E_InnerWB;
		r = Device.TestDataChunk(dC);
		if (r!=KErrNone) break;
		time[1] = dC.iTime;

		if(CacheInfo.iOuterCache)
			{
			if(CacheInfo.iMemoryRemapping)	dC.iCacheAttr = RCacheTestDevice::E_OuterWB_Remapped;
			else							dC.iCacheAttr = RCacheTestDevice::E_OuterWB;
			r = Device.TestDataChunk(dC);
			if (r!=KErrNone) break;
			time[2] = dC.iTime;

			dC.iCacheAttr = RCacheTestDevice::E_InOutWB;
			r = Device.TestDataChunk(dC);
			if (r!=KErrNone) break;
			time[3] = dC.iTime;
			}
		else 
			{
			time[2]= time[3]=0;
			}
		test.Printf(_L("%d\t%d\t%d\t%d\t%d\n"),size/0x400, time[0],time[1],time[2],time[3]);
		size += aIncrement;
		}

	test.Printf(_L("The test exited with %d\n"), r);
	test.Printf(_L("Press any key...\n"));
	test.Getch();
	StopDriver();	
	test.End();
	}

// Invoked by "t_cache code+<size_hex>"
void ManualCodeTestIncremental(TInt aIncrement)
	{
	TInt time[4];
	TInt r = KErrNone;
	TInt size = aIncrement;
	RCacheTestDevice::TChunkTest dC;

	StartDriver();	
	GetCacheInfo();

	test.Printf(_L("Chunk\t\tTime(KernelTicks):\n"));
	test.Printf(_L("Size(KB)\tUnCached\tInner\tOuter\tIn&Out\n"));

	while(size < KMaxChunkSize)
		{
		TempBuff.SetLength(0);

		dC.iSize = size;

		dC.iCacheAttr = RCacheTestDevice::E_Buffered_C;
		r = Device.TestCodeChunk(dC);
		if (r!=KErrNone) break;
		time[0] = dC.iTime;

		if(CacheInfo.iMemoryRemapping)	dC.iCacheAttr = RCacheTestDevice::E_InnerWB_Remapped;
		else							dC.iCacheAttr = RCacheTestDevice::E_InnerWB;
		r = Device.TestCodeChunk(dC);
		if (r!=KErrNone) break;
		time[1] = dC.iTime;

		if(CacheInfo.iOuterCache)
			{
			if(CacheInfo.iMemoryRemapping)	dC.iCacheAttr = RCacheTestDevice::E_OuterWB_Remapped;
			else							dC.iCacheAttr = RCacheTestDevice::E_OuterWB;
			r = Device.TestCodeChunk(dC);
			if (r!=KErrNone) break;
			time[2] = dC.iTime;
			//
			dC.iCacheAttr = RCacheTestDevice::E_InOutWB;
			r = Device.TestCodeChunk(dC);
			if (r!=KErrNone) break;
			time[3] = dC.iTime;
			}
		else
			{
			time[2]=time[3] = 0;
			}	

		test.Printf(_L("%d\t%d\t%d\t%d\t%d\n"),size/0x400, time[0],time[1],time[2],time[3]);
		size += aIncrement;
		}

	test.Printf(_L("The test exited with %d\n"), r);
	test.Printf(_L("Press any key...\n"));
	test.Getch();
	StopDriver();	
	test.End();
	}

TInt E32Main()
	{

	TBuf<64> c;
	TInt size;
	User::CommandLine(c);
	if (c.FindF(KPrintCacheInfos) >= 0) {ManualCacheInfo();		return 0;}
	if (c.FindF(KUseCase) >= 0)			{ManualUseCase();		return 0;}
	if (c.FindF(KThreshold) >= 0)		{ManualThresholds(c);	return 0;}

	if (c.FindF(KTestData) >= 0)
		{
		test.Start(_L("Data Chunk"));
		size = GetSizeFromCommandLine(c);
		// Always round up the size to 1K boundary (because of DataSegmetTestFunct)
		size +=0x3ff; size &=~0x3ff;
		
		if (c.FindF(KIncremental) >= 0)
			{
			// Invoked by "t_cache data+<size>"
			test.Printf(_L(" size + %xH\n"),size);
			if (size<=0)
					return KErrArgument;
			ManualDataTestIncremental(size);	
			}
		else
			{
			// Invoked by "t_cache data <size>"
			test.Printf(_L("chunk size %xH\n"),size);
			if (size<=0)
					return KErrArgument;
			ManualDataTest(size);	
			}
		return 0;
		}

	if (c.FindF(KTestCode) >= 0)
		{
		test.Start(_L("Code Chunk"));
		size = GetSizeFromCommandLine(c);
		// Always round up the size to 1K boundary
		size +=0x3ff; size &=~0x3ff;
		if (c.FindF(KIncremental) >= 0)
			{
			// Invoked by "t_cache code+<size>"
			test.Printf(_L(" size + %xH\n"),size);
			if (size<=0)
					return KErrArgument;
			ManualCodeTestIncremental(size);	
			}
		else
			{
			// Invoked by "t_cache code <size>"
			test.Printf(_L("chunk size %xH\n"),size);
			if (size<=0)
					return KErrArgument;
			ManualCodeTest(size);	
			}
		return 0;
		}

	if (c.FindF(KHelp) >= 0)
		{
		// Invoked by "t_cache help"
		test.Start(_L("t_cache usage:\n"));
		test.Printf(_L("t_cache info\n"));
		test.Printf(_L("t_cache data <size_hex>\n"));
		test.Printf(_L("t_cache code <size_hex>\n"));
		test.Printf(_L("t_cache data+<size_hex>\n"));
		test.Printf(_L("t_cache code+<size_hex>\n"));
		test.Printf(_L("t_cache usecase\n\n"));
		test.Printf(_L("t_cache threshold [<cache> <purge> <clean> <flush>]\n\n"));
		test.Printf(_L("... where <cache>= 1,2,4,8 or 10\n\n"));
		test.Printf(_L("Press any key...\n"));
		test.Getch();
		test.End();
		return 0;
		}

	
	// auto test starts here
	CTrapCleanup* trap = CTrapCleanup::New();
	if (!trap)
		return KErrNoMemory;
	test.Title();
	__UHEAP_MARK;
	TRAPD(r,AutoTestL());
	__UHEAP_MARKEND;
	delete trap;
	return r;
	}