See a switch in assembly

I've changed my switch to use ranges and it looks great. With both versions, the program compiles to the same size. I'd like to see the assembly code for both versions to: 1) see if there is a deference in how it compiles and runs and 2) learn more about making assembly jump tables for AVR uCs.

I can work my way backwards using objdump if I have to, but I'm wondering if there is a way to capture the assembly code before if gets assembled into a hex file?

Here are the two versions of the switch

With ranges:

uint8_t lookup(char character) {
  switch (character) {
    case ' ':
    return B00100000;
    case '!':
    return B00100001;
    case '"':
    return B00100010;
    case '#':
    return B00100011;
    case '$':
    return B00100100;
    case '%':
    return B00100101;
    case '&':
    return B00100110;
    case '\'':
    return B00100111;
    case '{':
    return B00101000;
    case '}':
    return B00101001;
    case '*':
    return B00101010;
    case '+':
    return B00101011;
    case ',':
    return B00101100;
    case '-':
    return B00101101;
    case '.':
    return B00101110;
    case '/':
    return B00101111;

    case '0' ... '9':
    return (uint8_t)character - 18;

    case ':':
    return B00111010;
    case ';':
    return B00111011;
    case '<':
    return B00111100;
    case '=':
    return B00111101;
    case '>':
    return B00111110;
    case '?':
    return B00111111;

    case '@':
    return B01000000;

    case 'A' ... 'Z':
    return (uint8_t)character;

    case 'a' ... 'z':
    return (uint8_t)character - 32;
    
    case '(':
    return B01011011;
    case '\\':
    return B01011100;
    case ')':
    return B01011101;
    case '^':
    return B01011110;
    case '_':
    return B01011111;
  }
}

Without ranges:

uint8_t lookup(char character) {
  switch (character) {
    case ' ':
    return B00100000;
    case '!':
    return B00100001;
    case '"':
    return B00100010;
    case '#':
    return B00100011;
    case '$':
    return B00100100;
    case '%':
    return B00100101;
    case '&':
    return B00100110;
    case '\'':
    return B00100111;
    case '{':
    return B00101000;
    case '}':
    return B00101001;
    case '*':
    return B00101010;
    case '+':
    return B00101011;
    case ',':
    return B00101100;
    case '-':
    return B00101101;
    case '.':
    return B00101110;
    case '/':
    return B00101111;

    case '0':
    return B00110000;
    case '1':
    return B00110001;
    case '2':
    return B00110010;
    case '3':
    return B00110011;
    case '4':
    return B00110100;
    case '5':
    return B00110101;
    case '6':
    return B00110110;
    case '7':
    return B00110111;
    case '8':
    return B00111000;
    case '9':
    return B00111001;
    case ':':
    return B00111010;
    case ';':
    return B00111011;
    case '<':
    return B00111100;
    case '=':
    return B00111101;
    case '>':
    return B00111110;
    case '?':
    return B00111111;

    case '@':
    return B01000000;
    case 'a':
    case 'A':
    return B01000001;
    case 'b':
    case 'B':
    return B01000010;
    case 'c':
    case 'C':
    return B01000011;
    case 'd':
    case 'D':
    return B01000100;
    case 'e':
    case 'E':
    return B01000101;
    case 'f':
    case 'F':
    return B01000110;
    case 'g':
    case 'G':
    return B01000111;
    case 'h':
    case 'H':
    return B01001000;
    case 'i':
    case 'I':
    return B01001001;
    case 'j':
    case 'J':
    return B01001010;
    case 'k':
    case 'K':
    return B01001011;
    case 'l':
    case 'L':
    return B01001100;
    case 'm':
    case 'M':
    return B01001101;
    case 'n':
    case 'N':
    return B01001110;
    case 'o':
    case 'O':
    return B01001111;

    case 'p':
    case 'P':
    return B01010000;
    case 'q':
    case 'Q':
    return B01010001;
    case 'r':
    case 'R':
    return B01010010;
    case 's':
    case 'S':
    return B01010011;
    case 't':
    case 'T':
    return B01010100;
    case 'u':
    case 'U':
    return B01010101;
    case 'v':
    case 'V':
    return B01010110;
    case 'w':
    case 'W':
    return B01010111;
    case 'x':
    case 'X':
    return B01011000;
    case 'y':
    case 'Y':
    return B01011001;
    case 'z':
    case 'Z':
    return B01011010;

    case '(':
    return B01011011;
    case '\\':
    return B01011100;
    case ')':
    return B01011101;
    case '^':
    return B01011110;
    case '_':
    return B01011111;
  }
}

