paiza.ioでelixir その295

# 概要
paiza.ioでelixirやってみた。
高位合成、やってみた。
練習問題やってみた。
実装編。

# 練習問題
俺言語で8bitシフトレジスタを実現せよ。

# サンプルコード

```


defmodule Asm do
	def start_link do
		Agent.start_link(fn ->
			%{u: ""}
		end, name: __MODULE__)
	end
    def a(a, b) do
		Agent.update(__MODULE__, fn v ->
		    c = String.to_integer(a) + 10
			str = "            " <> a <> ":\n" <>
			    "            begin\n" <>
			    "                a <= " <> b <> ";\n" <>
			    "                pc <= #{c};\n" <>
			    "            end\n"
			%{v | u: v.u <> str}
		end)
    end
    def o(a, b) do
		Agent.update(__MODULE__, fn v ->
		    c = String.to_integer(a) + 10
			str = "            " <> a <> ":\n" <>
			    "            begin\n" <>
			    "                o <= " <> b <> ";\n" <>
			    "                pc <= #{c};\n" <>
			    "            end\n"
			%{v | u: v.u <> str}
		end)
    end
    def p(a, b) do
		Agent.update(__MODULE__, fn v ->
		    c = String.to_integer(a) + 10
			str = "            " <> a <> ":\n" <>
			    "            begin\n" <>
			    "                p <= " <> b <> ";\n" <>
			    "                pc <= #{c};\n" <>
			    "            end\n"
			%{v | u: v.u <> str}
		end)
    end
    def x(a, b) do
		Agent.update(__MODULE__, fn v ->
		    c = String.to_integer(a) + 10
			str = "            " <> a <> ":\n" <>
			    "            begin\n" <>
			    "                x <= " <> b <> ";\n" <>
			    "                pc <= #{c};\n" <>
			    "            end\n"
			%{v | u: v.u <> str}
		end)
    end
    def b(a, b) do
		Agent.update(__MODULE__, fn v ->
		    c = String.to_integer(a) + 10
			str = "            " <> a <> ":\n" <>
			    "            begin\n" <>
			    "                b <= " <> b <> ";\n" <>
			    "                pc <= #{c};\n" <>
			    "            end\n"
			%{v | u: v.u <> str}
		end)
    end
    def c(a, b) do
		Agent.update(__MODULE__, fn v ->
		    c = String.to_integer(a) + 10
			str = "            " <> a <> ":\n" <>
			    "            begin\n" <>
			    "                c <= " <> b <> ";\n" <>
			    "                pc <= #{c};\n" <>
			    "            end\n"
			%{v | u: v.u <> str}
		end)
    end
    def d(a, b) do
		Agent.update(__MODULE__, fn v ->
		    c = String.to_integer(a) + 10
			str = "            " <> a <> ":\n" <>
			    "            begin\n" <>
			    "                d <= " <> b <> ";\n" <>
			    "                pc <= #{c};\n" <>
			    "            end\n"
			%{v | u: v.u <> str}
		end)
    end
    def e(a, b) do
		Agent.update(__MODULE__, fn v ->
		    c = String.to_integer(a) + 10
			str = "            " <> a <> ":\n" <>
			    "            begin\n" <>
			    "                e <= " <> b <> ";\n" <>
			    "                pc <= #{c};\n" <>
			    "            end\n"
			%{v | u: v.u <> str}
		end)
    end
    def f(a, b) do
		Agent.update(__MODULE__, fn v ->
		    c = String.to_integer(a) + 10
			str = "            " <> a <> ":\n" <>
			    "            begin\n" <>
			    "                f <= " <> b <> ";\n" <>
			    "                pc <= #{c};\n" <>
			    "            end\n"
			%{v | u: v.u <> str}
		end)
    end
    def g(a, b) do
		Agent.update(__MODULE__, fn v ->
		    c = String.to_integer(a) + 10
			str = "            " <> a <> ":\n" <>
			    "            begin\n" <>
			    "                g <= " <> b <> ";\n" <>
			    "                pc <= #{c};\n" <>
			    "            end\n"
			%{v | u: v.u <> str}
		end)
    end
    def h(a, b) do
		Agent.update(__MODULE__, fn v ->
		    c = String.to_integer(a) + 10
			str = "            " <> a <> ":\n" <>
			    "            begin\n" <>
			    "                h <= " <> b <> ";\n" <>
			    "                pc <= #{c};\n" <>
			    "            end\n"
			%{v | u: v.u <> str}
		end)
    end
    def print(a, b) do
		Agent.update(__MODULE__, fn v ->
            c = String.to_integer(a)
			if String.match?(b, ~r/\"/) do
			    b = String.replace(b, "\"", "")
		        s = String.split(b, "", trim: true)
                l = String.length(b)
			    str = Enum.reduce(s, ["", c], fn x, y ->
			        pc = Enum.at(y, 1)
			        str = Enum.at(y, 0) <> 
			            "            #{pc}:\n" <>
			            "            begin\n" <>
                        "                out <= \"#{x}\";\n" <>
                        "                pc <= #{pc + 1};\n" <>
                        "            end\n"
                    pc = pc + 1
                    [str, pc]
			    end)
			    str = Enum.at(str, 0) <>
    			    "            #{c + l}:\n" <>
		            "            begin\n" <>
                    "                out <= \" \";\n" <>
                    "                pc <= #{c + 10};\n" <>
                    "            end\n"
			    %{v | u: v.u <> str}
			else
			    str = "            #{c}:\n" <>
			    "            begin\n" <>
                "                out <= a / 10 + 48;\n" <>
                "                pc <= #{c + 1};\n" <>
                "            end\n" <>
                "            #{c + 1}:\n" <>
                "            begin\n" <>
                "                out <= a % 10 + 48;\n" <>
                "                pc <= #{c + 2};\n" <>
                "            end\n" <>
                "            #{c + 2}:\n" <>
                "            begin\n" <>
                "                out <= 32;\n" <>
                "                pc <= #{c + 10};\n" <>
                "            end\n"
                %{v | u: v.u <> str}
			end
		end)
    end
    def loop(a, b) do
		Agent.update(__MODULE__, fn v ->
		    c = String.to_integer(a) + 10
			if String.match?(b, ~r/\*/) do
			    b = String.replace(b, "@", "==")
		        s = String.split(b, "*")
			    str = "            " <> a <> ":\n" <>
			    "            begin\n" <>
			    "                if (" <> Enum.at(s, 0) <> ")\n" <>
			    "                    pc <= " <> Enum.at(s, 1) <> ";\n" <>
			    "                else\n" <>
                "                    pc <= #{c};\n" <>
			    "            end\n"
			    %{v | u: v.u <> str}
		    else
		        str = "            " <> a <> ":\n" <>
		        "            begin\n" <>
		        "                pc <= " <> b <> ";\n" <>
		        "            end\n"
		        %{v | u: v.u <> str}
		    end
		end)
    end
    def make() do
		Agent.get(__MODULE__, fn v ->
            IO.puts "module ore(input clk, input rst, input o, input p, input q, output x, output y, output z);\n" <>
	        "    reg [7:0] a;\n" <>
	        "    reg [7:0] b;\n" <>
	        "    reg [7:0] c;\n" <>
	        "    reg [7:0] d;\n" <>
	        "    reg [7:0] e;\n" <>
	        "    reg [7:0] f;\n" <>
	        "    reg [7:0] g;\n" <>
	        "    reg [7:0] h;\n" <>
	        "    reg [7:0] pc;\n" <>
	        "    reg x;\n" <>
	        "    reg y;\n" <>
	        "    reg z;\n" <>
	        "    wire o;\n" <>
	        "    wire p;\n" <>
	        "    wire q;\n" <>
	        "    always @(posedge clk)\n" <>
	        "    begin\n" <>
		    "        if (!rst)\n" <>
		    "        begin\n" <>
			"            a <= 0;\n" <>
			"            b <= 0;\n" <>
			"            c <= 0;\n" <>
			"            d <= 0;\n" <>
			"            e <= 0;\n" <>
			"            f <= 0;\n" <>
			"            g <= 0;\n" <>
			"            h <= 0;\n" <>
			"            pc <= 10;\n" <>
		    "        end\n" <>
		    "        else\n" <>
	        "        begin\n" <>
		    "            case(pc)\n" <>
		    v.u <>
		    "            endcase\n" <>
	        "        end\n" <>
	        "    end\n" <>
	        "    initial\n" <>
	        "    begin\n" <>
		    "        //$monitor(\" %d  %d\", pc, x);\n" <>
	        "    end\n" <>
		    "endmodule\n\n" <>
            "module test;\n" <>
	        "    reg clk,\n" <>
		    "        rst;\n" <>
	        "    wire [7:0] out;\n" <>
	        "    reg o;\n" <>
	        "    reg p;\n" <>
	        "    reg q;\n" <>
	        "    wire x;\n" <>
	        "    wire y;\n" <>
	        "    wire z;\n" <>
	        "    ore u(.clk(clk), .rst(rst), .o(o), .p(p), .q(q), .x(x), .y(y), .z(z));\n" <>
	        "    initial\n" <>
	        "    begin\n" <>
		    "        clk = 0;\n" <>
		    "        rst = 1;\n" <>	
		    "    #2\n" <>
			"        rst = 0;\n" <>
		    "    #2\n" <>
		    "        rst = 1;\n" <>
		    "    #40\n" <>
		    "        o = 0;\n" <>
		    "        p = 0;\n" <>
		    "    #40\n" <>
		    "        o = 1;\n" <>
		    "        p = 1;\n" <>
		    "    #40\n" <>
		    "        o = 0;\n" <>
		    "        p = 0;\n" <>
		    "    #40\n" <>
		    "        p = 1;\n" <>
		    "    #40\n" <>
		    "        p = 0;\n" <>
		    "    #40\n" <>
		    "        p = 1;\n" <>
		    "    #40\n" <>
		    "        p = 0;\n" <>
		    "    #40\n" <>
		    "        p = 1;\n" <>
		    "    #40\n" <>
		    "        p = 0;\n" <>
		    "    #40\n" <>
		    "        p = 1;\n" <>
		    "    #40\n" <>
		    "        p = 0;\n" <>
		    "    #40\n" <>
		    "        p = 1;\n" <>
		    "    #40\n" <>
		    "        p = 0;\n" <>
		    "    #40\n" <>
		    "        p = 1;\n" <>
		    "    #40\n" <>
		    "        p = 0;\n" <>
		    "    #40\n" <>
		    "        p = 1;\n" <>
		    "    #40\n" <>
		    "        p = 0;\n" <>
		    "    #40\n" <>
		    "        p = 1;\n" <>
		    "    #40\n" <>
		    "        p = 0;\n" <>
		    "    #40\n" <>
		    "        p = 1;\n" <>
		    "    #40\n" <>
		    "        p = 0;\n" <>
		    "    #40\n" <>
			"        $finish;\n" <>
	        "    end\n" <>
	        "    always\n" <>
		    "    #1\n" <>
			"        clk = ~clk;\n" <>
	        "    initial\n" <>
	        "    begin\n" <>
	        "        $display(\" o  p  x \");\n" <>
		    "        $monitor(\" %d %d  %d \", o, p, x);\n" <>
	        "    end\n" <>
            "endmodule\n"
		end)
	end
end

defmodule Main do
	def run(str) do
	    str = String.replace(str, "=", " ")
    	Enum.map(String.split(str, "\n"), fn l ->
		    s = String.split(l, " ")
		    cond do
			Enum.at(s, 1) == "?" ->
				Asm.print(Enum.at(s, 0), Enum.at(s, 2))
			Enum.at(s, 1) == "#" ->
				Asm.loop(Enum.at(s, 0), Enum.at(s, 2))
			Enum.at(s, 1) == "a" ->
				Asm.a(Enum.at(s, 0), Enum.at(s, 2))
			Enum.at(s, 1) == "o" ->
				Asm.o(Enum.at(s, 0), Enum.at(s, 2))
			Enum.at(s, 1) == "p" ->
				Asm.p(Enum.at(s, 0), Enum.at(s, 2))
			Enum.at(s, 1) == "x" ->
				Asm.x(Enum.at(s, 0), Enum.at(s, 2))
			Enum.at(s, 1) == "b" ->
				Asm.b(Enum.at(s, 0), Enum.at(s, 2))
			Enum.at(s, 1) == "c" ->
				Asm.c(Enum.at(s, 0), Enum.at(s, 2))
			Enum.at(s, 1) == "d" ->
				Asm.d(Enum.at(s, 0), Enum.at(s, 2))
			Enum.at(s, 1) == "e" ->
				Asm.e(Enum.at(s, 0), Enum.at(s, 2))
			Enum.at(s, 1) == "f" ->
				Asm.f(Enum.at(s, 0), Enum.at(s, 2))
			Enum.at(s, 1) == "g" ->
				Asm.g(Enum.at(s, 0), Enum.at(s, 2))
			Enum.at(s, 1) == "h" ->
				Asm.h(Enum.at(s, 0), Enum.at(s, 2))
			true ->
				IO.puts l
			end
	    end)
	    Asm.make
	end
end

Asm.start_link

Main.run("""
10 x=0
20 a=o
30 #=p@1*50
40 #=20
50 x=h
60 h=g
70 g=f
80 f=e
90 e=d
100 d=c
110 c=b
120 b=a
130 #=p@0*20
140 #=130
""")




```

# シュミレーション結果

```
>vvp a.out
 o  p  x
 x x  x
 x x  0
 0 0  0
 1 1  0
 0 0  0
 0 1  0
 0 0  0
 0 1  0
 0 0  0
 0 1  0
 0 0  0
 0 1  0
 0 0  0
 0 1  0
 0 0  0
 0 1  0
 0 0  0
 0 1  0
 0 1  1
 0 0  1
 0 1  1
 0 1  0
 0 0  0
 0 1  0
 0 0  0
ore1.v:181: $finish called at 884 (1s)
```

# 成果物


https://paiza.io/projects/1Wi0mmW5xIuaoxcgCIazwg


以上。