numpyeight.py

Created by nonogamer9

Created on February 06, 2025

8.34 KB

A CHIP-8 Emulator For Stock NumWorks!


# NumPy-8! Version 1.0 coded by nonogamer9 (c) 2025
# This is a CHIP-8 Emulator For Stock Numworks! So Performance can be abysmal!!
# This Chip 8 Emulator Is A derivative from nono CHIP-8!
# Pastebin! https://pastebin.com/AJBpBP1m
from kandinsky import fill_rect, color
from ion import keydown
import time
import random

class Chip8:
    def __init__(self):
        self.memory = [0] * 4096
        self.V = [0] * 16
        self.I = 0
        self.pc = 0x200
        self.stack = []
        self.delay_timer = 0
        self.sound_timer = 0
        self.keypad = [False] * 16
        self.display = [[False for _ in range(64)] for _ in range(32)]
        self.opcode = 0
        self.draw_flag = False

        self.load_font_set()

    def load_font_set(self):
        font_set = [
            0xF0, 0x90, 0x90, 0x90, 0xF0,  # 0
            0x20, 0x60, 0x20, 0x20, 0x70,  # 1
            0xF0, 0x10, 0xF0, 0x80, 0xF0,  # 2
            0xF0, 0x10, 0xF0, 0x10, 0xF0,  # 3
            0x90, 0x90, 0xF0, 0x10, 0x10,  # 4
            0xF0, 0x80, 0xF0, 0x10, 0xF0,  # 5
            0xF0, 0x80, 0xF0, 0x90, 0xF0,  # 6
            0xF0, 0x10, 0x20, 0x40, 0x40,  # 7
            0xF0, 0x90, 0xF0, 0x90, 0xF0,  # 8
            0xF0, 0x90, 0xF0, 0x10, 0xF0,  # 9
            0xF0, 0x90, 0xF0, 0x90, 0x90,  # A
            0xE0, 0x90, 0xE0, 0x90, 0xE0,  # B
            0xF0, 0x80, 0x80, 0x80, 0xF0,  # C
            0xE0, 0x90, 0x90, 0x90, 0xE0,  # D
            0xF0, 0x80, 0xF0, 0x80, 0xF0,  # E
            0xF0, 0x80, 0xF0, 0x80, 0x80   # F
        ]
        for i, byte in enumerate(font_set):
            self.memory[i] = byte

    def emulate_cycle(self):
        self.opcode = (self.memory[self.pc] << 8) | self.memory[self.pc + 1]
        self.pc += 2

        x = (self.opcode & 0x0F00) >> 8
        y = (self.opcode & 0x00F0) >> 4
        nnn = self.opcode & 0x0FFF
        nn = self.opcode & 0x00FF
        n = self.opcode & 0x000F

        if self.opcode & 0xF000 == 0x0000:
            if nn == 0xE0:
                self.display = [[False for _ in range(64)] for _ in range(32)]
                self.draw_flag = True
            elif nn == 0xEE:
                self.pc = self.stack.pop()
        elif self.opcode & 0xF000 == 0x1000:
            self.pc = nnn
        elif self.opcode & 0xF000 == 0x2000:
            self.stack.append(self.pc)
            self.pc = nnn
        elif self.opcode & 0xF000 == 0x3000:
            if self.V[x] == nn:
                self.pc += 2
        elif self.opcode & 0xF000 == 0x4000:
            if self.V[x] != nn:
                self.pc += 2
        elif self.opcode & 0xF000 == 0x5000:
            if self.V[x] == self.V[y]:
                self.pc += 2
        elif self.opcode & 0xF000 == 0x6000:
            self.V[x] = nn
        elif self.opcode & 0xF000 == 0x7000:
            self.V[x] = (self.V[x] + nn) & 0xFF
        elif self.opcode & 0xF000 == 0x8000:
            if n == 0x0:
                self.V[x] = self.V[y]
            elif n == 0x1:
                self.V[x] |= self.V[y]
            elif n == 0x2:
                self.V[x] &= self.V[y]
            elif n == 0x3:
                self.V[x] ^= self.V[y]
            elif n == 0x4:
                sum = self.V[x] + self.V[y]
                self.V[0xF] = 1 if sum > 255 else 0
                self.V[x] = sum & 0xFF
            elif n == 0x5:
                self.V[0xF] = 1 if self.V[x] > self.V[y] else 0
                self.V[x] = (self.V[x] - self.V[y]) & 0xFF
            elif n == 0x6:
                self.V[0xF] = self.V[x] & 0x1
                self.V[x] >>= 1
            elif n == 0x7:
                self.V[0xF] = 1 if self.V[y] > self.V[x] else 0
                self.V[x] = (self.V[y] - self.V[x]) & 0xFF
            elif n == 0xE:
                self.V[0xF] = (self.V[x] & 0x80) >> 7
                self.V[x] = (self.V[x] << 1) & 0xFF
        elif self.opcode & 0xF000 == 0x9000:
            if self.V[x] != self.V[y]:
                self.pc += 2
        elif self.opcode & 0xF000 == 0xA000:
            self.I = nnn
        elif self.opcode & 0xF000 == 0xB000:
            self.pc = nnn + self.V[0]
        elif self.opcode & 0xF000 == 0xC000:
            self.V[x] = random.randint(0, 255) & nn
        elif self.opcode & 0xF000 == 0xD000:
            self.V[0xF] = 0
            for row in range(n):
                sprite_byte = self.memory[self.I + row]
                for col in range(8):
                    if sprite_byte & (0x80 >> col) != 0:
                        if self.display[(self.V[y] + row) % 32][(self.V[x] + col) % 64]:
                            self.V[0xF] = 1
                        self.display[(self.V[y] + row) % 32][(self.V[x] + col) % 64] ^= True
            self.draw_flag = True
        elif self.opcode & 0xF000 == 0xE000:
            if nn == 0x9E:
                if self.keypad[self.V[x]]:
                    self.pc += 2
            elif nn == 0xA1:
                if not self.keypad[self.V[x]]:
                    self.pc += 2
        elif self.opcode & 0xF000 == 0xF000:
            if nn == 0x07:
                self.V[x] = self.delay_timer
            elif nn == 0x0A:
                key_pressed = False
                for i in range(16):
                    if self.keypad[i]:
                        self.V[x] = i
                        key_pressed = True
                        break
                if not key_pressed:
                    self.pc -= 2
            elif nn == 0x15:
                self.delay_timer = self.V[x]
            elif nn == 0x18:
                self.sound_timer = self.V[x]
            elif nn == 0x1E:
                self.I += self.V[x]
            elif nn == 0x29:
                self.I = self.V[x] * 5
            elif nn == 0x33:
                self.memory[self.I] = self.V[x] // 100
                self.memory[self.I + 1] = (self.V[x] % 100) // 10
                self.memory[self.I + 2] = self.V[x] % 10
            elif nn == 0x55:
                for i in range(x + 1):
                    self.memory[self.I + i] = self.V[i]
            elif nn == 0x65:
                for i in range(x + 1):
                    self.V[i] = self.memory[self.I + i]

        if self.delay_timer > 0:
            self.delay_timer -= 1
        if self.sound_timer > 0:
            self.sound_timer -= 1

    def update_screen(self):
        for y in range(32):
            for x in range(64):
                if self.display[y][x]:
                    fill_rect(x*2, y*2, 2, 2, color(255,255,255))
                else:
                    fill_rect(x*2, y*2, 2, 2, color(0,0,0))

    def handle_input(self):
        key_map = {
            0: 4, 1: 5, 2: 6, 3: 7,
            4: 8, 5: 9, 6: 10, 7: 11,
            8: 12, 9: 13, 10: 14, 11: 15,
            12: 0, 13: 1, 14: 2, 15: 3
        }
        for nw_key, chip8_key in key_map.items():
            self.keypad[chip8_key] = keydown(nw_key)

    def load_rom(self, rom_data):
        for i, byte in enumerate(rom_data):
            self.memory[0x200 + i] = byte

    def run(self):
        while True:
            self.emulate_cycle()
            self.handle_input()
            if self.draw_flag:
                self.update_screen()
                self.draw_flag = False
            time.sleep(1/60)

