Khan Academy

Khan Academyというは、Khanさんが主宰している英語のオンライン教育資料です。小学校から大学までの様々な分野の自宅学習用のレクチャービデオがyoutubeで無料で公開されています。ただし、英語がメインです。今週のTimeのReboot the Schoolという記事で、初めてKhan Academyについて知りました。この記事の前半では、Khanさんがどういう経緯でKhan Academyを始めることになったのかや、現在、どれだけの人々がKhan Academyの教材を使用しているかが説明されています。そして、後半では、Khanさんの抱いている未来の教育についての夢について書かれています。Khan Academyのきっかけは、遠くに住んでいる姪の宿題をオンラインで見てあげているうちに、それをビデオに撮ってyoutubeで公開することを勧められて、試しにuploadしてみたところ、瞬く間に有名になったそうです。それから、Bill Gatesを初めとする大物投資家・慈善事業家から高額のdonationを受けて、ついに仕事もやめてKhan Academyを設立して、その選任講師になっています。今では、レクチャービデオの本数は3,250本にもなり、学校の授業でも15,000のクラスでレクチャービデオが活用され、1ヶ月に5百万人のunique userがレクチャービデオを見ます。日本と比較すればアメリカの方がオンラインの教材の受け入れやすい環境にあると勝手に思いますが (国土が広いので、あまり面と向かい合うことを重要視しない、例えば職場でも電話会議がさかん、あと州によっては子供を学校ではなく家庭で教育する権利を認められていたような・・)、それでも凄い実績の数字だと思います。

Khanさんの描く未来の学校教育は、新しい知識を詰め込むような作業は、子供が各自で家でKhan Academyのようなレクチャービデオを見ながら進めておいて、学校の授業は先生と生徒のインタラクティブなやり取りが含まれる作業に集中します。例えば、レクチャーの中の分からない部分のフォローアップだとか実験だとかです。しかも、各自が自分の理解度に合わせた自由なスピードで学習を進めることができます。当然ながら、それによって大きな変化に襲われる既存の学校の先生からは様々な批判を受けています。また、Timeの記事でも、ここ10年で新しいテクノロジーが次々に学校教育に導入されたが、それが本当にどれだけの効果があったのかはよく分からない、としています。

日本にいて幼い子供を持つ親としては、ちょっと羨ましいような、少し怖いような複雑な気持ちです。自分の世代にもこのような教育のオプションがあったら、もっと視野も広がったかもしれないし、英語も上手になったかもしれないと思う反面、これからの世代の子供は、英語+インターネットの力で教育までもがコモディティとして世界中にくまなく普及していくような世界で、どのように生きて行くのでしょう。

日本語のKhan Academyのサイトもあります。レクチャービデオに日本語の字幕をつけたり、日本語で撮り直したりする活動を行っているようです。

SystemVeriogでTD4をAltera DE0 Boardに (その2)

前の記事で、TD4というCPU(!?)をAlteraのDE0に実装しました。今回は、いちおうその時のRTLを使って、ModelSimでSimulationを行なっていました。相変わらずのラーメンタイマです。

CPUの創り方という本は良くできた本なので、基本的なCPUのhardwareの中身が良く分かります。でも、CPUで遊ぶにはやっぱりFirmwareの開発環境が必要です。毎回、had assembleして、MemoryにLoadして、RTLでsimulationするわけにもいかないし。(でも、アメリカの西海岸にある会社と仕事したときには、そこのFirmwareの開発環境はこれに近かったなあ。)

`timescale 1ns/1ns
`define SIM
module tb_TD4();
	wire [9:0] LEDG;
	reg [3:0]  SW;
        reg CLK, RST;

	TD4 td4 (.*);

 	initial begin 
		CLK = 0;
		forever
		// 1 CYCLE = 20ns
		# 10 CLK = ~CLK;
	end

	initial begin 
		RST = 1;
		$display("simulation");
		# 6 RST = 0;
	end
	initial SW = 4'b0000;
        integer cnt = 0;
              always @(posedge CLK)
              cnt <= cnt+1;
        initial if (cnt > 200_000) $finish;
      
endmodule

簡単な2端子回路のS-parameter (その2)

前の記事ではSpectreを使って2端子回路のS-parameterを求めましたが、今回は手計算で同じ回路のs-parameterを求めてSpectreの結果と一致することを確認しました(って当たり前の結果ですが)。このグラフはS11を計算して, Spectreの結果と比べたものです・・。

[freq, s11, s12, s21, s22] = read_s2p('CapSpara.s2p', 'RI');

figure;
semilogx(freq*1e-9, 20*log10(abs(s11)), 'bo');
grid;
hold on ;

Z0=50;
Z1 = 1./(2.*pi.*i.*10e-12.*freq);
Z2 = Z1.*Z0./(Z1+Z0);
VA=Z2./(Z2+50);

semilogx(freq*1e-9, 20*log10(abs(VA*2-1)), 'r-');
legend('Spectre', 'Matlab');

