        org 0x700
        bits 16
        using "system"
start:

        xor ax, ax
        mov es, ax
        mov ax, 0x1301
        mov bx, 0x0007
        mov cx, 13
        mov dx, 0x0301
        mov bp, hello
        int 0x10
        
    mov ax, 4f01h
    mov cx, 0140h
    mov dx, 0
    mov es, dx
    mov di, some_data
    int 10h
    
    mov eax, [some_data+40]
    mov [frame_buffer], eax
    xor eax, eax
    mov ax, [some_data+18]
    call prinum1
    mov [winwidth], eax
    mov ax, [some_data+20]
    call prinum1
    mov [winheight], eax
    call waiting
  
    mov ax, 4f02h
    mov bx, 4140h
    int 10h

    

        mov bx, 10000
.lp1:   mov cx, 10000
.lp2:   imul ax, 1234
        dec cx
        jnz .lp2
        dec bx
        jnz .lp1

        mov al, 0xD1               ; Enable A20 (AT compatibles)
        out 0x64, al               ; (may need wait for it to happen)
        mov al, 0xDF
        out 0x60, al

     ;  in  al, 0x92               ; (commented out)
     ;  or  al, 2                  ; same for PS2 compatibles
     ;  out 0x92, al               ; faster, may not need wait?

        mov ah, 3
        mov bh, 0
        int 10h                    ; get current cursor posn and save it
        mov eax, 0
        mov al, dh
        mov [row], eax
        mov eax, 0
        mov al, dl
        mov [col], eax
        
        mov dx, 0x3D8
        mov al, 0x29
        out dx, al

        lea eax, [gdt]             ; EAX=PHYSICAL address of gdt
        mov [gdtr+2], eax

        cli

        lgdt [gdtr]

        mov eax, cr0
        or al, 1
        mov cr0, eax

        jmp SYS_CODE_SEL:do_pm         ;jumps to do_pm

hello: db " Starting... ", 0

babystk equ 0xE0000
inistk  equ 0x400000
tfreq   equ 1000
kbqsize equ 100

heapst  equ 0x200000
heapnd  equ 0x300000
heapcur:dd  heapst

pgdir   equ 0x310000
pgtab0  equ 0x311000
pgtab1  equ 0x312000

taskbase equ 0x340000

PCB0    equ 0x350000
PCB1    equ (PCB0+4096)
STK0    equ 0x360000
STK1    equ (STK0+4096)

wtcnt:  dd 0

a20tst: dd 0

state0: dd 0x00000010   ; ss
        dd 0x00000010   ; gs
        dd 0x00000010   ; fs
        dd 0x00000010   ; es
        dd 0x00000010   ; ds
        dd 0            ; edi
        dd 0            ; esi
        dd 0            ; ebp
        dd 0            ; esp -- set to process-specific value
        dd 0            ; ebx
        dd 0            ; edx
        dd 0            ; ecx
        dd 0            ; eax
        dd 0            ; eip -- set to process-specific value
        dd 0x00000008   ; cs
        dd 0x00200202   ; eflags

phex:   push ax
        push si
        push ax
        mov  si, ax
        and  si, 00F0h
        shr  si, 4
        add  si, hex
        mov  al, [si]
        call princ1
        pop  si
        and  si, 000Fh
        add  si, hex
        mov  al, [si]
        call princ1
        pop  si
        pop  ax
        ret

phex4:  push ax
        shr  ax, 8
        call phex
        pop  ax
        call phex
        ret

waiting:
  in al, 0x64
  and al, 1
  jz waiting
      ret

prinum1: pusha
        mov  bx, 10000
        xor  dx, dx
        idiv bx
        add  al, 48
        call princ1
        mov  bx, 1000
        mov  ax, dx
        xor  dx, dx
        idiv bx
        add  al, 48
        call princ1
        mov  bx, 100
        mov  ax, dx
        xor  dx, dx
        idiv bx
        add  al, 48
        call princ1
        mov  bx, 10
        mov  ax, dx
        xor  dx, dx
        idiv bx
        add  al, 48
        call princ1
        mov  al, dl
        add  al, 48
        call princ1
        popa
        ret

princ1:  push ax
        push bx
        mov  ah, 0Eh
        mov  bx, 0007h
        int  10h
        pop  bx
        pop  ax
        ret

        bits 32
do_pm:
        mov  ax, SYS_DATA_SEL
        mov  ds, ax
        mov  es, ax
        mov  fs, ax
        mov  gs, ax
        mov  ss, ax
        mov  esp, babystk
        mov  ax, SYS_TASK_SEL
        ltr  ax        
        mov  eax, 0x2365AB12
        push dword msgokpm
        call prins
        mov  edx, 0x89FE0245
        mov  ebx, a20tst
        mov  ecx, ebx
        add  ecx, 0x100000
        xor  edi, edi
.a20wt: mov  [ebx], eax
        mov  [ecx], edx
        mov  esi, [ebx]
        cmp  esi, [ecx]
        jne  .diff
        inc  edi
        cmp  edi, 0x9999
        jl   .a20wt
        push dword failed
        call prins
        jmp  .done
.diff:  mov  esp, inistk
.done:  push edi
        call prinhd
        push dword msga20
        call prins
        
intson:
        lidt [idtr]
        
        mov  al, 0x36
        out  0x43, al
        xor  edx, edx
        mov  ecx, tfreq    ; desired timer interrupt frequency
        mov  eax, 1193180
        idiv ecx
        out  0x40, al
        mov  al, ah
        out  0x40, al
        
        mov al, 0x11  ; send ICW1
        out 0x20, al
        mov al, 0x11
        out 0xA0, al

        mov al, 0x20  ; PIC1 interrupts 0x20-0x27
        out 0x21, al
        mov al, 0x28  ; PIC2 interrupts 0x28-0x2F
        out 0xA1, al

        mov al, 0x04  ; PIC1 communication pin
        out 0x21, al
        mov al, 0x02  ; PIC2 communication pin
        out 0xA1, al
        
        mov al, 0x01  ; send ICW4
        out 0x21, al
        mov al, 0x01 
        out 0xA1, al 

        mov al, 0xFC  ; interrupts 0x20(tim), 0x21(kbd) on
        out 0x21, al
        mov al, 0xFF  ; interrupts 0x28-0x2F off
        out 0xA1, al

        sti
        push strien
        call prins
        mov  [endstk], inistk
        
        xor  eax, eax
        mov  al, [0x0502]
        mov  ebx, [0x40008]
        mov  [firstblk], ebx
        mov  ecx, [0x4000C]
        add  ecx, ebx
        dec  ecx
        mov  [lastblk], ecx
        add  eax, ebx
        inc  eax
        mov  [dirblk], eax
        push [lastblk]
        push [dirblk]
        push [firstblk]
        push fmt1
        push 16
        call printf
        mov  [heapcur], heapst
        
        mov  [$princ],      princ
        mov  [$prinvc],     prinvc
        mov  [$prin4c],     prin4c
        mov  [$prins],      prins
        mov  [$prinsn],     prinsn
        mov  [$prinum],     prinum
        mov  [$prinhb],     prinhb
        mov  [$prinhw],     prinhw
        mov  [$prinhd],     prinhd
        mov  [$newline],    newline
        mov  [$inchar],     inchar
        mov  [$innum],      innum
        mov  [$iflush],     iflush
        mov  [$backch],     backch
        mov  [$flush],      flush
        mov  [$filenum],    filenum
        mov  [$findfile],   findfile
        mov  [$readblk],    readblk
        mov  [$printf],     printf
        mov  [$writeblk],   writeblk
        mov  [$ranseed],    ranseed
        mov  [$ticktime],   ticktime
        mov  [$reseth],     reseth
        mov  [$malloc],     malloc
        mov  [$palloc],     palloc
        mov  [$free],       free
        mov  [$clrscr],     clrscr
        mov  [$setcolor],   setcolor
        mov  eax, [winwidth]
        mov  [$winw],       eax
        mov  eax, [winheight]
        mov  [$winh],       eax
        mov  eax, [frame_buffer]
        mov  [$videomem],   eax

        mov  edx, $code
        push edx
        push edx
        push startupf
        call loadfile
        pop  edx
        jc   mainlp
        jmp  cmd_run
        
mainlp: 
    mov eax, [$videomem]
    ;push eax
    ;call [$prinum]
    mov edx, [$winh]
    imul edx, [$winw]
    shr edx, 2
    mov ebx, 255
fill:   mov [eax], dword 0x0000FF
        add eax, 4
        dec edx
        jnz fill
        
lpend:  call waiting
        
    push '>'
        call princ
        push ' '
        call princ
        call flush
        call iflush
        xor  ebx, ebx
        xor  ecx, ecx
        xor  edx, edx
        xor  edi, edi
        mov  esi, arg0
        mov  byte [esi], 0
        mov  byte [esi+16], 0
        mov  byte [esi+32], 0
        
