work on Integer.to_s , not a simple task as it turns out
This commit is contained in:
parent
918ede1c02
commit
b4c79d218f
@ -72,8 +72,57 @@ module Arm
|
||||
syscall( block , 4 )
|
||||
end
|
||||
|
||||
# make a string out of the integer.
|
||||
# as we don't have memory manegement yet, you have to pass the string in (ouch)
|
||||
# in a weird twist the string is actually a string, while we actually use its address.
|
||||
def integer_to_s block , string
|
||||
number = Vm::Integer.new(0)
|
||||
tos = Vm::Block.new("integer_to_s") # need to create a block to jump to
|
||||
block.add_code(tos) # and then use the new block to add code
|
||||
#STMFD sp!, {r9, r10, lr} #function entry save working regs (for recursion)
|
||||
tos.add_code( push :regs => [:lr ]) #and the return address.
|
||||
# MOV r9, r1 # preserve arguments over following
|
||||
# MOV r10, r2 # function calls
|
||||
# pin data, ie no saving
|
||||
remainder = Vm::Integer.new( number.register + 2)
|
||||
# BL udiv10 # r1 = r1 / 10
|
||||
div10( tos , number , remainder )
|
||||
# ADD r10, r10, 48 #'0' # make char out of digit (by using ascii encoding)
|
||||
tos.add_code( add( left: remainder , right: remainder , extra: 48 ))
|
||||
#STRB r10, [r1], 1 # store digit at end of buffer
|
||||
tos.add_code( strb( left: string , right: remainder )) #and increment TODO check
|
||||
# CMP r1, #0 # quotient non-zero?
|
||||
tos.add_code( cmp left: number , right: 0 )
|
||||
#BLNE utoa # conditional recursive call to utoa
|
||||
tos.add_code( callne( left: tos ))
|
||||
#LDMFD sp!, {r9, r10, pc} # function exit - restore and return
|
||||
tos.add_code( pop regs: [:pc])
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
|
||||
# the number (a Vm::integer) is (itself) divided by 10, ie overwritten by the result
|
||||
# and the remainder is overwritten (ie an out argument)
|
||||
# not really a function, more a macro, hence private
|
||||
def div10 block, number , remainder
|
||||
|
||||
# takes argument in r1
|
||||
# returns quotient in r1, remainder in r2
|
||||
# SUB r2, r1, #10 # keep (x-10) for later
|
||||
block.add_code sub(:left => remainder , :right => number , :extra => 10 )
|
||||
# SUB r1, r1, r1, lsr #2
|
||||
# ADD r1, r1, r1, lsr #4
|
||||
# ADD r1, r1, r1, lsr #8
|
||||
# ADD r1, r1, r1, lsr #16
|
||||
# MOV r1, r1, lsr #3
|
||||
# ADD r3, r1, r1, asl #2
|
||||
# SUBS r2, r2, r3, asl #1 # calc (x-10) - (x/10)*10
|
||||
# ADDPL r1, r1, #1 # fix-up quotient
|
||||
# ADDMI r2, r2, #10 # fix-up remainder
|
||||
# MOV pc, lr
|
||||
end
|
||||
|
||||
def syscall block , num
|
||||
block.add_code mov( :left => :r7 , :right => num )
|
||||
block.add_code swi( :left => 0 )
|
||||
|
@ -50,14 +50,15 @@ module Arm
|
||||
raise "reference offset too large/small (max 4095) #{arg} #{inspect}"
|
||||
end
|
||||
end
|
||||
elsif (arg.is_a?(Vm::StringConstant)) #use pc relative
|
||||
elsif (arg.is_a?(Vm::StringConstant) ) #use pc relative
|
||||
@rn = :pc
|
||||
@operand = arg.position - self.position - 8 #stringtable is after code
|
||||
@add_offset = 1
|
||||
if (@operand.abs > 4095)
|
||||
raise "reference offset too large/small (max 4095) #{arg} #{inspect}"
|
||||
end
|
||||
elsif (arg.is_a?(Arm::Label) or arg.is_a?(Vm::IntegerConstant))
|
||||
elsif( arg.is_a?(Vm::IntegerConstant) )
|
||||
raise "is this working ?? #{arg} #{inspect}"
|
||||
@pre_post_index = 1
|
||||
@rn = pc
|
||||
@use_addrtable_reloc = true
|
||||
|
@ -23,7 +23,7 @@ module Core
|
||||
|
||||
#TODO this is in the wrong place. It is a function that returns a function object
|
||||
# while all other methods add their code into some block. --> kernel
|
||||
def putstring
|
||||
def putstring context
|
||||
function = Vm::Function.new(:putstring , [Vm::Integer , Vm::Integer ] )
|
||||
block = function.body
|
||||
# should be another level of indirection, ie write(io,str)
|
||||
@ -31,6 +31,17 @@ module Core
|
||||
function.return_type = ret
|
||||
function
|
||||
end
|
||||
|
||||
def putint context
|
||||
function = Vm::Function.new(:putint , [Vm::Integer , Vm::Integer ] )
|
||||
block = function.body
|
||||
buffer = Vm::StringConstant.new(" ")
|
||||
context.program.add_object buffer
|
||||
# should be another level of indirection, ie write(io,str)
|
||||
ret = Vm::CMachine.instance.integer_to_s(block , buffer)
|
||||
function.return_type = ret
|
||||
function
|
||||
end
|
||||
end
|
||||
|
||||
extend ClassMethods
|
||||
|
@ -3,7 +3,7 @@ require 'parslet'
|
||||
require "elf/object_writer"
|
||||
require 'parser/crystal'
|
||||
require 'parser/transform'
|
||||
require "vm/context"
|
||||
require "vm/c_machine"
|
||||
require "vm/program"
|
||||
require "stream_reader"
|
||||
require "core/kernel"
|
||||
|
@ -35,6 +35,7 @@ module Vm
|
||||
|
||||
def add_code(kode)
|
||||
raise "alarm #{kode}" if kode.is_a? Word
|
||||
raise "alarm #{kode}" unless kode.is_a? Code
|
||||
@codes << kode
|
||||
self
|
||||
end
|
||||
|
@ -66,6 +66,7 @@ module Vm
|
||||
# code, and has opcode set to :b and :condition_code set to the condition
|
||||
CONDITIONS.each do |suffix|
|
||||
define_instruction_for("b#{suffix}".to_sym , CallInstruction)
|
||||
define_instruction_for("call#{suffix}".to_sym , CallInstruction)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -1,6 +1,4 @@
|
||||
require "core/kernel"
|
||||
require_relative "program"
|
||||
|
||||
require "support/hash_attributes"
|
||||
module Vm
|
||||
|
||||
#currently just holding the program in here so we can have global access
|
||||
|
@ -9,7 +9,7 @@ module Vm
|
||||
# Functions have a exactly three blocks, entry, exit and body, which are created for you
|
||||
# with straight branches between them.
|
||||
|
||||
# Also remember that if your den body exists of severa blocks, they must be wrapped in a
|
||||
# Also remember that if your den body exists of several blocks, they must be wrapped in a
|
||||
# block as the function really only has the one, and blocks only assemble their codes,
|
||||
# not their next links
|
||||
# This comes at zero runtime cost though, as the wrapper is just the sum of it's codes
|
||||
|
@ -50,6 +50,10 @@ module Vm
|
||||
@attributes[:condition_code] = opcode[1,2].to_sym
|
||||
@attributes[:opcode] = :b
|
||||
end
|
||||
if opcode.length == 6 and opcode[0] == "c"
|
||||
@attributes[:condition_code] = opcode[4,2].to_sym
|
||||
@attributes[:opcode] = :call
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,6 +1,8 @@
|
||||
require_relative "context"
|
||||
require_relative "function"
|
||||
require_relative "call_site"
|
||||
require "arm/arm_machine"
|
||||
require "core/kernel"
|
||||
|
||||
module Vm
|
||||
# A Program represents an executable that we want to build
|
||||
@ -58,7 +60,7 @@ module Vm
|
||||
def get_or_create_function name
|
||||
fun = get_function name
|
||||
unless fun
|
||||
fun = Core::Kernel.send(name)
|
||||
fun = Core::Kernel.send(name , context)
|
||||
raise "no such function '#{name}'" if fun == nil
|
||||
@functions << fun
|
||||
end
|
||||
|
@ -5,7 +5,8 @@ def fibonaccit(n) # n == r0
|
||||
tmp = a # r3 <- r1
|
||||
a = b # r1 <- r2
|
||||
b = tmp + b # r4 = r2 + r3 (r4 transient) r2 <- r4
|
||||
putstring(b)
|
||||
tmp = inttos(b)
|
||||
putstring(tmp)
|
||||
n = n - 1 # r2 <- 0 ???? #call ok
|
||||
end #r5 <- r0 - 1 # r0 <- r5
|
||||
end
|
||||
|
1
test/runners/putint.rb
Normal file
1
test/runners/putint.rb
Normal file
@ -0,0 +1 @@
|
||||
putint( 42 )
|
Loading…
Reference in New Issue
Block a user