PSP로 동영상을 보려고 인코딩 프로그램을 찾다가 꽤나 괜찮은 놈을 발견했습니다. XviD4PSP라는 녀석인데, 고화질로 인코딩 해주고, 파일 포맷 또한 PSP에서 바로 재생가능한 .mp4 파일로 만들어 줍니다.^^)/~

실행 파일은 http://pspmini.mud4u.com/bbs/board.php?bo_table=Pspmini_Homebrew&wr_id=28379 에서 다운 받을 수 있습니다. 아래에 파일로도 첨부했습니다.

사실 더 높은 버전의 XviD4PSP도 있지만 자막 크기를 조절하는 옵션이 사라진 듯(?)하더군요. 그래서 4.114 버전을 사용하게 됬습니다.

 자막 조절 방법은 http://pspmini.mud4u.com/bbs/board.php?bo_table=Pspmini_Tip&wr_id=2273&page=&sfl=wr_subject&stx=XVID4PSP&sop=and 에서 보실 수 있습니다. 포인트는 동영상의 Advance Option에 가장 아래에 있는 Auto Load Subtitles 옵션을 해제하는 것입니다. ^^;;; 안그러면 자막이 겹쳐서 나옵니다.

 이거 PSP를 쓰는 재미가 또 하나 늘었군요. ^^)/~
 그럼 다들 좋은 밤 되시길~ ;)


 오늘 후배가 꽤나 괜찮은 링크를 보내주더군요. ^^)/~ 후배의 블로그( http://www.filewiki.net/tc/entry/PSP-%EA%B0%9C%EB%B0%9C%EC%97%90-%EB%8C%80%ED%95%9C-%EC%9E%90%EB%A3%8C ) 에서 찾았습니다. ㅎㅎ

 한글로 된 자료를 찾으시는 분들이 많으시던데, 희소식이 되겠군요. ^^)/~


 그럼 좋은 하루 되세요 ;)
 학교 후배에게 뽐뿌를 해서 PSP를 지르게 만들었습니다. 그런데 이녀석이 홈브루를 개발한답시고 VS.net 2008용 App Wizard를 만들더군요.

 AppWizard는 후배의 블로그(http://www.filewiki.net/tc/entry/PSP-%EA%B0%9C%EB%B0%9C-AppWizard)에서 다운받을 수 있습니다.
 
사용자 삽입 이미지

 VS.net 환경에 익숙한 분이시라면 더욱 편리하게 사용하실 수 있을 것 같습니다. ^^)/~


 PSP의 비디오 모드를 뒤지다 보니, 4BYTE RGB를 사용하는 FrameBuffer모드가 기본인 것 같았습니다. DebugPrint류의 함수를 곰곰히 살펴본 결과 U32의 값으로 비디오 주소에 계속 출력하고 있더군요. 이걸로 바로 확신이 섰습니다. ^0^)/~

 그래서 NDS에 만들어뒀던 한글 출력 라이브러리를 포팅할려고, 뚝딱 소스를 갖다 부었더니 뭔가 잘 안되더군요. ㅜ_ㅜ)/~ 한글이 출력되는 게 아니라 뭔 점같은게 출력됬습니다. 한참 소스를 뒤진 결과, 간단한 연산 버그가 있어서 그랬습니다. 교육 때 들었던 unsigned char과 int의 연산 문제를 제 소스에서 딱 마주치니 웃음이 실실... ㅜ_ㅜ...

 결국 그 문제를 해결하고 나니 화면에 한글이 나왔습니다. ㅜ_ㅜ)-b 아아~ 이 감명깊은 순간을 캡쳐로 저장했어야하는데 RemoteJoy라는 프로그램을 깔지 않아서.... 내일 집에 오는대로 RemoteJoy를 설치해서 캡쳐해 올리겠습니다. 물론 소스와 함께 말이지요 >ㅁ<)/~!!!

 그럼 다들 좋은밤 되세요 ^^)/~~


 어제 한 2시간을 시도했었는데, 결국 실패했습니다. ㅜ_ㅜ... 소니 정품 메모리만 되는 것인가요? ㅜ_ㅜ 메직 메모리로 설정하고 판도라 배터리를 만들었는데, 샌디스크 메모리라서 그런지 인식이 안되더군요. 흑흑...

 그래서 그냥 펌웨어 버전만 업데이트하고 말았습니다. ㅜ_ㅜ)/~ 쓰던 3.80 버전에 문제가 있는지 가끔 느려지는 경우가 있더군요. 3.90버전으로 올라갔는데 아직은 그런 문제가 안보이네요. 좀 더 테스트를 해보고 글 남기겠습니다. ^^)/~

 주말을 맞아 하루종일 PSP와 NDS를 가지고 놀아야겠네요.
 다들 좋은 주말 보내세요. ;)


 제 PSP의 커스텀펌웨어 버전은 3.80입니다. 그런데 이 놈이 뭔가 좀 불안한 구석도 있고 동작이 이상하게 될 때도 있어서 펌웨어 업데이트를 찾아보고 있었습니다. 한참을 찾다보니 다크 알렉스(Dark Alex)의 홈페이지가 나오더군요. 정말 여러 버전의 커스텀펌웨어(커펌)를 개발했던데, 완전 킹왕짱입니다. ㅎㅎ 다크 알렉스의 사이트는 http://www.dark-alex.org 이니 관심있으신 분은 한번 들어가보세요. ^^)/~

 다크 알렉스의 사이트에 1.5 Custom Firmware 코드가 있길래 뭔가해서 살펴봤더니 1.5 펌웨어에 패치를 수행하는 코드인 것 같더군요. 그중에서 recovery 소스를 열어봤는데, USB를 사용하는 코드가 있었습니다. 딱봐도 한눈에 알수있던데, USB 제어하는 코드가 flash:0 영역에 모듈형태로 들어있더군요.

  정말 한눈에 딱 봐도 알 수 있지 않습니까? LoadStartModule()함수가 flash:0에서 커널로 로드해주고 있습니다. ^^)/~ PSP 커널은 정말 괴물이군요. 이정도까지 지원해 주다니... 이거 원 홈브루에서는 따로 손댈것도 없을 것 같습니다. 정말 NDS 홈브루를 개발할 때와 너무 비교되는군요.

 어쩌면 이런 지원때문에 NDS보다 PSP가 하드웨어적으로 분석된 자료가 적은 건지도 모르겠습니다. 다들 스펙 정도만 적혀있을 뿐이지 실제 구성도나 포트 I/O 같은 자료는 없더라구요(혹시나 PSP에 대한 자료를 갖고 계신분은 제보 부탁드립니다. ^^;;;).

 그나저나 커펌 버전을 높여야할지 고민입니다. 3.90 M33 버전이 안정적인지도 모르겠고... 아아~ 진짜 고민됩니다. ㅜ_ㅜ... 이걸 어찌해야할까요?


