This commit is contained in:
julianb0 2019-08-21 19:10:26 +02:00
parent 8ec0bffa53
commit aa192abe6d
No known key found for this signature in database
GPG Key ID: 9C7ACF0C053FB8A1
16 changed files with 4337 additions and 129 deletions

View File

@ -27,7 +27,7 @@ b_text = TemporaryFile(mode="w+b")
lst_instrs = open(os.path.join(sys.path[0], "instrs.lst"))
main_src = open(sys.argv[1])
source = open(sys.argv[1])
b_out = open(sys.argv[3], "wb")
b_sym = open(sys.argv[4], "w")
@ -42,7 +42,6 @@ def leave(i):
b_sym.close()
b_data.close()
b_text.close()
main_src.close()
lst_instrs.close()
sys.exit(i)
@ -124,59 +123,6 @@ def arith_eval(s):
#-------------------------------------------------------------------------------
inc_depth = 0
inc_depth_max = 16
# Quickly goes through source file and resolves "include" directives ONLY
def do_includes(fi):
global inc_depth
global pcurfile
for _, line in enumerate(fi):
line = line.rstrip()
tok = line.split(None, 1)
if len(tok) == 0:
continue
if tok[0] == "include":
if len(tok) == 1:
print("Missing parameter for include directive")
leave(1)
if tok[1][0] not in "'\"" or tok[1][-1] != tok[1][0]:
print("Invalid format for include directive: {}".format(line))
leave(1)
old_curf = pcurfile
pcurfile = tok[1][1:-1]
try:
new_fi = open(pcurfile, "r")
except:
print("Couldn't open file: {}".format(line))
leave(1)
inc_depth += 1
if inc_depth >= inc_depth_max:
print("Maximal include depth reached: {}".format(line))
leave(1)
source.write("$file: {}:\n".format(pcurfile.replace(' ', '')))
do_includes(new_fi)
pcurfile = old_curf
source.write("$file: {}:\n".format(pcurfile.replace(' ', '')))
else:
source.write("{}\n".format(line))
inc_depth -= 1
#-------------------------------------------------------------------------------
def parse():
global ptext
global pcurfile
@ -191,10 +137,14 @@ def parse():
if len(line) == 0:
continue
# len("$file: ") == 7
if len(line) > 7 and line[:7] == "$file: ":
pcurfile = line[7:]
continue
if line[0] == '#':
tok = line.split()
if len(tok) < 3:
print("Invalid # directive: {}".format(line))
leave(-1)
pcurfile = tok[2][1:-1]
quote = False
for i in range(len(line)):
@ -371,31 +321,13 @@ def parse_preproc(line):
#-------------------------------------------------------------------------------
fmts = {
"r": 0b00000000,
"m_r": 0b00100000,
"m_rr": 0b01000000,
"m_rriw": 0b01100000,
"m_rrid": 0b10000000,
"m_rrii": 0b10100000,
"m_riq": 0b11000000,
"imm8": 0b11100001,
"imm16": 0b11100010,
"imm32": 0b11100100,
"imm64": 0b11101000,
"r": 0b00000000, "m_r": 0b00100000, "m_rr": 0b01000000,
"m_rriw": 0b01100000, "m_rrid": 0b10000000, "m_rrii": 0b10100000,
"m_riq": 0b11000000, "imm8": 0b11100001, "imm16": 0b11100010,
"imm32": 0b11100100, "imm64": 0b11101000,
}
pref2len = {
"b" : 1,
"w" : 2,
"d" : 4,
"l" : 4,
"q" : 8,
}
i_aliases = {
"inc_2" : "add_2",
#"dec_2" : "sub_2",
}
pref2len = { "b" : 1, "w" : 2, "d" : 4, "l" : 4, "q" : 8 }
def parse_instr(line):
if line == None or len(line) == 0:
@ -423,9 +355,6 @@ def parse_instr(line):
instr_name += "_{}".format(len(tok))
if instr_name in i_aliases:
instr_name = i_aliases[instr_name]
#
# Parse operands
#
@ -778,7 +707,6 @@ def genout():
#-------------------------------------------------------------------------------
parse_lst_instrs()
do_includes(main_src)
parse()
gentext()
genout()

View File

