verilog

2014年2月23日 (日)

Icarus Verilog

以前はVerilog HDLのシミュレーションするのにXILINXから出ていたMXE3(ModelSim Xilinx Edition III)を使っていたんだけど、PCのOSを変えるたびにライセンスをもらうのが面倒なので、自由なソフトIcarus Verilogを入れてみた。

Windows版はここにある>> http://bleyer.org/icarus/

0.9.7のsetup.exeというのを実行して、適当にHDDの空いているところをターゲットに指定して・・・あとは自分でガンバレということ?素人さんお断りってこと?

とりあえずbinをPathに足しゃあなんとかなるかなと・・・なったね。

で、コンパイルとシミュレーションと波形のブラウズのやりかたのメモ:

>iverilog -o [出力file名] -s [root モジュール名] [ソースfile名 [ソースfile名]]
>vvp [入力ファイル名(上の出力ファイル名)]
>gtkwave [なんとか.vcd]

vvpが出力するファイル名はシミュレーション記述のところに

   $dumpfile("なんとか.vcp");

と書いておくわけだな。(そのファイルに何を出すかもだけど。)

もうちょっと親切な説明がこちらにあった>> http://cas.eedept.kobe-u.ac.jp/~arai/Verilog/index.html

数年前のエントリなので、ちょっとだけ違いがある。winwaveというのがどうやら不要になったみたい。gtkwaveだけで波形を見ることができる。

これでまだしばらくシミュレーションができる。次に苦労するのはlinux系に引っ越しする時かな。

2010年10月17日 (日)

verilogでアセンブラ


// http://d.hatena.ne.jp/propella/20080616/p1
// から落としてきたTD4のverilog HDLに
// 軽くマクロでアセンブラを付けた。


module td4(
           input CLOCK,
           input RESET,
           input [3:0] IN,
           output reg [3:0] OUT
           );

   reg [3:0] A, B; // Registers
   reg [3:0] PC; // Program Counter
   reg [7:0] ROM [15:0]; //the Instruction memory
   reg C; // Carry flag

   wire Cnext;
   wire [3:0] OP; // Operation code
   wire [3:0] IM; // Immediate data
   wire [3:0] CHANNEL; // Input channel
   wire [3:0] ALU;
   wire LOAD0, LOAD1, LOAD2, LOAD3;
   wire SELECT_A, SELECT_B;

// 0000 ADD A, Im
// 0001 MOV A, B
// 0010 IN  A
// 0011 MOV A, Im

// 0100 MOV B, A
// 0101 ADD B, Im
// 0110 IN  B
// 0111 MOV B, Im

// 1001 OUT B
// 1011 OUT Im
// 1110 JNC Im (Jump if No Carry)
// 1111 JMP Im

   assign IM = ROM[PC][3:0];
   assign OP = ROM[PC][7:4];
   // Data transfar
   always @(posedge CLOCK) begin
      C   <= RESET ? 0 :  Cnext;
      A   <= RESET ? 0 : ~LOAD0 ? ALU : A;
      B   <= RESET ? 0 : ~LOAD1 ? ALU : B;
      OUT <= RESET ? 0 : ~LOAD2 ? ALU : OUT;
      PC  <= RESET ? 0 : ~LOAD3 ? ALU : PC + 1;
   end

  // Opcode decode
   assign SELECT_A = OP[0] | OP[3];
   assign SELECT_B = OP[0];
   assign LOAD0 =  OP[2] |  OP[3];
   assign LOAD1 = ~OP[2] |  OP[3];
   assign LOAD2 =  OP[2] | ~OP[3];
   assign LOAD3 = ~OP[2] | ~OP[3] | (~OP[0] & C);
  // Data selector
   assign CHANNEL = (~SELECT_B & ~SELECT_A) ? A :
                    (~SELECT_B &  SELECT_A) ? B :
                    ( SELECT_B & ~SELECT_A) ? IN :
                    4'b0000;

   // ALU
   assign {Cnext, ALU} = CHANNEL + IM;

