; memory headers
bits 16
%pragma once
%ifndef memhdrs
 %define memhdrs

%define chseg(x,y)       _chseg x,y     ; chseg :: reg *seg -> int16 new -> void
%define sret(x)          _sret x        ; sret :: reg *seg -> void
%define palloc()         _palloc 1
%define palloc(x)        _palloc x      ; palloc :: int8 blocks? -> int24 *hi:lo
%define valloc(h,l,x,li) _valloc h,l,x,li
%define valloc(h,l,x)    _valloc h,l,x  ; valloc :: addr24 *hi:low -> int8 xs
                                        ;     -> int16 limit? -> int16 selector
%define dalloc(r)        _dalloc r      ; dalloc :: int8 ring
                                        ;     -> [ int32 sel:gdtidx ]
%define showgdt()       _showgdt        ; showgdt :: void -> void
%define setgdt(s,d,h,l,x)    _setgdt s,d,h,l,x
%define setgdt(s,d,h,l,x,li) _setgdt s,d,h,l,x,li
                                        ; setgdt :: gdtentry *seg:dest
                                        ;   -> addr24 *hi:low
                                        ;   -> int8 access
                                        ;   -> int16 limit? -> bool
%define setgate(s,d,sel,o,w,x) _setgate s,d,sel,o,w,x
                                        ; setgate :: gdtentry *seg:dest
                                        ;   -> addr *sel:offset -> int8 wordcnt
                                        ;   -> int8 access -> bool

%define MaxGdtSz  248
%define IdtSz     255
; %define IdtSz     32
                        ; ACCESS BYTE BITS:
                        ;   7 	6 	5 	4 	3 	2 	1 	0
                        ;   P 	DPL 		S 	E 	D/C	R/W A
%define P     (1<<7)    ; Present
%define Ring0 0         ; DPL=0 (adm)
%define Ring1 (1<<5)    ; DPL=1
%define Ring2 (0b10<<5) ; DPL=2 (dev)
%define Ring3 (0b11<<5) ; DPL=3 (usr)
%define S     (1<<4)    ; S (1=standard type)
%define E     (1<<3)    ; E (1=executable)
%define D     (1<<2)    ; Direction (1=stack)
%define C     (1<<2)    ; Conforming
%define R     (1<<1)    ; R (1=readable) code segments
%define W     (1<<1)    ; W (1=writable) data segments
%define A     (1<<0)    ; A (1=accessed)
%define Tss      0x0001 ; T (1=tss)
%define Ldt      0x0002
%define TssBusy  0x0003
%define CallGate 0x0004
%define TaskGate 0x0005
%define IntGate  0x0006
%define TrapGate 0x0007




%ifdef xpmemory
  global Palloc
%else
  extern Palloc
%endif

%ifdef xvmemory
  global Valloc
  global Showgdt
  global Setgate
  global Setgdt
  global Dalloc
%else
  extern Valloc
  extern Showgdt
  extern Setgate
  extern Setgdt
  extern Dalloc
%endif

%macro _setgate 6
  xor ah,ah
  mov byte al,%6
  push ax
  mov byte al,%5
  push ax
  mov ax,%4
  push ax
  mov ax,%3
  push ax
  mov ax,%2
  push ax
  mov ax,%1
  push ax
  call Setgate
  carry 6
%endmacro

%macro _dalloc 1
  mov ax,%1
  and ax,0xff
  push ax
  call Dalloc
  carry 1
%endmacro

%macro _setgdt 6
    mov ax,%6
    push ax
    mov ax,%5
    push ax
    mov ax,%4
    push ax
    mov ax,%3
    push ax
    mov ax,%2
    push ax
    mov ax,%1
    push ax
    call Setgdt
    carry 6
%endmacro
%macro _setgdt 5
    mov ax,0xffff
    push ax
    mov ax,%5
    push ax
    mov ax,%4
    push ax
    mov ax,%3
    push ax
    mov ax,%2
    push ax
    mov ax,%1
    push ax
    call Setgdt
    carry 6
%endmacro


%macro _showgdt 0
  call Showgdt
%endmacro

%macro _chseg 2
;   %push chseg
;   %define %$reg %1
   mov ax,%1
   push ax
   cmp word ax,%2
   je %%eq
 %%neq:
   mov ax,%2   ; ax=new seg
   mov %1,ax
 %%eq:
%endmacro

;%macro _sret 0
;   pop bx
;   mov cx,%$reg
;   %undef %$reg
;   %pop
;
;   cmp bx,cx
;   je %%eq
; %%neq:
;   mov %1,bx
; %%eq:
;%endmacro

%macro _sret 1
   pop bx
   push cx
   mov cx,%1
   cmp bx,cx
   pop cx
   je %%eq
 %%neq:
   mov %1,bx
 %%eq:
%endmacro

%macro _palloc 1
  mov ax,%1
  push ax
  call Palloc
  carry 1
%endmacro
%macro _palloc 0
  _palloc 1
%endmacro

%macro _valloc 4
  mov ax,%4
  push ax
  mov ax,%3
  and ax,0xff
  push ax
  mov ax,%2
  push ax
  mov ax,%1
  and ax,0xff
  push ax
  call Valloc
  carry 4
%endmacro
%macro _valloc 3
  mov ax,0xffff
  push ax
  mov ax,%3
  and ax,0xff
  push ax
  mov ax,%2
  push ax
  mov ax,%1
  and ax,0xff
  push ax
  call Valloc
  carry 4
%endmacro

; todo: add ldt support
%macro _xdtr 1
  mov dx,csselector
  mov ax,confseg.gdtr
%endmacro

; todo: add ldt support
%macro _xdt 1
  push si

  mov dx,csselector
  chseg(ds,dx)
  mov si,confseg.gdtseg
  mov word dx,ds:[si]
  xor ax,ax

  sret(ds)
  pop si
  clc
%endmacro 

struc Gdtr
  .sz:   resw 1
  .low:  resw 1
  .hi:   resb 1
  .res:  resb 1
  .end:
endstruc
%define Idtr(x) Gdtr. %+ x

struc gdtentry
    .limit:   resw 1
    .baselo:  resw 1
    .basehi   resb 1
    .xs:      resb 1
    .reserv:  resw 1
endstruc

struc Idt
  .offset:  resw 1
  .selector:resw 1 ; <<2
  .wordcnt: resb 1
  .xs:      resb 1
  .res:     resw 1
endstruc

%endif