# this is where you put your converted roms to! Just use this pastebin script and your chip8 roms and they will work! : https://pastebin.com/UR6xg0jc
rom_data = [
    0x00, 0xE0, 0xA2, 0x48, 0x60, 0x00, 0x61, 0x1E, 0x62, 0x00, 0xD2, 0x02, 0xD2, 0x12, 0x72, 0x08,
    0x32, 0x40, 0x12, 0x0A, 0x60, 0x00, 0x61, 0x3E, 0x62, 0x02, 0xA2, 0x4A, 0xD0, 0x2E, 0xD1, 0x2E,
    0x72, 0x0E, 0xD0, 0x2E, 0xD1, 0x2E, 0xA2, 0x58, 0x60, 0x0B, 0x61, 0x08, 0xD0, 0x1F, 0x70, 0x0A,
    0xA2, 0x67, 0xD0, 0x1F, 0x70, 0x0A, 0xA2, 0x76, 0xD0, 0x1F, 0x70, 0x03, 0xA2, 0x85, 0xD0, 0x1F,
    0x70, 0x0A, 0xA2, 0x94, 0xD0, 0x1F, 0x12, 0x46, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0,
    0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xFF, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0xFF, 0x81,
    0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
    0x80, 0x80, 0x80, 0x80, 0x80, 0xFF, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0xFF, 0x80, 0x80, 0x80,
    0x80, 0x80, 0x80, 0x80, 0xFF, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0xFF, 0x81, 0x81, 0x81, 0x81,
    0x81, 0x81, 0xFF, 0xFF,
]

chip8 = Chip8()
chip8.load_rom(rom_data)
chip8.run()

During your visit to our site, NumWorks needs to install "cookies" or use other technologies to collect data about you in order to:

With the exception of Cookies essential to the operation of the site, NumWorks leaves you the choice: you can accept Cookies for audience measurement by clicking on the "Accept and continue" button, or refuse these Cookies by clicking on the "Continue without accepting" button or by continuing your browsing. You can update your choice at any time by clicking on the link "Manage my cookies" at the bottom of the page. For more information, please consult our cookies policy.