This is code for my 2416 display library.

1 Like

Do it in WOKWI.  Right click on the code side - or F1 on windows machine - to bring up the command palette.  Scroll all the way down to find 'View compiled assembly ...' and click on that.

A file tab will be added called 'sketch.lst'.  That's your assembled code.  Sketches usually appear well down the listing.

3 Likes

Worked like a charm. So much easier than working backwards from a hex file.

Thank you!

ASCII '0' == 48 == B00110000

Without checking, the only cases that don't return the input are lower case alphas.

// make lower case into upper case
if (( chr >= 'a' ) && ( chr <= 'z' )) chr &= B11011111; // filter lower case

Do the least you need to.

:+1:t4: :smiley:

Or, better still:

chr = toupper(chr);

There's still a desire

so unless the compiler is as smart as y'all, there'll be a point to the manner in which the mission is accomplished.

Anyway, nice to learn more about wokwi.

a7

1 Like

Excellent!

When I first learned C I kept promising myself that I'd look at the resultant assembly code, but never got round to doing it.

1 Like

Going over it now, but good catch. I missed it. Thank you.

@alto777 is right, I do want to know more about switches and how compilers deal with them. I can make a jump table in assembly, but the compilers always add something better than I don't have experience enough to think of.

Ultimately, I'm trying to eliminate any Arduino specific code from the library. Is toupper() c++ or Arduino specific?

I'd like to publish the library, but make it available for any uC, not just Arduino. And I'd like to build a calculator algebra system with all of the code written in assembler. Might be a bit masochistic, but we all have our hobbies.

1 Like

toupper() and a hole family of associated functions are very old C.

Start here

a7

1 Like

I like the code from @GoForSmoke a bit better.

toupper (int c)
{
  return c >= -128 && c < 256 ? __ctype_toupper[c] : c;
}

Looks like there is an array that gets added to the program if you use it. Though I will take his code and make into an inline conditional.

 return  chr >= 'a' && chr <= 'z' ? chr & B11011111 : chr; 

Gee, I hate to tell you, but about 90% of c++ is "very old C". Since when is that a reason to not use it? toupper() does EXACTLY what the inline code does, and its usage and behavior is well-documented as well as reliable, and a function call is far more "readable" than new code that performs the same function.

I did not say that as an indictment, but an endorsement and as an answer to the specific question @er_name_not_found posed

Did you really

what you did?

a7

When all of it is going to be boiled down to assembly, this point is moot. Otherwise, I agree in principle, but when that one line is used once in an entire program, I tend to just use the code and do my best to eliminate excess stack usage.

What's better about it? School tie?

Yeth. My isn rule is that if similar code is used 1.5 times I start thinking about making it into a function.

a7

1 Like

In making a calculator algebra system, I will be counting every cycle and byte of program memory, though the display functions can be the slowest without impacting overall performance.

Did you mean to subtract 33? I thought it was 32.

I masked bit 5 off which is not the same as subtracting 32.

But bit 5 == B100000 == 32 == 2^5.

OTOH B1000000 & B11011111 == B1000000 where 64 - 32 == 32.

If I want to turn alpha caps to lower case, ( chr |= B100000 ) does it.

I have no idea where you pulled 33 out of.

1 Like

Oh, I see. I assumed you were subtracting, but simply turning off the 5 bit shifts. The highest bit made me thing that you were doing twos compliment subtraction by anding a negative subtrahend.

Very neat, thanks for clarifying. I love quality bit-twiddling.

B11011111 = -33 in twos compliment.