예제 #1
0
class Bus(object):

    def __init__(self):
        self.cpu = CPU()
        self.cpu.set_bus(self)

        self.ppu = PPU()

        self.cpu_ram = [0] * 64 * 1024

    def cpu_read(self, address, read_only):
        ignore_next, data = self.cartridge.cpu_read(address)

        if ignore_next:
            pass
        elif 0x0000 <= address <= 0x1FFF:
            # System RAM Address Range, mirrored every 2048
            data = self.cpu_ram[address & 0x07FF]
        elif 0x2000 <= address <= 0x3FFF:
            # PPU Address range, mirrored every 8
            data = self.ppu.cpu_read(address & 0x0007, read_only)
        return data

    def cpu_write(self, address, data):
        if self.cartridge.cpu_write(address, data):
            pass

        if 0x0000 <= address <= 0xffff:
            self.cpu_ram[address] = data

    def set_cartridge(self, cartridge):
        self.cartridge = cartridge
        self.ppu.set_cartridge(cartridge)
예제 #2
0
파일: nes.py 프로젝트: psykad/pytendo
 def __init__(self):
     self.cpu = CPU(self)
     self.mmu = MMU(self)
     self.ppu = PPU(self)
     self.cartridge = None
     self.ram = [0xFF] * 2048
     self._clock = 0
예제 #3
0
    def __init__(self):
        self.cpu = CPU()
        self.cpu.set_bus(self)

        self.ppu = PPU()

        self.cpu_ram = [0] * 64 * 1024
