0

I'll try to keep the preamble short.

Yes, this is essentially "help me with my college homework", but I am super stuck on this (we're on hour 10, here).

Objective - write an assembly program that takes a character as input and outputs that character as uppercase.

I have reviewed the textbook, emailed my professor (response pending, but I'm like a dog with a bone - I can't leave this homework alone until it's done), and tried every possible permutation that I can think of. This example is almost identical to an example included in the pep/8 help (fig 6.34 I think? Whichever one is the boolean translation example) except that the characters are stored in #1cs instead of #2d.

Anyways, the core of the issue is that any time I try to access ch2 within the uprcse function, the program grabs the return address off the stack instead. From what I can tell I'm doing this the same as the examples are, and unfortunately it's impossible to find good online resources of the pep/8 (thanks, Python, for calling your standards pep8...) so I am limited in how furiously I can google.

Please view my code below and feel free to run it through your own pep8 and tell me what the heck I am doing wrong.

Please don't feel the need to do the stack overflow thing and point out every tiny flaw in my code - I know this could branch differently within the uprcse function. I mean, you can give little corrections if that's how you get your kicks / karma but... eh.

         BR      main          
;
;******* char uppercase(char ch)
retVal:  .EQUATE 2           ;returned value #1c
ch2:     .EQUATE 1           ;formal parameter #1c
uprcse:  LDBYTEA ch2,sx    ;if ((ch >= 'a')
if:      CPA     'a',i         
         BRLT    else        
         LDBYTEA ch2,s         ;   && (a <= 'z'))
         CPA     'z',i     
         BRGT    else        
then:    LDBYTEA ch2,s      ;   return changed
         SUBA    'a',i
         ADDA    'A',i
         STBYTEA retVal,s    
         RET0                
else:    LDBYTEA ch2,d     ;   return unchanged
         STBYTEA retVal,s    
         RET0         

;******* main ()
ch:     .EQUATE  0           ;local variable #1c
main:    SUBSP   1,i         ;allocate #ch 
         STRO    msg0,d         ;cout << "Enter character, Zack" << endl
         CHARI   ch,s       ;cin >> ch  
         LDBYTEA ch,s        
         STBYTEA     -2,s        ;store the value of age
         SUBSP   2,i         ;push #retVal #ch2 
         CALL    uprcse      ;ch = (uppercase(ch)
         ADDSP   2,i         ;pop #ch2 #retVal 
         LDBYTEA -1,s        ;load retVal
         STBYTEA     ch,s
         CHARO   ch,s          ;cout << ch << endl
         CHARO   '\n',i        
         ADDSP   1,i         ;deallocate #ch 
         STOP                
msg0:    .ASCII "Enter character\n\x00"
         .END                  
  • What's wrong? Also, did you know you can flip a bit to go from upper to lower case? – aghast Mar 22 '17 at 01:38
  • If ch2 is equated to 1, is your return address 1 byte? What I found suggests that there is a 64k address space, so you should probably define that to 2. – aghast Mar 22 '17 at 01:55
  • Uh... google ' "pep/8" -python '? – philipxy Mar 22 '17 at 02:17
  • What do "try to access ch2" and "grabs the return address off the stack" mean? Where is "the pep/8 help"? Please make the effort explain clearly. Please read & act on [mcve]. – philipxy Mar 22 '17 at 02:19
  • He's defined ch2 to use as a stack-relative offset, but didn't allow enough room for the return address, I think. – aghast Mar 22 '17 at 02:21
  • >What do "try to access ch2" and "grabs the return address off the stack" mean? Where is "the pep/8 help"? When LDBYTEA ch2,s runs, it instead loads the first byte of RetAddr off of the stack rather than the value of ch2. The pep/8 help is the help included with the pep/8 system. – Monica Apologists Get Out Mar 22 '17 at 10:56
  • >He's defined ch2 to use as a stack-relative offset, but didn't allow enough room for the return address, Is correct, I think, but I don't know what I am doing wrong or how to change it - my program as above is almost identical to an example given by the textbook (Computer Systems 4e by Warford) except changed for single bytes. Clearly I am missing a step in that modification. – Monica Apologists Get Out Mar 22 '17 at 10:56

2 Answers2

0

I'm going to do that stackoverflow thing. Sorry.

In your main, after reading the character, you make a small error:

         STBYTEA -2,s        ;store the value of age
         SUBSP   2,i         ;push #retVal #ch2 

You store to SP-2, and then subtract 2 from SP. This leaves your code vulnerable to a rare problem caused by interrupts, where an interrupt could fire (writing data on the bottom of the stack) and then return, having corrupted your data.

When you're writing assembly, you should always do your frame adjustments prior to actually using the memory you are "allocating."

In this code,

         CALL    uprcse      ;ch = (uppercase(ch)
         ADDSP   2,i         ;pop #ch2 #retVal 
         LDBYTEA -1,s        ;load retVal
         STBYTEA     ch,s

You do the reverse, adding to SP before accessing your results. The same theory applies. Pull the data out before you deallocate.

    CALL     uprcse
    LDBYTEA  0,s       ; 0 because now return value is above SP
    STBYTEA  ch,s
    ADDSP    2,i

In your uprcse function, I think you have a simple arithmetic error:

;******* char uppercase(char ch)
retVal:  .EQUATE 2           ;returned value #1c
ch2:     .EQUATE 1           ;formal parameter #1c
uprcse:  LDBYTEA ch2,sx    ;if ((ch >= 'a')

In this code, you define ch2 to be SP+1. I think you should be using +2. Further, you can simplify your life by adjusting the stack frame to include local storage immediately:

ch:      .EQUATE  4       ; formal parameter `ch` #1c
;old-sp  .EQUATE  2       ; 2 bytes for return address
temp     .EQUATE  0       ; Not actually used, just to show locals

uprcse:  SUBSP    2,i     ; Adjust stack frame for locals
         LDA      ch,s

Note that on most computers (not all!) the "compare" operation is a synonym for "subtract." Sometimes it is "subtract but don't store". Other times it is "subtract and be sure to set the flags". But in general, subtract and compare are frequently related. You can use this to your advantage:

         CPA    'a',i    
         BRLT   else

At this point, the A register contains ch-'a'. Instead of reloading A and comparing to 'z', you could compare against 'z'-'a' (25):

         CPA   25,i
         BRGT  else

Finally, ASCII was designed (on purpose!) with 32 characters between upper and lower case letters. This makes lowercase just a ch+32 away. Or you could set the 32 bit. Similarly, to go from lower to upper, just subtract 32, or clear the 32 bit.

         LDBYTEA ch2,s
         SUB     32,i
         STBYTEA ch2,s
else:
         RET2           ; Remember temp?

In this case, I assume that you can re-use the storage of your ch2 formal parameter as the return result. Especially since the result will be the same as ch2 unless it's lower case, in which case we adjust it.

aghast
  • 14,785
  • 3
  • 24
  • 56
0

all! Follow up to this post.

I spoke with the professor and he clarified my mistakes -

The error I was making was that I did not set the right values in .EQUATE for the uppercase function. I should have been using 2 and 3 as values rather than 1 and 2. I also needed to clear the accumulator using LDA 0x0000,i at the start of the uppercase function. I will post the entire working source code when this assignment is closed and graded.