@ -8,12 +8,11 @@ KSDIR=../vm/ob
KPDIR=../vm/ob
KSRC = $(shell ls *.k)
KPPC = $(patsubst %.k,$(KODIR)/%.ppc,$(KSRC))
KCOM = $(patsubst %.k,$(KODIR)/%.com,$(KSRC))
$(KODIR)/%.com: %.k
@cpp -I. -x assembler-with-cpp $< > $(patsubst %.k,$(KODIR)/%.ppc,$<)
@../as/k-as.py $(patsubst %.k,$(KODIR)/%.ppc,$<) 0x100000 $@ $(patsubst %.k,$(KSDIR)/%.sym,$<)
@cpp -I. -x assembler-with-cpp $< > $(KSDIR)/$<
@../as/k-as.py $(KSDIR)/$< 0x100000 $@ $(patsubst %.k,$(KSDIR)/%.sym,$<)
dos: $(KCOM)

View File

@ -243,7 +243,7 @@ main:
push b[rax+3], rcx, w[rax+6]
call printf, .datefmt
inc rsp, 40
add rsp, 40
jmp .print_prompt
@ -286,7 +286,7 @@ main:
push b[rax], b[rax+1], b[rax+2]
call printf, .timefmt
inc rsp, 24
add rsp, 24
jmp .print_prompt
@ -338,7 +338,7 @@ main:
.exec_not_found:
push argv0
call printf, .enf_errmsg
inc rsp, 8
add rsp, 8
jmp .print_prompt
@ -347,7 +347,7 @@ main:
.file_not_found:
push q[argv1pos], argv0
call printf, .fnf_errmsg
inc rsp, 16
add rsp, 16
jmp .print_prompt
@ -356,7 +356,7 @@ main:
.empty_file:
push q[argv1pos], argv0
call printf, .ef_errmsg
inc rsp, 16
add rsp, 16
jmp .print_prompt
@ -365,7 +365,7 @@ main:
.couldnt_open:
push q[argv1pos], argv0
call printf, .cno_errmsg
inc rsp, 16
add rsp, 16
jmp .print_prompt
@ -374,7 +374,7 @@ main:
.couldnt_remove:
push q[argv1pos], argv0
call printf, .cne_errmsg
inc rsp, 16
add rsp, 16
jmp .print_prompt
@ -383,7 +383,7 @@ main:
.couldnt_read:
push q[argv1pos], argv0
call printf, .cnr_errmsg
inc rsp, 16
add rsp, 16
jmp .print_prompt

View File

@ -30,7 +30,7 @@ doprnt:
call .doput, b[r12]
inc r12, 1
inc r12
jmp .print_regular
.check_modf:
@ -40,7 +40,7 @@ doprnt:
; we did find a modifier / '%'
mov rax, b[r12+1]
inc r12, 2
add r12, 2
beq rax, 's', .modf_s
beq rax, 'c', .modf_c
@ -57,7 +57,7 @@ doprnt:
.modf_s:
; get string address
mov r13, q[r14]
inc r14, 8
add r14, 8
bzr r13, .nullstring
@ -72,7 +72,7 @@ doprnt:
.modf_c:
call .doput, q[r14]
inc r14, 8
add r14, 8
jmp .main_loop
@ -104,7 +104,7 @@ doprnt:
; assume modifier already set up ax2
call itoa, rsp, q[r14]
inc r14, 8
add r14, 8
.print_itoa_buf:
movzx ax0, b[r13]
@ -116,7 +116,7 @@ doprnt:
jmp .print_itoa_buf
.pib_end_loop:
inc rsp, 80
add rsp, 80
jmp .main_loop
.modf_percent:

View File

@ -47,11 +47,11 @@ ltostr:
blt 9, rdx, .nondec ; rdx > 9 ?
inc rdx, '0'
add rdx, '0'
jmp .next
.nondec:
inc rdx, 55 ; 'A' - 10
add rdx, 55 ; 'A' - 10
.next:
mov b[ax0], rdx

View File

@ -80,7 +80,7 @@ strtoq:
; if not, leave rax = 0 and *rdx = 'x'
bne ax1, 16, .done
; else
inc rdx, 1
inc rdx
jmp .main_loop
.parsed_0b:
@ -149,7 +149,7 @@ strtoq:
blteu ax1, rcx, .done
mul rax, ax1
inc rax, rcx
add rax, rcx
jmp .main_loop
.done:

View File

@ -36,7 +36,7 @@ DaysInYear:
jrcxnz .end
.leap:
inc rax, 1
inc rax
.end:
ret

View File

@ -29,7 +29,7 @@ ScreenOfDeath:
.do_print:
push r14, r12
call printf, .scr2
inc rsp, 24
add rsp, 24
call dumprf, r14
prn 10

View File

@ -167,27 +167,27 @@ DefaultTrapHandler:
; Disk API
;
.handle_FindFirst:
inc ax0, r12
add ax0, r12
call DISK.FindFirst
jmp .fini.savecx
.handle_FindNext:
inc ax0, r12
add ax0, r12
call DISK.FindNext
jmp .fini.savecx
.handle_OpenFile:
inc ax0, r12
add ax0, r12
call DISK.OpenFile
jmp .fini
.handle_CreateFile:
inc ax0, r12
add ax0, r12
call DISK.CreateFile
jmp .fini
.handle_RemoveFile:
inc ax0, r12
add ax0, r12
call DISK.RemoveFile
jmp .fini
@ -196,7 +196,7 @@ DefaultTrapHandler:
jmp .fini
.handle_ReadFile:
inc ax1, r12
add ax1, r12
call DISK.ReadFile
jmp .fini

View File

@ -1,7 +1,7 @@
; The OS/K Team licenses this file to you under the MIT license.
; See the LICENSE file in the project root for more information.
N := 11
#define N 11
.handle_DIR:
push rbp
@ -34,7 +34,7 @@ N := 11
jraxz .end
mov r15, rcx ; file size
inc r14, rcx
add r14, rcx
; directory?
bnz rdx, .is_dir
@ -102,7 +102,7 @@ N := 11
push r15, rax
call printf, .bytesstr
inc rsp, 16
add rsp, 16
.prepare_next:
; go find next entry
@ -117,11 +117,11 @@ N := 11
push r14, rax, rdx
call printf, .endstr0
inc rsp, 24
add rsp, 24
push r13, r12
call printf, .endstr1
inc rsp, 16
add rsp, 16
pop r15, r14
pop r13, r12
@ -134,8 +134,8 @@ N := 11
inc r13
; use printf instead of print
; because it returns # of printed
; characters
; because it returns the # of
; printed characters
call printf, .buf
blte N, rax, .dir_no_pad
@ -160,3 +160,5 @@ N := 11
.bytesstr = "%d kilobytes + %d bytes"
; .bytesstr = "%dMB + %dKB + %dB" # too soon
#undef N

1655
vm/ob/command.k Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1206,7 +1206,7 @@ main:
; The OS/K Team licenses this file to you under the MIT license.
; See the LICENSE file in the project root for more information.
N := 11
.handle_DIR:
push rbp
@ -1263,8 +1263,8 @@ N := 11
dec rdi
.ext_pad:
; print at least N non-space characters before extension
blte N, rdi, .print_ext
; print at least 11 non-space characters before extension
blte 11, rdi, .print_ext
prn ' '
inc rdi
jmp .ext_pad
@ -1339,12 +1339,12 @@ N := 11
inc r13
; use printf instead of print
; because it returns # of printed
; characters
; because it returns the # of
; printed characters
call printf, .buf
blte N, rax, .dir_no_pad
sub rcx, N, rax
blte 11, rax, .dir_no_pad
sub rcx, 11, rax
dec rcx
.dir.l:

1629
vm/ob/doskrnl.k Normal file

File diff suppressed because it is too large Load Diff

995
vm/ob/hello.k Normal file
View File

