root/headers/private/kernel/arch/m68k/arch_cpu.h
/*
** Copyright 2003-2004, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
** Distributed under the terms of the MIT License.
*/
#ifndef _KERNEL_ARCH_M68K_CPU_H
#define _KERNEL_ARCH_M68K_CPU_H

#ifndef _ASSEMBLER

#include <arch/m68k/arch_thread_types.h>
#include <kernel.h>

#endif  // !_ASSEMBLER


#define CPU_MAX_CACHE_LEVEL     8

#define CACHE_LINE_SIZE         16


#define arch_cpu_enable_user_access()
#define arch_cpu_disable_user_access()


#define SR_IP_MASK 0x0700
#define SR_S 0x2000
#define M68K_SR_S 13
#define M68K_SR_T_MASK 0xC000
#define M68K_SR_T0 14
#define M68K_SR_T1 15

#ifndef _ASSEMBLER

/* 68k has many different possible stack frames, differentiated by a 4 bit number,
 * but they also depend on the cpu type.
 * cf. mint/sys/arch/check_exc.h
 */

/* definitions for special status word */

// 020 as well
struct mc68030_ssw {
        uint16 fc:1;
        uint16 fb:1;
        uint16 rc:1;
        uint16 rb:1;
        uint16 :3;
        uint16 df:1;
        uint16 rm:1;
        uint16 rw:1;
        uint16 size:2;
        uint16 :1;
        uint16 as:3;
} _PACKED;

struct mc68040_ssw {
        uint16 cp:1;
        uint16 cu:1;
        uint16 ct:1;
        uint16 cm:1;
        uint16 ma:1;
        uint16 atc:1;
        uint16 lk:1;
        uint16 rw:1;
        uint16 :1;
        uint16 size:2;
        uint16 tt:2;
        uint16 tm:3;
} _PACKED;

struct mc68060_fslw {
        uint32 :4;
        uint32 ma:1;
        uint32 :1;
        uint32 lk:1;
        uint32 rw:2; //XXX ??
        uint32 size:2;
        uint32 tt:2;
        uint32 tm:2;
        uint32 io:1;
        uint32 pbe:1;
        uint32 sbe:1;
        uint32 pta:1;
        uint32 ptb:1;
        uint32 il:1;
        uint32 pf:1;
        uint32 sb:1;
        uint32 wp:1;
        uint32 twe:1;
        uint32 re:1;
        uint32 we:1;
        uint32 ttr:1;
        uint32 bpe:1;
        uint32 :1;
        uint32 see:1;
} _PACKED;

/* raw exception frames */

struct mc680x0_type_0_frame {
        uint16 sr;
        addr_t pc;
        uint16 type:4;
        uint16 vector:12;
};

struct mc680x0_type_1_frame {
        uint16 sr;
        addr_t pc;
        uint16 type:4;
        uint16 vector:12;
};

struct mc680x0_type_2_frame {
        uint16 sr;
        addr_t pc;
        uint16 type:4;
        uint16 vector:12;
        addr_t instruction_address;
};

struct mc680x0_type_3_frame {
        uint16 sr;
        addr_t pc;
        uint16 type:4;
        uint16 vector:12;
        addr_t effective_address;
};

struct mc68040_type_7_frame {
        uint16 sr;
        addr_t pc;
        uint16 type:4;
        uint16 vector:12;
        addr_t effective_address;
        struct mc68040_ssw ssw;
        // write-back status
        uint16 wb3s;
        uint16 wb2s;
        uint16 wb1s;
        addr_t fault_address;
        addr_t wb3a;
        uint32 wb3d;
        addr_t wb2a;
        uint32 wb2d;
        addr_t wb1a;
        uint32 wb1d; // also pd0
        uint32 pd1;
        uint32 pd2;
        uint32 pd3;
};

struct mc680x0_type_9_frame {
        uint16 sr;
        addr_t pc;
        uint16 type:4;
        uint16 vector:12;
        addr_t instruction_address;
        uint16 intregs[4];
};

struct mc68030_type_a_frame {
        uint16 sr;
        addr_t pc;
        uint16 type:4;
        uint16 vector:12;
        uint16 intreg1;
        struct mc68030_ssw ssw;
        uint16 instpipe_c;
        uint16 instpipe_b;
        addr_t fault_address;
        uint16 intregs2[2];
        uint32 dataout;
        uint16 intregs3[2];
};

struct mc68030_type_b_frame {
        uint16 sr;
        addr_t pc;
        uint16 type:4;
        uint16 vector:12;
        uint16 intreg1;
        struct mc68030_ssw ssw;
        uint16 instpipe_c;
        uint16 instpipe_b;
        addr_t fault_address;
        uint16 intregs2[2];
        uint32 dataout;
        uint16 intregs3[4];
        uint32 stbaddr;
        uint16 intregs4[2];
        uint32 datain;
        uint16 intregs5[3];
        uint16 intinfo;
        uint16 intregs6[18];
};

//XXX: add 060 frames

