/*
Copyright Notice
================
BOCHS is Copyright 1994 by Kevin P. Lawton.

BOCHS is shareware for PERSONAL USE only.

For more information, read the file 'LICENSE' included in the bochs
distribution.  If you don't have access to this file, or have questions
regarding the licensing policy, the author may be contacted via:

    US Mail:  Kevin Lawton
              528 Lexington St.
              Waltham, MA 02154

    EMail:    bochs@tiac.net
*/




#ifndef BX_BOCHS_H
#  define BX_BOCHS_H 1

#include <stdarg.h>
#include <stdio.h>

#include "config.h"


#define BX_PHY_MEMSIZE 0x10000


typedef unsigned char  Boolean;


/* maximum number of emulated devices allowed.  floppy, mda, etc...
   you can increase this to anything below 256 since an 8-bit handle
   is used for each device */
#define BX_MAX_IO_DEVICES 20

/* number of IRQ lines supported.  In an ISA PC there are two
   PIC chips cascaded together.  each has 8 IRQ lines, so there
   should be 16 IRQ's total */
#define BX_MAX_IRQS 16



#define BX_NO_IRQ  -1
#define BX_NO_FD   -1

#define BX_FD_EVENT_READ       1
#define BX_FD_EVENT_WRITE      2
#define BX_FD_EVENT_EXCEPTION  4




typedef struct {
  Bit8u   (* read_funct)(Bit32u addr);
  void    (* write_funct)(Bit32u addr, Bit8u value);
  char    *handler_name;
  Bit32u  start_addr;
  Bit32u  end_addr;
  int     irq;
  } bx_iodev_t;

typedef struct {
  Bit32u  start_addr;
  Bit32u  end_addr;
  char *  handler_name;
  Bit8u   (* read_funct)(Bit32u addr);
  void    (* write_funct)(Bit32u addr, Bit8u value);
  } bx_memdev_t;

typedef struct {
  Bit32u  period;
  Bit32u  remaining;
  Boolean active;
  void (* funct) (void);
  } bx_timer_t;

#define BX_MAX_TIMERS 10

#define BX_MAX_REGISTERED_FDS  20

typedef struct {
  Bit8u *mem;
  Bit8u flags;
  Bit8u (* read_funct) (Bit32u addr);
  void  (* write_funct) (Bit32u addr, Bit8u value);
  } bx_phy_mem_page_t;


#define bx_fetch_next_byte1(b) {\
  Bit32u addr; \
  addr = (bx_cpu.cs.selector.value << 4) + bx_cpu.eip++; \
  b = *((Bit8u *) &bx_phy_mem_pages[addr / BX_PAGE_SIZE].mem[addr % BX_PAGE_SIZE]); \
  }

#define bx_fetch_next_word1(w) {\
  w = bx_fetch_next_word();\
  }

#define bx_fetch_next_dword1(dw) {\
  dw = bx_fetch_next_dword();\
  }

#if 0
#define bx_fetch_next_word1(b) {\
  Bit32u addr; \
  addr = (bx_cpu.cs.selector.value << 4) + bx_cpu.eip; \
  bx_cpu.eip += 2; \
  b = *((Bit16u *) &bx_phy_mem_pages[addr / BX_PAGE_SIZE].mem[addr % BX_PAGE_SIZE]); \
  }


#define bx_fetch_next_dword1(b) {\
  Bit32u addr; \
  addr = (bx_cpu.cs.selector.value << 4) + bx_cpu.eip; \
  bx_cpu.eip += 4; \
  b = *((Bit32u *) &bx_phy_mem_pages[addr / BX_PAGE_SIZE].mem[addr % BX_PAGE_SIZE]); \
  }
#endif



void bx_register_io_handlers(void);
int  bx_register_io_handler( bx_iodev_t );
int  bx_register_mem_handler( bx_memdev_t );
void bx_register_int_vector(Bit8u interrupt, Bit8u* code, int code_size,
  void (* funct)(int vector));
int  bx_register_timer( void (*funct)(void), Bit32u useconds);

