/*
 * 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 PS1_BIOS_H
#define PS1_BIOS_H

#include <stdint.h>
#include <setjmp.h>

#if __GNUC__
#define PRINTF_ATTR __attribute__ ((format (__printf__, 1, 2)))
#else
#define PRINTF_ATTR
#endif

enum
{
    CLASS_IRQ0 = (long)0xf0000001,
    CLASS_GPU,
    CLASS_CDROM,
    CLASS_DMA,
    CLASS_RTC0  = (long)0xf2000000,
    CLASS_RTC1,
    CLASS_RTC2,
    CLASS_VBLANK,
    CLASS_CONTROLLER = (long)0xf0000008,
    CLASS_SPU,
    CLASS_PIO,
    CLASS_SIO
};

enum
{
    MODE_EXECUTE = 0x1000,
    MODE_READY = 0x2000
};

enum
{
    SPEC_COUNTER_ZERO = 1,
    SPEC_INTERRUPTED = 1 << 1,
    SPEC_EOF = 1 << 2,
    SPEC_FILE_CLOSED = 1 << 3,
    SPEC_COMMAND_ACK = 1 << 4,
    SPEC_COMMAND_COMPLETE = 1 << 5,
    SPEC_DATA_READY = 1 << 6,
    SPEC_DATA_END = 1 << 7,
    SPEC_TIMEOUT = 1 << 8,
    SPEC_UNKNOWN_CMD = 1 << 9,
    SPEC_END_READ_BUF = 1 << 10,
    SPEC_END_WRITE_BUF = 1 << 11,
    SPEC_GENERAL_INTERRUPT = 1 << 12,
    SPEC_NEW_DEVICE = 1 << 13,
    SPEC_SYSCALL = 1 << 14,
    SPEC_ERROR = 1 << 15,
    SPEC_WRITE_ERROR,
    SPEC_DOMAIN_ERROR = 0x301,
    SPEC_RANGE_RNG
};

struct CdAsyncSeekL
{
    uint8_t minutes, seconds, frames;
};

union SetMode
{
    struct
    {
        uint8_t cdda :1, autopause :1, report :1, xa_filter :1, ignore :1,
            whole_sector :1, xa_adpcm :1, speed :1;
    } bits;

    uint8_t mask;
};

struct CdAsyncReadSector_mode
{
    union SetMode mode;
    union
    {
        struct
        {
            uint8_t reads :1, :7;
        } bits;
    } read;

    uint16_t reserved;
};

int EnterCriticalSection(void);
void ExitCriticalSection(void);
void GetConf(uint32_t *events, uint32_t *tcb, void **stacktop);
void SetConf(uint32_t events, uint32_t tcb, void *stacktop);
int OpenEvent(int class, int spec, int mode, int (*f)(void));
int EnableEvent(int event);
int DisableEvent(int event);
int CloseEvent(int event);
int TestEvent(int event);
int WaitEvent(int event);
int CdAsyncGetStatus(uint8_t *response);
int CdAsyncReadSector(unsigned count, void *dst,
    struct CdAsyncReadSector_mode mode);
int CdAsyncSeekL(const struct CdAsyncSeekL *seekl);
int Printf(const char *fmt, ...) PRINTF_ATTR;
void SetCustomExitFromException(jmp_buf jmp);
void CdInit(void);
void CdRemove(void);
int SaveState(jmp_buf buf);
void RestoreState(jmp_buf buf, int value);
void ReturnFromException(void);

#endif