struct mc680x0_frame {
        union {
                struct {
                        uint16 sr;
                        addr_t pc;
                        uint16 type:4;
                        uint16 vector:12;
                };
                struct mc680x0_type_0_frame type_0;
                struct mc680x0_type_1_frame type_1;
                struct mc680x0_type_3_frame type_3;
                struct mc680x0_type_2_frame type_2;
                struct mc68040_type_7_frame type_7;
                struct mc680x0_type_9_frame type_9;
                struct mc68030_type_a_frame type_a;
                struct mc68030_type_b_frame type_b;
                // XXX: add 060 frames
        };
};

struct mc680x0_null_fpu_state {
        uint8 version; // 0
        uint8 type; // undefined
        uint16 dummy;
};

struct mc680x0_type_00_fpu_state {
        uint8 version;
        uint8 type; // 0
        uint16 dummy;
};

struct mc680x0_type_28_fpu_state {
        uint8 version;
        uint8 type; // 0x28
        uint16 dummy;
        // XXX: replace dummies
        uint32 dummies[0x28/4];
};

struct mc680x0_type_60_fpu_state {
        uint8 version;
        uint8 type; // 0x60
        uint16 dummy;
        // XXX: replace dummies
        uint32 dummies[0x60/4];
};

//XXX: those are 040, add others
// biggest known:
struct mc68882_type_d4_fpu_state {
        uint8 version;
        uint8 type; // 0xd4
        uint16 dummy;
        // XXX: replace dummies
        uint32 dummies[0xd4/4];
};

struct mc680x0_fpu_state {
        union {
                struct {
                        uint8 version;
                        uint8 type; // 0x60
                        uint16 dummy;
                };
                struct mc680x0_null_fpu_state null;
                struct mc680x0_type_00_fpu_state type_00;
                struct mc680x0_type_28_fpu_state type_28;
                struct mc680x0_type_60_fpu_state type_60;
                struct mc68882_type_d4_fpu_state type_d4;
        };
};

// 96-bit format
struct mc680x0_fp_data_reg {
        uint8 data[12];
};

struct mc680x0_fp_control_regs {
        uint32 fpcr;
        uint32 fpsr;
        uint32 fpiar;
};



#warning M68K: check for missing regs/movem
struct iframe {
        /* fpu data registers */
#warning M68K: sizeof(fp*)
        struct mc680x0_fp_data_reg fp[8];
        /* fpu control registers */
        struct mc680x0_fp_control_regs fpc;
        /* fpu state */
        struct mc680x0_fpu_state fpu;

        /* data and address registers */
        uint32 d[8];
        uint32 a[7];
        /* cpu exception frame, including sr, pc, format and vector */
        struct mc680x0_frame cpu;

/*      uint32 vector;
        uint32 srr0;
        uint32 srr1;
        uint32 dar;
        uint32 dsisr;
        uint32 lr;
        uint32 cr;
        uint32 xer;
        uint32 ctr;
        uint32 fpscr;
        uint32 r31;
        uint32 r30;
        uint32 r29;
        uint32 r28;
        uint32 r27;
        uint32 r26;
        uint32 r25;
        uint32 r24;
        uint32 r23;
        uint32 r22;
        uint32 r21;
        uint32 r20;
        uint32 r19;
        uint32 r18;
        uint32 r17;
        uint32 r16;
        uint32 r15;
        uint32 r14;
        uint32 r13;
        uint32 r12;
        uint32 r11;
        uint32 r10;
        uint32 r9;
        uint32 r8;
        uint32 r7;
        uint32 r6;
        uint32 r5;
        uint32 r4;
        uint32 r3;
        uint32 r2;
        uint32 r1;
        uint32 r0;
        double f31;
        double f30;
        double f29;
        double f28;
        double f27;
        double f26;
        double f25;
        double f24;
        double f23;
        double f22;
        double f21;
        double f20;
        double f19;
        double f18;
        double f17;
        double f16;
        double f15;
        double f14;
        double f13;
        double f12;
        double f11;
        double f10;
        double f9;
        double f8;
        double f7;
        double f6;
        double f5;
        double f4;
        double f3;
        double f2;
        double f1;
        double f0;*/
} _PACKED;

#if 0 /* ppc */
enum machine_state {
        MSR_EXCEPTIONS_ENABLED                  = 1L << 15,             // EE
        MSR_PRIVILEGE_LEVEL                             = 1L << 14,             // PR
        MSR_FP_AVAILABLE                                = 1L << 13,             // FP
        MSR_MACHINE_CHECK_ENABLED               = 1L << 12,             // ME
        MSR_EXCEPTION_PREFIX                    = 1L << 6,              // IP
        MSR_INST_ADDRESS_TRANSLATION    = 1L << 5,              // IR
        MSR_DATA_ADDRESS_TRANSLATION    = 1L << 4,              // DR
};

//struct block_address_translation;
#endif

typedef struct arch_cpu_info {
        int null;
} arch_cpu_info;


