// license:BSD-3-Clause // copyright-holders:Wilbert Pol /***************************************************************************** * * video/gb_lcd.h * ****************************************************************************/ #ifndef MAME_VIDEO_GB_LCD_H #define MAME_VIDEO_GB_LCD_H #pragma once #include "cpu/lr35902/lr35902.h" class dmg_ppu_device : public device_t, public device_video_interface { public: template dmg_ppu_device(const machine_config &mconfig, const char *tag, device_t *owner, T &&cpu_tag) : dmg_ppu_device(mconfig, tag, owner, u32(0)) { set_lr35902_tag(std::forward(cpu_tag)); } dmg_ppu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); template void set_lr35902_tag(T &&tag) { m_lr35902.set_tag(std::forward(tag)); } uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); DECLARE_READ8_MEMBER(vram_r); DECLARE_WRITE8_MEMBER(vram_w); DECLARE_READ8_MEMBER(oam_r); DECLARE_WRITE8_MEMBER(oam_w); virtual DECLARE_READ8_MEMBER(video_r); virtual DECLARE_WRITE8_MEMBER(video_w); virtual void update_state(); protected: enum { // bits in LCD Control register ENABLED = 0x80, WINDOW_ENABLED = 0x20, LARGE_SPRITES = 0x04, SPRITES_ENABLED = 0x02, BACKGROUND_ENABLED = 0x01, // bits in LCD Status register LY_LYC_INT_ENABLED = 0x40, MODE_2_INT_ENABLED = 0x20, MODE_1_INT_ENABLED = 0x10, MODE_0_INT_ENABLED = 0x08, LY_LYC_FLAG = 0x04 }; struct layer_struct { uint8_t enabled; uint8_t *bg_tiles; uint8_t *bg_map; uint8_t xindex; uint8_t xshift; uint8_t xstart; uint8_t xend; /* GBC specific */ uint8_t *gbc_map; int16_t bgline; }; inline void plot_pixel(int x, int y, uint16_t color); void select_sprites(); void calculate_window_cycles(); virtual void update_sprites(); virtual void update_scanline(uint32_t cycles_to_go); dmg_ppu_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, uint32_t vram_size); // device-level overrides virtual void device_start() override; virtual void device_reset() override; virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override; void common_start(); void common_reset(); required_device m_lr35902; address_space *m_program_space; // state variables bitmap_ind16 m_bitmap; uint8_t m_sgb_atf_data[4096]; /* (SGB) Attributes files 4050 bytes, but it's in WRAM, because 4k is transferred */ uint32_t m_sgb_atf; uint16_t m_sgb_pal_data[4096]; uint8_t m_sgb_pal_map[20][18]; uint16_t m_sgb_pal[128]; std::unique_ptr m_sgb_tile_data; uint8_t m_sgb_tile_map[2048]; uint8_t m_sgb_window_mask; int m_window_lines_drawn; static constexpr unsigned NR_GB_VID_REGS = 0x40; uint8_t m_vid_regs[NR_GB_VID_REGS]; uint8_t m_bg_zbuf[160]; uint16_t m_cgb_bpal[32]; /* CGB current background palette table */ uint16_t m_cgb_spal[32]; /* CGB current sprite palette table */ uint16_t m_gb_bpal[4]; /* Background palette */ uint16_t m_gb_spal0[4]; /* Sprite 0 palette */ uint16_t m_gb_spal1[4]; /* Sprite 1 palette */ /* WIP Things used to render current line */ struct { // Background/window data uint8_t tile_cycle; uint8_t tile_count; uint8_t y; uint16_t pattern_address; uint8_t pattern; uint16_t tile_address; uint8_t plane0; uint8_t plane1; uint16_t shift_register; // Sprite data struct { bool enabled; uint8_t x; uint8_t y; uint8_t pattern; uint8_t flags; uint8_t tile_plane_0; uint8_t tile_plane_1; } sprite[10]; uint8_t sprite_delay_cycles; // other internal data bool starting; // Initial fetches when (re)starting the rendering engine. uint8_t sequence_counter; bool drawing; bool start_drawing; uint8_t scrollx_delay; uint8_t scrollx_to_apply; uint8_t pixels_drawn; uint16_t window_compare_position; bool window_active; uint8_t scrollx; // To keep track of when changes to WNDPOSY/WNDPOSX should kick in uint8_t window_start_y[16]; uint8_t window_start_x[16]; int window_start_y_index; // To keep track of when changes to LCDCONT should kick in for window uint8_t window_enable[16]; int window_enable_index; bool window_should_trigger; } m_line; bool m_frame_window_active; int m_current_line; /* Current line */ int m_cmp_line; /* Compare line */ int m_sprCount; /* Number of sprites on current line */ int m_sprite[10]; /* References to sprites to draw on current line */ int m_previous_line; /* Previous line we've drawn in */ int m_start_x; /* Pixel to start drawing from (inclusive) */ int m_end_x; /* Pixel to end drawing (exclusive) */ int m_mode; /* Keep track of internal STAT mode */ int m_state; /* Current state of the video state machine */ int m_sprite_cycles; int m_window_cycles; int m_scrollx_adjust; int m_oam_locked; int m_oam_locked_reading; int m_vram_locked; int m_pal_locked; int m_hdma_enabled; int m_hdma_possible; int m_hdma_cycles_to_start; uint16_t m_hdma_length; struct layer_struct m_layer[2]; emu_timer *m_lcd_timer; int m_oam_dma_start_cycles; int m_oam_dma_cycles_left; uint16_t m_oam_dma_source_address; int m_gbc_mode; uint8_t m_window_x; uint8_t m_window_y; uint8_t m_old_curline; // Interrupt related bool m_stat_mode0_int; bool m_stat_mode1_int; bool m_stat_mode2_int; bool m_stat_lyc_int; bool m_stat_lyc_int_prev; bool m_stat_write_int; bool m_stat_int; std::unique_ptr m_vram; // Pointer to VRAM std::unique_ptr m_oam; // Pointer to OAM memory bool m_oam_dma_processing; uint8_t m_gb_tile_no_mod; uint32_t m_gb_chrgen_offs; // GB Character generator uint32_t m_gb_bgdtab_offs; // GB Background character table uint32_t m_gb_wndtab_offs; // GB Window character table uint32_t m_gbc_chrgen_offs; // CGB Character generator uint32_t m_gbc_bgdtab_offs; // CGB Background character table uint32_t m_gbc_wndtab_offs; // CGB Window character table int m_vram_bank; attotime m_last_updated; uint64_t m_cycles_left; int m_next_state; bool m_updating_state; bool m_enable_experimental_engine; virtual void videoptr_restore(); virtual bool stat_write(uint8_t new_data); void increment_scanline(); void lcd_switch_on(uint8_t new_data); void update_oam_dma_state(uint64_t cycles); void check_stat_irq(); void clear_line_state(); void update_line_state(uint64_t cycles); void check_start_of_window(); private: const uint32_t m_oam_size; const uint32_t m_vram_size; }; class mgb_ppu_device : public dmg_ppu_device { public: template mgb_ppu_device(const machine_config &mconfig, const char *tag, device_t *owner, T &&cpu_tag) : mgb_ppu_device(mconfig, tag, owner, u32(0)) { set_lr35902_tag(std::forward(cpu_tag)); } mgb_ppu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); protected: // device-level overrides virtual void device_start() override; }; class sgb_ppu_device : public dmg_ppu_device { public: template sgb_ppu_device(const machine_config &mconfig, const char *tag, device_t *owner, T &&cpu_tag) : sgb_ppu_device(mconfig, tag, owner, u32(0)) { set_lr35902_tag(std::forward(cpu_tag)); } sgb_ppu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); void sgb_io_write_pal(int offs, uint8_t *data); protected: // device-level overrides virtual void device_start() override; virtual void device_reset() override; virtual void update_sprites() override; virtual void update_scanline(uint32_t cycles_to_go) override; void refresh_border(); void sgb_vram_memcpy(uint8_t *dst, uint8_t start, size_t num_tiles); }; class cgb_ppu_device : public dmg_ppu_device { public: template cgb_ppu_device(const machine_config &mconfig, const char *tag, device_t *owner, T &&cpu_tag) : cgb_ppu_device(mconfig, tag, owner, u32(0)) { set_lr35902_tag(std::forward(cpu_tag)); } cgb_ppu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); virtual DECLARE_READ8_MEMBER(video_r) override; virtual DECLARE_WRITE8_MEMBER(video_w) override; protected: // device-level overrides virtual void device_start() override; virtual void device_reset() override; virtual void update_sprites() override; virtual void update_scanline(uint32_t cycles_to_go) override; virtual void update_state() override; virtual void videoptr_restore() override; virtual bool stat_write(uint8_t new_data) override; void update_hdma_state(uint64_t cycles); void hdma_trans(uint16_t length); void hdma_trans_execute(); }; DECLARE_DEVICE_TYPE(DMG_PPU, dmg_ppu_device) DECLARE_DEVICE_TYPE(MGB_PPU, mgb_ppu_device) DECLARE_DEVICE_TYPE(SGB_PPU, sgb_ppu_device) DECLARE_DEVICE_TYPE(CGB_PPU, cgb_ppu_device) #endif // MAME_VIDEO_GB_LCD_H