3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

自作CPUAdvent Calendar 2024

Day 3

ilasmでstack machine その59

Posted at

概要

ilasmでstack machineやってみた。
練習問題やってみた。
実装編

練習問題

elixirでilasmをアセンブルしてROM化せよ。

サンプルコード



defmodule Va do
	use Agent
	def start_link() do
		Agent.start_link(fn ->
			0
		end, name: __MODULE__)
	end
	def get() do
		Agent.get(__MODULE__, fn v ->
			v
		end)
	end
	def set(x) do
		Agent.update(__MODULE__, fn v ->
			x
		end)
	end
end

defmodule Src do
	use Agent
	def start_link() do
		Agent.start_link(fn -> 
            ""
		end, name: __MODULE__)
	end
	def set(x) do
		Agent.update(__MODULE__, fn v ->
	        x
		end)
	end
	def get() do
		Agent.get(__MODULE__, fn v ->
			v
		end)
	end
	def getv(m) do
		Agent.get(__MODULE__, fn v ->
	        Va.set(0)
            Enum.reduce(String.split(v, "\n", trim: true), 1, fn l, n ->
	    	    if n < m + 1 do
    	    	    if String.starts_with?(l, "  ldstr") do
	        	        Va.set(Va.get + 6)
	                else
	                    if String.ends_with?(l, ":") do
	                        n = n            
	                    else
    	        	        Va.set(Va.get + 1)
    	    	        end
	    	        end
                end
    	        n = n + 1
	    	end)
	        Va.get
	    end)
    end
	def getn(n) do
		Agent.get(__MODULE__, fn v ->
	    	Enum.at(String.split(v, "\n", trim: true), n - 1)
	    end)
    end
    def getl("end") do
        0
    end
	def getl(a) do
		Agent.get(__MODULE__, fn v ->
            Enum.reduce(String.split(v, "\n", trim: true), 1, fn l, n ->
	    	    if String.starts_with?(l, a) do
	    	        Va.set(n)
	    	    end
	    	    if String.starts_with?(l, "  ldstr") do
	    	        n = n + 6
	            else
	                if String.ends_with?(l, ":") do
	                    n = n            
	                else
        	    	    n = n + 1
    	    	    end
	    	    end
	    	end)
	        Va.get - 1
	    end)
    end
end