@ -0,0 +1,995 @@
# 1 "hello.k"
# 1 "<built-in>"
# 1 "<command-line>"
# 31 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 32 "<command-line>" 2
# 1 "hello.k"
; The OS/K Team licenses this file to you under the MIT license.
; See the LICENSE file in the project root for more information.
start:
jmp main
# 1 "crt/crt.k" 1
; The OS/K Team licenses this file to you under the MIT license.
; See the LICENSE file in the project root for more information.
;
; Limits
;
# 31 "crt/crt.k"
;
; Magic numbers
;
;
; CRT librairies
;
# 1 "./crt/sys.k" 1
; The OS/K Team licenses this file to you under the MIT license.
; See the LICENSE file in the project root for more information.
;
; SHUTDOWN syscall
;
; End virtual machine
;
Sys.Shutdown := 0x00
;
; EXIT syscall
;
; Return to COMMAND.COM
;
Sys.Exit := 0x01
;
; EXEC syscall
;
; IN
; ax0 = new RIP to load
; ax1 = frame ID to switch to
;
; New frame ID must be higher than current
; frame ID, and cannot be below 5
;
; New CR1 is set so that new RIP corresponds to 1MB
;
Sys.ExecuteInFrame := 0x02
; FIND syscalls
;
; Find file on disk
;
; IN
; ax0 = address of name buffer
; ax1 = size of name buffer
;
; OUT
; rax = # of bytes written in name buffer
; rdx = size of file
;
;
Sys.FindFirst := 0x20
Sys.FindNext := 0x21
;
; OPEN syscall
;
; IN
; ax0 = name string
;
; OUT
; rax = handle of file, or <0 if couldn't open
;
Sys.OpenFile := 0x30
;
; CREATE syscall
;
; IN
; ax0 = name string
;
; OUT
; rax = 0 on success, or <0 if couldn't open
;
Sys.CreateFile := 0x31
;
; REMOVE syscall
;
; IN
; ax0 = name string
;
; OUT
; rax = 0 on success, or <0 if couldn't open
;
Sys.RemoveFile := 0x32
;
; CLOSE syscall
;
; IN
; ax0 = file handle
;
Sys.CloseFile := 0x35
;
; READ syscall
;
; IN
; ax0 = file handle
; ax1 = buffer address
; ax2 = buffer size
;
; OUT
; rax = number of bytes read, <0 on error
;
Sys.ReadFile := 0x38
; Halt mode
Sys.EnterHaltMode := 0x999
# 43 "crt/crt.k" 2
# 1 "./crt/str.k" 1
; The OS/K Team licenses this file to you under the MIT license.
; See the LICENSE file in the project root for more information.
;
; int strnlen(char *, int)
;
strnlen:
mov rcx, ax1
scasb ax0, zero
sub rax, ax1, rcx
ret
;
; int strlen(char *)
;
strlen:
mov rcx, 0x7AFFFFFF
mov rdx, rcx
scasb ax0, zero
sub rax, rdx, rcx
ret
;
; void strcpy(char *, const char *)
;
strcpy:
.l:
mov rcx, b[ax1]
mov b[ax0], rcx
jrcxz .r
inc ax0
inc ax1
jmp .l
.r:
ret
;
; void strncpy(char *, const char *, int)
;
strncpy:
mov rcx, ax2
jrcxz .r
.l:
mov b[ax0], b[ax1]
inc ax0
inc ax1
loop .l
.r:
ret
;
; void strnzcpy(char *, const char *, int)
;
strnzcpy:
mov rcx, ax2
jrcxz .r
.l:
mov rax, b[ax1]
mov b[ax0], rax
jraxz .r
inc ax0
inc ax1
loop .l
.z:
nul b[ax0]
.r:
ret
;
; int strcmp(const char *str1, const char *str2)
;
; Returns:
; 0 if the contents of both strings are equal
; >0 if the first character that does not match has a greater value in str1 than in str2
; <0 if the first character that does not match has a lower value in str1 than in str2
;
strcmp:
nul rsi
.l:
movzx rax, b[ax0+rsi]
movzx rdx, b[ax1+rsi]
bne rax, rdx, .r
; both zero?
add rcx, rax, rdx
jrcxz .r
inc rsi
jmp .l
.r:
sub rax, rdx
ret
;
; int strncmp(const char *str1, const char *str2, int maxn)
;
strncmp:
mov rcx, ax2
jrcxz .r
.l:
movzx rax, b[ax0]
movzx rdx, b[ax1]
bne rax, rdx, .r
inc ax0
inc ax1
loop .l
.r:
sub rax, rdx
ret
;
; char *strchrnul(const char *str, int ch)
;
strchrnul:
mov rcx, 0x7AFFFFFF
scasb ax0, ax1
mov rax, ax0
ret
;
; char *strchr(const char *str, int ch)
;
strchr:
mov rcx, 0x7AFFFFFF
scasb ax0, ax1
bnz b[ax0], .r
nul rax
ret
.r:
mov rax, ax0
ret
;
; void strrev(char *buf, const char *str)
;
; buf and src must NOT overlap
;
strrev:
bzr b[ax1], .z
; save str's location
mov rsi, ax1
; go to str's end, just before
; the null terminator
mov rcx, 0x7AFFFFFF
scasb ax1, zero
dec ax1
.l:
; copy, going backward though str
; and forward through buf
mov b[ax0], b[ax1]
beq ax1, rsi, .r
inc ax0
dec ax1
jmp .l
.r:
nul b[ax0+1]
ret
.z:
nul b[ax0]
ret
;
; void strrev2(char *str)
;
; Inverses str
;
strrev2:
bzr b[ax0], .r
mov ax1, ax0
; go to str's end, just before
; the null terminator
mov rcx, 0x7AFFFFFF
scasb ax1, zero
dec ax1
; increase ax0 while decreasing ax1, performing exchanges
.l:
blteu ax1, ax0, .r
xchg b[ax0], b[ax1]
inc ax0
dec ax1
jmp .l
.r:
ret
# 44 "crt/crt.k" 2
# 1 "./crt/mem.k" 1
; The OS/K Team licenses this file to you under the MIT license.
; See the LICENSE file in the project root for more information.
;
; void memcpy(void *, const void *, int)
;
memcpy:
mov rcx, ax2
jrcxz .r
.l:
sub rdx, ax2, rcx
mov b[ax0+rdx], b[ax1+rdx]
loop .l
.r:
ret
;
; void memzero(void *, int)
;
memzero:
mov rcx, ax1
jrcxz .r
.l:
nul b[ax0]
inc ax0
loop .l
.r:
ret
# 45 "crt/crt.k" 2
# 1 "./crt/time.k" 1
; The OS/K Team licenses this file to you under the MIT license.
; See the LICENSE file in the project root for more information.
;
; struct TIME
; {
; byte sec; +0 (0-59)
; byte min; +1 (0-59)
; byte hour; +2 (0-23)
; byte mday; +3 (0-31)
; byte month; +4 (0-11)
; byte; +5 (pad)
; word year; +6 (0-65536)
; word yday; +8 (0-365)
; word; +10 (pad)
; dword; +12 (pad)
; } 16 bytes
;
;
; int DaysInYear(int year)
;
DaysInYear:
mov rax, 365
; divisible by 4?
rem rcx, ax0, 4
jrcxnz .end
; divisible by 100?
rem rcx, ax0, 100
jrcxnz .leap
; divisible by 400?
rem rcx, ax0, 400
jrcxnz .end
.leap:
inc rax
.end:
ret
;
; TIME *GetTimeUTC(void)
;
GetTimeUTC:
ytime
mov rdi, .buf
; seconds
rem rsi, rax, 60
mov b[rdi], rsi
; minutes
div rsi, rax, 60
rem rsi, 60
mov b[rdi+1], rsi
; hours
div rsi, rax, 3600
rem rsi, 24
mov b[rdi+2], rsi
; month days
div rsi, rax, 3600*24
mov b[rdi+3], rsi
; month
mov b[rdi+4], rbx
; years
mov w[rdi+6], rcx
;
; ydays (TODO)
;
mov rax, .buf
ret
.buf = [24]
# 46 "crt/crt.k" 2
# 1 "./crt/fmt/ltostr.k" 1
; The OS/K Team licenses this file to you under the MIT license.
; See the LICENSE file in the project root for more information.
;
; void itoa(char *buf, int num, int base)
;
itoa:
mov ax3, 1
jmp ltostr
;
; void utoa(char *buf, int num, int base)
;
utoa:
nul ax3
jmp ltostr
;
; void ltostr(char *buf, int num, int base, bool signed)
;
ltostr:
mov rax, ax0
nul rcx
; make sure base is in [2, 32]
bltu ax2, 2, .bad
bltu 36, ax2, .bad
; deal with zero
bzr ax1, .is_zero
; deal with base 10 signedness
bzr ax3, .conv
bne ax2, 10, .conv ; base 10
shr rcx, ax1, 63 ; extract ax1 sign
jrcxz .conv
neg ax1 ; NEG if negative
; main loop
.conv:
bzr ax1, .fini
rem rdx, ax1, ax2 ; ax1 % base
blt 9, rdx, .nondec ; rdx > 9 ?
add rdx, '0'
jmp .next
.nondec:
add rdx, 55 ; 'A' - 10
.next:
mov b[ax0], rdx
inc ax0
div ax1, ax2
jmp .conv
; add minus flag, null-terminate and reverse
.fini:
jrcxz .cxz
mov b[ax0], '-'
inc ax0
.cxz:
nul b[ax0]
call strrev2, rax
ret
;
; exceptional cases
;
.bad:
mov b[ax0], 0
ret
.is_zero:
mov b[ax0], 48 ; '0'
mov b[ax0+1], 0
ret
# 48 "crt/crt.k" 2
# 1 "./crt/fmt/strtol.k" 1
; The OS/K Team licenses this file to you under the MIT license.
; See the LICENSE file in the project root for more information.
;
; int strtol(const char *str, int base)
;
; rax = integer extracted from str
; rdx = pointer to first invalid byte
;
strtol:
mov ax2, 1
jmp strtoq
;
; int strtoul(const char *str, int base)
;
; rax = integer extracted from str
; rdx = pointer to first invalid byte
;
strtoul:
nul ax2
jmp strtoq
;
; int strtoq(const char *str, int base, bool signed)
;
; guesses base when 'base'=0
;
strtoq:
nul rax, rsi
mov rdx, ax0
; make sure base is in [2, 32]
beq ax1, 1, .bad
bltu 36, ax1, .bad
; empty string?
bzr b[rdx], .done
.skip_spc:
bne b[rdx], ' ', .no_spc
inc rdx
jmp .skip_spc
.no_spc:
; skip +
bne b[rdx], '+', .no_plus
inc rdx
.no_plus:
; unsigned?
bzr ax2, .unsigned
; parse '-'
bne b[rdx], '-', .unsigned
inc rdx
mov rsi, 1
.unsigned:
; base 0
bzr ax1, .base_0
; base prefix?
bne b[rdx], '0', .main_loop
inc rdx
movzx rcx, b[rdx]
; "0x"/"0b" prefix
jrcxz .done ; "0"
beq rcx, 'x', .parsed_0x
beq rcx, 'b', .parsed_0b
; may be octal, but we don't care
; we accept "0110101010" (despite base=2) for instance
jmp .main_loop
.parsed_0x:
; are we in base 16?
; if not, leave rax = 0 and *rdx = 'x'
bne ax1, 16, .done
; else
inc rdx
jmp .main_loop
.parsed_0b:
; are we in base 2?
; if not, leave rax = 0 and *rdx = 'b'
bne ax1, 2, .done
; else
inc rdx
jmp .main_loop
.base_0:
; guess base
beq b[rdx], '0', .b0_not10
; must be base 10
mov ax1, 10
jmp .main_loop
.b0_not10:
inc rdx
bne b[rdx], 'x', .b0_not16
inc rdx
mov ax1, 16
jmp .main_loop
.b0_not16:
bne b[rdx], 'b', .b0_not2
inc rdx
mov ax1, 2
jmp .main_loop
.b0_not2:
; take octal by default
mov ax1, 8
.main_loop:
movzx rcx, b[rdx]
inc rdx
; between 0 and 9?
bltu rcx, '0', .done
bltu '9', rcx, .not_digit10
; yes
sub rcx, '0'
jmp .next
.not_digit10:
bltu rcx, 'A', .done
bltu 'Z', rcx, .not_digitAZ
sub rcx, 55 ; 'A' - 10
jmp .next
.not_digitAZ:
bltu rcx, 'a', .done
bltu 'z', rcx, .done
sub rcx, 87 ; 'a' - 10
jmp .next
.next:
; too large for base?
blteu ax1, rcx, .done
mul rax, ax1
add rax, rcx
jmp .main_loop
.done:
; negative?
bzr rsi, .r
; yes
neg rax
.r:
ret
.bad:
ret
# 49 "crt/crt.k" 2
# 1 "./crt/fmt/doprnt.k" 1
; The OS/K Team licenses this file to you under the MIT license.
; See the LICENSE file in the project root for more information.
;
; typedef int (*PUTC)(int ch)
; int doprnt(PUTC putc, int n, const char *fmt, va_list ap)
;
doprnt:
push rbp
mov rbp, rsp
push r12, r13, r14
push r15, r16, r17
mov r12, ax2 ; fmt
mov r14, ax3 ; va_list
mov r15, ax1 ; n
mov r17, ax0 ; putc
nul r16 ; return value
.main_loop:
; find '%' or null-terminator
mov rcx, 0x7AFFFFFF
mov r13, r12
scasb r13, '%'
; everything below r13 is a regular character; print it
.print_regular:
beq r12, r13, .check_modf
call .doput, b[r12]
inc r12
jmp .print_regular
.check_modf:
; did we find a '%' ?
; if not, then we found fmt's null-terminator; we're done
bne b[r12], '%', .epilogue
; we did find a modifier / '%'
mov rax, b[r12+1]
add r12, 2
beq rax, 's', .modf_s
beq rax, 'c', .modf_c
beq rax, 'p', .modf_p
beq rax, 'x', .modf_x
beq rax, 'd', .modf_d
beq rax, 'o', .modf_o
beq rax, 'b', .modf_b
beq rax, '%', .modf_percent
; unrecognized
jmp .bad_modifier
.modf_s:
; get string address
mov r13, q[r14]
add r14, 8
bzr r13, .nullstring
.print_string:
movzx ax0, b[r13]
bzr ax0, .main_loop
inc r13
call .doput
jmp .print_string
.modf_c:
call .doput, q[r14]
add r14, 8
jmp .main_loop
.modf_p:
call .doput, '0'
call .doput, 'x'
; Fallthrough
.modf_x:
mov ax2, 16
jmp .print_number
.modf_d:
mov ax2, 10
jmp .print_number
.modf_o:
mov ax2, 8
jmp .print_number
.modf_b:
mov ax2, 2
jmp .print_number
.print_number:
; allocate itoa conversion buffer
sub rsp, 80
mov r13, rsp
; assume modifier already set up ax2
call itoa, rsp, q[r14]
add r14, 8
.print_itoa_buf:
movzx ax0, b[r13]
bzr ax0, .pib_end_loop
inc r13
call .doput
jmp .print_itoa_buf
.pib_end_loop:
add rsp, 80
jmp .main_loop
.modf_percent:
call .doput, '%'
jmp .main_loop
.bad_modifier:
; print "%?" to clearly indicate that something is wrong
call .doput, '%'
call .doput, '?'
jmp .main_loop
.nullstring:
; %s was passed a NULL
call .doput, '('
call .doput, 'n'
call .doput, 'u'
call .doput, 'l'
call .doput, 'l'
call .doput, ')'
jmp .main_loop
.epilogue:
mov rax, r16
pop r17, r16
pop r15, r14
pop r13, r12
leave
ret
;
; prints ax0
;
.doput:
; update print count
inc r16
; if n==0, don't print
; we follow the C convention that sprintf()-like functions
; should return the number of characters that would have
; been printed/written if 'n' were big enough
bzr r15, .r
; decrement n and print
dec r15
call r17
; did putc fail?
jraxz .r
; yes, so artificially set n=0
nul r15
.r:
ret
# 50 "crt/crt.k" 2
# 1 "./crt/fmt/printf.k" 1
; The OS/K Team licenses this file to you under the MIT license.
; See the LICENSE file in the project root for more information.
;
; int putc(int ch)
;
putc:
prn ax0
nul rax
ret
;
; int printf(const char *fmt, ...)
;
printf:
mov ax2, ax0
mov ax0, putc
mov ax1, 0x7AFFFFFF
add ax3, rsp, 8
jmp doprnt
;
; int nprintf(const char *fmt, int n, ...)
;
nprintf:
mov ax2, ax0
mov ax0, putc
add ax3, rsp, 8
jmp doprnt
;
; Print a string
; Guaranteed to only affect rcx and ax0
;
print:
.l:
movzx rax, b[ax0]
jraxz .r
prn rax
inc ax0
jmp .l
.r:
ret
;
; Print exactly ax1 characters
;
nprint:
mov rcx, ax1
jrcxz .r
.l:
prn b[ax0]
inc ax0
loop .l
.r:
ret
# 51 "crt/crt.k" 2
exit:
mov rax, Sys.Exit
trap 0
abort:
crash
# 8 "hello.k" 2
main:
mov rsp, 0x104000
nul rbp
call print, .hellow
jmp exit
.hellow = "Hello World!\n"