/***************************************************************************
  
  gb_pcode.h
  
  (c) Benoît Minisini <benoit.minisini@gambas-basic.org>

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2, 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 General Public License for more details.
  
  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
  MA 02110-1301, USA.
  
***************************************************************************/

#ifndef __GB_PCODE_H
#define __GB_PCODE_H

/* If this file is modified, don't forget to update GAMBAS_PCODE_VERSION in acinclude.m4 */

#define C_NOP                            0x0000

#define C_PUSH_QUICK                     0xF000

#define C_PUSH_LOCAL_NOREF               0xF100
#define C_PUSH_PARAM_NOREF               0xF200
#define C_JUMP_IF_TRUE_FAST              0XF300
#define C_JUMP_IF_FALSE_FAST             0XF400
#define C_PUSH_VARIABLE                  0xF500
#define C_POP_VARIABLE                   0xF600
#define C_PUSH_FLOAT                     0xF700
#define C_POKE                           0xF800
#define C_POP_LOCAL_NOREF                0xF900
#define C_POP_PARAM_NOREF                0xFA00
#define C_POP_LOCAL_FAST                 0xFB00
#define C_POP_PARAM_FAST                 0xFC00

#define C_AFTER_EVERY                    0xFD00

#define CAE_LATER 0
#define CAE_AFTER 1
#define CAE_EVERY 2

#define C_JUMP_NEXT_INTEGER              0xFE00

#define C_PUSH_CONST                     0xE000

#define C_POP_STATIC                     0xD800
#define C_POP_DYNAMIC                    0xD000
#define C_PUSH_STATIC                    0xC800
#define C_PUSH_DYNAMIC                   0xC000
#define C_PUSH_FUNCTION                  0xB800
#define C_PUSH_CLASS                     0xB000

#define C_ADD_QUICK                      0xA000

#define C_PUSH_ARRAY_NATIVE_INTEGER      0xA100
#define C_POP_ARRAY_NATIVE_INTEGER       0xA200
#define C_PUSH_ARRAY_NATIVE_FLOAT        0xA300
#define C_POP_ARRAY_NATIVE_FLOAT         0xA400
#define C_ADD_QUICK_INTEGER              0xA500
#define C_ADD_QUICK_FLOAT                0xA600
#define C_ADD_INTEGER                    0xA700
#define C_ADD_FLOAT                      0xA800
#define C_SUB_INTEGER                    0xA900
#define C_SUB_FLOAT                      0xAA00
#define C_MUL_INTEGER                    0xAB00
#define C_MUL_FLOAT                      0xAC00
#define C_DIV_INTEGER                    0xAD00
#define C_DIV_FLOAT                      0xAE00

#define C_PUSH_LOCAL                     0x0100
#define C_PUSH_PARAM                     0x0200
#define C_PUSH_ARRAY                     0x0300
#define C_PUSH_UNKNOWN                   0x0400

#define C_PUSH_EXTERN                    0x0500
#define C_BYREF                          0x0600
#define C_PUSH_EVENT                     0x0700
#define C_QUIT                           0x0800

#define C_POP_LOCAL                      0x0900
#define C_POP_PARAM                      0x0A00
#define C_POP_ARRAY                      0x0B00
#define C_POP_UNKNOWN                    0x0C00

#define C_POP_OPTIONAL                   0x0D00
#define C_POP_CTRL                       0x0E00

#define C_BREAK                          0x0F00

#define C_RETURN                         0x1000

#define C_PUSH_INTEGER                   0x1100
#define C_PUSH_LONG                      0x1200
#define C_PUSH_CHAR                      0x1300
#define C_PUSH_MISC                      0x1400
#define C_PUSH_ME                        0x1500

#define CPM_NULL         0
#define CPM_VOID         1
#define CPM_FALSE        2
#define CPM_TRUE         3
#define CPM_LAST         4
#define CPM_STRING       5
#define CPM_PINF         6
#define CPM_MINF         7
#define CPM_COMPLEX      8
#define CPM_VARGS        9
#define CPM_DROP_VARGS   10
#define CPM_RETURN       11
#define CPM_END_VARGS    12
#define CPM_PI           13

