paiza.ioでelixir その206

# 概要
paiza.ioでelixirやってみた。
練習問題やってみた。

# 練習問題
helloworldをアセンブラでコンパイルして、cpuなverilogを生成せよ。

# サンプルコード

```
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 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
	    	    n = n + 1
	        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 add(n) do
	    IO.puts "rom[#{n}] <= 12'hf_00;"
	end
	def sub(n) do
	    IO.puts "rom[#{n}] <= 12'hf_01;"
	end
	def mul(n) do
	    IO.puts "rom[#{n}] <= 12'hf_02;"
	end
	def div(n) do
	    IO.puts "rom[#{n}] <= 12'hf_03;"
	end
	def rem(n) do
	    IO.puts "rom[#{n}] <= 12'hf_03;"
	end
	def eq(n) do
	    IO.puts "rom[#{n}] <= 12'hf_03;"
	end
	def rnd(n) do
	    IO.puts "rom[#{n}] <= 12'hf_07;"
	end
	def dup(n) do
	    IO.puts "rom[#{n}] <= 12'h8_00;"
	end
	def drop(n) do
	    IO.puts "rom[#{n}] <= 12'h9_00;"
	end
	def gt(n) do
	    IO.puts "rom[#{n}] <= 12'hf_06;"
	end
	def out3(n) do
	    IO.puts "rom[#{n}] <= 12'h5_03;"
	end
	def out2(n) do
	    IO.puts "rom[#{n}] <= 12'h5_02;"
	end
	def out1(n) do
	    IO.puts "rom[#{n}] <= 12'h5_01;"
	end
	def out(n) do
	    IO.puts "rom[#{n}] <= 12'h5_00;"
	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'h2_#{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'h6_#{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'h1_#{j}#{i};"
	end
	def set(n, s) do
	    cond do
	    s == "a" ->
	        IO.puts "rom[#{n}] <= 12'h4_00;"
	    s == "b" ->
	        IO.puts "rom[#{n}] <= 12'h4_01;"
	    s == "c" ->
	        IO.puts "rom[#{n}] <= 12'h4_02;"
	    end
	end
	def get(n, s) do
	    cond do
	    s == "a" ->
	        IO.puts "rom[#{n}] <= 12'h3_00;"
	    s == "b" ->
	        IO.puts "rom[#{n}] <= 12'h3_01;"
	    s == "c" ->
	        IO.puts "rom[#{n}] <= 12'h3_02;"
	    end
	end
    def asm(str) do
        Enum.reduce(String.split(str, "\n"), 0, fn st, n ->
            IO.puts "//#{st}"
            s = String.split(st, "  ")
            cond do
	        Enum.at(s, 1) == "+" ->
		        add(n)
    	    Enum.at(s, 1) == "-" ->
	    	    sub(n)
	        Enum.at(s, 1) == "*" ->
		        mul(n)
    	    Enum.at(s, 1) == "/" ->
	    	    div(n)
    	    Enum.at(s, 1) == "%" ->
	    	    rem(n)
    	    Enum.at(s, 1) == "=" ->
	    	    eq(n)
    	    Enum.at(s, 1) == "rnd" ->
	    	    rnd(n)
    	    Enum.at(s, 1) == "out3" ->
	    	    out3(n)
    	    Enum.at(s, 1) == "out2" ->
	    	    out2(n)
    	    Enum.at(s, 1) == "out1" ->
	    	    out1(n)
    	    Enum.at(s, 1) == "out" ->
	    	    out(n)
	        Enum.at(s, 1) == "dup" ->
		        dup(n)
    	    Enum.at(s, 1) == "drop" ->
	    	    drop(n)
	        Enum.at(s, 1) == ">" ->
		        gt(n)
	        Enum.at(s, 1) == "jmp" ->
		        jmp(n, Enum.at(s, 2))
	        Enum.at(s, 1) == "if" ->
		        if_(n, Enum.at(s, 2))
	        Enum.at(s, 1) == "set" ->
		        set(n, Enum.at(s, 2))
    	    Enum.at(s, 1) == "get" ->
	    	    get(n, Enum.at(s, 2))
    	    true ->
                push(n, Enum.at(s, 1))
            end
            n = n + 1
        end)
    end
    def start(str) do
        Src.set(str)
        IO.puts """
module cpu12(input clk, input rst, output [7:0] outport);
	parameter N = 6;
	integer i;
	reg [7:0] q[0:N - 1];
	reg [11:0] rom[64:0];
	reg [7:0] ram[2:0];
	reg jpflg;
	reg [7:0] pc;
	reg [7:0] out;
	reg [7:0] rnd;
	wire [11:0] code;
	wire [3:0] op;
	wire [7:0] opland;
	wire [7:0] qtop;
	wire [7:0] qnext;
	assign code = rom[pc];
	assign op = code[11:8];
	assign opland = code[7:0];
	assign outport = out;
	assign qtop = q[0];
	assign qnext = q[1];
	task push;
	begin
		for (i = 1; i < N; i = i + 1)
			q[i] <= q[i - 1];
	end
	endtask
	task pop;
	begin
		for (i = 1; i < N - 1; i = i + 1)
			q[i] <= q[i + 1];
	end
	endtask
	always @(posedge clk)
	begin
		if (rst)
		begin        
"""
        asm(str)
        IO.puts """
        
			for (i = 0; i < N; i = i + 1)
				q[i] <= 0;
			jpflg <= 0;
			pc <= 0;
			ram[0] <= 0;
			ram[1] <= 0;
			ram[2] <= 0;
			rnd <= 234;
		end
		else
		begin
			case (op)
			4'h0://end
			begin
			end
			4'h1://jmp
			begin
				jpflg = 1;
				pc <= opland;
			end
			4'h2://push
			begin
				push;
				q[0] <= opland;
			end
			4'h3://get
			begin
				push;
				q[0] <= ram[opland];
			end
			4'h4://set
			begin
				ram[opland] <= q[0];
				pop;
			end
			4'h5://out
			begin
				case (opland)
				4'h0://out
				begin
					out <= q[0];
					pop;
				end
				4'h1://out1
				begin
					out <= (q[0] % 10) + 48;
					pop;
				end
				4'h2://out2
				begin
					out <= ((q[0] / 10) % 10) + 48;
					pop;
				end
				4'h3:///out3
				begin
					out <= (q[0] / 100) + 48;
					pop;
				end
				endcase
			end
			4'h6://if
			begin
				if (q[0] == 1)
				begin
					jpflg = 1;
					pc <= opland;
				end
			end
			4'h7://if!
			begin
				if (q[0] == 0)
				begin
					jpflg = 1;
					pc <= opland;
				end
			end
			4'h8://dup
			begin
				push;
			end
			4'h9://drop
			begin
				pop;
			end
			4'hf:
			begin
				case (opland)
				4'h0://+
				begin
					q[0] <= q[1] + q[0];
					pop;
				end
				4'h1://-
				begin
					q[0] <= q[1] - q[0];
					pop;
				end
				4'h2://*
				begin
					q[0] <= q[1] * q[0];
					pop;
				end
				4'h3:///
				begin
					q[0] <= q[1] / q[0];
					pop;
				end
				4'h4://%
				begin
					q[0] <= q[1] % q[0];
					pop;
				end
				4'h5://=
				begin
					if (q[1] == q[0])
						q[0] <= 1;
					else
						q[0] <= 0;
					pop;
				end
				4'h6://>
				begin
					if (q[1] > q[0])
						q[0] <= 1;
					else
						q[0] <= 0;
					pop;
				end
				4'h7://rnd
				begin
					rnd <= rnd * 5 + 1;
					push;
					q[0] <= rnd;
				end
				endcase
			end
			endcase
			if (jpflg == 0)
				pc <= pc + 1;
			else
				jpflg <= 0;
		end
	end
	initial
	begin
		//$display("pc, ram0, out");
		//$monitor("   %d   %d   %d   %d   %d   %s", pc, qtop, jpflg, ram[0], rnd, out);
	end
endmodule

module test;
	reg clk,
		rst;
	wire [7:0] outport;
	cpu12 u(.clk(clk), .rst(rst), .outport(outport));
	initial
	begin
		$monitor("   %s", outport);
		clk = 0;
		rst = 0;
		#2
			rst = 1;
		#2
			rst = 0;
		#200
			$finish;
	end
	always
		#1
			clk = ~clk;
endmodule

"""
    end
end

Va.start_link
Src.start_link

str = """
  'H'
  out
  'e'
  out
  'l'
  out
  'l'
  out
  'o'
  out
  ' '
  out
  'w'
  out
  'o'
  out
  'r'
  out
  'l'
  out
  'd'
  out
lup  jmp  lup
"""
Main.start(str)


```

