flat assembler
Message board for the users of flat assembler.

Index > Projects and Ideas > Chip-8 Emulator

Author
Thread Post new topic Reply to topic
windwakr



Joined: 30 Jun 2004
Posts: 827
windwakr 31 Aug 2010, 01:48
Simple Chip-8 I wrote in a couple of hours out of boredom.


VERY VERY ugly code, but it seems to work.

There are some 'public domain' programs for it available here, just add a '.c8' extension to the end of them:
http://www.zophar.net/pdroms/chip8.html



The Chip-8 controls are mapped to:
1234
qwer
asdf
zxcv


Emulator controls are:
Space: Pause the emu
Escape: Exit the emu
Plus and Minus on the numpad: Increase/decrease the instructions per second.
Control: When emu is paused, control allows you to load a new ROM. Emu remains paused.


I'm sorry if my coding style causes you to go blind. Very Happy
The emu is probably very buggy
Code:
;Simple Chip-8 emulator
;By windwakr
;Made at the end of August 2010

;Some of the basic timer/gdi framework borrowed from Alphonso:
;http://board.flatassembler.net/topic.php?t=9174


format PE GUI 4.0
include 'win32ax.inc'


entry start
section '.code' code readable executable

  start:
          invoke QueryPerformanceCounter,qpc    ;For PRNG.

          invoke  GetProcessHeap               ;Allocate the Chip-8's memory
          mov     [hHeap],eax
          invoke  HeapAlloc,[hHeap],0,0xFFF
          mov     [hMem],eax

          stdcall loadrom,1

          xor     edx,edx      ;Figure out how many Instructions to run per frame
          mov     eax,[IPS]
          mov     ebx,60
          div     ebx
          mov     [IPF],eax


          ;Just normal window junk
          invoke LoadIcon,0,IDI_APPLICATION
          mov    [wc.hIcon],eax
          invoke LoadCursor,0,IDC_ARROW
          mov    [wc.hCursor],eax
          invoke GetModuleHandle,0
          mov    [hInstance],eax
          mov    [wc.hInstance],eax
          invoke RegisterClass,wc

          invoke CreateDIBSection,0,BMPinfo,0,BitValues,0,0
          mov    [hBmp],eax

          invoke CreateWindowEx,0,_class,_title,WS_MINIMIZEBOX+WS_SYSMENU+WS_POPUP+WS_CAPTION+WS_VISIBLE,0,0,640,320,NULL,NULL,[hInstance],NULL
          mov    [mainhwnd],eax

          ;The client area needs to be 640 by 320, not the window
          invoke  GetClientRect,[mainhwnd],crect
          invoke  GetWindowRect,[mainhwnd],wrect
          mov     eax,[wrect.right]
          sub     eax,[wrect.left]
          sub     eax,[crect.right]
          add     eax,640
          mov     ebx,[wrect.bottom]
          sub     ebx,[wrect.top]
          sub     ebx,[crect.bottom]
          add     ebx,320
          invoke  MoveWindow,[mainhwnd],[wrect.left],[wrect.top],eax,ebx,FALSE
          invoke  UpdateWindow,[mainhwnd]

          invoke CreateCompatibleDC,0
          mov    [hdcMem],eax
          invoke SelectObject,[hdcMem],[hBmp]
          mov    [hbmOld],eax

          cinvoke wsprintf,buf,fmt,[IPS]
          invoke  SetWindowText,[mainhwnd],buf

          invoke ShowWindow,[mainhwnd],SW_SHOWNORMAL
          invoke UpdateWindow,[mainhwnd]

          ;;;;;;;
          ;Clear the screen
          stdcall CPUclrscrn
          ;;;;;;;

          ;Set the timer to go off 60 times a second.
          invoke SetTimer,[mainhwnd],1,16,CPUproc
          mov    [hTimer],eax

  msg_loop:
          invoke GetMessage,msg,NULL,0,0
          or     eax,eax
          jz     end_loop
          invoke TranslateMessage,msg
          invoke DispatchMessage,msg
          jmp    msg_loop

  end_loop:
          invoke KillTimer,[mainhwnd],[hTimer]
          invoke SelectObject,[hdcMem],[hbmOld]
          invoke DeleteObject,[hbmOld]
          invoke DeleteDC,[hdcMem]
          invoke HeapFree,[hHeap],0,[hMem]
          invoke ExitProcess,[msg.wParam]