01 따라하는 PSP 홈브루 개발 - Hello World 출력

원문 :http://kkamagui.springnote.com/pages/1075736

 

들어가기 전에...

 

0.시작하면서...

 이 글은 PSP 홈브루(Homebrew)를 Step by Step 형식으로 개발할 수 있도록 도와주는 문서이다. PSP SDK를 사용하는 방법만 단순히 설명하기보다 PSP의 전체적인 동작 방식과 흐름과 함께 설명하는데 목적을 두고 있다. 이번 회에서는 Hello World를 출력하는  간단한 홈브루를 구현해 볼 것이며, 더불이 PSP Kernel과 PSP 응용프로그램의 연결고리도 함께 살펴볼 것이다.

 

1.예제 소스코드

 아래는 처음으로 작성하는 "Hello World" 프로그램이다. 아래의 코드를 DevkitPSP로 컴파일 및 링크하면 EBOOT.PBP 파일을 얻을 수 있다. 이 파일을 메모리스틱에 PSP->GAME->TEST 폴더로 복사하면 PSP Home Menu의 Game 항목에서 볼 수 있다.

  1. #include <pspkernel.h>
    #include <pspdebug.h>

    // 매크로 정의
    #define TRUE 1
    #define FALSE 0
  2. #define printf pspDebugScreenPrintf

    /* Define the module info section */
    PSP_MODULE_INFO("KKAMAGUI", 0, 1, 1);

    /* Define the main thread's attribute value (optional) */
    PSP_MAIN_THREAD_ATTR(THREAD_ATTR_USER | THREAD_ATTR_VFPU);

    // 종료 Flag
    int g_bExit = FALSE;

    int ExitCallBack(int arg1, int arg2, void *common)
    {
        printf( "%X %X", arg1, arg2 );
        g_bExit = TRUE;
        return 0;
    }
     
    int main(int argc, char *argv[])
    {
        int cbid;

        pspDebugScreenInit();

        // Call Back 설정
        cbid = sceKernelCreateCallback("Exit Callback", ExitCallBack, NULL);
        sceKernelRegisterExitCallback(cbid);
       
        printf("Hello World\n");

        while( g_bExit == FALSE )
        {
            ;
        }
        sceKernelExitGame();
        return 0;
    }

 