defmodule Main do
    def val(nil) do
        0
    end
    def val(s) do
        if String.starts_with?(s, "'") do
            String.at(s, 1)
            |> String.to_charlist
            |> List.first
        else
            String.to_integer(s)
        end
    end
	def ldstr(n, s) do
	    IO.puts "rom[#{n}] <= 12'h2_01;"
        n = n + 1
	    i = String.at(s, 1)
            |> String.to_charlist
            |> List.first
	    j = Integer.floor_div(i, 16)
	    i = rem(i, 16)
	    i = Integer.to_string(i, 16)
	    j = Integer.to_string(j, 16)
	    IO.puts "rom[#{n}] <= 12'h2_#{j}#{i};"
        n = n + 1
        
	    i = String.at(s, 2)
            |> String.to_charlist
            |> List.first
	    j = Integer.floor_div(i, 16)
	    i = rem(i, 16)
	    i = Integer.to_string(i, 16)
	    j = Integer.to_string(j, 16)
	    IO.puts "rom[#{n}] <= 12'h2_#{j}#{i};"
        n = n + 1
        
	    i = String.at(s, 3)
            |> String.to_charlist
            |> List.first
	    j = Integer.floor_div(i, 16)
	    i = rem(i, 16)
	    i = Integer.to_string(i, 16)
	    j = Integer.to_string(j, 16)
	    IO.puts "rom[#{n}] <= 12'h2_#{j}#{i};"
        n = n + 1
        
	    i = String.at(s, 4)
            |> String.to_charlist
            |> List.first
	    j = Integer.floor_div(i, 16)
	    i = rem(i, 16)
	    i = Integer.to_string(i, 16)
	    j = Integer.to_string(j, 16)
	    IO.puts "rom[#{n}] <= 12'h2_#{j}#{i};"
        n = n + 1
	    IO.puts "rom[#{n}] <= 12'h2_00;"
	end	
    def add(n) do
	    IO.puts "rom[#{n}] <= 12'hf_02;"
	end
	def sub(n) do
	    IO.puts "rom[#{n}] <= 12'hf_03;"
	end
	def mul(n) do
	    IO.puts "rom[#{n}] <= 12'hf_04;"
	end
	def div(n) do
	    IO.puts "rom[#{n}] <= 12'hf_05;"
	end
	def rem(n) do
	    IO.puts "rom[#{n}] <= 12'hf_06;"
	end
	def ret(n) do
	    IO.puts "rom[#{n}] <= 12'h0_01;"
	end
	def out(n) do
	    IO.puts "rom[#{n}] <= 12'h4_00;"
	end
	def outs(n) do
	    IO.puts "rom[#{n}] <= 12'h5_00;"
	end
	def dup(n) do
	    IO.puts "rom[#{n}] <= 12'hf_00;"
	end
	def drop(n) do
	    IO.puts "rom[#{n}] <= 12'hf_01;"
	end
	def push(n, s) do
	    i = val(s)
	    j = Integer.floor_div(i, 16)
	    i = rem(i, 16)
	    i = Integer.to_string(i, 16)
	    j = Integer.to_string(j, 16)
	    IO.puts "rom[#{n}] <= 12'h1_#{j}#{i};"
	end	
	def bgt(n, s) do
	    i = Src.getl(s)
	    j = Integer.floor_div(i, 16)
	    i = rem(i, 16)
	    i = Integer.to_string(i, 16)
	    j = Integer.to_string(j, 16)
	    IO.puts "rom[#{n}] <= 12'h7_#{j}#{i};"
	end
	def if_(n, s) do
	    i = Src.getl(s)
	    j = Integer.floor_div(i, 16)
	    i = rem(i, 16)
	    i = Integer.to_string(i, 16)
	    j = Integer.to_string(j, 16)
	    IO.puts "rom[#{n}] <= 12'ha_#{j}#{i};"
	end
	def jmp(n, s) do
	    i = Src.getl(s)
	    j = Integer.floor_div(i, 16)
	    i = rem(i, 16)
	    i = Integer.to_string(i, 16)
	    j = Integer.to_string(j, 16)
	    IO.puts "rom[#{n}] <= 12'h9_#{j}#{i};"
	end
	def set(n, s) do
	    cond do
	    s == "a" ->
	        IO.puts "rom[#{n}] <= 12'hf_09;"
	    s == "b" ->
	        IO.puts "rom[#{n}] <= 12'hf_0b;"
	    end
	end
	def get(n, s) do
	    cond do
	    s == "a" ->
	        IO.puts "rom[#{n}] <= 12'hf_0a;"
	    s == "b" ->
	        IO.puts "rom[#{n}] <= 12'hf_0c;"
	    end
	end
    def asm(str) do
        Enum.reduce(String.split(str, "\n"), 0, fn st, n ->
            IO.puts "//#{st}"
            s = String.split(st, "  ")
            m = Src.getv(n)
            cond do
	        Enum.at(s, 1) == "ldstr" ->
		        ldstr(m, Enum.at(s, 2))
	        Enum.at(s, 1) == "ldc.i4" ->
		        push(m, Enum.at(s, 2))
	        Enum.at(s, 1) == "add" ->
		        add(m)        
    	    Enum.at(s, 1) == "sub" ->
	    	    sub(m)
	        Enum.at(s, 1) == "mul" ->
		        mul(m)
    	    Enum.at(s, 1) == "div" ->
	    	    div(m)
    	    Enum.at(s, 1) == "rem" ->
	    	    rem(m)
    	    Enum.at(s, 1) == "ret" ->
	    	    ret(m)
    	    Enum.at(s, 1) == "call" && Enum.at(s, 2) == "void [mscorlib] System.Console::WriteLine(int32)" ->
	    	    out(m)
    	    Enum.at(s, 1) == "call" && Enum.at(s, 2) == "void [mscorlib] System.Console::WriteLine(string)" ->
	    	    outs(m)
	        Enum.at(s, 1) == "dup" ->
		        dup(m)
    	    Enum.at(s, 1) == "pop" ->
	    	    drop(m)
	        Enum.at(s, 1) == "bgt" ->
		        bgt(m, Enum.at(s, 2))
	        Enum.at(s, 1) == "br" ->
		        jmp(m, Enum.at(s, 2))
	        Enum.at(s, 1) == "brfalse" ->
		        if_(m, Enum.at(s, 2))
	        Enum.at(s, 1) == "stloc" ->
		        set(m, Enum.at(s, 2))
		    Enum.at(s, 1) == "ldloc" ->
	    	    get(m, Enum.at(s, 2))
    	    true ->
                IO.puts(Enum.at(s, 1))
            end
            n = n + 1
        end)
    end
    def start(str) do
        Src.set(str)
        asm(str)
    end
