paiza.ioでelixir その73

# 概要
paiza.ioでelixirやってみた。
FPGAの高位合成書いてみた。

# 高位合成て何

FPGAを記述する、HDL言語を生成するコンパイラ
下のコードから下の下のコードを生成する。

```
make 4
in 0 1
out 2 3
xor 0 1 2
or 0 1 3
```

```
module x(input a0, input a1, output a2, output a3);
    assign a2 = a0 ^ a1;
    assign a3 = a0 | a1;
endmodule

module testbench;
    reg a0, a1;
    x u(.a0(a0), .a1(a1), .a2(a2), .a3(a3));
    initial
    begin
        $display("a0 a1 a2 a3");
        $monitor("%b  %b  %b  %b", a0, a1, a2, a3);
        a0 = 0; a1 = 0; #10;
        a0 = 0; a1 = 1; #10;
        a0 = 1; a1 = 0; #10;
        a0 = 1; a1 = 1; #10;
        $finish;
    end
endmodule
```

# シミュレーション結果

```
>iverilog x.v

>vvp a.out
a0 a1 a2 a3
0  0  0  0
0  1  1  1
1  0  1  1
1  1  0  1

```

# サンプルコード

```

defmodule Asm do
	def start_link do
		Agent.start_link(fn ->
			%{in0: "", in1: "", out0: "", u: ""}
		end, name: __MODULE__)
	end
    def make0(a) do
		Agent.update(__MODULE__, fn v ->
            v
		end)
	end
    def in0(a, b) do
		Agent.update(__MODULE__, fn v ->
            str = "input a" <> a <> ", input a" <> b 
            %{v | in0: str}
		end)
    end
    def out0(a, b) do
		Agent.update(__MODULE__, fn v ->
            str = ", output a" <> a <> ", output a" <> b 
            %{v | out0: str}
		end)
    end
    def and0(a, b, c) do
		Agent.update(__MODULE__, fn v ->
            str = "    assign a" <> c <> " = a" <> a <> " & a" <> b <> ";\n"
            %{v | u: v.u <> str}
		end)
    end
    def nand0(a, b, c) do
		Agent.update(__MODULE__, fn v ->
            str = "    assign a" <> c <> " = ~(a" <> a <> " & a" <> b <> ");\n"
            %{v | u: v.u <> str}
		end)
    end
    def nor0(a, b, c) do
		Agent.update(__MODULE__, fn v ->
            str = "    assign a" <> c <> " = ~(a" <> a <> " | a" <> b <> ");\n"
            %{v | u: v.u <> str}
		end)
    end
    def xor0(a, b, c) do
		Agent.update(__MODULE__, fn v ->
            str = "    assign a" <> c <> " = a" <> a <> " ^ a" <> b <> ";\n"
            %{v | u: v.u <> str}
		end)
    end
    def or0(a, b, c) do
		Agent.update(__MODULE__, fn v ->
            str = "    assign a" <> c <> " = a" <> a <> " | a" <> b <> ";\n"
            %{v | u: v.u <> str}
		end)
    end
    def print() do
		Agent.get(__MODULE__, fn v ->
            IO.puts "module x(" <> v.in0 <> v.out0 <> ");\n" <>
		    v.u <>
		    "endmodule\n\n" <>
		    "module testbench;\n" <>
		    "    reg a0, a1;\n" <>
		    "    x u(.a0(a0), .a1(a1), .a2(a2), .a3(a3));\n" <>
		    "    initial\n" <>
            "    begin\n" <>
	        "        $display(\"a0 a1 a2 a3\");\n" <>
	        "        $monitor(\"%b  %b  %b  %b\", a0, a1, a2, a3);\n"<>
		    "        a0 = 0; a1 = 0; #10;\n" <>
			"        a0 = 0; a1 = 1; #10;\n" <>
			"        a0 = 1; a1 = 0; #10;\n" <>
			"        a0 = 1; a1 = 1; #10;\n" <>
		    "        $finish;\n" <>
		    "    end\n" <>
		    "endmodule"
		end)
	end
end

defmodule Main do
	def run(str) do
    	Enum.map(String.split(str, "\n"), fn l ->
		    s = String.split(l, " ")
		    cond do
				Enum.at(s, 0) == "make" ->
					Asm.make0(Enum.at(s, 1))
				Enum.at(s, 0) == "in" ->
					Asm.in0(Enum.at(s, 1), Enum.at(s, 2))
				Enum.at(s, 0) == "out" ->
					Asm.out0(Enum.at(s, 1), Enum.at(s, 2))
				Enum.at(s, 0) == "and" ->
					Asm.and0(Enum.at(s, 1), Enum.at(s, 2), Enum.at(s, 3))
				Enum.at(s, 0) == "nand" ->
					Asm.nand0(Enum.at(s, 1), Enum.at(s, 2), Enum.at(s, 3))
				Enum.at(s, 0) == "nor" ->
					Asm.nor0(Enum.at(s, 1), Enum.at(s, 2), Enum.at(s, 3))
				Enum.at(s, 0) == "xor" ->
					Asm.xor0(Enum.at(s, 1), Enum.at(s, 2), Enum.at(s, 3))
				Enum.at(s, 0) == "or" ->
					Asm.or0(Enum.at(s, 1), Enum.at(s, 2), Enum.at(s, 3))
				true ->
					IO.puts ""
			end
	    end)
	    Asm.print
	end
end

Asm.start_link

Main.run("""
make 4
in 0 1
out 2 3
xor 0 1 2
or 0 1 3
""")





```

# 成果物

https://paiza.io/projects/lfpZBKnQQwwACZJzQFjpNQ?language=elixir

以上。