2.예제 소스코드 분석

 그럼 지금부터 위의 소스를 하나하나 분석해보자. 우선 가장 처음에 나오는 PSP_MOUDLE_INFO() 매크로는 pspmoduleinfo.h 파일에 정의되어있으며, 아래와 같이 특수한 섹션(.lib.ent.XX, .lib.stub.XX)에 데이터를 삽입하도록 되어있다. 주석을 보면 Source 파일에 반드시 있어야 한다고하니 필수 요소인 듯 하며, 나중에 PSP Kernel이 Load할 때 참고하는 정보임을 추측할 수 있다. 그냥 필수적으로 타이핑해야 하는 부분이라고 생각하면 된다.

 
  1. // pspmoduleinfo.h
  2. /* Declare a module.  This must be specified in the source of a library or executable. */
    #define PSP_MODULE_INFO(name, attributes, major_version, minor_version) \
        __asm__ (                                                       \
        "    .set push\n"                                               \
        "    .section .lib.ent.top, \"a\", @progbits\n"                 \
        "    .align 2\n"                                                \
        "    .word 0\n"                                                 \
        "__lib_ent_top:\n"                                              \
        "    .section .lib.ent.btm, \"a\", @progbits\n"                 \
        "    .align 2\n"                                                \
        "__lib_ent_bottom:\n"                                           \
        "    .word 0\n"                                                 \
        "    .section .lib.stub.top, \"a\", @progbits\n"                \
        "    .align 2\n"                                                \
        "    .word 0\n"                                                 \
        "__lib_stub_top:\n"                                             \
        "    .section .lib.stub.btm, \"a\", @progbits\n"                \
        "    .align 2\n"                                                \
        "__lib_stub_bottom:\n"                                          \
        "    .word 0\n"                                                 \
        "    .set pop\n"                                                \
        "    .text\n"                                                    \
        );                                                              \
        extern char __lib_ent_top[], __lib_ent_bottom[];                \
        extern char __lib_stub_top[], __lib_stub_bottom[];              \
        SceModuleInfo module_info                                       \
            __attribute__((section(".rodata.sceModuleInfo"),        \
                       aligned(16), unused)) = {                \
          attributes, { minor_version, major_version }, name, 0, _gp,  \
          __lib_ent_top, __lib_ent_bottom,                              \
          __lib_stub_top, __lib_stub_bottom                             \
        }

 

 그 다음에 오는 PSP_MAIN_THREAD_ATTR() 매크로는 pspmoduleinfo.h에 정의되어있으며 변수에 값을 설정하는 간단한 역할만 한다. Optional한 부분이므로 굳이 쓰지 않아도 되나, 만약의 사태를 대비해서 일단 추가해 두자.

  1. // pspmoduleinfo.h 파일에 포함된 내용
  2. /* Define the main thread's attributes. */
    #define PSP_MAIN_THREAD_ATTR(attr) \
        unsigned int sce_newlib_attribute = (attr)

 Thread의 Attribute는 pspthreadman.h 파일에 있으며 아래와 같이 정의되어있다. PspThreadAttributes에 나와있는 주석을 보면 Thread의 종류에따라 Device에 접근할 수 있는 범위가 제한됨을 알 수 있다. 아직은 USB나 WLAN을 접근할 일이 없지만, 추후에 접근할 일이 생기면 Thread의 목적에 맞게 Type을 설정해야 하는 듯 하다. 이런 것도 있다는 것만 알고 넘어가자.

  1. /** Attribute for threads. */
    enum PspThreadAttributes
    {
        /** Enable VFPU access for the thread. */
        PSP_THREAD_ATTR_VFPU = 0x00004000,
        /** Start the thread in user mode (done automatically
          if the thread creating it is in user mode). */
        PSP_THREAD_ATTR_USER = 0x80000000,
        /** Thread is part of the USB/WLAN API. */
        PSP_THREAD_ATTR_USBWLAN = 0xa0000000,
        /** Thread is part of the VSH API. */
        PSP_THREAD_ATTR_VSH = 0xc0000000,
        /** Allow using scratchpad memory for a thread, NOT USABLE ON V1.0 */
        PSP_THREAD_ATTR_SCRATCH_SRAM = 0x00008000,
        /** Disables filling the stack with 0xFF on creation */
        PSP_THREAD_ATTR_NO_FILLSTACK = 0x00100000,
        /** Clear the stack when the thread is deleted */
        PSP_THREAD_ATTR_CLEAR_STACK = 0x00200000,
    };

 

