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を動作させるというレベルまで、幅広い内容をカバーしています。出版社のサイトはこちらです。サンプルコードをダウンロードできます。