Jump to content

AutoChip


Luig
 Share

Recommended Posts

Alright I attempted to port a chip8 emulator in vb6 to autoit. The result is AutoChip. Although it isn't fully functional its a start. It seems to emulate sound correctly but something went wrong in the video. The result varies with different roms. Haven't implemented input yet. My hope is that it can be written in pure autoit if not I will have to code a lib for it in Delphi since I am not fluent in C.

Chip8 UDF:

#cs ----------------------------------------------------------------------------

 AutoIt Version: 3.3.6.1
 Author:         Luig

 Script Function:
    CHIP8 Emulator Internal Functions.

#ce ----------------------------------------------------------------------------

#include-once

#include <GuiConstantsEx.au3>
#include <GDIPlus.au3>
#include <EditConstants.au3>
#include <WindowsConstants.au3>

Dim $ram[8193]
Dim $stack[257]
Dim $v[257]
Dim $keydef[17]
Global $opcode1, $opcode2, $opcode3, $opcode4, $sp, $key_up, $key_down
Global $delaytimer, $soundtimer, $x, $y, $i, $j, $dbg, $Pause, $pc, $Index
Global $key_choice

$keydef[1] = 103
$keydef[2] = 104
$keydef[3] = 105
$keydef[4] = 100
$keydef[5] = 101
$keydef[6] = 102
$keydef[7] = 97
$keydef[8] = 98
$keydef[9] = 99
$keydef[10] = 96
$keydef[11] = 111
$keydef[12] = 106
$keydef[13] = 107
$keydef[14] = 13
$keydef[15] = 103
$keydef[16] = 110

$dbg = True

If $dbg Then
    $Debug = GUICreate("Debug", 387, 211, 192, 124)
    $Edit1 = GUICtrlCreateEdit("", 0, 0, 385, 209)
    GUISetState(@SW_SHOW)
EndIf

_GDIPlus_Startup()
Global $hScreen
Global $Black = _GDIPlus_PenCreate(0xFF00FF00)
Global $White = _GDIPlus_PenCreate(0xFFFFFFFF)

Func OpenRom($File)
    $a = 1
    For $i = 1 to StringLen($File)
        $ram[0x200 - 1 + $i] = '0x' & StringMid($File, $a, 2)
        $a += 2
    Next
    Restart_CPU()
EndFunc

Func Restart_CPU()
    $pc = 0x200
    $ram[0x1000] = 96
    $ram[0x1001] = 144
    $ram[0x1002] = 144
    $ram[0x1003] = 144
    $ram[0x1004] = 96
    $ram[0x1005] = 96
    $ram[0x1006] = 224
    $ram[0x1007] = 96
    $ram[0x1008] = 96
    $ram[0x1009] = 240
    $ram[0x100A] = 96
    $ram[0x100B] = 144
    $ram[0x100C] = 32
    $ram[0x100D] = 64
    $ram[0x100E] = 240
    $ram[0x100F] = 224
    $ram[0x1010] = 16
    $ram[0x1011] = 96
    $ram[0x1012] = 16
    $ram[0x1013] = 224
    $ram[0x1014] = 160
    $ram[0x1015] = 160
    $ram[0x1016] = 240
    $ram[0x1017] = 32
    $ram[0x1018] = 32
    $ram[0x1019] = 240
    $ram[0x101A] = 128
    $ram[0x101B] = 240
    $ram[0x101C] = 16
    $ram[0x101D] = 240
    $ram[0x101E] = 240
    $ram[0x101F] = 128
    $ram[0x1020] = 240
    $ram[0x1021] = 144
    $ram[0x1022] = 240
    $ram[0x1023] = 240
    $ram[0x1024] = 16
    $ram[0x1025] = 32
    $ram[0x1026] = 64
    $ram[0x1027] = 128
    $ram[0x1028] = 96
    $ram[0x1029] = 144
    $ram[0x102A] = 96
    $ram[0x102B] = 144
    $ram[0x102C] = 96
    $ram[0x102D] = 240
    $ram[0x102E] = 144
    $ram[0x102F] = 240
    $ram[0x1030] = 16
    $ram[0x1031] = 240
    $ram[0x1032] = 96
    $ram[0x1033] = 144
    $ram[0x1034] = 240
    $ram[0x1035] = 144
    $ram[0x1036] = 144
    $ram[0x1037] = 224
    $ram[0x1038] = 144
    $ram[0x1039] = 224
    $ram[0x103A] = 144
    $ram[0x103B] = 224
    $ram[0x103C] = 112
    $ram[0x103D] = 128
    $ram[0x103E] = 128
    $ram[0x103F] = 128
    $ram[0x1040] = 112
    $ram[0x1041] = 224
    $ram[0x1042] = 144
    $ram[0x1043] = 144
    $ram[0x1044] = 144
    $ram[0x1045] = 224
    $ram[0x1046] = 240
    $ram[0x1047] = 128
    $ram[0x1048] = 224
    $ram[0x1049] = 128
    $ram[0x104A] = 240
    $ram[0x104B] = 240
    $ram[0x104C] = 128
    $ram[0x104D] = 224
    $ram[0x104E] = 128
    $ram[0x104F] = 128
    Emulate_CPU()