void bx_iodev_setup(void);
void bx_add_input(int fd, int event_type, void (* funct)(void));


/* --- DEFINES --- */

#define BX_PAGE_SIZE               0x1000  /* 4 Kbyte pages */
#define BX_NUM_PAGES               0x100   /* 256 pages */
                                           /* 4K * 256 = 1M */

/* segment register encoding */
#define BX_SEG_REG_ES    0
#define BX_SEG_REG_CS    1
#define BX_SEG_REG_SS    2
#define BX_SEG_REG_DS    3
#define BX_SEG_REG_FS    4
#define BX_SEG_REG_GS    5



#ifdef LITTLE_ENDIAN
#define BX_REG8L_OFFSET 0
#define BX_REG8H_OFFSET 1
#define BX_REG16_OFFSET 0
#else /* BIG_ENDIAN */
#define BX_REG8L_OFFSET 3
#define BX_REG8H_OFFSET 2
#define BX_REG16_OFFSET 2
#endif /* ifdef LITTLE_ENDIAN */

#define BX_REGISTER_REF 10
#define BX_MEMORY_REF   11

#define BX_8BIT_REG_AL  0
#define BX_8BIT_REG_CL  1
#define BX_8BIT_REG_DL  2
#define BX_8BIT_REG_BL  3
#define BX_8BIT_REG_AH  4
#define BX_8BIT_REG_CH  5
#define BX_8BIT_REG_DH  6
#define BX_8BIT_REG_BH  7

#define BX_16BIT_REG_AX 0
#define BX_16BIT_REG_CX 1
#define BX_16BIT_REG_DX 2
#define BX_16BIT_REG_BX 3
#define BX_16BIT_REG_SP 4
#define BX_16BIT_REG_BP 5
#define BX_16BIT_REG_SI 6
#define BX_16BIT_REG_DI 7

#define BX_32BIT_REG_EAX 0
#define BX_32BIT_REG_ECX 1
#define BX_32BIT_REG_EDX 2
#define BX_32BIT_REG_EBX 3
#define BX_32BIT_REG_ESP 4
#define BX_32BIT_REG_EBP 5
#define BX_32BIT_REG_ESI 6
#define BX_32BIT_REG_EDI 7

#define AL *bx_8bit_gen_reg[BX_8BIT_REG_AL]
#define AH *bx_8bit_gen_reg[BX_8BIT_REG_AH]
#define BL *bx_8bit_gen_reg[BX_8BIT_REG_BL]
#define BH *bx_8bit_gen_reg[BX_8BIT_REG_BH]
#define CL *bx_8bit_gen_reg[BX_8BIT_REG_CL]
#define CH *bx_8bit_gen_reg[BX_8BIT_REG_CH]
#define DL *bx_8bit_gen_reg[BX_8BIT_REG_DL]
#define DH *bx_8bit_gen_reg[BX_8BIT_REG_DH]

#define AX *bx_16bit_gen_reg[BX_16BIT_REG_AX]
#define BX *bx_16bit_gen_reg[BX_16BIT_REG_BX]
#define CX *bx_16bit_gen_reg[BX_16BIT_REG_CX]
#define DX *bx_16bit_gen_reg[BX_16BIT_REG_DX]
#define SP *bx_16bit_gen_reg[BX_16BIT_REG_SP]
#define BP *bx_16bit_gen_reg[BX_16BIT_REG_BP]
#define SI *bx_16bit_gen_reg[BX_16BIT_REG_SI]
#define DI *bx_16bit_gen_reg[BX_16BIT_REG_DI]
#define IP *((Bit16u *) (((Bit8u *) &bx_cpu.eip) + BX_REG16_OFFSET))


#define EAX *bx_32bit_gen_reg[BX_32BIT_REG_EAX]
#define ECX *bx_32bit_gen_reg[BX_32BIT_REG_ECX]
#define EDX *bx_32bit_gen_reg[BX_32BIT_REG_EDX]
#define EBX *bx_32bit_gen_reg[BX_32BIT_REG_EBX]
#define ESP *bx_32bit_gen_reg[BX_32BIT_REG_ESP]
#define EBP *bx_32bit_gen_reg[BX_32BIT_REG_EBP]
#define ESI *bx_32bit_gen_reg[BX_32BIT_REG_ESI]
#define EDI *bx_32bit_gen_reg[BX_32BIT_REG_EDI]

