microasm.awk

download

# Poniżej zamieszczam skrypt napisany przeze mnie na drugim roku studiów
# w ramach laboratoriów z techniki cyfrowej. Należało zaprojektować
# system cyfrowy oparty na mikrokodzie. Studenci dostali specyfikację
# INTEL HEX formatu danych do wczytania do epromu. Do wyliczania
# korzystali z kalkulatorów.
# 
# Ponieważ jestem programistą z zamiłowania, to uznałem, że zadanie
# powinna być wsparte przez komputer. Napisałem mikroasembler, który
# automatycznie allokował adresy i rejestry oraz generował format potrzebny
# do programatora (zliczał także sumę kontrolną). Pozwoliło mi to na
# wygodne zaprojektowanie algorytmu.
# 
# Składnia wejściowa dla asemblera:
# 
#       BEGIN:  !s      A.LE B.LE L1.LE W.CE    BEGIN
#       L01:    B.Z                             EL01
#               !B[0]                           EIF01
#               0       W.LE                    -
#       EIF01:  1       A.SE B.SE               L01
#       EL01:   0       L1.EN M.S               -
#       L03:    W<L1                            EL03
#               1       W.LE M.S                L03
#       EL03:   s       r                       EL03
#               1                               BEGIN
# 
# Wynik działania skryptu został wygenerowany zdalnie na maszynie
# UNIX-owej (na Macintoshach nie mieliśmy shella ani narzędzia awk):
# 
#     :03000000F000000D
#     :03000100052000D7
#     :03000200044000B7
#     :0300030000610099
#     :0300040001860072
#     :0300050000780080
#     :0300060008A0004F
#     :030007000691005F
#     :0300080008E0000D
#     :0300090000800074
#     :00000001FF
# 
# Projekt oczywiście zamknąłem maksymalną liczbą punktów.
# Poniżej treść skryptu.

#!/bin/awk -f

# program przetwarza wsadowo asembler mikrokodu i wypisuje skoplilowana 
# tablice, ktora mozna wpisac do RAM
#
# postac:
# etykieta,predykat,akcja akcja ...,skok
# dozwolone komanetarze with #
# puste linie ignorowane

# pobranie bitu o numerze b ze slowa a
function bit(a,b,    tmp)
{
    tmp = int(a/(2^b));
    return (tmp==int(tmp/2)*2)?0:1
}
function error(co)
{
    print co
    exit(1);
}
function set_bit(a,nr)
{
    if(bit(a,nr)) return a
    a+=2^nr
    return a
}
function rights(a,i,ile)
{
    return substr(a,length(a)-i,ile)
}


BEGIN{
    # ostatni nie uzywany rekord
    PC=0    
    #delete tab    # tablica danych, gdzie wczytujemy program
    #delete labels    # tablica labels["LAB"]=PC

    #delete pred    # tablica predykatow pred["a"]=n_pred++
    #delete pred_nr    # pred_nr[n_pred++]="!a"
    n_pred=0    # wolny numer predykatu
    
    #delete data    # tablica danych zapisanych binarnie
    data_ile=0    # ile bitow na wiersz ?
    
    # pola w rekordzie tablicy
    LABEL=1
    PRED=2
    ACTION=3
    JUMP=4
    
    # tablica wyjsc postaci wyj["a3"]=3
    # wartosc to offset bitu w slowie sterowania Y
    #delete wyj
    #delete wyj_nr
    n_wyj=0        # wolna wartosc do przydzialu
}



/^#/ || ($0 ~ /^[\t ]*$/){
    next
}

function add_predicate(p        ,i)
{
    if(pred[p]!="") return pred[p]
    pred[p]=n_pred
    pred_nr[n_pred]=p
    return n_pred++
}

{
    n=1;
    ile=NF
    split($0,A)


    #print
    
    # label
    # print rights(A[n],0,1)
     if(rights(A[n],0,1)==":")
    {
        tab[PC,LABEL] = substr(A[n],1,length(A[n])-1)
        labels[tab[PC,LABEL]] = PC
        n++
    }
    
    # predicate
    tab[PC,PRED]=add_predicate(A[n])
    n++
    
    # operacje
    maska=0
    for(i=n;i<=ile-1;i++)
    {
        nr = wyj[A[i]]
        if(nr=="")
        {
            nr = wyj[A[i]] = n_wyj++
            wyj_nr[nr]=A[i]
        }
        # nr zawiera aktualny numer
        maska = set_bit(maska,nr)
    }
    tab[PC,ACTION] = maska
    
    # skok-gdzie
    tab[PC,JUMP] = A[ile]
    
    PC++
}