EndFunc

Func Emulate_CPU()
        Sleep(10)
        If $delaytimer > 1 Then $delaytimer -= 1
        If $Pause = False Then Interpret()
EndFunc

Func getopcode()
    $opcode1 = BitAND($ram[$pc], 0xF0)
    $opcode1 /= 2
    $opcode1 /= 2
    $opcode1 /= 2
    $opcode1 /= 2
    $opcode2 = BitAND($ram[$pc], 0xF)
    $opcode3 = BitAND($ram[$pc + 1], 0xF0)
    $opcode3 /= 2
    $opcode3 /= 2
    $opcode3 /= 2
    $opcode3 /= 2
    $opcode4 = BitAND($ram[$pc + 1], 0xF)
    $pc += 2
EndFunc

Func Timer()
    If $delaytimer > 0 Then $delaytimer = $delaytimer - 1
    If $soundtimer > 0 Then
        $soundtimer = $soundtimer - 1
        Beep(500, $soundtimer * 10)
        $soundtimer = 0
    EndIf
EndFunc

Func Interpret()
    getopcode()
    If $dbg Then Print(($pc - 2) & ': ' & $opcode1 & ' ' & $opcode2 & ' ' & $opcode3 & ' ' & $opcode4)
    Switch $opcode1
        Case 0x00
            Switch $opcode3
                Case 0x0E
                    Switch $opcode4
                        Case 0x00
                            If $dbg Then Print('ClearScreen')
                            ClearScreen()
                        Case 0x0E
                            If $dbg Then Print('ReturnFromSub')
                            ReturnFromSub()
                    EndSwitch
            EndSwitch
        Case 0x01
            If $dbg Then Print('JumpToAddress')
            JumpToAddress()
        Case 0x02
            If $dbg Then Print('JumpToSub')
            JumpToSub()
        Case 0x03
            If $dbg Then Print('SkipIfRegEqual')
            SkipIfRegEqual()
        Case 0x04
            If $dbg Then Print('SkipIfRegNotEqual')
            SkipIfRegNotEqual()
        Case 0x05
            If $dbg Then Print('SkipIfRegEqualReg')
            SkipIfRegEqualReg()
        Case 0x06
            If $dbg Then Print('LoadRegWithConstant')
            LoadRegWithConstant()
        Case 0x07
            If $dbg Then Print('AddConstantToReg')
            AddConstantToReg()
        Case 0x08
            Switch $opcode4
                Case 0x00
                    If $dbg Then Print('LoadRegWithReg')
                    LoadRegWithReg()
                Case 0x01
                    If $dbg Then Print('OrRegWithReg')
                    OrRegWithReg()
                Case 0x02
                    If $dbg Then Print('AndRegWithReg')
                    AndRegWithReg()
                Case 0x03
                    If $dbg Then Print('XorRegWithReg')
                    XorRegWithReg()
                Case 0x04
                    If $dbg Then Print('AddRegToReg')
                    AddRegToReg()
                Case 0x05
                    If $dbg Then Print('SubRegFromReg')
                    SubRegFromReg()
                Case 0x06
                    If $dbg Then Print('ShiftRegRight')
                    ShiftRegRight()
                Case 0x07
                    If $dbg Then Print('RSubRegFromReg')
                    RSubRegFromReg()
                Case 0x0E
                    If $dbg Then Print('ShiftRegLeft')
                    ShiftRegLeft()
            EndSwitch
        Case 0x09
            If $dbg Then Print('SkipIfRegNotEqualReg')
            SkipIfRegNotEqualReg()
        Case 0x0A
            If $dbg Then Print('LoadIndexWithConstant')
            LoadIndexWithConstant()
        Case 0x0B
            If $dbg Then Print('JumpToAddressPlusReg0')
            JumpToAddressPlusReg0()
        Case 0x0C
            If $dbg Then Print('CreateRandomNumber')
            CreateRandomNumber()
        Case 0x0D
            If $dbg Then Print('DrawSprite')
            DrawSprite()
        Case 0x0E
            Switch $opcode3
                Case 0x09
                    If $dbg Then Print('SkipIfKeyPressed')
                    SkipIfKeyPressed()
                Case 0x0A
                    If $dbg Then Print('SkipIfKeyNotPressed')
                    SkipIfKeyNotPressed()
            EndSwitch
        Case 0x0F
            Switch $opcode3
                Case 0x00
                    Switch $opcode4
                        Case 0x07
                            If $dbg Then Print('GetDelayTimerIntoReg')
                            GetDelayTimerIntoReg()
                        Case 0x0A
                            If $dbg Then Print('WaitForKeyPress')
                            WaitForKeyPress()
                    EndSwitch
                Case 0x01
                    Switch $opcode4
                        Case 0x05
                            If $dbg Then Print('SetDelayTimer')
                            SetDelayTimer()
                        Case 0x08
                            If $dbg Then Print('SetSoundTimer')
                            SetSoundTimer()
                        Case 0x0E
                            If $dbg Then Print('AddRegToIndex')
                            AddRegToIndex()
                    EndSwitch
                Case 0x02
                    If $dbg Then Print('PointIndexToFont')
                    PointIndexToFont()
                Case 0x03
                    If $dbg Then Print('StoreBCD')
                    StoreBCD()
                Case 0x05
                    If $dbg Then Print('StoreRegsAtIndex')
                    StoreRegsAtIndex()
                Case 0x06
                    If $dbg Then Print('LoadRegsFromIndex')
                    LoadRegsFromIndex()
            EndSwitch
    EndSwitch