다음은 ExitCallBack() 함수인데, 이 부분은 뒤에 sceKernelRegisterExitCallback() 함수를 설명하면서 같이 진행하기로 하고 main() 함수를 먼저 보자. main() 함수에서 제일 먼저 우리를 반기는 것은 pspDebugScreenInit() 함수다.  pspDebugScreenInit() 함수는 과연 무엇을 하는 함수일까? 함수가 psp라는 Prefix로 시작하는 것을 보아 PSP Library 함수임을 알 수 있으며 실제 함수의 구현부를 보면 아래와 같이 되어있다.

  1. // scr_printf.c 파일의 일부
  2. #define PSP_SCREEN_WIDTH 480
    #define PSP_SCREEN_HEIGHT 272
    #define PSP_LINE_SIZE 512
    #define PSP_PIXEL_FORMAT 3
  3. ... 생략 ...
  4. void pspDebugScreenInit()
    {
       X = Y = 0;
       /* Place vram in uncached memory */
       g_vram_base = (void *) (0x40000000 | (u32) sceGeEdramGetAddr());
       g_vram_offset = 0;
       sceDisplaySetMode(0, PSP_SCREEN_WIDTH, PSP_SCREEN_HEIGHT);
       sceDisplaySetFrameBuf((void *) g_vram_base, PSP_LINE_SIZE, PSP_PIXEL_FORMAT, 1);
       clear_screen(bg_col);
       init = 1;
    }

 코드에서 Display Mode를 408x272로 설정하고 Display할 데이터가 있는 주소 즉 Graphic Buffer를 FrameBuffer로 설정하는데, g_vram_base를 시작 주소로 설정하는 간단한 코드이다. PSP_LINE_SIZE는 확실치는 않지만 한 라인에 대응하는 Pixel의 수인 듯 하다. SCREEN_WIDTH가 480이고 PSP_LINE_SIZE가 512인 것으로 보아, 여유있게 잡았거나 Align하는 단위의 문제 때문에 좀 더 크게 잡은 것이 아닐까 추측한다. pspDebugScreenPrintf() 함수는 printf() 함수와 하는 역할이 거의 비슷하니 다음 함수로 넘어가겠다. 혹시 세부 구현이 궁금하다면 scr_printf.c 파일에 나와있으므로 관심있으면 참고하자.

 

 pspDebugScreenInit() 함수 아래를 자세히 보면 sceKernelXXX로 시작하는 함수를 볼 수 있다. 이 함수는 sceXXX Prefix로 시작되며, 이것은 PSP의 Kernel Service(Function)임을 나타낸다. sceXXX 로 시작하는 함수는 PSP Kernel로부터 Import 되는 함수로서, PSP Kernel이 프로그램을 로딩하면서 해당 영역에 실제 함수 주소를 연결해 주는 것 같다. 실제로 sceKernelCreateCallback() 함수의 정의를 따라가보면 구현은 없고 아래와 같은 Dummy Table만 볼 수 있다.

  1. // ThreadManForKernel.S 파일의 일부분
  2.     .set noreorder

    #include "pspimport.s"

    #ifdef F_ThreadManForKernel_0000
        IMPORT_START    "ThreadManForKernel",0x00010000
    #endif
    #ifdef F_ThreadManForKernel_0001
        IMPORT_FUNC    "ThreadManForKernel",0x0C106E53,sceKernelRegisterThreadEventHandler
    #endif
    #ifdef F_ThreadManForKernel_0002
        IMPORT_FUNC    "ThreadManForKernel",0x72F3C145,sceKernelReleaseThreadEventHandler
    #endif
    #ifdef F_ThreadManForKernel_0003
        IMPORT_FUNC    "ThreadManForKernel",0x369EEB6B,sceKernelReferThreadEventHandlerStatus
    #endif
    #ifdef F_ThreadManForKernel_0004
        IMPORT_FUNC    "ThreadManForKernel",0xE81CAF8F,sceKernelCreateCallback
    #endif
  3. ... 생략 ...

 IMPORT_FUNC는 pspimport.s 에 포함된 매크로로서 pspimport.s는 아래와 같이 어셈블리어 코드로 치환해주는 역할만 한다. 아래의 IMPORT_FUNC의 가운데 정도에 위치한 .ent 부분이 Loading 후에 실제로 Function Address로 치환되며, 이 위치의 Function Address를 사용하는 것으로 추측된다.


  1. .macro IMPORT_START module, flags_ver

        .set push
        .section .rodata.sceResident, "a"
        .word   0
    __stub_modulestr_\module:
        .asciz  "\module"
        .align  2

        .section .lib.stub, "a", @progbits
        .global __stub_module_\module
    __stub_module_\module:
        .word   __stub_modulestr_\module
        .word   \flags_ver
        .word   0x5
        .word   __executable_start
        .word   __executable_start

        .set pop
    .endm

    .macro IMPORT_FUNC module, funcid, funcname

        .set push
        .set noreorder

        .extern __stub_module_\module
        .section .sceStub.text, "ax", @progbits
        .globl  \funcname
        .type   \funcname, @function
        .ent    \funcname, 0
    \funcname:
        .word   __stub_module_\module
        .word   \funcid
        .end    \funcname
        .size   \funcname, .-\funcname

        .section .rodata.sceNid, "a"
        .word   \funcid

        .set pop
    .endm

    .macro IMPORT_FUNC_WITH_ALIAS module, funcid, funcname, alias

        .set push
        .set noreorder

        .extern __stub_module_\module
        .section .sceStub.text, "ax", @progbits
        .globl  \alias
        .type   \alias, @function
    \alias:
        .globl  \funcname
        .type   \funcname, @function
        .ent    \funcname, 0
    \funcname:
        .word   __stub_module_\module
        .word   \funcid
        .end    \funcname
        .size   \funcname, .-\funcname

        .section .rodata.sceNid, "a"
        .word   \funcid

        .set pop
    .endm

 

 예제의 하부에 있는 sceKernelCreateCallback() 함수는 CallBack Function의 Name과 Function Address, 그리고 Parameter를 받아서 Calback ID를 생성하여 반환한다. 이 반환된 ID를 등록하면 Callback 함수가 동작하는데, 테스트 프로그램에서는 sceKernelRegisterExitCallback() 함수를 사용해서 PSP의 Home 버튼과 연결하였다. sceKernelRegisterExitCallback() 함수는 Program이 끝났을 때, 즉 PSP의 Home 버튼을 눌러서 "예"를 선택했을 때 Callback을 불러주도록 등록하는 역할을 한다.

 Callback 함수의 원형은 아래와 같이 총 3개의 파라메터를 받도록 되어있으며, ExitCallBack() 함수의 생김새와 동일함을 알 수 있다.

  1. // pspthreadman.h 파일의 일부
  2. /** Callback function prototype */
    typedef int (*SceKernelCallbackFunction)(int arg1, int arg2, void *arg);

 ExitCallBack() 함수는  sceKernelRegisterExitCallback()에 의해 등록되었으므로,PSP의 Home 버튼을 눌렀을 때 XMB로 돌아가기를 선택하는 경우 불려진다. 혹시 Home 버튼을 눌렀을때 뜨는 선택 화면에서 호출되는 것이 아닌지 궁금해 할지도 몰라서, 테스트 해보기 위해 아래의 printf() 기능을 넣었다. 만약 Home 버튼을 누른 후 표시되는 메뉴에서 CallBack이 호출된다면 "아니오"를 선택하고 빠져나왔을때 화면에 무엇인가 출력되었어야 한다. 하지만 아무런 값이 출력되지 않은 것을 보아 메뉴에서 "예"를 누른 후 호출되는 것을 알 수 있다.

  1. int ExitCallBack(int arg1, int arg2, void *common)
    {
        printf( "%X %X", arg1, arg2 );
        //g_bExit = TRUE;
        return 0;
    }

 

 마지막 함수는 sceKernelExitGame() 함수이다. sce Prefix가 붙어있으므로 PSP Kenrel Service 임을 알 수 있으며, 이 함수를 호출하면 다시 PSP 메뉴(XMB)로 이동하게 된다. 이 함수를 ExitCallback()에서 부르게 되면 충돌이 발생하여 메뉴로 돌아가지 못하고 멈추므로 주의해야 한다.

 

