From 1c9272a954ae2bdf15e87b162bb0737e00774cd9 Mon Sep 17 00:00:00 2001 From: Mike Lowis Date: Tue, 16 Jul 2024 16:33:05 -0400 Subject: [PATCH] added space allocations for system variables and stubbed out where builtin word definitions will go --- asm.rb | 311 ++++++++++++++++++++++++++++++++++----------------- asm.s | 37 +++++- jonesforth.S | 2 +- 3 files changed, 242 insertions(+), 108 deletions(-) diff --git a/asm.rb b/asm.rb index cb7eb43..8ad54ef 100755 --- a/asm.rb +++ b/asm.rb @@ -37,40 +37,62 @@ def builtin(name, &code) $words[name] = Word.new(name, 0, code) end -$input = $stdin -$stack = [] -$state = 0 -$curr = nil +#------------------------------------------ +# Interpreter/Compiler State +#------------------------------------------ +$base = 10 +$input = $stdin +$stack = [] +$state = 0 +$curr = nil $buffer = "" -$words = { -# 'load-imm' => lambda { -# puts "load-imm" -# PROG.push(0x48) -# PROG.push(0xc7) -# PROG.push(0xC0 + $stack.pop) -# imm = $stack.pop -# PROG.push((imm >> 0) & 0xff) -# PROG.push((imm >> 8) & 0xff) -# PROG.push((imm >> 16) & 0xff) -# PROG.push((imm >> 24) & 0xff) -# }, -} - +$words = {} #------------------------------------------ # Stack Manipulation #------------------------------------------ -builtin('drop') { } -builtin('swap') { } -builtin('dup') { } -builtin('over') { } -builtin('rot') { } -builtin('-rot') { } - -builtin('2drop') { } -builtin('2swap') { } -builtin('2dup') { } -builtin('?dup') { } +builtin('drop') { + pop() +} + +builtin('swap') { + a = pop() + b = pop() + push a + push b +} + +builtin('dup') { + push $stack.last +} + +builtin('over') { + push $stack[-2] +} + +builtin('rot') { + +} + +builtin('-rot') { + +} + +builtin('2drop') { + +} + +builtin('2swap') { + +} + +builtin('2dup') { + +} + +builtin('?dup') { + +} builtin('1+') { } builtin('1-') { } @@ -83,10 +105,10 @@ builtin('8-') { } # Aritmetic #------------------------------------------ builtin('+') { push(pop() + pop()) } -builtin('-') { push(pop() - pop()) } +builtin('-') { a = pop(); push(pop() - a) } builtin('*') { push(pop() * pop()) } -builtin('/') { push(pop() / pop()) } -builtin('%') { push(pop() % pop()) } +builtin('/') { a = pop(); push(pop() / a) } +builtin('%') { a = pop(); push(pop() % a) } #------------------------------------------ # Comparison @@ -105,7 +127,6 @@ builtin('0>') { push(pop() > 0) } builtin('0<=') { push(pop() <= 0) } builtin('0>=') { push(pop() >= 0) } - #------------------------------------------ # Bitwise Operations #------------------------------------------ @@ -127,7 +148,6 @@ builtin('invert') { push(~pop()) } #builtin('bcopy') { } #builtin('bmove') { } - #------------------------------------------ # Variables #------------------------------------------ @@ -147,13 +167,29 @@ builtin('invert') { push(~pop()) } #F_HIDDEN The HIDDEN flag's actual value. #F_LENMASK The length mask in the flags/len byte. - #------------------------------------------ # Compiler #------------------------------------------ +builtin('hex') { + $base = 16 +} + +builtin('dec') { + $base = 10 +} + +builtin('oct') { + $base = 8 +} + +builtin('bin') { + $base = 2 +} + builtin('#') { $buffer = $input.gets +# puts " #{$buffer.inspect}" } builtin('.') { @@ -165,11 +201,20 @@ builtin('.') { } builtin('word') do - if $buffer.length == 0 then - $buffer = $input.gets +# puts " word" + word = nil + while word.nil? + if $buffer.length == 0 then + $buffer = $input.gets +# puts " #{$buffer.inspect}" + break if $buffer.nil? + end + $buffer.slice!(/^\s*/) + word = $buffer.slice!(/^[^\s]+/) end - $buffer.slice!(/^\s*/) - push $buffer.slice!(/^[^\s]+/) +# puts " word: #{word}" +# puts " end word" + push word end builtin('create') do @@ -200,52 +245,121 @@ word(';', IMM, [ ']', 'register' ]) # Assembler Words #------------------------------------------ -def pack8(val) - PROG.push(val & 0xff) +def pack8(val, off = nil) + PROG[off || PROG.length] = (val & 0xff) end -def pack16(val) - PROG.push((val >> 0) & 0xff) - PROG.push((val >> 8) & 0xff) +def pack16(val, off = nil) + off ||= PROG.length + PROG[off + 0] = ((val >> 0) & 0xff) + PROG[off + 1] = ((val >> 8) & 0xff) end -def pack32(val) - PROG.push((val >> 0) & 0xff) - PROG.push((val >> 8) & 0xff) - PROG.push((val >> 16) & 0xff) - PROG.push((val >> 24) & 0xff) +def pack32(val, off = nil) + off ||= PROG.length + PROG[off + 0] = ((val >> 0) & 0xff) + PROG[off + 1] = ((val >> 8) & 0xff) + PROG[off + 2] = ((val >> 16) & 0xff) + PROG[off + 3] = ((val >> 24) & 0xff) end -def pack64(val) - PROG.push((val >> 0) & 0xff) - PROG.push((val >> 8) & 0xff) - PROG.push((val >> 16) & 0xff) - PROG.push((val >> 24) & 0xff) - PROG.push((val >> 32) & 0xff) - PROG.push((val >> 40) & 0xff) - PROG.push((val >> 48) & 0xff) - PROG.push((val >> 56) & 0xff) +def pack64(val, off = nil) + off ||= PROG.length + PROG[off + 0] = ((val >> 0) & 0xff) + PROG[off + 1] = ((val >> 8) & 0xff) + PROG[off + 2] = ((val >> 16) & 0xff) + PROG[off + 3] = ((val >> 24) & 0xff) + PROG[off + 4] = ((val >> 32) & 0xff) + PROG[off + 5] = ((val >> 40) & 0xff) + PROG[off + 6] = ((val >> 48) & 0xff) + PROG[off + 7] = ((val >> 56) & 0xff) end def packBytes(bytes) PROG.append(*bytes) end -#builtin("virt-address") { -# -#} -# -#builtin("entry-offset") { -# -#} -# -#builtin("segment-size") { -# -#} -# -#builtin("segment-size") { +def unpack8(off) + PROG[off] +end + +def unpack16(off) + return ( + PROG[off] | + (PROG[off] << 8) + ) +end + +def unpack32(off) + ( + (PROG[off]) | + (PROG[off] << 8) | + (PROG[off] << 16) | + (PROG[off] << 24) + ) +end + +def unpack64(off) + ( + (PROG[off + 0]) | + (PROG[off + 1] << 8) | + (PROG[off + 2] << 16) | + (PROG[off + 3] << 24) | + (PROG[off + 4] << 32) | + (PROG[off + 5] << 40) | + (PROG[off + 6] << 48) | + (PROG[off + 7] << 56) + ) +end + + +builtin("here") { + push PROG.length +} + +builtin("@") { + push unpack64(pop()) +} + +builtin("!") { + off = pop() + val = pop() + pack64(val, off) +} + +builtin("+!") { + off = pop() + val = pop() + pack64(unpack64(off) + val, off) +} + +builtin("-!") { + off = pop() + val = pop() + pack64(unpack64(off) - val, off) +} + + + # -#} +# 0x7F, 0x45, 0x4C, 0x46, 0x02, 0x01, 0x01, 0x00, # 00 +# 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, # 08 +# 0x02, 0x00, 0x3E, 0x00, 0x01, 0x00, 0x00, 0x00, # 16 +# 0x78, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, # 24 e_entry: 0x0x00400078, (virtual memory address of entry point) +# 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, # 32 +# 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, # 40 +# 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x38, 0x00, # 48 +# 0x01, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, # 56 +# 0x01, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, # 64 +# 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, # 72 +# 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, # 78 p_vaddr: 0x00400000, (virtual address of segment in memory) +# 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, # 86 +# 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, # 94 p_filesz: 0x00011E02, (size in bytes of the segment in the file) +# 0x00, 0x00, 0xC0, 0x7F, 0x00, 0x00, 0x00, 0x00, # 102 p_memsz: 0x7FC00000, (siz + +builtin("entry-address") { push 24 } +builtin("virt-address") { push 78 } +builtin("segment-size") { push 102 } builtin('pack8') { pack8(pop()) } builtin('pack16') { pack16(pop()) } @@ -323,58 +437,53 @@ builtin('nop') { # Input Interpreter #------------------------------------------ def interp() - while (not $input.eof?) || ($buffer.length > 0) do +# puts " interp" + while (not $input.eof?) || ($buffer && $buffer.length > 0) do $words['word'].code.call() w = $stack.pop - next if w.nil? or w.length == 0 + break if w.nil? if $words[w] then if $state == 0 || (($words[w].flags & IMM) == IMM) $words[w].code.call else $curr.code << $words[w].code end - elsif w =~ /^[0-9]+$/ + elsif w =~ /^[0-9A-Fa-f]+$/ if $state == 0 - push w.to_i + push w.to_i($base) else $curr.code << lambda{ push w.to_i } end else pp $stack - puts "?" + puts "#{w.inspect} ?" $stack = [] end end +# puts " end interp" end def interp_file(file) +# puts "interp file: #{file}" prev = $input $input = File.open(file, "rb") interp() $input = prev +# puts "end interp file: #{file}" end - -interp_file("asm.s") - -#$stdin.each_line do |line| -# line.split.each do |w| -# end -#end -# -#File.read("asm.s").split.each do |w| -# if $words[w] -# $words[w].call() -# else -# $stack.push(w.to_i($base)) -# end -#end -# -# Set program length and write to disk -PROG[96] = ((PROG.length >> 0) & 0xFF) -PROG[97] = ((PROG.length >> 8) & 0xFF) -PROG[98] = ((PROG.length >> 16) & 0xFF) -PROG[99] = ((PROG.length >> 24) & 0xFF) -File.binwrite("a.out", PROG.map{|b| b.chr }.join) - - +#------------------------------------------ +# Parse Input and Generate Output +#------------------------------------------ +if ARGV.length > 0 + ARGV.each {|f| interp_file(f) } + + # Set program length and write to disk + PROG[96] = ((PROG.length >> 0) & 0xFF) + PROG[97] = ((PROG.length >> 8) & 0xFF) + PROG[98] = ((PROG.length >> 16) & 0xFF) + PROG[99] = ((PROG.length >> 24) & 0xFF) + File.binwrite("a.out", PROG.map{|b| b.chr }.join) +else + interp() +end diff --git a/asm.s b/asm.s index d80ac93..f0bcc34 100644 --- a/asm.s +++ b/asm.s @@ -1,10 +1,35 @@ +# record our current offset for later use +here + +# ---------------------------------------- +# SYSTEM VARIABLES +# ---------------------------------------- + # Allocate space for variables -# 0 pack64 # STATE -# 0 pack64 # HERE -# 0 pack64 # LATEST -# 0 pack64 # S0 -# 0 pack64 # R0 +0 pack64 # LATEST +0 pack64 # STATE +0 pack64 # HERE +0 pack64 # S0 +0 pack64 # R0 + +# ---------------------------------------- +# DEFINE BUILTIN WORDS +# ---------------------------------------- + +# quit: +# Loop Forever +# r0 +# rsp! +# interpret +# end + +# ---------------------------------------- +# ENTRY CODE STARTS HERE +# ---------------------------------------- + +# update our entry address to here +here swap - entry-address +! 60 rax load-imm -0 rdi load-imm +42 rdi load-imm syscall diff --git a/jonesforth.S b/jonesforth.S index 8d23e39..487faba 100644 --- a/jonesforth.S +++ b/jonesforth.S @@ -1053,7 +1053,7 @@ code_\label : // assembler code follows /* ! and @ (STORE and FETCH) store 32-bit words. It's also useful to be able to read and write bytes - so we also define standard words C@ and C!. + so we also defe standard words C@ and C!. Byte-oriented operations only work on architectures which permit them (i386 is one of those). */ -- 2.54.0