EndFunc

Func ClearScreen()
    _GDIPlus_GraphicsClear($hScreen, 0x00FFFFFF)
EndFunc

Func ReturnFromSub()
    $sp -= 1
    $pc = $stack[$sp]
EndFunc

Func JumpToAddress()
    For $a = 1 To 8
        $opcode2 *= 2
    Next
    For $a = 1 To 4
        $opcode3 *= 2
    Next
    $pc = $opcode2 + $opcode3 + $opcode4
EndFunc

Func JumpToSub()
    $stack[$sp] = $pc
    $sp += 1
    For $a = 1 To 8
        $opcode2 *= 2
    Next
    For $a = 1 To 4
        $opcode3 *= 2
    Next
    $pc = $opcode2 + $opcode3 + $opcode4
EndFunc

Func SkipIfRegEqual()
    For $a = 1 To 4
        $opcode3 *= 2
    Next
    If $v[$opcode2] = ($opcode3 + $opcode4) Then $pc +=2
EndFunc

Func SkipIfRegNotEqual()
    For $a = 1 To 4
        $opcode3 *= 2
    Next
    If $v[$opcode2] <> ($opcode3 + $opcode4) Then $pc += 2
EndFunc

Func SkipIfRegEqualReg()
    If $v[$opcode2] = $v[$opcode3] Then $pc += 2
EndFunc

Func SkipIfRegNotEqualReg()
    If $v[$opcode2] <> $v[$opcode3] Then $pc += 2
EndFunc

Func LoadRegWithConstant()
    For $a = 1 To 4
        $opcode3 *= 2
    Next
    $v[$opcode2] = ($opcode3 + $opcode4)
EndFunc

Func AddConstantToReg()
    For $a = 1 To 4
        $opcode3 *= 2
    Next
    $x = $v[$opcode2] + ($opcode3 + $opcode4)
    If $x > 255 Then $x -= 256
    $v[$opcode2] = $x
