From ec86ead0bb71a5b9b2cfdcfbc545077f022880f3 Mon Sep 17 00:00:00 2001 From: Tharo <17233964+Thar0@users.noreply.github.com> Date: Sun, 26 Dec 2021 01:56:48 +0000 Subject: [PATCH] PI IO , EPI IO, Flash (#9) * Rudimentary type information extraction in mdebug.py, spsetpc OK * ultratypes.h for setglobalintmask.c * pi and epi io routines * Flash files, non-matching elf disassembler tool --- include/PR/os.h | 260 +----- include/PR/os_convert.h | 43 + include/PR/os_exception.h | 57 ++ include/PR/os_flash.h | 69 ++ include/PR/os_internal.h | 25 +- include/PR/os_internal_exception.h | 2 +- include/PR/os_internal_flash.h | 40 + include/PR/os_internal_reg.h | 43 +- include/PR/os_message.h | 98 ++ include/PR/os_pi.h | 158 ++++ include/PR/os_system.h | 57 ++ include/PR/os_thread.h | 98 ++ include/PR/ultraerror.h | 2 +- include/macros.h | 2 + src/flash/flashallerase.c | 31 + src/flash/flashallerasethrough.c | 7 + src/flash/flashchange.c | 8 + src/flash/flashcheckeraseend.c | 21 + src/flash/flashclearstatus.c | 10 + src/flash/flashgetaddr.c | 7 + src/flash/flashinit.c | 43 + src/flash/flashreadarray.c | 49 + src/flash/flashreadid.c | 27 + src/flash/flashreadstatus.c | 17 + src/flash/flashreinit.c | 14 + src/flash/flashsectorerase.c | 31 + src/flash/flashsectorerasethrough.c | 7 + src/flash/flashwritearray.c | 33 + src/flash/flashwritebuffer.c | 19 + src/io/epidma.c | 24 + src/io/epigettype.c | 8 + src/io/epilinkhandle.c | 12 + src/io/epirawdma.c | 27 + src/io/epirawread.c | 14 + src/io/epirawwrite.c | 14 + src/io/epiread.c | 13 + src/io/epiwrite.c | 13 + src/io/piint.h | 59 ++ src/io/pirawdma.c | 25 + src/io/pirawread.c | 13 + src/io/pirawwrite.c | 13 + src/io/piread.c | 13 + src/io/piwrite.c | 13 + tools/disassemble_elf.py | 292 ++++++ tools/mdebug.py | 15 +- tools/mips_isa.py | 1309 +++++++++++++++++++++++++++ tools/util.py | 44 + 47 files changed, 2890 insertions(+), 309 deletions(-) create mode 100644 include/PR/os_convert.h create mode 100644 include/PR/os_exception.h create mode 100644 include/PR/os_flash.h create mode 100644 include/PR/os_internal_flash.h create mode 100644 include/PR/os_message.h create mode 100644 include/PR/os_pi.h create mode 100644 include/PR/os_system.h create mode 100644 include/PR/os_thread.h create mode 100644 src/flash/flashallerase.c create mode 100644 src/flash/flashallerasethrough.c create mode 100644 src/flash/flashchange.c create mode 100644 src/flash/flashcheckeraseend.c create mode 100644 src/flash/flashclearstatus.c create mode 100644 src/flash/flashgetaddr.c create mode 100644 src/flash/flashinit.c create mode 100644 src/flash/flashreadarray.c create mode 100644 src/flash/flashreadid.c create mode 100644 src/flash/flashreadstatus.c create mode 100644 src/flash/flashreinit.c create mode 100644 src/flash/flashsectorerase.c create mode 100644 src/flash/flashsectorerasethrough.c create mode 100644 src/flash/flashwritearray.c create mode 100644 src/flash/flashwritebuffer.c create mode 100644 src/io/epidma.c create mode 100644 src/io/epigettype.c create mode 100644 src/io/epilinkhandle.c create mode 100644 src/io/epirawdma.c create mode 100644 src/io/epirawread.c create mode 100644 src/io/epirawwrite.c create mode 100644 src/io/epiread.c create mode 100644 src/io/epiwrite.c create mode 100644 src/io/piint.h create mode 100644 src/io/pirawdma.c create mode 100644 src/io/pirawread.c create mode 100644 src/io/pirawwrite.c create mode 100644 src/io/piread.c create mode 100644 src/io/piwrite.c create mode 100644 tools/disassemble_elf.py create mode 100644 tools/mips_isa.py create mode 100644 tools/util.py diff --git a/include/PR/os.h b/include/PR/os.h index 50d548f..3b3060a 100644 --- a/include/PR/os.h +++ b/include/PR/os.h @@ -15,7 +15,14 @@ extern "C" { #endif -#include "PR/ultratypes.h" +#include "ultratypes.h" +#include "os_thread.h" +#include "os_message.h" +#include "os_exception.h" +#include "os_pi.h" +#include "os_system.h" +#include "os_flash.h" +#include "os_convert.h" #if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) @@ -25,140 +32,7 @@ extern "C" { * */ -typedef s32 OSPri; -typedef s32 OSId; -typedef union { struct { f32 f_odd; f32 f_even; } f; f64 d; } __OSfp; - -typedef struct { - u64 at, v0, v1, a0, a1, a2, a3; - u64 t0, t1, t2, t3, t4, t5, t6, t7; - u64 s0, s1, s2, s3, s4, s5, s6, s7; - u64 t8, t9, gp, sp, s8, ra; - u64 lo, hi; - u32 sr, pc, cause, badvaddr, rcp; - u32 fpcsr; - __OSfp fp0, fp2, fp4, fp6, fp8, fp10, fp12, fp14; - __OSfp fp16, fp18, fp20, fp22, fp24, fp26, fp28, fp30; -} __OSThreadContext; - -typedef struct OSThread_s { - struct OSThread_s *next; /* run/mesg queue link */ - OSPri priority; /* run/mesg queue priority */ - struct OSThread_s **queue; /* queue thread is on */ - struct OSThread_s *tlnext; /* all threads queue link */ - u16 state; /* OS_STATE_* */ - u16 flags; /* flags for rmon */ - OSId id; /* id for debugging */ - int fp; /* thread has used fp unit */ - __OSThreadContext context; /* register/interrupt mask */ -} OSThread; - -typedef u32 OSEvent; -typedef u32 OSIntMask; typedef u32 OSPageMask; -typedef u32 OSHWIntr; - -/* - * Structure for message - */ -typedef void * OSMesg; - -/* - * Structure for message queue - */ -typedef struct OSMesgQueue_s { - OSThread *mtqueue; /* Queue to store threads blocked - on empty mailboxes (receive) */ - OSThread *fullqueue; /* Queue to store threads blocked - on full mailboxes (send) */ - s32 validCount; /* Contains number of valid message */ - s32 first; /* Points to first valid message */ - s32 msgCount; /* Contains total # of messages */ - OSMesg *msg; /* Points to message buffer array */ -} OSMesgQueue; - -/* - * Structure for Enhanced PI interface - */ - -/* - * OSTranxInfo is set up for Leo Disk DMA. This info will be maintained - * by exception handler. This is how the PIMGR and the ISR communicate. - */ - -typedef struct { - u32 errStatus; /* error status */ - void *dramAddr; /* RDRAM buffer address (DMA) */ - void *C2Addr; /* C2 buffer address */ - u32 sectorSize; /* size of transfering sector */ - u32 C1ErrNum; /* total # of C1 errors */ - u32 C1ErrSector[4]; /* error sectors */ -} __OSBlockInfo; - -typedef struct { - u32 cmdType; /* for disk only */ - u16 transferMode; /* Block, Track, or sector? */ - u16 blockNum; /* which block is transfering */ - s32 sectorNum; /* which sector is transfering */ - u32 devAddr; /* Device buffer address */ - u32 bmCtlShadow; /* asic bm_ctl(510) register shadow ram */ - u32 seqCtlShadow; /* asic seq_ctl(518) register shadow ram */ - __OSBlockInfo block[2]; /* bolck transfer info */ -} __OSTranxInfo; - - -typedef struct OSPiHandle_s { - struct OSPiHandle_s *next; /* point to next handle on the table */ - u8 type; /* DEVICE_TYPE_BULK for disk */ - u8 latency; /* domain latency */ - u8 pageSize; /* domain page size */ - u8 relDuration; /* domain release duration */ - u8 pulse; /* domain pulse width */ - u8 domain; /* which domain */ - u32 baseAddress; /* Domain address */ - u32 speed; /* for roms only */ - /* The following are "private" elements" */ - __OSTranxInfo transferInfo; /* for disk only */ -} OSPiHandle; - -typedef struct { - u8 type; - u32 address; -} OSPiInfo; - -/* - * Structure for I/O message block - */ -typedef struct { - u16 type; /* Message type */ - u8 pri; /* Message priority (High or Normal) */ - u8 status; /* Return status */ - OSMesgQueue *retQueue; /* Return message queue to notify I/O - * completion */ -} OSIoMesgHdr; - -typedef struct { - OSIoMesgHdr hdr; /* Message header */ - void * dramAddr; /* RDRAM buffer address (DMA) */ - u32 devAddr; /* Device buffer address (DMA) */ - u32 size; /* DMA transfer size in bytes */ - OSPiHandle *piHandle; /* PI device handle */ -} OSIoMesg; - -/* - * Structure for device manager block - */ -typedef struct { - s32 active; /* Status flag */ - OSThread *thread; /* Calling thread */ - OSMesgQueue *cmdQueue; /* Command queue */ - OSMesgQueue *evtQueue; /* Event queue */ - OSMesgQueue *acsQueue; /* Access queue */ - /* Raw DMA routine */ - s32 (*dma)(s32, u32, void *, u32); - s32 (*edma)(OSPiHandle *, s32, u32, void *, u32); -} OSDevMgr; - /* * Structure to store VI register values that remain the same between 2 fields @@ -289,114 +163,6 @@ typedef struct { * */ -/* Thread states */ - -#define OS_STATE_STOPPED 1 -#define OS_STATE_RUNNABLE 2 -#define OS_STATE_RUNNING 4 -#define OS_STATE_WAITING 8 - -/* Events */ -#ifdef _FINALROM -#define OS_NUM_EVENTS 15 -#else -#define OS_NUM_EVENTS 23 -#endif - -#define OS_EVENT_SW1 0 /* CPU SW1 interrupt */ -#define OS_EVENT_SW2 1 /* CPU SW2 interrupt */ -#define OS_EVENT_CART 2 /* Cartridge interrupt: used by rmon */ -#define OS_EVENT_COUNTER 3 /* Counter int: used by VI/Timer Mgr */ -#define OS_EVENT_SP 4 /* SP task done interrupt */ -#define OS_EVENT_SI 5 /* SI (controller) interrupt */ -#define OS_EVENT_AI 6 /* AI interrupt */ -#define OS_EVENT_VI 7 /* VI interrupt: used by VI/Timer Mgr */ -#define OS_EVENT_PI 8 /* PI interrupt: used by PI Manager */ -#define OS_EVENT_DP 9 /* DP full sync interrupt */ -#define OS_EVENT_CPU_BREAK 10 /* CPU breakpoint: used by rmon */ -#define OS_EVENT_SP_BREAK 11 /* SP breakpoint: used by rmon */ -#define OS_EVENT_FAULT 12 /* CPU fault event: used by rmon */ -#define OS_EVENT_THREADSTATUS 13 /* CPU thread status: used by rmon */ -#define OS_EVENT_PRENMI 14 /* Pre NMI interrupt */ -#ifndef _FINALROM -#define OS_EVENT_RDB_READ_DONE 15 /* RDB read ok event: used by rmon */ -#define OS_EVENT_RDB_LOG_DONE 16 /* read of log data complete */ -#define OS_EVENT_RDB_DATA_DONE 17 /* read of hostio data complete */ -#define OS_EVENT_RDB_REQ_RAMROM 18 /* host needs ramrom access */ -#define OS_EVENT_RDB_FREE_RAMROM 19 /* host is done with ramrom access */ -#define OS_EVENT_RDB_DBG_DONE 20 -#define OS_EVENT_RDB_FLUSH_PROF 21 -#define OS_EVENT_RDB_ACK_PROF 22 -#endif - -/* Flags for debugging purpose */ - -#define OS_FLAG_CPU_BREAK 1 /* Break exception has occurred */ -#define OS_FLAG_FAULT 2 /* CPU fault has occurred */ - -/* Interrupt masks */ - -#define OS_IM_NONE 0x00000001 -#define OS_IM_RCP 0x00000401 -#define OS_IM_SW1 0x00000501 -#define OS_IM_SW2 0x00000601 -#define OS_IM_CART 0x00000c01 -#define OS_IM_PRENMI 0x00001401 -#define OS_IM_RDBWRITE 0x00002401 -#define OS_IM_RDBREAD 0x00004401 -#define OS_IM_COUNTER 0x00008401 -#define OS_IM_CPU 0x0000ff01 -#define OS_IM_SP 0x00010401 -#define OS_IM_SI 0x00020401 -#define OS_IM_AI 0x00040401 -#define OS_IM_VI 0x00080401 -#define OS_IM_PI 0x00100401 -#define OS_IM_DP 0x00200401 -#define OS_IM_ALL 0x003fff01 -#define RCP_IMASK 0x003f0000 -#define RCP_IMASKSHIFT 16 - -/* Recommended thread priorities for the system threads */ - -#define OS_PRIORITY_MAX 255 -#define OS_PRIORITY_VIMGR 254 -#define OS_PRIORITY_RMON 250 -#define OS_PRIORITY_RMONSPIN 200 -#define OS_PRIORITY_PIMGR 150 -#define OS_PRIORITY_SIMGR 140 -#define OS_PRIORITY_APPMAX 127 -#define OS_PRIORITY_IDLE 0 /* Must be 0 */ - - -/* Flags to turn blocking on/off when sending/receiving message */ - -#define OS_MESG_NOBLOCK 0 -#define OS_MESG_BLOCK 1 - -/* Flags to indicate direction of data transfer */ - -#define OS_READ 0 /* device -> RDRAM */ -#define OS_WRITE 1 /* device <- RDRAM */ -#define OS_OTHERS 2 /* for Leo disk only */ - -/* - * I/O message types - */ -#define OS_MESG_TYPE_BASE (10) -#define OS_MESG_TYPE_LOOPBACK (OS_MESG_TYPE_BASE+0) -#define OS_MESG_TYPE_DMAREAD (OS_MESG_TYPE_BASE+1) -#define OS_MESG_TYPE_DMAWRITE (OS_MESG_TYPE_BASE+2) -#define OS_MESG_TYPE_VRETRACE (OS_MESG_TYPE_BASE+3) -#define OS_MESG_TYPE_COUNTER (OS_MESG_TYPE_BASE+4) -#define OS_MESG_TYPE_EDMAREAD (OS_MESG_TYPE_BASE+5) -#define OS_MESG_TYPE_EDMAWRITE (OS_MESG_TYPE_BASE+6) - -/* - * I/O message priority - */ -#define OS_MESG_PRI_NORMAL 0 -#define OS_MESG_PRI_HIGH 1 - /* * Page size argument for TLB routines */ @@ -419,13 +185,6 @@ typedef struct { #define OS_MIN_STACKSIZE 72 -/* - * Values for osTvType - */ -#define OS_TV_PAL 0 -#define OS_TV_NTSC 1 -#define OS_TV_MPAL 2 - /* * Video Interface (VI) mode type */ @@ -846,8 +605,6 @@ extern s32 osPiRawReadIo(u32, u32 *); extern s32 osPiRawStartDma(s32, u32, void *, u32); extern s32 osPiWriteIo(u32, u32); extern s32 osPiReadIo(u32, u32 *); -extern s32 osPiStartDma(OSIoMesg *, s32, s32, u32, void *, u32, - OSMesgQueue *); extern void osCreatePiManager(OSPri, OSMesgQueue *, OSMesg *, s32); /* Video interface (Vi) */ @@ -959,7 +716,6 @@ extern void bzero(void *, int); /* Miscellaneous operations */ -extern void osInitialize(void); extern u32 osGetCount(void); extern void osExit(void); extern u32 osGetMemSize(void); diff --git a/include/PR/os_convert.h b/include/PR/os_convert.h new file mode 100644 index 0000000..c6126a3 --- /dev/null +++ b/include/PR/os_convert.h @@ -0,0 +1,43 @@ +#ifndef _OS_CONVERT_H_ +#define _OS_CONVERT_H_ + +#ifdef _LANGUAGE_C_PLUS_PLUS +extern "C" { +#endif + +#include "ultratypes.h" + +#define OS_CLOCK_RATE 62500000LL +#define OS_CPU_COUNTER (OS_CLOCK_RATE*3/4) + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +#define OS_NSEC_TO_CYCLES(n) (((u64)(n)*(OS_CPU_COUNTER/15625000LL))/(1000000000LL/15625000LL)) +#define OS_USEC_TO_CYCLES(n) (((u64)(n)*(OS_CPU_COUNTER/15625LL))/(1000000LL/15625LL)) +#define OS_CYCLES_TO_NSEC(c) (((u64)(c)*(1000000000LL/15625000LL))/(OS_CPU_COUNTER/15625000LL)) +#define OS_CYCLES_TO_USEC(c) (((u64)(c)*(1000000LL/15625LL))/(OS_CPU_COUNTER/15625LL)) + +/* OS_K?_TO_PHYSICAL macro bug fix for CodeWarrior */ +#ifndef __MWERKS__ +#define OS_K0_TO_PHYSICAL(x) (u32)(((char *)(x)-0x80000000)) +#define OS_K1_TO_PHYSICAL(x) (u32)(((char *)(x)-0xa0000000)) +#else +#define OS_K0_TO_PHYSICAL(x) ((char *)(x)-0x80000000) +#define OS_K1_TO_PHYSICAL(x) ((char *)(x)-0xa0000000) +#endif + +#define OS_PHYSICAL_TO_K0(x) (void *)(((u32)(x)+0x80000000)) +#define OS_PHYSICAL_TO_K1(x) (void *)(((u32)(x)+0xa0000000)) + +/* Address translation routines and macros */ + +extern u32 osVirtualToPhysical(void *); +extern void *osPhysicalToVirtual(u32); + +#endif /* defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) */ + +#ifdef _LANGUAGE_C_PLUS_PLUS +} +#endif + +#endif /* !_OS_CONVERT_H_ */ diff --git a/include/PR/os_exception.h b/include/PR/os_exception.h new file mode 100644 index 0000000..eb3c78c --- /dev/null +++ b/include/PR/os_exception.h @@ -0,0 +1,57 @@ +#ifndef _OS_EXCEPTION_H_ +#define _OS_EXCEPTION_H_ + +#ifdef _LANGUAGE_C_PLUS_PLUS +extern "C" { +#endif + +#include "ultratypes.h" + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +typedef u32 OSIntMask; +typedef u32 OSHWIntr; + +#endif /* defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) */ + +/* Flags for debugging purpose */ + +#define OS_FLAG_CPU_BREAK 1 /* Break exception has occurred */ +#define OS_FLAG_FAULT 2 /* CPU fault has occurred */ + +/* Interrupt masks */ + +#define OS_IM_NONE 0x00000001 +#define OS_IM_RCP 0x00000401 +#define OS_IM_SW1 0x00000501 +#define OS_IM_SW2 0x00000601 +#define OS_IM_CART 0x00000c01 +#define OS_IM_PRENMI 0x00001401 +#define OS_IM_RDBWRITE 0x00002401 +#define OS_IM_RDBREAD 0x00004401 +#define OS_IM_COUNTER 0x00008401 +#define OS_IM_CPU 0x0000ff01 +#define OS_IM_SP 0x00010401 +#define OS_IM_SI 0x00020401 +#define OS_IM_AI 0x00040401 +#define OS_IM_VI 0x00080401 +#define OS_IM_PI 0x00100401 +#define OS_IM_DP 0x00200401 +#define OS_IM_ALL 0x003fff01 +#define RCP_IMASK 0x003f0000 +#define RCP_IMASKSHIFT 16 + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +/* Interrupt operations */ + +extern OSIntMask osGetIntMask(void); +extern OSIntMask osSetIntMask(OSIntMask); + +#endif /* defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) */ + +#ifdef _LANGUAGE_C_PLUS_PLUS +} +#endif + +#endif /* !_OS_EXCEPTION_H_ */ diff --git a/include/PR/os_flash.h b/include/PR/os_flash.h new file mode 100644 index 0000000..18f880b --- /dev/null +++ b/include/PR/os_flash.h @@ -0,0 +1,69 @@ +#ifndef _OS_FLASH_H_ +#define _OS_FLASH_H_ + +#ifdef _LANGUAGE_C_PLUS_PLUS +extern "C" { +#endif + +#include "ultratypes.h" +#include "os_pi.h" + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +/* + * defines for FLASH + */ +#define FLASH_START_ADDR 0x08000000 + +#define FLASH_SIZE 0x20000 + +#define FLASH_LATENCY 0x5 +#define FLASH_PULSE 0x0c +#define FLASH_PAGE_SIZE 0xf +#define FLASH_REL_DURATION 0x2 +#define DEVICE_TYPE_FLASH 8 + +#define FLASH_VERSION_MX_PROTO_A 0x00c20000 +#define FLASH_VERSION_MX_A 0x00c20001 +#define FLASH_VERSION_MX_C 0x00c2001e +#define FLASH_VERSION_MX_B_AND_D 0x00c2001d +#define FLASH_VERSION_MEI 0x003200f1 + +/* OLD_FLASH is MX_PROTO_A, MX_A and MX_C */ +#define OLD_FLASH 0 +/* NEW_FLASH is MX_B_AND_D and MATSUSHITA flash */ +#define NEW_FLASH 1 + +#define FLASH_STATUS_ERASE_BUSY 2 +#define FLASH_STATUS_ERASE_OK 0 +#define FLASH_STATUS_ERASE_ERROR -1 + +#define FLASH_STATUS_WRITE_BUSY 1 +#define FLASH_STATUS_WRITE_OK 0 +#define FLASH_STATUS_WRITE_ERROR -1 + +extern OSPiHandle *osFlashReInit(u8 latency, u8 pulse, + u8 page_size, u8 rel_duration, u32 start); +extern OSPiHandle *osFlashInit(void); +extern void osFlashReadStatus(u8 *flash_status); +extern void osFlashReadId(u32 *flash_type, u32 *flash_maker); +extern void osFlashClearStatus(void); +extern s32 osFlashAllErase(void); +extern s32 osFlashSectorErase(u32 page_num); +extern s32 osFlashWriteBuffer(OSIoMesg *mb, s32 priority, + void *dramAddr, OSMesgQueue *mq); +extern s32 osFlashWriteArray(u32 page_num); +extern s32 osFlashReadArray(OSIoMesg *mb, s32 priority, u32 page_num, + void *dramAddr, u32 n_pages, OSMesgQueue *mq); +extern void osFlashChange(u32 flash_num); +extern void osFlashAllEraseThrough(void); +extern void osFlashSectorEraseThrough(u32 page_num); +extern s32 osFlashCheckEraseEnd(void); + +#endif /* defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) */ + +#ifdef _LANGUAGE_C_PLUS_PLUS +} +#endif + +#endif /* !_OS_FLASH_H_ */ diff --git a/include/PR/os_internal.h b/include/PR/os_internal.h index 7f874cd..c092052 100644 --- a/include/PR/os_internal.h +++ b/include/PR/os_internal.h @@ -13,34 +13,13 @@ extern "C" { #endif -#include "PR/os.h" +#include "os.h" #if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) #include "os_internal_reg.h" #include "os_internal_exception.h" - -/* Routines to get/fetch coprocessor 0 registers */ - -extern u32 __osGetCause(void); -extern void __osSetCause(u32); -extern u32 __osGetCompare(void); -extern void __osSetCompare(u32); -extern u32 __osGetConfig(void); -extern void __osSetConfig(u32); -extern void __osSetCount(u32); -extern u32 __osGetSR(void); -extern void __osSetSR(u32); -extern u32 __osDisableInt(void); -extern void __osRestoreInt(u32); - -/* Routines to get/set floating-point control and status register */ -extern u32 __osSetFpcCsr(u32); -extern u32 __osGetFpcCsr(void); - -/* Routine for global interrupt mask */ -extern void __osSetGlobalIntMask(OSHWIntr); -extern void __osResetGlobalIntMask(OSHWIntr); +#include "os_internal_flash.h" /* Routine for global interrupt mask */ extern s32 __osLeoInterrupt(void); diff --git a/include/PR/os_internal_exception.h b/include/PR/os_internal_exception.h index 198657e..4248cfa 100644 --- a/include/PR/os_internal_exception.h +++ b/include/PR/os_internal_exception.h @@ -12,7 +12,7 @@ extern "C" { #endif -#include "PR/os.h" +#include "os.h" #if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) diff --git a/include/PR/os_internal_flash.h b/include/PR/os_internal_flash.h new file mode 100644 index 0000000..d8681d7 --- /dev/null +++ b/include/PR/os_internal_flash.h @@ -0,0 +1,40 @@ +#ifndef _OS_INTERNAL_FLASH_H_ +#define _OS_INTERNAL_FLASH_H_ + +#include "os_message.h" +#include "os_flash.h" + +#define FLASH_BLOCK_SIZE 128 + +/** + * Flash commands + */ +#define FLASH_CMD_REG 0x10000 + +/* set whole chip erase mode */ +#define FLASH_CMD_CHIP_ERASE 0x3C000000 +/* set sector erase mode */ +#define FLASH_CMD_SECTOR_ERASE 0x4B000000 +/* do erasure */ +#define FLASH_CMD_EXECUTE_ERASE 0x78000000 +/* program selected page */ +#define FLASH_CMD_PROGRAM_PAGE 0xA5000000 +/* set page program mode */ +#define FLASH_CMD_PAGE_PROGRAM 0xB4000000 +/* set status mode */ +#define FLASH_CMD_STATUS 0xD2000000 +/* set silicon id mode */ +#define FLASH_CMD_ID 0xE1000000 +/* set read mode */ +#define FLASH_CMD_READ_ARRAY 0xF0000000 + +extern s32 __osFlashVersion; +extern OSPiHandle __osFlashHandler; +extern OSMesgQueue __osFlashMessageQ; +extern OSMesg __osFlashMsgBuf[1]; +extern OSIoMesg __osFlashMsg; +extern u32 __osFlashID[4]; + +u32 __osFlashGetAddr(u32 page_num); + +#endif diff --git a/include/PR/os_internal_reg.h b/include/PR/os_internal_reg.h index 6ed720e..a13ba67 100644 --- a/include/PR/os_internal_reg.h +++ b/include/PR/os_internal_reg.h @@ -1,41 +1,32 @@ -/*---------------------------------------------------------------------* - - $RCSfile: os_internal_reg.h,v $ - $Revision: 1.2 $ - $Date: 1999/03/10 12:19:14 $ - *---------------------------------------------------------------------*/ - #ifndef _OS_INTERNAL_REG_H_ -#define _OS_INTERNAL_REG_H_ +#define _OS_INTERNAL_REG_H_ #ifdef _LANGUAGE_C_PLUS_PLUS extern "C" { #endif -#include "PR/os.h" +#include "os.h" #if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) /* Routines to get/fetch coprocessor 0 registers */ - -extern u32 __osGetCause(void); -extern void __osSetCause(u32); -extern u32 __osGetCompare(void); -extern void __osSetCompare(u32); -extern u32 __osGetConfig(void); -extern void __osSetConfig(u32); -extern void __osSetCount(u32); -extern u32 __osGetSR(void); -extern void __osSetSR(u32); -extern u32 __osDisableInt(void); -extern void __osRestoreInt(u32); -extern u32 __osGetWatchLo(void); -extern void __osSetWatchLo(u32); +extern u32 __osGetCause(void); +extern void __osSetCause(u32); +extern u32 __osGetCompare(void); +extern void __osSetCompare(u32); +extern u32 __osGetConfig(void); +extern void __osSetConfig(u32); +extern void __osSetCount(u32); +extern u32 __osGetSR(void); +extern void __osSetSR(u32); +extern u32 __osDisableInt(void); +extern void __osRestoreInt(u32); +extern u32 __osGetWatchLo(void); +extern void __osSetWatchLo(u32); /* Routines to get/set floating-point control and status register */ -extern u32 __osSetFpcCsr(u32); -extern u32 __osGetFpcCsr(void); - +extern u32 __osSetFpcCsr(u32); +extern u32 __osGetFpcCsr(void); #endif /* _LANGUAGE_C */ diff --git a/include/PR/os_message.h b/include/PR/os_message.h new file mode 100644 index 0000000..531a537 --- /dev/null +++ b/include/PR/os_message.h @@ -0,0 +1,98 @@ +#ifndef _OS_MESSAGE_H_ +#define _OS_MESSAGE_H_ + +#ifdef _LANGUAGE_C_PLUS_PLUS +extern "C" { +#endif + +#include "ultratypes.h" +#include "os_thread.h" + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +typedef u32 OSEvent; + +/* + * Structure for message + */ +typedef void *OSMesg; + +/* + * Structure for message queue + */ +typedef struct OSMesgQueue_s { + OSThread *mtqueue; /* Queue to store threads blocked on empty mailboxes (receive) */ + OSThread *fullqueue; /* Queue to store threads blocked on full mailboxes (send) */ + s32 validCount; /* Contains number of valid message */ + s32 first; /* Points to first valid message */ + s32 msgCount; /* Contains total # of messages */ + OSMesg *msg; /* Points to message buffer array */ +} OSMesgQueue; + +#endif /* defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) */ + +/* Events */ +#ifdef _FINALROM +#define OS_NUM_EVENTS 15 +#else +#define OS_NUM_EVENTS 23 +#endif + +#define OS_EVENT_SW1 0 /* CPU SW1 interrupt */ +#define OS_EVENT_SW2 1 /* CPU SW2 interrupt */ +#define OS_EVENT_CART 2 /* Cartridge interrupt: used by rmon */ +#define OS_EVENT_COUNTER 3 /* Counter int: used by VI/Timer Mgr */ +#define OS_EVENT_SP 4 /* SP task done interrupt */ +#define OS_EVENT_SI 5 /* SI (controller) interrupt */ +#define OS_EVENT_AI 6 /* AI interrupt */ +#define OS_EVENT_VI 7 /* VI interrupt: used by VI/Timer Mgr */ +#define OS_EVENT_PI 8 /* PI interrupt: used by PI Manager */ +#define OS_EVENT_DP 9 /* DP full sync interrupt */ +#define OS_EVENT_CPU_BREAK 10 /* CPU breakpoint: used by rmon */ +#define OS_EVENT_SP_BREAK 11 /* SP breakpoint: used by rmon */ +#define OS_EVENT_FAULT 12 /* CPU fault event: used by rmon */ +#define OS_EVENT_THREADSTATUS 13 /* CPU thread status: used by rmon */ +#define OS_EVENT_PRENMI 14 /* Pre NMI interrupt */ +#ifndef _FINALROM +#define OS_EVENT_RDB_READ_DONE 15 /* RDB read ok event: used by rmon */ +#define OS_EVENT_RDB_LOG_DONE 16 /* read of log data complete */ +#define OS_EVENT_RDB_DATA_DONE 17 /* read of hostio data complete */ +#define OS_EVENT_RDB_REQ_RAMROM 18 /* host needs ramrom access */ +#define OS_EVENT_RDB_FREE_RAMROM 19 /* host is done with ramrom access */ +#define OS_EVENT_RDB_DBG_DONE 20 +#define OS_EVENT_RDB_FLUSH_PROF 21 +#define OS_EVENT_RDB_ACK_PROF 22 +#endif + +/* Flags to turn blocking on/off when sending/receiving message */ + +#define OS_MESG_NOBLOCK 0 +#define OS_MESG_BLOCK 1 + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +/* Get count of valid messages in queue */ +#define MQ_GET_COUNT(mq) ((mq)->validCount) + +/* Figure out if message queue is empty or full */ +#define MQ_IS_EMPTY(mq) (MQ_GET_COUNT(mq) == 0) +#define MQ_IS_FULL(mq) (MQ_GET_COUNT(mq) >= (mq)->msgCount) + +/* Message operations */ + +extern void osCreateMesgQueue(OSMesgQueue *, OSMesg *, s32); +extern s32 osSendMesg(OSMesgQueue *, OSMesg, s32); +extern s32 osJamMesg(OSMesgQueue *, OSMesg, s32); +extern s32 osRecvMesg(OSMesgQueue *, OSMesg *, s32); + +/* Event operations */ + +extern void osSetEventMesg(OSEvent, OSMesgQueue *, OSMesg); + +#endif /* defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) */ + +#ifdef _LANGUAGE_C_PLUS_PLUS +} +#endif + +#endif /* !_OS_MESSAGE_H_ */ diff --git a/include/PR/os_pi.h b/include/PR/os_pi.h new file mode 100644 index 0000000..4e26b5b --- /dev/null +++ b/include/PR/os_pi.h @@ -0,0 +1,158 @@ +#ifndef _OS_PI_H_ +#define _OS_PI_H_ + +#ifdef _LANGUAGE_C_PLUS_PLUS +extern "C" { +#endif + +#include "ultratypes.h" +#include "os_thread.h" +#include "os_message.h" + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +/* + * Structure for Enhanced PI interface + */ + +/* + * OSTranxInfo is set up for Leo Disk DMA. This info will be maintained + * by exception handler. This is how the PIMGR and the ISR communicate. + */ + +typedef struct { + u32 errStatus; /* error status */ + void *dramAddr; /* RDRAM buffer address (DMA) */ + void *C2Addr; /* C2 buffer address */ + u32 sectorSize; /* size of transfering sector */ + u32 C1ErrNum; /* total # of C1 errors */ + u32 C1ErrSector[4]; /* error sectors */ +} __OSBlockInfo; + +typedef struct { + u32 cmdType; /* for disk only */ + u16 transferMode; /* Block, Track, or sector? */ + u16 blockNum; /* which block is transfering */ + s32 sectorNum; /* which sector is transfering */ + u32 devAddr; /* Device buffer address */ + u32 bmCtlShadow; /* asic bm_ctl(510) register shadow ram */ + u32 seqCtlShadow; /* asic seq_ctl(518) register shadow ram */ + __OSBlockInfo block[2]; /* bolck transfer info */ +} __OSTranxInfo; + +typedef struct OSPiHandle_s { + struct OSPiHandle_s *next; /* point to next handle on the table */ + u8 type; /* DEVICE_TYPE_BULK for disk */ + u8 latency; /* domain latency */ + u8 pageSize; /* domain page size */ + u8 relDuration; /* domain release duration */ + u8 pulse; /* domain pulse width */ + u8 domain; /* which domain */ + u32 baseAddress; /* Domain address */ + u32 speed; /* for roms only */ + /* The following are "private" elements" */ + __OSTranxInfo transferInfo; /* for disk only */ +} OSPiHandle; + +typedef struct { + u8 type; + u32 address; +} OSPiInfo; + +/* + * Structure for I/O message block + */ +typedef struct { + u16 type; /* Message type */ + u8 pri; /* Message priority (High or Normal) */ + u8 status; /* Return status */ + OSMesgQueue *retQueue; /* Return message queue to notify I/O completion */ +} OSIoMesgHdr; + +typedef struct { + OSIoMesgHdr hdr; /* Message header */ + void *dramAddr; /* RDRAM buffer address (DMA) */ + u32 devAddr; /* Device buffer address (DMA) */ + u32 size; /* DMA transfer size in bytes */ + OSPiHandle *piHandle; /* PI device handle */ +} OSIoMesg; + +/* + * Structure for device manager block + */ +typedef struct { + s32 active; /* Status flag */ + OSThread *thread; /* Calling thread */ + OSMesgQueue *cmdQueue; /* Command queue */ + OSMesgQueue *evtQueue; /* Event queue */ + OSMesgQueue *acsQueue; /* Access queue */ + /* Raw DMA routine */ + s32 (*dma)(s32, u32, void *, u32); + s32 (*edma)(OSPiHandle *, s32, u32, void *, u32); +} OSDevMgr; + +#endif /* defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) */ + +/* Flags to indicate direction of data transfer */ + +#define OS_READ 0 /* device -> RDRAM */ +#define OS_WRITE 1 /* device <- RDRAM */ +#define OS_OTHERS 2 /* for Leo disk only */ + +/* + * I/O message types + */ +#define OS_MESG_TYPE_BASE (10) +#define OS_MESG_TYPE_LOOPBACK (OS_MESG_TYPE_BASE + 0) +#define OS_MESG_TYPE_DMAREAD (OS_MESG_TYPE_BASE + 1) +#define OS_MESG_TYPE_DMAWRITE (OS_MESG_TYPE_BASE + 2) +#define OS_MESG_TYPE_VRETRACE (OS_MESG_TYPE_BASE + 3) +#define OS_MESG_TYPE_COUNTER (OS_MESG_TYPE_BASE + 4) +#define OS_MESG_TYPE_EDMAREAD (OS_MESG_TYPE_BASE + 5) +#define OS_MESG_TYPE_EDMAWRITE (OS_MESG_TYPE_BASE + 6) + +/* + * I/O message priority + */ +#define OS_MESG_PRI_NORMAL 0 +#define OS_MESG_PRI_HIGH 1 + +/* + * PI/EPI + */ +#define PI_DOMAIN1 0 +#define PI_DOMAIN2 1 + + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +extern OSPiHandle *__osPiTable; /* The head of OSPiHandle link list */ + +/* Peripheral interface (PI) */ + +extern u32 osPiGetStatus(void); +extern s32 osPiGetDeviceType(void); +extern s32 osPiWriteIo(u32, u32); +extern s32 osPiReadIo(u32, u32 *); +extern s32 osPiStartDma(OSIoMesg *, s32, s32, u32, void *, u32, OSMesgQueue *); +extern void osCreatePiManager(OSPri, OSMesgQueue *, OSMesg *, s32); + +/* Enhanced PI interface */ + +extern OSPiHandle *osCartRomInit(void); +extern OSPiHandle *osLeoDiskInit(void); +extern OSPiHandle *osDriveRomInit(void); + +extern s32 osEPiDeviceType(OSPiHandle *, OSPiInfo *); +extern s32 osEPiWriteIo(OSPiHandle *, u32 , u32 ); +extern s32 osEPiReadIo(OSPiHandle *, u32 , u32 *); +extern s32 osEPiStartDma(OSPiHandle *, OSIoMesg *, s32); +extern s32 osEPiLinkHandle(OSPiHandle *); + +#endif /* defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) */ + +#ifdef _LANGUAGE_C_PLUS_PLUS +} +#endif + +#endif /* !_OS_PI_H_ */ diff --git a/include/PR/os_system.h b/include/PR/os_system.h new file mode 100644 index 0000000..062cc5a --- /dev/null +++ b/include/PR/os_system.h @@ -0,0 +1,57 @@ +#ifndef _OS_SYSTEM_H_ +#define _OS_SYSTEM_H_ + +#ifdef _LANGUAGE_C_PLUS_PLUS +extern "C" { +#endif + +#include "ultratypes.h" +#include "os_exception.h" + +/* + * Values for osTvType + */ +#define OS_TV_PAL 0 +#define OS_TV_NTSC 1 +#define OS_TV_MPAL 2 + +/* + * Size of buffer the retains contents after NMI + */ +#define OS_APP_NMI_BUFSIZE 64 + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +extern s32 osRomType; /* Bulk or cartridge ROM. 0=cartridge 1=bulk */ +extern void *osRomBase; /* Rom base address of the game image */ +extern s32 osTvType; /* 0 = PAL, 1 = NTSC, 2 = MPAL */ +extern s32 osResetType; /* 0 = cold reset, 1 = NMI */ +extern s32 osCicId; +extern s32 osVersion; +extern u32 osMemSize; /* Memory Size */ +extern s32 osAppNMIBuffer[OS_APP_NMI_BUFSIZE/sizeof(s32)]; + +extern u64 osClockRate; + +extern OSIntMask __OSGlobalIntMask; /* global interrupt mask */ + +#define osInitialize() \ + __osInitialize_common(); \ + __osInitialize_autodetect() + +void __osInitialize_common(void); +void __osInitialize_autodetect(void); + +extern void osExit(void); +extern u32 osGetMemSize(void); + +/* pre-NMI */ +extern s32 osAfterPreNMI(void); + +#endif /* defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) */ + +#ifdef _LANGUAGE_C_PLUS_PLUS +} +#endif + +#endif /* !_OS_SYSTEM_H_ */ diff --git a/include/PR/os_thread.h b/include/PR/os_thread.h new file mode 100644 index 0000000..44add4c --- /dev/null +++ b/include/PR/os_thread.h @@ -0,0 +1,98 @@ +#ifndef _OS_THREAD_H_ +#define _OS_THREAD_H_ + +#ifdef _LANGUAGE_C_PLUS_PLUS +extern "C" { +#endif + +#include "ultratypes.h" + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +typedef s32 OSPri; +typedef s32 OSId; + +typedef union { + struct { + f32 f_odd; + f32 f_even; + } f; + f64 d; +} __OSfp; + +typedef struct { + u64 at, v0, v1, a0, a1, a2, a3; + u64 t0, t1, t2, t3, t4, t5, t6, t7; + u64 s0, s1, s2, s3, s4, s5, s6, s7; + u64 t8, t9; + u64 gp, sp, s8, ra; + u64 lo, hi; + u32 sr, pc, cause, badvaddr, rcp; + u32 fpcsr; + __OSfp fp0, fp2, fp4, fp6, fp8, fp10, fp12, fp14; + __OSfp fp16, fp18, fp20, fp22, fp24, fp26, fp28, fp30; +} __OSThreadContext; + +typedef struct { + u32 flag; + u32 count; + u64 time; +} __OSThreadprofile_s; + +typedef struct OSThread_s { + struct OSThread_s *next; /* run/mesg queue link */ + OSPri priority; /* run/mesg queue priority */ + struct OSThread_s **queue; /* queue thread is on */ + struct OSThread_s *tlnext; /* all threads queue link */ + u16 state; /* OS_STATE_* */ + u16 flags; /* flags for rmon */ + OSId id; /* id for debugging */ + int fp; /* thread has used fp unit */ + __OSThreadprofile_s *thprof; /* workarea for thread profiler */ + __OSThreadContext context; /* register/interrupt mask */ +} OSThread; + +#endif /* defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) */ + +/* Thread states */ + +#define OS_STATE_STOPPED (1 << 0) +#define OS_STATE_RUNNABLE (1 << 1) +#define OS_STATE_RUNNING (1 << 2) +#define OS_STATE_WAITING (1 << 3) + +/* Recommended thread priorities for the system threads */ + +#define OS_PRIORITY_MAX 255 +#define OS_PRIORITY_VIMGR 254 +#define OS_PRIORITY_RMON 250 +#define OS_PRIORITY_RMONSPIN 200 +#define OS_PRIORITY_PIMGR 150 +#define OS_PRIORITY_SIMGR 140 +#define OS_PRIORITY_APPMAX 127 +#define OS_PRIORITY_IDLE 0 /* Must be 0 */ + +/* For thread profiler */ +#define THPROF_IDMAX 64 +#define THPROF_STACKSIZE 256 + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +/* Thread operations */ + +extern void osCreateThread(OSThread *, OSId, void (*)(void *), void *, void *, OSPri); +extern void osDestroyThread(OSThread *); +extern void osYieldThread(void); +extern void osStartThread(OSThread *); +extern void osStopThread(OSThread *); +extern OSId osGetThreadId(OSThread *); +extern void osSetThreadPri(OSThread *, OSPri); +extern OSPri osGetThreadPri(OSThread *); + +#endif /* defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) */ + +#ifdef _LANGUAGE_C_PLUS_PLUS +} +#endif + +#endif /* !_OS_THREAD_H_ */ diff --git a/include/PR/ultraerror.h b/include/PR/ultraerror.h index b5295ab..f6b62ff 100644 --- a/include/PR/ultraerror.h +++ b/include/PR/ultraerror.h @@ -13,7 +13,7 @@ extern "C" { #endif -#include "PR/ultratypes.h" +#include "ultratypes.h" #define OS_ERROR_FMT "/usr/lib/PR/error.fmt" #define OS_ERROR_MAGIC 0x6b617479 diff --git a/include/macros.h b/include/macros.h index f71db92..53352c8 100644 --- a/include/macros.h +++ b/include/macros.h @@ -3,4 +3,6 @@ #define ALIGNED(x) __attribute__((aligned(x))) +#define ARRLEN(x) ((s32)(sizeof(x) / sizeof(x[0]))) + #endif diff --git a/src/flash/flashallerase.c b/src/flash/flashallerase.c new file mode 100644 index 0000000..c66dbd6 --- /dev/null +++ b/src/flash/flashallerase.c @@ -0,0 +1,31 @@ +#include "PR/os_internal.h" + +s32 osFlashAllErase(void) { + u32 status; + OSTimer mytimer; + OSMesgQueue timerMesgQueue; + OSMesg dummy; + + // start chip erase operation + osEPiWriteIo(&__osFlashHandler, __osFlashHandler.baseAddress | FLASH_CMD_REG, FLASH_CMD_CHIP_ERASE); + osEPiWriteIo(&__osFlashHandler, __osFlashHandler.baseAddress | FLASH_CMD_REG, FLASH_CMD_EXECUTE_ERASE); + + // wait for completion by polling erase-busy flag + osCreateMesgQueue(&timerMesgQueue, &dummy, 1); + do { + osSetTimer(&mytimer, OS_USEC_TO_CYCLES(15000), 0, &timerMesgQueue, &dummy); + osRecvMesg(&timerMesgQueue, &dummy, OS_MESG_BLOCK); + osEPiReadIo(&__osFlashHandler, __osFlashHandler.baseAddress, &status); + } while ((status & FLASH_STATUS_ERASE_BUSY) == FLASH_STATUS_ERASE_BUSY); + + // check erase operation status, clear status + osEPiReadIo(&__osFlashHandler, __osFlashHandler.baseAddress, &status); + osFlashClearStatus(); + + // check for success + if (((status & 0xFF) == 8) || ((status & 0xFF) == 0x48) || ((status & 8) == 8)) { + return FLASH_STATUS_ERASE_OK; + } else { + return FLASH_STATUS_ERASE_ERROR; + } +} diff --git a/src/flash/flashallerasethrough.c b/src/flash/flashallerasethrough.c new file mode 100644 index 0000000..9e52b97 --- /dev/null +++ b/src/flash/flashallerasethrough.c @@ -0,0 +1,7 @@ +#include "PR/os_internal.h" + +void osFlashAllEraseThrough(void) { + // start chip erase operation, no waiting for completion + osEPiWriteIo(&__osFlashHandler, __osFlashHandler.baseAddress | FLASH_CMD_REG, FLASH_CMD_CHIP_ERASE); + osEPiWriteIo(&__osFlashHandler, __osFlashHandler.baseAddress | FLASH_CMD_REG, FLASH_CMD_EXECUTE_ERASE); +} diff --git a/src/flash/flashchange.c b/src/flash/flashchange.c new file mode 100644 index 0000000..e667668 --- /dev/null +++ b/src/flash/flashchange.c @@ -0,0 +1,8 @@ +#include "PR/os_internal.h" +#include "PR/R4300.h" + +void osFlashChange(u32 flash_num) { + __osFlashHandler.baseAddress = PHYS_TO_K1((FLASH_START_ADDR + flash_num * FLASH_SIZE)); + __osFlashHandler.type = DEVICE_TYPE_FLASH + flash_num; + return; +} diff --git a/src/flash/flashcheckeraseend.c b/src/flash/flashcheckeraseend.c new file mode 100644 index 0000000..47faf5c --- /dev/null +++ b/src/flash/flashcheckeraseend.c @@ -0,0 +1,21 @@ +#include "PR/os_internal.h" + +s32 osFlashCheckEraseEnd(void) { + u8 status; + + osFlashReadStatus(&status); + + if (!(status & FLASH_STATUS_ERASE_BUSY)) { + // not busy, read and clear status + osFlashReadStatus(&status); + osFlashClearStatus(); + + // check for success + if (((status & 0xFF) == 8) || ((status & 0xFF) == 0x48) || ((status & 8) == 8)) { + return FLASH_STATUS_ERASE_OK; + } else { + return FLASH_STATUS_ERASE_ERROR; + } + } + return FLASH_STATUS_ERASE_BUSY; +} diff --git a/src/flash/flashclearstatus.c b/src/flash/flashclearstatus.c new file mode 100644 index 0000000..7622f9c --- /dev/null +++ b/src/flash/flashclearstatus.c @@ -0,0 +1,10 @@ +#include "PR/os_internal.h" + +void osFlashClearStatus(void) { + // select status mode + osEPiWriteIo(&__osFlashHandler, __osFlashHandler.baseAddress | FLASH_CMD_REG, FLASH_CMD_STATUS); + // clear status + osEPiWriteIo(&__osFlashHandler, __osFlashHandler.baseAddress, 0); + + return; +} diff --git a/src/flash/flashgetaddr.c b/src/flash/flashgetaddr.c new file mode 100644 index 0000000..3fe2e37 --- /dev/null +++ b/src/flash/flashgetaddr.c @@ -0,0 +1,7 @@ +#include "PR/os_internal.h" + +u32 __osFlashGetAddr(u32 page_num) { + u32 devAddr = (__osFlashVersion == OLD_FLASH) ? page_num << 6 : page_num << 7; + + return devAddr; +} diff --git a/src/flash/flashinit.c b/src/flash/flashinit.c new file mode 100644 index 0000000..9b51a25 --- /dev/null +++ b/src/flash/flashinit.c @@ -0,0 +1,43 @@ +#include "PR/os_internal.h" +#include "PR/R4300.h" +#include "macros.h" + +OSMesgQueue __osFlashMessageQ ALIGNED(8); +OSMesg __osFlashMsgBuf[1]; +OSPiHandle __osFlashHandler ALIGNED(8); +s32 __osFlashVersion; +OSIoMesg __osFlashMsg ALIGNED(8); +u32 __osFlashID[4] ALIGNED(8); + +OSPiHandle* osFlashInit(void) { + u32 flash_type; + u32 flash_maker; + + osCreateMesgQueue(&__osFlashMessageQ, __osFlashMsgBuf, ARRLEN(__osFlashMsgBuf)); + + if (__osFlashHandler.baseAddress == PHYS_TO_K1(FLASH_START_ADDR)) { + return &__osFlashHandler; + } + + __osFlashHandler.type = DEVICE_TYPE_FLASH; + __osFlashHandler.baseAddress = PHYS_TO_K1(FLASH_START_ADDR); + __osFlashHandler.latency = FLASH_LATENCY; + __osFlashHandler.pulse = FLASH_PULSE; + __osFlashHandler.pageSize = FLASH_PAGE_SIZE; + __osFlashHandler.relDuration = FLASH_REL_DURATION; + __osFlashHandler.domain = PI_DOMAIN2; + __osFlashHandler.speed = 0; + + bzero(&__osFlashHandler.transferInfo, sizeof(__OSTranxInfo)); + + osEPiLinkHandle(&__osFlashHandler); + osFlashReadId(&flash_type, &flash_maker); + + if (flash_maker == FLASH_VERSION_MX_C || flash_maker == FLASH_VERSION_MX_A || flash_maker == FLASH_VERSION_MX_PROTO_A) { + __osFlashVersion = OLD_FLASH; + } else { + __osFlashVersion = NEW_FLASH; + } + + return &__osFlashHandler; +} diff --git a/src/flash/flashreadarray.c b/src/flash/flashreadarray.c new file mode 100644 index 0000000..6134d33 --- /dev/null +++ b/src/flash/flashreadarray.c @@ -0,0 +1,49 @@ +#include "PR/os_internal.h" + +s32 osFlashReadArray(OSIoMesg* mb, s32 priority, u32 page_num, void* dramAddr, u32 n_pages, OSMesgQueue* mq) { + u32 ret; + u32 tmp; + u32 end_page; + u32 one_dma_pages; + + // select read array mode + osEPiWriteIo(&__osFlashHandler, __osFlashHandler.baseAddress | FLASH_CMD_REG, FLASH_CMD_READ_ARRAY); + // dummy read? + osEPiReadIo(&__osFlashHandler, __osFlashHandler.baseAddress, &tmp); + + // DMA requested pages + mb->hdr.pri = priority; + mb->hdr.retQueue = mq; + mb->dramAddr = dramAddr; + + end_page = page_num + n_pages - 1; + + if ((end_page & 0xF00) != (page_num & 0xF00)) { + one_dma_pages = 256 - (page_num & 0xFF); + n_pages -= one_dma_pages; + mb->size = one_dma_pages * FLASH_BLOCK_SIZE; + mb->devAddr = __osFlashGetAddr(page_num); + osEPiStartDma(&__osFlashHandler, mb, OS_READ); + osRecvMesg(mq, NULL, OS_MESG_BLOCK); + page_num = (page_num + 256) & 0xF00; + mb->dramAddr = (u32)mb->dramAddr + mb->size; + } + + while (n_pages > 256) { + one_dma_pages = 256; + n_pages -= 256; + mb->size = one_dma_pages * FLASH_BLOCK_SIZE; + mb->devAddr = __osFlashGetAddr(page_num); + osEPiStartDma(&__osFlashHandler, mb, OS_READ); + osRecvMesg(mq, NULL, OS_MESG_BLOCK); + page_num += 256; + mb->dramAddr = (u32)mb->dramAddr + mb->size; + } + + mb->size = n_pages * FLASH_BLOCK_SIZE; + mb->devAddr = __osFlashGetAddr(page_num); + + ret = osEPiStartDma(&__osFlashHandler, mb, OS_READ); + + return ret; +} diff --git a/src/flash/flashreadid.c b/src/flash/flashreadid.c new file mode 100644 index 0000000..7c8a2c0 --- /dev/null +++ b/src/flash/flashreadid.c @@ -0,0 +1,27 @@ +#include "PR/os_internal.h" + +void osFlashReadId(u32* flash_type, u32* flash_maker) { + u8 tmp; + + // why read status ? + osFlashReadStatus(&tmp); + + // select silicon id read mode + osEPiWriteIo(&__osFlashHandler, __osFlashHandler.baseAddress | FLASH_CMD_REG, FLASH_CMD_ID); + + // read silicon id using DMA + __osFlashMsg.hdr.pri = OS_MESG_PRI_NORMAL; + __osFlashMsg.hdr.retQueue = &__osFlashMessageQ; + __osFlashMsg.dramAddr = __osFlashID; + __osFlashMsg.devAddr = 0; + __osFlashMsg.size = 2 * sizeof(u32); + + osInvalDCache(__osFlashID, sizeof(__osFlashID)); + osEPiStartDma(&__osFlashHandler, &__osFlashMsg, OS_READ); + osRecvMesg(&__osFlashMessageQ, NULL, OS_MESG_BLOCK); + + *flash_type = __osFlashID[0]; + *flash_maker = __osFlashID[1]; + + return; +} diff --git a/src/flash/flashreadstatus.c b/src/flash/flashreadstatus.c new file mode 100644 index 0000000..6bb582b --- /dev/null +++ b/src/flash/flashreadstatus.c @@ -0,0 +1,17 @@ +#include "PR/os_internal.h" + +void osFlashReadStatus(u8* flash_status) { + u32 status; + + osEPiWriteIo(&__osFlashHandler, __osFlashHandler.baseAddress | FLASH_CMD_REG, FLASH_CMD_STATUS); + // read status + osEPiReadIo(&__osFlashHandler, __osFlashHandler.baseAddress, &status); + + // why twice ? + osEPiWriteIo(&__osFlashHandler, __osFlashHandler.baseAddress | FLASH_CMD_REG, FLASH_CMD_STATUS); + osEPiReadIo(&__osFlashHandler, __osFlashHandler.baseAddress, &status); + + *flash_status = status & 0xFF; + + return; +} diff --git a/src/flash/flashreinit.c b/src/flash/flashreinit.c new file mode 100644 index 0000000..deb6070 --- /dev/null +++ b/src/flash/flashreinit.c @@ -0,0 +1,14 @@ +#include "PR/os_internal.h" +#include "PR/R4300.h" + +OSPiHandle* osFlashReInit(u8 latency, u8 pulse, u8 page_size, u8 rel_duration, u32 start) { + __osFlashHandler.baseAddress = PHYS_TO_K1(start); + __osFlashHandler.type++; + __osFlashHandler.latency = latency; + __osFlashHandler.pulse = pulse; + __osFlashHandler.pageSize = page_size; + __osFlashHandler.relDuration = rel_duration; + __osFlashHandler.domain = PI_DOMAIN2; + + return &__osFlashHandler; +} diff --git a/src/flash/flashsectorerase.c b/src/flash/flashsectorerase.c new file mode 100644 index 0000000..fcccc6e --- /dev/null +++ b/src/flash/flashsectorerase.c @@ -0,0 +1,31 @@ +#include "PR/os_internal.h" + +s32 osFlashSectorErase(u32 page_num) { + u32 status; + OSTimer mytimer; + OSMesgQueue timerMesgQueue; + OSMesg dummy; + + // start sector erase operation + osEPiWriteIo(&__osFlashHandler, __osFlashHandler.baseAddress | FLASH_CMD_REG, FLASH_CMD_SECTOR_ERASE | page_num); + osEPiWriteIo(&__osFlashHandler, __osFlashHandler.baseAddress | FLASH_CMD_REG, FLASH_CMD_EXECUTE_ERASE); + + // wait for completion by polling erase-busy flag + osCreateMesgQueue(&timerMesgQueue, &dummy, 1); + + do { + osSetTimer(&mytimer, OS_USEC_TO_CYCLES(12500), 0, &timerMesgQueue, &dummy); + osRecvMesg(&timerMesgQueue, &dummy, OS_MESG_BLOCK); + osEPiReadIo(&__osFlashHandler, __osFlashHandler.baseAddress, &status); + } while ((status & FLASH_STATUS_ERASE_BUSY) == FLASH_STATUS_ERASE_BUSY); + + // check erase operation status, clear status + osEPiReadIo(&__osFlashHandler, __osFlashHandler.baseAddress, &status); + osFlashClearStatus(); + + if (((status & 0xFF) == 8) || ((status & 0xFF) == 0x48) || ((status & 8) == 8)) { + return FLASH_STATUS_ERASE_OK; + } else { + return FLASH_STATUS_ERASE_ERROR; + } +} diff --git a/src/flash/flashsectorerasethrough.c b/src/flash/flashsectorerasethrough.c new file mode 100644 index 0000000..52097e1 --- /dev/null +++ b/src/flash/flashsectorerasethrough.c @@ -0,0 +1,7 @@ +#include "PR/os_internal.h" + +void osFlashSectorEraseThrough(u32 page_num) { + // start sector erase operation + osEPiWriteIo(&__osFlashHandler, __osFlashHandler.baseAddress | FLASH_CMD_REG, FLASH_CMD_SECTOR_ERASE | page_num); + osEPiWriteIo(&__osFlashHandler, __osFlashHandler.baseAddress | FLASH_CMD_REG, FLASH_CMD_EXECUTE_ERASE); +} diff --git a/src/flash/flashwritearray.c b/src/flash/flashwritearray.c new file mode 100644 index 0000000..555f1df --- /dev/null +++ b/src/flash/flashwritearray.c @@ -0,0 +1,33 @@ +#include "PR/os_internal.h" + +s32 osFlashWriteArray(u32 page_num) { + u32 status; + OSTimer mytimer; + OSMesgQueue timerMesgQueue; + OSMesg dummy; + + if (__osFlashVersion == NEW_FLASH) { + osEPiWriteIo(&__osFlashHandler, __osFlashHandler.baseAddress | FLASH_CMD_REG, FLASH_CMD_PAGE_PROGRAM); + } + + // start program page operation + osEPiWriteIo(&__osFlashHandler, __osFlashHandler.baseAddress | FLASH_CMD_REG, FLASH_CMD_PROGRAM_PAGE | page_num); + + // wait for completion by polling write-busy flag + osCreateMesgQueue(&timerMesgQueue, &dummy, 1); + do { + osSetTimer(&mytimer, OS_USEC_TO_CYCLES(200), 0, &timerMesgQueue, &dummy); + osRecvMesg(&timerMesgQueue, &dummy, OS_MESG_BLOCK); + osEPiReadIo(&__osFlashHandler, __osFlashHandler.baseAddress, &status); + } while ((status & FLASH_STATUS_WRITE_BUSY) == FLASH_STATUS_WRITE_BUSY); + + // check program operation status, clear status + osEPiReadIo(&__osFlashHandler, __osFlashHandler.baseAddress, &status); + osFlashClearStatus(); + + if (((status & 0xFF) == 4) || ((status & 0xFF) == 0x44) || ((status & 4) == 4)) { + return FLASH_STATUS_WRITE_OK; + } else { + return FLASH_STATUS_WRITE_ERROR; + } +} diff --git a/src/flash/flashwritebuffer.c b/src/flash/flashwritebuffer.c new file mode 100644 index 0000000..8cbd0c9 --- /dev/null +++ b/src/flash/flashwritebuffer.c @@ -0,0 +1,19 @@ +#include "PR/os_internal.h" + +s32 osFlashWriteBuffer(OSIoMesg* mb, s32 priority, void* dramAddr, OSMesgQueue* mq) { + s32 ret; + + // select page program mode + osEPiWriteIo(&__osFlashHandler, __osFlashHandler.baseAddress | FLASH_CMD_REG, FLASH_CMD_PAGE_PROGRAM); + + // DMA 128-byte page + mb->hdr.pri = priority; + mb->hdr.retQueue = mq; + mb->dramAddr = dramAddr; + mb->devAddr = 0; + mb->size = FLASH_BLOCK_SIZE; + + ret = osEPiStartDma(&__osFlashHandler, mb, OS_WRITE); + + return ret; +} diff --git a/src/io/epidma.c b/src/io/epidma.c new file mode 100644 index 0000000..d122791 --- /dev/null +++ b/src/io/epidma.c @@ -0,0 +1,24 @@ +#include "piint.h" + +s32 osEPiStartDma(OSPiHandle* pihandle, OSIoMesg* mb, s32 direction) { + s32 ret; + + if (!__osPiDevMgr.active) { + return -1; + } + mb->piHandle = pihandle; + + if (direction == OS_READ) { + mb->hdr.type = OS_MESG_TYPE_EDMAREAD; + } else { + mb->hdr.type = OS_MESG_TYPE_EDMAWRITE; + } + + if (mb->hdr.pri == OS_MESG_PRI_HIGH) { + ret = osJamMesg(osPiGetCmdQueue(), (OSMesg)mb, OS_MESG_NOBLOCK); + } else { + ret = osSendMesg(osPiGetCmdQueue(), (OSMesg)mb, OS_MESG_NOBLOCK); + } + + return ret; +} diff --git a/src/io/epigettype.c b/src/io/epigettype.c new file mode 100644 index 0000000..ef749ea --- /dev/null +++ b/src/io/epigettype.c @@ -0,0 +1,8 @@ +#include "piint.h" + +s32 osEPiGetDeviceType(OSPiHandle *pihandle, OSPiInfo *info) +{ + info->type = pihandle->type; + info->address = pihandle->baseAddress; + return 0; +} diff --git a/src/io/epilinkhandle.c b/src/io/epilinkhandle.c new file mode 100644 index 0000000..8785bdb --- /dev/null +++ b/src/io/epilinkhandle.c @@ -0,0 +1,12 @@ +#include "piint.h" + +s32 osEPiLinkHandle(OSPiHandle *EPiHandle) +{ + register s32 saveMask = __osDisableInt(); + + EPiHandle->next = __osPiTable; + __osPiTable = EPiHandle; + + __osRestoreInt(saveMask); + return 0; +} diff --git a/src/io/epirawdma.c b/src/io/epirawdma.c new file mode 100644 index 0000000..63ad6cf --- /dev/null +++ b/src/io/epirawdma.c @@ -0,0 +1,27 @@ +#include "piint.h" + +// TODO: this comes from a header +#ident "$Revision: 1.17 $" + +s32 __osEPiRawStartDma(OSPiHandle *pihandle, s32 direction, u32 devAddr, void *dramAddr, u32 size) +{ + u32 stat; + u32 domain; + + EPI_SYNC(pihandle, stat, domain); + IO_WRITE(PI_DRAM_ADDR_REG, osVirtualToPhysical(dramAddr)); + IO_WRITE(PI_CART_ADDR_REG, K1_TO_PHYS(pihandle->baseAddress | devAddr)); + + switch (direction) + { + case OS_READ: + IO_WRITE(PI_WR_LEN_REG, size - 1); + break; + case OS_WRITE: + IO_WRITE(PI_RD_LEN_REG, size - 1); + break; + default: + return -1; + } + return 0; +} diff --git a/src/io/epirawread.c b/src/io/epirawread.c new file mode 100644 index 0000000..7871f56 --- /dev/null +++ b/src/io/epirawread.c @@ -0,0 +1,14 @@ +#include "piint.h" + +// TODO: this comes from a header +#ident "$Revision: 1.17 $" + +s32 __osEPiRawReadIo(OSPiHandle* pihandle, u32 devAddr, u32* data) { + u32 stat; + u32 domain; + + EPI_SYNC(pihandle, stat, domain); + *data = IO_READ(pihandle->baseAddress | devAddr); + + return 0; +} diff --git a/src/io/epirawwrite.c b/src/io/epirawwrite.c new file mode 100644 index 0000000..5cc1752 --- /dev/null +++ b/src/io/epirawwrite.c @@ -0,0 +1,14 @@ +#include "piint.h" + +// TODO: this comes from a header +#ident "$Revision: 1.17 $" + +s32 __osEPiRawWriteIo(OSPiHandle* pihandle, u32 devAddr, u32 data) { + u32 stat; + u32 domain; + + EPI_SYNC(pihandle, stat, domain); + IO_WRITE(pihandle->baseAddress | devAddr, data); + + return 0; +} diff --git a/src/io/epiread.c b/src/io/epiread.c new file mode 100644 index 0000000..3918c5f --- /dev/null +++ b/src/io/epiread.c @@ -0,0 +1,13 @@ +#include "piint.h" + +s32 __osEPiRawReadIo(OSPiHandle*, u32, u32*); + +s32 osEPiReadIo(OSPiHandle* pihandle, u32 devAddr, u32* data) { + register s32 ret; + + __osPiGetAccess(); + ret = __osEPiRawReadIo(pihandle, devAddr, data); + __osPiRelAccess(); + + return ret; +} diff --git a/src/io/epiwrite.c b/src/io/epiwrite.c new file mode 100644 index 0000000..1a4c462 --- /dev/null +++ b/src/io/epiwrite.c @@ -0,0 +1,13 @@ +#include "piint.h" + +s32 __osEPiRawWriteIo(OSPiHandle*, u32, u32); + +s32 osEPiWriteIo(OSPiHandle* pihandle, u32 devAddr, u32 data) { + register s32 ret; + + __osPiGetAccess(); + ret = __osEPiRawWriteIo(pihandle, devAddr, data); + __osPiRelAccess(); + + return ret; +} diff --git a/src/io/piint.h b/src/io/piint.h new file mode 100644 index 0000000..a695bfd --- /dev/null +++ b/src/io/piint.h @@ -0,0 +1,59 @@ +#ifndef _PIINT_H_ +#define _PIINT_H_ + +#include "PR/os_internal.h" +#include "PR/rcp.h" + +extern OSDevMgr __osPiDevMgr; +extern OSPiHandle *__osCurrentHandle[2]; +extern OSPiHandle CartRomHandle; +extern OSPiHandle LeoDiskHandle; +extern OSMesgQueue __osPiAccessQueue; +extern u32 __osPiAccessQueueEnabled; + +int __osPiDeviceBusy(void); +void __osDevMgrMain(void *); +void __osPiCreateAccessQueue(void); +void __osPiRelAccess(void); +void __osPiGetAccess(void); +OSMesgQueue *osPiGetCmdQueue(void); + +#define WAIT_ON_IOBUSY(stat) \ + while (stat = IO_READ(PI_STATUS_REG), stat & (PI_STATUS_IO_BUSY | PI_STATUS_DMA_BUSY)) \ + ; \ + (void)0 + +#define UPDATE_REG(pihandle, reg, var) \ + if (cHandle->var != pihandle->var) \ + IO_WRITE(reg, pihandle->var) + +#define EPI_SYNC(pihandle, stat, domain) \ + \ + WAIT_ON_IOBUSY(stat); \ + \ + domain = pihandle->domain; \ + if (__osCurrentHandle[domain]->type != pihandle->type) \ + { \ + OSPiHandle *cHandle = __osCurrentHandle[domain]; \ + if (domain == PI_DOMAIN1) \ + { \ + UPDATE_REG(pihandle, PI_BSD_DOM1_LAT_REG, latency); \ + UPDATE_REG(pihandle, PI_BSD_DOM1_PGS_REG, pageSize); \ + UPDATE_REG(pihandle, PI_BSD_DOM1_RLS_REG, relDuration); \ + UPDATE_REG(pihandle, PI_BSD_DOM1_PWD_REG, pulse); \ + } \ + else \ + { \ + UPDATE_REG(pihandle, PI_BSD_DOM2_LAT_REG, latency); \ + UPDATE_REG(pihandle, PI_BSD_DOM2_PGS_REG, pageSize); \ + UPDATE_REG(pihandle, PI_BSD_DOM2_RLS_REG, relDuration); \ + UPDATE_REG(pihandle, PI_BSD_DOM2_PWD_REG, pulse); \ + } \ + cHandle->type = pihandle->type; \ + cHandle->latency = pihandle->latency; \ + cHandle->pageSize = pihandle->pageSize; \ + cHandle->relDuration = pihandle->relDuration; \ + cHandle->pulse = pihandle->pulse; \ + }(void)0 + +#endif diff --git a/src/io/pirawdma.c b/src/io/pirawdma.c new file mode 100644 index 0000000..28b19a5 --- /dev/null +++ b/src/io/pirawdma.c @@ -0,0 +1,25 @@ +#include "piint.h" + +// TODO: this comes from a header +#ident "$Revision: 1.17 $" + +s32 __osPiRawStartDma(s32 direction, u32 devAddr, void* dramAddr, size_t size) { + register u32 stat; + + WAIT_ON_IOBUSY(stat); + + IO_WRITE(PI_DRAM_ADDR_REG, osVirtualToPhysical(dramAddr)); + IO_WRITE(PI_CART_ADDR_REG, K1_TO_PHYS((u32)osRomBase | devAddr)); + + switch (direction) { + case OS_READ: + IO_WRITE(PI_WR_LEN_REG, size - 1); + break; + case OS_WRITE: + IO_WRITE(PI_RD_LEN_REG, size - 1); + break; + default: + return -1; + } + return 0; +} diff --git a/src/io/pirawread.c b/src/io/pirawread.c new file mode 100644 index 0000000..8531d17 --- /dev/null +++ b/src/io/pirawread.c @@ -0,0 +1,13 @@ +#include "piint.h" + +// TODO: this comes from a header +#ident "$Revision: 1.17 $" + +s32 __osPiRawReadIo(u32 devAddr, u32* data) { + register u32 stat; + + WAIT_ON_IOBUSY(stat); + *data = IO_READ((u32)osRomBase | devAddr); + + return 0; +} diff --git a/src/io/pirawwrite.c b/src/io/pirawwrite.c new file mode 100644 index 0000000..5e9d7c5 --- /dev/null +++ b/src/io/pirawwrite.c @@ -0,0 +1,13 @@ +#include "piint.h" + +// TODO: this comes from a header +#ident "$Revision: 1.17 $" + +s32 __osPiRawWriteIo(u32 devAddr, u32 data) { + register u32 stat; + + WAIT_ON_IOBUSY(stat); + IO_WRITE((u32)osRomBase | devAddr, data); + + return 0; +} diff --git a/src/io/piread.c b/src/io/piread.c new file mode 100644 index 0000000..2fed7a6 --- /dev/null +++ b/src/io/piread.c @@ -0,0 +1,13 @@ +#include "piint.h" + +s32 __osPiRawReadIo(u32, u32*); + +s32 osPiReadIo(u32 devAddr, u32* data) { + register s32 ret; + + __osPiGetAccess(); + ret = __osPiRawReadIo(devAddr, data); + __osPiRelAccess(); + + return ret; +} diff --git a/src/io/piwrite.c b/src/io/piwrite.c new file mode 100644 index 0000000..9935331 --- /dev/null +++ b/src/io/piwrite.c @@ -0,0 +1,13 @@ +#include "piint.h" + +s32 __osPiRawWriteIo(u32, u32); + +s32 osPiWriteIo(u32 devAddr, u32 data) { + register s32 ret; + + __osPiGetAccess(); + ret = __osPiRawWriteIo(devAddr, data); + __osPiRelAccess(); + + return ret; +} diff --git a/tools/disassemble_elf.py b/tools/disassemble_elf.py new file mode 100644 index 0000000..ef9c919 --- /dev/null +++ b/tools/disassemble_elf.py @@ -0,0 +1,292 @@ +#!/usr/bin/env python3 +# +# ELF disassembler that attempts to be matching +# + +import argparse, struct, sys + +from libelf import * +from mips_isa import * +from util import * + +def debug_log(msg): + print(msg, file=sys.stderr) + +class MipsDisasm: + """ + """ + + def __init__(self, elf_file) -> None: + self.elf_file = elf_file + mdebug_section = elf_file.find_section_by_type(SHT_MIPS_DEBUG) + if mdebug_section is not None: + self.mdebug = mdebug_section + self.has_mdebug = True + else: + self.has_mdebug = False + self.cur_file = None + self.comment_section_pos = 1 + self.section_local_labels = {} + + def add_section_local_label(self, section, offset): + if section not in self.section_local_labels: + self.section_local_labels.update({section : set()}) + self.section_local_labels[section].add(offset) + + def advance_file(self): + seen_cur_file = False + for sym in self.elf_file.symtab.symbol_entries: + if sym.type == ST_FILE: + if seen_cur_file or self.cur_file is None: + self.cur_file = sym + break + elif self.cur_file == sym: + seen_cur_file = True + + def disassemble_all_sections(self): + print(MipsDisasm.asm_prelude()) + + # debug_log("Name Type Addr Off Size ES Flg Lk Inf Al") + for section in self.elf_file.sections: + local_labels = self.section_local_labels.get(section.name, None) + # debug_log(section) + if section.name in ['', '.strtab', '.shstrtab', '.symtab', '.reginfo', '.comment', '.note'] or \ + (section.sh_type == SHT_REL or section.sh_type == SHT_RELA): + continue + if section.sh_size == 0: + continue + print("") + print(MipsDisasm.begin_section(section)) + if section.is_executable(): + self.disassemble_exec(section) + elif section.sh_type == SHT_PROGBITS: + # TODO kmc as doesn't support incbin, byte array this + # print(f".incbin \"libultra.a\", 0x{section.sh_offset:08X}, 0x{section.sh_size:X}") + first = True + for i,b in enumerate(section.data): + if local_labels is not None and i in local_labels: + if not first: + print("") + print(f".{section.name[1].upper()}_{i:08X}:") + print(" .byte ", end='') + first = True + elif first: + print(" .byte ", end='') + if not first: + print(", ", end='') + print(f"0x{int(b):02X}", end='') + first = False + print("") + elif section.sh_type == SHT_NOBITS: + print(f".skip 0x{section.sh_size:X}") + else: + assert False, f"Unhandled section: {section.name}" + # debug_log("/// UNHANDLED ///") + + def pass_section(self, section): + pass + + @staticmethod + def asm_prelude(): + return f""".include "macro.inc" +#include "regdef.h" + +// assembler directives +.set noat // allow manual use of $at +.set noreorder // don't insert nops after branches""" + + @staticmethod + def begin_section(section): + section_flags = section.flags_str().lower().replace(' ', '') + if section_flags != "": + section_flags = f", \"{section_flags}\"" + section_type = "" + if section.sh_type == SHT_PROGBITS: + section_type = ", @progbits" + elif section.sh_type == SHT_NOBITS: + section_type = ", @nobits" + if section_type != "" and section_flags == "": + section_flags = ", \"\"" + + return f""".section {section.name}{section_flags}{section_type} +.balign {section.sh_addralign} +""" + + def get_comment_string(self, start): + comment_section = self.elf_file.find_section_by_name(".comment") + end = comment_section.data.find(b'\0', start) + if end == -1: + return None, None + comment = comment_section.data[start:end].decode("ASCII") + return comment, end + 1 + + def print_end(self, vaddr, eof): + ends = eof.get(vaddr, None) + if ends is not None: + for sym in ends: + print(f" .type {sym.name}, @{'function' if sym.type == ST_FUNC else 'object'}") + if sym.st_size != 0: + print(f" .size {sym.name}, . - {sym.name}") + print(f" .end {sym.name}\n") + + def disassemble_exec(self, section): + raw_insns = as_word_list(section.data) + insns = [decode_insn(raw, section.sh_addr + j * 4) for j,raw in enumerate(raw_insns)] + + # enumerate branch labels + branch_labels = set() + + for i,insn in enumerate(insns): + if insn.id in MIPS_BRANCH_INSNS or insn.id == MIPS_INS_J: + branch_labels.add(insn.target if insn.id == MIPS_INS_J else insn.offset) + + eof = {} # vaddr : name + def add_end(vaddr, sym): + if vaddr not in eof: + eof[vaddr] = set() + eof[vaddr].add(sym) + + cur_fdr = None + cur_pdr = None + for i,insn in enumerate(insns): + mnemonic = insn.mnemonic + op_str = insn.op_str + + # Update mdebug info + src_inf = "" + if self.has_mdebug: + # Get new fdr if there is one + fdr = self.mdebug.fdr_foraddr(i * 4) + if fdr is not None: + # debug_log(fdr.name) + cur_fdr = fdr + + # Get new pdr if there is one + pdr = cur_fdr.pdr_foraddr(i * 4) + if pdr is not None: + # debug_log(pdr) + cur_pdr = pdr + + # Line numbers + if cur_pdr is not None: + asm_line = i - cur_pdr.addr//4 + if asm_line < len(cur_pdr.lines): + src_inf = f" {cur_pdr.lines[asm_line]:4}" + else: + src_inf = " PADDING" + + # Symbols for this address + syms = section.get_sym(i * 4) + # if len(syms) != 0: + # debug_log("\n".join([str(sym) for sym in syms])) + + # Print end + self.print_end(insn.vaddr, eof) + + # Print symbol + for sym in syms: + if sym.name == "gcc2_compiled.": + print(f"// compiler generated") + if self.cur_file is None: + print(f".version \"01.01\"") + self.advance_file() + print(f".file 1 \"{self.cur_file.name}\"") + + comment_string = None + while comment_string != "\"GCC: (GNU) 2.7.2\"": + comment_string, self.comment_section_pos = self.get_comment_string(self.comment_section_pos) + if comment_string is None: + break + print(f".ident \"{comment_string}\"") + + if sym.bind == SB_GLOBAL: + print(f"glabel {sym.name}") + else: + print(f"{sym.name}:") + + if sym.st_size != 0: + print(f" .ent {sym.name}") + add_end(insn.vaddr + sym.st_size, sym) + else: + print(f" .type {sym.name}, @{'function' if sym.type == ST_FUNC else 'object'}\n") + + # Print branch labels + if insn.vaddr in branch_labels: + print(f".L{insn.vaddr:08X}:") + + # Relocations for this address + rels = section.get_rel(i * 4) + assert len(rels) < 2 # There should never be more than 1 relocation for a single address, right? + # if len(rels) != 0: + # debug_log("\n".join([str(rel) for rel in rels])) + + # Apply relocation + if len(rels) != 0: + rel = rels[0] + if rel.rel_type == R_MIPS_26: + if insn.id == MIPS_INS_JAL: + op_str = rel.relocated_symbol.name + elif insn.id != MIPS_INS_J: # Branch labels for j instructions are also R_MIPS_26 relocations + assert False , f"Got unexpected R_MIPS_26 relocation {insn.id}" + elif rel.rel_type == R_MIPS_HI16: + assert insn.id in [MIPS_INS_LUI] + rel_name = rel.relocated_symbol.name + if rel.relocated_symbol.type == ST_SECTION: + rel_name = f".{rel_name[1].upper()}_00000000" + + op_str = f"{insn.abi.gpr_names[insn.rt]}, %hi({rel_name})" + elif rel.rel_type == R_MIPS_LO16: + # Ideally this should be in the elf code so the relocations don't look identical + addend = insn.imm + rel_name = rel.relocated_symbol.name + if rel.relocated_symbol.type == ST_SECTION: + rel_name = f".{rel_name[1].upper()}_{addend:08X}" + self.add_section_local_label(rel.relocated_symbol.name, addend) + addend = 0 + addend_str = f" + 0x{addend:X}" if addend != 0 else "" + + if insn.id == MIPS_INS_ADDIU: + op_str = f"{insn.abi.gpr_names[insn.rt]}, {insn.abi.gpr_names[insn.rs]}, %lo({rel_name}{addend_str})" + elif insn.id in MIPS_LOAD_STORE_INSNS: + if insn.id in MIPS_FP_LOAD_STORE_INSNS: + op_str = f"{insn.abi.cop1_names[insn.ft]}, " + else: + op_str = f"{insn.abi.gpr_names[insn.rt]}, " + op_str += f"%lo({rel_name}{addend_str})({insn.abi.gpr_names[insn.base]})" + else: + assert False + else: + assert False + + # Apply branch labels + if insn.id in MIPS_BRANCH_INSNS: + op_str_parts = [] + for field in insn.fields: + if field == 'offset': + op_str_parts.append(f".L{insn.offset:08X}") + else: + op_str_parts.append(insn.format_field(field)) + op_str = ", ".join(op_str_parts) + elif insn.id == MIPS_INS_J: + op_str = f".L{insn.target:08X}" + + print(f"/* {section.sh_offset + i * 4:06X} {insn.vaddr:08X} {insn.raw:08X}{src_inf} */ {mnemonic:12}{op_str:35}".rstrip()) + self.print_end(section.sh_addr + section.sh_size, eof) + +def main(): + parser = argparse.ArgumentParser(description="Disassemble relocatable ELF object.") + parser.add_argument("filepath", help="path to the ELF file") + # TODO unimplemented optionals + parser.add_argument("--compiler", help="original compiler that produced the ELF (IDO or GCC, IDO default)", default="IDO") + parser.add_argument("--strenc", help="string encoding, default is EUC-JP for IDO and SJIS for GCC") + args = parser.parse_args() + + elf_file = None + with open(args.filepath, "rb") as elf: + elf_file = ElfFile(bytearray(elf.read())) + + disassembler = MipsDisasm(elf_file) + disassembler.disassemble_all_sections() + +if __name__ == '__main__': + main() diff --git a/tools/mdebug.py b/tools/mdebug.py index bc45051..f643725 100644 --- a/tools/mdebug.py +++ b/tools/mdebug.py @@ -426,7 +426,7 @@ class EcoffSymr: if self.st == EcoffSt.STATICPROC: self.c_repr += "static " - self.return_type = self.process_type_information(1) + self.return_type, _ = self.process_type_information(1) self.c_repr += self.return_type if len(self.return_type) != 0: self.c_repr += " " @@ -438,13 +438,15 @@ class EcoffSymr: # value of a stMember is the offset in bits self.c_repr += f"/* 0x{self.value//8:X} */ " - self.c_repr += self.process_type_information(0) + type_str, bitwidth = self.process_type_information(0) + self.c_repr += type_str if len(self.c_repr) != 0: self.c_repr += " " - self.c_repr += f"{self.name};" + self.c_repr += f"{self.name}{f' : {bitwidth}' if bitwidth is not None else ''};" elif self.st == EcoffSt.TYPEDEF: # TODO the typedef may already be absorbed into a struct or similar, check before emitting - self.c_repr = f"typedef {self.type_name} {self.name};" + type_str, _ = self.process_type_information(0) + self.c_repr = f"typedef {type_str} {self.name};" def process_type_information(self, ind): c_bt_names = { @@ -499,8 +501,9 @@ class EcoffSymr: ind += 1 type_str = "" + bit_width = None if aux.ti.fBitfield == 1: - # TODO + bit_width = self.fdr.auxs[self.index + ind].isym ind += 1 if aux.ti.bt in [EcoffBt.STRUCT, EcoffBt.UNION, EcoffBt.ENUM, EcoffBt.TYPEDEF]: @@ -541,7 +544,7 @@ class EcoffSymr: if len(tqs) != 0: type_str += " " + tqs - return type_str + return type_str, bit_width def __str__(self) -> str: return f"""= EcoffSymr ============== {self.idx} diff --git a/tools/mips_isa.py b/tools/mips_isa.py new file mode 100644 index 0000000..d99dcda --- /dev/null +++ b/tools/mips_isa.py @@ -0,0 +1,1309 @@ +# TODO enum these constants +from enum import IntEnum, auto + +# Register IDs +class MipsGPReg(IntEnum): + R0 = 0 # 0 + AT = auto() # 1 + V0 = auto() # 2 + V1 = auto() # 3 + A0 = auto() # 4 + A1 = auto() # 5 + A2 = auto() # 6 + A3 = auto() # 7 + T0 = auto() # 8 + T1 = auto() # 9 + T2 = auto() # 10 + T3 = auto() # 11 + T4 = auto() # 12 + T5 = auto() # 13 + T6 = auto() # 14 + T7 = auto() # 15 + S0 = auto() # 16 + S1 = auto() # 17 + S2 = auto() # 18 + S3 = auto() # 19 + S4 = auto() # 20 + S5 = auto() # 21 + S6 = auto() # 22 + S7 = auto() # 23 + T8 = auto() # 24 + T9 = auto() # 25 + K0 = auto() # 26 + K1 = auto() # 27 + GP = auto() # 28 + SP = auto() # 29 + FP = auto() # 30 + RA = auto() # 31 + +class MipsFPReg(IntEnum): + F0 = 0 # 0 + F1 = auto() # 1 + F2 = auto() # 2 + F3 = auto() # 3 + F4 = auto() # 4 + F5 = auto() # 5 + F6 = auto() # 6 + F7 = auto() # 7 + F8 = auto() # 8 + F9 = auto() # 9 + F10 = auto() # 10 + F11 = auto() # 11 + F12 = auto() # 12 + F13 = auto() # 13 + F14 = auto() # 14 + F15 = auto() # 15 + F16 = auto() # 16 + F17 = auto() # 17 + F18 = auto() # 18 + F19 = auto() # 19 + F20 = auto() # 20 + F21 = auto() # 21 + F22 = auto() # 22 + F23 = auto() # 23 + F24 = auto() # 24 + F25 = auto() # 25 + F26 = auto() # 26 + F27 = auto() # 27 + F28 = auto() # 28 + F29 = auto() # 29 + F30 = auto() # 30 + F31 = auto() # 31 + +# Instruction Unique IDs +MIPS_INS_SLL = 0 +MIPS_INS_SRL = 1 +MIPS_INS_SRA = 2 +MIPS_INS_SLLV = 3 +MIPS_INS_SRLV = 4 +MIPS_INS_SRAV = 5 +MIPS_INS_JR = 6 +MIPS_INS_JALR = 7 +MIPS_INS_SYSCALL = 8 +MIPS_INS_BREAK = 9 +MIPS_INS_SYNC = 10 +MIPS_INS_MFHI = 11 +MIPS_INS_MTHI = 12 +MIPS_INS_MFLO = 13 +MIPS_INS_MTLO = 14 +MIPS_INS_DSLLV = 15 +MIPS_INS_DSRLV = 16 +MIPS_INS_DSRAV = 17 +MIPS_INS_MULT = 18 +MIPS_INS_MULTU = 19 +MIPS_INS_DIV = 20 +MIPS_INS_DIVU = 21 +MIPS_INS_DMULT = 22 +MIPS_INS_DMULTU = 23 +MIPS_INS_DDIV = 24 +MIPS_INS_DDIVU = 25 +MIPS_INS_ADD = 26 +MIPS_INS_ADDU = 27 +MIPS_INS_SUB = 28 +MIPS_INS_SUBU = 29 +MIPS_INS_AND = 30 +MIPS_INS_OR = 31 +MIPS_INS_XOR = 32 +MIPS_INS_NOR = 33 +MIPS_INS_SLT = 34 +MIPS_INS_SLTU = 35 +MIPS_INS_DADD = 36 +MIPS_INS_DADDU = 37 +MIPS_INS_DSUB = 38 +MIPS_INS_DSUBU = 39 +MIPS_INS_TGE = 40 +MIPS_INS_TGEU = 41 +MIPS_INS_TLT = 42 +MIPS_INS_TLTU = 43 +MIPS_INS_TEQ = 44 +MIPS_INS_TNE = 45 +MIPS_INS_DSLL = 46 +MIPS_INS_DSRL = 47 +MIPS_INS_DSRA = 48 +MIPS_INS_DSLL32 = 49 +MIPS_INS_DSRL32 = 50 +MIPS_INS_DSRA32 = 51 +MIPS_INS_BLTZ = 52 +MIPS_INS_BGEZ = 53 +MIPS_INS_BLTZL = 54 +MIPS_INS_BGEZL = 55 +MIPS_INS_TGEI = 56 +MIPS_INS_TGEIU = 57 +MIPS_INS_TLTI = 58 +MIPS_INS_TLTIU = 59 +MIPS_INS_TEQI = 60 +MIPS_INS_TNEI = 61 +MIPS_INS_BLTZAL = 62 +MIPS_INS_BGEZAL = 63 +MIPS_INS_BLTZALL = 64 +MIPS_INS_BGEZALL = 65 +MIPS_INS_J = 66 +MIPS_INS_JAL = 67 +MIPS_INS_BEQ = 68 +MIPS_INS_BNE = 69 +MIPS_INS_BLEZ = 70 +MIPS_INS_BGTZ = 71 +MIPS_INS_ADDI = 72 +MIPS_INS_ADDIU = 73 +MIPS_INS_SLTI = 74 +MIPS_INS_SLTIU = 75 +MIPS_INS_ANDI = 76 +MIPS_INS_ORI = 77 +MIPS_INS_XORI = 78 +MIPS_INS_LUI = 79 +MIPS_INS_MFC0 = 80 +MIPS_INS_MTC0 = 81 +MIPS_INS_TLBR = 82 +MIPS_INS_TLBWI = 83 +MIPS_INS_TLBWR = 84 +MIPS_INS_TLBP = 85 +MIPS_INS_ERET = 86 +MIPS_INS_MFC1 = 87 +MIPS_INS_DMFC1 = 88 +MIPS_INS_CFC1 = 89 +MIPS_INS_MTC1 = 90 +MIPS_INS_DMTC1 = 91 +MIPS_INS_CTC1 = 92 +MIPS_INS_BC1F = 93 +MIPS_INS_BC1T = 94 +MIPS_INS_BC1FL = 95 +MIPS_INS_BC1TL = 96 +MIPS_INS_ADD_S = 97 +MIPS_INS_SUB_S = 98 +MIPS_INS_MUL_S = 99 +MIPS_INS_DIV_S = 100 +MIPS_INS_SQRT_S = 101 +MIPS_INS_ABS_S = 102 +MIPS_INS_MOV_S = 103 +MIPS_INS_NEG_S = 104 +MIPS_INS_ROUND_L_S = 105 +MIPS_INS_TRUNC_L_S = 106 +MIPS_INS_CEIL_L_S = 107 +MIPS_INS_FLOOR_L_S = 108 +MIPS_INS_ROUND_W_S = 109 +MIPS_INS_TRUNC_W_S = 110 +MIPS_INS_CEIL_W_S = 111 +MIPS_INS_FLOOR_W_S = 112 +MIPS_INS_CVT_D_S = 113 +MIPS_INS_CVT_W_S = 114 +MIPS_INS_CVT_L_S = 115 +MIPS_INS_C_F_S = 116 +MIPS_INS_C_UN_S = 117 +MIPS_INS_C_EQ_S = 118 +MIPS_INS_C_UEQ_S = 119 +MIPS_INS_C_OLT_S = 120 +MIPS_INS_C_ULT_S = 121 +MIPS_INS_C_OLE_S = 122 +MIPS_INS_C_ULE_S = 123 +MIPS_INS_C_SF_S = 124 +MIPS_INS_C_NGLE_S = 125 +MIPS_INS_C_SEQ_S = 126 +MIPS_INS_C_NGL_S = 127 +MIPS_INS_C_LT_S = 128 +MIPS_INS_C_NGE_S = 129 +MIPS_INS_C_LE_S = 130 +MIPS_INS_C_NGT_S = 131 +MIPS_INS_ADD_D = 132 +MIPS_INS_SUB_D = 133 +MIPS_INS_MUL_D = 134 +MIPS_INS_DIV_D = 135 +MIPS_INS_SQRT_D = 136 +MIPS_INS_ABS_D = 137 +MIPS_INS_MOV_D = 138 +MIPS_INS_NEG_D = 139 +MIPS_INS_ROUND_L_D = 140 +MIPS_INS_TRUNC_L_D = 141 +MIPS_INS_CEIL_L_D = 142 +MIPS_INS_FLOOR_L_D = 143 +MIPS_INS_ROUND_W_D = 144 +MIPS_INS_TRUNC_W_D = 145 +MIPS_INS_CEIL_W_D = 146 +MIPS_INS_FLOOR_W_D = 147 +MIPS_INS_CVT_S_D = 148 +MIPS_INS_CVT_W_D = 149 +MIPS_INS_CVT_L_D = 150 +MIPS_INS_C_F_D = 151 +MIPS_INS_C_UN_D = 152 +MIPS_INS_C_EQ_D = 153 +MIPS_INS_C_UEQ_D = 154 +MIPS_INS_C_OLT_D = 155 +MIPS_INS_C_ULT_D = 156 +MIPS_INS_C_OLE_D = 157 +MIPS_INS_C_ULE_D = 158 +MIPS_INS_C_SF_D = 159 +MIPS_INS_C_NGLE_D = 160 +MIPS_INS_C_SEQ_D = 161 +MIPS_INS_C_NGL_D = 162 +MIPS_INS_C_LT_D = 163 +MIPS_INS_C_NGE_D = 164 +MIPS_INS_C_LE_D = 165 +MIPS_INS_C_NGT_D = 166 +MIPS_INS_CVT_S_W = 167 +MIPS_INS_CVT_D_W = 168 +MIPS_INS_CVT_S_L = 169 +MIPS_INS_CVT_D_L = 170 +MIPS_INS_BEQL = 171 +MIPS_INS_BNEL = 172 +MIPS_INS_BLEZL = 173 +MIPS_INS_BGTZL = 174 +MIPS_INS_DADDI = 175 +MIPS_INS_DADDIU = 176 +MIPS_INS_LDL = 177 +MIPS_INS_LDR = 178 +MIPS_INS_LB = 179 +MIPS_INS_LH = 180 +MIPS_INS_LWL = 181 +MIPS_INS_LW = 182 +MIPS_INS_LBU = 183 +MIPS_INS_LHU = 184 +MIPS_INS_LWR = 185 +MIPS_INS_LWU = 186 +MIPS_INS_SB = 187 +MIPS_INS_SH = 188 +MIPS_INS_SWL = 189 +MIPS_INS_SW = 190 +MIPS_INS_SDL = 191 +MIPS_INS_SDR = 192 +MIPS_INS_SWR = 193 +MIPS_INS_CACHE = 194 +MIPS_INS_LL = 195 +MIPS_INS_LWC1 = 196 +MIPS_INS_LWC2 = 197 +MIPS_INS_LLD = 198 +MIPS_INS_LDC1 = 199 +MIPS_INS_LDC2 = 200 +MIPS_INS_LD = 201 +MIPS_INS_SC = 202 +MIPS_INS_SWC1 = 203 +MIPS_INS_SWC2 = 204 +MIPS_INS_SCD = 205 +MIPS_INS_SDC1 = 206 +MIPS_INS_SDC2 = 207 +MIPS_INS_SD = 208 + +# RSP COP2 +MIPS_INS_VMULF = 209 +MIPS_INS_VMULU = 210 +MIPS_INS_VRNDP = 211 +MIPS_INS_VMULQ = 212 +MIPS_INS_VMUDL = 213 +MIPS_INS_VMUDM = 214 +MIPS_INS_VMUDN = 215 +MIPS_INS_VMUDH = 216 +MIPS_INS_VMACF = 217 +MIPS_INS_VMACU = 218 +MIPS_INS_VRNDN = 219 +MIPS_INS_VMACQ = 220 +MIPS_INS_VMADL = 221 +MIPS_INS_VMADM = 222 +MIPS_INS_VMADN = 223 +MIPS_INS_VMADH = 224 +MIPS_INS_VADD = 225 +MIPS_INS_VSUB = 226 +MIPS_INS_VABS = 227 +MIPS_INS_VADDC = 228 +MIPS_INS_VSUBC = 229 +MIPS_INS_VSAR = 230 +MIPS_INS_VLT = 231 +MIPS_INS_VEQ = 232 +MIPS_INS_VNE = 233 +MIPS_INS_VGE = 234 +MIPS_INS_VCL = 235 +MIPS_INS_VCH = 236 +MIPS_INS_VCR = 237 +MIPS_INS_VMRG = 238 +MIPS_INS_VAND = 239 +MIPS_INS_VNAND = 240 +MIPS_INS_VOR = 241 +MIPS_INS_VNOR = 242 +MIPS_INS_VXOR = 243 +MIPS_INS_VNXOR = 244 +MIPS_INS_VRCP = 245 +MIPS_INS_VRCPL = 246 +MIPS_INS_VRCPH = 247 +MIPS_INS_VMOV = 248 +MIPS_INS_VRSQ = 249 +MIPS_INS_VRSQL = 250 +MIPS_INS_VRSQH = 251 +MIPS_INS_VNOP = 252 +MIPS_INS_LBV = 253 +MIPS_INS_LSV = 254 +MIPS_INS_LLV = 255 +MIPS_INS_LDV = 256 +MIPS_INS_LQV = 257 +MIPS_INS_LRV = 258 +MIPS_INS_LPV = 259 +MIPS_INS_LUV = 260 +MIPS_INS_LHV = 261 +MIPS_INS_LFV = 262 +MIPS_INS_LTV = 263 +MIPS_INS_SBV = 264 +MIPS_INS_SSV = 265 +MIPS_INS_SLV = 266 +MIPS_INS_SDV = 267 +MIPS_INS_SQV = 268 +MIPS_INS_SRV = 269 +MIPS_INS_SPV = 270 +MIPS_INS_SUV = 271 +MIPS_INS_SHV = 272 +MIPS_INS_SFV = 273 +MIPS_INS_SWV = 274 +MIPS_INS_STV = 275 +MIPS_INS_MFC2 = 276 +MIPS_INS_MTC2 = 277 +MIPS_INS_CFC2 = 278 +MIPS_INS_CTC2 = 279 + +# Pseudo-Instruction Unique IDs +MIPS_INS_BEQZ = 280 +MIPS_INS_BNEZ = 281 +MIPS_INS_B = 282 +MIPS_INS_NOP = 283 +MIPS_INS_MOVE = 284 +MIPS_INS_NEGU = 285 +MIPS_INS_NOT = 286 + +# Invalid Instruction Unique ID +MIPS_INS_INVALID = -1 + +# Op IDs +# MIPS_OP_RS = 0 +# MIPS_OP_RT = 0 +# MIPS_OP_RD = 0 +# MIPS_OP_IMM = 0 + +# Instruction Groups + +MIPS_BRANCH_LIKELY_INSNS = [ + MIPS_INS_BEQL, MIPS_INS_BGEZALL, + MIPS_INS_BGEZL, MIPS_INS_BGTZL, + MIPS_INS_BLEZL, MIPS_INS_BLTZALL, + MIPS_INS_BLTZL, MIPS_INS_BNEL, + MIPS_INS_BC1TL, MIPS_INS_BC1FL, +] + +MIPS_BRANCH_INSNS = [ + *MIPS_BRANCH_LIKELY_INSNS, + + MIPS_INS_BEQ, + MIPS_INS_BGEZ, MIPS_INS_BGEZAL, + MIPS_INS_BGTZ, + MIPS_INS_BNE, + MIPS_INS_BLTZ, MIPS_INS_BLTZAL, + MIPS_INS_BLEZ, + MIPS_INS_BC1T, MIPS_INS_BC1F, + + MIPS_INS_BEQZ, + MIPS_INS_BNEZ, + MIPS_INS_B, +] + +MIPS_JUMP_INSNS = [ + MIPS_INS_JAL, MIPS_INS_JALR, MIPS_INS_J, MIPS_INS_JR +] + +MIPS_DELAY_SLOT_INSNS = [ + *MIPS_BRANCH_INSNS, *MIPS_JUMP_INSNS +] + +MIPS_FP_LOAD_INSNS = [ + MIPS_INS_LWC1, MIPS_INS_LDC1 +] + +MIPS_LOAD_INSNS = [ + MIPS_INS_LB, MIPS_INS_LBU, + MIPS_INS_LH, MIPS_INS_LHU, + MIPS_INS_LW, MIPS_INS_LWL, MIPS_INS_LWR, MIPS_INS_LWU, + MIPS_INS_LD, MIPS_INS_LDL, MIPS_INS_LDR, + MIPS_INS_LL, MIPS_INS_LLD, + *MIPS_FP_LOAD_INSNS +] + +MIPS_FP_STORE_INSNS = [ + MIPS_INS_SWC1, MIPS_INS_SDC1 +] + +MIPS_STORE_INSNS = [ + MIPS_INS_SB, + MIPS_INS_SH, + MIPS_INS_SW, MIPS_INS_SWL, MIPS_INS_SWR, + MIPS_INS_SD, MIPS_INS_SDL, MIPS_INS_SDR, + MIPS_INS_SC, MIPS_INS_SCD, + *MIPS_FP_STORE_INSNS +] + +MIPS_LOAD_STORE_INSNS = [ + *MIPS_LOAD_INSNS, + *MIPS_STORE_INSNS, +] + +MIPS_FP_LOAD_STORE_INSNS = [ + *MIPS_FP_LOAD_INSNS, *MIPS_FP_STORE_INSNS +] + +RSP_VECTOR_LOAD_STORES = [ + MIPS_INS_LBV, MIPS_INS_LSV, MIPS_INS_LLV, MIPS_INS_LDV, + MIPS_INS_LQV, MIPS_INS_LRV, MIPS_INS_LPV, MIPS_INS_LUV, + MIPS_INS_LHV, MIPS_INS_LFV, MIPS_INS_LTV, + + MIPS_INS_SBV, MIPS_INS_SSV, MIPS_INS_SLV, MIPS_INS_SDV, + MIPS_INS_SQV, MIPS_INS_SRV, MIPS_INS_SPV, MIPS_INS_SUV, + MIPS_INS_SHV, MIPS_INS_SFV, MIPS_INS_SWV, MIPS_INS_STV, +] + +# Labels + +# These labels can be referenced from pointers/loads/stores/etc. +LABEL_TYPE_FUNC = 0 +LABEL_TYPE_JTBL = 1 +LABEL_TYPE_DATA = 2 +LABEL_TYPE_BRANCH = 3 + +# Unknown +LABEL_TYPE_UNK = 20 + +class MipsLabel: + """ + Label + """ + + def __init__(self, vaddr, name=None, lbl_type=LABEL_TYPE_UNK, is_global=None) -> None: + self.name = name + self.vaddr = vaddr + self.lbl_type = lbl_type + self.is_global = is_global or (False if (lbl_type == LABEL_TYPE_BRANCH) else True) + + def __str__(self): + if self.name is not None: + return self.name + + if self.lbl_type == LABEL_TYPE_FUNC: + return f"func_{self.vaddr:08X}" + elif self.lbl_type == LABEL_TYPE_JTBL: + return f"jtbl_{self.vaddr:08X}" + elif self.lbl_type == LABEL_TYPE_BRANCH: + return f".L{self.vaddr:08X}" + elif (self.lbl_type == LABEL_TYPE_DATA or self.lbl_type == LABEL_TYPE_UNK): + return f"D_{self.vaddr:08X}" + assert False , f"Unimplemented default name for label type {self.lbl_type}" + +# Register Names + +mips_gpr_names = ( + "$zero", + "$at", + "$v0", "$v1", + "$a0", "$a1", "$a2", "$a3", + "$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7", + "$s0", "$s1", "$s2", "$s3", "$s4", "$s5", "$s6", "$s7", + "$t8", "$t9", + "$k0", "$k1", + "$gp", + "$sp", + "$fp", + "$ra", +) + +rsp_gpr_names = ( + "$zero", + "$1", "$2", "$3", "$4", "$5", "$6", + "$7", "$8", "$9", "$10", "$11", "$12", + "$13", "$14", "$15", "$16", "$17", "$18", + "$19", "$20", "$21", "$22", "$23", "$24", + "$25", "$26", "$27", "$28", "$29", "$30", + "$ra", +) + +mips_cop0_names = ( + "Index" , "Random" , "EntryLo0" , "EntryLo1" , + "Context" , "PageMask" , "Wired" , "Reserved07", + "BadVaddr" , "Count" , "EntryHi" , "Compare" , + "Status" , "Cause" , "EPC" , "PRevID" , + "Config" , "LLAddr" , "WatchLo" , "WatchHi" , + "XContext" , "Reserved21", "Reserved22", "Reserved23", + "Reserved24", "Reserved25", "PErr" , "CacheErr" , + "TagLo" , "TagHi" , "ErrorEPC" , "Reserved31", +) + +rsp_cop0_names = ( + "SP_MEM_ADDR", "SP_DRAM_ADDR", "SP_RD_LEN" , "SP_WR_LEN" , + "SP_STATUS" , "SP_DMA_FULL" , "SP_DMA_BUSY" , "SP_SEMAPHORE", + "DPC_START" , "DPC_END" , "DPC_CURRENT" , "DPC_STATUS" , + "DPC_CLOCK" , "DPC_BUFBUSY" , "DPC_PIPEBUSY", "DPC_TMEM" , +) + +mips_cop1_names = ( + "$f0", "$f1", "$f2", "$f3", + "$f4", "$f5", "$f6", "$f7", "$f8", "$f9", "$f10", "$f11", + "$f12", "$f13", "$f14", "$f15", + "$f16", "$f17", "$f18", "$f19", + "$f20", "$f21", "$f22", "$f23", "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", + # Status register + "FpCsr", +) + +rsp_cop2_names = ( + "$v0", "$v1", "$v2", "$v3", "$v4", "$v5", "$v6", "$v7", + "$v8", "$v9", "$v10", "$v11", "$v12", "$v13", "$v14", "$v15", + "$v16", "$v17", "$v18", "$v19", "$v20", "$v21", "$v22", "$v23", + "$v24", "$v25", "$v26", "$v27", "$v28", "$v29", "$v30", "$v31", +) + +rsp_cop2_ctrl_names = ( + '$vco', '$vcc', '$vce' +) + +# Instruction sets + +class MipsAbi: + def __init__(self, name, gpr_names, cop0_names, cop1_names, cop2_names): + self.name = name + self.gpr_names, self.cop0_names, self.cop1_names, self.cop2_names = \ + gpr_names, cop0_names, cop1_names, cop2_names + +ABI_VR4300 = MipsAbi("VR4300", mips_gpr_names, mips_cop0_names, mips_cop1_names, None ) +ABI_RSP = MipsAbi("RSP", rsp_gpr_names, rsp_cop0_names, None, rsp_cop2_names) + +# Instruction field fetching + +def sign_extend_6(value): + if value & (1 << (6 - 1)): + return value - (1 << 6) + return value + +def sign_extend_16(value): + return (value & 0x7FFF) - (value & 0x8000) + +def mask_shift(v, s, w): + return (v >> s) & ((1 << w) - 1) + +mips_get_field = lambda raw,vaddr : mask_shift(raw, 26, 6) +mips_get_special = lambda raw,vaddr : mask_shift(raw, 0, 6) +mips_get_cop0 = lambda raw,vaddr : mask_shift(raw, 21, 5) +mips_get_cop1 = lambda raw,vaddr : mask_shift(raw, 21, 5) +mips_get_cop2 = lambda raw,vaddr : mask_shift(raw, 21, 4) +mips_get_regimm = lambda raw,vaddr : mask_shift(raw, 16, 5) +mips_get_tlb = lambda raw,vaddr : mask_shift(raw, 0, 5) +mips_get_function = lambda raw,vaddr : mask_shift(raw, 0, 6) + +mips_get_cond = lambda raw,vaddr : mask_shift(raw, 0, 4) +mips_get_fd = lambda raw,vaddr : MipsFPReg(mask_shift(raw, 6, 5)) +mips_get_fs = lambda raw,vaddr : MipsFPReg(mask_shift(raw, 11, 5)) +mips_get_ft = lambda raw,vaddr : MipsFPReg(mask_shift(raw, 16, 5)) +mips_get_fmt = lambda raw,vaddr : mask_shift(raw, 21, 5) +mips_get_ndtf = lambda raw,vaddr : mask_shift(raw, 16, 2) + +mips_get_target = lambda raw,vaddr : ((vaddr & 0xFC000000) | (mask_shift(raw, 0, 26) << 2)) +mips_get_offset = lambda raw,vaddr : vaddr + 4 + sign_extend_16(mask_shift(raw, 0, 16)) * 4 +mips_get_imm = lambda raw,vaddr : mask_shift(raw, 0, 16) + +mips_get_base = lambda raw,vaddr : MipsGPReg(mask_shift(raw, 21, 5)) + +mips_get_cd = lambda raw,vaddr : mask_shift(raw, 11, 5) + +mips_get_code = lambda raw,vaddr : (mask_shift(raw, 6, 20) << 6) >> 16 +mips_get_op = lambda raw,vaddr : mask_shift(raw, 16, 5) + +mips_get_sa = lambda raw,vaddr : mask_shift(raw, 6, 5) + +mips_get_rd = lambda raw,vaddr : MipsGPReg(mask_shift(raw, 11, 5)) +mips_get_rs = lambda raw,vaddr : MipsGPReg(mask_shift(raw, 21, 5)) +mips_get_rt = lambda raw,vaddr : MipsGPReg(mask_shift(raw, 16, 5)) + +rsp_load_store_multiplier = { + 0b00000 : 0x01, # lbv, sbv + 0b00001 : 0x02, # lsv, ssv + 0b00010 : 0x04, # llv, slv + 0b00011 : 0x08, # ldv, sdv + 0b00100 : 0x10, # lqv, sqv + 0b00101 : 0x10, # lrv, srv + 0b00110 : 0x08, # lpv, spv + 0b00111 : 0x08, # luv, suv + + 0b01000 : 0x02, # lhv, shv + 0b01001 : 0x04, # lfv, sfv + 0b01010 : 0x10, # swv + 0b01011 : 0x10, # ltv, stv +} + +mips_get_vc = lambda raw,vaddr : mask_shift(raw, 11, 5) +mips_get_vd = lambda raw,vaddr : mask_shift(raw, 6, 5) +mips_get_vs = lambda raw,vaddr : mask_shift(raw, 11, 5) +mips_get_vt = lambda raw,vaddr : mask_shift(raw, 16, 5) +mips_get_elem = lambda raw,vaddr : mask_shift(raw, 21, 4) +mips_get_elemd = lambda raw,vaddr : mask_shift(raw, 7, 4) +mips_get_cop2_func = lambda raw,vaddr : mask_shift(raw, 25, 1) +mips_get_lwc2 = lambda raw,vaddr : mask_shift(raw, 11, 5) +mips_get_swc2 = lambda raw,vaddr : mask_shift(raw, 11, 5) +mips_get_voffset = lambda raw,vaddr : sign_extend_6(mask_shift(raw, 0, 6)) * rsp_load_store_multiplier[mips_get_lwc2(raw,vaddr)] + +# Formatting + +def resolve_pseudo_insn(insn): + # move varies between assemblers + # IDO + move_insn = MIPS_INS_OR + # GCC + # move_insn = MIPS_INS_ADDU + + if insn.id == MIPS_INS_SLL and insn.rd == MipsGPReg.R0 and insn.rt == MipsGPReg.R0 and insn.sa == 0: + return MIPS_INS_NOP, "nop", (), () + elif insn.id == MIPS_INS_BEQ and insn.rs == MipsGPReg.R0 and insn.rt == MipsGPReg.R0: + return MIPS_INS_B, "b", ("offset",), (False,) + elif insn.id == move_insn and insn.rt == MipsGPReg.R0: + return MIPS_INS_MOVE, "move", ("rd","rs"), (True,False) + elif insn.id == MIPS_INS_BEQ and insn.rt == MipsGPReg.R0: + return MIPS_INS_BEQZ, "beqz", ("rs","offset"), (False,False) + elif insn.id == MIPS_INS_BNE and insn.rt == MipsGPReg.R0: + return MIPS_INS_BNEZ, "bnez", ("rs","offset"), (False,False) + elif insn.id == MIPS_INS_SUBU and insn.rs == MipsGPReg.R0: + return MIPS_INS_NEGU, "negu", ("rd","rt"), (True,False) + elif insn.id == MIPS_INS_NOR and insn.rt == MipsGPReg.R0: + return MIPS_INS_NOT, "not", ("rd","rs"), (True,False) + else: + return insn.id, insn.mnemonic, insn.fields, insn.writes + +def format_hex(v, signed, zeros, no_zero): + if abs(v) < 10: + if v == 0 and no_zero: + return "" + return f"{v}" + elif not signed: + return f"0x{v:{f'0{zeros}' if zeros > 0 else ''}x}" + else: + return f"{v:#x}" + +def format_vector_elem(insn, elem): + if insn.id in RSP_VECTOR_LOAD_STORES: + return f"[{elem}]" + elif (elem & 8) == 8: + return f"[{elem & 7}]" + elif (elem & 0xC) == 4: + return f"[{elem & 3}h]" + elif (elem & 0xE) == 2: + return f"[{elem & 1}q]" + else: + return "" + +mips_field_formatters = { + 'code' : (lambda insn : f'{insn.code}' if insn.code != 0 else ''), + 'cd' : (lambda insn : insn.abi.cop0_names[insn.cd]), + 'rd' : (lambda insn : insn.abi.gpr_names[insn.rd]), + 'rs' : (lambda insn : insn.abi.gpr_names[insn.rs]), + 'rt' : (lambda insn : insn.abi.gpr_names[insn.rt]), + 'fd' : (lambda insn : insn.abi.cop1_names[insn.fd]), + 'fs' : (lambda insn : insn.abi.cop1_names[insn.fs]), + 'ft' : (lambda insn : insn.abi.cop1_names[insn.ft]), + 'sa' : (lambda insn : format_hex(insn.sa, True, 0, False)), + 'op' : (lambda insn : format_hex(insn.op, False, 0, False)), + 'imm' : (lambda insn : format_hex(insn.imm, True, 0, False)), + 'offset(base)' : (lambda insn : f'{format_hex(insn.imm, True, 0, True)}({insn.abi.gpr_names[insn.base]})'), + 'offset' : (lambda insn : f'{format_hex(insn.offset, True, 0, False)}'), + 'target' : (lambda insn : f'{format_hex(insn.target, False, 0, False)}'), + 'vd' : (lambda insn : insn.abi.cop2_names[insn.vd]), + 'vs' : (lambda insn : insn.abi.cop2_names[insn.vs]), + 'vt' : (lambda insn : insn.abi.cop2_names[insn.vt]), + 'vt[e]' : (lambda insn : f"{insn.abi.cop2_names[insn.vt]}{format_vector_elem(insn, insn.elem)}"), + 'vt[ed]' : (lambda insn : f"{insn.abi.cop2_names[insn.vt]}{format_vector_elem(insn, insn.elemd)}"), + 'vd[e]' : (lambda insn : f"{insn.abi.cop2_names[insn.vd]}{format_vector_elem(insn, insn.elem)}"), + 'vd[ed]' : (lambda insn : f"{insn.abi.cop2_names[insn.vd]}{format_vector_elem(insn, insn.elemd)}"), + 'voffset' : (lambda insn : f'{format_hex(insn.voffset, True, 0, False)}'), + 'voffset(base)' : (lambda insn : f'{format_hex(insn.voffset, True, 0, True)}({insn.abi.gpr_names[insn.base]})'), + 'vc' : (lambda insn : rsp_cop2_ctrl_names[insn.vc]) +} + +class MipsInsn: + + def __init__(self, abi, raw, vaddr, values): + self.abi = abi + self.raw = raw + self.vaddr = vaddr + + if values is None: + values = MIPS_INS_INVALID, f"/* Invalid Instruction */ .4byte 0x{raw:08X}", (), () + + self.id, self.mnemonic, self.fields, self.writes = values + + # self.code = self.sa = self.op = self.cd = self.rd = self.rs = self.rt = self.fd = self.fs = self.ft = self.imm = self.offset = self.base = self.target = None + + for field in self.fields: + self.set_value(field) + + self.id, self.mnemonic, self.fields, self.writes = resolve_pseudo_insn(self) + + self.op_str = self.format_insn() + + def read_fields(self): + return [field for i,field in enumerate(self.fields) if self.writes[i] == False] + + def write_fields(self): + return [field for i,field in enumerate(self.fields) if self.writes[i] == True] + + def has_field(self, field): + return field in self.fields + + def format_field(self, field): + return mips_field_formatters[field](self) + + def format_insn(self): + return ", ".join([self.format_field(field) for field in self.fields]) + + def __str__(self): + return f"{self.mnemonic:12}{self.op_str}" + + # Field setters + + def set_code(self): + self.code = mips_get_code(self.raw, self.vaddr) + + def set_sa(self): + self.sa = mips_get_sa(self.raw, self.vaddr) + + def set_op(self): + self.op = mips_get_op(self.raw, self.vaddr) + + def set_cd(self): + self.cd = mips_get_cd(self.raw, self.vaddr) + + def set_rd(self): + self.rd = mips_get_rd(self.raw, self.vaddr) + + def set_rs(self): + self.rs = mips_get_rs(self.raw, self.vaddr) + + def set_rt(self): + self.rt = mips_get_rt(self.raw, self.vaddr) + + def set_fd(self): + self.fd = mips_get_fd(self.raw, self.vaddr) + + def set_fs(self): + self.fs = mips_get_fs(self.raw, self.vaddr) + + def set_ft(self): + self.ft = mips_get_ft(self.raw, self.vaddr) + + do_sign_extend = [ + MIPS_INS_ADDIU, MIPS_INS_SLTI, MIPS_INS_ADDI, MIPS_INS_DADDIU, + MIPS_INS_LB, MIPS_INS_LBU, + MIPS_INS_LH, MIPS_INS_LHU, + MIPS_INS_LW, MIPS_INS_LWL, MIPS_INS_LWR, MIPS_INS_LWU, + MIPS_INS_LWC1, + MIPS_INS_LD, MIPS_INS_LDL, MIPS_INS_LDR, + MIPS_INS_LDC1, + MIPS_INS_LL, MIPS_INS_LLD, + MIPS_INS_SB, + MIPS_INS_SH, + MIPS_INS_SW, MIPS_INS_SWL, MIPS_INS_SWR, + MIPS_INS_SWC1, + MIPS_INS_SD, MIPS_INS_SDL, MIPS_INS_SDR, + MIPS_INS_SDC1, + MIPS_INS_SC, MIPS_INS_SCD, + ] + + def set_imm(self): + self.imm = mips_get_imm(self.raw, self.vaddr) + if self.id in MipsInsn.do_sign_extend: # sign extended immediates + self.imm = sign_extend_16(self.imm) + + def set_offset(self): + self.offset = mips_get_offset(self.raw, self.vaddr) + + def set_base(self): + self.base = mips_get_base(self.raw, self.vaddr) + + def set_offset_base(self): + self.set_imm() + self.set_base() + + def set_target(self): + self.target = mips_get_target(self.raw, self.vaddr) + + def set_vd(self): + self.vd = mips_get_vd(self.raw, self.vaddr) + + def set_vs(self): + self.vs = mips_get_vs(self.raw, self.vaddr) + + def set_vt(self): + self.vt = mips_get_vt(self.raw, self.vaddr) + + def set_e(self): + self.elem = mips_get_elem(self.raw, self.vaddr) + + def set_ed(self): + self.elemd = mips_get_elemd(self.raw, self.vaddr) + + def set_vd_e(self): + self.set_vd() + self.set_e() + + def set_vt_ed(self): + self.set_vt() + self.set_ed() + + def set_vt_e(self): + self.set_vt() + self.set_e() + + def set_vd_ed(self): + self.set_vd() + self.set_ed() + + def set_voffset(self): + self.voffset = mips_get_voffset(self.raw, self.vaddr) + + def set_voffset_base(self): + self.set_voffset() + self.set_base() + + def set_vc(self): + self.vc = mips_get_vc(self.raw, self.vaddr) + + field_setters = { + 'code' : set_code, + 'sa' : set_sa, + 'op' : set_op, + 'cd' : set_cd, + 'rd' : set_rd, + 'rs' : set_rs, + 'rt' : set_rt, + 'fd' : set_fd, + 'fs' : set_fs, + 'ft' : set_ft, + 'imm' : set_imm, + 'offset' : set_offset, + 'base' : set_base, + 'offset(base)' : set_offset_base, + 'target' : set_target, + 'vd' : set_vd, + 'vs' : set_vs, + 'vt' : set_vt, + 'vt[e]' : set_vt_e, + 'vt[ed]' : set_vt_ed, + 'vd[e]' : set_vd_e, + 'vd[ed]' : set_vd_ed, + 'voffset' : set_voffset, + 'voffset(base)' : set_voffset_base, + 'vc' : set_vc + } + + def set_value(self, name): + MipsInsn.field_setters[name](self) + + # Field getters + + field_getters = { + 'code' : (lambda insn: insn.code), + 'sa' : (lambda insn: insn.sa), + 'op' : (lambda insn: insn.op), + 'cd' : (lambda insn: insn.cd), + 'rd' : (lambda insn: insn.rd), + 'rs' : (lambda insn: insn.rs), + 'rt' : (lambda insn: insn.rt), + 'fd' : (lambda insn: insn.fd), + 'fs' : (lambda insn: insn.fs), + 'ft' : (lambda insn: insn.ft), + 'imm' : (lambda insn: insn.imm), + 'offset' : (lambda insn: insn.offset), + 'base' : (lambda insn: insn.base), + 'offset(base)' : (lambda insn: (insn.offset, insn.base)), + 'target' : (lambda insn: insn.target), + 'vd' : (lambda insn: insn.vd), + 'vs' : (lambda insn: insn.vs), + 'vt' : (lambda insn: insn.vt), + 'vt[e]' : (lambda insn: (insn.vt, insn.elem)), + 'vt[ed]' : (lambda insn: (insn.vt, insn.elemd)), + 'vd[e]' : (lambda insn: (insn.vd, insn.elem)), + 'vd[ed]' : (lambda insn: (insn.vd, insn.elemd)), + 'voffset' : (lambda insn: insn.voffset), + 'voffset(base)' : (lambda insn: (insn.voffset, insn.base)), + 'vc' : (lambda insn: insn.vc), + } + + def value_forname(self, name): + return MipsInsn.field_getters[name](self) + +def fetch_insn(raw, vaddr, insn_set, func): + insn = insn_set.get(func(raw, vaddr), None) # default none for invalid instruction encoding + + if insn is not None and type(insn[1]) == dict: # extra decoding required + insn = fetch_insn(raw, vaddr, insn[1], insn[0]) + return insn + +def decode_insn(raw, vaddr): + return MipsInsn(ABI_VR4300, raw, vaddr, fetch_insn(raw, vaddr, mips_insns, mips_get_field)) + +def decode_rsp_insn(raw, vaddr): + return MipsInsn(ABI_RSP, raw, vaddr, fetch_insn(raw, vaddr, rsp_insns, mips_get_field)) + +mips_insns = { + 0b000000: (mips_get_special, { + # opcode id mnemonic fields field is written to + 0b000000: (MIPS_INS_SLL, "sll", ("rd","rt","sa"), (True , False, False)), + 0b000010: (MIPS_INS_SRL, "srl", ("rd","rt","sa"), (True , False, False)), + 0b000011: (MIPS_INS_SRA, "sra", ("rd","rt","sa"), (True , False, False)), + 0b000100: (MIPS_INS_SLLV, "sllv", ("rd","rt","rs"), (True , False, False)), + 0b000110: (MIPS_INS_SRLV, "srlv", ("rd","rt","rs"), (True , False, False)), + 0b000111: (MIPS_INS_SRAV, "srav", ("rd","rt","rs"), (True , False, False)), + 0b001000: (MIPS_INS_JR, "jr", ("rs", ), (False, )), + 0b001001: (MIPS_INS_JALR, "jalr", ("rs", ), (False, )), # technically also rd but it's always $ra + 0b001100: (MIPS_INS_SYSCALL, "syscall", ( ), ( )), + 0b001101: (MIPS_INS_BREAK, "break", ("code", ), (False, )), + 0b001111: (MIPS_INS_SYNC, "sync", ( ), ( )), + 0b010000: (MIPS_INS_MFHI, "mfhi", ("rd", ), (True , )), + 0b010001: (MIPS_INS_MTHI, "mthi", ("rs", ), (False, )), + 0b010010: (MIPS_INS_MFLO, "mflo", ("rd", ), (True , )), + 0b010011: (MIPS_INS_MTLO, "mtlo", ("rs", ), (False, )), + 0b010100: (MIPS_INS_DSLLV, "dsllv", ("rd","rt","rs"), (True , False, False)), + 0b010110: (MIPS_INS_DSRLV, "dsrlv", ("rd","rt","rs"), (True , False, False)), + 0b010111: (MIPS_INS_DSRAV, "dsrav", ("rd","rt","rs"), (True , False, False)), + 0b011000: (MIPS_INS_MULT, "mult", ("rs","rt" ), (False, False )), + 0b011001: (MIPS_INS_MULTU, "multu", ("rs","rt" ), (False, False )), + 0b011010: (MIPS_INS_DIV, "div", ("rd","rs","rt"), (False, False, False)), # for some reason gas hates div instructions + 0b011011: (MIPS_INS_DIVU, "divu", ("rd","rs","rt"), (False, False, False)), # with the correct number of operands + 0b011100: (MIPS_INS_DMULT, "dmult", ("rs","rt" ), (False, False )), + 0b011101: (MIPS_INS_DMULTU, "dmultu", ("rs","rt" ), (False, False )), + 0b011110: (MIPS_INS_DDIV, "ddiv", ("rd","rs","rt"), (False, False, False)), + 0b011111: (MIPS_INS_DDIVU, "ddivu", ("rd","rs","rt"), (False, False, False)), + 0b100000: (MIPS_INS_ADD, "add", ("rd","rs","rt"), (True , False, False)), + 0b100001: (MIPS_INS_ADDU, "addu", ("rd","rs","rt"), (True , False, False)), + 0b100010: (MIPS_INS_SUB, "sub", ("rd","rs","rt"), (True , False, False)), + 0b100011: (MIPS_INS_SUBU, "subu", ("rd","rs","rt"), (True , False, False)), + 0b100100: (MIPS_INS_AND, "and", ("rd","rs","rt"), (True , False, False)), + 0b100101: (MIPS_INS_OR, "or", ("rd","rs","rt"), (True , False, False)), + 0b100110: (MIPS_INS_XOR, "xor", ("rd","rs","rt"), (True , False, False)), + 0b100111: (MIPS_INS_NOR, "nor", ("rd","rs","rt"), (True , False, False)), + 0b101010: (MIPS_INS_SLT, "slt", ("rd","rs","rt"), (True , False, False)), + 0b101011: (MIPS_INS_SLTU, "sltu", ("rd","rs","rt"), (True , False, False)), + 0b101100: (MIPS_INS_DADD, "dadd", ("rd","rs","rt"), (True , False, False)), + 0b101101: (MIPS_INS_DADDU, "daddu", ("rd","rs","rt"), (True , False, False)), + 0b101110: (MIPS_INS_DSUB, "dsub", ("rd","rs","rt"), (True , False, False)), + 0b101111: (MIPS_INS_DSUBU, "dsubu", ("rd","rs","rt"), (True , False, False)), + 0b110000: (MIPS_INS_TGE, "tge", ("rs","rt" ), (False, False )), + 0b110001: (MIPS_INS_TGEU, "tgeu", ("rs","rt" ), (False, False )), + 0b110010: (MIPS_INS_TLT, "tlt", ("rs","rt" ), (False, False )), + 0b110011: (MIPS_INS_TLTU, "tltu", ("rs","rt" ), (False, False )), + 0b110100: (MIPS_INS_TEQ, "teq", ("rs","rt" ), (False, False )), + 0b110110: (MIPS_INS_TNE, "tne", ("rs","rt" ), (False, False )), + 0b111000: (MIPS_INS_DSLL, "dsll", ("rd","rt","sa"), (True , False, False)), + 0b111010: (MIPS_INS_DSRL, "dsrl", ("rd","rt","sa"), (True , False, False)), + 0b111011: (MIPS_INS_DSRA, "dsra", ("rd","rt","sa"), (True , False, False)), + 0b111100: (MIPS_INS_DSLL32, "dsll32", ("rd","rt","sa"), (True , False, False)), + 0b111110: (MIPS_INS_DSRL32, "dsrl32", ("rd","rt","sa"), (True , False, False)), + 0b111111: (MIPS_INS_DSRA32, "dsra32", ("rd","rt","sa"), (True , False, False)), + }), + 0b000001: (mips_get_regimm, { + 0b00000: (MIPS_INS_BLTZ, "bltz", ("rs","offset"), (False, False)), + 0b00001: (MIPS_INS_BGEZ, "bgez", ("rs","offset"), (False, False)), + 0b00010: (MIPS_INS_BLTZL, "bltzl", ("rs","offset"), (False, False)), + 0b00011: (MIPS_INS_BGEZL, "bgezl", ("rs","offset"), (False, False)), + 0b01000: (MIPS_INS_TGEI, "tgei", ("rs","imm" ), (False, False)), + 0b01001: (MIPS_INS_TGEIU, "tgeiu", ("rs","imm" ), (False, False)), + 0b01010: (MIPS_INS_TLTI, "tlti", ("rs","imm" ), (False, False)), + 0b01011: (MIPS_INS_TLTIU, "tltiu", ("rs","imm" ), (False, False)), + 0b01100: (MIPS_INS_TEQI, "teqi", ("rs","imm" ), (False, False)), + 0b01110: (MIPS_INS_TNEI, "tnei", ("rs","imm" ), (False, False)), + 0b10000: (MIPS_INS_BLTZAL, "bltzal", ("rs","offset"), (False, False)), + 0b10001: (MIPS_INS_BGEZAL, "bgezal", ("rs","offset"), (False, False)), + 0b10010: (MIPS_INS_BLTZALL, "bltzall", ("rs","offset"), (False, False)), + 0b10011: (MIPS_INS_BGEZALL, "bgezall", ("rs","offset"), (False, False)), + }), + 0b000010: (MIPS_INS_J, "j", ("target", ), (False, )), + 0b000011: (MIPS_INS_JAL, "jal", ("target", ), (False, )), + 0b000100: (MIPS_INS_BEQ, "beq", ("rs","rt","offset"), (False, False, False)), + 0b000101: (MIPS_INS_BNE, "bne", ("rs","rt","offset"), (False, False, False)), + 0b000110: (MIPS_INS_BLEZ, "blez", ("rs","offset" ), (False, False, )), + 0b000111: (MIPS_INS_BGTZ, "bgtz", ("rs","offset" ), (False, False, )), + 0b001000: (MIPS_INS_ADDI, "addi", ("rt","rs","imm" ), (True , False, False)), + 0b001001: (MIPS_INS_ADDIU, "addiu", ("rt","rs","imm" ), (True , False, False)), + 0b001010: (MIPS_INS_SLTI, "slti", ("rt","rs","imm" ), (True , False, False)), + 0b001011: (MIPS_INS_SLTIU, "sltiu", ("rt","rs","imm" ), (True , False, False)), + 0b001100: (MIPS_INS_ANDI, "andi", ("rt","rs","imm" ), (True , False, False)), + 0b001101: (MIPS_INS_ORI, "ori", ("rt","rs","imm" ), (True , False, False)), + 0b001110: (MIPS_INS_XORI, "xori", ("rt","rs","imm" ), (True , False, False)), + 0b001111: (MIPS_INS_LUI, "lui", ("rt","imm" ), (True , False )), + 0b010000: (mips_get_cop0, { + 0b00000: (MIPS_INS_MFC0, "mfc0", ("rt","cd"), (True , False)), + 0b00100: (MIPS_INS_MTC0, "mtc0", ("rt","cd"), (False, True )), + 0b10000: (mips_get_tlb, { + 0b000001: (MIPS_INS_TLBR, "tlbr", (), ()), + 0b000010: (MIPS_INS_TLBWI, "tlbwi", (), ()), + 0b000110: (MIPS_INS_TLBWR, "tlbwr", (), ()), + 0b001000: (MIPS_INS_TLBP, "tlbp", (), ()), + 0b011000: (MIPS_INS_ERET, "eret", (), ()), + }), + }), + 0b010001: (mips_get_cop1, { + 0b00000: (MIPS_INS_MFC1, "mfc1", ("rt","fs"), (True , False)), + 0b00001: (MIPS_INS_DMFC1, "dmfc1", ("rt","fs"), (True , False)), + 0b00010: (MIPS_INS_CFC1, "cfc1", ("rt","fs"), (True , False)), + 0b00100: (MIPS_INS_MTC1, "mtc1", ("rt","fs"), (False, True )), + 0b00101: (MIPS_INS_DMTC1, "dmtc1", ("rt","fs"), (False, True )), + 0b00110: (MIPS_INS_CTC1, "ctc1", ("rt","fs"), (False, True )), + 0b01000: (mips_get_ndtf, { + 0b00: (MIPS_INS_BC1F, "bc1f", ("offset",), (False,)), + 0b01: (MIPS_INS_BC1T, "bc1t", ("offset",), (False,)), + 0b10: (MIPS_INS_BC1FL, "bc1fl", ("offset",), (False,)), + 0b11: (MIPS_INS_BC1TL, "bc1tl", ("offset",), (False,)), + }), + 0b010000: (mips_get_function, { + 0b000000: (MIPS_INS_ADD_S, "add.s", ("fd","fs","ft"), (True , False, False)), + 0b000001: (MIPS_INS_SUB_S, "sub.s", ("fd","fs","ft"), (True , False, False)), + 0b000010: (MIPS_INS_MUL_S, "mul.s", ("fd","fs","ft"), (True , False, False)), + 0b000011: (MIPS_INS_DIV_S, "div.s", ("fd","fs","ft"), (True , False, False)), + 0b000100: (MIPS_INS_SQRT_S, "sqrt.s", ("fd","fs" ), (True , False )), + 0b000101: (MIPS_INS_ABS_S, "abs.s", ("fd","fs" ), (True , False )), + 0b000110: (MIPS_INS_MOV_S, "mov.s", ("fd","fs" ), (True , False )), + 0b000111: (MIPS_INS_NEG_S, "neg.s", ("fd","fs" ), (True , False )), + 0b001000: (MIPS_INS_ROUND_L_S, "round.l.s", ("fd","fs" ), (True , False )), + 0b001001: (MIPS_INS_TRUNC_L_S, "trunc.l.s", ("fd","fs" ), (True , False )), + 0b001010: (MIPS_INS_CEIL_L_S, "ceil.l.s", ("fd","fs" ), (True , False )), + 0b001011: (MIPS_INS_FLOOR_L_S, "floor.l.s", ("fd","fs" ), (True , False )), + 0b001100: (MIPS_INS_ROUND_W_S, "round.w.s", ("fd","fs" ), (True , False )), + 0b001101: (MIPS_INS_TRUNC_W_S, "trunc.w.s", ("fd","fs" ), (True , False )), + 0b001110: (MIPS_INS_CEIL_W_S, "ceil.w.s", ("fd","fs" ), (True , False )), + 0b001111: (MIPS_INS_FLOOR_W_S, "floor.w.s", ("fd","fs" ), (True , False )), + 0b100001: (MIPS_INS_CVT_D_S, "cvt.d.s", ("fd","fs" ), (True , False )), + 0b100100: (MIPS_INS_CVT_W_S, "cvt.w.s", ("fd","fs" ), (True , False )), + 0b100101: (MIPS_INS_CVT_L_S, "cvt.l.s", ("fd","fs" ), (True , False )), + 0b110000: (MIPS_INS_C_F_S, "c.f.s", ("fs","ft" ), (False, False )), + 0b110001: (MIPS_INS_C_UN_S, "c.un.s", ("fs","ft" ), (False, False )), + 0b110010: (MIPS_INS_C_EQ_S, "c.eq.s", ("fs","ft" ), (False, False )), + 0b110011: (MIPS_INS_C_UEQ_S, "c.ueq.s", ("fs","ft" ), (False, False )), + 0b110100: (MIPS_INS_C_OLT_S, "c.olt.s", ("fs","ft" ), (False, False )), + 0b110101: (MIPS_INS_C_ULT_S, "c.ult.s", ("fs","ft" ), (False, False )), + 0b110110: (MIPS_INS_C_OLE_S, "c.ole.s", ("fs","ft" ), (False, False )), + 0b110111: (MIPS_INS_C_ULE_S, "c.ule.s", ("fs","ft" ), (False, False )), + 0b111000: (MIPS_INS_C_SF_S, "c.sf.s", ("fs","ft" ), (False, False )), + 0b111001: (MIPS_INS_C_NGLE_S, "c.ngle.s", ("fs","ft" ), (False, False )), + 0b111010: (MIPS_INS_C_SEQ_S, "c.seq.s", ("fs","ft" ), (False, False )), + 0b111011: (MIPS_INS_C_NGL_S, "c.ngl.s", ("fs","ft" ), (False, False )), + 0b111100: (MIPS_INS_C_LT_S, "c.lt.s", ("fs","ft" ), (False, False )), + 0b111101: (MIPS_INS_C_NGE_S, "c.nge.s", ("fs","ft" ), (False, False )), + 0b111110: (MIPS_INS_C_LE_S, "c.le.s", ("fs","ft" ), (False, False )), + 0b111111: (MIPS_INS_C_NGT_S, "c.ngt.s", ("fs","ft" ), (False, False )), + }), + 0b010001: (mips_get_function, { + 0b000000: (MIPS_INS_ADD_D, "add.d", ("fd","fs","ft"), (True , False, False)), + 0b000001: (MIPS_INS_SUB_D, "sub.d", ("fd","fs","ft"), (True , False, False)), + 0b000010: (MIPS_INS_MUL_D, "mul.d", ("fd","fs","ft"), (True , False, False)), + 0b000011: (MIPS_INS_DIV_D, "div.d", ("fd","fs","ft"), (True , False, False)), + 0b000100: (MIPS_INS_SQRT_D, "sqrt.d", ("fd","fs" ), (True , False )), + 0b000101: (MIPS_INS_ABS_D, "abs.d", ("fd","fs" ), (True , False )), + 0b000110: (MIPS_INS_MOV_D, "mov.d", ("fd","fs" ), (True , False )), + 0b000111: (MIPS_INS_NEG_D, "neg.d", ("fd","fs" ), (True , False )), + 0b001000: (MIPS_INS_ROUND_L_D, "round.l.d", ("fd","fs" ), (True , False )), + 0b001001: (MIPS_INS_TRUNC_L_D, "trunc.l.d", ("fd","fs" ), (True , False )), + 0b001010: (MIPS_INS_CEIL_L_D, "ceil.l.d", ("fd","fs" ), (True , False )), + 0b001011: (MIPS_INS_FLOOR_L_D, "floor.l.d", ("fd","fs" ), (True , False )), + 0b001100: (MIPS_INS_ROUND_W_D, "round.w.d", ("fd","fs" ), (True , False )), + 0b001101: (MIPS_INS_TRUNC_W_D, "trunc.w.d", ("fd","fs" ), (True , False )), + 0b001110: (MIPS_INS_CEIL_W_D, "ceil.w.d", ("fd","fs" ), (True , False )), + 0b001111: (MIPS_INS_FLOOR_W_D, "floor.w.d", ("fd","fs" ), (True , False )), + 0b100000: (MIPS_INS_CVT_S_D, "cvt.s.d", ("fd","fs" ), (True , False )), + 0b100100: (MIPS_INS_CVT_W_D, "cvt.w.d", ("fd","fs" ), (True , False )), + 0b100101: (MIPS_INS_CVT_L_D, "cvt.l.d", ("fd","fs" ), (True , False )), + 0b110000: (MIPS_INS_C_F_D, "c.f.d", ("fs","ft" ), (False, False )), + 0b110001: (MIPS_INS_C_UN_D, "c.un.d", ("fs","ft" ), (False, False )), + 0b110010: (MIPS_INS_C_EQ_D, "c.eq.d", ("fs","ft" ), (False, False )), + 0b110011: (MIPS_INS_C_UEQ_D, "c.ueq.d", ("fs","ft" ), (False, False )), + 0b110100: (MIPS_INS_C_OLT_D, "c.olt.d", ("fs","ft" ), (False, False )), + 0b110101: (MIPS_INS_C_ULT_D, "c.ult.d", ("fs","ft" ), (False, False )), + 0b110110: (MIPS_INS_C_OLE_D, "c.ole.d", ("fs","ft" ), (False, False )), + 0b110111: (MIPS_INS_C_ULE_D, "c.ule.d", ("fs","ft" ), (False, False )), + 0b111000: (MIPS_INS_C_SF_D, "c.sf.d", ("fs","ft" ), (False, False )), + 0b111001: (MIPS_INS_C_NGLE_D, "c.ngle.d", ("fs","ft" ), (False, False )), + 0b111010: (MIPS_INS_C_SEQ_D, "c.seq.d", ("fs","ft" ), (False, False )), + 0b111011: (MIPS_INS_C_NGL_D, "c.ngl.d", ("fs","ft" ), (False, False )), + 0b111100: (MIPS_INS_C_LT_D, "c.lt.d", ("fs","ft" ), (False, False )), + 0b111101: (MIPS_INS_C_NGE_D, "c.nge.d", ("fs","ft" ), (False, False )), + 0b111110: (MIPS_INS_C_LE_D, "c.le.d", ("fs","ft" ), (False, False )), + 0b111111: (MIPS_INS_C_NGT_D, "c.ngt.d", ("fs","ft" ), (False, False )), + }), + 0b010100: (mips_get_function, { + 0b100000: (MIPS_INS_CVT_S_W, "cvt.s.w", ("fd","fs"), (True , False)), + 0b100001: (MIPS_INS_CVT_D_W, "cvt.d.w", ("fd","fs"), (True , False)), + }), + 0b010101: (mips_get_function, { + 0b100000: (MIPS_INS_CVT_S_L, "cvt.s.l", ("fd","fs"), (True , False)), + 0b100001: (MIPS_INS_CVT_D_L, "cvt.d.l", ("fd","fs"), (True , False)), + }), + }), + 0b010100: (MIPS_INS_BEQL, "beql", ("rs","rt","offset" ), (False, False, False)), + 0b010101: (MIPS_INS_BNEL, "bnel", ("rs","rt","offset" ), (False, False, False)), + 0b010110: (MIPS_INS_BLEZL, "blezl", ("rs","offset" ), (False, False )), + 0b010111: (MIPS_INS_BGTZL, "bgtzl", ("rs","offset" ), (False, False )), + 0b011000: (MIPS_INS_DADDI, "daddi", ("rt","rs","imm" ), (True , False, False)), + 0b011001: (MIPS_INS_DADDIU, "daddiu", ("rt","rs","imm" ), (True , False, False)), + 0b011010: (MIPS_INS_LDL, "ldl", ("rt","offset(base)"), (True , False )), + 0b011011: (MIPS_INS_LDR, "ldr", ("rt","offset(base)"), (True , False )), + 0b100000: (MIPS_INS_LB, "lb", ("rt","offset(base)"), (True , False )), + 0b100001: (MIPS_INS_LH, "lh", ("rt","offset(base)"), (True , False )), + 0b100010: (MIPS_INS_LWL, "lwl", ("rt","offset(base)"), (True , False )), + 0b100011: (MIPS_INS_LW, "lw", ("rt","offset(base)"), (True , False )), + 0b100100: (MIPS_INS_LBU, "lbu", ("rt","offset(base)"), (True , False )), + 0b100101: (MIPS_INS_LHU, "lhu", ("rt","offset(base)"), (True , False )), + 0b100110: (MIPS_INS_LWR, "lwr", ("rt","offset(base)"), (True , False )), + 0b100111: (MIPS_INS_LWU, "lwu", ("rt","offset(base)"), (True , False )), + 0b101000: (MIPS_INS_SB, "sb", ("rt","offset(base)"), (False, False )), + 0b101001: (MIPS_INS_SH, "sh", ("rt","offset(base)"), (False, False )), + 0b101010: (MIPS_INS_SWL, "swl", ("rt","offset(base)"), (False, False )), + 0b101011: (MIPS_INS_SW, "sw", ("rt","offset(base)"), (False, False )), + 0b101100: (MIPS_INS_SDL, "sdl", ("rt","offset(base)"), (False, False )), + 0b101101: (MIPS_INS_SDR, "sdr", ("rt","offset(base)"), (False, False )), + 0b101110: (MIPS_INS_SWR, "swr", ("rt","offset(base)"), (False, False )), + 0b101111: (MIPS_INS_CACHE, "cache", ("op","offset(base)"), (False, False, False)), + 0b110000: (MIPS_INS_LL, "ll", ("rt","offset(base)"), (True , False )), + 0b110001: (MIPS_INS_LWC1, "lwc1", ("ft","offset(base)"), (True , False )), + # lwc2 + 0b110100: (MIPS_INS_LLD, "lld", ("rt","offset(base)"), (True , False )), + 0b110101: (MIPS_INS_LDC1, "ldc1", ("ft","offset(base)"), (True , False )), + # ldc2 + 0b110111: (MIPS_INS_LD, "ld", ("rt","offset(base)"), (True , False )), + 0b111000: (MIPS_INS_SC, "sc", ("rt","offset(base)"), (False, False )), + 0b111001: (MIPS_INS_SWC1, "swc1", ("ft","offset(base)"), (False, False )), + # lwc2 + 0b111100: (MIPS_INS_SCD, "scd", ("rt","offset(base)"), (False, False )), + 0b111101: (MIPS_INS_SDC1, "sdc1", ("ft","offset(base)"), (False, False )), + # sdc2 + 0b111111: (MIPS_INS_SD, "sd", ("rt","offset(base)"), (False, False )), +} + +rsp_insns = { + 0b000000: (mips_get_special, { + # opcode id mnemonic fields field is written to + 0b000000: (MIPS_INS_SLL, "sll", ("rd","rt","sa"), (True , False, False)), + 0b000010: (MIPS_INS_SRL, "srl", ("rd","rt","sa"), (True , False, False)), + 0b000011: (MIPS_INS_SRA, "sra", ("rd","rt","sa"), (True , False, False)), + 0b000100: (MIPS_INS_SLLV, "sllv", ("rd","rt","rs"), (True , False, False)), + 0b000110: (MIPS_INS_SRLV, "srlv", ("rd","rt","rs"), (True , False, False)), + 0b000111: (MIPS_INS_SRAV, "srav", ("rd","rt","rs"), (True , False, False)), + 0b001000: (MIPS_INS_JR, "jr", ("rs", ), (False, )), + 0b001001: (MIPS_INS_JALR, "jalr", ("rs", ), (False, )), # technically also rd but it's always $ra + 0b001101: (MIPS_INS_BREAK, "break", ("code", ), (False, )), + 0b100000: (MIPS_INS_ADD, "add", ("rd","rs","rt"), (True , False, False)), + 0b100001: (MIPS_INS_ADDU, "addu", ("rd","rs","rt"), (True , False, False)), + 0b100010: (MIPS_INS_SUB, "sub", ("rd","rs","rt"), (True , False, False)), + 0b100011: (MIPS_INS_SUBU, "subu", ("rd","rs","rt"), (True , False, False)), + 0b100100: (MIPS_INS_AND, "and", ("rd","rs","rt"), (True , False, False)), + 0b100101: (MIPS_INS_OR, "or", ("rd","rs","rt"), (True , False, False)), + 0b100110: (MIPS_INS_XOR, "xor", ("rd","rs","rt"), (True , False, False)), + 0b100111: (MIPS_INS_NOR, "nor", ("rd","rs","rt"), (True , False, False)), + 0b101010: (MIPS_INS_SLT, "slt", ("rd","rs","rt"), (True , False, False)), + 0b101011: (MIPS_INS_SLTU, "sltu", ("rd","rs","rt"), (True , False, False)), + }), + 0b000001: (mips_get_regimm, { + 0b00000: (MIPS_INS_BLTZ, "bltz", ("rs","offset"), (False, False)), + 0b00001: (MIPS_INS_BGEZ, "bgez", ("rs","offset"), (False, False)), + 0b10000: (MIPS_INS_BLTZAL, "bltzal", ("rs","offset"), (False, False)), + 0b10001: (MIPS_INS_BGEZAL, "bgezal", ("rs","offset"), (False, False)), + }), + 0b000010: (MIPS_INS_J, "j", ("target", ), (False, )), + 0b000011: (MIPS_INS_JAL, "jal", ("target", ), (False, )), + 0b000100: (MIPS_INS_BEQ, "beq", ("rs","rt","offset"), (False, False, False)), + 0b000101: (MIPS_INS_BNE, "bne", ("rs","rt","offset"), (False, False, False)), + 0b000110: (MIPS_INS_BLEZ, "blez", ("rs","offset" ), (False, False )), + 0b000111: (MIPS_INS_BGTZ, "bgtz", ("rs","offset" ), (False, False )), + 0b001000: (MIPS_INS_ADDI, "addi", ("rt","rs","imm" ), (True , False, False)), + 0b001001: (MIPS_INS_ADDIU, "addiu", ("rt","rs","imm" ), (True , False, False)), + 0b001010: (MIPS_INS_SLTI, "slti", ("rt","rs","imm" ), (True , False, False)), + 0b001011: (MIPS_INS_SLTIU, "sltiu", ("rt","rs","imm" ), (True , False, False)), + 0b001100: (MIPS_INS_ANDI, "andi", ("rt","rs","imm" ), (True , False, False)), + 0b001101: (MIPS_INS_ORI, "ori", ("rt","rs","imm" ), (True , False, False)), + 0b001110: (MIPS_INS_XORI, "xori", ("rt","rs","imm" ), (True , False, False)), + 0b001111: (MIPS_INS_LUI, "lui", ("rt","imm" ), (True , False )), + 0b010000: (mips_get_cop0, { + 0b00000: (MIPS_INS_MFC0, "mfc0", ("rt","cd"), (True , False)), + 0b00100: (MIPS_INS_MTC0, "mtc0", ("rt","cd"), (False, True )), + }), + 0b010010: (mips_get_cop2_func, { # TODO this encoding got ugly, move to a mask matcher like gnu objdump + 0b0: (mips_get_cop2, { + 0b0000: (MIPS_INS_MFC2, "mfc2", ("rt", "vd[e]"), (True , False)), + 0b0100: (MIPS_INS_MTC2, "mtc2", ("rt", "vd[e]"), (False, True )), + 0b0010: (MIPS_INS_CFC2, "cfc2", ("rt", "vc" ), (True , False)), + 0b0110: (MIPS_INS_CTC2, "ctc2", ("rt", "vc" ), (False, True )), + }), + 0b1: (mips_get_function, { + 0b000000: (MIPS_INS_VMULF, "vmulf", ("vd", "vs", "vt[e]"), (True , False, False)), + 0b000001: (MIPS_INS_VMULU, "vmulu", ("vd", "vs", "vt[e]"), (True , False, False)), + 0b000010: (MIPS_INS_VRNDP, "vrndp", ("vd", "vs", "vt[e]"), (True , False, False)), + 0b000011: (MIPS_INS_VMULQ, "vmulq", ("vd", "vs", "vt[e]"), (True , False, False)), + 0b000100: (MIPS_INS_VMUDL, "vmudl", ("vd", "vs", "vt[e]"), (True , False, False)), + 0b000101: (MIPS_INS_VMUDM, "vmudm", ("vd", "vs", "vt[e]"), (True , False, False)), + 0b000110: (MIPS_INS_VMUDN, "vmudn", ("vd", "vs", "vt[e]"), (True , False, False)), + 0b000111: (MIPS_INS_VMUDH, "vmudh", ("vd", "vs", "vt[e]"), (True , False, False)), + 0b001000: (MIPS_INS_VMACF, "vmacf", ("vd", "vs", "vt[e]"), (True , False, False)), + 0b001001: (MIPS_INS_VMACU, "vmacu", ("vd", "vs", "vt[e]"), (True , False, False)), + 0b001010: (MIPS_INS_VRNDN, "vrndn", ("vd", "vs", "vt[e]"), (True , False, False)), + 0b001011: (MIPS_INS_VMACQ, "vmacq", ("vd", "vs", "vt[e]"), (True , False, False)), + 0b001100: (MIPS_INS_VMADL, "vmadl", ("vd", "vs", "vt[e]"), (True , False, False)), + 0b001101: (MIPS_INS_VMADM, "vmadm", ("vd", "vs", "vt[e]"), (True , False, False)), + 0b001110: (MIPS_INS_VMADN, "vmadn", ("vd", "vs", "vt[e]"), (True , False, False)), + 0b001111: (MIPS_INS_VMADH, "vmadh", ("vd", "vs", "vt[e]"), (True , False, False)), + 0b010000: (MIPS_INS_VADD, "vadd", ("vd", "vs", "vt[e]"), (True , False, False)), + 0b010001: (MIPS_INS_VSUB, "vsub", ("vd", "vs", "vt[e]"), (True , False, False)), + 0b010011: (MIPS_INS_VABS, "vabs", ("vd", "vs", "vt[e]"), (True , False, False)), + 0b010100: (MIPS_INS_VADDC, "vaddc", ("vd", "vs", "vt[e]"), (True , False, False)), + 0b010101: (MIPS_INS_VSUBC, "vsubc", ("vd", "vs", "vt[e]"), (True , False, False)), + 0b011101: (MIPS_INS_VSAR, "vsar", ("vd", "vs", "vt[e]"), (True , False, False)), + 0b100000: (MIPS_INS_VLT, "vlt", ("vd", "vs", "vt[e]"), (True , False, False)), + 0b100001: (MIPS_INS_VEQ, "veq", ("vd", "vs", "vt[e]"), (True , False, False)), + 0b100010: (MIPS_INS_VNE, "vne", ("vd", "vs", "vt[e]"), (True , False, False)), + 0b100011: (MIPS_INS_VGE, "vge", ("vd", "vs", "vt[e]"), (True , False, False)), + 0b100100: (MIPS_INS_VCL, "vcl", ("vd", "vs", "vt[e]"), (True , False, False)), + 0b100101: (MIPS_INS_VCH, "vch", ("vd", "vs", "vt[e]"), (True , False, False)), + 0b100110: (MIPS_INS_VCR, "vcr", ("vd", "vs", "vt[e]"), (True , False, False)), + 0b100111: (MIPS_INS_VMRG, "vmrg", ("vd", "vs", "vt[e]"), (True , False, False)), + 0b101000: (MIPS_INS_VAND, "vand", ("vd", "vs", "vt[e]"), (True , False, False)), + 0b101001: (MIPS_INS_VNAND, "vnand", ("vd", "vs", "vt[e]"), (True , False, False)), + 0b101010: (MIPS_INS_VOR, "vor", ("vd", "vs", "vt[e]"), (True , False, False)), + 0b101011: (MIPS_INS_VNOR, "vnor", ("vd", "vs", "vt[e]"), (True , False, False)), + 0b101100: (MIPS_INS_VXOR, "vxor", ("vd", "vs", "vt[e]"), (True , False, False)), + 0b101101: (MIPS_INS_VNXOR, "vnxor", ("vd", "vs", "vt[e]"), (True , False, False)), + 0b110000: (MIPS_INS_VRCP, "vrcp", ("vd[ed]", "vt[e]" ), (True , False)), + 0b110001: (MIPS_INS_VRCPL, "vrcpl", ("vd[ed]", "vt[e]" ), (True , False)), + 0b110010: (MIPS_INS_VRCPH, "vrcph", ("vd[ed]", "vt[e]" ), (True , False)), + 0b110011: (MIPS_INS_VMOV, "vmov", ("vd[ed]", "vt[e]" ), (True , False)), + 0b110100: (MIPS_INS_VRSQ, "vrsq", ("vd[ed]", "vt[e]" ), (True , False)), + 0b110101: (MIPS_INS_VRSQL, "vrsql", ("vd[ed]", "vt[e]" ), (True , False)), + 0b110110: (MIPS_INS_VRSQH, "vrsqh", ("vd[ed]", "vt[e]" ), (True , False)), + 0b110111: (MIPS_INS_VNOP, "vnop", ( ), ()), + }), + }), + 0b100000: (MIPS_INS_LB, "lb", ("rt","offset(base)"), (True , False)), + 0b100001: (MIPS_INS_LH, "lh", ("rt","offset(base)"), (True , False)), + 0b100011: (MIPS_INS_LW, "lw", ("rt","offset(base)"), (True , False)), + 0b100100: (MIPS_INS_LBU, "lbu", ("rt","offset(base)"), (True , False)), + 0b100101: (MIPS_INS_LHU, "lhu", ("rt","offset(base)"), (True , False)), + 0b101000: (MIPS_INS_SB, "sb", ("rt","offset(base)"), (False, False)), + 0b101001: (MIPS_INS_SH, "sh", ("rt","offset(base)"), (False, False)), + 0b101011: (MIPS_INS_SW, "sw", ("rt","offset(base)"), (False, False)), + 0b110010: (mips_get_lwc2, { + 0b00000: (MIPS_INS_LBV, "lbv", ("vt[ed]", "voffset(base)"), (True , False)), + 0b00001: (MIPS_INS_LSV, "lsv", ("vt[ed]", "voffset(base)"), (True , False)), + 0b00010: (MIPS_INS_LLV, "llv", ("vt[ed]", "voffset(base)"), (True , False)), + 0b00011: (MIPS_INS_LDV, "ldv", ("vt[ed]", "voffset(base)"), (True , False)), + 0b00100: (MIPS_INS_LQV, "lqv", ("vt[ed]", "voffset(base)"), (True , False)), + 0b00101: (MIPS_INS_LRV, "lrv", ("vt[ed]", "voffset(base)"), (True , False)), + 0b00110: (MIPS_INS_LPV, "lpv", ("vt[ed]", "voffset(base)"), (True , False)), + 0b00111: (MIPS_INS_LUV, "luv", ("vt[ed]", "voffset(base)"), (True , False)), + 0b01000: (MIPS_INS_LHV, "lhv", ("vt[ed]", "voffset(base)"), (True , False)), + 0b01001: (MIPS_INS_LFV, "lfv", ("vt[ed]", "voffset(base)"), (True , False)), + 0b01011: (MIPS_INS_LTV, "ltv", ("vt[ed]", "voffset(base)"), (True , False)), + }), + 0b111010: (mips_get_swc2, { + 0b00000: (MIPS_INS_SBV, "sbv", ("vt[ed]", "voffset(base)"), (False, False)), + 0b00001: (MIPS_INS_SSV, "ssv", ("vt[ed]", "voffset(base)"), (False, False)), + 0b00010: (MIPS_INS_SLV, "slv", ("vt[ed]", "voffset(base)"), (False, False)), + 0b00011: (MIPS_INS_SDV, "sdv", ("vt[ed]", "voffset(base)"), (False, False)), + 0b00100: (MIPS_INS_SQV, "sqv", ("vt[ed]", "voffset(base)"), (False, False)), + 0b00101: (MIPS_INS_SRV, "srv", ("vt[ed]", "voffset(base)"), (False, False)), + 0b00110: (MIPS_INS_SPV, "spv", ("vt[ed]", "voffset(base)"), (False, False)), + 0b00111: (MIPS_INS_SUV, "suv", ("vt[ed]", "voffset(base)"), (False, False)), + 0b01000: (MIPS_INS_SHV, "shv", ("vt[ed]", "voffset(base)"), (False, False)), + 0b01001: (MIPS_INS_SFV, "sfv", ("vt[ed]", "voffset(base)"), (False, False)), + 0b01010: (MIPS_INS_SWV, "swv", ("vt[ed]", "voffset(base)"), (False, False)), + 0b01011: (MIPS_INS_STV, "stv", ("vt[ed]", "voffset(base)"), (False, False)), + }), +} diff --git a/tools/util.py b/tools/util.py new file mode 100644 index 0000000..b6c6155 --- /dev/null +++ b/tools/util.py @@ -0,0 +1,44 @@ + +import struct + +def enumerate_stepped(l, start=0, step=1): + p = start + for e in l: + yield p, e + p += step + +def back_align(x, al): + return x - (x % al) + +def forward_align(x, al): + return (x + (al - 1)) & ~(al - 1) + +def as_double(b): + return struct.unpack(">d", b)[0] + +def as_dword(b): + return struct.unpack(">Q", b)[0] + +def as_float(b): + return struct.unpack(">f", b)[0] + +def as_word(b): + return struct.unpack(">I", b)[0] + +def as_hword(b): + return struct.unpack(">H", b)[0] + +def as_double_list(b): + return [i[0] for i in struct.iter_unpack(">d", b)] + +def as_dword_list(b): + return [i[0] for i in struct.iter_unpack(">Q", b)] + +def as_float_list(b): + return [i[0] for i in struct.iter_unpack(">f", b)] + +def as_word_list(b): + return [i[0] for i in struct.iter_unpack(">I", b)] + +def as_hword_list(b): + return [h[0] for h in struct.iter_unpack(">H", b)]