// Assembler macro's
`define MOV_A(ii) ((8'b00110000)+(ii&4'hf))
`define MOV_B(ii) ((8'b01110000)+(ii&4'hf))
`define MOV_A_B    (8'b00010000)
`define MOV_B_A    (8'b01000000)
`define ADD_A(ii) ((8'b00000000)+(ii&4'hf))
`define ADD_B(ii) ((8'b01010000)+(ii&4'hf))
`define IN_A       (8'b00100000)
`define IN_B       (8'b01100000)
`define OUT_(ii)  ((8'b10110000)+(ii&4'hf))
`define OUT_B      (8'b10010000)
`define JMP_(ii)  ((8'b11110000)+(ii&4'hf))
`define JNC_(ii)  ((8'b11100000)+(ii&4'hf))


 // Ramen timer
   initial begin
/*
      ROM[0] =  8'b10110111; // OUT 0111   # LED
      ROM[1] =  8'b00000001; // ADD A,0001
      ROM[2] =  8'b11100001; // JNC 0001   # loop 16 times
      ROM[3] =  8'b00000001; // ADD A,0001
      ROM[4] =  8'b11100011; // JNC 0011   # loop 16 times
      ROM[5] =  8'b10110110; // OUT 0110   # LED
      ROM[6] =  8'b00000001; // ADD A,0001
      ROM[7] =  8'b11100110; // JNC 0110   # loop 16 times
      ROM[8] =  8'b00000001; // ADD A,0001 
      ROM[9] =  8'b11101000; // JNC 1000   # loop 16 times
      ROM[10] = 8'b10110000; // OUT 0000   # LED
      ROM[11] = 8'b10110100; // OUT 0100   # LED
      ROM[12] = 8'b00000001; // AND 0001
      ROM[13] = 8'b11101010; // JNC 1010   # loop 16 times
      ROM[14] = 8'b10111000; // OUT 1000   # LED
      ROM[15] = 8'b11111111; // JMP 1111
*/

      ROM[0] =  `OUT_(4'b0111);  //   # LED
      ROM[1] =  `ADD_A(4'b0001);
      ROM[2] =  `JNC_(4'b0001);  //   # loop 16 times
      ROM[3] =  `ADD_A(4'b0001);
      ROM[4] =  `JNC_(4'b0011);  //   # loop 16 times
      ROM[5] =  `OUT_(4'b0110);  //   # LED
      ROM[6] =  `ADD_A(4'b0001);
      ROM[7] =  `JNC_(4'b0110);  //   # loop 16 times
      ROM[8] =  `ADD_A(4'b0001);
      ROM[9] =  `JNC_(4'b1000);  //   # loop 16 times
      ROM[10] = `OUT_(4'b0000);  //   # LED
      ROM[11] = `OUT_(4'b0100);  //   # LED
      ROM[12] = `ADD_A(4'b0001);
      ROM[13] = `JNC_(4'b1010);  //   # loop 16 times
      ROM[14] = `OUT_(4'b1000);  //   # LED
      ROM[15] = `JMP_(4'b1111);  //   stop

   end

endmodule

////////////////////////////////////////


// testbench
module top_td4;

reg CK, RST;

td4 td4_0(
        .CLOCK(CK) ,
        .RESET(RST) ,
        .IN(),
        .OUT()
);
   
always #500 CK <= !CK;

initial begin

    $dumpfile("td4test.vcd");
    $dumpvars(0, top_td4);
    //$monitor ("%t: a = %b, b = %b, out = %b", $time, a, b, out);

  CK <=0;
  RST <=1'b1;
  #1000;
  
  RST <=1'b0;
  #1000000;

    $finish;

end
   
endmodule


///// 2014-11-05 iverilogでwaveを出せるようにチョロ変してみた。

「CPUの創りかた」のいじりかた

「CPUの創りかた」についてはググっていただくとして、・・・

ていうかもう初版が7年(!)も前の本で、いまさらこれについての話をするのもアレだなあ。
とはいってもこれを超える本は出てきていないので、書いてみる。

いや俺さ、verilogでプロセッサでも組んでみたりしてんだけどさ。
まあプロセッサ作るのが難しいのはともかく、
せめてアセンブラが無いとプログラム作るの大変じゃん。
ていうかシミュレーションでもプログラム走らせたいじゃん。
他の言語でアセンブラ作ってバイナリ作ってからシミュレータに食わせるのも考えたけど、
管理大変じゃん。
なんたって命令セット作りながら行き当たりばったりに設計してるんで、
アセンブラの仕様がころころ変わるし。
命令セット決めてから設計する方がいいってのはわかってるよ。
でもアレじゃん?作ってる途中で「うわーこれ命令セットがダメ」とかなるじゃん。
だからアセンブラもverilogで書いちまおうと。
で、まあ、かなり良いところまで行ったね。
といってもまだラベルの処理ができない程度なんで、
すごく期待してる人はこのへんでガッカリして他のことをした方が良いかも。

で、このverilogアセンブラを説明するために、
「CPUの創りかた」に出ているTD4というプロセッサを使おうというんで、
verilogで書いたTD4を漁ってみると、ここのがコンパクトで良い感じ。
http://d.hatena.ne.jp/propella/20080616/p1

で、それを元に、アセンブラ入りのRTLを作ったのが次のエントリなんでよろしく。

あとそれをシミュレーションした結果をマイフォトに晒したりして。

その他のカテゴリー

2014年11月
            1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30            
無料ブログはココログ