#define C_TRY                            0x1600
#define C_END_TRY                        0x1700
#define C_CATCH                          0x1800

#define C_DUP                            0x1900
#define C_DROP                           0x1A00
#define C_NEW                            0x1B00

#define C_CALL                           0x1C00
#define C_CALL_QUICK                     0x1D00
#define C_CALL_SLOW                      0x1E00
#define C_ON                             0x1F00

#define C_JUMP                           0x2000
#define C_JUMP_IF_TRUE                   0x2100
#define C_JUMP_IF_FALSE                  0x2200
#define C_GOSUB                          0x2300

#define C_JUMP_FIRST                     0x2400
#define C_JUMP_NEXT                      0x2500
#define C_ENUM_FIRST                     0x2600
#define C_ENUM_NEXT                      0x2700

#define C_EQ                             0x2800
#define C_NE                             0x2900
#define C_GT                             0x2A00
#define C_LE                             0x2B00
#define C_LT                             0x2C00
#define C_GE                             0x2D00
#define C_NEAR                           0x2E00
#define C_CASE                           0x2F00

#define C_ADD                            0x3000
#define C_SUB                            0x3100
#define C_MUL                            0x3200
#define C_DIV                            0x3300
#define C_NEG                            0x3400
#define C_QUO                            0x3500
#define C_REM                            0x3600
#define C_POW                            0x3700
#define C_AND                            0x3800
#define C_OR                             0x3900
#define C_XOR                            0x3A00
#define C_NOT                            0x3B00
#define C_CAT                            0x3C00
#define C_LIKE                           0x3D00
#define C_FILE                           0x3E00
#define C_IS                             0x3F00

#define CODE_FIRST_SUBR 0x40
#define CODE_LAST_SUBR  0x9F

#define CODE_CALL_VARIANT   0x80

#define CODE_STATIC    0x0800
#define CODE_FUNCTION  0x0400

#define CODE_NEW_ARRAY  0x40
#define CODE_NEW_EVENT  0x80

#define CODE_OCT         (CODE_FIRST_SUBR + 8)
#define CODE_RINSTR      (CODE_FIRST_SUBR + 12)
#define CODE_ABS         (CODE_FIRST_SUBR + 20)
#define CODE_MAX         (CODE_FIRST_SUBR + 30)
#define CODE_BCLR        (CODE_FIRST_SUBR + 36)
#define CODE_CONV        (CODE_FIRST_SUBR + 39)
#define CODE_BIN         (CODE_FIRST_SUBR + 40)
#define CODE_HEX         (CODE_FIRST_SUBR + 41)
#define CODE_DEBUG       (CODE_FIRST_SUBR + 54)
#define CODE_POKE        (CODE_FIRST_SUBR + 95)
#define CODE_DEC         (CODE_FIRST_SUBR + 189)

#define C_BCLR           (CODE_BCLR << 8)

typedef
  ushort PCODE;

#define PCODE_is(pcode, value)  (((pcode) & 0xFF00) == (value))
#define PCODE_is_xxx(pcode, value)  (((pcode) & 0xF800) == (value))
#define PCODE_get_nparam(pcode) ((pcode) & 0x3F)

#define PCODE_is_variant(pcode)  ((pcode) & CODE_CALL_VARIANT)
#define PCODE_is_void(pcode)    ((pcode) & CODE_CALL_VOID)

#define PCODE_is_breakpoint(pcode) PCODE_is(pcode, C_BREAK)
#define PCODE_is_jump(pcode) PCODE_is(pcode, C_JUMP)

#define PCODE_BREAKPOINT(num) ((PCODE)(C_BREAK | (num)))

#ifndef NO_CODE_DUMP
short PCODE_dump(FILE *out, ushort addr, PCODE *code);
void PCODE_dump_count(FILE *out);
#endif

#endif /* */
