def _load_background_shifters(self): self.bg_shifter_pattern_lo = to_16_bits((self.bg_shifter_pattern_lo & 0xFF00) | self.bg_next_tile_lsb) self.bg_shifter_pattern_hi = to_16_bits((self.bg_shifter_pattern_hi & 0xFF00) | self.bg_next_tile_msb) self.bg_shifter_attrib_lo = to_16_bits( (self.bg_shifter_attrib_lo & 0xFF00) | (0xFF if (self.bg_next_tile_attrib & 0b01) else 0x00)) self.bg_shifter_attrib_hi = to_16_bits( (self.bg_shifter_attrib_hi & 0xFF00) | (0xFF if (self.bg_next_tile_attrib & 0b10) else 0x00))
def cpu_write(self, addr, data): if addr > 0xFFFF: print("maior que 16 bits") if data > 0xFF: print("maior que 8 bits") if addr == 0x0000: # control self.control.reg = data self.tram_addr.set_nametable_x(self.control.get_nametable_x()) self.tram_addr.set_nametable_y(self.control.get_nametable_y()) elif addr == 0x0001: self.mask.reg = data # mask elif addr == 0x0002: # status pass elif addr == 0x0003: # OAM Address pass elif addr == 0x0004: # OAM Data pass elif addr == 0x0005: # Scroll if (self.address_latch == 0): self.fine_x = data & 0x07 self.tram_addr.set_coarse_x(data >> 3) self.address_latch = 1 else: self.tram_addr.set_fine_y(data & 0x07) self.tram_addr.set_coarse_y(data >> 3) self.address_latch = 0 elif addr == 0x0006: # PPU Address if self.address_latch == 0: self.tram_addr.reg = to_16_bits((data & 0x3F) << 8) | (self.tram_addr.reg & 0x00FF) self.address_latch = 1 else: self.tram_addr.reg = to_16_bits((self.tram_addr.reg & 0xFF00) | data) self.vram_addr.reg = self.tram_addr.reg self.address_latch = 0 elif addr == 0x0007: # PPU Data self.ppu_write(self.vram_addr.reg, data) self.vram_addr.reg = to_16_bits( self.vram_addr.reg + (32 if self.control.get_increment_mode() else 1))
def cpu_read(self, addr, is_read_only = False): if addr > 0xFFFF: print("maior que 16 bits") data = 0x00 if is_read_only: if addr == 0x0000: data = self.control.reg elif addr == 0x0001: data = self.mask.reg elif addr == 0x0002: data = self.status.reg elif addr == 0x0003: pass elif addr == 0x0004: pass elif addr == 0x0005: pass elif addr == 0x0006: pass elif addr == 0x0007: pass else: if addr == 0x0000: pass elif addr == 0x0001: pass elif addr == 0x0002: #self.status.set_vertical_blank(1) data = (self.status.reg & 0xE0) | (self.ppu_data_buffer & 0x1F) self.status.set_vertical_blank(0) self.address_latch = 0 elif addr == 0x0003: pass elif addr == 0x0004: pass elif addr == 0x0005: pass elif addr == 0x0006: pass elif addr == 0x0007: data = self.ppu_data_buffer self.ppu_data_buffer = self.ppu_read(self.vram_addr.reg) if (self.vram_addr.reg >= 0x3F00): data = self.ppu_data_buffer self.vram_addr.reg = to_16_bits( self.vram_addr.reg + (32 if self.control.get_increment_mode() else 1)) if data > 0xFF: print("maior que 8 bits") return to_8_bits(data)
def get_pattern_table(self, i, palette): for nTileY in range(16): for nTileX in range(16): nOffset = to_16_bits(nTileY * 256 + nTileX * 16) for row in range(8): tile_lsb = to_8_bits(self.ppu_read(i * 0x1000 + nOffset + row + 0x0000)) tile_msb = to_8_bits(self.ppu_read(i * 0x1000 + nOffset + row + 0x0008)) for col in range(8): pixel = to_8_bits((tile_lsb & 0x01) + (tile_msb & 0x01)) tile_lsb >>= 1 tile_msb >>= 1 self.spr_pattern_tbl[i].set_pixel( nTileX * 8 + (7 - col), nTileY * 8 + row, self.get_colour_from_palette_ram(palette, pixel) ) return self.spr_pattern_tbl[i]
def clock(self): if self.scanline >= -1 and self.scanline < 240: if self.scanline == 0 and self.cycle == 0: self.cycle = 1 if self.scanline == -1 and self.cycle == 1: self.status.set_vertical_blank(0) if (self.cycle >= 2 and self.cycle < 258) or (self.cycle >= 321 and self.cycle < 338): self._update_shifters() value = (self.cycle - 1) % 8 if value == 0: self._load_background_shifters() self.bg_next_tile_id = self.ppu_read(0x2000 | (self.vram_addr.reg & 0x0FFF)) #print(hex(self.bg_next_tile_id)) elif value == 2: self.bg_next_tile_attrib = self.ppu_read( 0x23C0 | (self.vram_addr.get_nametable_y() << 11) | (self.vram_addr.get_nametable_x() << 10) | ((self.vram_addr.get_coarse_y() >> 2) << 3) | (self.vram_addr.get_coarse_x() >> 2) ) if (self.vram_addr.get_coarse_y() & 0x02): self.bg_next_tile_attrib >>= 4 if (self.vram_addr.get_coarse_x() & 0x02): self.bg_next_tile_attrib >>= 2 self.bg_next_tile_attrib &= 0x03 elif value == 4: self.bg_next_tile_lsb = self.ppu_read( (self.control.get_pattern_background() << 12) + (to_16_bits(self.bg_next_tile_id) << 4) + (self.vram_addr.get_fine_y()) + 0 ) #print("LSB: ", self.bg_next_tile_lsb) elif value == 6: self.bg_next_tile_msb = self.ppu_read( (self.control.get_pattern_background() << 12) + (to_16_bits(self.bg_next_tile_id) << 4) + (self.vram_addr.get_fine_y()) + 8 ) #print("MSB: ", self.bg_next_tile_msb) elif value == 7: self._increment_scroll_x() if (self.cycle == 256): self._increment_scroll_y() if (self.cycle == 257): self._load_background_shifters() self._transfer_address_x() if (self.cycle == 338 or self.cycle == 340): self.bg_next_tile_id = self.ppu_read(0x2000 | (self.vram_addr.reg & 0x0FFF)) if (self.scanline == -1 and self.cycle >= 280 and self.cycle < 305): self._transfer_address_y() if (self.scanline == 240): pass # Post Render Scanline - Do Nothing! if self.scanline >= 241 and self.scanline < 261: if self.scanline == 241 and self.cycle == 1: #print("set_vertical_blank 1") self.status.set_vertical_blank(1) if self.control.get_enable_nmi(): self.nmi = True bg_pixel = 0x00 bg_palette = 0x00 if self.mask.get_render_background(): bit_mux = to_16_bits(0x8000 >> self.fine_x) p0_pixel = to_8_bits((self.bg_shifter_pattern_lo & bit_mux) > 0) p1_pixel = to_8_bits((self.bg_shifter_pattern_hi & bit_mux) > 0) bg_pixel = to_8_bits((p1_pixel << 1) | p0_pixel) bg_pal0 = to_8_bits((self.bg_shifter_attrib_lo & bit_mux) > 0) bg_pal1 = to_8_bits((self.bg_shifter_attrib_hi & bit_mux) > 0) bg_palette = to_8_bits((bg_pal1 << 1) | bg_pal0) self.spr_screen.set_pixel( self.cycle - 1, self.scanline, self.get_colour_from_palette_ram(bg_palette, bg_pixel)) #fake = 0x30 #if int((n.random.rand() * 15)) % 2: fake = 0x3F #self.spr_screen.set_pixel( self.cycle - 1, self.scanline, self.pal_screen[fake]) # Advance renderer - it never stops, it's relentless self.cycle += 1 if self.cycle >= 341: self.cycle = 0 self.scanline += 1 if self.scanline >= 261: self.scanline = -1 self.frame_complete = True if self.enable_log: print("Debug: ", end="") print(hex(self.bg_shifter_pattern_lo), " ", end="") print(hex(self.bg_shifter_pattern_hi), " ", end="") print(hex(self.bg_shifter_attrib_lo) , " ", end="") print(hex(self.bg_shifter_attrib_hi) , " ", end="") print(hex(self.bg_next_tile_id), " ", end="") print(hex(self.bg_next_tile_attrib), " ", end="") print(hex(self.bg_next_tile_lsb) , " ", end="") print(hex(self.bg_next_tile_msb) , " ", end="") print(hex(self.status.reg), " ", end="") print(hex(self.mask.reg), " ", end="") print(hex(self.control.reg) , " ", end="") print(hex(self.vram_addr.reg) , " ", end="") print(hex(self.tram_addr.reg), " ", end="") print(hex(self.fine_x), " ", end="") print(hex(self.address_latch), " ", end="") print(hex(self.ppu_data_buffer) , " ", end="") print(hex(self.scanline) , " ", end="") print(hex(self.cycle), " ")
def _update_shifters(self): if (self.mask.get_render_background()): self.bg_shifter_pattern_lo = to_16_bits(self.bg_shifter_pattern_lo << 1) self.bg_shifter_pattern_hi = to_16_bits(self.bg_shifter_pattern_hi << 1) self.bg_shifter_attrib_lo = to_16_bits(self.bg_shifter_attrib_lo << 1) self.bg_shifter_attrib_hi = to_16_bits(self.bg_shifter_attrib_hi << 1)