C++ function pointer in class, func need data in class

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
synthetix
Posts: 15
Joined: Sun Jan 28, 2007 8:45 am
Location: Somewhere in the infinite dimension universe that my vast imagination is.

C++ function pointer in class, func need data in class

Post by synthetix »

Hello, I'm (re)starting an OS project done in C++ from ground up.
The system is divided in 3 layers (by the way, I don't even know the kernel type of my system):

SystemLib: Upper-level system (VFS, power ,network, etc.) not done
CoreKernel: Architecture independent but close to hardware part (Task scheduling, IRQ upper-level management, memory management) not done
SysCore: Low-level part which plays with hardware (IDT,GDT) partial

SysCore itself is portable because of the way it is designed. It is a generic framework which uses (and needs) system handlers. These contain the code to initialize the system (x86 ex: Setup IDT,GDT, Remap IRQ,), and the code to access system vital hardware (MMU, PIC, basic IO mechanism). The system is also designed to be multiprocessing (not necessarily symmetric, but that's something I'm gonna do after).

Here is the definition of a Core (CPU, MMU, PIC, IO):
(If you find syntax errors, please say me, it is my first C++ big coding experience (appart hello world)).

Code: Select all


/* SysCore Core[] interface */

namespace SysCore {
		
	enum CPUInfoIndex_l {
		SpeedMHz = 0,
		SpeedMIPS,
		CPUID
	};
	
	enum Architecture_l {
		X86 = 0,
		PowerPC,
		ARM,
	};

	class CPUInfo_c {
		public:
			Architecture_l GetCPUArch();
			unsigned long GetCPUInfo(CPUInfoIndex_l CPUInfoNum);
		
			
		private:	
			Architecture_l CPUArch;
			unsigned int CPUSpeedMHz;
			unsigned int CPUSpeedMIPS;
	
			unsigned long CPU_CPUID;
	 
	};

	class CPU_c {
		public:
			SC_CPUInfo_c 	Info;
	
			void Jump(void (*Address2JumpTo));
			unsigned long (*GetRegister)(unsigned char Register);
			bool (*SetRegister)(unsigned char Register, unsigned long Value);
			bool (*GetFlag)(unsigned char FlagBit);
			bool (*SetFlag)(unsigned char FlagBit, bool FlagStatus);
	};

	class Interrupts_c {
		public:
			bool (*RegisterInt)(unsigned char IntNum, unsigned long CodeAddress, bool SupervisorMode);
			bool (*UnregisterInt)(unsigned char IntNum);
			
		
		private: 
			bool (*IntsSetStatus)(bool Active);
			bool *InterruptsRouteTable[16] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
			

	class MMU_c {
		public:
			bool MapLinear(void *RealBase, void *MapBase, unsigned long MapLenght, unsigned long *PageDir);
			bool (*MapPage)(unsigned long RealPageNum, unsigned VirtMapAddress);
			unsigned long FindFreePages(unsigned long PageNum);
			unsigned long FindFreePage();
	}	
	
	class Core_c {
		public:
			Core_c(unsigned long (*CPUGetRegister)(unsigned char Register), bool (*CPUSetRegister)(unsigned char Register, unsigned long Value), bool (*CPUGetFlag)(unsigned char FlagBit), bool (*CPUSetFlag)(unsigned char FlagBit, bool FlagStatus), bool (*MMUHMapPage)(unsigned long RealPageNum, unsigned VirtMapAddress), bool (*IntsSetStatus)(bool Active), bool (*SystemInitializer));
			CPU_c 	CPU;
			MMU_c 	*MMU;
			IO_c		GIOSys;
			Interrupts_c	*ISR;
	};

}
In Interrupts_c, InterruptsRouteTable needs to be accessed from the external handler. How can I do this, as the external handler's code is not in the class ?

I thank anybody to answer this question.
User avatar
mystran
Member
Member
Posts: 670
Joined: Thu Mar 08, 2007 11:08 am

Post by mystran »

You add the relevant accessors to class, and then call the accessors from your external handler? Or you move the relevant part of the external handler into the class?

Or if you really-really-really don't want to do either of the above, you could make the external handler a "friend" of the class.
The real problem with goto is not with the control transfer, but with environments. Properly tail-recursive closures get both right.
User avatar
os64dev
Member
Member
Posts: 553
Joined: Sat Jan 27, 2007 3:21 pm
Location: Best, Netherlands

Post by os64dev »

May i ask why do you declare all thos functions with a pointer?

for instance:

bool (*GetFlag)(unsigned char FlagBit);

is that because you wish to have an alternate implementation for them? Normally you would use function overloading for that.

Code: Select all

class CPU_c {
virtual bool GetFlag(unsigned char FlagBit) = 0;
}

class CPU_c_PowerPC : public CPU_c {
    bool GetFlag(unsigned char FlagBit) {
    //powerpc flags stuff.
   }
}
Author of COBOS
synthetix
Posts: 15
Joined: Sun Jan 28, 2007 8:45 am
Location: Somewhere in the infinite dimension universe that my vast imagination is.

External files supported

Post by synthetix »

os64dev, I have a question. With your method, could I put PowerPC stuff (example) in another file, even if using inheritance ? Cause, if yes, you're saving me MUCH trouble.

My original method was to have an external handler, implemented in another file, which would set Core function pointers to his functions not in a class, by calling a (very long ...) Core class constructor.

Example: My almost uncompleted X86 handler

Code: Select all

/* SC_CoreX86

Handlers and helper fonctions used to access registers, flags, and etc. on X86 

*/
	
unsigned long SC_CPUx86_GetRegister(CPUX86Registers Register) {
	switch (Register) {
		case EAX:
			return SC_CPUx86_GetEAX();
			break;
		case AX:
			return (SC_CPUx86_GetEAX() & 0x0000FFFF);
			break;
		case AH:
			return ((SC_CPUx86_GetEAX() & 0x000000FF) >> 8);
			break;
		case AL:
			return (SC_CPUx86_GetEAX() & 0x000000FF);
			break;
		case EBX:
			return SC_CPUx86_GetEBX();
			break;
		case BX:
			return (SC_CPUx86_GetEBX() & 0x0000FFFF);
			break;
		case BH:
			return ((SC_CPUx86_GetEBX() & 0x0000FFFF) >> 8);
			break;
		case BL:
			return (SC_CPUx86_GetEBX() & 0x000000FF);
			break;
		case ECX:
			return SC_CPUx86_GetECX();
			break;
		case CX:
			return (SC_CPUx86_GetECX() & 0x0000FFFF);
			break;
		case CH:
			return ((SC_CPUx86_GetECX() & 0x0000FFFF) >> 8);
			break;
		case CL:
			return (SC_CPUx86_GetECX() & 0x000000FF);
			break;
		case EDX:
			return SC_CPUx86_GetEAX();
			break;
		case DX:
			return (SC_CPUx86_GetEAX() & 0x0000FFFF);
			break;
		case DH:
			return ((SC_CPUx86_GetEAX() & 0x0000FFFF) >> 8);
			break;
		case DL:
			return (SC_CPUx86_GetEAX() & 0x000000FF);
			break;
		case ESS:
			return SC_CPUx86_GetESS();
			break;
		case EDS:
			return SC_CPUx86_GetEDS();
			break;
		case EFS:
			return SC_CPUx86_GetEFS();
			break;
		case EGS:
			return SC_CPUx86_GetEGS();
			break;
		case EES:
			return SC_CPUx86_GetEES();
			break;
		case ECS:
			return SC_CPUx86_GetECS();
			break;
		case ESI:
			return SC_CPUx86_GetESI();
			break;
		case EDI:
			return SC_CPUx86_GetEDI();
			break;
		case EBP:
			return SC_CPUx86_GetEBP();
			break;
		case EIP:
			return SC_CPUx86_GetEIP();
			break;
		case ESP:
			return SC_CPUx86_GetESP();
			break;
		case CR0:
			return SC_CPUx86_GetCR0();
			break;
		case CR1:
			return SC_CPUx86_GetCR1();
			break;
		case CR2:
			return SC_CPUx86_GetCR2();
			break;
		case CR3:
			return SC_CPUx86_GetCR3();
			break;
		case CR4:
			return SC_CPUx86_GetCR4();
			break;
	}
}

unsigned long SC_CPUx86_SetRegister(unsigned long Register, unsigned long RegValue) {
	switch (Register) {
		case EAX:
			return SC_CPUx86_SetEAX(RegValue);
			break;
		case AX:
			return SC_CPUx86_SetEAX(SC_CPUx86_GetEAX | (RegValue & 0x0000FFFF));
			break;
		case AH:
			return SC_CPUx86_SetEAX(SC_CPUx86_GetEAX | ((RegValue & 0x000000FF) << 8));
			break;
		case AL:
			return SC_CPUx86_SetEAX(SC_CPUx86_GetEAX | (RegValue & 0x000000FF));
			break;
		case EBX:
			return SC_CPUx86_SetEBX(RegValue);
			break;
		case BX:
			return SC_CPUx86_SetEBX(SC_CPUx86_GetEBX | (RegValue & 0x0000FFFF));
			break;
		case BH:
			return SC_CPUx86_SetEBX(SC_CPUx86_GetEBX | ((RegValue & 0x000000FF) << 8));
			break;
		case BL:
			return SC_CPUx86_SetEBX(SC_CPUx86_GetEBX | (RegValue & 0x000000FF));
			break;
		case ECX:
			return SC_CPUx86_SetECX(RegValue);
			break;
		case CX:
			return SC_CPUx86_SetECX(SC_CPUx86_GetECX | (RegValue & 0x0000FFFF));
			break;
		case CH:
			return SC_CPUx86_SetECX(SC_CPUx86_GetECX | ((RegValue & 0x000000FF) << 8));
			break;
		case CL:
			return SC_CPUx86_SetECX(SC_CPUx86_GetECX | (RegValue & 0x000000FF));
			break;
		case EDX:
			return SC_CPUx86_SetEDX(RegValue);
			break;
		case DX:
			return SC_CPUx86_SetEDX(SC_CPUx86_GetEDX | (RegValue & 0x0000FFFF));
			break;
		case DH:
			return SC_CPUx86_SetEDX(SC_CPUx86_GetEDX | ((RegValue & 0x000000FF) << 8));
			break;
		case DL:
			return SC_CPUx86_SetEDX(SC_CPUx86_GetEDX | (RegValue & 0x000000FF));
			break;
		case ESS:
			return SC_CPUx86_SetESS(RegValue);
			break;
		case EDS:
			return SC_CPUx86_SetEDS(RegValue);
			break;
		case EFS:
			return SC_CPUx86_SetEFS(RegValue);
			break;
		case EGS:
			return SC_CPUx86_SetEGS(RegValue);
			break;
		case EES:
			return SC_CPUx86_SetEES(RegValue);
			break;
		case ECS:
			return SC_CPUx86_SetECS(RegValue);
			break;
		case ESI:
			return SC_CPUx86_SetESI(RegValue);
			break;
		case EDI:
			return SC_CPUx86_SetEDI(RegValue);
			break;
		case EBP:
			return SC_CPUx86_SetEBP(RegValue);
			break;
		case EIP:
			return SC_CPUx86_SetEIP(RegValue);
			break;
		case ESP:
			return SC_CPUx86_SetESP(RegValue);
			break;
		case CR0:
			return SC_CPUx86_SetCR0(RegValue);
			break;
		case CR1:
			return SC_CPUx86_SetCR1(RegValue);
			break;
		case CR2:
			return SC_CPUx86_SetCR2(RegValue);
			break;
		case CR3:
			return SC_CPUx86_SetCR3(RegValue);
			break;
		case CR4:
			return SC_CPUx86_SetCR4(RegValue);
			break;
	}
}

bool SC_CPUx86_GetFlag(unsigned char FlagBit) {
	if (((CPUX86GetFlags & MathPower(CPUX86GetFlags, FlagBit)) / MathPower(CPUX86GetFlags, FlagBit)) == 1) {
		return true;
	else {
		return false;
	}
}
}

bool SC_CPUx86_SetFlag(unsigned char FlagBit, bool FlagStatus) {
	unsigned long CPUFlags;
	
	if (GetFlag(FlagBit) == true) { // Flag already set
		if (FlagStatus == true) { // If true, return true
			return true;
		}
		else { // Else, we erase the flag
			CPUFlags ^= MathPower(2,FlagBit);
			SC_X86CPUSetFlags(CPUFlags);
		}
	else { // Flag not set
		
		if (FlagStatus == true) // If flag is to be set, set it
			CPUFlags = SC_CPUX86GetFlags() | MathPower(2,FlagBit);
			SC_X86CPUSetFlags(CPUFlags); // External ASM function
			return true;
		}
		else { // Flag not to be set
			return false;
		}
	}
}

unsigned long SystemOInit() // A not done function to initialize MMU,GDT,IDT and all that stuff
If your method applies to external files as well, then you're saving me a lot of troubles.
User avatar
B.E
Member
Member
Posts: 275
Joined: Sat Oct 21, 2006 5:29 pm
Location: Brisbane Australia
Contact:

Post by B.E »

Couldn't you just use pure virtual functions, i.e

Code: Select all

class BaseCpu {
public:
   virtual void SomeFunction(int SomeParms)= 0;
};
class X86Cpu : public BaseCpu {
public:   
   void SomeFunction(int SomeParms){
      //some code
   }
};
Image
Microsoft: "let everyone run after us. We'll just INNOV~1"
User avatar
os64dev
Member
Member
Posts: 553
Joined: Sat Jan 27, 2007 3:21 pm
Location: Best, Netherlands

Post by os64dev »

synthetix wrote:os64dev, I have a question. With your method, could I put PowerPC stuff (example) in another file, even if using inheritance ? Cause, if yes, you're saving me MUCH trouble.

My original method was to have an external handler, implemented in another file, which would set Core function pointers to his functions not in a class, by calling a (very long ...) Core class constructor.
Yes, implementation of a class can be in different files, you can even have a file for each function :wink: . Declaration of a single class has to be in single header file. so in the example you can put class CPUInfo_c in cpuinfo.hand put CPU_c_PowerPC in cpuinfo-ppc.h ofr instance. external handlers are so native C instead of C++. In C++ you should never need function pointers only inheritence.
B.E. wrote:Couldn't you just use pure virtual functions, i.e

Code: Select all

class BaseCpu { 
public: 
   virtual void SomeFunction(int SomeParms)= 0; 
}; 
class X86Cpu : public BaseCpu { 
public:    
   void SomeFunction(int SomeParms){ 
      //some code 
   } 
}; 
Thought is strictly isn't nessecary to use an abstract class, it does make sence to do it here. The abstract BaseCpu class containing the pure virtual function specify an interface that has to be implemented by each derived class thus forcing you to implement thing properly.
Author of COBOS
synthetix
Posts: 15
Joined: Sun Jan 28, 2007 8:45 am
Location: Somewhere in the infinite dimension universe that my vast imagination is.

Sorry, misunderstanding here

Post by synthetix »

os64dev, sorry, I meant, can I put this in another binary file (my OS goal is to be modular and extensible) ? Also, why I'm thinking of it, will I be able to include a CPU_PowerPC_c in CPU_c array ? This is because I will have a system global object which address is gonna be passed to the upper-level system (SysCore does not depend on CoreKernel or SystemLib, you could do an entirely new os over it). Here is the definition of the System global object.

Code: Select all

#include "SystemConfig.h"

namespace SysCore {
	
	class System_c {
		Core_c Core[4]; // Number is to be adjusted dynamically in the future; This is the array I was speaking about, can I put a CPU_PowerPC_c here ?
		unsigned long MainCore; // Number of the main core
		void ShMem_MainCoreBaseAddress; // For future use
		unsigned char UpperSystemName[32];
		unsigned char UpperSystemVersion[8];
		
		unsigned char GetSysCoreVersion();
		unsigned char GetUpperSystemName();
		unsigned char SetUpperSystemName();
		);
		
	};
	
}
Post Reply