.agn:   
        call inchar
        cmp  al, 10
        je   .ready
        cmp  al, ' '
        jg   .visib
        and  esi, 0xFFFFFFF0
        cmp  [esi], 0
        je   .agn
        add  esi, 16
        cmp  edi, 0
        jne  .agn
        mov  edi, ebx
        xor  ebx, ebx
        jmp  .agn
.visib: mov  [esi], al
        inc  esi
        mov  byte [esi], 0
;        test ebx, ebx
;        jnz  .notd
        cmp  al, '0'
        jl   .notd
        cmp  al, '9'
        jg   .notd
        call backch
        call innum
        mov  ecx, edx
        mov  edx, eax
        jmp  .agn
.notd:  shl  ebx, 8
        mov  bl, al
        jmp  .agn
.ready: or   edi, edi
        je   .rrdy
        mov  ebx, edi
.rrdy:  
        cmp  ebx, 0
        je   mainlp
        cmp  ebx, '?'
        je   cmd_qmk
        cmp  ebx, 'test'
        je   cmd_test
        cmp  ebx, 'int'
        je   cmd_int
        cmp  ebx, 'dir'
        je   cmd_dir
        cmp  ebx, 'page'
        je   cmd_page
        cmp  ebx, 'lblk'
        je   cmd_lblk
        cmp  ebx, 'load'
        je   cmd_load
        cmp  ebx, 'exe'
        je   cmd_exe
        cmp  ebx, 'exeI'
        je   cmd_exeI
        cmp  ebx, 'show'
        je   cmd_show
        cmp  ebx, 'set'
        je   cmd_set
        cmp  ebx, 'step'
        je   cmd_step
        cmp  ebx, 'run'
        je   cmd_run
        cmp  ebx, 'time'
        je   cmd_time
        cmp  ebx, 'exit'
        je   cmd_exit
        cmp  ebx, 'star'
        je   cmd_star
        cmp  ebx, 'plus'
        je   cmd_plus
        cmp  ebx, 'go'
        je   cmd_go
        cmp  ebx, 'pcb'
        je   cmd_pcb
        cmp  ebx, 'rand'
        je   cmd_rand
        push strcmd
        call prins
        push ebx
        call prin4c
        push stre1b
        call prins
        jmp  mainlp

       align 16
arg0:  dd 0, 0, 0, 0
arg1:  dd 0, 0, 0, 0
arg2:  dd 0, 0, 0, 0
        
startupf: db "start", 0
fmt1:  db "[blocks: first %d, root %d, last %d]\n", 0

mkproc: ; push pcb-addr, then initial eip, then initial esp
        pushad
        mov  edi, [esp+44]         ; pcb
        mov  eax, [esp+36]         ; esp
        mov  [(state0+32)], eax
        mov  eax, [esp+40]         ; eip
        mov  [(state0+52)], eax
        mov  esi, state0
        mov  ecx, 16
        rep movsd
        popad
        ret 12

cmd_rand:
        call ranseed
        push eax
        call prinhd
        call newline
        jmp  mainlp

cmd_go:
        push pcb0
        push cmd_star
        push stk0
        call mkproc
        push pcb1
        push cmd_plus
        push stk1
        call mkproc
        mov  [np], 2
        mov  byte [TSON], 1
        mov  byte [run], 1
        
cmd_star:
        mov  byte [run], 1
.loop:
        mov  ecx, 5000000
.wait:  loop .wait
        push '*'
        call princ
        mov  al, [run]
        or   al, al
        jne  .loop
        jmp  mainlp

cmd_plus:
        mov  byte [run], 1
.loop:
        mov  ecx, 6000000
.wait:  loop .wait
        push '+'
        call princ
        mov  al, [run]
        or   al, al
        jne  .loop
        jmp  mainlp
       
cmd_pcb:
       push cmd_star
       call prinhd
       call newline
       mov  ecx, 16
.loop: push ecx
       call prinhb
       push ':'
       call princ
       push [pcb0+4*ecx]
       call prinhd
       call newline
       loop .loop
       push ecx
       call prinhb
       push ':'
       call princ
       push [pcb0+4*ecx]
       call prinhd
       call newline
       jmp mainlp
        
cmd_qmk:push edx
        call prinum
        push '-'
        call princ
        push arg0
        call prins
        push ','
        call princ
        push arg1
        call prins
        push ','
        call princ
        push arg2
        call prins
        push ','
        call princ
        push ecx
        call prinum
        push ','
        call princ
        push edx
        call prinum
        call newline
        jmp  mainlp

cmd_test:
        mov  ebx, inistk
        add  ebx, 0x4567
        mov  ecx, 4091
        xor  edx, edx
.loopa: mov  eax, 0x12345600
        mov  al, dl
        mov  [ebx], eax
        mov  eax, 0x89AB00EF
        mov  ah, dh
        mov  [ebx+4], eax
        add  ebx, 0x100000
        inc  edx
        loop .loopa
        mov  ebx, inistk
        add  ebx, 0x4567
        mov  ecx, 4091
        xor  edx, edx
.loopb: mov  eax, 0x12345600
        mov  al, dl
        cmp  [ebx], eax
        jne  .diff
        mov  eax, 0x89AB00EF
        mov  ah, dh
        cmp  [ebx+4], eax
        jne  .diff
        add  ebx, 0x100000
        inc  edx
        loop .loopb
.diff:  and  ebx, 0xFFF00000
        push ebx
        call prinhd
        push ':'
        call princ
        push ' '
        call princ
        shr  ebx, 20
        push ebx
        call prinum
        push 'M'
        call princ
        push 'B'
        call princ
        call newline
        jmp  mainlp

pging:  db   0
cmd_page:
        or   edx, edx
        jne  setpag
        mov  al, byte [pging]
        or   al, al
        je   .pgon
        mov  eax, cr0
        and  eax, 0x7FFFFFFF
        mov  cr0, eax
        xor  al, al
        mov  byte [pging], al
        push pgisof
        call prins
        jmp  mainlp  
.pgon:  mov  edi, pgdir
        xor  eax, eax
        mov  ecx, 1024
.loop1: mov  [edi], eax
        add  edi, 4
        loop .loop1
        mov  edi, pgdir
        mov  eax, pgtab0
        or   eax, 7
        mov  [edi], eax
        mov  eax, pgtab1
        or   eax, 7
        mov  [edi+2048], eax
        mov  edi, pgtab0
        mov  eax, 7
        mov  ecx, 1024
.loop2: mov  [edi], eax
        add  edi, 4
        add  eax, 4096
        loop .loop2
        mov  edi, pgtab1
        mov  ecx, 1024
.loop3: mov  [edi], eax
        add  edi, 4
        add  eax, 4096
        loop .loop3
        mov  eax, pgdir
        mov  cr3, eax
        mov  eax, cr0
        or   eax, 0x80000000
        mov  cr0, eax
        or   al, 1
        mov  byte [pging], al
        push pgison
        call prins
        jmp  mainlp
setpag: mov  eax, ecx
        or   ecx, ecx
        je   shopag
        shr  ecx, 10
        or   ecx, pgtab0
        and  edx, 0xFFFFF000
        or   dl, 7
        mov  [ecx], edx
        mov  edx, eax
shopag: mov  ebx, edx
        shr  edx, 10
        or   edx, pgtab0
        mov  ecx, [edx]
        and  ebx, 0xFFFFF000
        and  ecx, 0xFFFFF000
        push ebx
        call prinhd
        push '>'
        call princ
        push ecx
        call prinhd
        call newline
        jmp  mainlp
pgison: db "Paging is now ON\n", 0
pgisof: db "Paging is now OFF\n", 0

cmd_lblk:
        push ecx
        push edx
        call readblk
        jmp  mainlp

findfile:   ; push &size, push &firstblock; push filename, ret filenum
        mov  eax, [esp+4]
        push eax
        call filenum
        jnc  .ok
        xor  eax, eax
        ret  12
.ok:    push eax
        push ebx
        push edx
        push [dirblk]
        push 0x41000
        call readblk
        dec  eax
        shl  eax, 4
        add  eax, 0x41008
        mov  ebx, [eax]
        mov  edx, [esp+20]
        mov  [edx], ebx
        mov  ebx, [eax+4]
        mov  edx, [esp+24]
        mov  [edx], ebx
        pop  edx
        pop  ebx
        pop  eax
        ret  12

loadfile:   ; push address, push filename, call me, CF=error
        pushad
        mov  edx, [esp+36]
        push edx
        push edx
        call filenum
        jnc  .ok
        push filnotfnd1
        call prins
        call prins
        push filnotfnd2
        call prins
        popad
        stc
        ret  8