簡単な2端子回路のS-parameter

簡単な2端子回路のS-parameterを2通りのやり方で求めてみました。

AC analysisで求める方法。回路図がちょっとだけ面倒です。

S11は、ノードaの電圧と1Vの差分なので、S11 = db20(1-VF("/a"))
S21は、Port2に発生する電圧だけど、この場合はPort2はノードaそのものなので、S21 = db20(VF("/a"))


Spectreには、SP analysisという解析機能があります。これを使うと、S-Parameterを直接求めてくれます。
SP analysisのための回路図

上のAC analysisで求めた結果と同じです(あたりまえですが・・)。これに加えて、S-parameter(s2p)をファイルに出力してくれます

SystemVeriogでTD4をAltera DE0 Boardに

以前に読んだCPUの創り方という本に載っている4bitのCPU「TD4」をAlteraのFPGA Board DE0に移植してみました。無駄にmoduleの数を増やしています。こことかこことかを参考にしました。


TD4.h

`define OPCODE_WIDTH  4
`define DATA_WIDTH    4

TD4.v

`include "TD4.h"
module TD4(
	input CLK, RST,
	input [`DATA_WIDTH-1:0] SW,
	output [9:0] LEDG
);
   wire [`DATA_WIDTH-1:0] _OUT_, _IN_;
   wire CLK1Hz;
	
   CLKGEN u_clkgen(.*);
   TD4_CORE u_td4_core (.*, .CLK(CLK1Hz));
	
//	assign LEDG[4] = CLK1Hz;
   assign LEDG[3:0] = _OUT_;
   assign LEDG[9:`DATA_WIDTH] = {10-`DATA_WIDTH{1'b0}};
   assign _IN_ = SW;
endmodule

TD4_CORE.v

`include "TD4.h"
module TD4_CORE(
	input CLK, RST,
	input [`DATA_WIDTH-1:0] _IN_,
	output wire [`DATA_WIDTH-1:0] _OUT_
);
   wire LOAD0, LOAD1, LOAD2, LOAD3;
   wire [`DATA_WIDTH-1:0] ALU_IN, ALU_OUT;
   wire [`DATA_WIDTH-1:0] A, B, IM, PC;
   wire [`DATA_WIDTH+`OPCODE_WIDTH-1:0] INST;
   wire [`OPCODE_WIDTH-1:0] OP;
   wire C, Cnext;
	assign OP = INST[`DATA_WIDTH+`OPCODE_WIDTH-1:`DATA_WIDTH];
	assign IM = INST[`DATA_WIDTH-1:0];
	
   // ROM
   ROM rom(.*);
   // OpCode Decode
  OpDecode u_opdecode (.*);
   // ALU
   ALU u_alu (.*);
   // Register + Register Control
   RegRW u_regrw(.*);
endmodule

OpDecode.v

include "TD4.h"
module OpDecode(
	input [`OPCODE_WIDTH-1:0] OP,
	input [`DATA_WIDTH-1:0]   A, B, _IN_,
	input C,
	output wire LOAD0, LOAD1,LOAD2, LOAD3, 
	output wire [`DATA_WIDTH-1:0] ALU_IN
);
  // 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 ALU_IN = (~SELECT_B & ~SELECT_A) ? A :
                   (~SELECT_B &  SELECT_A) ? B :
                   ( SELECT_B & ~SELECT_A) ? _IN_ :
                   `DATA_WIDTH'd0;
endmodule

ALU.v

`include "TD4.h"
module ALU(
	input [`DATA_WIDTH-1:0]  ALU_IN,
	input [`DATA_WIDTH-1:0]  IM,
	output wire [`DATA_WIDTH-1:0] ALU_OUT, 
	output wire Cnext
);
   // ALU
   assign {Cnext, ALU_OUT} = {1'b0,ALU_IN}+{1'b0,IM};
endmodule

RegRW.v

`include "TD4.h"
module RegRW (
	input CLK, RST,
	input LOAD0, LOAD1, LOAD2, LOAD3, 
	input [`DATA_WIDTH-1:0] ALU_OUT,
	input Cnext,
	output reg [`DATA_WIDTH-1:0] A, B, PC, _OUT_,
	output reg C
);
always @(posedge CLK, posedge RST) begin
   if (RST) begin
  	A  <= `DATA_WIDTH'd0;
	B  <= `DATA_WIDTH'd0;
	PC <= `DATA_WIDTH'd0;
	C  <= Cnext;
   end
   else begin
	  if (~LOAD0) A <= ALU_OUT;
     if (~LOAD1) B <= ALU_OUT;
	  if (~LOAD2) _OUT_ <= ALU_OUT;
     if (~LOAD3)  
	     PC <= ALU_OUT;
	  else
		  PC <= PC + `DATA_WIDTH'd1;
	  C  <= Cnext;
   end
end	
endmodule

ROM.v

`include "TD4.h"

module ROM (
	input [`DATA_WIDTH-1:0] PC,
	output [`DATA_WIDTH+`OPCODE_WIDTH-1:0] INST
);
   reg [`DATA_WIDTH+`OPCODE_WIDTH-1:0] _ROM_ [2**`DATA_WIDTH-1:0];
   assign INST = _ROM_[PC];
	 // 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
   end
endmodule

CLKGEN.v

module CLKGEN (
	input CLK, RST, 
	output reg CLK1Hz
);
reg [25:0] cnt;
wire cnt_1Hz;
always @(posedge CLK, posedge RST) begin
	if (RST) begin
		cnt <= 26'd0;
		CLK1Hz <= 1'b0;
	end
 	else begin
	   cnt <= cnt_1Hz ? 26'd0 : cnt+26'd1;
		CLK1Hz <= cnt >= 26'd25_000_000;
	end
end
assign cnt_1Hz = (cnt==26'd49_999_999);
endmodule

理想的な50ohmではない負荷が接続された場合のEYEの計算方法

以前の記事では、MatlabでSparameterからEYE Diagramを計算しました。このときのEYEは、理想的な伝送条件のEYEです。理想的というのは、ドライバの駆動インピーダンスが50ohm (差動で100ohm), 負荷のインピーダンスが50ohm (差動で100ohm)という意味です。


実際のシステムでは、この条件は成り立ちません。ドライバや負荷のDCの抵抗値は、素子のばらつきにより50ohmから+/-10%くらいばらつきます。また、ドライバや負荷についている寄生容量によってインピーダンス成分も発生します。ドライバや負荷が理想的ではない場合の、周波数ドメインでの伝送特性 (Voltage Transfer Function) は、この式を用いて計算することができます。この式は、元々はこの資料に載っていたものです。


上の資料は、実は高速伝送のSignal Integrityについての講義資料の一部を抜粋したものです。おおもとの講義資料は、Intel Higher EducationのECLT 865, Signal Integrity on System Bus TechnologyというクラスのLectures 7-9 Introduction to Frequency Domain Analysisというレクチャーに含まれています。理想的ではない負荷が接続された場合のVoltage Transfer Functionの式を、Signal Flow Graphを使って導き出しています。このSignal Flow Graphの計算がずっと理解できずに困っていたのですが、最近になってこの本を読んでやっと理解することが出来ました。この本は、S-parameterにかかわる計算式をとても分かりやすく説明してくれています。


Voltage Transfer Functionの式をMatlabに入力して、負荷の抵抗値や寄生容量の有無によって周波数ドメインでの伝送特性がどのように変化するかを、Backplaneのs-paraを用いて計算してみました。下のグラフは、負荷の抵抗値を40ohm, 50ohm, 60ohmと変えた場合です。40ohmにすると、減衰量が少しだけ大きくなり、60ohmの場合は減衰量が少しだけ小さくなることが分かります。


こちらは、1pFの寄生容量をドライバ、負荷の両方につけた場合です。寄生容量がつくと、周波数特性が「波打つ」ようになります。時間ドメインでみると、小さな反射が起きていると思われます。


使用したMatlabソースコードはこんな感じです。ここで計算したVoltage Transfer Functionを用いて、昔の記事に書かれている方法で時間ドメインの波形を求めれば、負荷が理想的ではない場合のEYE diagramを表示されることができます。

Z0    = 50;
DrvR  = 50;
DrvC  = 1e-12;
LoadR = 50;
LoadC = 1e-12;

if DrvC
    DrvZcap = 1./(2 .* pi .* freq .* DrvC.*j);
    DrvZ = DrvR .* DrvZcap ./ (DrvR + DrvZcap);
else
    DrvZ = DrvR * ones(1, length(freq));
end

if LoadC
    LoadZcap = 1./(2 .* pi .* freq .* LoadC.*j);
    LoadZ = LoadR .* LoadZcap ./ (LoadR + LoadZcap);
else
    LoadZ = LoadR * ones(1, length(freq));
end

DrvRefC  = (DrvZ  - Z0) ./ (DrvZ  + Z0);
LoadRefC = (LoadZ - Z0) ./ (LoadZ + Z0);

VoltageTF = sdd21.*(1 + LoadRefC).*(1 - DrvRefC) ./ ...
      (1 - sdd11.*DrvRefC - sdd22.*LoadRefC - sdd21.*sdd12.*DrvRefC.*LoadRefC + sdd11.*sdd22.*DrvRefC.*LoadRefC);

% figure;
plot(freq*1e-9, 20*log10(abs(VoltageTF)), 'r');

FPGAボードで学ぶ組込みシステム開発入門

先日、購入したAltera FPGAのDE0という評価ボードで遊ぶためのテキストを購入しました。「FPGA開発ツールQuartus IIの使い方」という非常にベーシックな内容から、組み込みLinuxを動作させるというレベルまで、幅広い内容をカバーしています。出版社のサイトはこちらです。サンプルコードをダウンロードできます。