# 実行結果

```
module cpu12(input clk, input rst, output [7:0] outport);
	parameter N = 6;
	integer i;
	reg [7:0] q[0:N - 1];
	reg [11:0] rom[64:0];
	reg [7:0] ram[2:0];
	reg jpflg;
	reg [7:0] pc;
	reg [7:0] out;
	reg [7:0] rnd;
	wire [11:0] code;
	wire [3:0] op;
	wire [7:0] opland;
	wire [7:0] qtop;
	wire [7:0] qnext;
	assign code = rom[pc];
	assign op = code[11:8];
	assign opland = code[7:0];
	assign outport = out;
	assign qtop = q[0];
	assign qnext = q[1];
	task push;
	begin
		for (i = 1; i < N; i = i + 1)
			q[i] <= q[i - 1];
	end
	endtask
	task pop;
	begin
		for (i = 1; i < N - 1; i = i + 1)
			q[i] <= q[i + 1];
	end
	endtask
	always @(posedge clk)
	begin
		if (rst)
		begin        

//  'H'
rom[0] <= 12'h2_48;
//  out
rom[1] <= 12'h5_00;
//  'e'
rom[2] <= 12'h2_65;
//  out
rom[3] <= 12'h5_00;
//  'l'
rom[4] <= 12'h2_6C;
//  out
rom[5] <= 12'h5_00;
//  'l'
rom[6] <= 12'h2_6C;
//  out
rom[7] <= 12'h5_00;
//  'o'
rom[8] <= 12'h2_6F;
//  out
rom[9] <= 12'h5_00;
//  ' '
rom[10] <= 12'h2_20;
//  out
rom[11] <= 12'h5_00;
//  'w'
rom[12] <= 12'h2_77;
//  out
rom[13] <= 12'h5_00;
//  'o'
rom[14] <= 12'h2_6F;
//  out
rom[15] <= 12'h5_00;
//  'r'
rom[16] <= 12'h2_72;
//  out
rom[17] <= 12'h5_00;
//  'l'
rom[18] <= 12'h2_6C;
//  out
rom[19] <= 12'h5_00;
//  'd'
rom[20] <= 12'h2_64;
//  out
rom[21] <= 12'h5_00;
//lup  jmp  lup
rom[22] <= 12'h1_16;
//
rom[23] <= 12'h2_00;
        
			for (i = 0; i < N; i = i + 1)
				q[i] <= 0;
			jpflg <= 0;
			pc <= 0;
			ram[0] <= 0;
			ram[1] <= 0;
			ram[2] <= 0;
			rnd <= 234;
		end
		else
		begin
			case (op)
			4'h0://end
			begin
			end
			4'h1://jmp
			begin
				jpflg = 1;
				pc <= opland;
			end
			4'h2://push
			begin
				push;
				q[0] <= opland;
			end
			4'h3://get
			begin
				push;
				q[0] <= ram[opland];
			end
			4'h4://set
			begin
				ram[opland] <= q[0];
				pop;
			end
			4'h5://out
			begin
				case (opland)
				4'h0://out
				begin
					out <= q[0];
					pop;
				end
				4'h1://out1
				begin
					out <= (q[0] % 10) + 48;
					pop;
				end
				4'h2://out2
				begin
					out <= ((q[0] / 10) % 10) + 48;
					pop;
				end
				4'h3:///out3
				begin
					out <= (q[0] / 100) + 48;
					pop;
				end
				endcase
			end
			4'h6://if
			begin
				if (q[0] == 1)
				begin
					jpflg = 1;
					pc <= opland;
				end
			end
			4'h7://if!
			begin
				if (q[0] == 0)
				begin
					jpflg = 1;
					pc <= opland;
				end
			end
			4'h8://dup
			begin
				push;
			end
			4'h9://drop
			begin
				pop;
			end
			4'hf:
			begin
				case (opland)
				4'h0://+
				begin
					q[0] <= q[1] + q[0];
					pop;
				end
				4'h1://-
				begin
					q[0] <= q[1] - q[0];
					pop;
				end
				4'h2://*
				begin
					q[0] <= q[1] * q[0];
					pop;
				end
				4'h3:///
				begin
					q[0] <= q[1] / q[0];
					pop;
				end
				4'h4://%
				begin
					q[0] <= q[1] % q[0];
					pop;
				end
				4'h5://=
				begin
					if (q[1] == q[0])
						q[0] <= 1;
					else
						q[0] <= 0;
					pop;
				end
				4'h6://>
				begin
					if (q[1] > q[0])
						q[0] <= 1;
					else
						q[0] <= 0;
					pop;
				end
				4'h7://rnd
				begin
					rnd <= rnd * 5 + 1;
					push;
					q[0] <= rnd;
				end
				endcase
			end
			endcase
			if (jpflg == 0)
				pc <= pc + 1;
			else
				jpflg <= 0;
		end
	end
	initial
	begin
		//$display("pc, ram0, out");
		//$monitor("   %d   %d   %d   %d   %d   %s", pc, qtop, jpflg, ram[0], rnd, out);
	end
endmodule

module test;
	reg clk,
		rst;
	wire [7:0] outport;
	cpu12 u(.clk(clk), .rst(rst), .outport(outport));
	initial
	begin
		$monitor("   %s", outport);
		clk = 0;
		rst = 0;
		#2
			rst = 1;
		#2
			rst = 0;
		#200
			$finish;
	end
	always
		#1
			clk = ~clk;
endmodule

```

# iverilog実行結果

```
>iverilog cpu17.v

>vvp a.out

   H
   e
   l
   o

   w
   o
   r
   l
   d
```

# 成果物

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

以上。