3.컴파일 및 실행

 DevkitPro가 설치된 폴더의 PSP Sample Code 폴더에 보면 elf_template 폴더가 있다(D:\devkitPro\devkitPSP\psp\sdk\samples\template\elf_template). 그 폴더의 main.c 파일에 예제 소스를 덮어쓰고 cmd.exe를 실행하여 make를 입력하면 EBOO 파일이 생성될 것이다. 이 파일을 PSP 메모리스틱에 H:\PSP\GAME\Test 폴더에 넣은 후, PSP 메뉴의 게임->Memory Stick에 가면 실행할 수 있다. 화면 우측 상단에 하얀색으로 빛나는 멋진 Hello World가 표시될 것이다. @0@)/~

 

 

4.마치면서...

 이것으로 Hello World를 화면에 출력하는 PSP 홈브루(Homebrew)를 완성하였다. 첫시간이니만큼 API의 사용법보다는 전체적인 소스의 구성 및 구조에 더 치중하려고 노력하였다. 다음은 PSP의 키입력 처리에 대해서 알아보도록 하자.

 

 

이 글은 스프링노트에서 작성되었습니다.

01 PSP 홈브루(Homebrew) 개발 환경 설치

원문 : http://kkamagui.springnote.com/pages/1075476

 

들어가기 전에...

 