.ok:    pop  edx
        mov  edx, [esp+40]
        push [dirblk]
        push 0x41000
        call readblk
        dec  eax
        shl  eax, 4
        add  eax, 0x41008
        mov  ebx, [eax]
        add  eax, 4
        mov  ecx, [eax]
        mov  esi, ecx
        sal  esi, 9
.loop:  push ebx
        push edx
        call readblk
        inc  ebx
        add  edx, 512
        loop .loop
        popad
        clc
        ret  8
filnotfnd1: db "File '", 0
filnotfnd2: db "' not found\n", 0
        
cmd_load:
        or   edx, edx
        jne  .go
        mov  edx, $code
.go:    push edx
        push arg1
        call loadfile
        jc   mainlp
        jmp  mainlp


        
cmd_exe:
        or   edx, edx
        jne  .go
        mov  edx, $code
.go:    push edx
        push edx
        push arg1
        call loadfile
        pop  edx
        jc   mainlp
        jmp  cmd_run
        
strdir: db "Directory", 0
stremp: db " Empty", 0
dirblk: dd 0
firstblk: dd 0
lastblk: dd 0
cmd_dir:push strdir
        call prins
        push [dirblk]
        push 0x41000
        call readblk
        mov  ecx, 32
        mov  eax, 1
        xor  ebx, ebx
        mov  edx, 0x41000
.next:  cmp  [edx], 0
        je   .goon
        call newline
        inc  ebx
        push eax
        call prinum
        push ':'
        call princ
        push ' '
        call princ
        push edx
        push 8
        call prinsn
        push ' '
        call princ
        push [edx+8]
        call prinum
        push ' '
        call princ
        push [edx+12]
        call prinum
.goon:  inc  eax
        add  edx, 16
        loop .next
        cmp  ebx, 0
        jne  .some
        push stremp
        call prins
.some:  call newline
        jmp  mainlp
        
filenum:
        push ecx
        push edx
        push [dirblk]
        push 0x41000
        call readblk
        mov  ecx, 32
        mov  eax, 1
        mov  edx, 0x41000
.next:  push edx
        push [esp+16]
        call streql8
        je   .found
        inc  eax
        add  edx, 16
        loop .next
        xor  eax, eax
        stc
        jmp  .end
.found: clc
.end:   pop  edx
        pop  ecx
        ret  4
 
streql8:pushad
        mov  eax, [esp+40]
        mov  ebx, [esp+36]
        mov  ecx, 8
.loop:  mov  dl, [eax]
        mov  dh, [ebx]
        cmp  dl, dh
        jne  .end
        cmp  dl, 0
        je   .end
        inc  ebx
        inc  eax
        loop .loop
        cmp  eax, eax
.end:   popad
        ret  8
 
cmd_step:  
        or   edx, edx
        jne  .ok
        mov  edx, $code
.ok:    mov  dword [ssender], .ra
        lea  eax, [esp-4]
        mov  dword [endstk], eax
        xor  eax, eax
        xor  ebx, ebx
        xor  ecx, ecx
        xor  esi, esi
        xor  edi, edi
        pushfd
        or   byte [esp+1], 1
        popfd
        call edx
.ra:    pushfd
        and  byte [esp+1], 0xFE
        popfd
        mov  dword [endstk], inistk
        jmp  mainlp
 
runstr: db "running from %08X\n", 0
 
cmd_exeI:
        or   edx, edx
        jne  .go
        mov  edx, $code
.go:    push edx
        push edx
        push arg1
        call loadfile
        pop  edx
        jc   mainlp
        mov [Int_Disable],byte 1
        jmp  cmd_run

Int_Disable : db 0      


cmd_run:  
        or   edx, edx
        jne  .ok
        mov  edx, $code
.ok:    
        mov  dword [ssender], .end
        lea  eax, [esp-4]
        mov  dword [endstk], eax
        xor  eax, eax
        xor  ebx, ebx
        xor  ecx, ecx
        xor  esi, esi
        xor  edi, edi
        call edx
.end:   mov [Int_Disable],byte 0
        mov  dword [endstk], inistk
        test eax, eax
        jnz  rncode
        push pterms
        call prins
        jmp  mainlp
rncode: push eax
        push ptermf
        push 8
        call printf
        jmp  mainlp
pterms: db "\nProgram Terminated\n", 0       
ptermf: db "\nProgram Terminated with Exit Code %d\n", 0  

cmd_set:
        mov  byte [ecx], dl
        and  ecx, 0xFFFFFFFC
        push ecx
        call prinhd
        push ':'
        call princ
        push ' '
        call princ
        push [ecx]
        call prinhd
        call newline
        jmp  mainlp

cmd_show:
        or   edx, edx
        jne  .ok
        mov  edx, $code
.ok:    push edx 
        call pr16b
        add  edx, 16
        push edx 
        call pr16b
        add  edx, 16
        push edx 
        call pr16b
        add  edx, 16
        push edx 
        call pr16b
        add  edx, 16
        push edx 
        call pr16b
        jmp  mainlp
        
strcmd: db 10, "Worthless command ", 0
strarg: db " Argument ", 0
stre1b: db " not recognised.", 10, 0
dotdot: db " ......", 10, 0
strexi: db 10, "EXIT", 10, 0
strien: db "Interrupts enabled", 10, 0

strtim: db "Running %d.%03d seconds, or %d ticks\n", 0
 
cmd_int:
        int  3
        jmp  mainlp
 
cmd_time:
        push dword [totalticks]
        push dword [ticks]
        push dword [timnow]
        push strtim
        push 16
        call printf
        cli
        mov  al, 0x32
        out  0x70, al
        in   al, 0x71
        mov  dh, al
        
        mov  al, 0x9
        out  0x70, al
        in   al, 0x71
        mov  dl, al
        
        mov  al, 0x8
        out  0x70, al
        in   al, 0x71
        mov  cl, al
        
        mov  al, 0x7
        out  0x70, al
        in   al, 0x71
        mov  ch, al
        
        mov  al, 0x4
        out  0x70, al
        in   al, 0x71
        mov  bl, al
        
        mov  al, 0x2
        out  0x70, al
        in   al, 0x71
        mov  bh, al
        
        mov  al, 0x0
        out  0x70, al
        in   al, 0x71
        
        sti
        push edx
        call prinhw
        push '/'
        call princ
        push ecx
        call prinhb
        push '/'
        call princ
        shr  ecx, 8
        push ecx
        call prinhb
        push '-'
        call princ
        push ebx
        call prinhb
        push ':'
        call princ
        shr  ebx, 8
        push ebx
        call prinhb
        push ':'
        call princ
        push eax
        call prinhb
        push '.'
        call princ
        push dword [ticks]
        call prinum3z
        call newline
        call flush
        jmp  mainlp

cmd_exit:
        push strexi
        call prins
        call flush
        cli
        hlt

int0str:  db "divide error", 0
int1str:  db "debug exception", 0
int2str:  db "NMI", 0
int3str:  db "breakpoint", 0
int4str:  db "INTO overflow", 0
int5str:  db "BOUND outside range", 0
int6str:  db "invalid opcode or operand", 0
int7str:  db "device not available", 0
int8str:  db "double fault", 0
int9str:  db "reserved", 0
int10str: db "invalid task state segment", 0
int11str: db "segment not present", 0
int12str: db "stack fault", 0
int13str: db "general protection fault", 0
int14str: db "page fault", 0
int15str: db "reserved", 0
int16str: db "floating point error", 0
int17str: db "alignment check", 0
intname: dd int0str, int1str, int2str, int3str, int4str, int5str, int6str
         dd int7str, int8str, int9str, int10str, int11str, int12str, int13str
         dd int14str, int15str, int16str, int17str

streax: db "  EAX=", 0
strebx: db "  EBX=", 0
strecx: db "  ECX=", 0
stredx: db "  EDX=", 0
stresi: db "  ESI=", 0
stredi: db "  EDI=", 0
strebp: db "  EBP=", 0
stresp: db "   ESP=", 0
streip: db "   EIP=", 0
strcs:  db "  CS=", 0
strds:  db "  DS=", 0
stres:  db "  ES=", 0
strfs:  db "  FS=", 0
strgs:  db "  GS=", 0
strss:  db "  SS=", 0
strfl:  db "  FLAGS=", 0

dprint:
       push [esp+8]
       call prins
       push [esp+4]
       call prinhd
       push '='
       call princ
       push [esp+4]
       call prinuml
       ret  8
        
dregs: 
       push streax
       push eax
       call dprint
       push strebx
       push ebx
       call dprint
       push strecx
       push ecx
       call dprint
       call newline
       push stredx
       push edx
       call dprint
       push stresi
       push esi
       call dprint
       push stredi
       push edi
       call dprint
       call newline
       push strebp
       call prins
       push ebp
       call prinhd
       push stresp
       call prins
       push esp
       call prinhd
       ret
       
