/***************************************************************************** * pce * *****************************************************************************/ /***************************************************************************** * File name: src/cpu/ppc405/internal.h * * Created: 2003-11-07 by Hampa Hug * * Copyright: (C) 2003-2018 Hampa Hug * * Copyright: (C) 2003-2006 Lukas Ruf * *****************************************************************************/ /***************************************************************************** * This program is free software. You can redistribute it and / or modify it * * under the terms of the GNU General Public License version 2 as published * * by the Free Software Foundation. * * * * This program is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY, without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General * * Public License for more details. * *****************************************************************************/ /***************************************************************************** * This software was developed at the Computer Engineering and Networks * * Laboratory (TIK), Swiss Federal Institute of Technology (ETH) Zurich. * *****************************************************************************/ #ifndef PPC405_INTERNAL_H #define PPC405_INTERNAL_H #include #include /***************************************************************************** * MMU *****************************************************************************/ void p405_tlb_init (p405_tlb_t *tlb); void p405_tbuf_clear (p405_t *c); void p405_set_tlb_entry_hi (p405_t *c, unsigned idx, uint32_t tlbhi, uint8_t pid); void p405_set_tlb_entry_lo (p405_t *c, unsigned idx, uint32_t tlblo); uint32_t p405_get_tlb_entry_hi (p405_t *c, unsigned idx); uint32_t p405_get_tlb_entry_lo (p405_t *c, unsigned idx); uint32_t p405_get_tlb_entry_tid (p405_t *c, unsigned idx); void p405_tlb_invalidate_all (p405_t *c); int p405_ifetch (p405_t *c, uint32_t addr, uint32_t *val); int p405_dload8 (p405_t *c, uint32_t addr, uint8_t *val); int p405_dload16 (p405_t *c, uint32_t addr, uint16_t *val); int p405_dload32 (p405_t *c, uint32_t addr, uint32_t *val); int p405_dstore8 (p405_t *c, uint32_t addr, uint8_t val); int p405_dstore16 (p405_t *c, uint32_t addr, uint16_t val); int p405_dstore32 (p405_t *c, uint32_t addr, uint32_t val); /***************************************************************************** * PPC *****************************************************************************/ #define P405_PVR_405GP 0x40110000 #define P405_PVR_405GP_A 0x40110000 #define P405_PVR_405GP_B 0x40110040 #define P405_PVR_405GP_C 0x40110082 #define P405_PVR_405GP_D 0x401100c4 #define P405_PVR_NPE405H 0x41410140UL #define P405_PVR_NPE405L 0x416100c0UL #define P405_CACHE_LINE_SIZE 32 #define P405_IR_OE 0x0400 #define P405_IR_RC 0x0001 #define P405_IR_LK 0x0001 #define P405_IR_AA 0x0002 #define P405_INT_EXT 1 #define P405_INT_PIT 2 #define P405_INT_FIT 4 #define P405_EXCPT_MSR (P405_MSR_AP | P405_MSR_APE | P405_MSR_WE | P405_MSR_EE |\ P405_MSR_PR | P405_MSR_FP | P405_MSR_FE0 | P405_MSR_DWE | P405_MSR_FE1 |\ P405_MSR_IR | P405_MSR_DR) #define p405_sext(x, n) ( \ ((x) & (1UL << ((n) - 1))) ? \ (((x) | ~((1UL << (n)) - 1)) & 0xffffffffUL) : \ ((x) & ((1UL << (n)) - 1)) \ ) #define p405_uext(x, n) ((x) & ((1 << (n)) - 1)) #define p405_bits(val, i, n) (((val) >> (32 - (i) - (n))) & ((1UL << (n)) - 1)) #define p405_get_ir_rc(ir) (((ir) & P405_IR_RC) != 0) #define p405_get_ir_oe(ir) (((ir) & P405_IR_OE) != 0) #define p405_get_ir_lk(ir) (((ir) & P405_IR_LK) != 0) #define p405_get_ir_aa(ir) (((ir) & P405_IR_AA) != 0) #define p405_get_ir_ra(ir) (((ir) >> 16) & 0x1f) #define p405_get_ir_rb(ir) (((ir) >> 11) & 0x1f) #define p405_get_ir_rs(ir) (((ir) >> 21) & 0x1f) #define p405_get_ir_rt(ir) (((ir) >> 21) & 0x1f) #define p405_get_ra(c, ir) ((c)->gpr[p405_get_ir_ra (ir)]) #define p405_get_rb(c, ir) ((c)->gpr[p405_get_ir_rb (ir)]) #define p405_get_rs(c, ir) ((c)->gpr[p405_get_ir_rs (ir)]) #define p405_get_rt(c, ir) ((c)->gpr[p405_get_ir_rt (ir)]) #define p405_get_ra0(c, ir) (((ir) & 0x1f0000) ? p405_get_ra (c, ir) : 0) #define p405_set_ra(c, ir, val) do { (c)->gpr[p405_get_ir_ra (ir)] = (val); } while (0) #define p405_set_rb(c, ir, val) do { (c)->gpr[p405_get_ir_rb (ir)] = (val); } while (0) #define p405_set_rs(c, ir, val) do { (c)->gpr[p405_get_ir_rs (ir)] = (val); } while (0) #define p405_set_rt(c, ir, val) do { (c)->gpr[p405_get_ir_rt (ir)] = (val); } while (0) #define p405_get_simm16(ir) (((ir) & 0x8000) ? ((ir) | 0xffff0000) : ((ir) & 0xffff)) #define p405_get_uimm16(ir) ((ir) & 0xffff) #define p405_set_clk(c, dpc, clk) do { (c)->pc += (dpc); (c)->delay += (clk); } while (0) typedef struct { unsigned op; p405_opcode_f fct; } p405_opcode_list_t; uint64_t p405_mul (uint32_t s1, uint32_t s2); uint16_t p405_br16 (uint16_t x); uint32_t p405_br32 (uint32_t x); void p405_op_branch (p405_t *c, uint32_t dst, unsigned bo, unsigned bi, int aa, int lk); void p405_op_crop (p405_t *c, unsigned bt, unsigned ba, unsigned bb, unsigned booltab); void p405_op_lsw (p405_t *c, unsigned rt, unsigned ra, unsigned rb, uint32_t ea, unsigned cnt); void p405_op_stsw (p405_t *c, unsigned rs, uint32_t ea, unsigned cnt); void p405_op_undefined (p405_t *c); void p405_exception_data_store (p405_t *c, uint32_t ea, int store, int zone); void p405_exception_instr_store (p405_t *c, int zone); void p405_exception_external (p405_t *c); void p405_exception_program (p405_t *c, uint32_t esr); void p405_exception_program_fpu (p405_t *c); void p405_exception_syscall (p405_t *c); void p405_exception_pit (p405_t *c); void p405_exception_fit (p405_t *c); void p405_exception_tlb_miss_data (p405_t *c, uint32_t ea, int store); void p405_exception_tlb_miss_instr (p405_t *c); void p405_set_opcode13 (p405_t *c); void p405_set_opcode1f (p405_t *c); void p405_set_opcodes (p405_t *c); static inline int p405_check_reserved (p405_t *c, uint32_t res) { if (c->ir & res) { p405_op_undefined (c); return (1); } return (0); } static inline int p405_check_privilege (p405_t *c) { if (p405_get_msr_pr (c)) { p405_exception_program (c, P405_ESR_PPR); return (1); } return (0); } static inline void p405_set_xer_oflow (p405_t *c, int of) { if (of) { c->xer |= (P405_XER_SO | P405_XER_OV); } else { c->xer &= ~P405_XER_OV; } } static inline void p405_set_cr0 (p405_t *c, uint32_t r) { c->cr &= 0x0fffffff; if (r & 0x80000000) { c->cr |= P405_CR0_LT; } else if (r & 0x7fffffff) { c->cr |= P405_CR0_GT; } else { c->cr |= P405_CR0_EQ; } if (c->xer & P405_XER_SO) { c->cr |= P405_CR0_SO; } } static inline int p405_get_ea (p405_t *c, uint32_t *val, int idx, int upd) { if (upd) { if (p405_get_ir_ra (c->ir) == 0) { p405_op_undefined (c); return (1); } } if (idx) { *val = p405_get_ra0 (c, c->ir) + p405_get_rb (c, c->ir); } else { *val = p405_get_ra0 (c, c->ir) + p405_get_simm16 (c->ir); } *val &= 0xffffffff; return (0); } #endif