0. 시작하면서...

 PSP 개발 환경은 크게 PSPSDK + Cygwin or Linux, DevkitPro가 있다. DevkitPro가 설치도 편리하고 사용하기도 나쁘지 않으므로 DevkitPro를 설치해서 사용할 것이다. DevkitPro는 http://www.devkitpro.org에서 받을 수 있다. Cygwin + PSPSDK 조합이 편하다고 생각한다면, http://grampus.tistory.com/entry/참고-개발환경-구축을 참고하면 된다.

 

1.업데이트 파일 다운로드

 http://sourceforge.net/project/showfiles.php?group_id=114505로 이동하면 아래와 같은 화면이 보인다. 여기서 DevkitPro Updater를 다운로드 받아서 실행하자. 최신 버전의 설치파일을 다운로드하면 된다.

 Devkit1.PNG

<다운로드 할 파일>

2.업데이트 실행

 다운을 받고 나면 설치 과정을 거쳐야 한다. 다운로드한 DevkitPro Updater 파일을 적당한 폴더를 생성해서 넣고 실행하자. 그럼 아래와 같은 화면이 표시된다.

Devkit2.PNG

<업데이트 화면>

 

 위의 화면이 표시되면 Next 버튼을 눌러 파일을 다운 받자. 아래는 다운로드가 진행중이고 완료된 후 완전히 설치가 끝난 화면이다.

Devkit3.PNG

<다운로드 진행중>

Devkit4.PNG

<설치 완료>

 

 각자 취향에 맞게 설치한 후 해당 폴더로 이동하면 아래와 비슷한 폴더 구조를 볼 수 있다(필자는 D:\devkitPro 폴더에 설치를 했다).

PSP환경.PNG

<PSP 개발 폴더>

3.PATH 설정

 설치가 끝난 후, 컴파일을 정상적으로 수행하기 위해서는 Path를 설정해 줘야 한다. "내컴퓨터" 아이콘에서 오른쪽 버튼을 눌러 "시스템 등록 정보"를 표시한다. 그 후 Path에 D:\devkitPro\devkitPSP\bin를 가장 앞에 추가한다.

 PSPPath_설정.PNG

<PATH 추가>

4.테스트 프로그램 컴파일 및 링크

 콘솔(cmd.exe)을 띄워서 해당 소스 폴더로 이동한 후, make를 입력하거나 IDE의 명령실행 창에서 make를 입력하면 컴파일 및 링크를 실행할 수 있다.

 정상.PNG

