/*
 * dsp56300 emulator C API (auto-generated by cbindgen)
 *
 * SPDX-License-Identifier: MIT
 */

#ifndef DSP56300_H
#define DSP56300_H

#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>

/**
 * Region kind tag for C FFI.
 */
enum Dsp56300Region
#if __STDC_VERSION__ >= 202311L
  : uint32_t
#endif // __STDC_VERSION__ >= 202311L
 {
  DSP56300_REGION_BUFFER = 0,
  DSP56300_REGION_CALLBACK = 1,
};
#if __STDC_VERSION__ >= 202311L
typedef enum Dsp56300Region Dsp56300Region;
#else
typedef uint32_t Dsp56300Region;
#endif // __STDC_VERSION__ >= 202311L

/**
 * FFI-safe memory space enum.
 */
enum Dsp56300MemSpace
#if __STDC_VERSION__ >= 202311L
  : uint32_t
#endif // __STDC_VERSION__ >= 202311L
 {
  DSP56300_MEM_SPACE_X = 0,
  DSP56300_MEM_SPACE_Y = 1,
  DSP56300_MEM_SPACE_P = 2,
};
#if __STDC_VERSION__ >= 202311L
typedef enum Dsp56300MemSpace Dsp56300MemSpace;
#else
typedef uint32_t Dsp56300MemSpace;
#endif // __STDC_VERSION__ >= 202311L

/**
 * Register file indices (6-bit DDDDDD encoding per DSP56300 instruction set).
 */
enum Dsp56300Reg
#if __STDC_VERSION__ >= 202311L
  : uint32_t
#endif // __STDC_VERSION__ >= 202311L
 {
  DSP56300_REG_X0 = 4,
  DSP56300_REG_X1 = 5,
  DSP56300_REG_Y0 = 6,
  DSP56300_REG_Y1 = 7,
  DSP56300_REG_A0 = 8,
  DSP56300_REG_B0 = 9,
  DSP56300_REG_A2 = 10,
  DSP56300_REG_B2 = 11,
  DSP56300_REG_A1 = 12,
  DSP56300_REG_B1 = 13,
  DSP56300_REG_R0 = 16,
  DSP56300_REG_R1 = 17,
  DSP56300_REG_R2 = 18,
  DSP56300_REG_R3 = 19,
  DSP56300_REG_R4 = 20,
  DSP56300_REG_R5 = 21,
  DSP56300_REG_R6 = 22,
  DSP56300_REG_R7 = 23,
  DSP56300_REG_N0 = 24,
  DSP56300_REG_N1 = 25,
  DSP56300_REG_N2 = 26,
  DSP56300_REG_N3 = 27,
  DSP56300_REG_N4 = 28,
  DSP56300_REG_N5 = 29,
  DSP56300_REG_N6 = 30,
  DSP56300_REG_N7 = 31,
  DSP56300_REG_M0 = 32,
  DSP56300_REG_M1 = 33,
  DSP56300_REG_M2 = 34,
  DSP56300_REG_M3 = 35,
  DSP56300_REG_M4 = 36,
  DSP56300_REG_M5 = 37,
  DSP56300_REG_M6 = 38,
  DSP56300_REG_M7 = 39,
  DSP56300_REG_EP = 42,
  DSP56300_REG_VBA = 48,
  DSP56300_REG_SC = 49,
  DSP56300_REG_SZ = 56,
  DSP56300_REG_SR = 57,
  DSP56300_REG_OMR = 58,
  DSP56300_REG_SP = 59,
  DSP56300_REG_SSH = 60,
  DSP56300_REG_SSL = 61,
  DSP56300_REG_LA = 62,
  DSP56300_REG_LC = 63,
  DSP56300_REG_COUNT = 64,
};
#if __STDC_VERSION__ >= 202311L
typedef enum Dsp56300Reg Dsp56300Reg;
#else
typedef uint32_t Dsp56300Reg;
#endif // __STDC_VERSION__ >= 202311L

/**
 * Opaque handle to a DSP instance with JIT engine.
 */
typedef struct Dsp56300Jit Dsp56300Jit;

/**
 * Buffer variant data for C FFI.
 */
typedef struct {
  uint32_t *base;
  uint32_t offset;
} Dsp56300BufferRegion;

/**
 * Callback variant data for C FFI.
 */
typedef struct {
  void *opaque;
  uint32_t (*read)(void*, uint32_t);
  void (*write)(void*, uint32_t, uint32_t);
} Dsp56300CallbackRegion;

/**
 * Union payload for CMemoryRegion.
 */
typedef union {
  Dsp56300BufferRegion buffer;
  Dsp56300CallbackRegion callback;
} Dsp56300RegionData;

/**
 * A single memory region descriptor (C FFI).
 *
 * Tagged union: check `kind` to determine which union field is valid.
 */
typedef struct {
  uint32_t start;
  uint32_t end;
  Dsp56300Region kind;
  Dsp56300RegionData data;
} Dsp56300MemoryRegion;

/**
 * Memory region configuration for X, Y, and P address spaces (C FFI).
 */
typedef struct {
  const Dsp56300MemoryRegion *x_regions;
  uint32_t x_count;
  const Dsp56300MemoryRegion *y_regions;
  uint32_t y_count;
  const Dsp56300MemoryRegion *p_regions;
  uint32_t p_count;
} Dsp56300MemoryMap;

