5
\$\begingroup\$

You can see it live here.

;This is a program which is supposed to ;convert binary numbers entered using the ;switches to octal, and display the octal ;numbers using the 7-segment displays. ;For converting binary digits to octal, it ;is supposed to use the algorithm we were ;taught in our Digital Electronics classes, ;namely, grouping the binary digits into ;groups of three starting with the last ;digit, and then converting each group of ;the binary digits to octal separately. ;As far as I've tested this program, ;it works. I haven't tested it on ;real PicoBlaze, though. address 0 ;That's a message to the ;preprocessor of the assembler ;to start assembling from the ;memory address 0. Every ;PicoBlaze program starts like ;that. input s0, 0 ;The switches are at the ;input address 0. ;The octal numbers that fit in 8 bits ;can be up to 3 digits long. I think ;it's easier to deal with the first ;digit separately, storing it in the ;register sc. namereg sc, first_digit load first_digit, 0 compare s0, 300'o jump c, less_than_300 load first_digit, 3 sub s0, 300'o less_than_300: compare s0, 200'o jump c, less_than_200 load first_digit, 2 sub s0, 200'o less_than_200: compare s0, 100'o jump c, less_than_100 load first_digit, 1 sub s0, 100'o less_than_100: ;So, here goes the core of the algorithm. ;It's supposed to take s0 as the input, ;the binary digits 00ABCDEF, and store into ;sa the result 0ABC0DEF. load sa, 0 load s3, 0 beginning_of_the_loop: compare s3, 2 * 3 + 1 ;Six binary digits ;plus one step with ;the special case. jump nc, end_of_the_loop compare s3, 3 jump nz, not_the_special_case ;The fourth time, do nothing except ;shifting sa to the right and ;increasing the counter. sr0 sa add s3, 1 jump beginning_of_the_loop not_the_special_case: sr0 s0 sra sa add s3, 1 jump beginning_of_the_loop end_of_the_loop: sr0 sa ;And now output the octal number you have ;got to the seven-segment displays. The ;first two digits are the output address 1, ;and the second two are the output ;address 2. output sa, 2 output first_digit, 1 ;Then run into an infinite loop... jump 0 ;You can add a breakpoint here. 

It's using the algorithm we were taught in our Digital Electronics classes for quickly converting binary to octal: group the binary digits into groups consisting of three digits starting with the last digit, and then convert each of those groups of three digits separately to octal. For example, let's say we have a binary number 10101010. First, we group the binary digits into groups of three starting from the last one, like this: (0)10|101|010. Then we convert each of those three groups of three digits separately. Since 010 is 2, and 101 is 5, the final result is 252.

\$\endgroup\$

    2 Answers 2

    5
    \$\begingroup\$

    masking

     sub s0, 300'o less_than_300: 

    That wasn't obvious to me. Wouldn't the relevant magic number be 377'o, instead? And why are we subtracting rather than ANDing? Perhaps there is some requirement or some aspect of how the switches work that I'm not yet seeing.

    Oh, now I see. We exhaustively check possible values for those two high bits. Wow, that's tedious. Just mask and be done with it.

    In any event, those are well-chosen informative labels.

    good comments

    ;It's supposed to take s0 as the input, ;the binary digits 00ABCDEF, and store into ;sa the result 0ABC0DEF. 

    That's very helpful, thank you. We know exactly what the contract is now.

    bit twiddling

    I imagine the loop does the right thing, but it seems tedious.

     jump beginning_of_the_loop not_the_special_case: 

    Those are not great labels. Maybe shift_loop? and skip_bit? We need a better name than "special case".

    There's a lot of instructions here, to accomplish a simple thing. Just allocate storage for abc and for def, use AND masking to isolate them, shift abc left one bit, then OR them back together. The masks are: 070'o, 007'o.

    A mask of 300'o would let you clean up that "deal with first digit" stuff, as well.

    \$\endgroup\$
    5
    • \$\begingroup\$I've tried to use the 300'o mask to extract the first digit: picoblaze-simulator.sourceforge.io/PicoBlaze.html?id=63 However, that doesn't speed up my program significantly because you need to shift that first digit by 6 bits to the right, and PicoBlaze has no instruction for shifting a certain number of bits. PicoBlaze only has instructions for shifting by 1 bit.\$\endgroup\$CommentedNov 23, 2024 at 16:52
    • 1
      \$\begingroup\$Oh, I'm sure that's right. But the first thing we go for in software engineering is Maintainability. We write primarily to communicate ideas to another human, and only incidentally to communicate to the machine. The first part is the harder one. I claim that writing down six "obvious" shift-right instructions is sort of "one thing" to a human, and it makes Author's Intent crystal clear. Bury it within a SHR6 macro if you like. // There's only 256 possible inputs. If saving cycles is truly the goal, you can always build 256-element lookup tables beforehand. Then you get the answer instantly.\$\endgroup\$
      – J_H
      CommentedNov 23, 2024 at 18:30
    • \$\begingroup\$Well, the assembler I made doesn't support macros.\$\endgroup\$CommentedNov 23, 2024 at 23:23
    • \$\begingroup\$Yeah, that's cool. A makefile could always use the m4 macro processor on top of lower levels like a particular assembler. We build in layers.\$\endgroup\$
      – J_H
      CommentedNov 24, 2024 at 0:36
    • \$\begingroup\$I don't think that using m4 is an option given how my assembler is structured. My assembler runs in a browser. You can see the source code of my assembler here: github.com/FlatAssembler/PicoBlaze_Simulator_in_JS/blob/master/…\$\endgroup\$CommentedNov 24, 2024 at 6:19
    3
    \$\begingroup\$

    Name all the registers

    namereg s0, switches namereg sa, last_digits namereg sc, first_digit input switches, 0 

    Two lefts equal six rights

    For the most significant digit, mask the two highest bits and then rotate left (rl) twice instead of doing six right shifts (rs0)

    ; copy the switches to the output register, mask off bits 7 and 6, and ; rotate the register to the bits are in bit positions 1 and 0. load first_digit, switches and first_digit, 300'o rl first_digit rl first_digit 

    Work on groups of bits

    The algorithm you learned splits the input into groups of bits and then does something with the groups. But your main code processes 1 bit at a time. Use and instruction to get a group of bits and manipulate them as a group.

    ; copy switches to last digits, mask bits 5,4,3, and shift the bits ; left so they are in bit positions 6, 5, 4 load last_digits, switches and last_digits, 070'o shl0 last_digits ; mask off switches 2,1,0 and or them into place in the output and switches, 007'o or last_digits, switches output first_digit, 1 output last_digits, 2 ; infinite loop jump 0 

    I don't have the hardware or software to test this code, but you should get the idea.

    \$\endgroup\$
    1

    Start asking to get answers

    Find the answer to your question by asking.

    Ask question

    Explore related questions

    See similar questions with these tags.