;Firsttime variable tells it to close the program if it's the first time this is called and it fails. Else, we'll just keep emulating the open program.
proc loadrom stdcall firsttime:DWORD

          ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
          ;Ugly file selecting code...
          invoke  GetOpenFileName, ofn
          cmp     eax,0
          jne      .2
          cmp      [firsttime],1
          jne      .1
          invoke   MessageBox,NULL,'Error selecting file, closing down.','ERROR',MB_OK
          invoke   ExitProcess,0
      .1:
          mov      eax,1
          ret
      .2:
          stdcall CPUreset                     ;Reset the Chip-8 CPU
          invoke  CreateFile,filebuf,GENERIC_READ,0,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0
          cmp     eax,INVALID_HANDLE_VALUE
          jne     @f
          invoke   MessageBox,NULL,'Error opening file, closing down.','ERROR',MB_OK
          invoke   ExitProcess,0
       @@:
          mov     [hFile],eax
          invoke  GetFileSize,[hFile],0
          mov     [nSize],eax
          mov     eax,[hMem]
          add     eax,0x200
          invoke  ReadFile,[hFile],eax,[nSize],bytesread,0
          invoke  CloseHandle,[hFile]
          ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
          mov     eax,0
          ret
endp


proc WindowProc uses ebx esi edi, hwnd,wmsg,wparam,lparam
          cmp    [wmsg],WM_CLOSE
          je     .wmclose
          cmp    [wmsg],WM_PAINT
          je     .wmpaint
          cmp    [wmsg],WM_KEYDOWN
          je     .wmkeydown
          cmp    [wmsg],WM_KEYUP
          je     .wmkeyup
          cmp    [wmsg],WM_ERASEBKGND
          jne    .defwndproc
          mov    eax,1
          jmp    .finish

  .defwndproc:
          invoke DefWindowProc,[hwnd],[wmsg],[wparam],[lparam]
          jmp    .finish

  .wmpaint:
          invoke BeginPaint,[hwnd],PaintS
          mov    [hDC],eax

          invoke BitBlt,[hDC],0,0,640,320,[hdcMem],0,0,SRCCOPY
          invoke EndPaint,[hwnd],PaintS
          mov    eax,1
          jmp    .finish


  ;Ugly keypress code, viewer beware....
  .wmkeydown:
          pushad
          cmp    [wparam],VK_ESCAPE
          je     .wmclose
          cmp    [wparam],VK_SPACE
          jne    .notspace
          xor    [paused],1
 .updatetitle:
          cmp    [paused],1
          jne    @f
          cinvoke wsprintf,buf,fmt_paused,[IPS]
          invoke  SetWindowText,[mainhwnd],buf
          jmp    .donekeys
       @@:
          cinvoke wsprintf,buf,fmt,[IPS]
          invoke  SetWindowText,[mainhwnd],buf
          jmp     .donekeys
  .notspace:
          cmp    [wparam],VK_ADD
          jne    .notadd
          cmp    [IPS],10000
          je     .donekeys
          add    [IPS],100
          xor     edx,edx
          mov     eax,[IPS]
          mov     ebx,60
          div     ebx
          mov     [IPF],eax
          jmp    .updatetitle
  .notadd:
          cmp    [wparam],VK_SUBTRACT
          jne    .notsubtract
          cmp    [IPS],0
          je     .donekeys
          sub    [IPS],100
          xor     edx,edx
          mov     eax,[IPS]
          mov     ebx,60
          div     ebx
          mov     [IPF],eax
          jmp    .updatetitle
  .notsubtract:
          xor    ecx,ecx
          mov    edi,keys
          mov    esi,keycodes
       @@:
          lodsb
          movzx  eax,al
          cmp    [wparam],eax
          jne    .notkey
          add    edi,ecx
          mov    al,1
          stosb
          jmp    .donekeys
       .notkey:
          inc    ecx
          cmp    ecx,16
          jne    @b

          cmp    [wparam],VK_CONTROL
          jne    .donekeys
          cmp    [paused],1
          jne    .donekeys
          stdcall loadrom,0
          cmp     eax,1
          je      .donekeys
          stdcall CPUclrscrn
       .donekeys:
          popad
          xor    eax,eax
          jmp    .finish

  .wmkeyup:
          pushad
          xor    ecx,ecx
          mov    edi,keys
          mov    esi,keycodes
       @@:
          lodsb
          movzx  eax,al
          cmp    [wparam],eax
          jne    .notkey1
          add    edi,ecx
          mov    al,0
          stosb
          jmp    .donekeys1
       .notkey1:
          inc    ecx
          cmp    ecx,16
          jne    @b
       .donekeys1:
          popad
          xor    eax,eax
          jmp    .finish

  .wmclose:
          invoke PostQuitMessage,0
          xor    eax,eax
          jmp    .finish

  .finish:
          ret
