Link to home
Start Free TrialLog in
Avatar of xxaznqboyxx
xxaznqboyxx

asked on

Assembly language: converting ASCII to Binary and Binary to ASCII

Hi,

I'm very new with Assembly Language.  I am to write an assembly program that will implement a 16-bit calculator that add and subtract.  I will need to check to see if the ASCII characters are valid.... (0-9).  All inputs should be echoed to the output.  If it is not  a valid ASCII then the output will output a message "ERROR".  

The operation will be off the form:
-2+4+10-33=

Once it reads in an equal then it will output the solution.  I am completely lost as what to do.  I've written a input and output routine which I don't even know if it is correct.  Please help me with code examples, especially the converting and adding/subtracting.

/INPUT ROUTINE
CIF,      SKI        /Check input flag
      BUN CIF  /Flag=0, check again
      INP        /Flag=1, input
      OUT        /Print Character
      STA CHR  /Store Character
      HLT
CHR,       HEX 0001

/OUTPUT ROUTINE
      LDA CHR  /Load char in AC
COF,      SKO        /Check output flag
      BUN COF  /Flag=0, check again
      OUT        /Flag=1, output
      HLT
CHR,      HEX 0057 /Character is "W"

Thanks.
Avatar of ADSLMark
ADSLMark

I am completely unfamiliar with Basic Computer Assembly, but i guess i know where you got your example ;-)

http://calab.kaist.ac.kr/~hyoon/courses/cs311/cs311_2006/Ch6.ppt

So let's see.. this sounds like homework.. anyway.. my idea would be:

Make a loop until we come along a '='
Read a digit or '+' or '-'
Write read character
Compute number and/or answer

So in pseudo code:

dig = true;
ans = 0;
cur = 0;
neg = false;

do
{
    c = read();
    if(c >= '0' && c <= '9')
    {
        cur = cur*10 + (c - '0');
        dig = false;
    }
    else if(c == '+' && !dig)
    {
        if(negate) cur = -cur;
        ans += cur
        cur = 0;
        neg = false;
        dig = true;
    }
    else if(c == '-' && !dig)
    {
        if(neg)
        {
            cur = -cur;
            neg = false;
        }
        ans += cur;
        cur = 0;
        neg = true;
        dig = true;
    }
    else
    {
        write("ERROR");
    }
}
while(c != '=')

write(ans);

Now translating this to your assembly code.. I did most of the work and i did not run a test (i have no idea how), but it's getting late and you can do the rest yourself, i think not so difficult. ENJOY!

         ORG 100

         /c = read();
LOOP,    SKI          /check for character
         BUN LOOP     /loop while no character
         INP          /read
         OUT          /write
         STA c        /c = <input>

         /if(c >= '0')
CZERO,   LDA zero     /AC = zero
         CMA          /AC = -AC
         ADD c        /AC = AC + c
         INC          /AC = AC + 1
         SPA          /if(AC > 0) skip
         BUN CPLUS    /goto CPLUS
         BUN CNINE    /goto CNINE

         /if(c <= '9')
CNINE,   LDA nine     /AC = nine
         INC          /AC = AC + 1
         CMA          /AC = -AC
         ADD c        /AC = AC + c
         SNA          /if(AC < 0) skip
         BUN CPLUS    /goto CPLUS
         BUN LDIGIT   /goto LDIGIT

         /if(c == '+')
CPLUS,   LDA plus     /AC = plus
         CMA          /AC = -AC
         ADD c        /AC = AC + c
         SZA          /if(AC == 0) skip
         BUN CMINUS   /goto CMINUS
         BUN LPLUS    /goto LPLUS

         /if(c == '-')
CMINUS,  LDA minus    /AC = minus
         CMA          /AC = -AC
         ADD c        /AC = AC + c
         SZA          /if(AC == 0) skip
         BUN ERROR    /goto ERROR

         /c = c - '0'
LDIGIT,  LDA zero     /AC = zero
         CMA          /AC = -AC
         ADD c        /AC = AC + c
         STA c        /c = AC

         /counter = -10
         LDA tentime
         STA counter

         /AC = cur * 10;
         LDA cur      /AC = cur
MUL,     ADD cur      /AC = AC + cur
         ISZ counter  /counter++; if(counter == 0) skip
         BUN MUL      /goto MUL

         /cur = AC + c;
         ADD c
         STA cur

         /dig = false;
         LDA false
         STA dig      /dig = false
         BUN CHECK    /goto CHECK

         /pretty much similar to the minus case.
LPLUS,   ...
         BUN CHECK    /goto CHECK

         /if(neg == true)
LMINUS,  LDA neg      /AC = neg
         SZA          /if(AC == true) skip
         BUN NONEG    /goto NONEG

         /cur = -cur;
         LDA cur      /AC = cur
         CMA cur      /AC = -AC
         STA cur      /cur = AC

         /ans += cur;