EndFunc

Func LoadRegWithReg()
    $v[$opcode2] = $v[$opcode3]
EndFunc

Func OrRegWithReg()
    $v[$opcode2] = BitOR($v[$opcode2], $v[$opcode3])
EndFunc

Func AndRegWithReg()
    $v[$opcode2] = BitAND($v[$opcode2], $v[$opcode3])
EndFunc

Func XorRegWithReg()
    $v[$opcode2] = BitXOR($v[$opcode2], $v[$opcode3])
EndFunc

Func AddRegToReg()
    Local $x
    If $v[$opcode2] >= $v[$opcode3] Then
        $v[0x0F] = 1
    Else
        $v[0x0F] = 0
    EndIf
    $x = $v[$opcode2]
    $x -= $v[$opcode3]
    If $x < 0 Then $x += 256
    $v[$opcode2] = $x
EndFunc

Func SubRegFromReg()
    Local $x
    If $v[$opcode2] >= $v[$opcode3] Then
        $v[0x0F] = 1
    Else
        $v[0x0F] = 0
    EndIf
    $x = $v[$opcode2]
    $x = $x - $v[$opcode3]
    If $x < 0 Then $x = $x + 256
    $v[$opcode2] = $x
EndFunc

Func ShiftRegRight()
    If BitAND($v[$opcode2], 1) Then
        $v[0x0F] = 1
    Else
        $v[0x0F] = 0
    EndIf
    $v[$opcode2] /= 2
EndFunc

Func RSubRegFromReg()
    Local $x
    If $v[$opcode2] >= $v[$opcode3] Then
        $v[0x0F] = 1
    Else
        $v[0x0F] = 0
    EndIf
    $x = $v[$opcode3]
    $x -= $v[$opcode2]
    If $x < 0 Then $x += 256
    $v[$opcode2] = $x
EndFunc

Func ShiftRegLeft()
    If BitAND($v[0x0F], 128) Then
        $v[0x0F] = 1
    Else
        $v[0x0F] = 0
    EndIf
    $x = $v[$opcode2] * 2
    If $x > 255 Then $x -= 256
    $v[$opcode2] = $x
EndFunc

Func LoadIndexWithConstant()
    For $a = 1 To 8
        $opcode2 *= 2
    Next
    For $a = 1 To 4
        $opcode3 *= 2
    Next
    $Index = $opcode2 + $opcode3 + $opcode4
EndFunc

Func JumpToAddressPlusReg0()
    For $a = 1 To 8
        $opcode2 *= 2
    Next
    For $a = 1 To 4
        $opcode3 *= 2
    Next
    $pc = $v[0] + $opcode2 + $opcode3 + $opcode4
EndFunc

Func CreateRandomNumber()
    For $a = 1 To 4
        $opcode3 *= 2
    Next
    $v[$opcode2] = BitAND(Int(Random() * 256), ($opcode3 + $opcode4))
EndFunc

Func DrawSprite()
    $v[0x0F] = 0
    For $j = 0 To $opcode4 - 1
        $datax = $ram[$Index + $j]
        $i = 0
        $x = $v[$opcode2] * 4
        $y = $v[$opcode4] * 4
        If $datax >= 128 Then
            drawscreen()
            $datax -= 128
        EndIf
        $i += 1
        If $datax >= 64 Then
            drawscreen()
            $datax -= 64
        EndIf
        $i += 1
        If $datax >= 32 Then
            drawscreen()
            $datax -= 32
        EndIf
        $i += 1
        If $datax >= 16 Then
            drawscreen()
            $datax -= 16
        EndIf
        $i += 1
        If $datax >= 8 Then
            drawscreen()
            $datax -= 8
        EndIf
        $i += 1
        If $datax >= 4 Then
            drawscreen()
            $datax -= 4
        EndIf
        $i += 1
        If $datax >= 2 Then
            drawscreen()
            $datax -= 2
        EndIf
        $i += 1
        If $datax >= 1 Then
            drawscreen()
            $datax -= 1
        EndIf
    Next
EndFunc