endp



proc CPUreset stdcall
          mov    [CI],0
          mov    [CPC],0x200
          mov    [CDelay],0
          mov    [CSound],0
          mov    dword[CR],0
          mov    dword[CR+4],0
          mov    dword[CR+8],0
          mov    dword[CR+12],0

          mov    [curstck],endstack

          mov    ecx,0xFFF shr 2   ;Zero out the memory
          mov    edi,[hMem]
          mov    eax,0
          rep    stosd
          mov    edi,[hMem]
          mov    esi,font
          mov    ecx,80
       @@:
          lodsb
          stosb
          loop   @b
          ret
endp


;The timer proc
proc CPUproc uses ebx esi edi, hwnd,tmsg,event,dtime
          cmp     [paused],1
          je      @f
          stdcall CPUdectimers
          stdcall CPUexecute,[IPF]   ;Execute the number of instructions specified by IPF(instructions per frame)
       @@:
          invoke InvalidateRect,[mainhwnd],0,0
          xor    eax,eax
          ret
endp


proc CPUdectimers stdcall
          cmp    [CDelay],0
          je     @f
          dec    [CDelay]
       @@:
          cmp    [CSound],0
          je     @f
          dec    [CSound]
          stdcall CPUbeep
       @@:
          ret
endp


proc CPUbeep stdcall  ;Empty.....for now.....
          ret
endp



