[[MenuBar]]
* 概要 [#zaba5b6a]
- miniCPU をI2Cのmaster device として、I2Cのslave device を miniCPUのプログラムで、自動的に動かします。
- 動作モードを変更することにより、I2Cのslave device を手で動かしたり、miniCPUをI2Cと切り離して単独で動かしたり、miniCPU でI2Cの slave device 自動的に動かしたりできるようにします。
- 動作モードの変更は、5つのボタンの、左右(西と東)を使って変更します。
- miniCPUのクロックは、中央のボタンを押したり離したりして供給します。
- miniCPUでI2Cの slave device を動かしているとき、miniCPUのoutバッファの out[0]で scl を動かし, out[1]で sda を動かします。
* 回路の概要 [#oe8fa2dd]
- miniCPU を構成する部品は、[[MiniCPU]]のものをそのまま使います。
- 「[[I2Cデバイスを手で動かしてみる]]」の回路を拡張して、miniCPUと接続します。
- sw[15:0]と up button, left button, center button, right button をチャタリング防止回路に通し、その出力をswx[15:0], BUx, BLx, BCx, BRx とします。
- sclx が1のときは、sclはZ(high impedance), sclxが0のときは sclは0とします。
- sdax が1のときは、sdaはZ(high impedance), sclxが0のときは sclは0とします。
- 動作モードを表すレジスタ, operationMode を使います。operationMode が 0のときは、I2Cを手動で動かすモード, 1のときは miniCPU を独立して動かすモード, 2のときは miniCPUでI2Cを動かすモードとします。
-- 動作モードをカラーLED 1で表示します。
-- 動作モード 0 のときは、miniCPUのクロック(cpuCLK)や run信号線(cpuRun)や入力信号線(cpuIn)を遮断し、7セグメントLEDの左から5桁目と6桁目で data レジスタを表示し、7桁目と8桁目で、swx[7:0] を表示します。led[15:8]はデータレジスタを表示します。led[7:0]はswx[7:0]を表示します。sclxはBCxと接続し, sdaxはswx[0]と接続します。 color LED 2 は、sda と sclの 1,0を表します。
-- 動作モード 1 のときは、BCxを miniCPUのクロックに接続し、BNxをcpuRUNに接続し, data をcpuINの下位8bit に接続します。7セグメントLEDの左から1桁目で cpu の状態を表します。2桁目から4桁目でcpuの実行中のアドレスを表します。5桁目から8桁目で、実行中の命令を表します。 led のはminiCPUの出力(out)を表します。sclx, sdax はa にします。color LED 2 は、sda と sclの 1,0を表します。
-- 動作モード 2 のときは, BCxを miniCPUのクロックに接続し、BNxをcpuRUNに接続し, data をcpuINの下位8bit に接続します。7セグメントLEDの左から1桁目で cpu の状態を表します。2桁目から4桁目でcpuのアドレスバスの値を表します。5桁目から8桁目で、cpuのデータバスの内容を表します。 ledの上位8bit で, data レジスタの内容を表示し, led の下位8bit でminiCPUの出力(out)の下位8bitを表します。scl にcpuの出力の下位から2bit目, out[1], sda に cpu の出力の下位1bit目, out[0] を接続します。はZ にします。color LED 2 は、sda と sclの 1,0を表します。
- 動作モードの表 &br;
|operationMode |Color LED 1|cpuClk|cpuRun|cpuIn|sSegArray|led|sclx, sdax|Color LED 2|
|0| {0,0,0} | 0 | 0 | 0| {16{0}, data,swx[7:0]}|{data,swx[7:0]}|BCx,swx[0]|{0,sda,scl}|
|1|{0,0,1}|BCx|BNx|swx|{{0},cpuCs,pcout,irout}|out|1,1|{0,sda,scl}|
|2|{0,1,0}|BCx|BNx|{8{0},data}|{{0},cpuCs,abus,dbus}|{data,out[7:0]}|out[1],out[0]|{0,sda,scl}|

- down button をリセット信号とします。
- sda を led[8] に接続します。scl が 0->1 に変化するたびに、これをシフトして、過去8回のsda の High/Low の遷移を led[15:8] に表示します。 これを実現するために、レジスタ data[7:0] を使っています。
- 1つのポートで入出力を行う為、scl, sda は verilog の inout 型を使います。
* verilog [#l41887fa]
- [[miniCPU]] の top.v と ram.v を以下の verilog で置き換えます。
- [[MiniCPU]] の top.v と ram.v を以下の verilog で置き換えます。
- 以下の ram.v は、ADT7420 で計測された温度を取得し, led に表示します。
- top.v
 module top(sSegAnode, sSegCathode, sw, ledOut, colorLed_1, colorLed_2,
  bu, bd, bl, br, bc, scl, sda, 
  bclck
     ); 
   output [7:0] sSegAnode;
   output [7:0] sSegCathode;
   output [15:0] ledOut;              // led[8] ... if sda is sending, corresponding to the last sended sda, 
                                      //            else corresponding to the last received sda
                                      //             it is shifted to left when a positive edge of scl is detected.
                                  	 //  led[0] corresponding to sw[0]
										 		 //  led[1] corresponding to sw[1]
										 		 //  led[2] corresponsing to center button, bc.
   output [2:0] colorLed_1;
   output [2:0] colorLed_2;          // color LED 
   input [15:0] sw;                  // sw[15:8] ... for setting sda send data, sw[7:0] ... for controlling
                                     //    sw[0] ... if 1 scl is not ready, else scl is ready;
 										 		//    sw[1] ... if 1 sda is receiving(1), else sda is sending(0).
 										 		//    sw[2] ... sending sda.
            												  
   input bu, bd, bl, br, bc, bclck;  //  bd corresponding to !reset.
                                     //  bc corresponding to scl.  scl=sw[0]|bc
										 		//  if posedge bl is detected, sw is shown in hex in the 7seg led array.
   
   inout scl, sda;
   reg sclx, sdax;
   
   assign scl=(~sclx)?1'b0:1'bz;
   assign sda=(~sdax)?1'b0:1'bz;
   
   wire BNx, BWx, BEx, BCx;
   // reset: BSx
   // BWx, BEx ... change operationMode
   // 
   wire [15:0] swx;
   wire reset;
 //  reg sclRw, sdaRw; // write=1, read=0;
   reg cpuClk,cpuRun;
   reg [7:0] data;
   reg [1:0] operationMode;
   // operationMode: 0 ... manual operation of peripherals
   //                1 ... CPU independent
   //                2 ... CPU, I2C connected
   reg [15:0] ledWire,cpuIn;
   wire [2:0] cpuCs;
   wire [11:0] pcout,abus;
   wire [15:0] irout,qtop,dbus,out;
   reg [31:0] sSegArray;
   reg [15:0] led;
   assign ledOut=led;
   
   reg [2:0] colorLed_1x, colorLed_2x;
 //  
   assign colorLed_1=colorLed_1x;
 //  assign colorLed_2=colorLed_2x;
   assign reset=~bd;
   
 //  always @(sclx or sdax ) begin
 //    colorLed_2x[0]<=sclx;
 //    colorLed_2x[1]<=sdax;
 //    colorLed_2x[2]<=0;
 //  end
   
   assign colorLed_2={0,sda,scl}; 
 
   always @(posedge sclx, negedge reset) begin
     if(!reset) begin
     	 data<=0;
 	 end
 	 else
     data<={data[6:0],sda};
   end
   
   // for operation mode
   always @(posedge BEx or negedge reset) begin
      if(!reset) begin
 	    operationMode<=0;
 	  end
 	  else
 	  if(BEx) operationMode<=operationMode+1;
   end
   
 //  always @(operationMode or swx[0] or BCx or data or BNx or cpuCs or out or sda or scl or out[0] or out[1]) begin
   always @(operationMode) begin
      case(operationMode)
       0: begin
            colorLed_1x=3'b000;
            cpuClk=0; cpuRun=0; cpuIn=0;
            sSegArray={{16{0}},data,swx[7:0]};
            led[15:8]=data;
            led[7:0]=swx[7:0];
            sclx=BCx;
            sdax=swx[0];
          end
       1: begin // CPU independent, 
            colorLed_1x=3'b001;
            cpuClk=BCx; cpuRun=BNx; cpuIn=swx; 
            sSegArray={{0},cpuCs,pcout,irout};
            led={{0{16}},out};
            sclx=1'b1;
            sdax=1'b1;
          end 
 		2: begin
            colorLed_1x=3'b010;
            cpuClk=BCx; cpuRun=BNx; cpuIn={{8{0}},data}; 
            sSegArray={{0},cpuCs,abus,dbus};
            led[15:8]=data;
            led[7:0]=out[7:0];
            sclx=out[1];
            sdax=out[0];
          end
       default begin
            colorLed_1x=3'b011;
            cpuClk=BCx; cpuRun=BNx; cpuIn=swx; 
            sSegArray={{0{16}},data,swx[7:0]};
            led[15:8]=data;
            led[7:0]=swx[7:0];
            sclx=BCx;
            sdax=swx[0]; 
 	end
     endcase
   end
   
   chattering #(20) chattering0(.clk(bclck), .reset(reset), .in({bu,bl,br,bc,sw}), .out({BNx,  BWx, BEx, BCx,swx}));
 //  assign BNx=bu;
 //  assign BWx=bl;
 //  assign BEx=br;
 //  assign BCx=bc;
 //  assign swx=sw;
 
  sSegArray sSegArray0(.clk(bclck), .reset(reset), .load(1), .d(sSegArray), .anode(sSegAnode), .cathode(sSegCathode));
  
   minicpu minicpu0(.clk(cpuClk), .reset(reset), .run(cpuRun), .in(cpuIn), .cs(cpuCs), .pcout(pcout), .irout(irout), .qtop(qtop), .abus(abus), .dbus(dbus), .out(out));
  
 endmodule
- ram0
 module ram(clk, load, addr, d, q
 );
 parameter DWIDTH=16, AWIDTH=12, WORDS=4096; 
 
 input clk, load;
 input [AWIDTH-1:0] addr;
 input [DWIDTH-1:0] d;
 output [DWIDTH-1:0] q;
 reg [DWIDTH-1:0] q;
 reg [DWIDTH-1:0] mem [WORDS-1:0];
 
 always @(posedge clk)
 begin
 if(load) mem[addr] <= d;
 q <= mem[addr];
 end
 
 integer i;
 initial begin
 for(i=0; i<WORDS; i=i+1)
 mem[i]=12'h000;
 mem[8'h00] = 16'h1000; //      PUSHI 0
 mem[8'h01] = 16'h3011; //      POP  i  ... i=0;
 mem[8'h02] = 16'h2011; // L1   PUSH i
 mem[8'h03] = 16'h1012; //      PUSHI C
 mem[8'h04] = 16'hF000; //      ADD
 mem[8'h05] = 16'h7000; //      LD     ... C[i];
 mem[8'h06] = 16'hE000; //      OUT    ... print(C[i]) ;
 mem[8'h07] = 16'h2011; //      PUSH i;
 mem[8'h08] = 16'h1001; //      PUSH 1     
 mem[8'h09] = 16'hF000; //      ADD
 mem[8'h0A] = 16'h3011; //      POP i
 mem[8'h0B] = 16'h2011; //      PUSH i
 mem[8'h0C] = 16'h2010; //      PUSH n
 mem[8'h0D] = 16'hF001; //      SUB
 mem[8'h0E] = 16'h6002; //      JNZ L1:   if(i<n) goto L1;
 mem[8'h0F] = 16'h0000; // L2:  HALT
 mem[8'h10] = 16'h0076; // n:   0x76 ... 0x88-0x12
 mem[8'h11] = 16'h0000; // i:
 //
 // data for controlling i2c
 //  (MSB) ......    scl, sda (LSB)
 mem[8'h12] = 16'h0003; // C:   11
 mem[8'h13] = 16'h0002; //      10 start
 mem[8'h14] = 16'h0000; //      00
 mem[8'h15] = 16'h0001; //      01 
 mem[8'h16] = 16'h0003; //      11  sda 1
 mem[8'h17] = 16'h0001; //      01
 mem[8'h18] = 16'h0000; //      00
 mem[8'h19] = 16'h0002; //      10  sda 10
 mem[8'h1A] = 16'h0000; //      00
 mem[8'h1B] = 16'h0002; //      10  sda 100
 mem[8'h1C] = 16'h0000; //      00
 mem[8'h1D] = 16'h0001; //      01
 mem[8'h1E] = 16'h0003; //      11  sda 1001
 mem[8'h1F] = 16'h0001; //      01
 mem[8'h20] = 16'h0000; //      00
 mem[8'h21] = 16'h0002; //      10  sda 10010
 mem[8'h22] = 16'h0000; //      00
 mem[8'h23] = 16'h0001; //      01
 mem[8'h24] = 16'h0003; //      11  sda 100101
 mem[8'h25] = 16'h0001; //      01
 mem[8'h26] = 16'h0003; //      11  sda 1001011 .. 0x4B
 mem[8'h27] = 16'h0001; //      01
 mem[8'h28] = 16'h0000; //      00
 mem[8'h29] = 16'h0002; //      10  send 0 ... write
 mem[8'h2A] = 16'h0000; //      00
 mem[8'h2B] = 16'h0001; //      01
 mem[8'h2C] = 16'h0003; //      11  read ack 
 mem[8'h2D] = 16'h0001; //      01
 mem[8'h2E] = 16'h0000; //      00
 mem[8'h2F] = 16'h0002; //      10   write 0
 mem[8'h30] = 16'h0000; //      00
 mem[8'h31] = 16'h0002; //      10   write 00
 mem[8'h32] = 16'h0000; //      00
 mem[8'h33] = 16'h0002; //      10   write 000
 mem[8'h34] = 16'h0000; //      00
 mem[8'h35] = 16'h0002; //      10   write 0000
 mem[8'h36] = 16'h0000; //      00
 mem[8'h37] = 16'h0002; //      10   write 00000
 mem[8'h38] = 16'h0000; //      00
 mem[8'h39] = 16'h0002; //      10   write 000000
 mem[8'h3A] = 16'h0000; //      00
 mem[8'h3B] = 16'h0002; //      10   write 0000000
 mem[8'h3C] = 16'h0000; //      00
 mem[8'h3D] = 16'h0002; //      10   write 00000000  .... write register 0
 mem[8'h3E] = 16'h0000; //      00
 mem[8'h3F] = 16'h0001; //      01
 mem[8'h40] = 16'h0003; //      11  read ack 
 mem[8'h41] = 16'h0001; //      01
 mem[8'h42] = 16'h0003; //      11
 mem[8'h43] = 16'h0002; //      10   ... repeat start
 mem[8'h44] = 16'h0000; //      00
 mem[8'h45] = 16'h0001; //      01 
 mem[8'h46] = 16'h0003; //      11  sda 1
 mem[8'h47] = 16'h0001; //      01
 mem[8'h48] = 16'h0000; //      00
 mem[8'h49] = 16'h0002; //      10  sda 10
 mem[8'h4A] = 16'h0000; //      00
 mem[8'h4B] = 16'h0002; //      10  sda 100
 mem[8'h4C] = 16'h0000; //      00
 mem[8'h4D] = 16'h0001; //      01
 mem[8'h4E] = 16'h0003; //      11  sda 1001
 mem[8'h4F] = 16'h0001; //      01
 mem[8'h50] = 16'h0000; //      00
 mem[8'h51] = 16'h0002; //      10  sda 10010
 mem[8'h52] = 16'h0000; //      00
 mem[8'h53] = 16'h0001; //      01
 mem[8'h54] = 16'h0003; //      11  sda 100101
 mem[8'h55] = 16'h0001; //      01
 mem[8'h56] = 16'h0003; //      11  sda 1001011 .. 0x4B
 mem[8'h57] = 16'h0001; //      01
 mem[8'h58] = 16'h0003; //      11  send 1 ... read
 mem[8'h59] = 16'h0001; //      01  
 mem[8'h5A] = 16'h0003; //      11  read ack 
 mem[8'h5B] = 16'h0001; //      01
 mem[8'h5C] = 16'h0003; //      11  read 1st bit
 mem[8'h5D] = 16'h0001; //      01
 mem[8'h5E] = 16'h0003; //      11  read 2nd bit
 mem[8'h5F] = 16'h0001; //      01
 mem[8'h60] = 16'h0003; //      11  read 3rd bit
 mem[8'h61] = 16'h0001; //      01
 mem[8'h62] = 16'h0003; //      11  read 4th bit
 mem[8'h63] = 16'h0001; //      01
 mem[8'h64] = 16'h0003; //      11  read 5th bit
 mem[8'h65] = 16'h0001; //      01
 mem[8'h66] = 16'h0003; //      11  read 6th bit
 mem[8'h67] = 16'h0001; //      01
 mem[8'h68] = 16'h0003; //      11  read 7th bit
 mem[8'h69] = 16'h0001; //      01
 mem[8'h6A] = 16'h0003; //      11  read 8th bit
 mem[8'h6B] = 16'h0001; //      01
 mem[8'h6C] = 16'h0000; //      00
 mem[8'h6D] = 16'h0002; //      10  write ack 
 mem[8'h6E] = 16'h0000; //      00
 mem[8'h6F] = 16'h0001; //      01  
 mem[8'h70] = 16'h0003; //      11  read ack 
 mem[8'h71] = 16'h0001; //      01
 mem[8'h72] = 16'h0003; //      11  read 1st bit
 mem[8'h73] = 16'h0001; //      01
 mem[8'h74] = 16'h0003; //      11  read 2nd bit
 mem[8'h75] = 16'h0001; //      01
 mem[8'h76] = 16'h0003; //      11  read 3rd bit
 mem[8'h77] = 16'h0001; //      01
 mem[8'h78] = 16'h0003; //      11  read 4th bit
 mem[8'h79] = 16'h0001; //      01
 mem[8'h7A] = 16'h0003; //      11  read 5th bit
 mem[8'h7B] = 16'h0001; //      01
 mem[8'h7C] = 16'h0003; //      11  read 6th bit
 mem[8'h7D] = 16'h0001; //      01
 mem[8'h7E] = 16'h0003; //      11  read 7th bit
 mem[8'h7F] = 16'h0001; //      01
 mem[8'h80] = 16'h0003; //      11  read 8th bit
 mem[8'h81] = 16'h0001; //      01
 mem[8'h82] = 16'h0003; //      11  write NACK
 mem[8'h83] = 16'h0001; //      01      
 mem[8'h84] = 16'h0000; //      00
 mem[8'h85] = 16'h0002; //      10  
 mem[8'h86] = 16'h0003; //      11  stop the transfering
 mem[8'h87] = 16'h0001; //      01          
 
 end
 endmodule

* 実行 [#xa8f59dd]
- start up clock を jtag に設定し、bitファイルを生成し、ボードに書き込みます。
- 7segment LEDの表示が 0000 0000 になります(sw で異なります)。動作モードは0になります。
- BD(下 or 南)ボタンを押すとリセットされ、動作モードが0になります。
- 動作モードが 0 のとき(bitファイルをボードに書き込んだ直後の状態)は、Color LED 1 が消灯しています。このときは、「[[I2Cデバイスを手で動かしてみる]]」と同じように操作します。
- BE(右 or 東)ボタンを押すごとに動作モード1ずつ増えて変わります。動作モード1のときは、Color LED 1の色が青になります。動作モードが1のときは、「[[MiniCPU]]」と同じように操作します。クロックは中央ボタンの on/off で供給します。プログラムの実行は、BN(上または北)ボタンを押して、押したまま、中央ボタンを押すことで始まります。入力はスライドスイッチ sw で行います。出力は、ledおよび 7セグメントLEDマトリックスに表示されます。
- 動作モードが2のときは、Color LED 1の色が 緑になります。クロックは中央ボタンの on/off で供給します。プログラムの実行は、BN(上または北)ボタンを押して、押したまま、中央ボタンを押すことで始まります。I2Cの操作は、miniCPUの出力バッファ(out)の out[1]と out[0]を変化させることで行います。out[1]でsclを, out[0]で scaを、それぞれ操作します。
I2Cからの入力は、、「[[I2Cデバイスを手で動かしてみる]]」と同じように、読みだされたデータが、data バッファに書き込まれ、これを miniCPU の IN命令で miniCPUのレジスタに取り込むことができます。
* 考察 [#aedb8465]
- クロックの供給は手入力なので、大変。クロックも自動的に供給したい。デバッグしたり、高速に動かしたりするため、クロックスピードを変えることができるようにしたい。
- プログラムでサブルーチンを利用したい。サブルーチンを利用することにより、繰り返し行われる手続きをまとめることができるし、プログラムの機能分割が可能になる。

----
#counter

トップ   編集 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS