ぱらぱらめくる『クヌース本1』

  • 64bit マシン
    • 2進で64桁
    • 16進法では4ビット使う
    • 64ビットは16進数(0,1,...,9,a,b,...,f)が16 \times 4 =64で16個並ぶ
# 64桁の01の数値列
a <- sample(0:1,64,replace =TRUE)
# 4桁の01の数値列を0,1,2,...fに対応づける
b <- as.matrix(expand.grid(rep(list(0:1),4)))
b <- b[,4:1]
d <- c(as.character(0:9),letters[1:6])
# 2進64桁を16進16桁に直す
chage64to16<- function(a){
	b <- as.matrix(expand.grid(rep(list(0:1),4)))
	b <- b[,4:1]
	d <- c(as.character(0:9),letters[1:6])
	n <- length(a)%/%4
	ret <- rep(0,n)
	for(i in 1:n){
		tmp <- apply((t(b) - a[(1+4*(i-1)):(4*i)]==0),2,prod)
		ret[i] <- d[which(tmp==1)]
	}
	ret
}
chage64to16(a)
a
> chage64to16(a)
 [1] "a" "6" "8" "c" "b" "c" "e" "a" "0" "e" "6" "4" "1" "4" "e" "0"
> 
> a
 [1] 1 0 1 0 0 1 1 0 1 0 0 0 1 1 0 0 1 0 1 1 1 1 0 0 1 1 1 0 1 0 1 0 0 0 0 0 1 1 1 0 0
[42] 1 1 0 0 1 0 0 0 0 0 1 0 1 0 0 1 1 1 0 0 0 0 0
  • 文字コードとバイト
    • 4ビット→16進数1桁
    • 8ビット→16進数2桁→1バイト
    • 16ビット→16進数4桁→Unicode UTF-16文字コード→2バイト→1ワイド(wyde)
    • 32ビット→16進数8桁→4バイト→2ワイド→1テトラ
    • 64ビット→16進数16桁→8バイト→4ワイド→2テトラ→1オクタ
  • 非負の整数と正負の整数を表す
seisuu <- function(a,negative =FALSE){
	if(negative){
		if(a[1] ==1){
			sum(a[2:length(a)] * 2^((length(a)-2):0))-2^(length(a)-1)
		}else{
			sum(a[2:length(a)] * 2^((length(a)-2):0))
		}
		
	}else{
		sum(a*2^((length(a)-1):0))
	}
}

seisuu(rep(1,8))
seisuu(rep(1,8),negative=TRUE)

b <- as.matrix(expand.grid(rep(list(0:1),4)))
b <- b[,4:1]
b

for(i in 1:length(b[,1])){
	print(seisuu(b[i,]))
}
for(i in 1:length(b[,1])){
	print(seisuu(b[i,],negative=TRUE))
}
> b
      Var4 Var3 Var2 Var1
 [1,]    0    0    0    0
 [2,]    0    0    0    1
 [3,]    0    0    1    0
 [4,]    0    0    1    1
 [5,]    0    1    0    0
 [6,]    0    1    0    1
 [7,]    0    1    1    0
 [8,]    0    1    1    1
 [9,]    1    0    0    0
