diff --git a/Makefile b/Makefile index c13892e..54f192b 100644 --- a/Makefile +++ b/Makefile @@ -19,7 +19,7 @@ $(KODIR)/a.out: $(DOSK) kas .PHONY: clean clean: @cd vm && make clean --no-print-directory - @rm -f $(KODIR)/a.out $(KODIR)/a.out.sym $(KODIR)/k.exe $(KODIR)/stdout.txt as/instrs.lst + @rm -f $(KODIR)/a.out $(KODIR)/a.out.sym $(KODIR)/k.exe as/instrs.lst test: $(KODIR)/a.out @vm/k.exe $(KODIR)/a.out $(KODIR)/a.sym diff --git a/vm/in/ARITH b/vm/in/ARITH new file mode 100644 index 0000000..d8022a9 --- /dev/null +++ b/vm/in/ARITH @@ -0,0 +1,158 @@ +# The OS/K Team licenses this file to you under the MIT license. +# See the LICENSE file in the project root for more information. + +#---------------------------------------------------------------------------# +# Arithmetic instructions # +#---------------------------------------------------------------------------# + +# +# CMP Comparison instruction +# +# $1 - $2 +# +# Sets CF if unsigned integer overflow occur, clears it otherwise +# Sets OF is signed integer overflow occur, clears it otherwise +# Sets ZF and SF according to the result +# +cmp rim rim + +# +# Arithmetical SGN operation +# +# IF ($1 == 0) THEN +# $2 = 0 +# ELIF ($1 GT 0) THEN +# $2 = 1 +# ELSE +# $2 = LONG_MIN +# FI +# +# Treats $1 and $2 as signed values +# Sets ZF and SF according to the result +# +sgn rm rim +sgnf rm rim + +# +# Arithmetical NEG operation +# +# $1 = NOT($1) + 1 +# +# Sets CF if $1 == 0; clears it otherwise +# Sets OF if $1 == $LONG_MIN; clears it otherwise +# Sets ZF and SF according to the result +# +neg rm +negf rm + +# +# Arithmetical INC operation +# +# $1 = $1 + 1 +# +# Preserves CF +# Sets OF if $1 == $LONG_MAX, clears it otherwise +# Sets ZF and SF according to the result +# +inc rm +incf rm + +# +# Arithmetical DEC operation +# +# $1 = $1 - 1 +# +# Preserves CF +# Sets OF if $1 == $LONG_MIN, clears it otherwise +# Sets ZF and SF according to the result +# +dec rm +decf rm + +# +# Arithmetical ADD operation +# +# $1 = $1 + $2 +# +# Sets CF if unsigned integer overflow occur, clears it otherwise +# Sets OF is signed integer overflow occur, clears it otherwise +# Sets ZF and SF according to the result +# +add rm rim +addf rm rim + +# +# Arithmetical ADD operation, with carry +# +# $1 = $1 + $2 + CF +# +# Sets CF if unsigned integer overflow occur, clears it otherwise +# Sets OF is signed integer overflow occur, clears it otherwise +# Sets ZF and SF according to the result +# +adc rm rim +adcf rm rim + +# +# Arithmetical SUB operation +# +# $1 = $1 - $2 +# +# Sets CF if unsigned integer overflow occur, clears it otherwise +# Sets OF is signed integer overflow occur, clears it otherwise +# Sets ZF and SF according to the result +# +sub rm rim +subf rm rim + +# +# Arithmetical unsigned MUL operation +# +# $1 = LO($1 * $2) +# +# Sets CF and OF if HI($1 * $2) > 0, clears them otherwise +# Preserves ZF and SF +# +mul rm rim +mulf rm rim + +# +# Arithmetical unsigned DIV operation +# +# $1 = $1 DIV $2 +# +# Preserves all flags +# +div rm rim + +# +# Arithmetical unsigned modulo operation (REM) +# +# $1 = $1 MOD $2 +# +# Preserves all flags +# +rem rm rim + +# +# Arithmetical unsigned 128-bit MUL operation +# +# RDX = HI(RAX * $1) +# RAX = LO(RAX * $1) +# +# Sets CF and OF if HI($1 * $2) > 0, clears them otherwise +# Preserves ZF and SF +# +mul2 rim +mul2f rim + +# +# Arithmetical unsigned combined DIV and MOD operations +# +# RDX = (RAX MOD $1) +# RAX = (RAX DIV $1) +# +# Preserves all flags +# +div2 rim + diff --git a/vm/in/DEBUG b/vm/in/DEBUG new file mode 100644 index 0000000..126a6a6 --- /dev/null +++ b/vm/in/DEBUG @@ -0,0 +1,26 @@ +# The OS/K Team licenses this file to you under the MIT license. +# See the LICENSE file in the project root for more information. + +#---------------------------------------------------------------------------# +# 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 + diff --git a/vm/in/FLAGS b/vm/in/FLAGS new file mode 100644 index 0000000..290e262 --- /dev/null +++ b/vm/in/FLAGS @@ -0,0 +1,45 @@ +# The OS/K Team licenses this file to you under the MIT license. +# See the LICENSE file in the project root for more information. + +#---------------------------------------------------------------------------# +# Flag manipulation instructions # +#---------------------------------------------------------------------------# + +# +# Clear or set interrupt flag (CLI/STI) +# +# Throws: +# #SYS if not in supervisor mode +# +cli +sti + +# +# Clear or set direction flag (CLD/STD) +# +cld +std + +# +# Complement, clear or set carry flag (CMC/CLC/STC) +# +cmc +clc +stc + +# +# Load FLG register (LODF) +# +# $1 = FLG +# +lodf rm + +# +# Store FLG register - lower byte only (STOFB) +# +# FLG[7:0] = $1[7:0] +# +# Note: FLG's lower byte contains CF, OF, ZF, SF, PF and DF +# +stofb rm + diff --git a/vm/in/INOUT b/vm/in/INOUT new file mode 100644 index 0000000..97c67fd --- /dev/null +++ b/vm/in/INOUT @@ -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. + +#---------------------------------------------------------------------------# +# I/O instructions # +#---------------------------------------------------------------------------# + +# +# Send a character to standard output (PRN) +# +prn rim + +# +# Scan a character from standard input (SCAN) +# +scan rm + diff --git a/vm/in/INSTRS b/vm/in/INSTRS index 8b0aa8b..0abe895 100644 --- a/vm/in/INSTRS +++ b/vm/in/INSTRS @@ -5,729 +5,16 @@ # Special instructions # #---------------------------------------------------------------------------# -# -# Initiate machine shutdown (STOP) -# -# THROW #SHT -# -# Throws: -# #SYS if not in supervisor mode -# #ILL if disabled through DV -# #SHT otherwise -# -stop - -#---------------------------------------------------------------------------# -# Logical instructions # -#---------------------------------------------------------------------------# - -# -# Bitwise NOT operation -# -# $1 = NOT($1) -# -# Preserves all flags -# -not rm - -# -# Bitwise OR operation -# -# $1 = $1 OR $2 -# -# Clears OF and CF -# Sets ZF and SF according to the result -# -or rm rim -orf rm rim - -# -# Bitwise AND operation -# -# $1 = $1 AND $2 -# -# Clears OF and CF -# Sets ZF and SF according to the result -# -and rm rim -andf rm rim - -# -# Bitwise XOR operation -# -# $1 = $1 XOR $2 -# -# Clears OF and CF -# Sets ZF and SF according to the result -# -xor rm rim -xorf rm rim - -# To document -shl rm rim -shr rm rim -shlf rm rim -shrf rm rim - -#---------------------------------------------------------------------------# -# Arithmetic instructions # -#---------------------------------------------------------------------------# - -# -# Arithmetical SGN operation -# -# IF ($1 == 0) THEN -# $2 = 0 -# ELIF ($1 GT 0) THEN -# $2 = 1 -# ELSE -# $2 = LONG_MIN -# FI -# -# Treats $1 and $2 as signed values -# Sets ZF and SF according to the result -# -sgn rm rim -sgnf rm rim - -# -# Arithmetical NEG operation -# -# $1 = NOT($1) + 1 -# -# Sets CF if $1 == 0; clears it otherwise -# Sets OF if $1 == $LONG_MIN; clears it otherwise -# Sets ZF and SF according to the result -# -neg rm -negf rm - -# -# Arithmetical INC operation -# -# $1 = $1 + 1 -# -# Preserves CF -# Sets OF if $1 == $LONG_MAX, clears it otherwise -# Sets ZF and SF according to the result -# -inc rm -incf rm - -# -# Arithmetical DEC operation -# -# $1 = $1 - 1 -# -# Preserves CF -# Sets OF if $1 == $LONG_MIN, clears it otherwise -# Sets ZF and SF according to the result -# -dec rm -decf rm - -# -# Arithmetical ADD operation -# -# $1 = $1 + $2 -# -# Sets CF if unsigned integer overflow occur, clears it otherwise -# Sets OF is signed integer overflow occur, clears it otherwise -# Sets ZF and SF according to the result -# -add rm rim -addf rm rim - -# -# Arithmetical ADD operation, with carry -# -# $1 = $1 + $2 + CF -# -# Sets CF if unsigned integer overflow occur, clears it otherwise -# Sets OF is signed integer overflow occur, clears it otherwise -# Sets ZF and SF according to the result -# -adc rm rim -adcf rm rim - -# -# Arithmetical SUB operation -# -# $1 = $1 - $2 -# -# Sets CF if unsigned integer overflow occur, clears it otherwise -# Sets OF is signed integer overflow occur, clears it otherwise -# Sets ZF and SF according to the result -# -sub rm rim -subf rm rim - -# -# Arithmetical unsigned MUL operation -# -# $1 = LO($1 * $2) -# -# Sets CF and OF if HI($1 * $2) > 0, clears them otherwise -# Preserves ZF and SF -# -mul rm rim -mulf rm rim - -# -# Arithmetical unsigned DIV operation -# -# $1 = $1 DIV $2 -# -# Preserves all flags -# -div rm rim - -# -# Arithmetical unsigned modulo operation (REM) -# -# $1 = $1 MOD $2 -# -# Preserves all flags -# -rem rm rim - -# -# Arithmetical unsigned 128-bit MUL operation -# -# RDX = HI(RAX * $1) -# RAX = LO(RAX * $1) -# -# Sets CF and OF if HI($1 * $2) > 0, clears them otherwise -# Preserves ZF and SF -# -mul2 rim -mul2f rim - -# -# Arithmetical unsigned combined DIV and MOD operations -# -# RDX = (RAX MOD $1) -# RAX = (RAX DIV $1) -# -# Preserves all flags -# -div2 rim - -#---------------------------------------------------------------------------# -# Comparison instructions # -#---------------------------------------------------------------------------# - -# -# TEST Comparison instruction -# -# $1 AND $2 -# -# Clears OF and CF -# Sets ZF and SF according to the result -# -test rim rim - -# -# CMP Comparison instruction -# -# $1 - $2 -# -# Sets CF if unsigned integer overflow occur, clears it otherwise -# Sets OF is signed integer overflow occur, clears it otherwise -# Sets ZF and SF according to the result -# -cmp rim rim - -#---------------------------------------------------------------------------# -# Jump instructions # -#---------------------------------------------------------------------------# - -# -# Unconditional jump (JMP) instruction -# -# RIP = $1 -# -j ri -jmp ri - -# -# RCX-dependent jump (LOOP) instruction -# -# IF (RCX > 0) THEN -# RCX = RCX - 1 -# RIP = $1 -# FI -# -loop ri - -#---------------------------------------------------------------------------# -# Movement instructions # -#---------------------------------------------------------------------------# - -# -# Load Effective Address (LEA) instruction -# -# $1 = ADDR($2) -# -# For instance: -# LEA RAX, [RBX + RCX + 4] -# will result in: -# RAX = RBX + RCX + 4 -# -# Preserves all flags -# -lea rm m - -# -# Movement (MOV) instruction -# -# $1 = $2 -# -mov rm rim - -# -# Movement with zero-extension (MOVZX) instruction -# -# $1 = ZeroExtend($2) -# -movzx rm m - -# -# Exchange (XCHG) instruction -# -# $_ = $1 -# $1 = $2 -# $2 = $_ -# -xchg rm rim - -# -# Compare-and-exchange (CMPXCHG) instruction -# -# IF ($1 == RAX) THEN -# $1 = $2 -# ZF = 1 -# ELSE -# RAX = $1 -# ZF = 0 -# FI -# -# Preserves CF, OF and SF -# -cmpxchg rm rim - -# -# Load argument #N (LDARG) -# -# IF ($2 < 8) THEN -# $1 = AX$2 -# ELSE -# $1 = LX($2-8) -# FI -# -# Throws: -# #ILL if $2 ≥ 16 -# -ldarg rm rim - -#---------------------------------------------------------------------------# -# Stack manipulation instructions # -#---------------------------------------------------------------------------# - -# -# Unconditional jump with possible return (CALL) -# -# PUSH(RIP) -# JMP(RIP) -# -call rim - -# -# Return to caller (RET) -# -# POP(RIP) -# -ret - -# -# Make new stack frame (ENTER) -# -# PUSH(RBP) -# RBP = RSP -# RSP = RSP - $1 -# -enter i - -# -# Leave stack frame (LEAVE) -# -# RSP = RBP -# POP(RBP) -# -leave - -# -# PUSH value onto stack -# -# RSP = RSP - 8 -# *RSP = $1 -# -push rim - -# -# POP value from stack -# -# $1 = *RSP -# RSP = RSP + 8 -# -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) -# -# See dv/DEVAPI -# -devctl rim rim - -# -# Call a device-defined function slot of device (IOCALL) -# -# See dv/DEVAPI -# -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 - -# -# Get timestamp in seconds -# -time rm - -# -# Get timestamp in µseconds -# -utime rm - -# -# 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 # -#---------------------------------------------------------------------------# - -# -# Clear or set interrupt flag (CLI/STI) -# -# Throws: -# #SYS if not in supervisor mode -# -cli -sti - -# -# Clear or set direction flag (CLD/STD) -# -cld -std - -# -# Complement, clear or set carry flag (CMC/CLC/STC) -# -cmc -clc -stc - -# -# Load FLG register (LODF) -# -# $1 = FLG -# -lodf rm - -# -# Store FLG register - lower byte only (STOFB) -# -# FLG[7:0] = $1[7:0] -# -# Note: FLG's lower byte contains CF, OF, ZF, SF, PF and DF -# -stofb rm - -#---------------------------------------------------------------------------# -# Byte-wise / bit-wise manipulation instructions # -#---------------------------------------------------------------------------# - -# -# Byte/word/dword swap (xSWAP) -# -# Change endianness -# -bswap rm rim -wswap rm rim -dswap rm rim - -#---------------------------------------------------------------------------# -# String manipulation instructions # -#---------------------------------------------------------------------------# - -# -# Store value into string (STOSx) -# -# [%1] = $2 -# IF (DF == 0) THEN -# %str = %str + sizeof(x) -# ELSE -# %str = %str - sizeof(x) -# FI -# -# When no parameters are given, %str = RDI and $val = RAX -# When one parameter is given, %str = RDI and $val = $1 -# When two parameters are given, %str = $1 and $val = $2 -# -stosb r rim -stosw r rim -stosl r rim -stosq r rim - -# -# Load value from string (LODSx) -# -# $1 = [%2] -# IF (DF == 0) THEN -# %str = %str + sizeof(x) -# ELSE -# %str = %str - sizeof(x) -# FI -# -# Preserves CF, OF and SF -# Sets ZF according to the loaded value -# -lodsb r r -lodsw r r -lodsl r r -lodsq r r - -# -# Scan string for a particular value (SCASx) -# -# CMP([%1], $2) -# -# IF ([%1] == 0) THEN -# ZF = 1 -# ELIF (ZF == 0) THEN -# IF (DF == 0) THEN -# %1 = %1 + sizeof(x) -# ELSE -# %1 = %1 - sizeof(x) -# FI -# FI -# -# Sets CF, OF and SF according to the result of the comparison -# Sets ZF according to whether [%1] and $2 are equal, OR if [%1] is null -# -# Notes: -# - Does not move past the value when found -# - 'SCASB.REP.NZ reg ch' is a short 'strchnul()' -# -scasb r rim -scasw r rim -scasl r rim -scasq r rim - -# -# Compare bytes in strings (CMPSx) -# -# CMP([%1], [%2]) -# -# IF (DF == 0) THEN -# %1 = %1 + sizeof(x) -# %2 = %2 + sizeof(x) -# ELSE -# %1 = %1 - sizeof(x) -# %2 = %2 - sizeof(x) -# FI -# -# Sets CF, OF, ZF and SF according to the result of the comparison -# -# Moves past the compared values in any case! -# -cmpsb r r -cmpsw r r -cmpsl r r -cmpsq r r - -# -# Safe compare bytes in strings (CMPZSx) -# -# Behaves precisely like CMPSx, except in the following case: -# - If both [%1] and [%2] are zero, clears ZF (indicating NOT EQUAL) -# -# This prevents 'CMPZSx.REP.Z' from looping infinitely when both strings -# have the exact same content; this allows for short strcmp's -# -cmpzsb r r -cmpzsw r r -cmpzsl r r -cmpzsq r r - -# -# Move value from string to string (MOVSx) -# -# [%1] = [%1] -# IF (DF == 0) THEN -# %1 = %1 + sizeof(x) -# %2 = %2 + sizeof(x) -# ELSE -# %1 = %1 - sizeof(x) -# %2 = %2 - sizeof(x) -# FI -# -# Preserves CF, OF and SF -# Sets ZF according to the moved value -# -movsb r r -movsw r r -movsl r r -movsq r r - -#---------------------------------------------------------------------------# +include "SUPER" +include "TRAP" +include "MOV" +include "MISC" +include "LOGIC" +include "ARITH" +include "JUMPS" +include "STACK" +include "FLAGS" +include "INOUT" +include "DEBUG" +include "STRING" diff --git a/vm/in/JUMPS b/vm/in/JUMPS new file mode 100644 index 0000000..e7ad97f --- /dev/null +++ b/vm/in/JUMPS @@ -0,0 +1,24 @@ +# The OS/K Team licenses this file to you under the MIT license. +# See the LICENSE file in the project root for more information. + +#---------------------------------------------------------------------------# +# Jump instructions # +#---------------------------------------------------------------------------# + +# +# Unconditional jump (JMP) instruction +# +# RIP = $1 +# +j ri +jmp ri + +# +# RCX-dependent jump (LOOP) instruction +# +# IF (RCX > 0) THEN +# RCX = RCX - 1 +# RIP = $1 +# FI +# +loop ri diff --git a/vm/in/LOGIC b/vm/in/LOGIC new file mode 100644 index 0000000..88fed45 --- /dev/null +++ b/vm/in/LOGIC @@ -0,0 +1,65 @@ +# The OS/K Team licenses this file to you under the MIT license. +# See the LICENSE file in the project root for more information. + +#---------------------------------------------------------------------------# +# Logical instructions # +#---------------------------------------------------------------------------# + +# +# TEST Comparison instruction +# +# $1 AND $2 +# +# Clears OF and CF +# Sets ZF and SF according to the result +# +test rim rim + +# +# Bitwise NOT operation +# +# $1 = NOT($1) +# +# Preserves all flags +# +not rm + +# +# Bitwise OR operation +# +# $1 = $1 OR $2 +# +# Clears OF and CF +# Sets ZF and SF according to the result +# +or rm rim +orf rm rim + +# +# Bitwise AND operation +# +# $1 = $1 AND $2 +# +# Clears OF and CF +# Sets ZF and SF according to the result +# +and rm rim +andf rm rim + +# +# Bitwise XOR operation +# +# $1 = $1 XOR $2 +# +# Clears OF and CF +# Sets ZF and SF according to the result +# +xor rm rim +xorf rm rim + +# To document +shl rm rim +shr rm rim +shlf rm rim +shrf rm rim + diff --git a/vm/in/MISC b/vm/in/MISC new file mode 100644 index 0000000..1b16d47 --- /dev/null +++ b/vm/in/MISC @@ -0,0 +1,83 @@ +# The OS/K Team licenses this file to you under the MIT license. +# See the LICENSE file in the project root for more information. + +#---------------------------------------------------------------------------# +# 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 + +# +# Pause the CPU for a relatively long time (XPAUSE) +# +# Throws: +# #SYS if not in supervisor mode +# +xpause + +# +# Get timestamp in seconds +# +time rm + +# +# Get timestamp in µseconds +# +utime rm + +# +# CPU Identification Number +# +# Does nothing (for now) +# +cpuid + +#---------------------------------------------------------------------------# +# 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 + +#---------------------------------------------------------------------------# +# Byte-wise / bit-wise manipulation instructions # +#---------------------------------------------------------------------------# + +# +# Byte/word/dword swap (xSWAP) +# +# Change endianness +# +bswap rm rim +wswap rm rim +dswap rm rim + diff --git a/vm/in/MOV b/vm/in/MOV new file mode 100644 index 0000000..3fda2f2 --- /dev/null +++ b/vm/in/MOV @@ -0,0 +1,82 @@ +# The OS/K Team licenses this file to you under the MIT license. +# See the LICENSE file in the project root for more information. + +#---------------------------------------------------------------------------# +# Movement instructions # +#---------------------------------------------------------------------------# + +# +# Load Effective Address (LEA) instruction +# +# $1 = ADDR($2) +# +# For instance: +# LEA RAX, [RBX + RCX + 4] +# will result in: +# RAX = RBX + RCX + 4 +# +# Preserves all flags +# +lea rm m + +# +# Movement (MOV) instruction +# +# $1 = $2 +# +mov rm rim + +# +# Movement with zero-extension (MOVZX) instruction +# +# $1 = ZeroExtend($2) +# +movzx rm m + +# +# Exchange (XCHG) instruction +# +# $_ = $1 +# $1 = $2 +# $2 = $_ +# +xchg rm rim + +# +# Compare-and-exchange (CMPXCHG) instruction +# +# IF ($1 == RAX) THEN +# $1 = $2 +# ZF = 1 +# ELSE +# RAX = $1 +# ZF = 0 +# FI +# +# Preserves CF, OF and SF +# +cmpxchg rm rim + +# +# Load argument #N (LDARG) +# +# IF ($2 < 8) THEN +# $1 = AX$2 +# ELSE +# $1 = LX($2-8) +# FI +# +# Throws: +# #ILL if $2 ≥ 16 +# +ldarg rm rim + +# +# Get code/data offset (GCO/GCD) +# +# $1 = CR1 (GCO) +# $1 = CR2 (GCD) +# +gco rm +gcd rm + diff --git a/vm/in/STACK b/vm/in/STACK new file mode 100644 index 0000000..e3aac88 --- /dev/null +++ b/vm/in/STACK @@ -0,0 +1,55 @@ +# The OS/K Team licenses this file to you under the MIT license. +# See the LICENSE file in the project root for more information. + +#---------------------------------------------------------------------------# +# Stack manipulation instructions # +#---------------------------------------------------------------------------# + +# +# Unconditional jump with possible return (CALL) +# +# PUSH(RIP) +# JMP(RIP) +# +call rim + +# +# Return to caller (RET) +# +# POP(RIP) +# +ret + +# +# Make new stack frame (ENTER) +# +# PUSH(RBP) +# RBP = RSP +# RSP = RSP - $1 +# +enter i + +# +# Leave stack frame (LEAVE) +# +# RSP = RBP +# POP(RBP) +# +leave + +# +# PUSH value onto stack +# +# RSP = RSP - 8 +# *RSP = $1 +# +push rim + +# +# POP value from stack +# +# $1 = *RSP +# RSP = RSP + 8 +# +pop rm + diff --git a/vm/in/STRING b/vm/in/STRING new file mode 100644 index 0000000..af310e9 --- /dev/null +++ b/vm/in/STRING @@ -0,0 +1,129 @@ +# The OS/K Team licenses this file to you under the MIT license. +# See the LICENSE file in the project root for more information. + +#---------------------------------------------------------------------------# +# String manipulation instructions # +#---------------------------------------------------------------------------# + +# +# Store value into string (STOSx) +# +# [%1] = $2 +# IF (DF == 0) THEN +# %str = %str + sizeof(x) +# ELSE +# %str = %str - sizeof(x) +# FI +# +# When no parameters are given, %str = RDI and $val = RAX +# When one parameter is given, %str = RDI and $val = $1 +# When two parameters are given, %str = $1 and $val = $2 +# +stosb r rim +stosw r rim +stosl r rim +stosq r rim + +# +# Load value from string (LODSx) +# +# $1 = [%2] +# IF (DF == 0) THEN +# %str = %str + sizeof(x) +# ELSE +# %str = %str - sizeof(x) +# FI +# +# Preserves CF, OF and SF +# Sets ZF according to the loaded value +# +lodsb r r +lodsw r r +lodsl r r +lodsq r r + +# +# Scan string for a particular value (SCASx) +# +# CMP([%1], $2) +# +# IF ([%1] == 0) THEN +# ZF = 1 +# ELIF (ZF == 0) THEN +# IF (DF == 0) THEN +# %1 = %1 + sizeof(x) +# ELSE +# %1 = %1 - sizeof(x) +# FI +# FI +# +# Sets CF, OF and SF according to the result of the comparison +# Sets ZF according to whether [%1] and $2 are equal, OR if [%1] is null +# +# Notes: +# - Does not move past the value when found +# - 'SCASB.REP.NZ reg ch' is a short 'strchnul()' +# +scasb r rim +scasw r rim +scasl r rim +scasq r rim + +# +# Compare bytes in strings (CMPSx) +# +# CMP([%1], [%2]) +# +# IF (DF == 0) THEN +# %1 = %1 + sizeof(x) +# %2 = %2 + sizeof(x) +# ELSE +# %1 = %1 - sizeof(x) +# %2 = %2 - sizeof(x) +# FI +# +# Sets CF, OF, ZF and SF according to the result of the comparison +# +# Moves past the compared values in any case! +# +cmpsb r r +cmpsw r r +cmpsl r r +cmpsq r r + +# +# Safe compare bytes in strings (CMPZSx) +# +# Behaves precisely like CMPSx, except in the following case: +# - If both [%1] and [%2] are zero, clears ZF (indicating NOT EQUAL) +# +# This prevents 'CMPZSx.REP.Z' from looping infinitely when both strings +# have the exact same content; this allows for short strcmp's +# +cmpzsb r r +cmpzsw r r +cmpzsl r r +cmpzsq r r + +# +# Move value from string to string (MOVSx) +# +# [%1] = [%1] +# IF (DF == 0) THEN +# %1 = %1 + sizeof(x) +# %2 = %2 + sizeof(x) +# ELSE +# %1 = %1 - sizeof(x) +# %2 = %2 - sizeof(x) +# FI +# +# Preserves CF, OF and SF +# Sets ZF according to the moved value +# +movsb r r +movsw r r +movsl r r +movsq r r + +#---------------------------------------------------------------------------# + diff --git a/vm/in/SUPER b/vm/in/SUPER new file mode 100644 index 0000000..6e98a2f --- /dev/null +++ b/vm/in/SUPER @@ -0,0 +1,37 @@ +# The OS/K Team licenses this file to you under the MIT license. +# See the LICENSE file in the project root for more information. + +#---------------------------------------------------------------------------# +# Supervisor only instructions # +#---------------------------------------------------------------------------# + +# +# Initiate machine shutdown (STOP) +# +# THROW #SHT +# +# Throws: +# #SYS if not in supervisor mode +# #ILL if disabled through DV +# #SHT otherwise +# +stop + +# +# Halt the processor until next E/I (HLT) +# +hlt + +# +# Call an architecture-reserved function slot of device (DEVCTL) +# +# See dv/DEVAPI +# +devctl rim rim + +# +# Call a device-defined function slot of device (IOCALL) +# +# See dv/DEVAPI +# +iocall rim rim diff --git a/vm/in/TRAP b/vm/in/TRAP new file mode 100644 index 0000000..a2b15ea --- /dev/null +++ b/vm/in/TRAP @@ -0,0 +1,20 @@ +# The OS/K Team licenses this file to you under the MIT license. +# See the LICENSE file in the project root for more information. + +#---------------------------------------------------------------------------# +# 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 diff --git a/vm/in/arch_i.c b/vm/in/arch_i.c new file mode 100644 index 0000000..d6aeb1f --- /dev/null +++ b/vm/in/arch_i.c @@ -0,0 +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. + +#include + +#define _NEED_ARCH_I +#include diff --git a/vm/in/arch_i.py b/vm/in/arch_i.py index 9a55a3d..0551f9c 100644 --- a/vm/in/arch_i.py +++ b/vm/in/arch_i.py @@ -5,6 +5,114 @@ from tempfile import TemporaryFile +def getflag(s): + if s == "r": + return "P_REG" + + if s == "i": + return "P_IMM" + + if s == "m": + return "P_MEM" + + return "__FLAG_ERROR__" + +def doprnt(fp, i, p1, p2): + for c1 in p1: + for c2 in p2: + fp.write("{} {} {}".format(i, c1, c2).strip()) + fp.write('\n') + +def parse_1(fi, fp): + global count + + # "instr ri ri" => "instr r r\ninstr r i\ninstr i r..." + # not optimal but will do for now + for _, line in enumerate(fi): + if line[0] == '#' or line[0] == ' ' or line[0] == '\n': + continue + + line = line.strip() + + if line[:8] == "include ": + _, fn = line.split(' ', 1) + fi2 = open(fn[1:-1]) + parse_1(fi2, fp) + continue + + tok = line.split(' ') + + if len(tok) == 0: + continue + + i = tok[0].strip() + + if len(tok) == 1: + doprnt(fp, i, ' ', ' ') + continue + + if len(tok) == 2: + p = tok[1].strip() + doprnt(fp, i, p, ' ') + continue + + assert(len(tok) == 3) + + p1 = tok[1].strip() + p2 = tok[2].strip() + + doprnt(fp, i, p1, p2) + + fi.close() + +def parse_2(fp): + global count + fp.seek(0) + + for _, line in enumerate(fp): + tok = line.strip().split(' ') + + assert(len(tok) > 0) + + deprecated = '' + if tok[0][0] == '!': + assert(len(tok[0]) > 1) + deprecated = '__' + tok[0] = tok[0][1:] + + if len(tok) == 1: + name = tok[0] + p1 = "NOPRM" + p2 = "NOPRM" + + elif len(tok) == 2: + name = "{}_{}".format(tok[0], tok[1].strip()) + p1 = getflag(tok[1]) + p2 = "NOPRM" + + elif len(tok) == 3: + name = "{}_{}_{}".format(tok[0], tok[1], tok[2].strip()) + p1 = getflag(tok[1]) + p2 = getflag(tok[2]) + + else: + name = "__TOK_ERROR__" + p1 = "__TOK_ERROR__" + p2 = "__TOK_ERROR__" + + ls.write("{}{}\n".format(deprecated, name)) + + hd.write("#ifdef _NEED_ARCH_I\n") + hd.write('{{ "{}{}", "{}{}", {}, {}, i_{} }},\n'\ + .format(deprecated, tok[0], deprecated, name, p1, p2, tok[0])) + hd.write("#else\n") + hd.write("#define I_{} {}\n".format(name.upper(), count)) + hd.write("extern bool i_{}(ctx_t *, acc_t *, acc_t *, ulong *, ulong *);\n" + .format(tok[0])) + hd.write("#endif\n\n") + + count = count + 1 + fi = open("INSTRS") hd = open("arch_i.h", "w") ls = open("instrs.lst", "w") @@ -18,99 +126,8 @@ hd.write("instr_t arch_i[] =\n{\n\n") hd.write("#endif\n") fp = TemporaryFile(mode="w+") - -def getflag(s): - if s == "r": - return "P_REG" - - if s == "i": - return "P_IMM" - - if s == "m": - return "P_MEM" - - return "__FLAG_ERROR__" - -def doprnt(i, p1, p2): - for c1 in p1: - for c2 in p2: - fp.write("{} {} {}".format(i, c1, c2).strip()) - fp.write('\n') - -# "instr ri ri" => "instr r r\ninstr r i\ninstr i r..." -# not optimal but will do for now -for _, line in enumerate(fi): - if line[0] == '#' or line[0] == ' ' or line[0] == '\n': - continue - - tok = line.strip().split(' ') - - if len(tok) == 0: - continue - - i = tok[0].strip() - - if len(tok) == 1: - doprnt(i, ' ', ' ') - continue - - if len(tok) == 2: - p = tok[1].strip() - doprnt(i, p, ' ') - continue - - assert(len(tok) == 3) - - p1 = tok[1].strip() - p2 = tok[2].strip() - - doprnt(i, p1, p2) - -fp.seek(0) - -for _, line in enumerate(fp): - tok = line.strip().split(' ') - - assert(len(tok) > 0) - - deprecated = '' - if tok[0][0] == '!': - assert(len(tok[0]) > 1) - deprecated = '__' - tok[0] = tok[0][1:] - - if len(tok) == 1: - name = tok[0] - p1 = "NOPRM" - p2 = "NOPRM" - - elif len(tok) == 2: - name = "{}_{}".format(tok[0], tok[1].strip()) - p1 = getflag(tok[1]) - p2 = "NOPRM" - - elif len(tok) == 3: - name = "{}_{}_{}".format(tok[0], tok[1], tok[2].strip()) - p1 = getflag(tok[1]) - p2 = getflag(tok[2]) - - else: - name = "__TOK_ERROR__" - p1 = "__TOK_ERROR__" - p2 = "__TOK_ERROR__" - - ls.write("{}{}\n".format(deprecated, name)) - - hd.write("#ifdef _NEED_ARCH_I\n") - hd.write('{{ "{}{}", "{}{}", {}, {}, i_{} }},\n'\ - .format(deprecated, tok[0], deprecated, name, p1, p2, tok[0])) - hd.write("#else\n") - hd.write("#define I_{} {}\n".format(name.upper(), count)) - hd.write("extern bool i_{}(ctx_t *, acc_t *, acc_t *, ulong *, ulong *);\n" - .format(tok[0])) - hd.write("#endif\n\n") - - count = count + 1 +parse_1(fi, fp) +parse_2(fp) hd.write("#ifdef _NEED_ARCH_I\n") hd.write("};\n") @@ -120,5 +137,4 @@ hd.write("#endif\n") ls.close() hd.close() -fi.close() diff --git a/vm/in/devctl.c b/vm/in/devctl.c deleted file mode 100644 index f2cf3d2..0000000 --- a/vm/in/devctl.c +++ /dev/null @@ -1,106 +0,0 @@ -// 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 - -// -// code common to devctl and iocall -// -dev_t *devctl_common(ctx_t *ctx, ulong v1, ulong v2) -{ - dev_t *dev = devget(ctx, v1); - - if (!dev) - rax = -2; - - else if (dev->state == DEVPWOF) - rax = -3; - - else if (dev->state == DEVFERR) - rax = -4; - - else if (dev->state == DEVPLUG) - rax = -5; - - else - return dev; - - return NULL; -} - -void copystr(ctx_t *ctx, ulong addr, ulong maxn, char *str) -{ - for (; *str && maxn > 0; str++, addr++, maxn--) { - writemem(ctx, *str, addr, 1); - } - - writemem(ctx, 0, addr, 1); -} - -IMPL_START_2(devctl) -{ - CHK_SUPERV(); - - dev_t *dev = devctl_common(ctx, v1, v2); - - if (dev == NULL) - return 0; - - switch (v2) { - case 0: - copystr(ctx, ax0, DEVLEN, dev->type); - break; - - case 1: - copystr(ctx, ax0, DEVLEN, dev->name); - break; - - case 2: - copystr(ctx, ax0, DEVLEN, dev->modl); - break; - - case 3: - copystr(ctx, ax0, DEVLEN, dev->vend); - break; - - case 4: - rax = dev->major; - rdx = dev->minor; - break; - - case 5: - rax = dev->feats; - rdx = dev->revis; - break; - - default: - rax = -6; - break; - } -} -IMPL_END; - -IMPL_START_2(iocall) -{ - CHK_SUPERV(); - - long rc; - dev_t *dev = devctl_common(ctx, v1, v2); - - if (dev == NULL) - return 0; - - if (v2 >= DEVSLOTS) - rax = -6; - - else if (dev->fslots[v2] == NULL) - rax = -6; - - else { - rc = dev->fslots[v2](ctx, dev); - if (rc < 0) rax = rc; - } -} -IMPL_END; - diff --git a/vm/in/flags.c b/vm/in/flags.c index d1de65c..f4412d3 100644 --- a/vm/in/flags.c +++ b/vm/in/flags.c @@ -5,6 +5,22 @@ //----------------------------------------------------------------------------// +IMPL_START_0(cli) +{ + CHK_SUPERV(); + cr0 &= ~IF; +} +IMPL_END; + +IMPL_START_0(sti) +{ + CHK_SUPERV(); + cr0 |= IF; +} +IMPL_END; + +//----------------------------------------------------------------------------// + IMPL_START_0(cld) { flg &= ~DF; diff --git a/vm/in/instrs.c b/vm/in/instrs.c deleted file mode 100644 index e835c16..0000000 --- a/vm/in/instrs.c +++ /dev/null @@ -1,90 +0,0 @@ -// 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 -#include -#include - -#include - -#define _NEED_ARCH_I -#include - -//----------------------------------------------------------------------------// - -IMPL_START_0(nop) -{ -} -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; -} -IMPL_END; - -//----------------------------------------------------------------------------// - -IMPL_START_1(rand32) -{ - v1 = (int)random(); -} -IMPL_OUT; - -IMPL_START_1(rand64) -{ - v1 = (random() << 32) | (int)random(); -} -IMPL_OUT; - -//----------------------------------------------------------------------------// - -IMPL_START_1(time) -{ - v1 = time(NULL); -} -IMPL_OUT; - -IMPL_START_1(utime) -{ - struct timeval time; - gettimeofday(&time, NULL); - v1 = (time.tv_sec * 1000) + (time.tv_usec / 1000); -} -IMPL_OUT; - -//----------------------------------------------------------------------------// - -IMPL_START_0(clr) -{ - rax = rbx = rcx = rdx = 0; - rsx = rbi = rdi = rsi = 0; -} -IMPL_END; - -IMPL_START_0(cla) -{ - ax0 = ax1 = ax2 = ax3 = 0; - ax4 = ax5 = ax6 = ax7 = 0; -} -IMPL_END; - -//----------------------------------------------------------------------------// diff --git a/vm/in/misc.c b/vm/in/misc.c index de01301..91e2460 100644 --- a/vm/in/misc.c +++ b/vm/in/misc.c @@ -2,6 +2,71 @@ // See the LICENSE file in the project root for more information. #include +#include +#include +#include + +//----------------------------------------------------------------------------// + +IMPL_START_0(nop) +{ +} +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; +} +IMPL_END; + +//----------------------------------------------------------------------------// + +IMPL_START_1(time) +{ + v1 = time(NULL); +} +IMPL_OUT; + +IMPL_START_1(utime) +{ + struct timeval time; + gettimeofday(&time, NULL); + v1 = (time.tv_sec * 1000) + (time.tv_usec / 1000); +} +IMPL_OUT; + +//----------------------------------------------------------------------------// + +IMPL_START_0(clr) +{ + rax = rbx = rcx = rdx = 0; + rsx = rbi = rdi = rsi = 0; +} +IMPL_END; + +IMPL_START_0(cla) +{ + ax0 = ax1 = ax2 = ax3 = 0; + ax4 = ax5 = ax6 = ax7 = 0; +} +IMPL_END; //----------------------------------------------------------------------------// diff --git a/vm/in/super.c b/vm/in/super.c index 8660e6a..b2e1bdf 100644 --- a/vm/in/super.c +++ b/vm/in/super.c @@ -2,9 +2,17 @@ // See the LICENSE file in the project root for more information. #include +#include #include #include +IMPL_START_0(stop) +{ + CHK_SUPERV(); + _except(ctx, E_SHT, "STOP INSTR"); +} +IMPL_END; + IMPL_START_0(hlt) { CHK_SUPERV(); @@ -21,24 +29,103 @@ IMPL_START_0(hlt) } IMPL_END; -IMPL_START_0(cli) +// +// code common to devctl and iocall +// +dev_t *devctl_common(ctx_t *ctx, ulong v1, ulong v2) +{ + dev_t *dev = devget(ctx, v1); + + if (!dev) + rax = -2; + + else if (dev->state == DEVPWOF) + rax = -3; + + else if (dev->state == DEVFERR) + rax = -4; + + else if (dev->state == DEVPLUG) + rax = -5; + + else + return dev; + + return NULL; +} + +void copystr(ctx_t *ctx, ulong addr, ulong maxn, char *str) +{ + for (; *str && maxn > 0; str++, addr++, maxn--) { + writemem(ctx, *str, addr, 1); + } + + writemem(ctx, 0, addr, 1); +} + +IMPL_START_2(devctl) { CHK_SUPERV(); - cr0 &= ~IF; + + dev_t *dev = devctl_common(ctx, v1, v2); + + if (dev == NULL) + return 0; + + switch (v2) { + case 0: + copystr(ctx, ax0, DEVLEN, dev->type); + break; + + case 1: + copystr(ctx, ax0, DEVLEN, dev->name); + break; + + case 2: + copystr(ctx, ax0, DEVLEN, dev->modl); + break; + + case 3: + copystr(ctx, ax0, DEVLEN, dev->vend); + break; + + case 4: + rax = dev->major; + rdx = dev->minor; + break; + + case 5: + rax = dev->feats; + rdx = dev->revis; + break; + + default: + rax = -6; + break; + } } IMPL_END; -IMPL_START_0(sti) +IMPL_START_2(iocall) { CHK_SUPERV(); - cr0 |= IF; -} -IMPL_END; - -IMPL_START_0(stop) -{ - CHK_SUPERV(); - _except(ctx, E_SHT, "STOP INSTR"); + + long rc; + dev_t *dev = devctl_common(ctx, v1, v2); + + if (dev == NULL) + return 0; + + if (v2 >= DEVSLOTS) + rax = -6; + + else if (dev->fslots[v2] == NULL) + rax = -6; + + else { + rc = dev->fslots[v2](ctx, dev); + if (rc < 0) rax = rc; + } } IMPL_END; diff --git a/vm/in/trap.c b/vm/in/trap.c index b85a0df..08de390 100644 --- a/vm/in/trap.c +++ b/vm/in/trap.c @@ -3,8 +3,6 @@ #include -static volatile long *prev_stk; - IMPL_START_1(trap) { if (v1 > 255) diff --git a/vm/pc/console.c b/vm/pc/console.c index 2ae40db..c68a2ee 100644 --- a/vm/pc/console.c +++ b/vm/pc/console.c @@ -3,8 +3,15 @@ #include -#define CONSOLE_WIDTH 80 -#define CONSOLE_HEIGHT 25 +#ifndef _LARGE_SCREEN +# define CONSOLE_WIDTH 80 +# define CONSOLE_HEIGHT 25 +# define CONSOLE_FONT_SIZE 16 +#else +# define CONSOLE_WIDTH 160 +# define CONSOLE_HEIGHT 50 +# define CONSOLE_FONT_SIZE 32 +#endif #define SCREEN_WIDTH (9 * CONSOLE_WIDTH) #define SCREEN_HEIGHT (16 * CONSOLE_HEIGHT) @@ -43,7 +50,7 @@ void console_init(ctx_t *ctx) TTF_Init(); scr_font = TTF_OpenFont - ("fn/console_font.ttf", 16); + ("fn/console_font.ttf", CONSOLE_FONT_SIZE); if (scr_font == NULL) { diff --git a/vm/pc/dump.c b/vm/pc/dump.c index 7357321..05eba20 100644 --- a/vm/pc/dump.c +++ b/vm/pc/dump.c @@ -28,7 +28,11 @@ void dump_instr(ctx_t *ctx, uint cond, ulong pc) { +/* trace("%03lu 0x%lX:\t", ctx->ninstrs, pc); +*/ + + trace("0x%lX:\t", pc); if (lock) trace("lock"); diff --git a/vm/pc/except.c b/vm/pc/except.c index 3f50014..a4fbe72 100644 --- a/vm/pc/except.c +++ b/vm/pc/except.c @@ -10,7 +10,6 @@ void _except(ctx_t *ctx, int _code, char *fmt, ...) va_list ap; ulong handler; uint code = _code; - volatile char ch; ulong orig_frame;