Page 1 of 1

ChipEm revised

Posted: Sun Jan 21, 2007 7:26 pm
by BalrogSoft
Hi, the old emulators i made, are really bad coded, i used strings instead bytes, i don't remember very well, i'm not sure if PB on this time didn't supported hex values, or i didn't know how use hex values. But i made a fast port to Purebasic from my ChipEm emulator written in JavaScript. Is a better source to learn how to code emulators:

(EDITED: Saved some lines, 382 line)

Code: Select all

; Copyright 2007 ChipEm Revised by Pedro Gil (Balrog Soft)

InitSprite()
InitKeyboard()

Global *MEM, *RAM.Character, DT, ST
   
Procedure counters()
  If (DT > 0) : DT - 1 : EndIf
  If (ST > 0) : ST - 1 : EndIf
  If (DT < 0) : DT = 0 : EndIf
  If (ST < 0) : ST = 0 : EndIf
EndProcedure

Procedure GetPC()
  ProcedureReturn *RAM - *MEM
EndProcedure

Dim subAddress.w(15)
Dim V.c(15)
Dim Key.b(15)
Dim KeyCode(15)

KeyCode(0) = #PB_Key_X
KeyCode(1) = #PB_Key_1
KeyCode(2) = #PB_Key_2
KeyCode(3) = #PB_Key_3
KeyCode(4) = #PB_Key_Q
KeyCode(5) = #PB_Key_W
KeyCode(6) = #PB_Key_E
KeyCode(7) = #PB_Key_A
KeyCode(8) = #PB_Key_S
KeyCode(9) = #PB_Key_D
KeyCode(10) = #PB_Key_Z
KeyCode(11) = #PB_Key_C
KeyCode(12) = #PB_Key_4
KeyCode(13) = #PB_Key_R
KeyCode(14) = #PB_Key_F
KeyCode(15) = #PB_Key_V

*MEM = AllocateMemory(4096)
*RAM.Character = *MEM

File.s = OpenFileRequester("Open Chip 8 ROM", "", "", 0)
If File.s
  If ReadFile(0, File.s)
    ReadData(0, *MEM + $200, Lof(0))
    CloseFile(0)
  EndIf
Else
  FreeMemory(*MEM)
  End
EndIf