dregs2:
       push eax
       push ecx
       push streip
       call prins
       mov  eax, [esp+12]
       push eax
       call prinhd
       push ':'
       call princ
       push [eax]
       call prinhb
       mov ecx, 6
.oplp: push ','
       call princ
       inc  eax
       push [eax]
       call prinhb
       loop .oplp
       call newline
       push strcs
       call prins
       mov  eax, [esp+16]
       push eax
       call prinhw
       push strds
       call prins
       xor  eax, eax
       mov  ax, ds
       push eax
       call prinhw
       push stres
       call prins
       mov  ax, es
       push eax
       call prinhw
       push strfs
       call prins
       mov  ax, fs
       push eax
       call prinhw
       push strgs
       call prins
       mov  ax, gs
       push eax
       call prinhw
       push strss
       call prins
       mov  ax, ss
       push eax
       call prinhw
       call newline
       push strfl
       call prins
       mov  eax, [esp+20]
       push eax
       call prinhd
       push ebx
       push edx
       xor  edx, edx
       mov  ecx, 32
       mov  ebx, flnam
.flop: test eax, 1
       jz   .cflp
       push ' '
       call princ
       mov  dl, [ebx]
       push edx
       call princ
       mov dl, [ebx+1]
       push edx
       call princ
.cflp: inc  ebx
       inc  ebx
       shr  eax, 1
       loop .flop
       call newline
       pop  edx
       pop  ebx
       pop  ecx
       pop  eax
       ret

flnam: db "CF01PF03AF05ZFSFTFIFDFOFP1P2NT15RFVMAC19202122232425262728293031"

sspm: db "SP+", 0
sdstr: db "  Stack Dump:\n", 0
spstr: db "    ", 0
endstk: dd 0

dstack: push eax
        push ebx
        push ecx
        push sdstr
        call prins
        mov ecx, 8
        mov ebx, esp
        add ebx, 28
        xor eax, eax
.loop:  cmp ebx, [endstk]
        jge .end
        push spstr
        call prins
        push ebx
        call prinhd
        push '='
        call princ
        push sspm
        call prins
        push eax
        call prinum2
        push ':'
        call princ
        push [ebx]
        call prinhd
        push '='
        call princ
        push [ebx]
        call prinum
        call newline
        add  ebx, 4
        add  eax, 4
        loop .loop
.end:   pop  ecx
        pop  ebx
        pop  eax
        ret

intsvc:
        mov ax, SYS_DATA_SEL
        mov ds, ax
        mov es, ax
        mov ss, ax
        push strintn
        call prins
        xor  eax, eax
        mov  al, cl
        push eax
        call prinum
        push ' '
        call princ
        sal  eax, 2
        lea  ebx, [intname]
        add  ebx, eax
        push [ebx]
        call prins
        call newline
        popad
        call dregs
        call dregs2
        call dstack
        call flush
        
        cli
        hlt
        
        iretd
        
intsvce:
        mov ax, SYS_DATA_SEL
        mov ss, ax
        mov ds, ax
        mov es, ax
        push strintn
        call prins
        xor  eax, eax
        mov  al, cl
        push eax
        call prinum
        push ' '
        call princ
        sal  eax, 2
        lea  ebx, [intname]
        add  ebx, eax
        push [ebx]
        call prins
        push ' '
        call princ
        push '('
        call princ
        push [esp+32]
        call prinum
        push ')'
        call princ
        call newline
        popad
        call dregs
        add  esp, 4
        call dregs2
        call dstack
        call flush
        
        cli
        hlt
        
        iretd


nullsvc:push eax
    mov  al, 0x20
        out  0xA0, al
        out  0x20, al
        call flush
    pop eax
    iretd
    
intsvc0:pushad
        mov  cl, 0
        jmp  near intsvc

ssender:  dd 0
testing:  db "TESTING\n", 0

intsvc1:
    pushad
        mov eax, [esp+32]
        cmp [ssender], eax
        je  .endss
        mov  cl, 1
        mov ax, SYS_DATA_SEL
        mov ds, ax
        mov es, ax
        mov ss, ax
        push strintn
        call prins
        xor  eax, eax
        mov  al, cl
        push eax
        call prinum
        push ' '
        call princ
        sal  eax, 2
        lea  ebx, [intname]
        add  ebx, eax
        push [ebx]
        call prins
        call newline
        popad
        call dregs
        call dregs2
        call dstack
        call flush
        pushad
        push ssingstp
        call prins
        call flush
.again:
        call inchnoi
        cmp  al, 10
        je   .doit
        cmp  al, ' '
        jle  .again
        mov  bl, al
        jmp  .again
.doit:  cmp  bl, 'g'
        jne  .end
.endss: mov  eax, [esp+40]
        and  eax, 0xFFFFFEFF
        mov  [esp+40], eax
.end:   popad
        iretd

intsvc2:
        pushad
        mov  cl, 2
        jmp  near intsvc

intsvc3:
        pushad
        mov  cl, 3
        jmp  near intsvc

intsvc4:
        pushad
        mov  cl, 4
        jmp  near intsvc

intsvc5:
        pushad
        mov  cl, 5
        jmp  near intsvc

intsvc6:
        pushad
        mov  cl, 6
        jmp  near intsvc

intsvc7:
        pushad
        mov  cl, 7
        jmp  near intsvc

intsvc8:
        pushad
        mov  cl, 8
        jmp  near intsvc   ; docs say should be intsvce

intsvc10:
        pushad
        mov  cl, 10
        jmp  near intsvce

intsvc11:
        pushad
        mov  cl, 11
        jmp  near intsvce

intsvc12:
        pushad
        mov  cl, 12
        jmp  near intsvce

intsvc13:
        pushad
        mov  cl, 13
        jmp  near intsvce

intsvc14:
        pushad
        mov  cl, 15
        jmp  near intsvce

intsvc16:
        pushad
        mov  cl, 16
        jmp  near intsvc

intsvc17:
        pushad
        mov  cl, 17
        jmp  near intsvce

strintn: db 10, "Exception ", 0
ssingstp: db 10, "ENTER for next, G for GO: ", 0

irqsvc:
        push strirqn
        call prins
        xor  eax, eax
        mov  al, cl
        push eax
        call prinum
        call newline
        mov  al, 0x20
        out  0xA0, al
        out  0x20, al
        call flush
        popad
        iretd

ranseed:
        push ebx
        mov  eax, [totalticks]
        xor  eax, [esp+8]
        xor  eax, [keyrand]
        mov  ebx, eax
        shr  ebx, 10
        xor  eax, ebx
        imul eax, 0x9174D2A9
        add  eax, 0x9841
        imul eax, [prevsd]
        mov  ebx, eax
        xor  ebx, 0x101
        mov  [prevsd], ebx
        pop  ebx
        and  eax, 0x7FFFFFFF
        ret  4

ticktime:
        mov  eax, [totalticks]
        ret

prevsd: dd 1
ticks:  dd 0
totalticks: dd 0
timnow: dd 0
quantum equ 1
qtmlft: dd quantum
irqsvc0:
        push eax
        inc  dword [totalticks]
        mov  eax, [ticks]
        inc  eax
        mov  [ticks], eax
        cmp  eax, tfreq
        jl   .not
        xor  eax, eax
        mov  [ticks], eax
        inc  dword [timnow]
.not:   mov  al, 0x20
        out  0xA0, al
        out  0x20, al
        mov  eax, [totalticks]
        sub  eax, [loutt]
        cmp  eax, 100
        jl   .nofl
;        cmp  [col], 79
;        jge  .nofl
        mov  al, [flline]
        add  al, 4
        and  al, 31
        mov  [flline], al
        mov  eax, [totalticks]
        mov  [loutt], eax
        call pinch
        mov  ah, al
        xor  al, ' '
        call pouch
        mov  al, ah
        call pouch

        call flush
.nofl:  pop  eax

        cmp byte[TSON], 0
        je .done
        dec [qtmlft]
        jg .done
        mov [qtmlft], quantum
        pushad
        push ds
        push es
        push fs
        push gs
        push ss
        mov ecx, 16
        mov esi, esp
        mov edi, [CPPCB]
        rep movsd
        
        mov eax, [CPN]
        inc eax
        cmp eax, [NP]
        jl .cont
        xor eax, eax
        
 .cont:
        mov [CPN], eax
        sal eax, 12
        add eax, PCB0
        mov [CPPCB], eax
        
        mov ecx, 16
        mov esi, [CPPCB]
        mov edi, esp
        rep movsd

        pop ss
        pop gs
        pop fs
        pop es
        pop ds
        popad
.done:   
        iretd

xchar: db ' '

inchnoi:
.loop:
        call intinch
        mov  eax, [kblin]
        or   eax, eax
        je   .loop
        call inchar
        ret

