/*
 * Equi platform reference implementation
 *
 * Created in 2022 by Luxferre, released into public domain
 *
 * See equi.md file for the specification and manual
 *
 * @license Unlicense <https://unlicense.org>
 * @author Luxferre
 */

/* Standard includes with size optimizations for TCC */

#ifdef __TINYC__
#include <tcclib.h>
#else
#include <stdlib.h>
#include <stdio.h>
#endif

/*
 * Non-standard includes
 * To save space, we emulate necessary conio functions on non-6502 systems, not vice versa
 */

#ifdef __CC65__
#include <conio.h>
#else

#define cgetc() (fgetc(stdin))
#define cputc(c) (fputc(c, stdout))

#endif

/* Definitions section */

#define EQUI_VER "0.0.1"

#define ushort unsigned short /* basic 16-bit integer */
#define uchar unsigned char /* basic 8-bit integer */
#define WS sizeof(ushort) /* Equi word size in bytes */
#define CLT_ENTRY_LEN 6u /* Amount of significant compiled word characters */
#define CLT_ENTRY_SIZE (CLT_ENTRY_LEN + WS) /* Full size in bytes taken by one CLT entry */
#define BS 8u /* Backspace character code */

/* Configuration section (constants overridable at compile-time) */

/* Main and return stack size in bytes */
#ifndef STACK_SIZE
#define STACK_SIZE 256u
#endif

/* Literal stack size in bytes */
#ifndef LIT_STACK_SIZE
#define LIT_STACK_SIZE 32u
#endif

/* Command buffer size in bytes */
#ifndef GPD_AREA_SIZE
#define GPD_AREA_SIZE 6400u
#endif

/* Command buffer size in bytes */
#ifndef CMD_BUF_SIZE
#define CMD_BUF_SIZE 15600u
#endif

/* Maximum amount of CLT entries */
#ifndef CLT_ENTRIES_MAX
#define CLT_ENTRIES_MAX 512u
#endif

/* Some necessary constants and offsets derived from the above values */
#define STACK_SIZE_WORDS (STACK_SIZE / WS) /* Main and return stack size in words */

/*
 * Structures that describe Equi machine RAM using the above configuration
 */

struct CLTEntry {
  uchar name[CLT_ENTRY_LEN]; /* compiled word name */
  ushort loc;    /* compiled word location */
};

struct EquiRAM { 
  ushort main_stack[STACK_SIZE_WORDS];
  ushort return_stack[STACK_SIZE_WORDS];
  uchar literal_stack[LIT_STACK_SIZE];
  ushort pc; /* program counter */
  ushort msp; /* main stack pointer */
  ushort rsp; /* return stack pointer */
  uchar lsp; /* literal stack pointer */
  ushort cbp; /* compilation buffer pointer */
  ushort cltp; /* compilation lookup table pointer */
  unsigned int II:1; /* instruction ignore mode */
  unsigned int CM:1; /* compilation mode */
  unsigned int IM:1; /* interpretation mode */
  ushort gpd_start;
  ushort cmd_start;
  ushort cmd_size;
  ushort ibp; /* input buffer pointer */
  struct CLTEntry clt[CLT_ENTRIES_MAX]; /* compilation lookup table */
  uchar gpd[GPD_AREA_SIZE];
  uchar cmdbuf[CMD_BUF_SIZE];
};

/* Before running the main code, instantiate the machine RAM */
static struct EquiRAM ram;

/* Also create an alternative view of the same RAM area for direct offset-based access */
static uchar* flatram = (uchar *)&ram;

int main(int argc, char* argv[]) {
  /* initialize the RAM in the most standard way */
  ram.gpd_start = (uchar *)&ram.gpd - (uchar *)&ram.main_stack;
  ram.cmd_start = (uchar *)&ram.cmdbuf - (uchar *)&ram.main_stack;
  ram.cmd_size = CMD_BUF_SIZE;
  ram.pc = ram.cmd_start; /* Start execution from the start of command buffer */
  ram.ibp = ram.cmd_start; /* Start input buffering from the start of command buffer */

  printf("Welcome to Equi v" EQUI_VER " by Luxferre, 2022\n\nCLT: 0x%X (%d bytes)\nGPD: 0x%X (%d bytes)\nCommand buffer: 0x%X (%d bytes)\nEqui ready\n\n",
      (uchar *)&ram.clt - (uchar *)&ram.main_stack,
      (uchar *)&ram.gpd - (uchar *)&ram.clt,
      ram.gpd_start,
      ram.cmd_start - ram.gpd_start,
      ram.cmd_start, ram.cmd_size);

  cputc('>');
  cgetc();


  return 0;
}