;Will document this later.....
proc CPUexecute stdcall number:DWORD
  locals
      ;-.decode0 to save a word for each one
      jmptbl    dw .decode0-.decode0, .opcode1NNN-.decode0, .opcode2NNN-.decode0, .opcode3XNN-.decode0, .opcode4XNN-.decode0, .opcode5XY0-.decode0,\
                   .opcode6XNN-.decode0, .opcode7XNN-.decode0, .decode8-.decode0, .opcode9XY0-.decode0, .opcodeANNN-.decode0, .opcodeBNNN-.decode0,\
                   .opcodeCXNN-.decode0, .opcodeDXYN-.decode0, .decodeE-.decode0, .decodeF-.decode0
    num dd 0
  endl
          mov    ebx,[number]
          mov    [num],ebx
    .loop:
          cmp    [num],0
          je     .done

          mov    edi,[hMem]
          mov    ebx,[CPC]
          add    edi,ebx
          xor    ebx,ebx
          mov    bh,byte[edi]
          or     bl,byte[edi+1]
          add    [CPC],2

          mov    eax,ebx
          and    eax,0xF000
          shr    eax,12

          lea    eax,[eax*2+jmptbl]
          movzx  eax,word[eax]
          add    eax,.decode0
          jmp    eax

    .decode0:
          mov    eax,ebx
          and    eax,0xF
          cmp    al,0x0
          je     .opcode00E0
          cmp    al,0xE
          je     .opcode00EE
          jmp    .next

    .decode8:
          mov    eax,ebx
          and    eax,0xF
          cmp    al,0x0
          je     .opcode8XY0
          cmp    al,0x1
          je     .opcode8XY1
          cmp    al,0x2
          je     .opcode8XY2
          cmp    al,0x3
          je     .opcode8XY3
          cmp    al,0x4
          je     .opcode8XY4
          cmp    al,0x5
          je     .opcode8XY5
          cmp    al,0x6
          je     .opcode8XY6
          cmp    al,0x7
          je     .opcode8XY7
          cmp    al,0xE
          je     .opcode8XYE
          jmp    .next

    .decodeE:
          mov    eax,ebx
          and    eax,0xF
          cmp    al,0x1
          je     .opcodeEXA1
          cmp    al,0xE
          je     .opcodeEX9E
          jmp    .next

    .decodeF:
          mov    eax,ebx
          and    eax,0xFF
          cmp    al,0x07
          je     .opcodeFX07
          cmp    al,0x0A
          je     .opcodeFX0A
          cmp    al,0x15
          je     .opcodeFX15
          cmp    al,0x18
          je     .opcodeFX18
          cmp    al,0x1E
          je     .opcodeFX1E
          cmp    al,0x29
          je     .opcodeFX29
          cmp    al,0x33
          je     .opcodeFX33
          cmp    al,0x55
          je     .opcodeFX55
          cmp    al,0x65
          je     .opcodeFX65
          jmp    .next


    .opcode00E0:
          stdcall CPUclrscrn
          jmp    .next
    .opcode00EE:
          mov    edi,[curstck]
          mov    eax,[edi]
          mov    [CPC],eax
          add    [curstck],4
          jmp    .next

    .opcode1NNN:
          and    ebx,0xFFF
          mov    [CPC],ebx
          jmp    .next

    .opcode2NNN:
          sub    [curstck],4
          mov    edi,[curstck]
          mov    eax,[CPC]
          mov    [edi],eax
          mov    eax,ebx
          and    eax,0xFFF
          mov    [CPC],eax
          jmp    .next

    .opcode3XNN:
          mov    edi,ebx
          and    edi,0x0F00
          shr    edi,8
          add    edi,CR
          movzx  eax,byte[edi]
          and    ebx,0x00FF
          cmp    eax,ebx
          jne    @f
          add    [CPC],2
       @@:
          jmp    .next

    .opcode4XNN:
          mov    edi,ebx
          and    edi,0x0F00
          shr    edi,8
          add    edi,CR
          movzx  eax,byte[edi]
          and    ebx,0x00FF
          cmp    eax,ebx
          je    @f
          add    [CPC],2
       @@:
          jmp    .next

    .opcode5XY0:
          mov    edi,ebx
          and    edi,0x0F00
          shr    edi,8
          add    edi,CR
          mov    al,byte[edi]
          and    ebx,0x00F0
          shr    ebx,4
          add    ebx,CR
          cmp    al,byte[ebx]
          jne    @f
          add    [CPC],2
       @@:
          jmp    .next

    .opcode6XNN:
          mov    edi,ebx
          and    edi,0x0F00
          shr    edi,8
          add    edi,CR
          and    ebx,0x00FF
          mov    byte[edi],bl
          jmp    .next

    .opcode7XNN:
          mov    edi,ebx
          and    edi,0x0F00
          shr    edi,8
          add    edi,CR
          and    ebx,0x00FF
          add    byte[edi],bl
          jmp    .next

    .opcode8XY0:
          mov    edi,ebx
          and    edi,0x00F0
          shr    edi,4
          add    edi,CR
          mov    al,byte[edi]
          and    ebx,0x0F00
          shr    ebx,8
          add    ebx,CR
          mov    edi,ebx
          mov    byte[edi],al
          jmp    .next
    .opcode8XY1:
          mov    edi,ebx
          and    edi,0x0F00
          shr    edi,8
          add    edi,CR
          mov    al,byte[edi]
          and    ebx,0x00F0
          shr    ebx,4
          add    ebx,CR
          or     al,byte[ebx]
          mov    byte[edi],al
          jmp    .next
    .opcode8XY2:
          mov    edi,ebx
          and    edi,0x0F00
          shr    edi,8
          add    edi,CR
          mov    al,byte[edi]
          and    ebx,0x00F0
          shr    ebx,4
          add    ebx,CR
          and    al,byte[ebx]
          mov    byte[edi],al
          jmp    .next
    .opcode8XY3:
          mov    edi,ebx
          and    edi,0x0F00
          shr    edi,8
          add    edi,CR
          mov    al,byte[edi]
          and    ebx,0x00F0
          shr    ebx,4
          add    ebx,CR
          xor    al,byte[ebx]
          mov    byte[edi],al
          jmp    .next
    .opcode8XY4:
          mov    edi,ebx
          and    ebx,0x00F0
          shr    ebx,4
          add    ebx,CR
          mov    al,byte[ebx]
          and    edi,0x0F00
          shr    edi,8
          add    edi,CR
          add    byte[edi],al
          jnc    @f
          mov    edi,0xF
          add    edi,CR
          mov    byte[edi],1
       @@:
          jmp    .next
    .opcode8XY5:
          mov    edi,ebx
          and    ebx,0x00F0
          shr    ebx,4
          add    ebx,CR
          mov    al,byte[ebx]
          and    edi,0x0F00
          shr    edi,8
          add    edi,CR
          sub    byte[edi],al
          jc    @f
          mov    edi,0xF
          add    edi,CR
          mov    byte[edi],1
          jmp    .next
       @@:
          mov    edi,0xF
          add    edi,CR
          mov    byte[edi],0
          jmp    .next
    .opcode8XY6:
          mov    edi,ebx
          and    edi,0x0F00
          shr    edi,8
          add    edi,CR
          mov    al,byte[edi]
          shr    al,1
          mov    ah,0
          rcl    ah,1
          mov    byte[edi],al
          mov    edi,CR
          add    edi,0xF
          cmp    ah,1
          je     @f
          mov    byte[edi],0
          jmp    .next
       @@:
          mov    byte[edi],1
          jmp    .next
    .opcode8XY7:
          mov    edi,ebx
          and    edi,0x00F0
          shr    edi,4
          add    edi,CR
          mov    al,byte[edi]
          and    ebx,0x0F00
          shr    ebx,8
          add    ebx,CR
          sub    al,byte[ebx]
          mov    byte[ebx],al
          jnc    @f
          mov    edi,0xF
          add    edi,CR
          mov    byte[edi],0
          jmp    .next
       @@:
          mov    edi,0xF
          add    edi,CR
          mov    byte[edi],1
          jmp    .next
    .opcode8XYE:
          mov    edi,ebx
          and    edi,0x0F00
          shr    edi,8
          add    edi,CR
          mov    al,byte[edi]
          shl    al,1
          mov    ah,0
          rcl    ah,1
          mov    byte[edi],al
          mov    edi,CR
          add    edi,0xF
          cmp    ah,1
          je     @f
          mov    byte[edi],0
          jmp    .next
       @@:
          mov    byte[edi],1
          jmp    .next

    .opcode9XY0:
          mov    edi,ebx
          and    edi,0x0F00
          shr    edi,8
          add    edi,CR
          mov    al,byte[edi]
          and    ebx,0x00F0
          shr    ebx,4
          add    ebx,CR
          cmp    al,byte[ebx]
          je    @f
          add    [CPC],2
       @@:
          jmp    .next

    .opcodeANNN:
          and    ebx,0x0FFF
          mov    [CI],ebx
          jmp    .next

    .opcodeBNNN:
          and    ebx,0x0FFF
          movzx  eax,byte[CR]
          add    ebx,eax
          mov    [CPC],ebx
          jmp    .next

    .opcodeCXNN:
          mov    eax,dword[qpc]
          imul   eax
          or     eax,0x5
          add    dword[qpc],eax
          mov    edi,ebx
          and    ebx,0x00FF
          and    eax,ebx
          and    edi,0x0F00
          shr    edi,8
          add    edi,CR
          mov    byte[edi],al
          jmp    .next

    .opcodeDXYN:
          mov edi,ebx
          and edi,0x0F00
          shr edi,8
          add edi,CR
          mov ecx,ebx
          and ecx,0x000F
          mov [sprheight],ecx
          and ebx,0x00F0
          shr ebx,4
          add ebx,CR
          mov ecx,10
          movzx eax,byte[edi]
          mul ecx
          mov [coordx],eax
          movzx eax,byte[ebx]
          mul ecx
          mov [coordy],eax
          mov edi,CR
          add edi,0xF
          mov byte[edi],0

          mov [yline],0

 .oloop:
        mov edi,[hMem]
        add edi,[CI]
        add edi,[yline]
        movzx eax,byte[edi]
        mov [sprdata],eax

        mov [xline],0
        mov [mask],7

 .iloop:
        mov ecx,[mask]
        mov eax,1
        shl eax,cl
        and eax,[sprdata]
        jz  .nextloop

        mov ecx,10
        mov eax,[yline]
        mul ecx
        add eax,[coordy]
        mov ebx,[xline]
        xchg eax,ebx
        mul ecx
        xchg eax,ebx
        add ebx,[coordx]
        mov [color],0
        mov edi,[BitValues]
        mov ecx,640
        mul ecx
        add eax,ebx
        mov ecx,4
        mul ecx
        add edi,eax
        movzx eax,byte[edi]
        cmp eax,0
        jne @f
        mov [color],0x00FFFFFF
        mov ebx,CR
        add ebx,0xF
        mov byte[ebx],1
     @@:
        mov eax,[color]
        mov ebx,0
     .ooloop:
        mov ecx,0
     .iiloop:
        mov eax,[color]
        stosd
        inc ecx
        cmp ecx,10
        jnz .iiloop
        add edi,2520
        inc ebx
        cmp ebx,10
        jnz .ooloop