keyrand:  dd 0
oldflags: dd 0
irqsvc1:cmp [Int_Disable], byte 1
    je nullsvc
        pushad
        call intinch
        mov  ebx, [keyrand]
        imul ebx, 0x7654321
        xor  ebx, [totalticks]
        add  ebx, eax
        mov  [keyrand], ebx
        cmp  eax, 0x22E
        jne  .notcc
        mov  byte [TSON], 0
        mov  byte [run], 0
        call newline
        mov  eax, [esp+40]
        mov  esp, inistk
        push eax
        push SYS_CODE_SEL
        push mainlp
        pushad
.notcc: mov  al, 0x20
        out  0xA0, al
        out  0x20, al
        popad
        iretd
        
intinch:
        in   al, 0x64
        and  al, 1
        jz   .drop
        in   al, 0x60
        cmp  al, 0xE0
        je   .drop
        cmp  al, 0xE1
        je   .drop
        mov  ah, [kstate]
        cmp  al, 0x2A
        jne  .notsh1
        or   ah, 0x01
        mov  [kstate], ah
.drop:  
        ret
.notsh1:
        cmp  al, 0x36
        jne  .notsh2
        or   ah, 0x01
        mov  [kstate], ah
        jmp  .drop
.notsh2:
        cmp  al, 0xAA
        jne  .notsh3
        and  ah, 0xFE
        mov  [kstate], ah
        jmp  .drop
.notsh3:
        cmp  al, 0xB6
        jne  .notsh4
        and  ah, 0xFE
        mov  [kstate], ah
        jmp  .drop
.notsh4:
        cmp  al, 0x1D
        jne  .notct1
        or   ah, 0x02
        mov  [kstate], ah
        jmp  .drop
.notct1:
        cmp  al, 0x9D
        jne  .notct2
        and  ah, 0xFD
        mov  [kstate], ah
        jmp  .drop
.notct2:
        cmp  al, 0x38
        jne  .notal1
        or   ah, 0x04
        mov  [kstate], ah
        jmp  .drop
.notal1:
        cmp  al, 0xB8
        jne  .notal2
        and  ah, 0xFB
        mov  [kstate], ah
        jmp  .drop
.notal2:
        cmp  al, 0x5B
        jne  .notwn1
        or   ah, 0x08
        mov  [kstate], ah
        jmp  .drop
.notwn1:
        cmp  al, 0x5C
        jne  .notwn2
        or   ah, 0x08
        mov  [kstate], ah
        jmp  near .drop
.notwn2:
        cmp  al, 0xDB
        jne  .notwn3
        and  ah, 0xF7
        mov  [kstate], ah
        jmp  near .drop
.notwn3:
        cmp  al, 0x5D
        jne  .notmn1
        or   ah, 0x10
        mov  [kstate], ah
        jmp  near .drop
.notmn1:
        cmp  al, 0xDD
        jne  .notmn2
        and  ah, 0xEF
        mov  [kstate], ah
        jmp  near .drop
.notmn2:
        cmp  al, 0xBA
        jne  .notclk
        mov  ah, [clstat]
        xor  ah, 1
        mov  [clstat], ah
        jmp  near .drop
.notclk:
        mov  esi, eax
        mov  cl, al
        and  cl, 0x80
        jz   near .drop
        and  al, 0x7F
        xor  ah, [clstat]
        mov  cl, ah
        and  cl, 0x02
        jnz  .usectl
        mov  cl, ah
        and  cl, 0x01
        jnz  .useshf
        lea  ebx, [cplain]
        jmp  .use
.useshf:
        lea  ebx, [cshift]
        jmp  .use
.usectl:
        lea  ebx, [ccntrl]
.use:   xor  ecx, ecx
        mov  cl, al
        add  ebx, ecx        
.semtry:
        xor  eax, eax
        inc  eax
        lock xchg eax, [kbsem]
        or   eax, eax
        jnz  .semtry
        
        xor  eax, eax
        mov  al, [ebx]
        cmp  al, 10
        jne  .notnl
        inc  dword [kblin]
.notnl: cmp  al, 8
        jne  .notbs
        mov  ebx, [kbnum]
        dec  ebx
        jl   near .noadd
        mov  ecx, [kbend]
        dec  ecx
        jge  .bsok1
        mov  ecx, kbqsize
.bsok1: cmp  byte [kbqueue+ecx], 10
        je   near .noadd
        mov  [kbnum], ebx
        mov  [kbend], ecx
        mov  bl, [doecho]
        or   bl, bl
        je   .noadd
        push 8
        call princ
        push ' '
        call princ
        push 8
        call princ
        call flush
        jmp  .noadd
.notbs: mov  ebx, [kbnum]
        cmp  ebx, kbqsize
        jge  .noadd
        inc  ebx
        mov  [kbnum], ebx
        mov  ecx, [kbend]
        mov  [kbqueue+ecx], al
        inc  ecx
        cmp  ecx, kbqsize
        jle  .kbeok
        xor  ecx, ecx
.kbeok: mov  [kbend], ecx
        mov  bl, [doecho]
        or   bl, bl

;        je   .noecho    ; remove the ;

        push eax
        call prinvc
.noecho:
.noadd:
        xor  ecx, ecx
        mov  [kbsem], ecx
        call flush
        ret
.reset: mov  al, 0xFE
        out  0x64, al
        ret

irqsvc2:
        pushad
        mov  cl, 2
        jmp  near irqsvc

irqsvc3:
        pushad
        mov  cl, 3
        jmp  near irqsvc

irqsvc4:
        pushad
        mov  cl, 4
        jmp  near irqsvc

irqsvc5:
        pushad
        mov  cl, 5
        jmp  near irqsvc

irqsvc6:
        pushad
        mov  cl, 6
        jmp  near irqsvc

irqsvc7:
        pushad
        mov  cl, 7
        jmp  near irqsvc

irqsvc8:
        pushad
        mov  cl, 8
        jmp  near irqsvc

irqsvc9:
        pushad
        mov  cl, 9
        jmp  near irqsvc

irqsvc10:
        pushad
        mov  cl, 10
        jmp  near irqsvc

irqsvc11:
        pushad
        mov  cl, 11
        jmp  near irqsvc

irqsvc12:
        pushad
        mov  cl, 12
        jmp  near irqsvc

irqsvc13:
        pushad
        mov  cl, 13
        jmp  near irqsvc

irqsvc14:
        pushad
        mov  cl, 14
        jmp  near irqsvc

irqsvc15:
        pushad
        mov  cl, 15
        jmp  near irqsvc

strirqn: db "\nIRQ ", 0

reseth:
        mov   [heapcur], heapst
        ret
        
heapfl: db "\nOut of Heap Memory\n", 0
malloc:
        push  ebx
        mov   eax, [heapcur]
        mov   ebx, eax
        add   ebx, [esp+8]
        cmp   ebx, heapnd
        jl    .ok
        push  heapfl
        call  prins
        xor   eax, eax
        pop   ebx
        ret   4
.ok:    mov   [heapcur], ebx
        pop   ebx
        ret   4

palloc: push  ebx
        mov   eax, [heapcur]
        add   eax, 4095
        and   eax, 0xFFFFF000
        mov   ebx, eax
        add   ebx, 4096
        cmp   ebx, heapnd
        jl    .ok
        push  heapfl
        call  prins
        xor   eax, eax
        pop   ebx
        ret
.ok:    mov   [heapcur], ebx
        pop   ebx
        ret
        
free:
        ret   4
        
readblk: 
        pushad
.notrdy:
        mov  dx, 0x1F7
        in   al, dx
        test al, 0x40
        jz   .notrdy
        mov  ebx, [esp+40]     ; push LBA block number first
        mov  edi, [esp+36]     ; then push address to read into
        mov  dx, 0x1F2         ; Sector count port 1F2
        mov  al, 1             ; 01 = Read one sector
        out  dx, al
        inc  edx               ; Sector number port 1F3
        mov  al, bl
        out  dx, al            ; BlockNumber[7..0]
        shr  ebx, 8
        inc  edx               ; Cylinder low port 1F4
        mov  al, bl
        out  dx, al            ; BlockNumber[15..8]
        shr  ebx, 8
        inc  edx               ; Cylinder high port 1F5
        mov  al, bl
        out  dx, al            ; BlockNumber[23..16]
        shr  ebx, 8
        and  bl, 0x0F
        inc  edx               ; Drive and head port 1F6
        mov  al, 0xE0          ; E0 = LBA, Drive 0
        or   al, bl            ;  
        out  dx, al            ; bits are 111DAAAA  D=drive A=blockNumber[27..24]
        inc  edx               ; Command port 1F7
        mov  al, 0x20          ; 20 = Read with retry.
        out  dx, al
.wait:
        in   al, dx
        test al, 8             ; This means the sector buffer requires servicing.
        jz   .wait
        mov  ecx, 128          ; number of dwords
        mov  edx, 0x1F0        ; Data port
        rep  insd
        popad
        ret  8
        
writeblk: 
        pushad
.notrdy:
        mov  dx, 0x1F7
        in   al, dx
        test al, 0x40
        jz   .notrdy
        mov  ebx, [esp+40]     ; push LBA block number first
        mov  esi, [esp+36]     ; then push address to write from
        mov  dx, 0x1F2         ; Sector count port 1F2
        mov  al, 1             ; 01 = Read one sector
        out  dx, al
        inc  edx               ; Sector number port 1F3
        mov  al, bl
        out  dx, al            ; BlockNumber[7..0]
        shr  ebx, 8
        inc  edx               ; Cylinder low port 1F4
        mov  al, bl
        out  dx, al            ; BlockNumber[15..8]
        shr  ebx, 8
        inc  edx               ; Cylinder high port 1F5
        mov  al, bl
        out  dx, al            ; BlockNumber[23..16]
        shr  ebx, 8
        and  bl, 0x0F
        inc  edx               ; Drive and head port 1F6
        mov  al, 0xE0          ; E0 = LBA, Drive 0
        or   al, bl            ;  
        out  dx, al            ; bits are 111DAAAA  D=drive A=blockNumber[27..24]
        inc  edx               ; Command port 1F7
        mov  al, 0x30          ; 30 = Write with retry.
        out  dx, al
.wait:
        in   al, dx
        test al, 8             ; This means the sector buffer requires servicing.
        jz   .wait
        mov  ecx, 128          ; number of dwords
        mov  edx, 0x1F0        ; Data port
        rep  outsd
        popad
        ret  8

        
flline: db 1
flush:                  ; update cursor position
        pushad
        mov  ebx, dword [row]
        imul ebx, 80
        add  ebx, dword [col]
        mov  al, 14
        mov  dx, 0x3D4
        out  dx, al
        mov  al, bh
        inc  dx
        out  dx, al
        mov  al, 15
        dec  dx
        out  dx, al
        mov  al, bl
        inc  dx
        out  dx, al
        mov  al, 10
        dec  dx
        out  dx, al
        mov  bl, [flline]
        cmp  bl, 16
        jl   .sml
        neg  bl
        add  bl, 32
.sml:   mov  al, bl    ; cursor start scan line
        inc  dx
        out  dx, al
        mov  al, 11
        dec  dx
        out  dx, al
        inc  bl
        mov  al, bl    ; cursor end scan line
        inc  dx
        out  dx, al
        popad
        ret

pouch:  push edi
        mov  edi, dword [row]
        imul edi, 80
        add  edi, dword [col]
        shl  edi, 1
        add  edi, dword 0xB8000
        mov  byte [edi], al
        pop  edi
        ret

pinch:  push edi
        mov  edi, dword [row]
        imul edi, 80
        add  edi, dword [col]
        shl  edi, 1
        add  edi, dword 0xB8000
        mov  al, byte [edi]
        pop  edi
        ret

setcolor:
        push eax
        mov  eax, [esp+8]
        mov  [pxcol], eax
        pop  eax
        ret  4

loutt:  dd 0
princ:  cli        ; BAD
        push eax
        push edi
        mov  eax, [totalticks]
        mov  [loutt], eax
        mov al, [esp+12]
        cmp al, 10
        jne .notnl
        mov dword [col], 0
        inc dword [row]
        jmp short .fixrow
.notnl: cmp al, 8
        jne .doit
        call goback1ch
        pop edi
        pop eax
        sti        ; BAD
        ret 4
.doit:
        mov edi, dword [row]
        imul edi, 80
        add edi, dword [col]
        shl edi, 1
        add edi, dword 0xB8000
        mov byte [edi], al
        inc edi
        mov eax, [pxcol]
        mov byte [edi], al
        inc edi
.fixcol:
        inc dword [col]
        cmp dword [col], 80
        jl .done
        mov dword [col], 0
        inc dword [row]
.fixrow:
        cmp dword [row], 25
        jl .nrdone
        dec dword [row]
        push ecx
        push esi
        mov ecx, 960
        mov esi, 0xB80A0
        mov edi, 0xB8000
        rep movsd
        mov [edi], dword 0
        mov ecx, 39
        mov esi, edi
        add edi, 4
        rep movsd
        mov edi, 0xB8F00
        mov ecx, 40
.fixup: mov [edi], 0x7000700
        add edi, 4
        loop .fixup
        pop esi
        pop ecx
.nrdone:
        call flush
.done:
        pop edi
        pop eax
        sti        ; BAD
        ret 4
        
clrscr:
        pushad
        mov   ecx, 1000
        mov   eax, 0x7000700
        mov   edi, 0xB8000
.loop:  mov   [edi], eax
        add   edi, 4
        loop  .loop
        popad
        xor   eax, eax
        mov   [row], eax
        mov   [col], eax
        ret
        
goback1ch:
        push eax
        mov  eax, [col]
        cmp  eax, 0
        je   .wrap
        dec  eax
        mov  [col], eax
        pop  eax
        ret
.wrap:  mov  eax, [row]
        cmp  eax, 0
        je   .nowrap
        dec  eax
        mov  [row], eax
        mov  dword [col], 80
.nowrap:pop  eax
        ret

prin4c: push eax
        mov  eax, [esp+8]
        rol  eax, 8
        or   al, al
        je   .a
        push eax
        call princ
.a:     rol  eax, 8
        or   al, al
        je   .b
        push eax
        call princ
.b:     rol  eax, 8
        or   al, al
        je   .c
        push eax
        call princ
.c:     rol  eax, 8
        or   al, al
        je   .done
        push eax
        call princ
.done:  pop  eax
        ret
        
prinvc: push eax
        xor  eax, eax
        mov  al, [esp+8]
        cmp  al, 31
        jg   .ok1
        cmp  al, 10
        jne  .not10
        push byte '\\'
        call princ
        push byte 'n'
        call princ
        call newline
        pop  eax
        ret  4
.not10: cmp  al, 13
        jne  .not13
        push byte '\\'
        call princ
        push byte 'r'
        call princ
        pop  eax
        ret  4
.not13: push byte '^'
        call princ
        add  al, 64
        push eax
        call princ
        pop  eax
        ret  4
.ok1:   cmp  al, 126
        ja   .toobig
        push eax
        call princ
        pop  eax
        ret  4
.toobig:push byte '\\'
        call princ
        mov  ah, al
        shr  al, 6
        add  al, '0'
        push eax
        call princ
        mov  al, ah
        shr  al, 3
        and  al, 7
        add  al, 48
        push eax
        call princ
        mov  al, ah
        and  al, 7
        add  al, 48
        push eax
        call princ
        pop  eax
        ret  4

newline:
        push dword 10
        call princ
        ret

printf:
        pushad
        mov  edx, [esp+40]
        lea  ebx, [esp+44]
printflp:
        mov  byte [leadzer], 0
        mov  al, [edx]
        inc  edx
        cmp  al, 0
        je   near .end
        cmp  al, '%'
        je   .spec
        push eax
        call princ
        jmp  printflp
.spec:  xor  ecx, ecx
        xor  eax, eax
.splp:  mov  al, [edx]
        inc  edx
        cmp  al, '0'
        je   .zero
        jl   .spch
        cmp  al, '9'
        jg   .spch
.notz:  sub  al, '0'
        imul ecx, 10
        add  ecx, eax
        jmp  .splp
.zero:  test ecx, ecx
        jnz  .notz
        mov  byte [leadzer], 1
        jmp  .splp
.spch:  cmp  al, 0              ; [leadzer] says if leading zero
        je   .end               ; ecx is format size
        mov  esi, [ebx]         ; esi is the value to be printed
        add  ebx, 4
        cmp  al, 'b'
        je   percentb
        cmp  al, 'c'
        je   percentc
        cmp  al, 'C'
        je   percentcc
        cmp  al, 's'
        je   percents
        cmp  al, 'S'
        je   percentcs
        cmp  al, 'd'
        je   percentd
        cmp  al, 'x'
        je   percentx
        cmp  al, 'X'
        je   percentx
        push '%'
        call princ
        dec  edx
        jmp  printflp
.end:   lea  eax, [esp+36]
        mov  ebx, eax
        add  ebx, [eax]
        mov  ecx, [esp+32]
        mov  [ebx], ecx
        mov  [esp+32], ebx
        popad
        pop  esp
        ret

leadzer: db 0

percentc:
        push esi
        call princ
        jmp  printflp

percentcc:
        push esi
        call prinvc
        jmp  printflp

percents:
        xor  eax, eax
