diff --git a/lib/register/boot.rb b/lib/register/boot.rb index d2977b64..1e67b5e6 100644 --- a/lib/register/boot.rb +++ b/lib/register/boot.rb @@ -152,7 +152,7 @@ module Register @space.get_class_by_name(:Word).add_instance_method Builtin::Word.send(:putstring , nil) obj = @space.get_class_by_name(:Integer) - [:mod , :putint , :div10 , :mod10].each do |f| + [ :putint, :mod4].each do |f| obj.add_instance_method Builtin::Integer.send(f , nil) end end diff --git a/lib/register/builtin/integer.rb b/lib/register/builtin/integer.rb index ba7cb684..dc8c8458 100644 --- a/lib/register/builtin/integer.rb +++ b/lib/register/builtin/integer.rb @@ -5,49 +5,8 @@ module Register module ClassMethods include AST::Sexp - def div10 context - compiler = Soml::Compiler.new.create_method(:Integer,:div10 ).init_method - do_div10(compiler) - # return div - return compiler.method - end - def mod10 context - compiler = Soml::Compiler.new.create_method(:Integer,:mod10 ).init_method - do_div10(compiler) - #return mod - return compiler.method - end - - def do_div10 compiler - - end - # The conversion to base10 is quite a bit more complicated than i thought. - # The bulk of it is in div10 - # We set up variables, do the devision and write the result to the string - # then check if were done and recurse if neccessary - # As we write before we recurse (save a push) we write the number backwards - # arguments: string address , integer - # def utoa context - # compiler = Soml::Compiler.new.create_method(:Integer ,:utoa , [ :Integer ] ).init_method - # function.source.receiver = :Integer - # return utoa_function - # # str_addr = utoa_function.receiver - # # number = utoa_function.args.first - # # remainder = utoa_function.new_local - # # RegisterMachine.instance.div10( utoa_function , number , remainder ) - # # # make char out of digit (by using ascii encoding) 48 == "0" - # # utoa_function.instance_eval do - # # add( remainder , remainder , 48) - # # strb( remainder, str_addr ) - # # sub( str_addr, str_addr , 1 ) - # # cmp( number , 0 ) - # # callne( utoa_function ) - # # end - # # return utoa_function - # end - - def mod context - compiler = Soml::Compiler.new.create_method(:Integer,:mod , {:Integer => :by} ).init_method + def mod4 context + compiler = Soml::Compiler.new.create_method(:Integer,:mod4 ).init_method return compiler.method end def putint context diff --git a/lib/soml/parfait/integer.soml b/lib/soml/parfait/integer.soml index d2f0e9df..e25576d2 100644 --- a/lib/soml/parfait/integer.soml +++ b/lib/soml/parfait/integer.soml @@ -8,6 +8,88 @@ class Integer < Value end end + int high_times( int by_high , int by_low) + + int num_high = self >> 16 + int num_low = self & 65535 + + int res_high = by_high * num_high + + num_low = by_high * num_low + num_high = num_high * by_low + + num_high = num_low + num_high + + num_high = num_high >> 16 + + res_high = res_high + num_high + + return res_high + + end + + int low_times( int by_high , int by_low) + + int num_high = self >> 16 + int num_low = self & 65535 + + int res_low = by_low * num_low + + num_low = by_high * num_low + num_high = num_high * by_low + + num_low = num_low + num_high + + num_low = num_low << 16 + + res_low = res_low + num_low + + return res_low + + end + + int div10() + int minus_10 = self - 10 + int me = self + + int tmp = me >> 2 + me = me - tmp + + tmp = me >> 4 + me = me + tmp + + tmp = me >> 8 + me = me + tmp + + tmp = me >> 16 + me = me + tmp + me = me >> 3 + + int tmp2 = me << 2 + tmp2 = me + tmp2 + + tmp2 = tmp2 << 1 + minus_10 = tmp2 - minus_10 + + if_minus(minus_10) + me = me + 1 + end + return me + end + + int div10_almost() + int me = self + if_zero( me >> 26 ) + me = me + 1 + end + int res_high = me.high_times( 26214 , 26215 ) + int res_low = self >> 31 + res_high = res_high >> 2 + + return res_high + res_low + + end + Word as_string(Word str) if_minus( self - 10 ) int num = as_char() diff --git a/lib/soml/parfait/word.soml b/lib/soml/parfait/word.soml index 04c79aca..57872511 100644 --- a/lib/soml/parfait/word.soml +++ b/lib/soml/parfait/word.soml @@ -5,7 +5,7 @@ class Word < Object word_index = word_index >> 2 word_index = word_index + 3 int rest = index - 1 - rest = rest.mod(4) + rest = rest.mod4() int char = get_internal(word_index) int shifted = 8 * rest shifted = char >> shifted @@ -27,7 +27,7 @@ class Word < Object word_index = word_index + 3 int rest = index - 1 - rest = rest.mod(4) + rest = rest.mod4() int shifted = rest * 8 shifted = char << shifted diff --git a/test/parfait/test_integer.rb b/test/parfait/test_integer.rb index 0bc44159..ba1614f0 100644 --- a/test/parfait/test_integer.rb +++ b/test/parfait/test_integer.rb @@ -9,20 +9,47 @@ class TestPutiRT < MiniTest::Test check_return m % 4 end end - def test_mod10 - [2,3,4,5,10,12,55].each do |m| - @string_input = "return #{m}.mod10()" - check_return m % 10 + + # if you multiply i by "by" the return is the high 32 bits + def high_times( i , by_high , by_low) + by = by_high * 65536 + by_low + by *= i + by /= 65536 + by /= 65536 + return by + end + + # if you multiply i by "by" the return is the low 32 bits + def low_times( i , by_high , by_low) + by = by_high * 65536 + by_low + by *= i + return (by & 0xffffffff) + end + + def test_hightimes + [2,3,4,5,10,121212 , 12345 , 3456 , 234567].each do |m| + @string_input = "return #{m}.high_times(12 , 333)" + check_return high_times(m,12,333) + end + end + def test_lowtimes + [2,3,4,5,10 , 3456 , 12345 , 121212 , 234567].each do |m| + @string_input = "return #{m}.low_times(14 , 33)" + check_return low_times(m,14,33) end end + # finally settled on the long version in http://www.sciencezero.org/index.php?title=ARM:_Division_by_10 + # also the last looked good, but some bug is admittedly in all the ones i tried + # (off course the bug is not included in the test, but easy to achieve with random numbers ) + # for high numbers with ending 0 they are all 1 low. Possibly Interpreter bug ? def test_div10 - [2,5,10,12 , 55 ].each do |m| + [2,3,4,5,10 , 3456 , 12345 , 121212 , 234567].each do |m| @string_input = "return #{m}.div10()" check_return m / 10 end end - + def test_as_char1 @string_input = "return 5.as_char()" check_return 53