/*
 * wnix, a Unix-like operating system for WebAssembly applications.
 * Copyright (C) 2025  Xavier Del Campo Romero
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

#ifndef DRV_PS1_GPU_H
#define DRV_PS1_GPU_H

#include <stdint.h>

enum
{
    GP0_FILL_VRAM = 0x02,
    GP0_TEXTRECT_VARSZ_OPAQ_RAW = 0x65,
    GP0_COPY_RECT_CPU_VRAM = 0xa0,
    GP0_COPY_RECT_VRAM_CPU = 0xc0,
    GP0_DRAW_MODE = 0xe1,
    GP0_TEX_WINDOW,
    GP0_DRAW_AREA_TOP_LEFT,
    GP0_DRAW_AREA_BOTTOM_RIGHT,
    GP0_DRAW_OFFSET,
    GP0_DRAW_MASK_BIT
};

enum
{
    GP1_RESET_GPU,
    GP1_RESET_CMDBUF,
    GP1_ACK_IRQ,
    GP1_DISPLAY_ENABLE,
    GP1_DMA_DIR,
    GP1_START_DISPLAY_AREA,
    GP1_H_DISPLAY_RANGE,
    GP1_V_DISPLAY_RANGE,
    GP1_DISPLAY_MODE
};

enum
{
    GP1_DMA_DIR_OFF,
    GP1_DMA_DIR_FIFO,
    GP1_DMA_DIR_CPU_TO_GP0,
    GP1_DMA_DIR_GPUREAD_TO_CPU
};

union drv_ps1_gpu_gp0
{
    uint32_t mask;

    struct
    {
        uint32_t w :16, h :16, x :16, y :16, r :8, g :8, b :8, cmd :8;
    } fill_vram;

    struct
    {
        uint32_t :24, cmd :8;
    } copy_rect;

    struct
    {
        uint16_t x, y;
    } coord;

    struct
    {
        uint16_t w, h;
    } size;

    struct
    {
        uint32_t page_x :4, page_y :1, stp :2, bpp :2, dither :1,
            draw_to_display :1, tex_disable :1, xflip :1, yflip :1, :10,
            cmd :8;
    } draw_mode;

    struct
    {
        uint32_t mask_x :5, mask_y :5, off_x :5, off_y :5, :4, cmd :8;
    } tex_window;

    struct
    {
        uint32_t x :10, y :9, :5, cmd :8;
    } draw_area_tl, draw_area_br;

    struct
    {
        int32_t x :11, y :11, :2, cmd :8;
    } offset;

    struct
    {
        uint32_t set :1, check :1, :22, cmd :8;
    } mask_bit;
};

union drv_ps1_gpu_gp1
{
    uint32_t mask;

    struct
    {
        uint32_t :24, cmd:8;
    } reset_gpu, reset_cmdbuf, ack_irq;

    struct
    {
        uint32_t disable :1, :23, cmd :8;
    } display;

    struct
    {
        uint32_t dir :2, :22, cmd :8;
    } dma;

    struct
    {
        uint32_t x :10, y :9, :5, cmd :8;
    } disparea;

    struct
    {
        uint32_t x1 :12, x2 :12, cmd :8;
    } h_display_range;

    struct
    {
        uint32_t y1 :10, y2 :10, :4, cmd :8;
    } v_display_range;

    struct
    {
        uint32_t hres :2, vres :1, vmode :1, coldepth :1, vinterlace :1,
            hres2 :1, reverse :1, :16, cmd :8;
    } display_mode;
};

union drv_ps1_gpu_stat
{
    struct
    {
        uint32_t x_base :4, y_base :1, stp :2, bpp :2, dither :1,
            draw_to_display :1, set_mask :1, draw_pix :1, interlace :1,
            reverse :1, disable :1, xres2 :1, xres1 :2, yres :1, vmode :1,
            coldepth :1, vinterlace :1, display_enable :1, irq_req :1,
            dma_req :1, ready_cmd :1, ready_send :1, ready_dma :1, dma_dir :2,
            draw_odd :1;
    } bits;

    uint32_t mask;
};

#define GPU_BASE 0x1f801810
#define GPU_REG(x) (GPU_BASE + (x))
#define GP0 ((volatile union drv_ps1_gpu_gp0 *)GPU_REG(0))
#define GP1 ((volatile union drv_ps1_gpu_gp1 *)GPU_REG(4))
#define GPUSTAT ((volatile const union drv_ps1_gpu_stat *)GPU_REG(4))

#endif