function find_label(s            ,code)
{
    if(s=="-") return 0
    code = labels[s]
    if(code=="")
    {
        printf("error: can't find label %s in code\n",s)
    }
    return code
}

function compile(        code)
{
    for(i=0;i<PC;i++)
    {
        code=find_label(tab[i,JUMP])
        tab[i,JUMP] = code
    }
}
function log2(x        ,licz)
{
    licz=0;
    while(x)
    {
        x=int(x/2)
        licz++
    }
    return licz
}
function decorate()
{
    printf("*** ");
}
function show_tables(        i,ile)
{
    print ""
    ile=log2(n_pred)-1
    decorate()
    printf "PREDICATS (%d bits: %d..%d):\n",
        ile+1,
        ile_jump+ile_act+ile_pred-1 ,ile_jump+ile_act
        
        
    for(i=0;i<n_pred;i++)
    {
        printf("%s\t= ",pred_nr[i])
        out_bin(i,ile)
        
        printf "\n"
    }
    decorate()
    printf "OUTPUTS (%d bits):\n",n_wyj
    for(i=0;i<n_wyj;i++)
    {
        printf("%s\t= %d",wyj_nr[i],i)
        printf(" (%d)\n",i+ile_jump);
    }
}
function out_bin(a,max            ,n)
{
    for(n=max;n>-1;n--)
        if(bit(a,n)) printf("1")
        else printf("0")
}
function out_hex(a,ile)
{
    while(ile)
    {
        printf( "%X",int(a/(16^(ile-1)))%16 );
        ile--
    }
}
function show_binary(        pc,i)
{
    print ""
    
    
    for(pc=0;pc<PC;pc++)
    {
        out_bin(tab[pc,PRED],ile_pred-1)
        #printf(" ")
        out_bin(tab[pc,ACTION],ile_act-1)
        #printf(" ")
        out_bin(tab[pc,JUMP],ile_jump-1)
        printf("\n")
    }
}
function show_intelhex(pc,
i,ile_pred,ile_act,ile_jump,a,p,bytes,n,kod,ile)
{
    print ""
    ile_pred = log2(n_pred)
    ile_act = n_wyj
    ile_jump = log2(PC-1)
    ile = ile_pred+ile_act+ile_jump
    
    
    if(ile<=8) bytes=1
    else if(ile<=16) bytes=2
    else if(ile<=24) bytes=3
    else if(ile<=32) bytes=4
    else error("too many data bytes" )
    print ile,"bits used in program,","->",bytes,"bytes for code"
    
    for(pc=0;pc<PC;pc++)
    {
        a=0
        sum=0;

        
        printf(":0%d",bytes)
        sum+=bytes

        out_hex(pc,4)
        sum+=int(pc/256)
        sum+=pc%256

        # kod
        out_hex(0,2)
        
        
        a+=(tab[pc,PRED]*2^(ile_jump + ile_act))
        a+=(tab[pc,ACTION]*2^(ile_jump))
        a+=(tab[pc,JUMP]*2^(0))
        
        int_table[pc]=a;

        # wypisanie zawartosci pamieci
        for(n=0;n<bytes;n++)
        {
            out_hex(a/(256^n),2)
        }
        for(n=0;n<bytes;n++)
        {
            sum+=int(a/(256^n))
        }
        sum=sum%256
        out_hex((256-sum)%256,2)
        
        
        printf("\n")
        
    }
    print ":00000001FF"
}
function show_int()
{
    print ""
    for(pc=0;pc<PC;pc++)
    {
        print int_table[pc]
    }
}

END{
    compile()

    ile_pred = log2(n_pred)
    ile_act = n_wyj
    ile_jump = log2(PC-1)

    show_tables()
    show_binary()
    show_intelhex()
    show_int()

}

(...) Nie ma bowiem łatwych odpowiedzi. Nie istnieje nic takiego jak najlepsze rozwiązanie - zarówno jeśli chodzi o narzędzia, jak i języki czy systemy operacyjne. Są jedynie systemy, które mogą być bardziej odpowiednie w konkretnych okolicznościach.

I tu właśnie do gry wchodzi pragmatyzm. Nie należy przywiązywać się do żadnej określonej metody, ale mieć na tyle rozległą wiedzę i doświadczenie, by w danej sytuacji wybrać dobre rozwiązanie. (...)

Andrew Hunt, David Thomas "Pragmatyczny Programista"