/*
 * Copyright (c) 2021-2025 Rupert Carmichael
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#ifndef SMSVDP_H
#define SMSVDP_H

#include "cega_z80.h"

#define SMS_VDP_WIDTH           256
#define SMS_VDP_HEIGHT          192
#define SMS_VDP_HEIGHT_EXT1     224
#define SMS_VDP_HEIGHT_EXT2     240
#define SMS_VDP_SCANLINES       262
#define SMS_VDP_SCANLINES_PAL   313

#define SMS_VDP_QUIRK_SMS1VDP  0x01
#define SMS_VDP_QUIRK_FRINT    0x02
#define SMS_VDP_QUIRK_PHOFFSET 0x04

#define GG_VIEWPORT_WIDTH       160
#define GG_VIEWPORT_HEIGHT      144
#define GG_XOFFSET               48
#define GG_YOFFSET               24
#define GG_YOFFSET_EXT           40

#define SIZE_VRAM 0x4000
#define SIZE_CRAM 0x40

typedef struct _smsvdp_t {
    uint8_t vram[SIZE_VRAM]; // 16K VRAM
    uint8_t cram[SIZE_CRAM]; // 32 byte (SMS) or 64 byte (GG) CRAM
    uint16_t tbl_col; // Address for Colour table
    uint16_t tbl_pgen; // Address for Pattern Generator table
    uint16_t tbl_pname; // Address for Pattern Name table
    uint16_t tbl_sattr; // Address for Sprite Attribute table
    uint16_t tbl_spgen; // Addresss for Sprite Generator table
    uint16_t line; // Line currently being drawn
    uint16_t cyc; // Master Cycle in current scanline
    uint16_t dot; // Dot currently being drawn
    uint16_t addr; // Memory Address - 14 bit address
    uint8_t code; // Code - 2 bits
    uint8_t ctrl[16]; // 16 Control Registers
    uint8_t stat; // Status Register - read only
    uint8_t rdbuf; // Read Buffer
    uint8_t alatch; // Address Latch
    uint8_t clatch; // CRAM Latch - Game Gear only
    uint8_t wlatch; // Write Latch
    uint8_t hscroll; // Horizontal Scroll Latch
    uint8_t hcount; // HCounter Value
    uint8_t lcount; // Line Interrupt Counter
    uint8_t int_fr_pending; // Frame Interrupt Pending
    uint8_t int_ln_pending; // Line Interrupt Pending
    uint8_t paused; // Set if the system is paused, unset if unpaused

    /* All member variables below are unnecessary for saving the state.
    */
    uint32_t *vbuf; // Pointer to the video framebuffer to be drawn on
    uint32_t palette[32]; // Dynamic palette for SMS Video Mode 4
    uint16_t pnmask; // Pattern Name Table mask

    // Line buffers for sprites on a scanline
    uint8_t linebuf_spr[256]; // Palette data
    uint8_t linebuf_col[256]; // Collision data
    uint8_t linebuf_pri[256]; // Background pixels with priority

    // VDP quirks for older VDP revisions and finnicky software
    unsigned quirks;

    // Keep track of whether to render background/sprites, or use backdrop
    unsigned rendering;

    // Number of scanlines to process in the current video mode (Default 262)
    unsigned numscanlines;

    // Number of scanlines to render (Default 192)
    unsigned numrenderlines;

    unsigned ggmode;
} smsvdp_t;

void smsvdp_set_nmi_callback(void (*)(void));
void smsvdp_set_size_callback(void (*)(int, int, int, int));

void smsvdp_init(void);

void smsvdp_set_buffer(uint32_t*);
void smsvdp_set_palette(unsigned);
void smsvdp_set_quirks(unsigned);
void smsvdp_set_region(unsigned);
void smsvdp_set_ggmode(unsigned);

int smsvdp_phaser_triggered(void);
void smsvdp_phaser_coords(int32_t, int32_t);

uint8_t smsvdp_rd_data(void);
uint8_t smsvdp_rd_stat(void);

void smsvdp_wr_hcount(void);
uint8_t smsvdp_rd_hcount(void);
uint8_t smsvdp_rd_vcount(void);

void smsvdp_wr_ctrl(uint8_t);
void smsvdp_wr_data(uint8_t);

void smsvdp_rehash(void);

int smsvdp_exec(void);

smsvdp_t* smsvdp_ctx(void);

#endif