.nextloop:
        inc [xline]
        dec [mask]
        cmp [xline],8
        jne .iloop
        inc [yline]
        mov eax,[sprheight]
        cmp [yline],eax
        jne .oloop
        jmp    .next


    .opcodeEX9E:
          and    ebx,0x0F00
          shr    ebx,8
          add    ebx,CR
          movzx  eax,byte[ebx]
          mov    ebx,keys
          add    ebx,eax
          cmp    byte[ebx],1
          jne    @f
          add    [CPC],2
       @@:
          jmp    .next
    .opcodeEXA1:
          and    ebx,0x0F00
          shr    ebx,8
          add    ebx,CR
          movzx  eax,byte[ebx]
          mov    ebx,keys
          add    ebx,eax
          cmp    byte[ebx],1
          je    @f
          add    [CPC],2
       @@:
          jmp    .next

    .opcodeFX07:
          and    ebx,0x0F00
          shr    ebx,8
          add    ebx,CR
          mov    al,[CDelay]
          mov    byte[ebx],al
          jmp    .next
    .opcodeFX0A:
          mov    ecx,15
          mov    edi,keys
       @@:
          cmp    byte[edi],1
          je     .keypressed
          inc    edi
          dec    ecx
          jnz    @b
          sub    [CPC],2
          jmp    .next
       .keypressed:
          sub    edi,keys
          mov    eax,edi
          and    ebx,0x0F00
          shr    ebx,8
          add    ebx,CR
          mov    byte[ebx],al
          jmp    .next
    .opcodeFX15:
          and    ebx,0x0F00
          shr    ebx,8
          add    ebx,CR
          mov    al,byte[ebx]
          mov    [CDelay],al
          jmp    .next
    .opcodeFX18:
          and    ebx,0x0F00
          shr    ebx,8
          add    ebx,CR
          mov    al,byte[ebx]
          mov    [CSound],al
          jmp    .next
    .opcodeFX1E:
          mov    edi,CR
          add    edi,0xF
          mov    byte[edi],0
          and    ebx,0x0F00
          shr    ebx,8
          add    ebx,CR
          movzx  eax,byte[ebx]
          add    [CI],eax
          cmp    [CI],0xFFF
          jna    @f
          mov    byte[edi],1
       @@:
          jmp    .next
    .opcodeFX29:
          and    ebx,0x0F00
          shr    ebx,8
          add    ebx,CR
          movzx  eax,byte[ebx]
          mov    bl,5
          mul    bl
          mov    [CI],eax
          jmp    .next
    .opcodeFX33:
          and    ebx,0x0F00
          shr    ebx,8
          add    ebx,CR
          movzx  eax,byte[ebx]
          mov    ebx,eax
          mov    cl,100
          div    cl
          mov    edi,[hMem]
          add    edi,[CI]
          stosb
          mov    eax,ebx
          mov    cl,10
          div    cl
          mov    [edi+1],ah
          movzx  eax,al
          div    cl
          mov    al,ah
          stosb
          jmp    .next
    .opcodeFX55:
          mov    edi,[hMem]
          add    edi,[CI]
          mov    esi,CR
          and    ebx,0x0F00
          shr    ebx,8
          xor    ecx,ecx
       @@:
          lodsb
          stosb
          inc    ecx
          cmp    ecx,ebx
          jna    @b
          ;add    [CI],ebx    ;These two lines of code SHOULD NOT be commented, but it oddly messes up when they aren't.
          ;inc    [CI]        ;Must be some bug elsewhere in the emulation...
          jmp    .next
    .opcodeFX65:
          mov    esi,[hMem]
          add    esi,[CI]
          mov    edi,CR
          and    ebx,0x0F00
          shr    ebx,8
          xor    ecx,ecx
       @@:
          lodsb
          stosb
          inc    ecx
          cmp    ecx,ebx
          jna    @b
          ;add    [CI],ebx    ;These two lines of code SHOULD NOT be commented, but it oddly messes up when they aren't.
          ;inc    [CI]        ;Must be some bug elsewhere in the emulation...
          jmp    .next


    .next:
          dec    [num]
          jmp    .loop
    .done:
          ret
