2021年11月3日水曜日

Perlで加算回路。

いまさらな加算回路を、いまさらのPerlで書いてみた。

普通に計算すりゃいいじゃねーか!って内容なわけだけど、脳みそのリハビリを兼ねてZ80用のバイナリコードをニーモニックに変換してたついでに加算回路を記述してみた。
Perlなのは、使用環境がVSCode+WSL2:Ubuntuだったので、インストール作業なし、バージョン差異なし、コンパイル作業なし、文字列の取り扱いが楽って理由で変換コード書く際に使っていたから。

で、コードについてもメモしとくと、Z80のALUは、4bitで演算してるので半加算器、全加算器、それらを組みわあせた4bit加算器となっている。
#
# HALF ADDER
sub half_adder {
    return hex($_[0])^hex($_[1]), hex($_[0])&hex($_[1]);
}
#
# FULL ADDER
sub full_adder {
    my($BIT, $CARRY1 ) = half_adder($_[0],$_[1]);
    my($BIT, $CARRY2 ) = half_adder($BIT,$_[2]);
    return $BIT, ($CARRY1|$CARRY2);
}
#
# 4bit ADDER
sub ADD_4bit {
    my @BIT; my $CARRY = 0;
    my @BIT1 = sprintf("%04b",hex($_[0])) =~ /.{1}/g;
    my @BIT2 = sprintf("%04b",hex($_[1])) =~ /.{1}/g;
    if ( $_[2] ) { $CARRY = $_[2] }
    for ( my $i = 3; $i >= 0; $i-- ) {
        ($BIT[$i], $CARRY) = full_adder($BIT1[$i],$BIT2[$i],$CARRY);
    }
    return join('',@BIT), $CARRY;
}

以下は、8bitと16bitの加減算用サブルーチン。
$C、$Hは、元コードで宣言済みのフラグレジスタのキャリーフラグとハーフキャリーフラグを指す変数。ここでは何も宣言してないので意味ないんだけど。
実際のコードでは、まとめて一つの関数にしてあるのだけど、コメントアウトしても場所とって邪魔なので、こちらに保管。
sub ADD_8bit {
    my @BITS;
    if ( !$_[2] ) { $C = 0; }
    ($BITS[1], $H) = ADD_4bit(substr($_[0],1,1),substr($_[1],1,1),$C);
    ($BITS[0], $C) = ADD_4bit(substr($_[0],0,1),substr($_[1],0,1),$H);
    return sprintf("%02X",oct("0b".join("",@BITS)));
}
 
sub ADD_16bit {
    my @BITS;
    if ( !$_[2] ) { $C = 0; }
    ($BITS[3], $H) = ADD_4bit(substr($_[0],3,1),substr($_[1],3,1),$C);
    ($BITS[2], $C) = ADD_4bit(substr($_[0],2,1),substr($_[1],2,1),$H);
    ($BITS[1], $H) = ADD_4bit(substr($_[0],1,1),substr($_[1],1,1),$C);
    ($BITS[0], $C) = ADD_4bit(substr($_[0],0,1),substr($_[1],0,1),$H);
    return sprintf("%04X",oct("0b".join("",@BITS)));
}

sub SUB_8bit {
    $C = 1;
    my @BITS;
    my $NOT_BIT = sprintf("%02X",oct("0b".substr(sprintf("%b",~hex($_[1])),-8,8)));
    ($BITS[1], $H) = ADD_4bit(substr($_[0],1,1),substr($NOT_BIT,1,1),$C);
    ($BITS[0], $C) = ADD_4bit(substr($_[0],0,1),substr($NOT_BIT,0,1),$H);
    return sprintf("%02X",oct("0b".join("",@BITS)));
}
 
sub SUB_16bit {
    $C = 1;
    my @BITS;
    my $NOT_BIT = sprintf("%04X",oct("0b".substr(sprintf("%016b",~hex($_[1])),-16,16)));
    ($BITS[3], $H) = ADD_4bit(substr($_[0],3,1),substr($NOT_BIT,3,1),$C);
    ($BITS[2], $C) = ADD_4bit(substr($_[0],2,1),substr($NOT_BIT,2,1),$H);
    ($BITS[1], $H) = ADD_4bit(substr($_[0],1,1),substr($NOT_BIT,1,1),$C);
    ($BITS[0], $C) = ADD_4bit(substr($_[0],0,1),substr($NOT_BIT,0,1),$H);
    return sprintf("%04X",oct("0b".join("",@BITS)));
}

0 件のコメント:

コメントを投稿