/* #define BX_READ_8BIT_REG1(index) *bx_8bit_gen_reg[index] */

#define BX_READ_8BIT_REG(var, index) {\
  var = *bx_8bit_gen_reg[index];\
  }
#define BX_READ_16BIT_REG(var, index) {\
  var = *bx_16bit_gen_reg[index];\
  }
#define BX_READ_32BIT_REG(var, index) {\
  var = *bx_32bit_gen_reg[index];\
  }

#define BX_READ_16BIT_BASE_REG(var, index) {\
  var = *bx_16bit_base_reg[index];\
  }

#define BX_READ_16BIT_INDEX_REG(var, index) {\
  var = *bx_16bit_index_reg[index];\
  }

#define BX_WRITE_8BIT_REG(index, val) {\
  *bx_8bit_gen_reg[index] = val; \
  }
#define BX_WRITE_16BIT_REG(index, val) {\
  *bx_16bit_gen_reg[index] = val; \
  }
#define BX_WRITE_32BIT_REG(index, val) {\
  *bx_32bit_gen_reg[index] = val; \
  }

/* convert an unsigned byte to a signed one */
#define BX_U_TO_S_BYTE(ubyte) ((Bit8s) ubyte)

/* convert an unsigned dword to a signed dword */
#define BX_U_TO_S_32BIT(udword) ((Bit32s) udword)

#define BX_ES 10
#define BX_CS 11
#define BX_SS 12
#define BX_DS 13
#define BX_FS 14
#define BX_GS 15




#define BX_DECODE_MODRM(mod_rm_byte, mod, reg, rm) \
  {\
  mod = mod_rm_byte >> 6; \
  reg = (mod_rm_byte >> 3) & 0x07; \
  rm  = mod_rm_byte & 0x07; \
  /*fprintf(stderr, "  [modrm=%d, mod=%d, reg=%d, rm=%d] ", \
    mod_rm_byte, mod, reg, rm);*/ \
  assert(mod<4 && reg<8 && rm<8); \
  }


#define BX_OVERFLOW_FLAG   0x0800
#define BX_SIGN_FLAG       0x0080
#define BX_ZERO_FLAG       0x0040
#define BX_ADJUST_FLAG     0x0010
#define BX_PARITY_FLAG     0x0004
#define BX_CARRY_FLAG      0x0001

/* define bitwise masks for each of the flags in the EFLAGS register */
#define BX_EFLAG_CF  0x00000001
#define BX_EFLAG_PF  0x00000004
#define BX_EFLAG_AF  0x00000010
#define BX_EFLAG_ZF  0x00000040
#define BX_EFLAG_SF  0x00000080
#define BX_EFLAG_TF  0x00000100
#define BX_EFLAG_IF  0x00000200
#define BX_EFLAG_DF  0x00000400
#define BX_EFLAG_OF  0x00000800


#define BX_SS_EXCEPTION  12
#define BX_GP_EXCEPTION  13


#define BX_READ    1
#define BX_WRITE   2

/* --- TYPEDEFS --- */

typedef struct {
  Boolean cf;
  Boolean pf;
  Boolean af;
  Boolean zf;
  Boolean sf;
  Boolean tf;
  Boolean if_;
  Boolean df;
  Boolean of;
  Bit8u   iopl;
  Boolean nt;
  Boolean rf;
  Boolean vm;
  Boolean ac;
  } bx_flags_reg_t;


typedef struct {
  Boolean pg; /* paging */
  Boolean cd; /* cache disable */
  Boolean nw; /* no write-through */
  Boolean am; /* alignment mask */
  Boolean wp; /* write-protect */
  Boolean ne; /* numerics exception */
  Boolean et; /* extension type */
  Boolean ts; /* task switched */
  Boolean em; /* emulate math coprocessor */
  Boolean mp; /* monitor coprocessor */
  Boolean pe; /* protected mode enable */
  } bx_cr0_t;