endp


proc CPUclrscrn
          mov    edi,[BitValues]
          mov    ecx,640*320
          mov    eax,0x00FFFFFF
          rep    stosd
          ret
endp


section '.data' data readable writeable

  hFile     dd 0
  nSize     dd 0
  bytesread dd 0

  hBmp      dd 0
  hDC       dd 0
  hdcMem    dd 0
  hbmOld    dd 0
  hTimer    dd 0
  hHeap     dd 0
  mainhwnd  dd 0
  hInstance dd 0
  BitValues dd 0
  _title    db 'Simple Chip-8 emulator',0
  _class    db 'CHIP8EMU',0
  wc        WNDCLASS 0,WindowProc,0,0,NULL,NULL,NULL,7,NULL,_class
  msg       MSG
  PaintS    PAINTSTRUCT
  wrect     RECT
  crect     RECT
  BMPinfo   BITMAPINFOHEADER sizeof.BITMAPINFOHEADER,640,-320,1,32,BI_RGB,0,0,0,0,0

  CI        dd 0  ;Address pointer
  CPC       dd 0  ;Program counter
  CR        db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0  ;The 16 registers
  CDelay    db 0  ;Delay counter
  CSound    db 0  ;Beep counter
  hMem      dd 0

  keys      db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0  ;The 16 keys
  keycodes  db 0x58,0x31,0x32,0x33,0x51,0x57,0x45,0x41,0x53,0x44,0x5A,0x43,0x34,0x52,0x46,0x56
  paused    dd 0 ;Is it paused?

  font      db 0xF0, 0x90, 0x90, 0x90, 0xF0, 0x20, 0x60, 0x20, 0x20, 0x70, 0xF0, 0x10, 0xF0, 0x80, 0xF0,\    ;Font 'borrowed' from some Chip-8 emu I found
               0xF0, 0x10, 0xF0, 0x10, 0xF0, 0x90, 0x90, 0xF0, 0x10, 0x10, 0xF0, 0x80, 0xF0, 0x10, 0xF0,\
               0xF0, 0x80, 0xF0, 0x90, 0xF0, 0xF0, 0x10, 0x20, 0x40, 0x40, 0xF0, 0x90, 0xF0, 0x90, 0xF0,\
               0xF0, 0x90, 0xF0, 0x10, 0xF0, 0xF0, 0x90, 0xF0, 0x90, 0x90, 0xE0, 0x90, 0xE0, 0x90, 0xE0,\
               0xF0, 0x80, 0x80, 0x80, 0xF0, 0xE0, 0x90, 0x90, 0x90, 0xE0, 0xF0, 0x80, 0xF0, 0x80, 0xF0,\
               0xF0, 0x80, 0xF0, 0x80, 0x80

  IPS       dd 600
  IPF       dd 0

  yline     dd 0
  xline     dd 0
  sprdata   dd 0
  sprx      dd 0
  spry      dd 0
  coordx    dd 0
  coordy    dd 0
  sprheight dd 0
  color     dd 0
  mask      dd 0

  ofn       OPENFILENAME sizeof.OPENFILENAME,NULL,NULL,filefilter,NULL,NULL,NULL,filebuf,256,NULL,NULL,NULL,NULL,OFN_FILEMUSTEXIST + OFN_PATHMUSTEXIST,NULL,NULL,NULL,NULL,NULL,NULL
  filefilter db 'Chip-8 files',0,'*.c8',0,0

  align 4
  qpc:  dq 0

  curstck   dd 0
  stck      rd 16
  endstack = $-4

  fmt       db 'Simple Chip-8 emulator    IPS: %hu',0
  fmt_paused db 'PAUSED    IPS: %hu',0
  buf       rb 200
  filebuf   rb 260

