[[MiniCPUとI2Cバスの接続]] * 概要 [#zaba5b6a] - OSはプログラムを動かすプログラムであり、プログラムと人間とハードウェアの間のインターフェースです。よく利用されているようなOSを作成するのは大変ですが、miniCPUを操作するための簡単な機能をハードウェアで構成します。 - このOSは、miniCPUの起動と停止, miniCPUの実行速度の変更, miniCPUの入出力及び、インターフェースの接続状況の変更を行います。プログラムは、ram.v に書かれたものに限定します。 -- fpga で、miniCPU と周辺機器の接続を変更したり、miniCPUの実行を自動で行ったり、実行速度を変えたりすることを、fpga 上の基盤のスイッチの切り替えで行う回路を作成します。 -- 一般的なOSはプログラムの入れ替えを行うことができますが(プログラムローダが存在します)、この簡易OSではminiCPUのプログラムは、あらかじめ、ram.v に書かれたプログラムのみ実行することができます。 プログラムの入れ替えは、ISE上でram.v を書き換えて生成された bitファイルのダウンロードによって行います。 - [[MiniCPUとI2Cバスの接続]]を拡張します。[[MiniCPUとI2Cバスの接続]]と同様に、miniCPU をI2Cのmaster device として、I2Cのslave device を miniCPUのプログラムで、自動的に動かします。 - 動作モードを変更することにより、([[MiniCPUとI2Cバスの接続]]と同様に) I2Cのslave device を手で動かしたり、miniCPUをI2Cと切り離して単独で動かしたり、miniCPU でI2Cの slave device 自動的に動かしたりできる他, miniCPUにクロックを自動的に供給し, 自動的にminiCPUを動かすことができるようにします。このとき、miniCPU のクロックを、ボードのクロックを分周することにより、変化させることができるようにします。 -- 動作モードの変更は、5つのボタンの、左(東)を使って変更します。 - miniCPUのクロックを手で供給するときは、中央のボタンを押したり離したりして供給します。 -- Nexys4ボードのクロックは 100MHz です。ボードのクロックは32bitカウンタに供給されます。Nexys4のスライドスイッチの, 右から5つまでを使って分周比を決定します。このスライドスイッチで0-31までの数を表すことができますが、32bitカウンタを、左から数えて、その数が表す桁の値を、分周されたクロックとして、取り出します。 スライドスイッチを右から(1,1,1,1,0)とすると, これは32bit カウンタの, 下から30bit目の値を取り出すことになり, およそ, 10秒に1回クロックを供給することになります。 - 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|start| |0|I2Cバスの手動操作| {0,0,0} |BCx | 0 | 0| {16{0}, data,swx[7:0]}|{data,swx[7:0]}|BCx,swx[0]|{0,sda,scl}|0| |1|miniCPUの独立実行(手動クロック供給)|{0,0,1}|BCx|BNx|swx|{{0},cpuCs,pcout,irout}|out|1,1|{0,sda,scl}|0| |2|miniCPUでI2Cバスを操作(手動クロック供給)|{0,1,0}|BCx|BNx|{8{0},data}|{{0},cpuCs,abus,dbus}|{data,out[7:0]}|out[1],out[0]|{0,sda,scl}|0| |3|miniCPU自動クロック供給のときのクロック分周値設定 |{0,1,1}|BCx |0|{8{0},data}|{{0},cpuCs,abus,dbus}|{data,out[7:0]}|out[1],out[0]|{0,sda,scl}|0| |4|miniCPUの独立実行(自動クロック供給)|{1,0,0}|dclk|ssRun(自動スタート)|swx|{{0},cpuCs,pcout,irout}|out|1,1|{0,sda,scl}|BCx| |5|miniCPUでI2Cバスを操作(自動クロック供給)|{1,0,1}|dclk|ssRun(自動スタート)|{8{0},data}|{{0},cpuCs,abus,dbus}|{data,out[7:0]}|out[1],out[0]|{0,sda,scl}|BCx| - down button をリセット信号とします。 - sda を led[8] に接続します。scl が 0->1 に変化するたびに、これをシフトして、過去8回のsda の High/Low の遷移を led[15:8] に表示します。 これを実現するために、レジスタ data[7:0] を使っています。 - 1つのポートで入出力を行う為、scl, sda は verilog の inout 型を使います。 ** Verilog [#y617cf4a] - 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; wire cpuClk; wire cpuRun; reg [7:0] data; reg [2: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; wire start; wire haltIn; wire halt; reg [4:0] divide; wire dclk; assign ledOut=led; reg [2:0] colorLed_1x; wire [2:0] colorLed_2x; // assign colorLed_1=colorLed_1x; assign colorLed_2=colorLed_2x; assign reset=~bd; 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<=3'b000; end else case (operationMode) 3'b000: operationMode<=3'b001; 3'b001: operationMode<=3'b010; 3'b010: operationMode<=3'b011; 3'b011: operationMode<=3'b100; 3'b100: operationMode<=3'b101; 3'b101: operationMode<=3'b110; 3'b110: operationMode<=3'b000; default operationMode<=3'b000; endcase end /* always @(posedge BWx or negedge reset ) begin if(!reset) begin operationMode<=0; end else case (operationMode) 3'b000: operationMode<=3'b110; 3'b001: operationMode<=3'b000; 3'b010: operationMode<=3'b001; 3'b011: operationMode<=3'b010; 3'b100: operationMode<=3'b011; 3'b101: operationMode<=3'b100; 3'b110: operationMode<=3'b101; default operationMode<=3'b000; endcase end */ /* */ // assign setDivide=(operationMode==3'b011)?BCx:1'b0; always @(posedge BCx ) begin if(operationMode==3'b011) begin divide<=swx[15:11]; end end assign colorLed_2x={dclk,scl,sda}; assign start=(operationMode==3'b100|operationMode==3'b101)?BCx:1'b0; assign cpuClk=(operationMode==3'b100|operationMode==3'b101)? dclk:BCx; assign cpuRun=(operationMode==3'b100|operationMode==3'b101)? ssRun:BNx; assign haltIn=(operationMode==3'b100|operationMode==3'b101)? halt:1'b0; // 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 @(posedge BEx or posedge BWx or negedge reset) begin always @(operationMode) begin case(operationMode) 3'b000: begin // direct i2c operation only colorLed_1x=3'b000; 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 3'b001: begin // mini CPU, with manual clock only ... for start ... push BTN, keep, push BTC, release BTN, BTC colorLed_1x=3'b001; // blue cpuIn=swx; sSegArray={{0},cpuCs,pcout,irout}; led={{0{16}},out}; sclx=1'b1; sdax=1'b1; end 3'b010: begin // mini CPU, with manual clock, with i2c IO colorLed_1x=3'b010; //green 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 3'b011: begin // set clock divider for mini CPU with automatic clock colorLed_1x=3'b011; // cyan .. aqua cpuIn=0; sSegArray={divide,{13{0}},data,swx[7:0]}; led[15:8]=divide; led[7:0]=swx[7:0]; sclx=1; sdax=1; end 3'b100: begin // mini CPU, only, with automatic clock, colorLed_1x=3'b100; // red cpuIn=swx; sSegArray={{0},cpuCs,pcout,irout}; led={{0{16}},out}; sclx=1'b1; sdax=1'b1; end 3'b101: begin // mini CPU, with automatic clock, with i2c IO colorLed_1x=3'b101; // purple 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'b000; 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})); /* for test bench assign BNx=bu; assign BWx=bl; assign BEx=br; assign BCx=bc; assign swx=sw; */ sSegArray sSegArray0(.clk(bclck), .reset(reset), .load(1'b1), .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), .haltx(haltIn)); clockDivider clockDivider0(.clk(bclck),.reset(reset), .div(divide), .dclk(dclk)); cpuStartStopSequence cpuStartStopSequence0(.clk(dclk), .reset(reset), .start(start), .run(ssRun), .halt(halt)); endmodule ---- #counter