예제 #4
0
class Gameboy:
    def __init__(self, bootrom, rom, skip_bootrom=False):
        self.timer = Timer()
        self.ppu = PPU()
        self.apu = APU()
        self.joypad = Joypad()
        self.cartridge = Cartridge(rom)
        self.mmu = MMU(bootrom, self.cartridge, self.timer, self.ppu, self.apu,
                       self.joypad)
        self.timer.mmu = self.mmu
        self.ppu.mmu = self.mmu
        self.joypad.mmu = self.mmu
        self.cpu = CPU(self.mmu)
        self.t_cycles = 0
        self.reset(skip_bootrom)
        #if skip_bootrom:
        #    self.ppu.LY = 0x90 # for LY stubbed testing

    def reset(self, skip_bootrom=False):
        self.cpu.reset(skip_bootrom)
        self.mmu.reset(skip_bootrom)
        self.timer.reset(skip_bootrom)
        self.ppu.reset(skip_bootrom)
        self.joypad.reset()
        self.cartridge.reset()

    def run_frame(self):
        while not self.ppu.new_frame:
            self.cpu.handle_interrupts()
            cycles = self.cpu.tick()
            for i in range(cycles // 4):
                self.timer.tick()
                self.ppu.tick()
            self.t_cycles += cycles
        self.ppu.new_frame = False
예제 #5
0
    def __init__(self):
        self.MEMORY_SIZE = 0x800  # 2kB

        self.rom = None
        self.ram = RAM(self.MEMORY_SIZE)
        self.cpu = CPU(self.cpu_read, self.cpu_write)
        self.ppu = PPU(self.ppu_read, self.ppu_write)

        self.system_clock = 0
예제 #6
0
 def __init__(self, RAM, ROM, SRAM, use_MAD1_mapping, SRAM_size):
     self.RAM = RAM  # TODO: maybe rename to WRAM
     self.ROM = ROM
     self.SRAM = SRAM
     self.use_MAD1_mapping = use_MAD1_mapping
     self.SRAM_size = SRAM_size
     self.dma = DMAController()
     self.hdm = HDMAController()
     self.internal_cpu_registers = InternalCPURegisters()
     self.ppu = PPU()
예제 #7
0
    def __init__(self, file_name):
        pygame.init()
        self.screen = pygame.display.set_mode([256, 240])

        self.nes_file = self.read_nes_file(file_name)
        self.main_memory = [0 for _ in range(0x800)]
        self.save_memory = [0 for _ in range(0x2000)]
        self.ppu = PPU(self.nes_file)
        self.cpu = CPU(self.nes_file, self.main_memory, self.save_memory,
                       self.ppu)
예제 #8
0
 def __init__(self, bootrom, rom, skip_bootrom=False):
     self.timer = Timer()
     self.ppu = PPU()
     self.apu = APU()
     self.joypad = Joypad()
     self.cartridge = Cartridge(rom)
     self.mmu = MMU(bootrom, self.cartridge, self.timer, self.ppu, self.apu,
                    self.joypad)
     self.timer.mmu = self.mmu
     self.ppu.mmu = self.mmu
     self.joypad.mmu = self.mmu
     self.cpu = CPU(self.mmu)
     self.t_cycles = 0
     self.reset(skip_bootrom)
예제 #9
0
def main():
    # Set up command line arguments parser
    parser = argparse.ArgumentParser(description='NES Emulator')
    parser.add_argument('rom_path',
                        metavar='R',
                        type=str,
                        help='The location to the rom file')
    args = parser.parse_args()

    # load rom
    with open(args.rom_path, 'rb') as file:
        rom_bytes = file.read()

    rom = ROM(rom_bytes)

    # create ram
    ram = RAM()

    # create ppu
    ppu = PPU()

    # create cpu
    cpu = CPU(ram, ppu)
    cpu.start_up()
    cpu.run_rom(rom)
예제 #10
0
 def __init__(self, rom_path):
     self.rom_path = rom_path
     self._screen = Screen()
     self._memory = Memory()
     self._ppu = PPU(self._screen, self._memory)
     self._apu = APU(self._memory)
     self._rom = ROM(rom_path)
     self._cpu = CPU(self._memory, self._ppu, self._apu, self._rom)
예제 #11
0
    def __init__(self,
                 rom: str,
                 skipBios: bool = False,
                 nostalgic: bool = False) -> None:
        # main units
        self.z80 = Z80(self)
        self.ppu = PPU(self, nostalgic)
        self.mmu = MMU(self, rom)
        self.timer = Timer(self)
        # log dict
        self.LOG = {}
        # global states
        self.frames = 0
        self.paused = False

        self.initData(skipBios)
        print(INSTRUCTION)
예제 #12
0
def cpu():
    ram = RAM()
    ppu = PPU()
    cpu = CPU(ram, ppu)
    cpu.start_up()
    cpu.rom = MagicMock()
    cpu.rom.memory_start_location = 0
    cpu.rom.memory_end_location = 0x1FFF
    return cpu
예제 #13
0
def main():
    mode = 1
    frequency = 0

    if len(sys.argv) >= 2:
        cpu = CPU(mode=0 if "async" in sys.argv else 1,
                  frequency=frequency,
                  console=False if "noconsole" in sys.argv else True)

    else:
        cpu = CPU(mode=mode, frequency=frequency, console=True)

    if sys.platform == "win32":
        ppu = PPU(cpu)
        ppu.start()

    clear()
    print(cpu)
    print("6502 Emulator by Andrija Jovanovic\n")
    print("Running ROM: ", end='')
    print(cpu.rom_path)
    input("\nPress <Enter> to start...")
    cpu.start()
예제 #14
0
파일: nes.py 프로젝트: psykad/pytendo
class NES:
    def __init__(self):
        self.cpu = CPU(self)
        self.mmu = MMU(self)
        self.ppu = PPU(self)
        self.cartridge = None
        self.ram = [0xFF] * 2048
        self._clock = 0

    def reset(self):
        self.cpu.reset()

    def start(self):
        if (self.cartridge is None):
            raise RuntimeError("No ROM loaded!")

        self.cpu.reset()

        # TODO: Create proper execution loop.
        while True:
            self.frame()
            #time.sleep(0.016)

    def frame(self):
        self.step()

    def step(self):
        self.cpu.step()

    def consume_cycles(self, cycles):
        # Update clock with instruction cycles.
        self._clock = (self._clock + cycles) & 0xFFFFFFFF

        self.ppu.step(cycles)

    def load_cartridge(self, filename):
        self.cartridge = Cartridge(filename)
예제 #15
0
파일: nes.py 프로젝트: ottolin/pyNES
    def __init__(self):
        self.cpu = CPU(self)
        self.ppu = PPU(self)
        self.papu = PAPU(self)
        self.keyboard = Keyboard(self)
        self.rom = None
        self.romFile = None
        self.mmap = None

        self.isRunning = False
        self.limitFrames = True
        self.fpsFrameCount = 0
        
        self.opts = Nes.Options()
        self.frameTime = self.opts.preferredFrameRate
예제 #16
0
class NES():
    def __init__(self, prg, chr):
        self.ppu = PPU(chr)
        self.cpu = CPU(prg, self.ppu)
        self.frame = self.ppu.init_frame()

    def cycle(self):
        start = time.time()
        ##########

        out = None
        while not out:
            cycle = self.cpu.run()
            out = self.ppu.run(cycle * 3)
        self.frame = out

        ###########
        #time.sleep(max(0,(1.0/60-(time.time() - start))))
        #time.sleep(0.01)
        return

    def run(self):
        while True:
            self.cycle()
예제 #17
0
def main():
    # set up command line argument parser
    parser = argparse.ArgumentParser(description="NES Emulator.")
    parser.add_argument('rom_path',
                        metavar='R',
                        type=str,
                        help='path to nes rom')
    parser.add_argument('--test')

    args = parser.parse_args()

    # TODO: validate rom path is correct
    print(args.rom_path)

    # load rom
    with open(args.rom_path, 'rb') as file:
        rom_bytes = file.read()

    # create ram
    ram = RAM()

    # create ppu
    ppu = PPU()

    # create apu
    apu = APU()

    rom = ROM(rom_bytes)

    # create cpu
    cpu: CPU = CPU(ram, ppu, apu)
    cpu.start_up()
    cpu.load_rom(rom, args.test)

    # check if running test rom
    if args.test:
        # load in the test log
        with open('test_log.log', 'r') as nes_test_file:
            nes_test_log = NesTestLog(nes_test_file.readlines())
        while True:
            cpu.identify()
            nes_test_log.compare(cpu)
            cpu.execute()
    else:
        while True:
            cpu.identify()
            cpu.execute()
예제 #18
0
    def __init__(self, rom_bytes, testing):
        self.rom = ROM(rom_bytes)

        # create ram
        self.ram = RAM()

        # create ppu and apu
        self.ppu = PPU()
        self.apu = APU()

        # create cpu
        self.cpu = CPU(self.ram, self.ppu, self.apu)

        # create ppu window
        self.window = Window()

        self.testing = testing

        self.nes_test_log = None
예제 #19
0
파일: main.py 프로젝트: caiocdcs/MC861
def main():

	# Check if there's a parameter
	if len(sys.argv) != 2:
		print ("Provide a .nes file\n")
		return
	
	window = Window()
	window.set_size(256, 240)
	# window.set_size(768, 720)
	cpu = CPU()
	ppu = PPU(window)
	bus = BUS(cpu, ppu)
	cart = Cartridge(sys.argv[1])
	bus.insertCartridge(cart)
	
	cpu.connectBus(bus)

	# Do all init (load pallettes, background, set flags...) before running pyglet loop
	
	pyglet.clock.schedule_interval(bus.setFrame, 1/60.0)
	pyglet.app.run()
예제 #20
0
파일: main.py 프로젝트: ldesuque/pNES
def main():
    parser = argparse.ArgumentParser(description='NesEmulator :)')
    parser.add_argument('rom_path',
                        metavar='R',
                        type=str,
                        help='Path to the NES ROM')

    args = parser.parse_args()

    # TODO: Implement drag and drop rom system
    print(args.rom_path)

    with open(args.rom_path, 'rb') as file:
        rom_bytes = file.read()

        rom = ROM(rom_bytes)

        ram = RAM()
        ppu = PPU()

        cpu = CPU(ram, ppu)
        cpu.start_up()
        cpu.run_rom(rom)
예제 #21
0
def main():
    parser = argparse.ArgumentParser(description='NES Emulator.')

    parser.add_argument('rom_path',
                        metavar='R',
                        type=str,
                        help='path to the nes rom')

    args = parser.parse_args()

    print(args.rom_path)

    with open(args.rom_path, 'rb') as file:
        rom_bytes = file.read()

    rom = ROM(rom_bytes)

    memory = Memory()
    ppu = PPU()

    cpu = CPU(memory, ppu)

    cpu.initialization()
    cpu.load_rom(rom)
예제 #22
0
파일: nes.py 프로젝트: ottolin/pyNES
class Nes:
    #class ExecutionThread(Thread):
    #    def __init__(self, nes):
    #        self.nes = nes
    #        Thread.__init__(self)
    #    
    #    def run(self):
    #        print "Execution thread started."
    #        while self.nes.isRunning:
    #            self.nes.cpu.emulate()

    class Options:
        CPU_FREQ_NTSC= 1789772.5 #1789772.72727272d
        CPU_FREQ_PAL= 1773447.4
        def __init__(self):
            self.preferredFrameRate= 60,
            self.fpsInterval= 500 # Time between updating FPS in ms
            self.showDisplay= True
    
            self.emulateSound= False
            self.sampleRate= 44100 # Sound sample rate in hz
    
    def __init__(self):
        self.cpu = CPU(self)
        self.ppu = PPU(self)
        self.papu = PAPU(self)
        self.keyboard = Keyboard(self)
        self.rom = None
        self.romFile = None
        self.mmap = None

        self.isRunning = False
        self.limitFrames = True
        self.fpsFrameCount = 0
        
        self.opts = Nes.Options()
        self.frameTime = self.opts.preferredFrameRate

        #self.executionThread = Nes.ExecutionThread(self)
        
    def reset(self):
        if self.mmap:
            self.mmap.reset()
        self.cpu.reset()
        self.ppu.reset()
        self.papu.reset()

    def start(self):
        if (self.rom and self.rom.valid):
            if (not self.isRunning):
                self.isRunning = True;
                self.ppu.startFrame()
                #self.executionThread.start()
        else:
            print "There is no ROM loaded, or it is invalid."
    
    def printFps(self):
        pass
    
    def stop(self):
        self.isRunning = False
    
    def reloadRom(self):
        if self.romFile:
            self.loadRom(self.romFile)
    
    def loadRom(self, file):
        if self.isRunning:
            self.stop()
        
        print "Loading rom {0}...".format(file)
        
        # Load ROM file
        self.rom = Rom(self)
        self.rom.load(file)
        if self.rom.valid:
            print "Rom loaded."
            self.reset()
            print "Creating rom mapper..."
            self.mmap = self.rom.createMapper()
            if not self.mmap:
                return
            self.mmap.loadROM()
            # TODO:
            self.ppu.setMirroring(self.rom.getMirroringType())
            self.romFile = file
            
            print "Initialized NES, ready to start."
        else:
            print "Invalid ROM: {0}".format(file)
        
        return self.rom.valid
예제 #23
0
class Emulator(object):
    def __init__(self, file_name):
        pygame.init()
        self.screen = pygame.display.set_mode([256, 240])

        self.nes_file = self.read_nes_file(file_name)
        self.main_memory = [0 for _ in range(0x800)]
        self.save_memory = [0 for _ in range(0x2000)]
        self.ppu = PPU(self.nes_file)
        self.cpu = CPU(self.nes_file, self.main_memory, self.save_memory,
                       self.ppu)

    def read_nes_file(self, file_name):
        with open(file_name, 'rb') as f:
            header = Header(f.read(16))
            trainer = f.read(512) if header.has_trainer else 0
            nes_prg_rom = f.read(header.prg_rom_size)
            nes_chr_rom = f.read(header.chr_rom_size)
            return NesFile(header, trainer, nes_prg_rom, nes_chr_rom)

    def run(self):
        for event in pygame.event.get():
            if event.type == QUIT:
                exit()
            elif event.type == pygame.KEYDOWN or event.type == pygame.KEYUP:
                if event.key == pygame.K_u:
                    self.cpu.input_status[0] = event.type == pygame.KEYDOWN
                if event.key == pygame.K_i:
                    self.cpu.input_status[1] = event.type == pygame.KEYDOWN
                if event.key == pygame.K_j:
                    self.cpu.input_status[2] = event.type == pygame.KEYDOWN
                if event.key == pygame.K_k:
                    self.cpu.input_status[3] = event.type == pygame.KEYDOWN
                if event.key == pygame.K_w:
                    self.cpu.input_status[4] = event.type == pygame.KEYDOWN
                if event.key == pygame.K_s:
                    self.cpu.input_status[5] = event.type == pygame.KEYDOWN
                if event.key == pygame.K_a:
                    self.cpu.input_status[6] = event.type == pygame.KEYDOWN
                if event.key == pygame.K_d:
                    self.cpu.input_status[7] = event.type == pygame.KEYDOWN

        cycles_per_scanline = 341 / 3
        end_of_render = self.cpu.cpu_cycle + (240 + 1) * cycles_per_scanline
        end_of_vblank = end_of_render + 20 * cycles_per_scanline
        end_of_flame = self.cpu.cpu_cycle + 29780.5

        is_8x16_mode = self.ppu.ppu_ctrl.bit5
        sprites_number_per_lines = [0 for _ in range(256 + 16)]
        for index in range(64):
            for y in range(16 if is_8x16_mode else 8):
                # print(self.ppu.oam[index * 4], y)
                sprites_number_per_lines[self.ppu.oam[index * 4] + y] += 1

        # ppu render flame
        for line in range(241):
            end_of_scanline = self.cpu.cpu_cycle + cycles_per_scanline

            # ppu render one scanline
            while self.cpu.cpu_cycle < end_of_scanline:
                self.cpu.exec_op()

            # hblank
            if line == self.ppu.oam[0]:
                self.ppu.ppu_status.bit6 = 1
            if sprites_number_per_lines[line] > 8:
                self.ppu.ppu_status.bit5 = 1
        while self.cpu.cpu_cycle < end_of_render:
            self.cpu.exec_op()

        # vblank
        self.ppu.ppu_status.value |= 0x80
        self.cpu.nmi()
        while self.cpu.cpu_cycle < end_of_vblank:
            self.cpu.exec_op()
        while self.cpu.cpu_cycle < end_of_flame:
            self.cpu.exec_op()

        # end of flame, render and show
        if self.ppu.ppu_mask.bit3:
            self.ppu.render_background_1()
        if self.ppu.ppu_mask.bit4:
            self.ppu.render_sprites()

        pygame.surfarray.blit_array(self.screen, self.ppu.pixels)
        pygame.display.update()

        self.ppu.ppu_status.bit6 = 0
        self.ppu.ppu_status.bit5 = 0
예제 #24
0
파일: nes.py 프로젝트: SuperJason/SlimPyNES
    else:
        rom_file_name = 'supermario.nes'

    nes = NES()
    rom = ROM(nes)
    if rom.headercheck(rom_file_name) != True:
        exit()
    nes.rom = rom

    mem = MEMORY(nes)
    rom.load(rom_file_name, mem)
    nes.mem = mem

    cpu = CPU(nes)
    nes.cpu = cpu
    cpu.reset()

    ppu = PPU(nes)
    nes.ppu = ppu
    ppu.reset()

    disp = DISPLAY(nes)
    nes.disp = disp
    disp.init()

    in_put = INPUT(nes)
    nes.in_put = in_put
    in_put.reset()

    nes.start()
예제 #25
0
class Emulator(object):

    __slots__ = ('z80', 'ppu', 'mmu', 'timer', 'LOG', 'frames', 'paused')

    def __init__(self,
                 rom: str,
                 skipBios: bool = False,
                 nostalgic: bool = False) -> None:
        # main units
        self.z80 = Z80(self)
        self.ppu = PPU(self, nostalgic)
        self.mmu = MMU(self, rom)
        self.timer = Timer(self)
        # log dict
        self.LOG = {}
        # global states
        self.frames = 0
        self.paused = False

        self.initData(skipBios)
        print(INSTRUCTION)

    def step(self) -> None:
        if self.mmu.dmaInProgress:
            cyclesPassed = self.mmu.step()
        else:
            cyclesPassed = self.z80.step()
        self.takeLog()
        self.timer.tick(cyclesPassed)
        self.ppu.tick(cyclesPassed)

    def run(self, frames: int = -1) -> None:
        while self.frames != frames:
            self.step()
            self.ppu.handleEvents()

    def read(self, addr: int) -> int:
        return self.mmu.read(addr)

    def write(self, addr: int, byte: int) -> None:
        self.mmu.write(addr, byte)

    def initData(self, skipBios: bool) -> None:
        if not skipBios: return

        self.z80.PC = 0x100
        self.z80.SP = 0xFFFE
        self.z80.A = 0x01
        self.z80.B = 0x00
        self.z80.C = 0x13
        self.z80.D = 0x00
        self.z80.E = 0xD8
        self.z80.F = 0xB0
        self.z80.H = 0x01
        self.z80.L = 0x4D

        self.write(0xFF10, 0x80)
        self.write(0xFF11, 0xBF)
        self.write(0xFF12, 0xF3)
        self.write(0xFF14, 0xBF)
        self.write(0xFF16, 0x3F)
        self.write(0xFF19, 0xBF)
        self.write(0xFF1A, 0x7F)
        self.write(0xFF1B, 0xFF)
        self.write(0xFF1C, 0x9F)
        self.write(0xFF1E, 0xBF)
        self.write(0xFF20, 0xFF)
        self.write(0xFF23, 0xBF)
        self.write(0xFF24, 0x77)
        self.write(0xFF25, 0xF3)
        self.write(0xFF26, 0xF1)
        self.write(0xFF40, 0x91)
        self.write(0xFF41, 0x05)
        self.write(0xFF47, 0xFC)
        self.write(0xFF48, 0xFF)
        self.write(0xFF49, 0xFF)
        self.write(0xFF50, 0x01)

    def takeLog(self) -> None:
        self.LOG['frames'] = self.frames
        self.LOG['opcode'] = toHex(self.z80.opcode)
        self.LOG['opname'] = self.z80.opname

        self.LOG['arg0'] = toHex(self.z80.args[0])
        self.LOG['arg1'] = toHex(self.z80.args[1])

        self.LOG['PC'] = toHex(self.z80.PC, 4)
        self.LOG['SP'] = toHex(self.z80.SP, 4)

        self.LOG['A'] = toHex(self.z80.A)
        self.LOG['B'] = toHex(self.z80.B)
        self.LOG['C'] = toHex(self.z80.C)
        self.LOG['D'] = toHex(self.z80.D)
        self.LOG['E'] = toHex(self.z80.E)
        self.LOG['F'] = toHex(self.z80.F)
        self.LOG['H'] = toHex(self.z80.H)
        self.LOG['L'] = toHex(self.z80.L)

    def printReg(self) -> None:
        print('\nregisters:')
        for key, val in self.LOG.items():
            print('\t', key, val)

    def printMem(self, title: str, start: int, stop: int, step: int) -> None:
        print(title)
        for addr in range(start, stop, step):
            print(f'\t{toHex(addr, length=4)}', end='    ')
            for offset in range(step):
                print(toHex(self.read(addr + offset)), end=' ')
            print()
예제 #26
0
 def __init__(self, prg, chr):
     self.ppu = PPU(chr)
     self.cpu = CPU(prg, self.ppu)
     self.frame = self.ppu.init_frame()
예제 #27
0
class Emulator:
    def __init__(self):
        self.MEMORY_SIZE = 0x800  # 2kB

        self.rom = None
        self.ram = RAM(self.MEMORY_SIZE)
        self.cpu = CPU(self.cpu_read, self.cpu_write)
        self.ppu = PPU(self.ppu_read, self.ppu_write)

        self.system_clock = 0

    def set_rom(self, rom: ROM):
        self.rom = rom
        self.cpu.reset()

    def has_rom(self):
        return self.rom is not None

    def tick_clock(self):
        self.ppu.clock()

        if self.system_clock % 3 == 0:
            self.cpu.clock()

        self.system_clock += 1

    # ----------------------------------- PPU BUS ADDRESSING - 16 bits range - 0x0000 to 0xFFFF
    def ppu_write(self, addr, value):
        addr &= 0x3FFF

        # pattern memory
        # if addr <= 0x1FFF:
        # return self.rom.get_chr_data(addr)  # self.ppu.tbl_pattern[int(addr >= 0x1000)][addr & 0x0FFF]
        # elif addr <= 0x3EFF:
        #    pass
        # palette memory
        if 0x3F00 <= addr <= 0x3FFF:
            addr &= 0x001F
            # mirroring
            if addr == 0x0010 or addr == 0x0014 or addr == 0x0018 or addr == 0x001C:
                addr -= 0x10
            self.ppu.tbl_palette[addr] = value
        return value

    def ppu_read(self, addr, byte=1):
        addr &= 0x3FFF

        # pattern memory
        if addr <= 0x1FFF:
            return self.rom.get_chr_data(
                addr
            )  # self.ppu.tbl_pattern[int(addr >= 0x1000)][addr & 0x0FFF]
        elif addr <= 0x3EFF:
            pass
        # palette memory
        elif 0x3F00 <= addr <= 0x3FFF:
            addr &= 0x001F
            # mirroring
            if addr == 0x0010 or addr == 0x0014 or addr == 0x0018 or addr == 0x001C:
                addr -= 0x10
            return self.ppu.tbl_palette[addr]

    def __ppu_memory_access(self, write, addr, value, word=0):
        pass

    # ----------------------------------- CPU BUS ADDRESSING - 16 bits range - 0x0000 to 0xFFFF
    # CPU write to memory
    def cpu_write(self, addr, value):
        return self.__cpu_memory_access(True, addr, value)

    # CPU read from memory
    def cpu_read(self, addr, byte=1):
        if byte == 2:
            return self.__cpu_memory_access(False, addr, None, 1)
        return self.__cpu_memory_access(False, addr, None)

    def __cpu_memory_access(self, write, addr, value, word=0):
        # RAM ranges from 0x0000 to 0x2000 and uses mirroring each 0x800
        if addr <= 0x1FFF:
            if write:
                return self.ram.cpu_write(addr, value)
            else:
                if word:
                    return self.ram.get_word(addr)  # pop 2 bytes from memory
                else:
                    return self.ram.cpu_read(addr)  # pop 1 byte from memory

        # PPU Ranges from 0x2000 to 0x3FFF
        elif addr <= 0x3FFF:
            if write:
                return self.ppu.cpu_write(addr, value)
            else:
                return self.ppu.cpu_read(addr)

        # access rom otherwise
        if word:
            return self.rom.get_word(addr)

        return self.rom.get(addr)
예제 #28
0
파일: main.py 프로젝트: PietPtr/Gameboy
from ppu import PPU
from threading import Thread
from queue import Queue
import time

data = array("B")

if len(sys.argv) < 2:
    print("pls give rom name")
    sys.exit()

filename = sys.argv[1]
filesize = os.stat(filename).st_size

print("Loading", filename, " (" + str(filesize) + " bytes)")

with open(filename, 'rb') as f:
    data.fromfile(f, filesize)

queue = Queue()

render_thread = Thread(target=renderer.render, args=(queue, ))
render_thread.start()

memory.loadROM(data)
memory.loadBootstrap()

ppu = PPU(queue)

cpu.run(ppu)
예제 #29
0
class LoROMMemoryMapper(object):
    def __init__(self, RAM, ROM, SRAM, use_MAD1_mapping, SRAM_size):
        self.RAM = RAM  # TODO: maybe rename to WRAM
        self.ROM = ROM
        self.SRAM = SRAM
        self.use_MAD1_mapping = use_MAD1_mapping
        self.SRAM_size = SRAM_size
        self.dma = DMAController()
        self.hdm = HDMAController()
        self.internal_cpu_registers = InternalCPURegisters()
        self.ppu = PPU()

    def read(self, bank, offset):
        if bank >= 0x00 and bank <= 0x3F:
            return self.read_system(bank, offset)
        elif bank >= 0x40 and bank <= 0x6F:
            return self.read_ROM(bank, offset)
        elif bank >= 0x70 and bank <= 0x7D:
            return self.read_SRAM_ROM(bank, offset)
        elif bank >= 0x7E and bank <= 0x7F:
            return self.read_RAM(bank, offset)
        elif bank >= 0x80 and bank <= 0xFF:
            return self.read_upper_mirror(bank, offset)
        else:
            raise IllegalAddressExcpetion()

    # 0x00:0000 - 3F:FFFF read ROM and system stuff
    # TODO: the doc on the internet is very inconsistent about the memory ranges
    def read_system(self, bank, offset):
        if offset <= 0x1FFF:
            return self.RAM[offset]
        elif offset >= 0x2000 and offset <= 0x2FFF:  # maybe 21FF is correct
            # TODO: PPU, APU, Hardware Registers
            # 0x2100 - 0x213F PPU (or PPU2 ?)
            # 0x2180 - 0x2183 (insde RAM?)
            # raise NotImplementedError()
            return self.ppu.read(offset)
        elif offset >= 0x3000 and offset <= 0x3FFF:
            # TODO: Super-FX, DSP
            raise NotImplementedError()
        elif offset >= 0x4000 and offset <= 0x41FF:  # maybe 40FF is correct
            # TODO: Joypad Registers / Controller
            # 0x4016 - 0x4017 CPU
            raise NotImplementedError()
        elif offset >= 0x4200 and offset <= 0x5FFF:  # maybe 44FF is correct
            # TODO: DMA, PPU2, Hardware Registers
            # 0x4200 - 0x420D CPU
            # 0x4100 - 0x421F CPU
            # 0x4300 - 0x437F CPU
            if offset == 0x4200:
                return self.internal_cpu_registers.read(offset)
            elif offset >= 0x4300 and offset <= 0x43FF:
                return self.dma.read(offset)
            print("Error read Address: " + hex(offset))
            return 0
        elif offset >= 0x6000 and offset <= 0x7FFF:
            # TODO: enhancement chip memory
            raise NotImplementedError()
        elif offset >= 0x8000:
            # read ROM
            ROM_bank = (bank) * 0x8000
            return self.ROM[ROM_bank + (offset - 0x8000)]
        else:
            raise IllegalAddressExcpetion()

    # 0x40:0000 - 6F:FFFF read ROM (only 32 KB in 64KB, the other half is "maybe" mirrored)
    def read_ROM(self, bank, offset):
        if offset <= 0x7FFF and not self.use_MAD1_mapping:
            # read ROM
            ROM_bank = 0x20000 + (bank - 0x40) * 0x10000
            return self.ROM[ROM_bank + offset]
        elif offset >= 0x8000:
            # read ROM
            ROM_bank = 0x20000 + (bank - 0x40) * 0x10000
            return self.ROM[ROM_bank + offset]
        else:
            raise IllegalAddressExcpetion()

    # 0x70:0000 - 7D:FFFF reads the SRAM inside the cartirge or the ROM
    def read_SRAM_ROM(self, bank, offset):
        if offset >= 0x0000 and offset <= 0x7FFF:
            # read SRAM
            # if the SRAM is smaller than 32Kbyte it is repeated on and on (SRAM mirror)
            return self.SRAM[offset % self.SRAM_size]
        elif offset >= 0x8000 and offset <= 0xFFFF:
            # read ROM from 38:XXXX in 32KB chunks
            ROM_bank = 0x380000 + (bank - 0x70) * 0x8000
            return self.ROM[ROM_bank + (offset - 0x8000)]
        else:
            raise IllegalAddressExcpetion()

    # 0x7E:0000 - 0x7F:FFFF read the RAM inside the SNES
    def read_RAM(self, bank, offset):
        # 8KB LowRAM, 24KB HighRAM, 96KB ExRAM
        if bank == 0x7E:
            return self.RAM[offset]
        elif bank == 0x7F:
            return self.RAM[0x8000 + offset]
        else:
            raise IllegalAddressExcpetion()

    # 0x80:0000 - 0xFF:FFFF mirror (same as self.read except RAM)
    def read_upper_mirror(self, bank, offset):
        if bank >= (0x00 + 0x80) and bank <= (0x3F + 0x80):
            return self.read_system(bank - 0x80, offset)
        elif bank >= (0x40 + 0x80) and bank <= (0x6F + 0x80):
            return self.read_ROM(bank - 0x80, offset)
        elif bank >= (0x70 + 0x80) and bank <= (0x7D + 0x80):
            return self.read_SRAM_ROM(bank - 0x80, offset)
        elif bank >= (0x7E + 0x80) and bank <= (0x7F + 0x80):
            return self.read_more_SRAM_ROM(bank,
                                           offset)  # different to self.read
        else:
            raise IllegalAddressExcpetion()

    # 0xFE:0000 - 0xFF:FFFF read more SRAM and ROM
    def read_more_SRAM_ROM(self, bank, offset):
        if bank == 0xFE:
            if offset >= 0x0000 and offset <= 0x7FFF:
                return self.SRAM[offset]
            elif offset >= 0x8000 and offset <= 0xFFFF:
                return self.ROM[0x3E8000 + offset]
            else:
                raise IllegalAddressExcpetion()
        elif bank == 0xFF:
            if offset >= 0x0000 and offset <= 0x7FFF:
                return self.SRAM[offset]
            elif offset >= 0x8000 and offset <= 0xFFFF:
                return self.ROM[0x3F0000 + offset]
            else:
                raise IllegalAddressExcpetion()
        else:
            raise IllegalAddressExcpetion()

    def write(self, bank, offset, value):
        if bank >= 0x00 and bank <= 0x3F:
            self.write_system(bank, offset, value)
        elif bank >= 0x40 and bank <= 0x6F:
            raise CanNotWriteROMException()
        elif bank >= 0x70 and bank <= 0x7D:
            self.write_SRAM_ROM(bank, offset, value)
        elif bank >= 0x7E and bank <= 0x7F:
            self.write_RAM(bank, offset, value)
        elif bank >= 0x80 and bank <= 0xFF:
            self.write_upper_mirror(bank, offset, value)
        else:
            raise IllegalAddressExcpetion()

    # 0x00:0000 - 3F:FFFF write system stuff
    # TODO: the doc on the internet is very inconsistent about the memory ranges
    # TODO: do we need the bak arg?
    def write_system(self, bank, offset, value):
        if offset <= 0x1FFF:
            self.RAM[offset] = value
        elif offset >= 0x2000 and offset <= 0x2FFF:  # maybe 21FF is correct
            # TODO: PPU, APU, Hardware Registers
            # 0x2100 - 0x213F PPU (or PPU2 ?)
            # 0x2180 - 0x2183 (insde RAM?)
            # raise NotImplementedError()
            self.ppu.write(offset, value)
        elif offset >= 0x3000 and offset <= 0x3FFF:
            # TODO: Super-FX, DSP
            raise NotImplementedError()
        elif offset >= 0x4000 and offset <= 0x41FF:  # maybe 40FF is correct
            # TODO: Joypad Registers / Controller
            # 0x4016 - 0x4017 CPU
            raise NotImplementedError()
        elif offset >= 0x4200 and offset <= 0x5FFF:  # maybe 44FF is correct
            # TODO: DMA, PPU2, Hardware Registers
            # 0x4200 - 0x420D CPU
            # 0x4100 - 0x421F CPU
            if offset == 0x4200:
                self.internal_cpu_registers.write(offset, value)
                return
            elif offset >= 0x4300 and offset <= 0x43FF:
                self.dma.write(offset, value)
                return
            # 0x4300 - 0x437F CPU
            print("Error write Address: " + hex(offset) + str(value))
        elif offset >= 0x6000 and offset <= 0x7FFF:
            # TODO: enhancement chip memory
            raise NotImplementedError()
        elif offset >= 0x8000:
            # write ROM
            raise CanNotWriteROMException()
        else:
            raise IllegalAddressExcpetion()

    # 0x70:0000 - 7D:FFFF writes the SRAM inside the cartirge or the ROM
    def write_SRAM_ROM(self, bank, offset, value):
        if offset >= 0x0000 and offset <= 0x7FFF:
            # write SRAM
            # if the SRAM is smaller than 32Kbyte it is repeated on and on (SRAM mirror)
            self.SRAM[offset % self.SRAM_size] = value
        elif offset >= 0x8000 and offset <= 0xFFFF:
            # write ROM
            raise CanNotWriteROMException()
        else:
            raise IllegalAddressExcpetion()

    # 0x7E:0000 - 0x7F:FFFF writes the RAM inside the SNES
    def write_RAM(self, bank, offset, value):
        # 8KB LowRAM, 24KB HighRAM, 96KB ExRAM
        if bank == 0x7E:
            self.RAM[offset] = value
        elif bank == 0x7F:
            self.RAM[0x8000 + offset] = value
        else:
            raise IllegalAddressExcpetion()

    # 0x80:0000 - 0xFF:FFFF mirror (same as self.write except RAM)
    def write_upper_mirror(self, bank, offset, value):
        if bank >= (0x00 + 0x80) and bank <= (0x3F + 0x80):
            self.write_system(bank - 0x80, offset, value)
        elif bank >= (0x40 + 0x80) and bank <= (0x6F + 0x80):
            # write ROM
            raise CanNotWriteROMException()
        elif bank >= (0x70 + 0x80) and bank <= (0x7D + 0x80):
            self.write_SRAM_ROM(bank - 0x80, offset, value)
        elif bank >= (0x7E + 0x80) and bank <= (0x7F + 0x80):
            self.write_more_SRAM_ROM(bank, offset,
                                     value)  # different to self.write
        else:
            raise IllegalAddressExcpetion()

    # 0xFE:0000 - 0xFF:FFFF read more SRAM and ROM
    def write_more_SRAM_ROM(self, bank, offset, value):
        if bank == 0xFE:
            if offset >= 0x0000 and offset <= 0x7FFF:
                self.SRAM[offset] = value
            elif offset >= 0x8000 and offset <= 0xFFFF:
                # write ROM
                raise CanNotWriteROMException()
            else:
                raise IllegalAddressExcpetion()
        elif bank == 0xFF:
            if offset >= 0x0000 and offset <= 0x7FFF:
                self.SRAM[offset] = value
            elif offset >= 0x8000 and offset <= 0xFFFF:
                # write ROM
                raise CanNotWriteROMException()
            else:
                raise IllegalAddressExcpetion()
        else:
            raise IllegalAddressExcpetion()