Func drawscreen()
    Local $pointx, $pointy, $height, $width
    $pointx = 1 + $x + ($i * 4)
    $pointy = $y + ($j * 4)
    $width = (1 + $x + ($i * 4) + 3) - $pointx
    $height = ($y + ($j * 4) + 3) - $pointy
    If _PixelGetColor_GetPixel($hScreen, 1 + $x + ($i * 4), $y + ($j * 4)) = 0x00FF00 Then
        _GDIPlus_GraphicsDrawRect($hScreen, $pointx, $pointy, $width, $height, $White)
        ;_GDIPlus_GraphicsDrawLine($hScreen, 1 + $x + ($i * 4), $y + ($j * 4), 1 + $x + ($i * 4) + 3, $y + ($j * 4) + 3, $White)
    Else
        _GDIPlus_GraphicsDrawRect($hScreen, $pointx, $pointy, $width, $height, $Black)
        ;_GDIPlus_GraphicsDrawLine($hScreen, 1 + $x + ($i * 4), $y + ($j * 4), 1 + $x + ($i * 4) + 3, $y + ($j * 4) + 3, $Black)
    EndIf
EndFunc

Func SkipIfKeyPressed()
    If $key_down = $v[$opcode2] Then $pc += 2
EndFunc

Func SkipIfKeyNotPressed()
    If $key_down <> $v[$opcode2] Then $pc += 2
EndFunc

Func WaitForKeyPress()
    $key_down = 0
    While $key_down = 0
        Sleep(1)
    WEnd
    $v[$opcode2] = $key_down
EndFunc

Func SetDelayTimer()
    $delaytimer = $v[$opcode2]
EndFunc

Func GetDelayTimerIntoReg()
    $v[$opcode2] = $delaytimer
EndFunc

Func SetSoundTimer()
    $soundtimer = $v[$opcode2]
EndFunc

Func AddRegToIndex()
    $Index += $v[$opcode2]
EndFunc

Func PointIndexToFont()
    $Index = 0x1000 + ($v[$opcode2] * 0x05)
EndFunc

Func StoreBCD()
    $num = $v[$opcode2]
    For $i = 3 To 1 Step -1
        $ram[$Index + ($i - 2)] = Mod($num, 10)
        $num /= 10
    Next
EndFunc

Func StoreRegsAtIndex()
    For $i = 0 To $opcode2
        $ram[$index + $i] = $v[$i]
    Next
EndFunc

Func LoadRegsFromIndex()
    For $i = 0 To $opcode2
        $v[$i] = $ram[$Index + $i]
    Next
EndFunc

Func Print($String)
    GUICtrlSetData($Edit1, GUICtrlRead($Edit1) & @CRLF & $String)
EndFunc

Func _PixelGetColor_GetPixel($iPixelGetColor_MemoryContext,$iX,$iY, $hDll = "gdi32.dll")
    $iColor = DllCall($hDll,"int","GetPixel","int",$iPixelGetColor_MemoryContext,"int",$iX,"int",$iY)
    If $iColor[0] = -1 then Return SetError(1,0,-1)
    $sColor = Hex($iColor[0],6)
    Return StringRight($sColor,2) & StringMid($sColor,3,2) & StringLeft($sColor,2)
EndFunc

Emulator:

#cs ----------------------------------------------------------------------------

 AutoIt Version: 3.3.6.1
 Author:         Luig

 Script Function:
    GUI of Emulator.

#ce ----------------------------------------------------------------------------

#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include 'CHIP8v2.au3'

$Form1 = GUICreate("AutoChip v 1.0", 270, 134, 374, 138)
GUISetState(@SW_SHOW)

$hScreen = _GDIPlus_GraphicsCreateFromHWND($Form1)
ClearScreen()

$File = FileOpen(@ScriptDir & '\Pong (19xx)(-)(Chip-8).ch8', 16)
$Raw = FileRead($File)
FileClose($File)

OpenRom(StringTrimLeft($Raw, 2))

;AdlibRegister('Timer', 17)

While 1
    Timer()
    Emulate_CPU()
    $nMsg = GUIGetMsg()
    Switch $nMsg
        Case $GUI_EVENT_CLOSE
            Exit

    EndSwitch
WEnd

You can get the VB Source here : http://www.zophar.net/chip8/vb-chip-8.html

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...