%include "c16.mac"

section _mytext

; void get_xy(int x, int y);
proc    _goto_xy
%$x     arg
%$y     arg
        mov     ax,[bp+%$x]
        mov     [_cur_x],ax
        mov     ax,[bp+%$y]
        mov     [_cur_y],ax
endproc
        
; void set_attr(unsigned char attr);
proc    _set_attr
%$attr  arg
        mov     al,[bp+%$attr]
        mov     [_cur_attr],al
endproc

; void clear_scr(void);
global  _clear_scr
_clear_scr:
        mov      ah,[_cur_attr]
        mov      al,0
        mov      cx,2000
        mov      bx,0
clrchr:
        mov      [fs:bx],ax
        inc      bx
        inc      bx
        loop     clrchr
        ret     

; void write_str(char *str);
global  _write_str
_write_str:
        push    bp
        mov     bp,sp
        push    si
        cld
        
        mov      ax,[_cur_y]
        mov      cl,4
        shl      ax,cl
        mov      bx,ax  ; bx = _cur_y * 16
        shr      cl,1
        shl      ax,cl  ; ax = _cur_y * 64
        add      bx,ax  ; bx = _cur_y * 80
        add      bx,[_cur_x] ; bx = _cur_y * 80 + _cur_x
        shl      bx,1   ; bx = bx * 2
        mov      ah,[_cur_attr]
        
        mov      si,[bp+4]
loadchr:
        lodsb   
        cmp      al,0
        je      short finish
        mov      [fs:bx],ax
        add      bx,2
        jmp     short loadchr
finish:
        pop     si
        pop     bp
        ret     


..start:
        mov     ax,_mydata
        mov     ds,ax
        mov     es,ax

        ; set up stack  ; No need, DOS has done it
        ;mov    ax,_mystack
        ;mov    ss,ax
        ;mov    sp,stktop

        ;; save seg regs
        mov     ax,cs
        mov     [old_cs],ax
        mov     ax,ds
        mov     [old_ds],ax
        mov     ax,ss
        mov     [old_ss],ax
        ;mov    [old_sp],sp
        mov     ax,fs
        mov     [old_fs],ax
        
        ;; set up c16 descriptor
        xor     eax,eax
        mov     ax,cs
        shl     eax,4
        mov     [c16+2],ax
        shr     eax,16
        mov     [c16+4],al
        
        ;; set up d16 descriptor
        xor     eax,eax
        mov     ax,ds
        shl     eax,4
        mov     [d16+2],ax
        shr     eax,16
        mov     [d16+4],al

        ;; set up s16 descriptor
        xor     eax,eax
        mov     ax,ss
        shl     eax,4
        mov     [s16+2],ax
        shr     eax,16
        mov     [s16+4],al

        ;; disable interrupt
        cli

        ;; disable NMI
        in      al,70h
        or      al,80h
        out     70h,al

        ;; set up GDTR
        xor     eax,eax
        mov     ax,ds
        shl     eax,4
        add     eax,gdt
        mov     [gdtr+2],eax
        lgdt    [gdtr]

        ;; enter protected moe
        mov     eax,cr0
        or      eax,1
        mov     cr0,eax

        ;; clear ins cache & re-load CS
        jmp     0x08:.1
.1:
        ;; load DS
        mov     ax,10h
        mov     ds,ax

        ;; set up stack 
        mov     ax,18h
        mov     ss,ax
        ;mov    esp,pstop

        mov     ax,20h
        mov     fs,ax

        call    _clear_scr

        mov     ax,msg
        push    ax
        call    _write_str
        pop     cx

        mov     ax,10
        push    ax
        mov     ax,20
        push    ax
        call    _goto_xy
        pop     cx
        pop     cx

        mov     al,20
        push    ax
        call    _set_attr
        pop     cx

        mov     ax,msg
        push    ax
        call    _write_str
        pop     cx

        ;; change back to real mode
        mov     eax,cr0
        and     eax,0FFFFFFFEh
        mov     cr0,eax

        mov     ax,[old_cs]
        push    ax
        push    word .1
        retf
        ;jmp    _mytext:.2
.2:
        mov     ax,[old_ds]
        mov     ds,ax
        mov     es,ax

        mov     ax,[old_ss]
        mov     ss,ax
        ;mov    sp,[old_sp]
        mov     ax,[old_fs]
        mov     fs,ax
        
        ;; enable NMI
        in      al,70h
        and     al,7Fh
        out     70h,al

        ;; enable interrupt
        sti

        mov     ax,4C00h
        int     21h

section _mydata align=16
global old_sp
;old_sp dw      0
old_ss  dw      0
old_fs  dw      0
old_ds  dw      0
old_cs  dw      0

global gdt
gdt:
null    dq      0
c16     db      0FFh,0FFh,0,0,0,9Ah,0,0 ; nonconforming, readable, 16-bit
d16     db      0FFh,0FFh,0,0,0,92h,0,0 ; expand-up, writable, 16-bit
s16     db      0FFh,0FFh,0,0,0,92h,0,0
vga     db      0FFh,0FFh,0,80h,0Bh,92h,0,0     

gdtr    dw      $-gdt-1
        dd      gdt
global  _cur_x,_cur_y,_cur_attr,msg
_cur_x  dw      0
_cur_y  dw      0
_cur_attr db    0Fh

msg     db      'Hello World From Protected Mode!',0

section _mystack stack align=16
        resb    0x40
global stktop
stktop:

;section _pmstack aligh=16
;       resb    0x40
;pstop:
