; =============================================================================
;
; Litos - Console
;
; =============================================================================
CODE_SECTION 32
; -----------------------------------------------------------------------------
; Initialize list of consoles
; -----------------------------------------------------------------------------
; ------------- Prepare registers
ConInit: mov ebx,ConList ; EBX <- list of console interfaces
mov ecx,CONSOLE_NUM ; ECX <- number of consoles
; ------------- Set write functions
ConInit2: mov eax,ConWriteEmpty ; EAX <- write function
mov [ebx+CON_Write],eax ; set write function
mov [ebx+CON_MWrite],eax ; set multi-write function
mov [ebx+CON_2+CON_Write],eax ; set write2 function
mov [ebx+CON_2+CON_MWrite],eax ; set multi-write2 function
; ------------- Set read function
add eax,byte ConReadEmpty-ConWriteEmpty ; EAX <- read func.
mov [ebx+CON_Read],eax ; set read function
mov [ebx+CON_2+CON_Read],eax ; set read2 function
; ------------- Set key-read function
add eax,byte ConKReadEmpty-ConReadEmpty ; EAX <- kread fnc
mov [ebx+CON_KRead],eax ; set key-read function
mov [ebx+CON_2+CON_KRead],eax ; set key-read2 function
; ------------- Set multi-read function
add eax,byte ConMReadEmpty-ConKReadEmpty ; EAX <- mread fnc
mov [ebx+CON_MRead],eax ; set multi-read function
mov [ebx+CON_2+CON_MRead],eax ; set multi-read2 function
; ------------- Next console interface
add ebx,CONSOLE_size ; EBX <- next console interface
loop ConInit2 ; next console interface
; ------------- Empty read/write functions
ConReadEmpty: mov al,0 ; invalid character
stc ; set error flag
ConWriteEmpty: ret
ConKReadEmpty: xor eax,eax ; EAX <- 0, no read data
stc ; set error flag
ret
ConMReadEmpty: xor ecx,ecx ; ECX <- 0, no read data
stc ; set error flag
ret
; -----------------------------------------------------------------------------
; Write to specific consoles
; -----------------------------------------------------------------------------
; INPUT: AL = character to output
; EDX = mask of consoles (1=output to console)
; -----------------------------------------------------------------------------
; ------------- Push registers
ConWriteMask: push ebx ; push EBX
push ecx ; push ECX
push edx ; push EDX
; ------------- Prepare first console (-> ECX)
bsf ecx,edx ; ECX <- index of first console
jz ConWriteMask8 ; no console found
shr edx,cl ; EDX <- destroy unneeded bits
mov ecx,[ConListAddr+ecx*4-4] ; ECX <- first console-1
; ------------- Check if use this console
ConWriteMask2: add ecx,CONSOLE_size ; ECX <- next console interface
shr edx,1 ; shift mask of consoles
jnc ConWriteMask6 ; don't use this console
; ------------- Output to the console
mov ebx,[ecx+CON_DataWrite] ; EBX <- private data
call dword [ecx+CON_Write] ; output data
; ------------- Output2 to the console
mov ebx,[ecx+CON_2+CON_DataWrite] ; EBX <- private data 2
call dword [ecx+CON_2+CON_Write] ; output2 data
; ------------- Next console interface
or edx,edx ; any other console?
ConWriteMask6: jnz ConWriteMask2 ; next console interface
; ------------- Pop registers
ConWriteMask8: pop edx ; pop EDX
pop ecx ; pop ECX
pop ebx ; pop EBX
ret
; -----------------------------------------------------------------------------
; Write to all opened consoles
; -----------------------------------------------------------------------------
; INPUT: AL = character to output
; -----------------------------------------------------------------------------
ConWriteAll: push edx ; push EDX
mov edx,[ConOpenMask] ; EDX <- mask of opened consoles
call ConWriteMask ; output to consoles
pop edx ; pop EDX
ret
; -----------------------------------------------------------------------------
; Write to active consoles (with user focus)
; -----------------------------------------------------------------------------
; INPUT: AL = character to output
; -----------------------------------------------------------------------------
ConWriteAct: push edx ; push EDX
mov edx,[ConActMask] ; EDX <- mask of active consoles
call ConWriteMask ; output to consoles
pop edx ; pop EDX
ret
; -----------------------------------------------------------------------------
; Write to selected consoles of the task
; -----------------------------------------------------------------------------
; INPUT: AL = character to output
; -----------------------------------------------------------------------------
ConWrite: push edx ; push EDX
CURRENT edx ; EDX <- current task
mov edx,[edx+TASK_ConOutMask] ; EDX <- output consoles
call ConWriteMask ; output to consoles
pop edx ; pop EDX
ret
; -----------------------------------------------------------------------------
; Multi-write to specific consoles
; -----------------------------------------------------------------------------
; INPUT: EAX = output buffer
; ECX = number of bytes
; EDX = mask of consoles (1=output to console)
; -----------------------------------------------------------------------------
; ------------- Push registers
ConMWriteMask: push ebx ; push EBX
push edx ; push EDX
push esi ; push ESI
; ------------- Prepare first console (-> ESI)
bsf esi,edx ; ESI <- index of first console
jz ConMWriteMask8 ; no console found
xchg ecx,esi ; ECX <- index, ESI <- push ECX
shr edx,cl ; EDX <- destroy unneeded bits
xchg ecx,esi ; ECX <- pop ECX, ESI <- index
mov esi,[ConListAddr+esi*4-4] ; ESI <- first console-1
; ------------- Check if use this console
ConMWriteMask2: add esi,CONSOLE_size ; ESI <- next console interface
shr edx,1 ; shift mask of consoles
jnc ConMWriteMask6 ; don't use this console
; ------------- Output to the console
mov ebx,[esi+CON_DataMWrite] ; EBX <- private data
call dword [esi+CON_MWrite] ; output data
; ------------- Output2 to the console
mov ebx,[esi+CON_2+CON_DataMWrite] ; ECX <- private data 2
call dword [esi+CON_2+CON_MWrite] ; output2 data
; ------------- Next console interface
or edx,edx ; any other console?
ConMWriteMask6: jnz ConMWriteMask2 ; next console interface
; ------------- Pop registers
ConMWriteMask8: pop esi ; pop ESI
pop edx ; pop EDX
pop ebx ; pop EBX
ret
; -----------------------------------------------------------------------------
; Multi-write to all opened consoles
; -----------------------------------------------------------------------------
; INPUT: EAX = output buffer
; ECX = number of bytes
; -----------------------------------------------------------------------------
ConMWriteAll: push edx ; push EDX
mov edx,[ConOpenMask] ; EDX <- mask of opened consoles
call ConMWriteMask ; multi-output to consoles
pop edx ; pop EDX
ret
; -----------------------------------------------------------------------------
; Multi-write to active consoles (with user focus)
; -----------------------------------------------------------------------------
; INPUT: EAX = output buffer
; ECX = number of bytes
; -----------------------------------------------------------------------------
ConMWriteAct: push edx ; push EDX
mov edx,[ConActMask] ; EDX <- mask of active consoles
call ConMWriteMask ; multi-output to consoles
pop edx ; pop EDX
ret
; -----------------------------------------------------------------------------
; Multi-write to selected consoles of the task
; -----------------------------------------------------------------------------
; INPUT: EAX = output buffer
; ECX = number of bytes
; -----------------------------------------------------------------------------
ConMWrite: push edx ; push EDX
CURRENT edx ; EDX <- current task
mov edx,[edx+TASK_ConOutMask] ; EDX <- output consoles
call ConMWriteMask ; multi-output to consoles
pop edx ; pop EDX
ret
; -----------------------------------------------------------------------------
; Read character from specific consoles
; -----------------------------------------------------------------------------
; INPUT: EDX = mask of consoles (1=input from console)
; OUTPUT: AL = character (if NC, else AL = 0)
; CY = no character ready (AL = 0 if CY)
; -----------------------------------------------------------------------------
; ------------- Push registers
ConReadMask: push ebx ; push EBX
push ecx ; push ECX
push edx ; push EDX
; ------------- Prepare first console (-> EBX)
mov al,0 ; AL <- 0, no character
bsf ecx,edx ; ECX <- index of first console
jz ConReadMask7 ; no console found
shr edx,cl ; EDX <- destroy unneeded bits
mov ecx,[ConListAddr+ecx*4-4] ; ECX <- first console-1
; ------------- Check if use this console
ConReadMask2: add ecx,CONSOLE_size ; ECX <- next console interface
shr edx,1 ; shift mask of consoles
jnc ConReadMask6 ; don't use this console
; ------------- Input from the console
mov ebx,[ecx+CON_DataRead] ; EBX <- private data
call dword [ecx+CON_Read] ; input data
jnc ConReadMask8 ; character found
; ------------- Input2 from the console
mov ebx,[ecx+CON_2+CON_DataRead] ; EBX <- private data 2
call dword [ecx+CON_2+CON_Read] ; input2 data
jnc ConReadMask8 ; character found
; ------------- Next console interface
or edx,edx ; any other console?
ConReadMask6: jnz ConReadMask2 ; next console interface
ConReadMask7: stc ; set error flag
; ------------- Pop registers
ConReadMask8: pop edx ; pop EDX
pop ecx ; pop ECX
pop ebx ; pop EBX
ret
; -----------------------------------------------------------------------------
; Read character from all opened consoles
; -----------------------------------------------------------------------------
; OUTPUT: AL = character (if NC, else AL = 0)
; CY = no character ready (AL = 0 if CY)
; -----------------------------------------------------------------------------
ConReadAll: push edx ; push EDX
mov edx,[ConOpenMask] ; EDX <- mask of opened consoles
call ConReadMask ; input from consoles
pop edx ; pop EDX
ret
; -----------------------------------------------------------------------------
; Read character from active consoles (with user focus)
; -----------------------------------------------------------------------------
; OUTPUT: AL = character (if NC, else AL = 0)
; CY = no character ready (AL = 0 if CY)
; -----------------------------------------------------------------------------
ConReadAct: push edx ; push EDX
mov edx,[ConActMask] ; EDX <- mask of active consoles
call ConReadMask ; input from consoles
pop edx ; pop EDX
ret
; -----------------------------------------------------------------------------
; Read character from selected consoles of the task
; -----------------------------------------------------------------------------
; OUTPUT: AL = character (if NC, else AL = 0)
; CY = no character ready (AL = 0 if CY)
; -----------------------------------------------------------------------------
ConRead: push edx ; push EDX
CURRENT edx ; EDX <- current task
mov edx,[edx+TASK_ConInMask] ; EDX <- input consoles
call ConReadMask ; input from consoles
pop edx ; pop EDX
ret
; -----------------------------------------------------------------------------
; Read key code from specific consoles
; -----------------------------------------------------------------------------
; INPUT: EDX = mask of consoles (1=input from console)
; OUTPUT: EAX = key code (if NC, else EAX = 0)
; CY = no key code ready (EAX = 0 if CY)
; -----------------------------------------------------------------------------
; ------------- Push registers
ConKReadMask: push ebx ; push EBX
push ecx ; push ECX
push edx ; push EDX
; ------------- Prepare first console (-> EBX)
xor eax,eax ; EAX <- 0, no key code
bsf ecx,edx ; ECX <- index of first console
jz ConKReadMask7 ; no console found
shr edx,cl ; EDX <- destroy unneeded bits
mov ecx,[ConListAddr+ecx*4-4] ; ECX <- first console-1
; ------------- Check if use this console
ConKReadMask2: add ecx,CONSOLE_size ; ECX <- next console interface
shr edx,1 ; shift mask of consoles
jnc ConKReadMask6 ; don't use this console
; ------------- Input from the console
mov ebx,[ecx+CON_DataKRead] ; EBX <- private data
call dword [ecx+CON_KRead] ; input data
jnc ConKReadMask8 ; character found
; ------------- Input2 from the console
mov ebx,[ecx+CON_2+CON_DataKRead] ; EBX <- private data 2
call dword [ecx+CON_2+CON_KRead] ; input2 data
jnc ConKReadMask8 ; character found
; ------------- Next console interface
or edx,edx ; any other console?
ConKReadMask6: jnz ConKReadMask2 ; next console interface
ConKReadMask7: stc ; set error flag
; ------------- Pop registers
ConKReadMask8: pop edx ; pop EDX
pop ecx ; pop ECX
pop ebx ; pop EBX
ret
; -----------------------------------------------------------------------------
; Read key code from all opened consoles
; -----------------------------------------------------------------------------
; OUTPUT: EAX = key code (if NC, else EAX = 0)
; CY = no key code ready (EAX = 0 if CY)
; -----------------------------------------------------------------------------
ConKReadAll: push edx ; push EDX
mov edx,[ConOpenMask] ; EDX <- mask of opened consoles
call ConKReadMask ; input from consoles
pop edx ; pop EDX
ret
; -----------------------------------------------------------------------------
; Read key code from active consoles (with user focus)
; -----------------------------------------------------------------------------
; OUTPUT: EAX = key code (if NC, else EAX = 0)
; CY = no key code ready (EAX = 0 if CY)
; -----------------------------------------------------------------------------
ConKReadAct: push edx ; push EDX
mov edx,[ConActMask] ; EDX <- mask of active consoles
call ConKReadMask ; input from consoles
pop edx ; pop EDX
ret
; -----------------------------------------------------------------------------
; Read key code from selected consoles of the task
; -----------------------------------------------------------------------------
; OUTPUT: EAX = key code (if NC, else EAX = 0)
; CY = no key code ready (EAX = 0 if CY)
; -----------------------------------------------------------------------------
ConKRead: push edx ; push EDX
CURRENT edx ; EDX <- current task
mov edx,[edx+TASK_ConInMask] ; EDX <- input consoles
call ConKReadMask ; input from consoles
pop edx ; pop EDX
ret
; -----------------------------------------------------------------------------
; Multi-read from specific consoles
; -----------------------------------------------------------------------------
; INPUT: EAX = input buffer
; ECX = buffer size
; EDX = mask of consoles (1=input from console)
; OUTPUT: ECX = read bytes (if NC, else ECX = 0)
; CY = no character ready (ECX = 0 if CY)
; -----------------------------------------------------------------------------
; ------------- Push registers
ConMReadMask: push ebx ; push EBX
push edx ; push EDX
push esi ; push ESI
push edi ; push EDI
mov edi,ecx ; EDI <- push ECX (buffer size)
; ------------- Prepare first console (-> ESI)
bsf ecx,edx ; ECX <- index of first console
jz ConMReadMask7 ; no console found
shr edx,cl ; EDX <- destroy unneeded bits
mov esi,[ConListAddr+ecx*4-4] ; ESI <- first console-1
; ------------- Check if use this console
ConMReadMask2: add esi,CONSOLE_size ; ESI <- next console interface
shr edx,1 ; shift mask of consoles
jnc ConMReadMask6 ; don't use this console
; ------------- Input from the console
mov ebx,[esi+CON_DataMRead] ; EBX <- private data
mov ecx,edi ; ECX <- buffer size
call dword [esi+CON_MRead] ; input data
jnc ConMReadMask8 ; character found
; ------------- Input2 from the console
mov ebx,[esi+CON_2+CON_DataMRead] ; EBX <- private data 2
mov ecx,edi ; ECX <- buffer size
call dword [esi+CON_2+CON_MRead] ; input2 data
jnc ConMReadMask8 ; character found
; ------------- Next console interface
or edx,edx ; any other console?
ConMReadMask6: jnz ConMReadMask2 ; next console interface
ConMReadMask7: xor ecx,ecx ; ECX <- 0, no data
stc ; set error flag
; ------------- Pop registers
ConMReadMask8: pop edi ; pop EDI
pop esi ; pop ESI
pop edx ; pop EDX
pop ebx ; pop EBX
ret
; -----------------------------------------------------------------------------
; Nulti-read from all opened consoles
; -----------------------------------------------------------------------------
; INPUT: EAX = input buffer
; ECX = buffer size
; OUTPUT: ECX = read bytes (if NC, else ECX = 0)
; CY = no character ready (ECX = 0 if CY)
; -----------------------------------------------------------------------------
ConMReadAll: push edx ; push EDX
mov edx,[ConOpenMask] ; EDX <- mask of opened consoles
call ConMReadMask ; multi-read from consoles
pop edx ; pop EDX
ret
; -----------------------------------------------------------------------------
; Multi-read from active consoles (with user focus)
; -----------------------------------------------------------------------------
; INPUT: EAX = input buffer
; ECX = buffer size
; OUTPUT: ECX = read bytes (if NC, else ECX = 0)
; CY = no character ready (ECX = 0 if CY)
; -----------------------------------------------------------------------------
ConMReadAct: push edx ; push EDX
mov edx,[ConActMask] ; EDX <- mask of active consoles
call ConMReadMask ; input from consoles
pop edx ; pop EDX
ret
; -----------------------------------------------------------------------------
; Multi-read from selected consoles of the task
; -----------------------------------------------------------------------------
; INPUT: EAX = input buffer
; ECX = buffer size
; OUTPUT: ECX = read bytes (if NC, else ECX = 0)
; CY = no character ready (ECX = 0 if CY)
; -----------------------------------------------------------------------------
ConMRead: push edx ; push EDX
CURRENT edx ; EDX <- current task
mov edx,[edx+TASK_ConInMask] ; EDX <- input consoles
call ConMReadMask ; input from consoles
pop edx ; pop EDX
ret
; -----------------------------------------------------------------------------
; Register console function (for internal use only)
; -----------------------------------------------------------------------------
; INPUT: EAX = function
; EBX = private data
; CL = offset of function entry in console interface
; EDX = mask of consoles (1=register to this console)
; -----------------------------------------------------------------------------
; ------------- Push registers
ConRegReg: push ecx ; push ECX
push edx ; push EDX
; ------------- Prepare registers
movzx ecx,cl ; ECX <- offset of data entry
add ecx,ConList-CONSOLE_size ; ECX <- list of consoles
; ------------- Test if use this console
ConRegReg2: add ecx,CONSOLE_size ; ECX <- next console interface
shr edx,1 ; shift mask of consoles
jnc ConRegReg6 ; don't register this console
; ------------- Register console
mov [ecx+CON_DataWrite-CON_Write],ebx ; private data
mov [ecx],eax ; set function
; ------------- Next console interface
ConRegReg6: jnz ConRegReg2 ; next console interface
; ------------- Pop registers
ConRegReg8: pop edx ; pop EDX
pop ecx ; pop ECX
ret
; -----------------------------------------------------------------------------
; Register console function
; -----------------------------------------------------------------------------
; INPUT: EAX = function
; EBX = private data
; EDX = mask of consoles (1=register to this console)
; -----------------------------------------------------------------------------
; ------------- Macro - register console function
; %1 = offset of function entry
%macro CONREG 1
push ecx ; push ECX
mov cl,%1 ; CL <- offset of function entry
call ConRegReg ; register function
pop ecx ; pop ECX
ret
%endmacro
; ------------- Register console output function
ConRegWrite: CONREG CON_Write
; ------------- Register console output2 function (echo)
ConRegWrite2: CONREG (CON_2+CON_Write)
; ------------- Register console multi-output function
ConRegMWrite: CONREG CON_MWrite
; ------------- Register console multi-output2 function (echo)
ConRegMWrite2: CONREG (CON_2+CON_MWrite)
; ------------- Register console input function
ConRegRead: CONREG CON_Read
; ------------- Register console input2 function (alternate input)
ConRegRead2: CONREG (CON_2+CON_Read)
; ------------- Register console key code input function
ConRegKRead: CONREG CON_KRead
; ------------- Register console key code input2 function
ConRegKRead2: CONREG (CON_2+CON_KRead)
; ------------- Register console multi-input function
ConRegMRead: CONREG CON_MRead
; ------------- Register console multi-input2 function (alternate input)
ConRegMRead2: CONREG (CON_2+CON_MRead)
; -----------------------------------------------------------------------------
; Unregister console function (for internal use only)
; -----------------------------------------------------------------------------
; INPUT: EAX = function
; CL = offset of function entry in console interface
; EDX = mask of consoles (1=register to this console)
; NOTES: Don't use ConRegReg instead due to untimely order of filling entries.
; -----------------------------------------------------------------------------
; ------------- Push registers
ConUnregReg: push ecx ; push ECX
push edx ; push EDX
; ------------- Prepare registers
movzx ecx,cl ; ECX <- offset of data entry
add ecx,ConList-CONSOLE_size ; ECX <- list of consoles
; ------------- Test if use this console
ConUnregReg2: add ecx,CONSOLE_size ; ECX <- next console interface
shr edx,1 ; shift mask of consoles
jnc ConUnregReg6 ; don't register this console
; ------------- Register console
mov [ecx],eax ; set function
; ------------- Next console interface
ConUnregReg6: jnz ConUnregReg2 ; next console interface
; ------------- Pop registers
ConUnregReg8: pop edx ; pop EDX
pop ecx ; pop ECX
ret
; -----------------------------------------------------------------------------
; Unregister console function
; -----------------------------------------------------------------------------
; INPUT: EDX = mask of consoles (1=register to this console)
; -----------------------------------------------------------------------------
; ------------- Macro - unregister console function
; %1 = empty function, %2 = offset of function entry
%macro CONUNREG 2
push eax ; push EAX
push ecx ; push ECX
mov eax,%1 ; EAX <- empty function
mov cl,%2 ; CL <- offset of function entry
call ConUnregReg ; unregister function
pop ecx ; pop ECX
pop eax ; pop EAX
ret
%endmacro
; ------------- Unregister console output function
ConUnregWrite: CONUNREG ConWriteEmpty, CON_Write
; ------------- Unregister console output2 function (echo)
ConUnregWrite2: CONUNREG ConWriteEmpty, (CON_2+CON_Write)
; ------------- Unregister console multi-output function
ConUnregMWrite: CONUNREG ConWriteEmpty, CON_MWrite
; ------------- Unregister console output2 function (echo)
ConUnregMWrite2:CONUNREG ConWriteEmpty, (CON_2+CON_MWrite)
; ------------- Unregister console input function
ConUnregRead: CONUNREG ConReadEmpty, CON_Read
; ------------- Unregister console input2 function (alternate input)
ConUnregRead2: CONUNREG ConReadEmpty, (CON_2+CON_Read)
; ------------- Unregister console key code input function
ConUnregKRead: CONUNREG ConKReadEmpty, CON_KRead
; ------------- Unregister console key code input2 function (alternate input)
ConUnregKRead2: CONUNREG ConKReadEmpty, (CON_2+CON_KRead)
; ------------- Unregister console multi-input function
ConUnregMRead: CONUNREG ConMReadEmpty, CON_MRead
; ------------- Unregister console multi-input2 function (alternate input)
ConUnregMRead2: CONUNREG ConMReadEmpty, (CON_2+CON_MRead)
; -----------------------------------------------------------------------------
; Data
; -----------------------------------------------------------------------------
DATA_SECTION
; ------------- Active consoles (with user input focus)
align 4,db 0
ConActMask: dd B0 ; mask of active consoles
; ------------- Open consoles
align 4, db 0
ConOpenMask: dd B0+B1+B2+B3+B4+B5+B6+B7+B8+B9 ; mask of open consoles
; ------------- Pointers to console interfaces (+ one invalid pointer)
align 4, db 0
dd ConList - CONSOLE_size ; first console - 1
ConListAddr:
%assign CONINX 0
%rep CONSOLE_NUM
dd ConList + CONSOLE_size*CONINX
%assign CONINX CONINX+1
%endrep
; -----------------------------------------------------------------------------
; Uninitialized data
; -----------------------------------------------------------------------------
BSS_SECTION
; ------------- List of console interfaces
align 8, resb 1
ConList: resb CONSOLE_size*CONSOLE_NUM ; list of console interfaces
|