[10,]    1    0    0    1
[11,]    1    0    1    0
[12,]    1    0    1    1
[13,]    1    1    0    0
[14,]    1    1    0    1
[15,]    1    1    1    0
[16,]    1    1    1    1
> for(i in 1:length(b[,1])){
+ print(seisuu(b[i,]))
+ }
[1] 0
[1] 1
[1] 2
[1] 3
[1] 4
[1] 5
[1] 6
[1] 7
[1] 8
[1] 9
[1] 10
[1] 11
[1] 12
[1] 13
[1] 14
[1] 15
> for(i in 1:length(b[,1])){
+ print(seisuu(b[i,],negative=TRUE))
+ }
[1] 0
[1] 1
[1] 2
[1] 3
[1] 4
[1] 5
[1] 6
[1] 7
[1] -8
[1] -7
[1] -6
[1] -5
[1] -4
[1] -3
[1] -2
[1] -1
  • メモリとレジスタ
    • メモリ
      • M[0],...,M[2^64-1]個のメモリセルからなるメモリ。全部で2^{64}バイトのメモリに相当する
    • レジスタ
    • メモリのグルーピング
      • (M[0],M[1]),...,(M[2k],M[2k+1]),...と組にして、それぞれに1ワイドを対応させる(2^{63}個のワイドができる
        • M_2[0] = M_2[1]=M_1[0]M_1[1],M_2[2k] = M_2[2k+1] = M_1[2k]M[2k+1]
      • となり合う4個を束ねて2^{62}個のテトラができる
        • M_4\{4k]=M_4[4k+1]=M_4[4k+2]=M_4[4k+3] = M_1[4k]M_1[4k+1]M_1[4k+2]M_1[4k+3]
      • となり合う8個を束ねて2^{61}個のオクタができる
        • M_8[8k]=M_8[4k+1]=...M_8[8k+7] = M_1[8k]M_1[8k+1]...M_1[8k+7]
      • M_t[x]M_1[x]を含むワイド・テトラ・オクタとする
      • x < 0, x \ge 2^{64}の場合はM_t[x] = M_t[x \text{mod} 2^{64}]
p <- 10
M <- sample(0:1,2^p,replace=TRUE)
t <- 8 # オクタ

x <- sample(0:(2^p/t),1)
y <- floor(x/t)

M8 <- M[(t*y):(t*y+t-1)]
x
y
M[(x-t):(x+t)]
M8
> x
[1] 60
> y
[1] 7
> M[(x-t):(x+t)]
 [1] 1 0 1 1 0 1 0 1 0 0 1 0 0 0 1 1 1
> M8
[1] 0 1 0 1 0 0 1 0
> M[56]
[1] 0
> M[56:63]
[1] 0 1 0 1 0 0 1 0
  • コマンド
    • メモリに入れる
    • 1コマンドは1テトラバイト
    • 1テトラバイトを構成する4バイトはそれぞれOP,X,Y,Zに対応する
    • OPはオペレーションコード
    • X,Y,Zはオペランド
  • 命令(256種類)
    • 命令は分類される
    • ロードとストア
      • ロードとストア
        • ロードはメモリからレジスタへの書きだし、ストアはレジスタからメモリへの書きこみ
        • 書きだし・書き込みにあたって、バイト・ワイド・テトラ・オクタの4つの長さで別々にできるようにし、また、符号付きか符号なしか、(バイト・ワイド・テトラだと桁に余裕があるが)右詰にするか左詰にするか、などで、それぞれ異なる命令として決めてある
    • 数値演算命令
      • レジスタの値とレジスタの値をとって演算結果を納める
      • 加減乗除、剰余、加算は少しバリエーションあり、符号反転、左右へシフト、大小比較
    • 条件命令
      • レジスタの値の正負ゼロを判定して、その判定結果によって、納める値を変える
    • ビットごと命令
      • 64個のビットのビットごと演算(ブール演算)(参考)
    • バイトごと・ワイドごと・テトラごと・オクタごと命令
      • ビットごとの代わりにバイト・ワイド・テトラ・オクタごとでも
      • オクタバイトは8x8のブール行列と見ることもできる
    • 浮動小数点演算命令
    • 即値命令
      • 良く使う「値(1やバイト・ワイド…などでの桁変更、真偽値など)」の扱いは命令として使えるようにしてある
      • メモリへのアクセスを発生させないで命令が実行できる
    • ジャンプと分岐の命令
      • 指定がないときの命令の実行順は(OP1,X1,Y1,Z1),(OP2,X2,Y2,Z2),...のような並び順でOP1,OP2の命令がそれぞれのオペランドに対して行われるが、それを変えたいときに使う
      • 分岐処理は、条件判定をしてから分岐先のことを考えるやり方と、条件判定をする前から、分岐するものと見込んで準備しておく(外れたら、見込み作業は捨てる)方法がある。分岐予測(Wiki)という
      • これに対応して、予測ありの分岐と予測なしの分岐の2通りの命令が準備されている
    • サブルーチンコール命令
    • システムとのやりとりのための命令
    • 割り込み命令
    • 全256コマンド表はこちら
      • この表の見方は:表の行の"nx"の"n"が16進数で、"x"の方に列の方の値を対応づける。ただし列は8列になっていて、2段で8x2=16進数に対応。上段は0,1,...,7で、下段だったら、8,9,a,...,f
      • したがって、左上隅のTRAPは"00"、その隣のFCMPは"01"、#Exの行の#3の列の上段はSETLだが、これは、"E3"で、その下のORLは"EB"
    • 命令は専用レジスタを使って処理をする
  • アセンブラ
  • サブルーチンとコルーチン
  • インタープリタ