typedef struct { /* bx_selector_t */
  Bit16u value;   /* the 16bit value of the selector */
    /* the following fields are extracted from the value field in virtual
       mode only.  They're used for sake of efficiency */
  Bit16u index;   /* 13bit index extracted from value in virtual mode */
  Bit8u  ti;      /* table indicator bit extracted from value */
  Bit8u  rpl;     /* RPL extracted from value */
  } bx_selector_t;

  /* the x86 maintains a descriptor cache for each segment register.  Upon
     loading a segment register, fields from the descriptor it selects are
     cached in the corresponding descriptor cache.  the descriptor cache
     structure is not available by applications, it is maintained soley
     by the CPU
   */
typedef struct { /* bx_segment_attributes_t */
  Bit8u   dwordcount; /* parameter count for call gates only */
  Boolean d;         /* default size, 0=16bit ops & addrs, 1=32bit */
  Boolean p;         /* present bit */
  Bit8u   dpl;       /* descriptor privilege level */
  Boolean dtype;     /* descriptor type, 0=system, 1=application */
  Bit8u   type;      /* segment type, 3bit
                        0 = read-only data segment
                        1 = read-write data segment
                        2 = read-only expand down data segment
			3 = read-write expand down data segment
			4 = execute-only code segment
			5 = execute-readable code segment
			6 = execute-only conforming code segment
			7 = execute-readable conforming code segment
                      */
  Boolean g;         /* limit granularity. 0=byte, 1=4K */
  } bx_segment_attr_t;


/* for simplicity, I use one typedef for the GDTR, IDTR, LDTR, TR,
   & segment registers.  GDTR & IDTR do not use the selector field.
 */

typedef struct {
  bx_selector_t      selector;
  Bit32u             base;      /* base address, 32bit */
  Bit32u             limit;     /* limit, 16bit or 20bit */
  bx_segment_attr_t  attributes; /* shadow register attributes */
  } bx_segment_reg_t;


typedef struct {
  /* general register set */
  Bit32u eax; /* accumulator */
  Bit32u ebx; /* base */
  Bit32u ecx; /* count */
  Bit32u edx; /* data */
  Bit32u ebp; /* base pointer */
  Bit32u esi; /* source index */
  Bit32u edi; /* destination index */
  Bit32u esp; /* stack pointer */

  /* status and control flags register set */
  bx_flags_reg_t eflags; /* status and control flags */
  Bit32u eip;    /* instruction pointer */

  /* user segment register set */
  bx_segment_reg_t  cs; /* code segment register */
  bx_segment_reg_t  ss; /* stack segment register */
  bx_segment_reg_t  ds; /* data segment register */
  bx_segment_reg_t  es; /* extra segment register */
  bx_segment_reg_t  fs; /* extra segment register */
  bx_segment_reg_t  gs; /* extra segment register */

  /* system segment registers */
  bx_segment_reg_t gdtr; /* global descriptor table register */
  bx_segment_reg_t idtr; /* interrupt descriptor table register */
  bx_segment_reg_t ldtr; /* interrupt descriptor table register */
  bx_segment_reg_t tr;   /* task register */


  /* debug registers 0-7 (unimplemented) */
  Bit32u dr0;
  Bit32u dr1;
  Bit32u dr2;
  Bit32u dr3;
  Bit32u dr4;
  Bit32u dr5;
  Bit32u dr6;
  Bit32u dr7;

  /* test registers 3-7 (unimplemented) */
  Bit32u tr3;
  Bit32u tr4;
  Bit32u tr5;
  Bit32u tr6;
  Bit32u tr7;

  /* Control registers */
  bx_cr0_t  cr0;
  } bx_cpu_t;




/* --- EXTERNS --- */

extern Bit8u  *bx_8bit_gen_reg[8];
extern Bit16u *bx_16bit_gen_reg[8];
extern Bit32u *bx_32bit_gen_reg[8];

extern Bit16u *bx_16bit_base_reg[8];
extern Bit16u *bx_16bit_index_reg[8];