<정상적인 경우>

 간혹 아래와 같이 Runtime Error가 발생할 수 있는데, 이런 경우 command.exe를 실행하여 컴파일하면 정상적으로 수행된다. 정확한 이유는 모르겠지만 프로그램 설치 과정에서 Shell 관련 DLL이 교체되어 문제가 발생하는 것이 아닌가 한다.

Error.PNG

<에러발생>

5.마치면서...

  지금까지 PSP 개발 툴 킷인 Devkit Pro를 설치하고 예제 프로그램을 컴파일/링크하여 실행하는 과정을 간단히 알아보았다. 이제 우리 모두 PSP 홈브루의 세계로 빠져보자. @ㅁ@)/~~

 

 

이 글은 스프링노트에서 작성되었습니다.

00 PSP Hardware Spec

원문 :  http://kkamagui.springnote.com/pages/1062052

참고 : http://wiki.ps2dev.org/psp:hardware_specifications

 

들어가기 전에...

 

1.CPU

1.1 Main CPU

  • Allegrex CPU

    • MIPS r4000 32-bit core 1-333mhz
    • 16kib I-Cache & D-Cache

      • 64-byte line length
      • 2-way set associative, LRU
    • No TLB
    • 7-stage pipeline
    • 32 32-bit registers
  • FPU (COP1)

    • 32-bit single precision
    • 32 32-bit registers
    • IEEE 754 compliant
    • Sqrt (28 cycles), div(28 cycles), most others 1 cycle
  • VFPU (COP2)

    • Vector FPU “Macromode only”
    • Designed for vector and matrix ops
    • 128 32-bit registers

      • Reconfigurable as scalar, vector or matrix
      • IEEE 754 Single precision float
    • Can also handle 32-bit int, 16-bit int, 8-bit int, half float
    • vmmul.z vd, vs, vt - 4×4 matrix/vector multiply, 22 cycles

 

1.2 Sub CPU

  • Media Block CPU

    • MIPS r4000-based core
    • 2MB Embedded DRAM
    • VME - Virtual Mobile Engine

      • Reconfigurable processor to decode audio & video
      • ATRAC3plus & MP3 for music

        • ATRAC3plus & ADPCM for games but not MP3 due to licensing issues
    • AVC H.264 engine

      • MPEG-4 Hardware accelerator
      • Up to 720x480x30fps

        • Libraries support 480x272x29.97fps

 

2.Bus

  • Main bus shared by CPU and Graphics Engine(GE)
  • CPU only has level-1 cache, recomend minimizing memory usage
  • Cache miss ~70 cycles
  • VRAM read ~44 cycles

    • contention with GE
  • Scratchpad read ~38 cycles

 

3.Graphic Engine

  • 2MB Embedded DRAM
  • Supports Lighting, skinning (8 weights), morphing, subdivision, pixel operations
  • Operates at bus speed (default 111mhz)
  • 3.5GB/s Bus bandwidth
  • 444 Mpixels/sec fill rate
  • 23 Mploys/sec T&L

 

4.Storage

 

5.Ports

  • USB-Port

 

6.Memory Map

 

Base Address   Length                      Description

------------------------------------------------------------------
0×00010000    0×00004000 (16 KiB)   Allegrex Scratchpad
0×04000000    0×00200000 (2 MiB)   Ge VRAM

0×08000000    0×00800000 (8 MiB)    Allegrex Kernel memory
0×08800000    0×01800000 (24 MiB)  Allegrex User memory

------------------------------------------------------------------

0×44000000    0×00200000 (2 MiB)    Ge VRAM (Cache Through)
0×48800000    0×01800000 (24 MiB)   Allegrex User memory (CacheThrough)

0×88000000    0×00800000 (8 MiB)    Allegrex Kernel memory (???)

 

IMPORTANT

To get uncached reads and writes, OR your pointers with 0×40000000 (for example, the location of the Ge VRAM then becomes 0×44000000). When writing to VRAM or feeding data to the GE (graphics chip) through display lists in main memory, this is VERY important. Not doing so will cause unpredictable behaviour and hanging because the graphics chip may miss your END and FINISH commands since they might still be sitting in the cache.

이 글은 스프링노트에서 작성되었습니다.

+ Recent posts