section '.idata' import data readable writeable

  library kernel32,'KERNEL32.DLL',\
          user32,'USER32.DLL',\
          gdi32,'GDI32.DLL',\
          comdlg32,'Comdlg32.dll'

  include 'api\kernel32.inc'
  include 'api\user32.inc'
  include 'api\gdi32.inc'
  include 'api\comdlg32.inc'
    


EDIT: Oops, bug in BCD instruction, should be fixed now.

EDIT2: Simple jump table, as suggested below. Multi-instruction numbers still have to get further decoding, though.

_________________
----> * <---- My star, won HERE


Last edited by windwakr on 31 Aug 2010, 14:30; edited 2 times in total
Post 31 Aug 2010, 01:48
View user's profile Send private message Reply with quote
bitRAKE



Joined: 21 Jul 2003
Posts: 4249
Location: vpcmpistri
bitRAKE 31 Aug 2010, 05:01
Hehe...thanks for the retro flashback. Very Happy

All I got to say about the code is: jump-tables.

(Well, and AdjustWindowRect. Might fix the painting error I'm seeing. Could change the background color in the class to zero, and then blit in the WM_ERASEBKGND (DC is wParam) -- WM_PAINT can go to default handler.)
Post 31 Aug 2010, 05:01
View user's profile Send private message Visit poster's website Reply with quote
windwakr



Joined: 30 Jun 2004
Posts: 827
windwakr 31 Aug 2010, 14:29
What painting error are you seeing?
Post 31 Aug 2010, 14:29
View user's profile Send private message Reply with quote
bitRAKE



Joined: 21 Jul 2003
Posts: 4249
Location: vpcmpistri
bitRAKE 31 Aug 2010, 15:45
If I force the title bar to redraw then it is corrected:


Description:
Filesize: 12.17 KB
Viewed: 16814 Time(s)

w32.chip8.png



_________________
¯\(°_o)/¯ “languages are not safe - uses can be” Bjarne Stroustrup
Post 31 Aug 2010, 15:45
View user's profile Send private message Visit poster's website Reply with quote
bitRAKE



Joined: 21 Jul 2003
Posts: 4249
Location: vpcmpistri
bitRAKE 31 Aug 2010, 16:49
AdjustWindowRectEx and WM_ERASEBKGND painting:


Description:
Download
Filename: w32.chip8_.zip
Filesize: 4.95 KB
Downloaded: 1023 Time(s)


_________________
¯\(°_o)/¯ “languages are not safe - uses can be” Bjarne Stroustrup
Post 31 Aug 2010, 16:49
View user's profile Send private message Visit poster's website Reply with quote
Coty



Joined: 17 May 2010
Posts: 542
Location: &#9216;
Coty 02 Sep 2010, 10:57
Awesome! i have always wanted to build my own emu, mabey i will get to it someday...

thanks for sharing *bows down*

_________________
http://codercat.org/
Post 02 Sep 2010, 10:57
View user's profile Send private message Send e-mail Visit poster's website Reply with quote
mindcooler



Joined: 01 Dec 2009
Posts: 423
Location: Västerås, Sweden
mindcooler 02 Sep 2010, 14:02
Post 02 Sep 2010, 14:02
View user's profile Send private message Visit poster's website MSN Messenger ICQ Number Reply with quote
flaith



Joined: 07 Feb 2005
Posts: 122
Location: $300:20 58 FC 60 N 300G => Vietnam
flaith 04 Sep 2010, 20:27
i really like those retro things, thanks for sharing Very Happy

_________________
Je suis sur de 'rien', mais je ne suis pas sur du 'tout'.
Post 04 Sep 2010, 20:27
View user's profile Send private message Visit poster's website Reply with quote
rugxulo



Joined: 09 Aug 2005
Posts: 2341
Location: Usono (aka, USA)
rugxulo 09 Sep 2010, 20:00
Congrats, windwakr, nice to see you programming something cool, as usual. Wink
Post 09 Sep 2010, 20:00
View user's profile Send private message Visit poster's website Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2025, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.