.loop1: mov  al, [esi]
  inc  esi
        cmp  al, 0
        je   .done1
        push eax
        call princ
        dec  ecx
        jmp  .loop1
.done1: cmp  ecx, 0
        jle  printflp
        push ' '
        call princ
        dec  ecx
        jmp  .done1

percentcs:
        xor  eax, eax
.loop1: mov  al, [esi]
        inc  esi
        cmp  al, 0
        je   .done1
        push eax
        call prinvc
        dec  ecx
        jmp  .loop1
.done1: cmp  ecx, 0
        jle  printflp
        push ' '
        call princ
        dec  ecx
        jmp  .done1
        
percentd:
        push esi
        mov  esi, ecx
        cmp  byte [leadzer], 0
        je   .notlz
        call prinumz
        jmp  printflp
.notlz: call prinumn
        jmp  printflp

percentb:
        pushad
        bsr  ebx, esi
        jnz  .pt1
        xor  ebx, ebx   
.pt1:   inc  ebx
        cmp  ecx, 0
        je   .pt2
        cmp  ebx, ecx
        jge  .pt2
        sub  ecx, ebx
        xor  edx, edx
        cmp  byte [leadzer], 0
        je   .pplz
        mov  edx, 'O'
        jmp  .plz
.pplz:  mov  edx, ' '
.plz:   push edx
        call princ
        loop .plz
.pt2:   mov  ecx, ebx
        ror  esi, cl
.pt3:   rcl  esi, 1
        jc   .pt4
        push 'O'
        jmp  .pt5
.pt4:   push '1'
.pt5:   call princ
        loop .pt3
        popad
        jmp  printflp
        
percentx:        ; esi is value; ecx is format size;
        pushad
        cmp  byte [leadzer], 0
        je   .ldsp
        mov  byte [leadzer], 'O'
        jmp  .go
.ldsp:  mov  byte [leadzer], ' '
.go:    mov  eax, ecx
        xor  ecx, ecx
        mov  ebx, esi
.pt1:   or   ebx, ebx
        je   .pt2
        shr  ebx, 4
        inc  ecx
        jmp  .pt1
.pt2:   cmp  ecx, eax    ; esi is value; ecx is number of digits in it
        jge  .pt3        ; eax is format size
        mov  ecx, eax
.pt3:   cmp  ecx, 8      ; ecx is number of digits to be printed
        jle  .pt4
        push [leadzer]
        call princ
        dec  ecx
        jmp  .pt3
.pt4:   test ecx, 0xF
        jnz  .pt5
        inc  ecx
.pt5:   mov  ebx, ecx    ; ecx is number of real digits still to be printed
        mov  ecx, 8
        sub  ecx, ebx
        shl  ecx, 2      ; cl is 4*(8 - digits to be printed)
        sal  esi, cl     ; esi is value shifted so no unneeded leading zeros
        mov  ecx, ebx    ; ecx is number of digits still to be printed
.pt6:   rol  esi, 4
        test esi, 0xF
        jnz  .pt8
        push [leadzer]
        call princ
        loop .pt6
.pt7:   rol  esi, 4
.pt8:   push esi
        call prinh
        loop .pt7
        popad
        jmp  printflp

prins:  push esi
        push eax
        mov esi, [esp+12]
.loop:  xor eax, eax
        mov al, [esi]
        inc esi
        or al, al
        jz .done
        push eax
        call princ
        jmp .loop
.done:  pop eax
        pop esi
        ret 4

prinsn:
        push esi
        push eax
        push ecx
        mov  esi, [esp+20]
        mov  ecx, [esp+16]
.loop:
        xor  eax, eax
        mov  al, [esi]
        inc  esi
        or   al, al
        jz   .done
        push eax
        call princ
        loop .loop
.done:
        pop  ecx
        pop  eax
        pop  esi
        ret  8

prind:  push eax
        mov  al, [esp+8]
        cmp  al, '0'
        jne  .norm
        mov  al, 'O'
.norm:  push eax
        call princ
        pop  eax
        ret  4

prinh:  push eax
        xor  eax, eax
        mov  al, [esp+8]
        and  al, 0x0F
        jnz  .notz
        mov  al, 'O'
        jmp  .ok
.notz:  add  al, '0'
        cmp  al, '9'
        jle  .ok
        add  al, 7
.ok:    push eax
        call princ
        pop  eax
        ret  4

prinhb:
        push eax
        xor  eax, eax
        mov  al, [esp+8]
        push eax
        shr  eax, 4
        push eax
        call prinh
        call prinh
        pop eax
        ret 4

prinhw:
        push eax
        mov eax, [esp+8]
        shr eax, 8
        push eax
        call prinhb
        mov eax, [esp+8]
        and eax, 0xff
        push eax
        call prinhb
        pop eax
        ret 4

prinhd:
        push eax
        mov eax, [esp+8]
        shr eax, 16
        push eax
        call prinhw
        mov eax, [esp+8]
        push eax
        call prinhw
        pop eax
        ret 4

pr16b:  push eax
        push ecx
        push edi
        mov  edi, [esp+16]
        push edi
        call prinhd
        push ':'
        call princ
        push ' '
        call princ
        mov  ecx, 16
.loop:  mov  al, [edi]
        push eax
        call prinhb
        push ' '
        call princ
        inc  edi
        loop .loop
        pop  edi
        pop  ecx
        pop  eax
        call newline
        ret  4
        
prinumn:    ; esi = number of digits
        pushad
        mov  byte [leadz], ' '
        jmp  short prinumx
prinumz:    ; esi = number of digits
        pushad
        mov  byte [leadz], 'O'
        jmp  short prinumx
prinum2:
        pushad
        mov  esi, 2
        mov  byte [leadz], ' '
        jmp  short prinumx
prinum3z:
        pushad
        mov  esi, 3
        mov  byte [leadz], 'O'
        jmp  short prinumx
prinuml:
        pushad
        mov  esi, 10
        mov  byte [leadz], ' '
        jmp  short prinumx
leadz:  db 0
prinum:
        pushad
        mov  esi, 1
prinumx:
        lea  edi, [.digs]
        mov  ebx, 10
        xor  ecx, ecx
        mov  eax, [esp+36]
        cmp  eax, 0
        jge  .pos
        push '-'
        call princ
        dec  esi
        neg  eax
.pos:   xor  edx, edx
        div  ebx
        cmp  dl, 0
        jne  .notz
        mov  dl, ('O'-'0')
.notz:  add  dl, '0'
        mov  [edi], dl
        inc  edi
        dec  esi
        inc  ecx
        cmp  eax, 0
        jne  .pos
.lead:  cmp  esi, 0
        jle  .out
        mov  dl, [leadz]
        mov  [edi], dl
        inc  edi
        dec  esi
        inc  ecx
        jmp  .lead
.out:   dec  edi
        mov  al, [edi]
        push eax
        call princ
        loop .out
.done:  popad
        ret  4
.digs:  db  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
        
backch: push ebx
.semtry:xor  ebx, ebx
        inc  ebx
        lock xchg ebx, [kbsem]
        or   ebx, ebx
        jnz  .semtry
        inc  dword [kbnum]
        mov  ebx, [kbbeg]
        dec  ebx
        jge  .kbbok
        mov  ebx, (kbqsize-1)
.kbbok: mov  [kbbeg], ebx
        cmp  byte [kbqueue+ebx], '\n'
        jne  .notnl
        inc  dword [kblin]
.notnl: xor  ebx, ebx
        mov  [kbsem], ebx
        pop  ebx
        ret

inchar: push  ebx
.again: mov   eax, [kblin]
        or    eax, eax
        je    .again
.semtry:xor   eax, eax
        inc   eax
        lock  xchg eax, [kbsem]
        or    eax, eax
        jnz   .semtry
        mov   eax, [kblin]
        or    eax, eax
        jnz   .cont
        mov   [kbsem], eax
        jmp   .again
.cont:  dec   [kbnum]
        mov   ebx, [kbbeg]
        xor   eax, eax
        mov   al, [kbqueue+ebx]
        inc   ebx
        cmp   ebx, kbqsize
        jl    .kbbok
        xor   ebx, ebx
.kbbok: cmp   al, 10
        jne   .notnl
        dec   dword [kblin]
.notnl: mov   [kbbeg], ebx
        xor   ebx, ebx
        mov   [kbsem], ebx
        pop   ebx
        ret        

skipws: push eax
.loop:  call inchar
        cmp  al, 3
        je   .end
        cmp  al, 32
        jle  .loop
.end:   call backch
        pop  eax
        ret

iflush: push eax
.try:   xor  eax, eax
        inc  eax
        lock xchg eax, [kbsem]
        or   eax, eax
        jnz  .try
        mov  [kbnum], eax
        mov  [kblin], eax
        mov  [kbend], eax
        mov  [kbbeg], eax
        mov  [kbsem], eax
        pop  eax
        ret
        