NONEG,   LDA cur      /AC = cur
         ADD ans      /AC = AC + ans
         STA ans      /ans = AC

         /cur = 0;
         LDA true     /AC = true
         STA cur      /cur = AC

         /neg = true;
         STA neg      /neg = AC

         /dig = true;
         STA dig      /dig = AC

         BUN CHECK    /goto CHECK

         /write("ERROR");
ERROR,   ...

         /while(c != '=')
CHECK,   LDA equal    /AC = equal
         CMA          /AC = -AC
         ADD c        /AC = AC + c
         SZA          /if(AC == 0) skip
         BUN LOOP     /goto LOOP

         /write(ans);
         ...

         /halt();
         HLT

neg,     DEC 1        /neg = false
dig,     DEC 0        /dig = true
ans,     DEC 0        /ans = 0
cur,     DEC 0        /cur = 0
c,       DEC 0        /c = 0
true     DEC 0        /true = 0
false    DEC 1        /false = 1
tentime, DEC -10      /tentime = -10
counter, HEX 0        /counter = 0
zero,    HEX 30       /zero = '0'
nine,    HEX 39       /nine = '9'
plus,    HEX 2B       /plus = '+'
minus,   HEX 2D       /minus = '-'
equal,   HEX 3D       /equal = '='
         END

I hope it works, at least it's close to a working version.

Mark
Avatar of xxaznqboyxx

ASKER

Hi Mark,

I changed the values that you left blank and tested it out.  For some reason it kept branching to the error message.  It is not recognizing the signs, +/- .   Everytime it encounters the sign it will branch to the error routine.  The routine looks right... you load the + sign which is the value 2B in hex, then complement it and add to the input and it should equal to zero and shall skip if it is zero.  For some reason it does not skip.  Can you see anything wrong??  I have an assembler here to run the code and test.  You just need to compile and execute it.  Then enter the value in the Input textfield.  If you could give me your e-mail address I can mail it to you.  Thanks again.

       ORG 100

         /c = read();
LOOP,    SKI          /check for character
         BUN LOOP     /loop while no character
         INP          /read
         OUT          /write
         STA c        /c = <input>

         /if(c >= '0')
CZERO,   LDA zero     /AC = zero
         CMA          /AC = -AC
         ADD c        /AC = AC + c
         INC          /AC = AC + 1
         SPA          /if(AC > 0) skip
         BUN CPLUS    /goto CPLUS
         BUN CNINE    /goto CNINE

         /if(c <= '9')
CNINE,   LDA nine     /AC = nine
         INC          /AC = AC + 1
         CMA          /AC = -AC
         ADD c        /AC = AC + c
         SNA          /if(AC < 0) skip
         BUN CPLUS    /goto CPLUS
         BUN LDIGIT   /goto LDIGIT

         /if(c == '+')
CPLUS,   LDA plus     /AC = plus
         CMA          /AC = -AC
         ADD c        /AC = AC + c
         SZA          /if(AC == 0) skip
        BUN CMINUS   /goto CMINUS
         BUN LPLUS    /goto LPLUS

         /if(c == '-')
CMINUS,  LDA minus    /AC = minus
         CMA          /AC = -AC
         ADD c        /AC = AC + c
         SZA          /if(AC == 0) skip
         BUN ERROR    /goto ERROR

         /c = c - '0'
LDIGIT,  LDA zero     /AC = zero
         CMA          /AC = -AC
         ADD c        /AC = AC + c
         STA c        /c = AC

         /counter = -10
         LDA tentime
         STA counter

         /AC = cur * 10;
         LDA cur      /AC = cur
MUL,     ADD cur      /AC = AC + cur
         ISZ counter  /counter++; if(counter == 0) skip
         BUN MUL      /goto MUL

         /cur = AC + c;
         ADD c
         STA cur

         /dig = false;
         LDA false
         STA dig      /dig = false
         BUN CHECK    /goto CHECK

         /if(neg == false)
LPLUS,   LDA neg       /AC = neg
        SZA             /if(AC == false)
        BUN NONEG       /goto NONEG

        /cur = cur;
        LDA cur       /AC = cur
        STA cur       /cur = AC

         /if(neg == true)
LMINUS,  LDA neg      /AC = neg
         SZA          /if(AC == true) skip
         BUN NONEG    /goto NONEG

         /cur = -cur;
         LDA cur      /AC = cur
         CMA cur      /AC = -AC
         STA cur      /cur = AC

         /ans += cur;