end

Va.start_link
Src.start_link

str = """
  ldc.i4  100
  stloc  b
  ldc.i4  1
  stloc  a
loop:
  ldloc  a
  ldloc  b
  bgt  bye
  ldloc  a
  ldc.i4  15
  rem
  brfalse  fb
  ldloc  a
  ldc.i4  5
  rem
  brfalse  bb
  ldloc  a
  ldc.i4  3
  rem
  brfalse  ff
  ldloc  a
  call  void [mscorlib] System.Console::WriteLine(int32)
  br  tugi
fb:
  ldstr  'fibu'
  br  print
bb:
  ldstr  'buzz'
  br  print
ff:
  ldstr  'fizz'
print:
  call  void [mscorlib] System.Console::WriteLine(string)
tugi:
  ldloc  a
  ldc.i4  1
  add
  stloc  a
  br  loop
bye:
  ret
"""

Main.start(str)




実行結果

//  ldc.i4  100
rom[0] <= 12'h1_64;
//  stloc  b
rom[1] <= 12'hf_0b;
//  ldc.i4  1
rom[2] <= 12'h1_01;
//  stloc  a
rom[3] <= 12'hf_09;
//loop:

//  ldloc  a
rom[4] <= 12'hf_0a;
//  ldloc  b
rom[5] <= 12'hf_0c;
//  bgt  bye
rom[6] <= 12'h7_30;
//  ldloc  a
rom[7] <= 12'hf_0a;
//  ldc.i4  15
rom[8] <= 12'h1_0F;
//  rem
rom[9] <= 12'hf_06;
//  brfalse  fb
rom[10] <= 12'ha_16;
//  ldloc  a
rom[11] <= 12'hf_0a;
//  ldc.i4  5
rom[12] <= 12'h1_05;
//  rem
rom[13] <= 12'hf_06;
//  brfalse  bb
rom[14] <= 12'ha_1D;
//  ldloc  a
rom[15] <= 12'hf_0a;
//  ldc.i4  3
rom[16] <= 12'h1_03;
//  rem
rom[17] <= 12'hf_06;
//  brfalse  ff
rom[18] <= 12'ha_24;
//  ldloc  a
rom[19] <= 12'hf_0a;
//  call  void [mscorlib] System.Console::WriteLine(int32)
rom[20] <= 12'h4_00;
//  br  tugi
rom[21] <= 12'h9_2B;
//fb:

//  ldstr  'fibu'
rom[22] <= 12'h2_01;
rom[23] <= 12'h2_66;
rom[24] <= 12'h2_69;
rom[25] <= 12'h2_62;
rom[26] <= 12'h2_75;
rom[27] <= 12'h2_00;
//  br  print
rom[28] <= 12'h9_2A;
//bb:

//  ldstr  'buzz'
rom[29] <= 12'h2_01;
rom[30] <= 12'h2_62;
rom[31] <= 12'h2_75;
rom[32] <= 12'h2_7A;
rom[33] <= 12'h2_7A;
rom[34] <= 12'h2_00;
//  br  print
rom[35] <= 12'h9_2A;
//ff:

//  ldstr  'fizz'
rom[36] <= 12'h2_01;
rom[37] <= 12'h2_66;
rom[38] <= 12'h2_69;
rom[39] <= 12'h2_7A;
rom[40] <= 12'h2_7A;
rom[41] <= 12'h2_00;
//print:

//  call  void [mscorlib] System.Console::WriteLine(string)
rom[42] <= 12'h5_00;
//tugi:

//  ldloc  a
rom[43] <= 12'hf_0a;
//  ldc.i4  1
rom[44] <= 12'h1_01;
//  add
rom[45] <= 12'hf_02;
//  stloc  a
rom[46] <= 12'hf_09;
//  br  loop
rom[47] <= 12'h9_04;
//bye:

//  ret
rom[48] <= 12'h0_01;
//

成果物

以上。

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?