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 )
|
syscall( block , 4 )
|
||||||
end
|
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
|
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
|
def syscall block , num
|
||||||
block.add_code mov( :left => :r7 , :right => num )
|
block.add_code mov( :left => :r7 , :right => num )
|
||||||
block.add_code swi( :left => 0 )
|
block.add_code swi( :left => 0 )
|
||||||
|
@ -57,7 +57,8 @@ module Arm
|
|||||||
if (@operand.abs > 4095)
|
if (@operand.abs > 4095)
|
||||||
raise "reference offset too large/small (max 4095) #{arg} #{inspect}"
|
raise "reference offset too large/small (max 4095) #{arg} #{inspect}"
|
||||||
end
|
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
|
@pre_post_index = 1
|
||||||
@rn = pc
|
@rn = pc
|
||||||
@use_addrtable_reloc = true
|
@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
|
#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
|
# 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 ] )
|
function = Vm::Function.new(:putstring , [Vm::Integer , Vm::Integer ] )
|
||||||
block = function.body
|
block = function.body
|
||||||
# should be another level of indirection, ie write(io,str)
|
# should be another level of indirection, ie write(io,str)
|
||||||
@ -31,6 +31,17 @@ module Core
|
|||||||
function.return_type = ret
|
function.return_type = ret
|
||||||
function
|
function
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
extend ClassMethods
|
extend ClassMethods
|
||||||
|
@ -3,7 +3,7 @@ require 'parslet'
|
|||||||
require "elf/object_writer"
|
require "elf/object_writer"
|
||||||
require 'parser/crystal'
|
require 'parser/crystal'
|
||||||
require 'parser/transform'
|
require 'parser/transform'
|
||||||
require "vm/context"
|
|
||||||
require "vm/c_machine"
|
require "vm/c_machine"
|
||||||
require "vm/program"
|
require "vm/program"
|
||||||
require "stream_reader"
|
require "stream_reader"
|
||||||
|
require "core/kernel"
|
||||||
|
@ -35,6 +35,7 @@ module Vm
|
|||||||
|
|
||||||
def add_code(kode)
|
def add_code(kode)
|
||||||
raise "alarm #{kode}" if kode.is_a? Word
|
raise "alarm #{kode}" if kode.is_a? Word
|
||||||
|
raise "alarm #{kode}" unless kode.is_a? Code
|
||||||
@codes << kode
|
@codes << kode
|
||||||
self
|
self
|
||||||
end
|
end
|
||||||
|
@ -66,6 +66,7 @@ module Vm
|
|||||||
# code, and has opcode set to :b and :condition_code set to the condition
|
# code, and has opcode set to :b and :condition_code set to the condition
|
||||||
CONDITIONS.each do |suffix|
|
CONDITIONS.each do |suffix|
|
||||||
define_instruction_for("b#{suffix}".to_sym , CallInstruction)
|
define_instruction_for("b#{suffix}".to_sym , CallInstruction)
|
||||||
|
define_instruction_for("call#{suffix}".to_sym , CallInstruction)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
require "core/kernel"
|
require "support/hash_attributes"
|
||||||
require_relative "program"
|
|
||||||
|
|
||||||
module Vm
|
module Vm
|
||||||
|
|
||||||
#currently just holding the program in here so we can have global access
|
#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
|
# Functions have a exactly three blocks, entry, exit and body, which are created for you
|
||||||
# with straight branches between them.
|
# 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,
|
# block as the function really only has the one, and blocks only assemble their codes,
|
||||||
# not their next links
|
# not their next links
|
||||||
# This comes at zero runtime cost though, as the wrapper is just the sum of it's codes
|
# 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[:condition_code] = opcode[1,2].to_sym
|
||||||
@attributes[:opcode] = :b
|
@attributes[:opcode] = :b
|
||||||
end
|
end
|
||||||
|
if opcode.length == 6 and opcode[0] == "c"
|
||||||
|
@attributes[:condition_code] = opcode[4,2].to_sym
|
||||||
|
@attributes[:opcode] = :call
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
|
require_relative "context"
|
||||||
require_relative "function"
|
require_relative "function"
|
||||||
require_relative "call_site"
|
require_relative "call_site"
|
||||||
require "arm/arm_machine"
|
require "arm/arm_machine"
|
||||||
|
require "core/kernel"
|
||||||
|
|
||||||
module Vm
|
module Vm
|
||||||
# A Program represents an executable that we want to build
|
# A Program represents an executable that we want to build
|
||||||
@ -58,7 +60,7 @@ module Vm
|
|||||||
def get_or_create_function name
|
def get_or_create_function name
|
||||||
fun = get_function name
|
fun = get_function name
|
||||||
unless fun
|
unless fun
|
||||||
fun = Core::Kernel.send(name)
|
fun = Core::Kernel.send(name , context)
|
||||||
raise "no such function '#{name}'" if fun == nil
|
raise "no such function '#{name}'" if fun == nil
|
||||||
@functions << fun
|
@functions << fun
|
||||||
end
|
end
|
||||||
|
@ -5,7 +5,8 @@ def fibonaccit(n) # n == r0
|
|||||||
tmp = a # r3 <- r1
|
tmp = a # r3 <- r1
|
||||||
a = b # r1 <- r2
|
a = b # r1 <- r2
|
||||||
b = tmp + b # r4 = r2 + r3 (r4 transient) r2 <- r4
|
b = tmp + b # r4 = r2 + r3 (r4 transient) r2 <- r4
|
||||||
putstring(b)
|
tmp = inttos(b)
|
||||||
|
putstring(tmp)
|
||||||
n = n - 1 # r2 <- 0 ???? #call ok
|
n = n - 1 # r2 <- 0 ???? #call ok
|
||||||
end #r5 <- r0 - 1 # r0 <- r5
|
end #r5 <- r0 - 1 # r0 <- r5
|
||||||
end
|
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