#ifndef BX_MAIN_C
extern Boolean bx_use_video;
extern FILE *bx_logfd;
#endif

#ifndef BX_DECODE_C
extern Bit32u bx_prev_eip;
#endif

extern  bx_segment_reg_t *bx_seg_reg_mod00_rm[8];
extern  bx_segment_reg_t *bx_seg_reg_mod01_rm[8];
extern  bx_segment_reg_t *bx_seg_reg_mod10_rm[8];
extern  bx_segment_reg_t *bx_seg_reg_mod00_base[8];
extern  bx_segment_reg_t *bx_seg_reg_mod01_base[8];
extern  bx_segment_reg_t *bx_seg_reg_mod10_base[8];


extern Boolean bx_parity_lookup[256];
extern Boolean bx_32bit_opsize;
extern Boolean bx_32bit_addrsize;
extern Boolean bx_rep_prefix;
extern Boolean bx_repne_prefix;


bx_segment_reg_t *bx_segment_override;


#ifndef BX_MAIN_C

extern bx_cpu_t bx_cpu;

#endif /* ifndef BX_MAIN_C */

#ifndef BX_MEMORY_C
extern bx_phy_mem_page_t bx_phy_mem_pages[BX_NUM_PAGES];
#endif /* BX_MEMORY_C */


/* --- PROTOTYPES --- */

void bx_decode_exgx(Bit32u *op1_addr, Bit32u *op2_addr,
  int *op2_type, bx_segment_reg_t **seg_reg_code);





Bit8u  bx_fetch_next_byte(void);
Bit8u  bx_peek_next_byte(void);
Bit16u bx_fetch_next_word(void);
Bit32u bx_fetch_next_dword(void);

void bx_invalid_instruction(void);


void bx_printf(int bomb_out, ...);

Bit8u  bx_read_8bit(Bit32u, bx_segment_reg_t *);
Bit16u bx_read_16bit(Bit32u, bx_segment_reg_t *);
Bit32u bx_read_32bit(Bit32u, bx_segment_reg_t *);
void   bx_write_8bit(Bit32u,  bx_segment_reg_t *, Bit8u);
void   bx_write_16bit(Bit32u, bx_segment_reg_t *, Bit16u);
void   bx_write_32bit(Bit32u, bx_segment_reg_t *, Bit32u);

void   bx_load_seg_reg(bx_segment_reg_t *seg, Bit16u new_value);

void bx_virtual_block_write(bx_segment_reg_t *seg, Bit32u offset,
  Bit32u length, void *data);
void bx_virtual_block_read(bx_segment_reg_t *seg, Bit32u offset,
  Bit32u length, void *data);

void bx_access_virtual(bx_segment_reg_t *seg, Bit32u offset, Bit8u length,
    Bit8u rw, void *data);


void bx_segment_exception(int vector, Bit16u error_code);
void bx_access_linear(Bit32u address, Bit8u length, Bit8u pl, 
    Bit8u rw, void *data);
Bit32u bx_translate_linear(Bit32u addr, Bit8u pl, Bit8u rw);
void bx_access_physical(Bit32u addr, Bit8u len, Bit8u rw, void *data);



Bit16u bx_read_segment_register(Bit32u index);
void bx_write_segment_register(Bit32u index, Bit16u value);

void bx_push_16(Bit16u value);
void bx_push_32(Bit32u value);
void bx_pop_16(Bit16u *value);
void bx_pop_32(Bit32u *value);
void bx_write_eflags(Bit32u eflags);
void bx_write_flags(Bit32u flags);
void bx_decode(void);

void bx_init_memory(int memsize);
void bx_set_interrupt_vector(int interrupt, Bit32u address);
void bx_invoke_interrupt(int interrupt);


void  bx_outp(Bit16u addr, Bit8u value);
Bit8u bx_inp(Bit16u addr);

void bx_debug(bx_segment_reg_t *seg, Bit32u offset);

char *bx_strseg(bx_segment_reg_t *seg);

#endif  /* BX_BOCHS_H */