innum:  push edx
        push ecx
        xor  edx, edx   ; edx is the result so far
        xor  ecx, ecx   ; ecx is the sign
.skip:  call inchar
        cmp  al, '-'
        je  .negs
        cmp  al, '+'
        je  .loop
        cmp  al, '0'
        jl  .skip
        je  .initz
        cmp  al, '9'
        jg  .skip
        jmp .norm
.initz: call inchar
        cmp  al, 'x'
        je   inhexi
        jmp  .norm
.negs:  inc  ecx
.loop:  call inchar
.norm:  sub  al, '0'
        jl   .end
        cmp  al, 9
        jg   .end
        imul edx, 10
        add  edx, eax
        jmp  short .loop
.end:   call backch
        or   ecx, ecx
        je   .final
        neg  edx
.final: mov  eax, edx
        pop  ecx
        pop  edx
        ret
        
inhex:  push edx
        push ecx
        xor  edx, edx
inhexi: xor  eax, eax
        call inchar
        cmp  al, ' '
        jle  short inhexi
.loop:  cmp  al, '0'
        jl   .end
        cmp  al, 'a'
        jl   .nolc
        sub  al, 32
.nolc:  cmp  al, 'F'
        jg   .end
        cmp  al, '9'
        jle  .ok
        cmp  al, 'A'
        jl   .end
        sub  al,  16
.ok:    sub  al, '0'
        shl  edx, 4
        add  edx, eax
        call inchar
        jmp  .loop
.end:   call backch
        mov  eax, edx
        pop  ecx
        pop  edx
        ret
        
;data ------------------------------------------------------------------------
frame_buffer: dd 0
some_data: db "                                                           ", 0
winheight:  dd 0
winwidth:  dd 0

kstate: db  0
clstat: db  0
doecho: db  1
kbqueue: db 0
        loc (kbqueue+kbqsize)
        db 0, 0
kbbeg:  dd 0
kbend:  dd 0
kbnum:  dd 0
kblin:  dd 0
kbsem:  dd 0
        
;            0   1    2    3    4    5    6    7    8    9    A    B    C    D    E    F
cplain: db   0,  27, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=',   8,   9
        db 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']',  10,   0, 'a', 's'
        db 'd', 'f', 'g', 'h', 'j', 'k', 'l',  59,  39, '`',   0,  92, 'z', 'x', 'c', 'v'
        db 'b', 'n', 'm', ',', '.', '/',   0, 175,   0, ' ',   0, 129, 130, 131, 132, 133
        db 134, 135, 136, 137, 138, 211, 142, 145, 149, 146, 153, 150, 154, 151, 155, 147
        db 152, 148, 144, 127,   0,   0,   0, 139, 140,   0,   0,   0,   0,   0,   0,   0
        db   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0
        db   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0

cshift: db   0,  27, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+',   8,   9
        db 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}',  13,   0, 'A', 'S'
        db 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':',  34, '~',   0, '|', 'Z', 'X', 'C', 'V'
        db 'B', 'N', 'M', '<', '>', '?',   0, 141,   0, ' ',   0, 163, 164, 165, 166, 167
        db 168, 169, 170, 171, 172, 177, 176, 179, 183, 180, 187, 184, 188, 185, 189, 181
        db 186, 182, 178, 127,   0,   0,   0, 173, 174,   0,   0,   0,   0,   0,   0,   0
        db   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0
        db   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0

ccntrl: db   0,  27,   0,   0,   0,   0,   0,  30,   0,   0,   0,   0,  31,   0,   8,   9
        db  17,  23,   5,  18,  20,  25,  21,   9,  15,  16,  27,  29,  13,   0,   1,  19
        db   4,   6,   7,   8,  10,  11,  12,  59,  39,   0,   0,  28,  26,  24,   3,  22
        db   2,  14,  13,   0,   0,   0,   0, 209,   0,   0,   0, 197, 198, 199, 200, 201
        db 202, 203, 204, 205, 206, 143, 210, 213, 217, 214, 221, 218, 222, 219, 223, 215
        db 220, 216, 212, 127,   0,   0,   0, 207, 208,   0,   0,   0,   0,   0,   0,   0
        db   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0
        db   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0


row:    dd 0
col:    dd 0
pxcol:  dd 7

hex:     db "0123456789ABCDEF"
msgokpm: db "LOADER "
         datecode
         db " Ready.\nA20 wait ", 0
msga20:  db " loops\n", 0
failed:  db " FAILED\n", 0
msghalt: db "\nHALT\n", 0


TSON:   dd 0
CPPCB:  dd PCB0
CPN:    dd 0
NP:     dd 2
run:    dd 1

        align 8
gdtr:   dw (gdt_end-gdt-1)               ;GDT limit
        dd gdt                           ;(GDT base gets set above)

;global descriptor table (GDT)
        align 8
gdt:  
      segdesc null=1
SYS_CODE_SEL  equ ($-gdt)
      segdesc base=0, limit=0xFFFFF, gran=4096, code=1, read=1
SYS_DATA_SEL  equ ($-gdt)
      segdesc base=0, limit=0xFFFFF, gran=4096, data=1, write=1
SYS_TASK_SEL   equ ($-gdt)
      segdesc base=taskbase, limit=0xFFF, gran=1, task=1
gdt_end:


        align 8
idtr:   dw (idt_end-idt-1)             ;GDT limit
        dd idt                         ;(GDT base gets set above)

;global descriptor table (GDT)
        align 8
idt:  
      intgate seg=SYS_CODE_SEL, offset=intsvc0              ; 0
      intgate seg=SYS_CODE_SEL, offset=intsvc1              ; 1
      intgate seg=SYS_CODE_SEL, offset=intsvc2              ; 2
      intgate seg=SYS_CODE_SEL, offset=intsvc3              ; 3
      intgate seg=SYS_CODE_SEL, offset=intsvc4              ; 4
      intgate seg=SYS_CODE_SEL, offset=intsvc5              ; 5
      intgate seg=SYS_CODE_SEL, offset=intsvc6              ; 6
      intgate seg=SYS_CODE_SEL, offset=intsvc7              ; 7
      intgate seg=SYS_CODE_SEL, offset=intsvc8              ; 8
      intgate null=1                                        ; 9
      intgate seg=SYS_CODE_SEL, offset=intsvc10             ; 10
      intgate seg=SYS_CODE_SEL, offset=intsvc11             ; 11
      intgate seg=SYS_CODE_SEL, offset=intsvc12             ; 12
      intgate seg=SYS_CODE_SEL, offset=intsvc13             ; 13
      intgate seg=SYS_CODE_SEL, offset=intsvc14             ; 14
      intgate null=1                                        ; 15
      intgate seg=SYS_CODE_SEL, offset=intsvc16             ; 16
      intgate seg=SYS_CODE_SEL, offset=intsvc17             ; 17
      intgate null=1                                        ; 18
      intgate null=1                                        ; 19
      intgate null=1                                        ; 20
      intgate null=1                                        ; 21
      intgate null=1                                        ; 22
      intgate null=1                                        ; 23
      intgate null=1                                        ; 24
      intgate null=1                                        ; 25
      intgate null=1                                        ; 26
      intgate null=1                                        ; 27
      intgate null=1                                        ; 28
      intgate null=1                                        ; 29
      intgate null=1                                        ; 30
      intgate null=1                                        ; 31
      intgate seg=SYS_CODE_SEL, offset=irqsvc0              ; 32
      intgate seg=SYS_CODE_SEL, offset=irqsvc1              ; 33
      intgate seg=SYS_CODE_SEL, offset=irqsvc2              ; 34
      intgate seg=SYS_CODE_SEL, offset=irqsvc3              ; 35
      intgate seg=SYS_CODE_SEL, offset=irqsvc4              ; 36
      intgate seg=SYS_CODE_SEL, offset=irqsvc5              ; 37
      intgate seg=SYS_CODE_SEL, offset=irqsvc6              ; 38
      intgate seg=SYS_CODE_SEL, offset=irqsvc7              ; 39
      intgate seg=SYS_CODE_SEL, offset=irqsvc8              ; 40
      intgate seg=SYS_CODE_SEL, offset=irqsvc9              ; 41
      intgate seg=SYS_CODE_SEL, offset=irqsvc10             ; 42
      intgate seg=SYS_CODE_SEL, offset=irqsvc11             ; 43
      intgate seg=SYS_CODE_SEL, offset=irqsvc12             ; 44
      intgate seg=SYS_CODE_SEL, offset=irqsvc13             ; 45
      intgate seg=SYS_CODE_SEL, offset=irqsvc14             ; 46
      intgate seg=SYS_CODE_SEL, offset=irqsvc15             ; 47
idt_end:

      db 0xBA, 0xBA