NONEG,   LDA cur      /AC = cur
         ADD ans      /AC = AC + ans
         STA ans      /ans = AC

         /cur = 0;
         LDA true     /AC = true
         STA cur      /cur = AC

         /neg = true;
         STA neg      /neg = AC

         /dig = true;
         STA dig      /dig = AC

         BUN CHECK    /goto CHECK

         /write("INPUTERR");
ERROR,   LDA letterI
        OUT
        LDA letterN
        OUT
        LDA letterP
        OUT
        LDA letterU
        OUT
        LDA letterT
        OUT
        LDA letterE
        OUT
        LDA letterR
        OUT
        LDA letterR
         OUT

        HLT

         /while(c != '=')
CHECK,   LDA equal    /AC = equal
         CMA          /AC = -AC
         ADD c        /AC = AC + c
         SZA          /if(AC == 0) skip
         BUN LOOP     /goto LOOP

         /write(ans);
        LDA ans
         OUT

         /halt();
         HLT

neg,     DEC 1        /neg = false
dig,     DEC 0        /dig = true
ans,     DEC 0        /ans = 0
cur,     DEC 0        /cur = 0
c,       DEC 0        /c = 0
true,    DEC 0        /true = 0
false,   DEC 1        /false = 1
tentime, DEC -10      /tentime = -10
counter, HEX 0        /counter = 0
zero,    HEX 30       /zero = '0'
nine,    HEX 39       /nine = '9'
plus,    HEX 2B       /plus = '+'
minus,   HEX 2D       /minus = '-'
equal,   HEX 3D       /equal = '='
letterI, HEX 49       /letterI = I
letterN, HEX 4E       /letterN = N
letterP, HEX 50       /letterP = P
letterU, HEX 55       /letterU = U
letterT, HEX 54       /letterT = T
letterE, HEX 45       /letterE = E
letterR, HEX 52       /letterR = R
         END
Hi Mark,

For some reason it is not recognizing the +/- sign.  Once I enter the +/- it branches to the ERROR routine.  Do you know why?  I mean the routine looks correct, for a plus, you would load the hex value 2B, then complement it and add it to the input.  It should equal zero and skip the minus routine... I don't know why it's not working.  I have an assembler for this basic computer if you need it, please give me your e-mail address.  Thanks.
You can adjust this:

CMINUS,  LDA minus    /AC = minus
         CMA          /AC = -AC
         ADD c        /AC = AC + c
         SZA          /if(AC == 0) skip
         BUN ERROR    /goto ERROR


to:

CMINUS,  LDA minus    /AC = minus
         CMA          /AC = -AC
         ADD c        /AC = AC + c
         SZA          /if(AC == 0) skip
         BUN ERROR    /goto ERROR
         BUN LMINUS   /goto LMINUS

Also check the value of - (0x2D), since it might be a different dash then you use on your command line.

Next, I forgot to mention, but it does not parse the unary - sign. So for example, 4+-2 is not valid, this also includes: -2+4... So, if you have to implement unary - also, then you should extend the program to remember if the digit is negative, if so, complement and add. It complicates the whole program a bit, so I left it out.

Mark
If you want me to help debug, then it might help if you could post a link to the simulator software, or sth similar..

Mark
Ok, I wrote my own little simulator.. and i noticed it worked quite well.
Sometimes the jumps are not very smart, since they all jump to the CHECK label, but you can better jump to LOOP.. Also the case:

CMINUS,  LDA minus    /AC = minus
         CMA          /AC = -AC
         ADD c        /AC = AC + c
         SZA          /if(AC == 0) skip
         BUN ERROR    /goto ERROR

should be BUN CHECK.

The idea is to make it like:
LOOP : c = read();
CZERO  : if(c>='0') goto CNINE else CPLUS
CNINE  : if(c<='9') goto LDIGIT else CPLUS
CPLUS  : if(c=='+') goto LPLUS else CMINUS
CMINUS: if(c=='-') goto LMINUS else CHECK
CHECK : if(c=='=') goto LOOP else ERROR

So you should adjust the jumps (BUNs).

Mark
I'm not sure how the IN/OUT works, but i guess you should convert the answer back to ASCII....
Mark
I made a mistake in the JUMPs (AGAIN!)

LOOP : c = read();
      : if(c=='=') goto LANS else CZERO
CZERO  : if(c>='0') goto CNINE else CPLUS
CNINE  : if(c<='9') goto LDIGIT else CPLUS
CPLUS  : if(c=='+') goto LPLUS else CMINUS
CMINUS: if(c=='-') goto LMINUS else ERROR
LDIGIT: goto LOOP
LPLUS : goto LOOP
LMINUS: goto LOOP
LANS: write(ans);

That should be correct.

Mark
ASKER CERTIFIED SOLUTION
Avatar of ADSLMark
ADSLMark

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Thanks Mark, I can see your algorithm.  I am trying to implement it on my assembler now.  I will let you know the results.