#ifdef __cplusplus
extern "C" {
#endif

#if 0
//PPC stuff
extern uint32 get_sdr1(void);
extern void set_sdr1(uint32 value);
extern uint32 get_sr(void *virtualAddress);
extern void set_sr(void *virtualAddress, uint32 value);
extern uint32 get_msr(void);
extern uint32 set_msr(uint32 value);
extern uint32 get_pvr(void);

extern void set_ibat0(struct block_address_translation *bat);
extern void set_ibat1(struct block_address_translation *bat);
extern void set_ibat2(struct block_address_translation *bat);
extern void set_ibat3(struct block_address_translation *bat);
extern void set_dbat0(struct block_address_translation *bat);
extern void set_dbat1(struct block_address_translation *bat);
extern void set_dbat2(struct block_address_translation *bat);
extern void set_dbat3(struct block_address_translation *bat);

extern void get_ibat0(struct block_address_translation *bat);
extern void get_ibat1(struct block_address_translation *bat);
extern void get_ibat2(struct block_address_translation *bat);
extern void get_ibat3(struct block_address_translation *bat);
extern void get_dbat0(struct block_address_translation *bat);
extern void get_dbat1(struct block_address_translation *bat);
extern void get_dbat2(struct block_address_translation *bat);
extern void get_dbat3(struct block_address_translation *bat);

extern void reset_ibats(void);
extern void reset_dbats(void);
#endif

//extern void sethid0(unsigned int val);
//extern unsigned int getl2cr(void);
//extern void setl2cr(unsigned int val);
extern long long get_time_base(void);

void __m68k_setup_system_time(vint32 *cvFactor);
        // defined in libroot: os/arch/system_time.c
int64 __m68k_get_time_base(void);
        // defined in libroot: os/arch/system_time_asm.S

extern void m68k_context_switch(void **_oldStackPointer, void *newStackPointer);

extern bool m68k_set_fault_handler(addr_t *handlerLocation, addr_t handler)
        __attribute__((noinline));

extern bool m68k_is_hw_register_readable(addr_t address);
extern bool m68k_is_hw_register_writable(addr_t address, uint16 value);
        // defined in kernel: arch/m68k/cpu_asm.S


static inline void
arch_cpu_idle(void)
{
        // TODO: M68K CPU idle call
        // there isn't really any insn for this. Maybe NOP/FNOP?
        // TODO: make a 060 module using LPSTOP
        //asm volatile ("lpstop");
}


static inline void
arch_cpu_pause(void)
{
        // TODO: M68K STOP call
        // the problem is STOP wants an immediate to put into SR
        // but we don't want to overwrite it.
        //asm volatile("stop #0" : : : "memory");
}

#ifdef __cplusplus
}
#endif

struct m68k_cpu_ops {
        void (*flush_insn_pipeline)(void);
        void (*flush_atc_all)(void);
        void (*flush_atc_user)(void);
        void (*flush_atc_addr)(addr_t addr);
        void (*flush_dcache)(addr_t address, size_t len);
        void (*flush_icache)(addr_t address, size_t len);
        void (*idle)(void);
};

extern struct m68k_cpu_ops cpu_ops;

//#define

#if 0
#define eieio() asm volatile("eieio")
#define isync() asm volatile("isync")
#define tlbsync() asm volatile("tlbsync")
#define ppc_sync() asm volatile("sync")
#define tlbia() asm volatile("tlbia")
#define tlbie(addr) asm volatile("tlbie %0" :: "r" (addr))
#endif

#if 0

// XXX: not used: we just use decimal chip number, like 68030

// m68k processor version.
enum m68k_processor_version {
        /* those two we don't support */
        CPU_68000               = 0x0000,
        CPU_68010               = 0x0001,
        /* maybe with a pmmu and fpu */
        CPU_68020               = 0x0002,
        /* should work */
        CPU_68030               = 0x0003,
        CPU_68040               = 0x0004,
        CPU_68060               = 0x0006,
        /* mask */
        CPU_MASK                = 0x000F
};

enum m68k_fpu_version {
        /* we don't support */
        FPU_NONE                = 0x0000,
        FPU_68881               = 0x0010,
        FPU_68882               = 0x0020,
        FPU_030                 = 0x0030,
        FPU_040                 = 0x0040,
        FPU_060                 = 0x0060,
        FPU_MASK                = 0x00F0
};

enum m68k_mmu_version {
        MMU_NONE                = 0x0000,
        MMU_68551               = 0x0100,
        MMU_68030               = 0x0300,
        MMU_68040               = 0x0400,
        MMU_68060               = 0x0600,
        MMU_MASK                = 0x0F00
};
#endif

extern int arch_cpu_type;
extern int arch_fpu_type;
extern int arch_mmu_type;
extern int arch_platform;
extern int arch_machine;

/*
        Use of (some) special purpose registers.
        XXX: those regs aren't implemented/accessed the same way on different cpus...

        SRP[63-32]: current Thread*
        SRP[31-0] :
        CAAR      : can we use it ??
        MSP       :

        PPC:
        SPRG0: per CPU physical address pointer to an ppc_cpu_exception_context
               structure
        SPRG1: scratch
        SPRG2: current Thread*
        SPRG3: TLS base pointer (only for userland threads)
*/

#endif  // !_ASSEMBLER

#endif  /* _KERNEL_ARCH_PPC_CPU_H */