目次
前
次
簡易プロセッサ開発
MCR_VCでは、マイコン、モータ等の種別は
問われないので、各種マイコンが使われて
います。
マイコンの種別が問題にされないのなら、自作の
プロセッサを利用し、それをFPGAに封入して利用
してもよいだろうと考えました。
仕事関係で入手したCPLD/FPGA基板があったので
この評価を兼ねた自作プロセッサを開発すると
目標を立てます。
MCR_VCのシステムを実現するプロセッサ動作は
非常に単純で、次のことを繰り返しているだけ。
- 路面状況入手
- エンコーダから回転数入手
- 取得した情報から、モータに与えるDUTY比計算
- モータドライバのカウンタに、DUTY比を設定
- 1に戻る
上のシーケンスを電源が切れるまで繰り返せば
MCR_VCマシンは、動きます。
mugen2012マシンでは、簡単なシーケンサを利用して
動かした実績があります。シーケンサの性能を少し
上げて、プロセッサに近いことをさせるとよいかな
と判断しました。
なるべく単純な動作でMCR_VCマシンを動かせるように
シーケンスの各ステートで担当する機能を考えます。
路面状況入手
カメラかカメラ相当デバイスから1次元の
路面センサー情報を入手するのは、専用の
デジタル回路をFPGA内部に入れて対応します。
プロセッサは、専用回路が出力する結果だけを
利用し、専用回路制御に触れないとすると、
1次元の路面センサー情報(8ビット程度)を
入力するだけに機能限定です。
回転数入手
ロータリーエンコーダが出力するパルスを
FPGA内部のカウンタでカウントし、その値
をプロセッサが取得できるようにします。
プロセッサは、カウンタの値だけを利用し
制御等はやらないと判断です。
DUTY比計算
路面センサーと回転数の情報から、モータに
与えるDUTY比を求めるには、内部にROMを用意
し、その値を取出すことで対応します。
細かい計算が必要ならば、専用の計算ブロックを
用意し、そのブロックからの計算結果を利用する
ことに。
ここまでのメモから、プログラミングモデルを決めました。
汎用CPUのプログラミングモデルからは、相当外れていると
思います。専用プロセッサですから、これで充分でしょう。
各レジスタの仕様を決めていきます。
Instruction Pointer
命令コードを記憶しているROMのアドレスを格納します。
12ビットとして、0〜4095のアドレスを指定。
Instruction Register
ROMから取り出した、20ビット命令を格納します。
Working Register
12ビットの作業用レジスタ。
A、Bの2種を用意。
Data Pointer Register
各種データを格納しているSRAMのアドレスを格納。
12ビットとして、0〜4095のアドレスを指定。
Sensor Register
カメラまたはセンサーの8ビットデータを格納
しているレジスタ。
Left Encoder Register
左ロータリーエンコーダのカウント値を格納する12ビットレジスタ。
12ビットカウンタの値を、そのまま反映。
Right Encoder Register
右ロータリーエンコーダのカウント値を格納する12ビットレジスタ。
12ビットカウンタの値を、そのまま反映。
Servo Motor Register
サーボモータの角度を格納する8ビットレジスタ。
角度は0〜180とする。
Left Motor Register
左DCモータの方向とDuty比を格納する9ビットレジスタ。
9ビットのMSBとその下の2ビットで方向を指定し
7ビットにDuty比を指定。
方向は2進数で指定。
00 回転停止
01 右(前)回転
10 左(後)回転
11 回転停止
Right Motor Register
右DCモータの方向とDuty比を格納する10ビットレジスタ。
9ビットのMSBとその下の2ビットで方向を指定し
7ビットにDuty比を指定。
方向は2進数で指定。
00 回転停止
01 右(前)回転
10 左(後)回転
11 回転停止
Flag Status
演算結果のフラグを記憶する2ビットレジスタ。
フラグは、Zero、Negative。
レジスタ仕様を決めたなら、命令コード(ニモニック)を定義します。
- LD データメモリからWorking Registerにデータ転送
- ST Working Registerからデータメモリにデータ転送
- JNG レジスタのMSBが1のとき、指定ステップに分岐
- JZE フラグが0のとき、指定ステップに分岐
- JMP 指定ステップに分岐
- MOV レジスタ間のデータ転送
- MVI レジスタに値を設定
- EQ Working Registerと値が等しいかを求め、フラグ設定
- INC Working Register、Data Pointerの値を+1。フラグ設定
- DEC Working Register、Data Pointerの値を−1。フラグ設定
命令コードを決めたなら、マイクロプログラムを
考えます。マイクロプログラムは、デジタル回路
を動かすビットの組み合わせになります。
20ビットで、プログラムコードを記述します。
命令は10種類以上ですが、分類すると以下のように
なります。
ニモニックコードを定義します。
LD
データメモリからWorking Registerにデータ転送するので
命令の4ビットを1000、データメモリのアドレスは12ビット
Working Registerは、A(0)かB(1)とします。
アドレスは、即値かData Pointer Register格納値を利用。
LD WA,100
LD WB,200
LD WA,DPR
LD WB,DPR
ST
Working Registerからデータメモリにデータ転送するので
命令の4ビットを1001、データメモリのアドレスは12ビット
Working Registerは、A(0)かB(1)とします。
アドレスは、即値かData Pointer Register格納値を利用。
ST WA,100
ST WB,200
ST WA,DPR
ST WB,DPR
JNG
Nフラグが1のとき、指定ステップに分岐します。
命令の4ビットを1010、それに続けて4ビットの
フラグ値を入れます。フラグに続き、命令を格納
したアドレスを入れます。
フラグが0でないときは、次のステップに分岐します。
JZE
Zフラグが1のとき、指定ステップに分岐します。
命令の4ビットを1011、それに続けて4ビットの
フラグ値を入れます。フラグに続き、命令を格納
したアドレスを入れます。
フラグが0でないときは、次のステップに分岐します。
JMP
指定ステップに分岐します。
命令の4ビットを1100、続く4ビットを飛ばして
命令を格納したアドレスを入れます。
MOV
レジスタ間のデータ転送をするので、命令の4ビットを0000とし
それに続けて、転送先の指定4ビット、転送元の指定4ビットを
定義します。下の5ビットはDon't careにします。
レジスタに番号をつけておきます。
- Working Register A 0000
- Working Register B 0001
- Data Pointer Register 0010
- Servo Motor Register 0100
- Right Motor Register 0101
- Left Motor Register 0110
- Sensor Register 1100
- Right Rotary Encoder 1101
- Left Rotary Encoder 1110
MVI
レジスタに値を設定するため、命令の4ビット
は0001とし、レジスタは6種類限定です。
レジスタ番号は、MOV命令に利用した値と同じです。
ただし、使えるレジスタは以下です。
- Working Register A 0000
- Working Register B 0001
- Data Pointer Register 0010
- Servo Motor Register 0100
- Right Motor Register 0101
- Left Motor Register 0110
EQ
Working Registerと値を比較し、結果をフラグに反映。
命令の4ビットは0010とします。2つあるレジスタの
うち、どちらを利用するのかを1ビット指定、続けて
12ビットの値を指定します。
INC
Working Register、Data Pointerの値を+1する。
命令の4ビットは0011とします。利用レジスタは
次の3本とします。
- Working Register A 0000
- Working Register B 0001
- Data Pointer Register 0010
演算後、フラグを設定します。
DEC
Working Register、Data Pointerの値を+1する。
命令の4ビットは0100とします。利用レジスタは
次の3本とします。
- Working Register A 0000
- Working Register B 0001
- Data Pointer Register 0010
演算後、フラグを設定します。
アセンブラ、シミュレータ作成
ニモニックから16ビットコードを生成し、プロセッサの
動作をシミュレーションします。
アセンブラとシミュレータは、マルチプラットホームを
想定し、スクリプト言語Tcl/Tkで記述します。
過去にTcl/Tkでアセンブラ、シミュレータを作成した
経験と資産を活用します。
PLC用アセンブラ、シミュレータを改造して
開発時間を短縮します。
バッチファイルを作成し、一気にアセンブルする方式でも
よいのですが、GUI操作が簡単と考え、次画面としました。
Tcl/Tkのソースコードは、以下。
#!/usr/local/bin/wish
wm title . "My Assemble Simulator"
set theFileName ""
set fd_in ""
set last 0
for {set i 0} {$i < 4096} {incr i} {
set memory($i) 0
}
set msft 0
set index 0
set pgm(0) ""
set pgmcode ""
set xsensor 24
set xsensorb "00011000"
set xleftrotary 0
set xrightrotary 0
set xservo 150
set xleftmotor 0
set xrightmotor 0
set xwrav 0
set xwrbv 0
set xdprv 0
set xflag "00"
#######################################
# define objects
#######################################
#----- label -----
label .lblFileNameLabel -text "FileName"
label .lblFileName -textvariable theFileName
label .lblMemory -text "Memory"
label .lblIndex -text "index"
label .lblCode -text "code"
label .lblIndexV -textvariable index
label .lblCodeV -textvariable pgmcode
label .lblWorkingRegisterA -text "WRA"
label .lblWorkingRegisterB -text "WRB"
label .lblDataPointRegister -text "DPR"
label .lblSensor -text "Sensor"
label .lblLeftRotary -text "Left rotary"
label .lblRightRotary -text "Right rotary"
label .lblServo -text "Servo"
label .lblLeftMotor -text "Left motor"
label .lblRightMotor -text "Right motor"
label .lblServoV -textvariable xservo
label .lblLeftMotorV -textvariable xleftmotor
label .lblRightMotorV -textvariable xrightmotor
label .lblWorkingRegisterAV -textvariable xwrav
label .lblWorkingRegisterBV -textvariable xwrbv
label .lblDataPointRegisterV -textvariable xdprv
label .lblFlagStatus -text "Flag Status"
label .lblFlagStatusV -textvariable xflag
#----- list box -----
listbox .lstCode -yscrollcommand ".scbLadderV set" -width 24
listbox .lstMemory -yscrollcommand ".scbMemoryV set" -width 24
#----- scroll bar -----
scrollbar .scbLadderV -orient vertical -command ".lstCode yview"
scrollbar .scbMemoryV -orient vertical -command ".lstMemory yview"
#----- entry -----
entry .txtSensor -width 10 -textvariable xsensor
entry .txtLeftRotary -width 10 -textvariable xleftrotary
entry .txtRightRotary -width 10 -textvariable xrightrotary
#----- button -----
button .btnExit -text "Exit" -command "exit"
button .btnLoad -text "Load" -command {
# tk_messageBox -type ok -message "Load"
set theFileName [tk_getOpenFile -filetypes {{"text file" {.txt}}}]
# clear list box
.lstCode delete 0 end
# open
set fd_in [open $theFileName "r"]
# read context
set i 0
while { [gets $fd_in sbuf] >= 0 } {
# store
set pgm($i) $sbuf
# convert
set pgmx($i) [getCode $pgm($i)]
# display
set tmp [format "%04d %s <- %s" $i $pgmx($i) $pgm($i)]
.lstCode insert end $tmp
# increment
incr i
}
set last $i
# close
close $fd_in
ShowMemory 0
#
set pgmcode $pgm(0)
}
button .btnZero -text "Zero" -command {
set index 0
set msft 0
set pgmcode $pgm($index)
}
button .btnStep -text "Step" -command {
doScan $index
# increment step index
incr index
#
if { $index < $last } {
set pgmcode $pgm($index)
}
if { $index == $last } {
set index 0
set msft 0
set pgmcode $pgm($index)
}
}
#######################################
# procedures
#######################################
proc doScan {x} {
global last pgm pgmx memory index xwrav xwrbv xdprv xflag xsensor
global xleftrotary xrightrotary xservo xleftmotor xrightmotor
#
if { $x < $last } {
# show memory
ShowMemory 0
# separate code
set pgmxx(0) [string index $pgmx($x) 0]
set pgmxx(1) [string index $pgmx($x) 1]
set pgmxx(2) [string index $pgmx($x) 2]
set pgmxx(3) [string index $pgmx($x) 3]
set pgmxx(4) [string index $pgmx($x) 4]
# get opcode
set opcode [getHex $pgmxx(0)]
# clear flag
set xflag "00"
# LD instruction
if { $opcode == 8 } {
# register
set reg [getHex $pgmxx(1)]
# address
set adr 0
set dv [getHex $pgmxx(2)] ; set value [expr $adr * 16 + $dv]
set dv [getHex $pgmxx(3)] ; set value [expr $adr * 16 + $dv]
set dv [getHex $pgmxx(4)] ; set value [expr $adr * 16 + $dv]
# WA direct
if { $reg == 0 } {
set xwrav $memory($adr)
}
# WB direct
if { $reg == 1 } {
set xwrbv $memory($adr)
}
# WA indirect
if { $reg == 8 } {
# tk_messageBox -type ok -message "$memory($xdprv) $xdprv"
set xwrav $memory($xdprv)
}
# WB indirect
if { $reg == 9 } {
# tk_messageBox -type ok -message "$memory($xdprv) $xdprv"
set xwrbv $memory($xdprv)
}
}
# ST instruction
if { $opcode == 9 } {
# register
set reg [getHex $pgmxx(1)]
# address
set adr 0
set dv [getHex $pgmxx(2)] ; set value [expr $adr * 16 + $dv]
set dv [getHex $pgmxx(3)] ; set value [expr $adr * 16 + $dv]
set dv [getHex $pgmxx(4)] ; set value [expr $adr * 16 + $dv]
# WA direct
if { $reg == 0 } {
set memory($adr) $xwrav
}
# WB direct
if { $reg == 1 } {
set memory($adr) $xwrbv
}
# WA indirect
if { $reg == 8 } {
set memory($xdprv) $xwrav
}
# WB indirect
if { $reg == 9 } {
set memory($xdprv) $xwrbv
}
}
# JNG instruction
if { $opcode == 10 } {
# get flag
set tflag $xflag
set tflag [expr $tflag / 2]
# calculate address
set adr 0
set dv [getHex $pgmxx(2)] ; set value [expr $adr * 16 + $dv]
set dv [getHex $pgmxx(3)] ; set value [expr $adr * 16 + $dv]
set dv [getHex $pgmxx(4)] ; set value [expr $adr * 16 + $dv]
# negative flag is set
if { $tflag > 0 } {
set index [expr $adr - 1]
}
}
# JZE instruction
if { $opcode == 11 } {
# get flag
set tflag $xflag
set tflag [expr $tflag % 2]
# calculate address
set adr 0
set dv [getHex $pgmxx(2)] ; set value [expr $adr * 16 + $dv]
set dv [getHex $pgmxx(3)] ; set value [expr $adr * 16 + $dv]
set dv [getHex $pgmxx(4)] ; set value [expr $adr * 16 + $dv]
# negative flag is set
if { $tflag > 0 } {
set index [expr $adr - 1]
}
}
# JMP instruction
if { $opcode == 12 } {
# calculate address
set adr 0
set dv [getHex $pgmxx(2)] ; set value [expr $adr * 16 + $dv]
set dv [getHex $pgmxx(3)] ; set value [expr $adr * 16 + $dv]
set dv [getHex $pgmxx(4)] ; set value [expr $adr * 16 + $dv]
#
set index [expr $adr - 1]
}
# MOV instruction
if { $opcode == 0 } {
# destination register
set regd [getHex $pgmxx(1)]
# source register
set regs [getHex $pgmxx(2)]
#tk_messageBox -type ok -message "$regd $regs"
# source WRA
if { $regs == 0 } {
set tmp $xwrav
}
# source WRB
if { $regs == 1 } {
set tmp $xwrbv
}
# source Data Point Register
if { $regs == 2 } {
set tmp $xdprv
}
# source Servo motor register
if { $regs == 4 } {
set tmp $xservo
}
# source Right Motor Register
if { $regs == 5 } {
set tmp $xrightmotor
}
# source Left Motor Register
if { $regs == 6 } {
set tmp $xleftmotor
}
# source Sensor register
if { $regs == 8 } {
set tmp $xsensor
}
# source Right Encoder
if { $regs == 9 } {
set tmp $xrightrotary
}
# source Left Encoder
if { $regs == 10 } {
set tmp $xleftrotary
}
# destination WRA
if { $regd == 0 } {
set xwrav $tmp
}
# destination WRB
if { $regd == 1 } {
set xwrbv $tmp
}
# destination Data Point Register
if { $regd == 2 } {
set xdprv $tmp
}
# destination Servo motor register
if { $regd == 4 } {
set xservo $tmp
}
# destination Right Motor Register
if { $regd == 5 } {
set xrightmotor $tmp
}
# destination Left Motor Register
if { $regd == 6 } {
set xleftmotor $tmp
}
}
# MVI instruction
if { $opcode == 1 } {
# register
set reg [getHex $pgmxx(1)]
# value
set value 0
set dv [getHex $pgmxx(2)] ; set value [expr $value * 16 + $dv]
set dv [getHex $pgmxx(3)] ; set value [expr $value * 16 + $dv]
set dv [getHex $pgmxx(4)] ; set value [expr $value * 16 + $dv]
# WA
if { $reg == 0 } {
set xwrav $value
}
# WB
if { $reg == 1 } {
set xwrbv $value
}
# DPR
if { $reg == 2 } {
set xdprv $value
}
# Servo motor register
if { $reg == 4 } {
set xservo $value
}
# Right Motor Register
if { $reg == 5 } {
set xrightmotor $value
}
# Left Motor Register
if { $reg == 6 } {
set xleftmotor $value
}
}
# EQ instruction
if { $opcode == 2 } {
# register
set reg [getHex $pgmxx(1)]
# value
set value 0
set dv [getHex $pgmxx(2)] ; set value [expr $value * 16 + $dv]
set dv [getHex $pgmxx(3)] ; set value [expr $value * 16 + $dv]
set dv [getHex $pgmxx(4)] ; set value [expr $value * 16 + $dv]
# WA
if { $reg == 0 } {
set tmp ""
# ==
if { $xwrav == $value } {
set tmp "1$tmp"
} else {
set tmp "0$tmp"
}
# negative
if { $xwrav & 512 } {
set tmp "1$tmp"
} else {
set tmp "0$tmp"
}
# update flag
set xflag $tmp
}
# WB
if { $reg == 1 } {
set tmp ""
# ==
if { $xwrbv == $value } {
set tmp "1$tmp"
} else {
set tmp "0$tmp"
}
# negative
if { $xwrbv & 512 } {
set tmp "1$tmp"
} else {
set tmp "0$tmp"
}
# update flag
set xflag $tmp
}
}
# INC instruction
if { $opcode == 3 } {
# register
set reg [getHex $pgmxx(1)]
# WA
if { $reg == 0 } {
set xwrav [expr $xwrav + 1]
}
# WB
if { $reg == 1 } {
set xwrbv [expr $xwrbv + 1]
}
# Data Pointer Register
if { $reg == 2 } {
set xdprv [expr $xdprv + 1]
}
}
# DEC instruction
if { $opcode == 4 } {
# register
set reg [getHex $pgmxx(1)]
# WA
if { $reg == 0 } {
set xwrav [expr $xwrav - 1]
}
# WB
if { $reg == 1 } {
set xwrbv [expr $xwrbv - 1]
}
# Data Pointer Register
if { $reg == 2 } {
set xdprv [expr $xdprv - 1]
}
}
# show memory
ShowMemory 0
}
}
proc getCode {x} {
# get command
set opcode [lindex $x 0]
# get operand
set operand [lindex $x end]
set location [string first "," $operand 0]
# default
set car ""
set cdr ""
#
if { $location > 0 } {
# calculate location
set before [expr $location-1]
set after [expr $location+1]
# convert
set car [string range $operand 0 $before]
set cdr [string range $operand $after end]
}
# conversion
if { $opcode == "LD" } {
# pat
set pat "000000000000"
# add register name
if { $car == "WA" } {
if { $cdr == "DPR" } {
set xcode "10001000$pat"
} else {
set xcode "10000000"
set xcode "$xcode[convBinary $cdr]"
}
}
if { $car == "WB" } {
if { $cdr == "DPR" } {
set xcode "10000001$pat"
} else {
set xcode "10001001"
set xcode "$xcode[convBinary $cdr]"
}
}
}
if { $opcode == "ST" } {
# pat
set pat "000000000000"
# add register name
if { $car == "WA" } {
if { $cdr == "DPR" } {
set xcode "10011000$pat"
} else {
set xcode "10010000"
set xcode "$xcode[convBinary $cdr]"
}
}
if { $car == "WB" } {
if { $cdr == "DPR" } {
set xcode "10011001$pat"
} else {
set xcode "10010001"
set xcode "$xcode[convBinary $cdr]"
}
}
}
if { $opcode == "JNG" } {
set xcode "10100010[convBinary $operand]"
}
if { $opcode == "JZE" } {
set xcode "10110001[convBinary $operand]"
}
if { $opcode == "JMP" } {
set xcode "11000000[convBinary $operand]"
}
if { $opcode == "MOV" } {
set xcode "0000"
# destination register name
set dst [getRegValue $car]
# souce register name
set src [getRegValue $cdr]
#
set pat "00000000"
# concatenate
set xcode "$xcode$dst$src$pat"
}
if { $opcode == "MVI" } {
# add register name
if { $car == "WA" } {
set xcode "00010000"
}
if { $car == "WB" } {
set xcode "00010001"
}
if { $car == "DPR" } {
set xcode "00010010"
}
if { $car == "SMR" } {
set xcode "00010100"
}
if { $car == "RMR" } {
set xcode "00010101"
}
if { $car == "LMR" } {
set xcode "00010110"
}
set xcode "$xcode[convBinary $cdr]"
}
if { $opcode == "EQ" } {
# add register name
if { $car == "WA" } {
set xcode "00100000"
}
if { $car == "WB" } {
set xcode "00100001"
}
set xcode "$xcode[convBinary $cdr]"
}
if { $opcode == "INC" } {
# pat
set pat "0000000000"
# add register name
if { $operand == "WA" } {
set xcode "00110000"
}
if { $operand == "WB" } {
set xcode "00110001"
}
if { $operand == "DPR" } {
set xcode "00110010"
}
set xcode "$xcode$pat"
}
if { $opcode == "DEC" } {
# pat
set pat "0000000000"
# add register name
if { $operand == "WA" } {
set xcode "01000001"
}
if { $operand == "WB" } {
set xcode "01000011"
}
if { $operand == "DPR" } {
set xcode "01000010"
}
set xcode "$xcode$pat"
}
# seperate
set result0 [transHex [string range $xcode 0 3]]
set result1 [transHex [string range $xcode 4 7]]
set result2 [transHex [string range $xcode 8 11]]
set result3 [transHex [string range $xcode 12 15]]
set result4 [transHex [string range $xcode 16 end]]
# concatenate
set result "$result0$result1$result2$result3$result4"
# tk_messageBox -type ok -message "$x => $result"
return $result
}
proc h2b {x} {
# separate
set tmp $x
# separate
for {set i 0} {$i < 12} {incr i} {
set res($i) [expr $tmp % 2] ; set tmp [expr $tmp / 2] ;
}
set res(0) [expr $tmp % 2] ; set tmp [expr $tmp / 2] ;
# concatenate
set result "$res(11)$res(10)$res(9)$res(8)"
set result "$result$res(7)$res(6)$res(5)$res(4)"
set result "$result$res(3)$res(2)$res(1)$res(0)"
#
return $result
}
proc getHex {x} {
set result $x
if {[string tolower $x] == "a"} {
set result 10
}
if {[string tolower $x] == "b"} {
set result 11
}
if {[string tolower $x] == "c"} {
set result 12
}
if {[string tolower $x] == "d"} {
set result 13
}
if {[string tolower $x] == "e"} {
set result 14
}
if {[string tolower $x] == "f"} {
set result 15
}
return $result
}
proc pushVal {x} {
global msft
set xx $x
# shift
set msft [expr $msft * 2]
# store LSB
set msft [expr $msft + $xx]
}
proc pullVal {x} {
global msft
# get LSB
set result [expr $msft % 2]
# shift
set msft [expr $msft / 2]
#
return $result
}
proc ShowMemory {x} {
global memory
# delete
.lstMemory delete 0 end
for {set i 0} {$i < 4096} {incr i} {
.lstMemory insert end "[format "%04d" $i] [h2b $memory($i)]"
}
}
proc calcNumber16 {x y} {
# calculate
set result [expr $x * 16 + $y]
return $result
}
proc convBinary {x} {
set tmp $x
# separate
for {set i 0} {$i < 12} {incr i} {
set res($i) [expr $tmp % 2] ; set tmp [expr $tmp / 2] ;
}
# concatenate
set result "$res(11)$res(10)$res(9)$res(8)$res(7)$res(6)$res(5)$res(4)"
set result "$result$res(3)$res(2)$res(1)$res(0)"
#
return $result
}
proc getRegValue {x} {
set tmp $x
# judge
if { $tmp == "WA" } {
set result "0000"
}
if { $tmp == "WB" } {
set result "0001"
}
if { $tmp == "DPR" } {
set result "0010"
}
if { $tmp == "SMR" } {
set result "0100"
}
if { $tmp == "RMR" } {
set result "0101"
}
if { $tmp == "LMR" } {
set result "0110"
}
if { $tmp == "SR" } {
set result "1000"
}
if { $tmp == "RRE" } {
set result "1001"
}
if { $tmp == "LRE" } {
set result "1010"
}
return $result
}
proc transHex {x} {
#
if { $x == "0000" } {
set result "0"
}
if { $x == "0001" } {
set result "1"
}
if { $x == "0010" } {
set result "2"
}
if { $x == "0011" } {
set result "3"
}
if { $x == "0100" } {
set result "4"
}
if { $x == "0101" } {
set result "5"
}
if { $x == "0110" } {
set result "6"
}
if { $x == "0111" } {
set result "7"
}
if { $x == "1000" } {
set result "8"
}
if { $x == "1001" } {
set result "9"
}
if { $x == "1010" } {
set result "a"
}
if { $x == "1011" } {
set result "b"
}
if { $x == "1100" } {
set result "c"
}
if { $x == "1101" } {
set result "d"
}
if { $x == "1110" } {
set result "e"
}
if { $x == "1111" } {
set result "f"
}
return $result
}
#######################################
# window area placing
#######################################
grid .lblFileNameLabel -column 0 -row 0
grid .lblFileName -column 0 -row 1
grid .lstCode -column 0 -row 2
grid .lblMemory -column 0 -row 3
grid .lstMemory -column 0 -row 4
grid .lblIndex -column 0 -row 5
grid .lblCode -column 0 -row 6
grid .scbLadderV -column 1 -row 2 -sticky ns
grid .scbMemoryV -column 1 -row 4 -sticky ns
grid .lblIndexV -column 2 -row 5
grid .lblCodeV -column 2 -row 6
grid .btnLoad -column 3 -row 0
grid .btnZero -column 3 -row 5
grid .btnStep -column 3 -row 6
grid .btnExit -column 6 -row 14
grid .lblFlagStatus -column 0 -row 8
grid .lblFlagStatusV -column 1 -row 8
grid .lblWorkingRegisterA -column 4 -row 5
grid .lblWorkingRegisterB -column 4 -row 6
grid .lblDataPointRegister -column 4 -row 7
grid .lblSensor -column 4 -row 8
grid .lblLeftRotary -column 4 -row 9
grid .lblRightRotary -column 4 -row 10
grid .lblServo -column 4 -row 11
grid .lblLeftMotor -column 4 -row 12
grid .lblRightMotor -column 4 -row 13
grid .lblWorkingRegisterAV -column 5 -row 5
grid .lblWorkingRegisterBV -column 5 -row 6
grid .lblDataPointRegisterV -column 5 -row 7
grid .txtSensor -column 5 -row 8
grid .txtLeftRotary -column 5 -row 9
grid .txtRightRotary -column 5 -row 10
grid .lblServoV -column 5 -row 11
grid .lblLeftMotorV -column 5 -row 12
grid .lblRightMotorV -column 5 -row 13
シーケンス作成
アセンブラ、シミュレータが出来たので、MCR_VCマシンを
動かすシーケンスは、どうするのかを考えます。
プロセッサの動作は、以下を繰返すだけです。
- 路面状況入手
- エンコーダから回転数入手
- 取得した情報から、モータに与えるDUTY比計算
- モータドライバのカウンタに、DUTY比を設定
- 1に戻る
上の動作を、ニモニックで記述します。
路面状況入手
路面状況は、カメラ相当のセンサーが入手し
レジスタSRに格納されています。
MOV命令でSRレジスタの内容を、WorkingRegisterに
転送すれば、路面状況の入手は完了です。
インストラクションは、以下。
MOV WA,SR
WorkingRegisterから、メモリのどこかにコピーして
おけばよいので、それを付加します。
MOV WA,SR
MVI DPR,100
ST WA,DPR
INC DPR
エンコーダから回転数入手
左右のエンコーダカウント値は、2つのレジスタLRE、RREに
格納されているので、WorkingRegisterに転送し、メモリの
どこかに保存しておきます。
動作を命令に変換すると、以下。
MOV WB,LRE
ST WB,DPR
INC DPR
MOV WB,RRE
ST WB,DPR
モータに与えるDUTY比計算
路面状況はWorkingRegisterに保存されているので
EQ命令を利用して、どういう値になっているかを
知り、対応したDUTY比を3つのモータレジスタに
転送します。
DUTY比設定は以下。
MVI WB,95
MOV SMR,WB
MVI WB,25
MOV LMR,WB
MVI WB,35
MOV RMR,WB
JMP 1023
センサー値を比較して、その値と一致したときと
異なるときの処理は、単純です。
EQ WA,24
JZE 100
EQ WA,3
JZE 120
分岐先で、DUTY比設定したなら、同じシーケンスを
繰り返すだけです。
JMP 0
NORMAL、CRANK、LANE_CHANGEの処理は、状態を
表現してメモリの中にいれます。情報を出入れ
するメモリは、DataPointerRegisterにアドレス
を与えて、LD、ST命令を使うだけで操作できます。
また、状態判定はEQ命令を使えば充分です。
プログラムは、EEPROMの中に格納して動かします。
FPGAの中に簡易プロセッサを入れるので、電源を入れたとき
EEPROMの内容をリードし、内部SRAMに転換します。
手持ちのEEPROMのうち、IICバスでないものを利用します。
IICバスでは、データ交換に1ピンを使うので、ピン利用の
効率はよいですが、アドレスを与えてからデータを受取る
ために、一度ピンの入出力を変更するのが煩雑です。
入力、出力のピン方向が確定しているデバイスを使います。
目次
前
次