If OpenWindow(0, 100, 100, 256, 128, "ChipEm rEvISeD", #PB_Window_SystemMenu|#PB_Window_ScreenCentered)
  OpenWindowedScreen(WindowID(0), 0, 0, 256, 128, 0, 0, 0)
 
  CreateImage(0, 64, 32, #PB_Image_DisplayFormat)

  Skip.b = #False
  Jump.b = #False
  flipScreen.b = #False
  EmulationActive.b = #True
  WaitKey.b = #False
      
  SP = 0 : DT = 0 :  ST = 0 : Index = 0
   
  Restore FontData
  For i = 0 To 79
    Read b.c
    *RAM\c = b.c
    *RAM + 1
  Next i
 
  *RAM = *MEM + $200
 
  timer = GetTickCount_()
 
  Repeat
   
     If EmulationActive.b = #True
       WindowEvent = WindowEvent()
     ElseIf EmulationActive.b = #False
       WindowEvent = WaitWindowEvent()
     EndIf
    
     If WindowEvent = #PB_Event_CloseWindow
       Quit = #True
     EndIf
      
     If EmulationActive.b = #True

       ExamineKeyboard()
     
       For k = 0 To 15
         Key(k) = #False
         If KeyboardPushed(KeyCode(k))
           Key(k) = #True
         EndIf
       Next
     
       If WaitKey = #False
       
          If GetTickCount_() - timer >= 16
            counters()
            timer = GetTickCount_()
          EndIf
         
          Skip.b = #False
          Jump.b = #False
          flipScreen.b = #False
          
          OpCode.c = *RAM\c
          OpCodeH.c = (OpCode >> 4) & $f
          OpCodeL.c = OpCode & $f
          
          *ptr.Character = *RAM + 1
          HByte.c = *ptr\c
 
          Select OpCodeH
          
          Case $0:
             Select HByte
                Case $e0:
                  CreateImage(0, 64, 32, #PB_Image_DisplayFormat)
             
                Case $ee:
                   SP - 1
                   *RAM = *MEM + (subAddress(SP) + 2)
                   Jump = #True
                
             EndSelect
   
          Case $1:
             *RAM = *MEM + ((OpCodeL << 8) + HByte)
             Jump = #True
 
          Case $2:
             subAddress(SP) = GetPC()
             SP + 1
             *RAM = *MEM + ((OpCodeL << 8) + HByte)
             Jump = #True
 
          Case $3:
             If (V(OpCodeL) = HByte)
                Skip = #True
             Else
                Skip = #False
             EndIf
 
          Case $4:
            If (V(OpCodeL) <> HByte)
               Skip = #True
            Else
               Skip = #False
            EndIf   
 
          Case $5:
            reg = (HByte >> 4) & $f
            If (V(OpCodeL) = V(reg))
               Skip = #True
            Else
               Skip = #False
            EndIf
 
          Case $6:
             V(OpCodeL) = HByte
 
          Case $7:
             V(OpCodeL) + HByte
 
          Case $8:
            Operator = HByte & $f
             reg = (HByte >> 4) & $f
             
             Select Operator
                Case $0:
                   V(OpCodeL) = V(reg)
 
                Case $1:
                   V(OpCodeL) | V(reg)
                
                Case $2:
                   V(OpCodeL) & V(reg)
                
                Case $3:
                   V(OpCodeL) ! V(reg)
                
                Case $4:
                   V($f) = ((V(OpCodeL) + V(reg)) >> 8) & 1
                   V(OpCodeL) + V(reg)
                   
                Case $5:
                   V($0f) = ((((V(OpCodeL) - V(reg)) >> 8) + 1) & 1)
                   V(OpCodeL) - V(reg)
                   
                Case $6:
                   V($f) = V(OpCodeL) & 1
                   V(OpCodeL) = V(OpCodeL) >> 1
 
                Case $7:
                   V($0f) = ((((V(reg) - V(OpCodeL)) >> 8) + 1) & 1)
                   V(OpCodeL) = V(reg) - V(OpCodeL)
 
                Case $e:
                   V($f) = (V(OpCodeL) >> 7) & 1
                   V(OpCodeL) = V(OpCodeL) << 1
                   
             EndSelect
 
          Case $9:
             If (V(OpCodeL) <> V((HByte >> 4) & $f))
               Skip = #True
             Else
               Skip = #False
             EndIf
          
          Case $a:
             Index = (OpCodeL << 8) + HByte
          
          Case $b:
             *RAM = *MEM + ((OpCodeL << 8) + HByte + V($0))
             Jump = #True
   
          Case $c:
             V(OpCodeL) = Random(HByte)
   
          Case $d:
            height = HByte & $f
            reg = (HByte >> 4) & $f
            sprx = V(OpCodeL)
            spry = V(reg)
            V($f) = 0
            *ptr.Character = *MEM
            *ptr + Index
            StartDrawing(ImageOutput(0))
            DrawingMode(#PB_2DDrawing_XOr)
            For y = 0 To height - 1
              For x = 0 To 7
                xc = (x + sprx) % 64
                yc = (y + spry) % 32
             
                Pixel = (*ptr\c >> (7 - x)) & $1
                
                If Pixel
                  prev = Point(xc, yc)
                  Plot(xc, yc, $FFFFFF)
                  If prev <> 0 : V($f) = 1 : EndIf
                  If prev = 0 And flipScreen = #False 
                    flipScreen = #True
                  EndIf
                EndIf
              Next x
              *ptr + 1
            Next y
            StopDrawing()
            
          Case $e:
             Select HByte
                Case $9e:
                   If (Key(V(OpCodeL)) = #True)
                      Skip = #True
                   EndIf
   
                Case $a1:
                   If (Key(V(OpCodeL)) <> #True)
                      Skip = #True
                   EndIf
 
             EndSelect
   
          Case $f:
             Select HByte
                Case $07:
                   V(OpCodeL) = DT
 
                Case $0a:
                   WaitKey = #True
                   registerKey = OpCodeL
 
                Case $15:
                   DT = V(OpCodeL)
 
                Case $18:
                   ST = V(OpCodeL)
 
                Case $1e:
                   Index + V(OpCodeL)
 
                Case $29:
                   Index = (5 * V(OpCodeL))
   
                Case $33:
                   bcd.s = Str(V(OpCodeL))
                   If (Len(bcd) = 1)
                     bcd = "00" + bcd
                   ElseIf (Len(bcd) = 2)
                     bcd = "0" + bcd
                   EndIf
                   *ptr.Character = *MEM
                   *ptr + Index
                   *ptr\c = Val(Mid(bcd, 1, 1))
                   *ptr + 1
                   *ptr\c  = Val(Mid(bcd, 2, 1))
                   *ptr + 1
                   *ptr\c  = Val(Mid(bcd, 3, 1))
                   
                Case $55:
                  *ptr.Character = *MEM
                   *ptr + Index
                   For reg = 0 To OpCodeL
                      *ptr\c = V(reg)
                      *ptr + 1
                   Next reg
 
                Case $65:
                  *ptr.Character = *MEM
                   *ptr + Index
                   For reg = 0 To OpCodeL
                      V(reg) = *ptr\c
                      *ptr + 1
                   Next reg
 
             EndSelect
          EndSelect
   
          If Jump = #False
             If Skip = #False
                *RAM + 2
           Else
               *RAM + 4
              EndIf
          EndIf
          
          If FlipScreen = #True
            CopyImage(0, 1)
            ResizeImage(1, 256, 128, #PB_Image_Raw)
            StartDrawing(ScreenOutput())
              DrawImage(ImageID(1), 0, 0)
            StopDrawing()
            FlipBuffers()
          EndIf
       EndIf   
     EndIf
        
    If WaitKey = #True
      For reg = 0 To 15
        If Key(reg) = #True
          V(registerKey) = reg
          WaitKey = #False
        EndIf
      Next reg
    EndIf
   
  Until Quit = #True
 
  CloseWindow(0)
EndIf

FreeMemory(*MEM)

End

DataSection
  FontData:
    Data.b $F0, $90, $90, $90, $F0
      Data.b $20, $60, $20, $20, $70
      Data.b $F0, $10, $F0, $80, $F0
      Data.b $F0, $10, $F0, $10, $F0
      Data.b $90, $90, $F0, $10, $10
      Data.b $F0, $80, $F0, $10, $F0
      Data.b $F0, $80, $F0, $90, $F0
      Data.b $F0, $10, $20, $40, $40
      Data.b $F0, $90, $F0, $90, $F0
      Data.b $F0, $90, $F0, $10, $F0
      Data.b $F0, $90, $F0, $90, $90
      Data.b $E0, $90, $E0, $90, $E0
      Data.b $F0, $80, $80, $80, $F0
      Data.b $E0, $90, $90, $90, $E0
      Data.b $F0, $80, $F0, $80, $F0
      Data.b $F0, $80, $F0, $80, $80
EndDataSection

Posted: Sun Jan 21, 2007 11:00 pm
by Joakim Christiansen
Wow, very neat!

Posted: Mon Jan 22, 2007 12:13 am
by dell_jockey
where does one download the ROM file?

Posted: Mon Jan 22, 2007 12:34 am
by BalrogSoft
Heathen's Chip 8 emulator (http://www.purebasic.fr/english/viewtopic.php?t=25443) have a lot of roms, but some are for Super Chip, and this version only emulate Chip 8, but here is a pack of Chip 8 games:
http://www.zophar.net/roms/files/chip8/c8games.zip

Posted: Mon Jan 22, 2007 2:49 am
by Heathen
Looking good! Way better structured than mine. I still regret using strings instead of hex + bitwise, but made sure not to make that mistake with my z80 emulator.