diff --git a/Makefile b/Makefile index 3d9bd34..b2bd77f 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ KODIR=ka/obj all: kas kpc: - @cd vm && make --no-print-directory verbose=no + @cd vm && make --no-print-directory -s verbose=yes kas: kpc as/regs.lst as/k-as.py @cp vm/in/instrs.lst as diff --git a/as/k-as.py b/as/k-as.py index 88a9ed6..737ae17 100755 --- a/as/k-as.py +++ b/as/k-as.py @@ -216,6 +216,17 @@ def parse(): #------------------------------------------------------------------------------- +escape_dict = { + 'n': '\n', + 't': '\t', + 'r': '\r', + 'v': '\v', + 'f': '\f', + '"': '"', + '\'': '\'', + '\\': '\\', +} + def parse_preproc(line): global pdata @@ -286,10 +297,9 @@ def parse_preproc(line): if escaping: escaping = False - if c == 'n': - c = '\n' - elif c == 't': - c = '\t' + if c in escape_dict: + c = escape_dict[c] + else: print("Unrecognized escape sequence: {}".format(line)) leave() diff --git a/ka/ABI b/ka/ABI index 2a4d9ef..52c90bf 100644 --- a/ka/ABI +++ b/ka/ABI @@ -56,7 +56,6 @@ the function - uses no local variables (on the stack) - never uses any function that changes 'rbp' nor 'rsp', aside from 'call' and 'ret' - - never calls a variadic function You can never omit 'enter' without omitting 'leave', and vice-versa. diff --git a/ka/crt/fmt/itoa.k b/ka/crt/fmt/itoa.k index 9389cd4..fa88810 100644 --- a/ka/crt/fmt/itoa.k +++ b/ka/crt/fmt/itoa.k @@ -36,7 +36,7 @@ itoa: j.z .fini mov lx1, ax1 - mod lx1, ax2 ; ax1 % base + rem lx1, ax2 ; ax1 % base cmp lx1, 9 ; lx1 > 9 ? j.a .nondec diff --git a/ka/dos.k b/ka/dos.k index 5fb814d..cd570a6 100644 --- a/ka/dos.k +++ b/ka/dos.k @@ -20,8 +20,8 @@ include "crt/crt.k" ; ; Disk Operating System ; -include "sys/cpudev.k" -include "sys/memdev.k" +include "sys/drv/cpudev.k" +include "sys/drv/memdev.k" include "sys/tests.k" include "sys/main.k" diff --git a/ka/sys/cpudev.k b/ka/sys/drv/cpudev.k similarity index 100% rename from ka/sys/cpudev.k rename to ka/sys/drv/cpudev.k diff --git a/ka/sys/memdev.k b/ka/sys/drv/memdev.k similarity index 100% rename from ka/sys/memdev.k rename to ka/sys/drv/memdev.k diff --git a/ka/sys/main.k b/ka/sys/main.k index 702b3fa..9fcd66d 100644 --- a/ka/sys/main.k +++ b/ka/sys/main.k @@ -5,5 +5,6 @@ ; Main function ; main: + call keybd_test ret diff --git a/ka/sys/tests.k b/ka/sys/tests.k index e64d6f5..a191d6c 100644 --- a/ka/sys/tests.k +++ b/ka/sys/tests.k @@ -1,6 +1,19 @@ ; The OS/K Team licenses this file to you under the MIT license. ; See the LICENSE file in the project root for more information. +keybd_test: +.1: + scan rax + xpause + + test rax, rax + j.z .1 + + prn rax + jmp .1 + + ret + putc_scroll_test: mov rdx, 25 .1: diff --git a/vm/Makefile b/vm/Makefile index c4d782f..59974dd 100644 --- a/vm/Makefile +++ b/vm/Makefile @@ -39,9 +39,9 @@ $(OBJDIR)/%.o: %.c $(OBJDIR)/%.d: %.c @mkdir -p $(shell dirname $@) @cc -I. -MM -MT $(@:%.d=%.o) -MF $@ $< - @if [ $(verbose) = "yes" ]; then \ - echo ${CL2}[$@] ${CL}dependencies generated.${CL3};\ - fi + #@if [ $(verbose) = "yes" ]; then \ + # echo ${CL2}[$@] ${CL}dependencies generated.${CL3};\ + #fi in/instrs.lst: in/INSTRS in/arch_i.py @cd in && python3 arch_i.py diff --git a/vm/in/INSTRS b/vm/in/INSTRS index 8e849b6..9851648 100644 --- a/vm/in/INSTRS +++ b/vm/in/INSTRS @@ -183,13 +183,13 @@ mulf rm rim div rm rim # -# Arithmetical unsigned MOD operation +# Arithmetical unsigned modulo operation (REM) # # $1 = $1 MOD $2 # # Preserves all flags # -mod rm rim +rem rm rim # # Arithmetical unsigned 128-bit MUL operation @@ -382,10 +382,34 @@ push rim # pop rm +#---------------------------------------------------------------------------# +# I/O instructions # +#---------------------------------------------------------------------------# + +# +# Send a character to standard output (PRN) +# +prn rim + +# +# Scan a character from standard input (SCAN) +# +scan rm + #---------------------------------------------------------------------------# # Supervisor only instructions # #---------------------------------------------------------------------------# +# +# Halt the processor until next E/I (HLT) +# +hlt + +# +# Pause the CPU for a relatively long time (XPAUSE) +# +xpause + # # Call an architecture-reserved function slot of device (DEVCTL) # @@ -400,6 +424,122 @@ devctl rim rim # iocall rim rim +#---------------------------------------------------------------------------# +# E/I handling instructions # +#---------------------------------------------------------------------------# + +# +# Trap into exception handler (TRAP) +# +# Throw: +# #ILL if $1 > 255 +# #($1+256) otherwise +# +trap rim + +# +# Return from exception/interrupt (IRET) +# +iret + +#---------------------------------------------------------------------------# +# Misc. instructions # +#---------------------------------------------------------------------------# + +# +# Do nothing (NOOP) +# +# (nothing) +# +# Throws: +# (nothing) +# +# Preserves all flags +# +nop + +# +# Pause the CPU for a very short amount of time (PAUSE) +# Used in spin-like loops +# +pause + +# +# CPU Identification Number +# +# Does nothing (for now) +# +cpuid + +# +# Pseudo-random number generation (RAND32/RAND64) +# +# RAND32 generates a 32-bit pseudo-random number using +# a nonlinear additive feedback pseudo-random number generator +# of period 16 * (2^31 - 1). +# +# RAND64 generates two such numbers, and store them in the destination +# operand's higher and lower double words respectively +# +# The running program does not control the seeding and the processor +# may generate numbers from the same generator for other purposes +# than this instruction +# +#rand32 rm +#rand64 rm + +# +# Get code/data offset (GCO/GCD) +# +# $1 = CR1 (GCO) +# $1 = CR2 (GCD) +# +gco rm +gcd rm + +#---------------------------------------------------------------------------# +# Debugging instructions # +#---------------------------------------------------------------------------# + +# +# Breakpoint instruction (BREAK) +# +# (cause register dump on standard error) +# (wait for user input before proceeeding) +# +break + +# +# Step-by-step execution (STEP) +# +# IF $1 == 0 THEN +# (disable step-by-step execution) +# ELSE +# (enable step-by-step execution) +# FI +# +step rim + +#---------------------------------------------------------------------------# +# Clean-up misc. instructions # +#---------------------------------------------------------------------------# + +# +# Clear base volatile registers (CLR) +# +# RAX = RBX = RCX = RDX = 0 +# RSX = RBI = RDI = RSI = 0 +# +clr + +# +# Clear argument registers (CLA) +# +# AX0 = AX1 = AX2 = AX3 = 0 +# AX4 = AX5 = AX6 = AX7 = 0 +# +cla + #---------------------------------------------------------------------------# # Flag manipulation instructions # #---------------------------------------------------------------------------# @@ -455,127 +595,6 @@ bswap rm rim wswap rm rim dswap rm rim -#---------------------------------------------------------------------------# -# E/I handling instructions # -#---------------------------------------------------------------------------# - -# -# Trap into exception handler (TRAP) -# -# Throw: -# #ILL if $1 > 255 -# #($1+256) otherwise -# -trap rim - -# -# Return from exception/interrupt (IRET) -# -iret - -hlt - -#---------------------------------------------------------------------------# -# Misc. instructions # -#---------------------------------------------------------------------------# - -# -# Do nothing (NOOP) -# -# (nothing) -# -# Throws: -# (nothing) -# -# Preserves all flags -# -nop - -# -# CPU Identification Number -# -# Does nothing (for now) -# -cpuid - -# -# Pseudo-random number generation (RAND32/RAND64) -# -# RAND32 generates a 32-bit pseudo-random number using -# a nonlinear additive feedback pseudo-random number generator -# of period 16 * (2^31 - 1). -# -# RAND64 generates two such numbers, and store them in the destination -# operand's higher and lower double words respectively -# -# The running program does not control the seeding and the processor -# may generate numbers from the same generator for other purposes -# than this instruction -# -#rand32 rm -#rand64 rm - -# -# Get code/data offset (GCO/GCD) -# -# $1 = CR1 (GCO) -# $1 = CR2 (GCD) -# -gco rm -gcd rm - -# -# Send a character to standard output (PRN) -# -# Throws: -# #PRN if DV text mode enabled -# #PRN if graphic mode enabled -# -prn rim - -#---------------------------------------------------------------------------# -# Debugging instructions # -#---------------------------------------------------------------------------# - -# -# Breakpoint instruction (BREAK) -# -# (cause register dump on standard error) -# (wait for user input before proceeeding) -# -break - -# -# Step-by-step execution (STEP) -# -# IF $1 == 0 THEN -# (disable step-by-step execution) -# ELSE -# (enable step-by-step execution) -# FI -# -step rim - -#---------------------------------------------------------------------------# -# Clean-up misc. instructions # -#---------------------------------------------------------------------------# - -# -# Clear base volatile registers (CLR) -# -# RAX = RBX = RCX = RDX = 0 -# RSX = RBI = RDI = RSI = 0 -# -clr - -# -# Clear argument registers (CLA) -# -# AX0 = AX1 = AX2 = AX3 = 0 -# AX4 = AX5 = AX6 = AX7 = 0 -# -cla - #---------------------------------------------------------------------------# # String manipulation instructions # #---------------------------------------------------------------------------# diff --git a/vm/in/arith.c b/vm/in/arith.c index 67b30e8..460c69a 100644 --- a/vm/in/arith.c +++ b/vm/in/arith.c @@ -220,7 +220,7 @@ IMPL_START_2(div) } IMPL_OUT; -IMPL_START_2(mod) +IMPL_START_2(rem) { v1 %= v2; } diff --git a/vm/in/inout.c b/vm/in/inout.c new file mode 100644 index 0000000..6f94f19 --- /dev/null +++ b/vm/in/inout.c @@ -0,0 +1,27 @@ +// The OS/K Team licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#include +#include + +//----------------------------------------------------------------------------// + +IMPL_START_1(prn) +{ + if (p1->mlen > 1) { + trace("prn warning: large access size\n"); + } + console_putc(ctx, (char)v1); +} +IMPL_END; + +//----------------------------------------------------------------------------// + +IMPL_START_1(scan) +{ + v1 = console_scankeybuf(ctx); +} +IMPL_OUT; + +//----------------------------------------------------------------------------// + diff --git a/vm/in/instrs.c b/vm/in/instrs.c index 19e1363..30532ef 100644 --- a/vm/in/instrs.c +++ b/vm/in/instrs.c @@ -3,6 +3,7 @@ #include #include +#include #include @@ -18,6 +19,21 @@ IMPL_END; //----------------------------------------------------------------------------// +IMPL_START_0(pause) +{ + usleep(5000); +} +IMPL_END; + +IMPL_START_0(xpause) +{ + CHK_SUPERV(); + usleep(25000); +} +IMPL_END; + +//----------------------------------------------------------------------------// + IMPL_START_0(cpuid) { rax = rdx = 0; @@ -50,17 +66,6 @@ IMPL_OUT; //----------------------------------------------------------------------------// -IMPL_START_1(prn) -{ - if (p1->mlen > 1) { - trace("prn warning: large access size\n"); - } - console_putc(ctx, (char)v1); -} -IMPL_END; - -//----------------------------------------------------------------------------// - IMPL_START_0(clr) { rax = rbx = rcx = rdx = 0; diff --git a/vm/pc/console.c b/vm/pc/console.c index 2e02c56..826785b 100644 --- a/vm/pc/console.c +++ b/vm/pc/console.c @@ -77,6 +77,9 @@ void console_exit(ctx_t *ctx) SDL_DestroyTexture(scr_texts[y]); } + if (scr_rend) + SDL_DestroyRenderer(scr_rend); + if (scr_win) SDL_DestroyWindow(scr_win); @@ -102,6 +105,27 @@ void console_render(ctx_t *ctx) //----------------------------------------------------------------------------// +void console_update(ctx_t *ctx) +{ + SDL_Event evt; + + if (__builtin_expect(SDL_PollEvent(&evt) == 1, 0)) + { + switch (evt.type) + { + case SDL_QUIT: + die(0); + break; + + case SDL_KEYDOWN: + console_handle_input(ctx, evt.key.keysym.sym); + break; + } + } +} + +//----------------------------------------------------------------------------// + void console_putat(ctx_t *ctx, char ch, int x, int y) { SDL_Surface *surf; @@ -172,16 +196,28 @@ void console_putc(ctx_t *ctx, char ch) { size_t y; - if (ch < ' ' && ch != '\n') - ch = 127; - - if (ch == '\n') - csn_x = CONSOLE_WIDTH; - - else + switch (ch) { - console_putat(ctx, ch, csn_x, csn_y); - csn_x++; + case '\n': + csn_x = CONSOLE_WIDTH; + break; + + case '\r': + csn_x = 0; + return; + + case '\b': + if (csn_x == 0) + return; + + csn_x--; + console_putat(ctx, ' ', csn_x, csn_y); + break; + + default: + console_putat(ctx, ch, csn_x, csn_y); + csn_x++; + break; } if (csn_x == CONSOLE_WIDTH) diff --git a/vm/pc/console.h b/vm/pc/console.h index ddd1aa4..3cc0693 100644 --- a/vm/pc/console.h +++ b/vm/pc/console.h @@ -1,9 +1,11 @@ // The OS/K Team licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +// Critical ordering #include #include #include +#include void console_init(ctx_t *ctx); void console_exit(ctx_t *ctx); @@ -11,4 +13,7 @@ void console_exit(ctx_t *ctx); void console_render(ctx_t *ctx); void console_putat(ctx_t *ctx, char ch, int x, int y); void console_putc(ctx_t *ctx, char ch); +void console_update(ctx_t *ctx); + +void console_handle_input(ctx_t *, SDL_Keycode); diff --git a/vm/pc/except.h b/vm/pc/except.h index 32a9e99..1faadd2 100644 --- a/vm/pc/except.h +++ b/vm/pc/except.h @@ -20,8 +20,7 @@ enum E_DBF, // Double fault E_IMP, // Not implemented E_ALI, // Alignment error - E_STA, // Stack misalignment - E_STU, // Stack underflow + E_BRK, // Ctrl+C or similar NEXCPTS }; diff --git a/vm/pc/keybd.c b/vm/pc/keybd.c new file mode 100644 index 0000000..1f0dd12 --- /dev/null +++ b/vm/pc/keybd.c @@ -0,0 +1,84 @@ +// The OS/K Team licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#include + +#define KEYBUFSIZE 8192 + +typedef uint keycode_t; + +keycode_t keybuf[KEYBUFSIZE] = { 0 }; +keycode_t *keybuf_last = &keybuf[0]; +keycode_t *keybuf_ptr = &keybuf[0]; + +void console_addkey(ctx_t *ctx, keycode_t key) +{ + *keybuf_ptr++ = key; + + if (keybuf_ptr == keybuf + KEYBUFSIZE) + keybuf_ptr = &keybuf[0]; +} + +keycode_t console_getkey(ctx_t *ctx) +{ + keycode_t rc = *keybuf_last++; + + if (keybuf_last == keybuf + KEYBUFSIZE) + keybuf_last = &keybuf[0]; + + return rc; +} + +keycode_t console_scankeybuf(ctx_t *ctx) +{ + if (keybuf_last != keybuf_ptr) + return console_getkey(ctx); + + return 0; +} + +void console_handle_input(ctx_t *ctx, SDL_Keycode key) +{ + keycode_t code = 0; + + SDL_Keymod mod = SDL_GetModState(); + + if (key <= 'z' && key >= 'a') + { + if (mod & (KMOD_CTRL|KMOD_ALT)) + { + if (key == 'c') + _except(ctx, E_BRK, "Ctrl+C received"); + + return; + } + + if (mod & KMOD_SHIFT) + key -= ('a' - 'A'); + + console_addkey(ctx, key); + + return; + } + + if (key <= '0' && key >= '9') + console_addkey(ctx, key); + + switch (key) + { + case SDLK_SPACE: code = ' '; break; + case SDLK_BACKSLASH: code = '\\'; break; + case SDLK_BACKSPACE: code = '\b'; break; + + case SDLK_RETURN: + case SDLK_RETURN2: + code = '\n'; + break; + + default: + return; + } + + console_addkey(ctx, code); +} + diff --git a/vm/pc/keybd.h b/vm/pc/keybd.h new file mode 100644 index 0000000..0f15cad --- /dev/null +++ b/vm/pc/keybd.h @@ -0,0 +1,17 @@ +// The OS/K Team licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#define KEYBUFSIZE 8192 + +typedef uint keycode_t; + +extern keycode_t keybuf[KEYBUFSIZE]; +extern keycode_t *keybuf_last; +extern keycode_t *keybuf_ptr; + +keycode_t console_getkey(ctx_t *); +keycode_t console_scankeybuf(ctx_t *); + +void console_addkey(ctx_t *, keycode_t); +void console_handle_input(ctx_t *ctx, SDL_Keycode key); + diff --git a/vm/pc/main.c b/vm/pc/main.c index a642734..f45a906 100644 --- a/vm/pc/main.c +++ b/vm/pc/main.c @@ -34,7 +34,7 @@ ctx_t main_ctx; void sigcommon(void) { - _except(&main_ctx, 1023, "SIGNAL'ed"); + _except(&main_ctx, E_BRK, "SIGNAL'ed"); } void sigint(int _) @@ -53,8 +53,6 @@ void sigsegv(int _) // void main_loop(void) { - SDL_Event evt; - // // Start decoding // @@ -62,11 +60,7 @@ void main_loop(void) // Execute one instruction decode(&main_ctx); - if (__builtin_expect(SDL_PollEvent(&evt) == 1, 0)) - { - if (evt.type == SDL_QUIT) - die(0); - } + console_update(&main_ctx); if (main_ctx.step) getchar(); diff --git a/vm/pc/sym.c b/vm/pc/sym.c index 6c20424..f099f0d 100644 --- a/vm/pc/sym.c +++ b/vm/pc/sym.c @@ -22,7 +22,7 @@ int create_symtab(const char *name) { // log("SYM: '%.*s' '%lu'\n", SYMLEN_MAX, buf, addr); - if (prev_addr >= addr) + if (prev_addr > addr) { logerr("Symbol addresses in symbol table not in increasing order\n"); logerr("Previous symbol: '%s' '%lu'\n", symtab[it-1].name, prev_addr);