/**
 * Initialization parameters for `dsp56300_create` (C FFI).
 */
typedef struct {
  Dsp56300MemoryMap memory_map;
} Dsp56300CreateInfo;

/**
 * Interrupt pipeline state for save/restore.
 */
typedef struct {
  uint64_t pending_bits[2];
  uint8_t pipeline_stage;
  uint32_t vector_addr;
  uint32_t saved_pc;
  uint8_t state;
  int8_t ipl[128];
  uint8_t ipl_to_raise;
} Dsp56300InterruptState;

/**
 * Bulk state for save/restore, including registers and stack.
 */
typedef struct {
  uint32_t pc;
  uint32_t pc_advance;
  bool pc_on_rep;
  uint32_t cycle_count;
  int32_t cycle_budget;
  Dsp56300InterruptState interrupts;
  bool loop_rep;
  bool halt_requested;
  uint8_t power_state;
  uint32_t registers[64];
  uint32_t stack[2][16];
} Dsp56300State;

/**
 * Create a new DSP JIT instance.
 *
 * The `info` parameter provides the memory map and callback configuration.
 * Buffer pointers in the map must remain valid for the lifetime of the
 * returned `DspJit`.
 *
 * # Safety
 * All buffer and callback pointers in `info` must be valid.
 */
Dsp56300Jit *dsp56300_create(const Dsp56300CreateInfo *info);

/**
 * Destroy a DSP JIT instance.
 *
 * # Safety
 * `dsp` must be a valid pointer returned by `dsp56300_create`.
 */
void dsp56300_destroy(Dsp56300Jit *dsp);

/**
 * Dump block execution profile to `path`. Enables profiling on first call.
 *
 * # Safety
 * `dsp` must be a valid pointer to a `DspJit`.
 * `path` must be a valid null-terminated C string.
 */
void dsp56300_dump_profile(Dsp56300Jit *dsp, const char *path);

/**
 * Enable perf map output for `perf record` profiling.
 *
 * # Safety
 * `dsp` must be a valid pointer to a `DspJit`.
 */
void dsp56300_enable_perf_map(Dsp56300Jit *dsp);

/**
 * Reset the DSP to its initial state, preserving memory map and callbacks.
 *
 * # Safety
 * `dsp` must be a valid pointer to a `DspJit`.
 */
void dsp56300_reset(Dsp56300Jit *dsp);

/**
 * Execute a single instruction.
 *
 * # Safety
 * `dsp` must be a valid pointer to a `DspJit`.
 */
void dsp56300_step(Dsp56300Jit *dsp);

/**
 * Run for the given number of cycles.
 *
 * # Safety
 * `dsp` must be a valid pointer to a `DspJit`.
 */
void dsp56300_run(Dsp56300Jit *dsp, int32_t cycles);

/**
 * Check if a halt has been requested.
 *
 * # Safety
 * `dsp` must be a valid pointer to a `DspJit`.
 */
bool dsp56300_halt_requested(const Dsp56300Jit *dsp);

/**
 * Request (or clear) a halt. When `halt` is true, also sets
 * `exit_requested` so the currently executing block returns to the
 * run loop.
 *
 * # Safety
 * `dsp` must be a valid pointer to a `DspJit`.
 */
void dsp56300_set_halt_requested(Dsp56300Jit *dsp, bool halt);

/**
 * Get the current cycle count.
 *
 * # Safety
 * `dsp` must be a valid pointer to a `DspJit`.
 */
uint32_t dsp56300_cycle_count(const Dsp56300Jit *dsp);

/**
 * Set the cycle count.
 *
 * # Safety
 * `dsp` must be a valid pointer to a `DspJit`.
 */
void dsp56300_set_cycle_count(Dsp56300Jit *dsp, uint32_t count);

/**
 * Invalidate the JIT block cache. Call when P-memory is modified externally.
 *
 * # Safety
 * `dsp` must be a valid pointer to a `DspJit`.
 */
void dsp56300_invalidate_cache(Dsp56300Jit *dsp);

/**
 * Read a word from DSP memory.
 *
 * # Safety
 * `dsp` must be a valid pointer to a `DspJit`.
 */
uint32_t dsp56300_read_memory(const Dsp56300Jit *dsp, Dsp56300MemSpace space, uint32_t addr);

/**
 * Write a word to DSP memory.
 *
 * If writing to P-space, automatically marks the dirty bitmap for JIT
 * cache invalidation. Also logs writes for shadow comparison mode.
 *
 * # Safety
 * `dsp` must be a valid pointer to a `DspJit`.
 */
void dsp56300_write_memory(Dsp56300Jit *dsp, Dsp56300MemSpace space, uint32_t addr, uint32_t value);

/**
 * Copy all scalar sync state from the JIT into `out`.
 *
 * # Safety
 * `dsp` and `out` must be valid non-null pointers.
 */
void dsp56300_get_state(const Dsp56300Jit *dsp, Dsp56300State *out);

/**
 * Apply all scalar sync state from `src` into the JIT.
 *
 * # Safety
 * `dsp` and `src` must be valid non-null pointers.
 */
void dsp56300_set_state(Dsp56300Jit *dsp, const Dsp56300State *src);

#endif  /* DSP56300_H */
