4
\$\begingroup\$

You can see it live here:

;A very advanced example: Implementing the permutations algorithm in PicoBlaze assembly. base_decimal constant NDEBUG, 1 constant address_of_the_current_attempt, 8 constant bottom_of_the_stack, 16 address 0 namereg sf, length_of_the_input call print_the_introduction_message load length_of_the_input, 0 beginning_of_the_input_loop: call UART_RX compare s9, a'x ;The new-line character. jump z, end_of_the_input_loop store s9, (length_of_the_input) add length_of_the_input, 1 jump beginning_of_the_input_loop end_of_the_input_loop: compare length_of_the_input, 0 jump z, 0 beginning_of_the_bubble_sort: load s4, 0 ;A boolean indicating ;whether a swap has been ;performed. load s0, 0 inner_bubble_sort_loop: load s1, length_of_the_input sub s1, 1 compare s0, s1 jump nc, end_of_the_inner_bubble_sort_loop load s1, s0 add s1, 1 fetch s2, (s0) fetch s3, (s1) compare s3, s2 jump nc, do_not_swap store s3, (s0) store s2, (s1) load s4, 1 do_not_swap: add s0, 1 jump inner_bubble_sort_loop end_of_the_inner_bubble_sort_loop: compare s4, 0 jump nz, beginning_of_the_bubble_sort end_of_the_bubble_sort_loop: jump NDEBUG ? the_permutations_algorithm : printing_the_sorted_array printing_the_sorted_array: call print_the_sorted_array_message load s0, 0 printing_the_sorted_array_loop: compare s0, length_of_the_input jump nc, end_of_the_printing_the_sorted_array_loop fetch s9, (s0) call UART_TX add s0, 1 jump printing_the_sorted_array_loop end_of_the_printing_the_sorted_array_loop: load s9, a'x call UART_TX the_permutations_algorithm: namereg se, top_of_the_stack load top_of_the_stack, bottom_of_the_stack load s0, 0 store s0, (top_of_the_stack) add top_of_the_stack, length_of_the_input add top_of_the_stack, 1 beginning_of_the_permutations_loop: compare top_of_the_stack, bottom_of_the_stack jump z, end_of_the_permutations_loop sub top_of_the_stack, length_of_the_input sub top_of_the_stack, 1 namereg sd, length_of_the_current_attempt fetch length_of_the_current_attempt, (top_of_the_stack) load s0, address_of_the_current_attempt store length_of_the_current_attempt, (s0) load s1, 0 copying_the_current_attempt_from_the_stack_loop: compare s1, length_of_the_current_attempt jump nc, end_of_copying load s0, address_of_the_current_attempt add s0, s1 add s0, 1 load s3, top_of_the_stack add s3, s1 add s3, 1 fetch s4, (s3) store s4, (s0) add s1, 1 jump copying_the_current_attempt_from_the_stack_loop end_of_copying: jump NDEBUG ? dont_print_the_current_attempt : print_the_current_attempt print_the_current_attempt: call print_the_length_of_the_current_attempt_message load s9, length_of_the_current_attempt add s9, "0" call UART_TX load s9, a'x call UART_TX call print_the_current_attempt_message load s0, address_of_the_current_attempt + 1 printing_the_current_attempt_loop: load s1, address_of_the_current_attempt + 1 add s1, length_of_the_current_attempt compare s0, s1 jump nc, end_of_the_printing_the_current_attempt_loop fetch s9, (s0) call UART_TX add s0, 1 jump printing_the_current_attempt_loop end_of_the_printing_the_current_attempt_loop: load s9, a'x call UART_TX dont_print_the_current_attempt: compare length_of_the_current_attempt, length_of_the_input jump c, current_attempt_is_not_a_solution call print_found_a_solution_message load s0, address_of_the_current_attempt + 1 printing_the_solution_loop: load s1, address_of_the_current_attempt + 1 add s1, length_of_the_current_attempt compare s0, s1 jump nc, end_of_the_printing_the_solution_loop fetch s9, (s0) call UART_TX add s0, 1 jump printing_the_solution_loop end_of_the_printing_the_solution_loop: load s9, a'x call UART_TX jump end_of_the_branching current_attempt_is_not_a_solution: load s0, length_of_the_input sub s0, 1 add_a_new_character_loop: compare s0, ff'x ;Overflow jump z, end_of_the_add_a_new_character_loop namereg sc, character_we_try_to_add fetch character_we_try_to_add, (s0) load s7, s0 add s7, 1 load s8, 0 ;Whether we already tried adding that character. check_if_we_already_tried_that_character_loop: compare s7, length_of_the_input jump nc, end_of_the_check_if_we_already_tried_that_character_loop fetch s6, (s7) compare s6, character_we_try_to_add jump nz, third_characters_are_not_equal_label load s8, 1 third_characters_are_not_equal_label: add s7, 1 jump check_if_we_already_tried_that_character_loop end_of_the_check_if_we_already_tried_that_character_loop: test s8, s8 jump nz, dont_add_the_new_character jump NDEBUG ? dont_print_the_character_we_are_trying_to_add : print_the_character_we_are_trying_to_add print_the_character_we_are_trying_to_add: call print_we_are_trying_to_add_message load s9, character_we_try_to_add call UART_TX load s9, a'x call UART_TX dont_print_the_character_we_are_trying_to_add: load s2, 0 ; How many of the chosen character are present in the current attempt. load s1, address_of_the_current_attempt + 1 count_in_the_current_attempt_loop: load s4, address_of_the_current_attempt + 1 add s4, length_of_the_current_attempt compare s1, s4 jump z, end_of_the_count_in_the_current_attempt_loop fetch s4, (s1) compare s4, character_we_try_to_add jump nz, first_the_characters_are_not_equal_label add s2, 1 first_the_characters_are_not_equal_label: add s1, 1 jump count_in_the_current_attempt_loop end_of_the_count_in_the_current_attempt_loop: jump NDEBUG ? dont_print_how_many_in_the_current_attempt : print_how_many_in_the_current_attempt print_how_many_in_the_current_attempt: call print_the_current_attempt_count_message load s9, s2 add s9, "0" call UART_TX load s9, a'x call UART_TX dont_print_how_many_in_the_current_attempt: load s3, 0 ; How many of the chosen character are present in the input. load s1, 0 count_in_the_input_loop: compare s1, length_of_the_input jump z, end_of_the_count_in_the_input_loop fetch s4, (s1) compare s4, character_we_try_to_add jump nz, second_the_characters_are_not_equal_label add s3, 1 second_the_characters_are_not_equal_label: add s1, 1 jump count_in_the_input_loop end_of_the_count_in_the_input_loop: jump NDEBUG ? dont_print_how_many_in_the_input : print_how_many_in_the_input print_how_many_in_the_input: call print_count_in_the_input_message load s9, s3 add s9, "0" call UART_TX load s9, a'x call UART_TX dont_print_how_many_in_the_input: compare s2, s3 jump nc, dont_add_the_new_character load s1, NDEBUG test s1, s1 call z, print_the_we_are_adding_the_new_character_message load s1, top_of_the_stack load s2, length_of_the_current_attempt add s2, 1 store s2, (s1) add s1, 1 load s3, address_of_the_current_attempt + 1 copying_the_new_attempt_loop: load s5, address_of_the_current_attempt + 1 add s5, length_of_the_current_attempt compare s3, s5 jump z, end_of_the_copying_the_new_attempt_loop fetch s4, (s3) store s4, (s1) add s3, 1 add s1, 1 jump copying_the_new_attempt_loop end_of_the_copying_the_new_attempt_loop: load s1, top_of_the_stack add s1, length_of_the_current_attempt add s1, 1 store character_we_try_to_add, (s1) add top_of_the_stack, length_of_the_input add top_of_the_stack, 1 dont_add_the_new_character: sub s0, 1 jump add_a_new_character_loop end_of_the_add_a_new_character_loop: jump end_of_the_branching end_of_the_branching: jump beginning_of_the_permutations_loop end_of_the_permutations_loop: call print_the_end_message jump 0 print_the_introduction_message: load s9, "E" call UART_TX load s9, "n" call UART_TX load s9, "t" call UART_TX load s9, "e" call UART_TX load s9, "r" call UART_TX load s9, " " call UART_TX load s9, "a" call UART_TX load s9, " " call UART_TX load s9, "s" call UART_TX load s9, "h" call UART_TX load s9, "o" call UART_TX load s9, "r" call UART_TX load s9, "t" call UART_TX load s9, " " call UART_TX load s9, "s" call UART_TX load s9, "t" call UART_TX load s9, "r" call UART_TX load s9, "i" call UART_TX load s9, "n" call UART_TX load s9, "g" call UART_TX load s9, " " call UART_TX load s9, "a" call UART_TX load s9, "n" call UART_TX load s9, "d" call UART_TX load s9, " " call UART_TX load s9, "p" call UART_TX load s9, "r" call UART_TX load s9, "e" call UART_TX load s9, "s" call UART_TX load s9, "s" call UART_TX load s9, " " call UART_TX load s9, "e" call UART_TX load s9, "n" call UART_TX load s9, "t" call UART_TX load s9, "e" call UART_TX load s9, "r" call UART_TX load s9, "." call UART_TX load s9, a'x call UART_TX return print_the_sorted_array_message: load s9, "A" call UART_TX load s9, "f" call UART_TX load s9, "t" call UART_TX load s9, "e" call UART_TX load s9, "r" call UART_TX load s9, " " call UART_TX load s9, "t" call UART_TX load s9, "h" call UART_TX load s9, "e" call UART_TX load s9, " " call UART_TX load s9, "B" call UART_TX load s9, "u" call UART_TX load s9, "b" call UART_TX load s9, "b" call UART_TX load s9, "l" call UART_TX load s9, "e" call UART_TX load s9, " " call UART_TX load s9, "S" call UART_TX load s9, "o" call UART_TX load s9, "r" call UART_TX load s9, "t" call UART_TX load s9, " " call UART_TX load s9, "a" call UART_TX load s9, "l" call UART_TX load s9, "g" call UART_TX load s9, "o" call UART_TX load s9, "r" call UART_TX load s9, "i" call UART_TX load s9, "t" call UART_TX load s9, "h" call UART_TX load s9, "m" call UART_TX load s9, "," call UART_TX load s9, " " call UART_TX load s9, "t" call UART_TX load s9, "h" call UART_TX load s9, "e" call UART_TX load s9, " " call UART_TX load s9, "i" call UART_TX load s9, "n" call UART_TX load s9, "p" call UART_TX load s9, "u" call UART_TX load s9, "t" call UART_TX load s9, " " call UART_TX load s9, "s" call UART_TX load s9, "t" call UART_TX load s9, "r" call UART_TX load s9, "i" call UART_TX load s9, "n" call UART_TX load s9, "g" call UART_TX load s9, " " call UART_TX load s9, "l" call UART_TX load s9, "o" call UART_TX load s9, "o" call UART_TX load s9, "k" call UART_TX load s9, "s" call UART_TX load s9, " " call UART_TX load s9, "l" call UART_TX load s9, "i" call UART_TX load s9, "k" call UART_TX load s9, "e" call UART_TX load s9, " " call UART_TX load s9, "t" call UART_TX load s9, "h" call UART_TX load s9, "i" call UART_TX load s9, "s" call UART_TX load s9, " " call UART_TX return print_the_current_attempt_message: load s9, "T" call UART_TX load s9, "h" call UART_TX load s9, "e" call UART_TX load s9, " " call UART_TX load s9, "c" call UART_TX load s9, "u" call UART_TX load s9, "r" call UART_TX load s9, "r" call UART_TX load s9, "e" call UART_TX load s9, "n" call UART_TX load s9, "t" call UART_TX load s9, " " call UART_TX load s9, "a" call UART_TX load s9, "t" call UART_TX load s9, "t" call UART_TX load s9, "e" call UART_TX load s9, "m" call UART_TX load s9, "p" call UART_TX load s9, "t" call UART_TX load s9, " " call UART_TX load s9, "i" call UART_TX load s9, "s" call UART_TX load s9, " " call UART_TX return print_we_are_trying_to_add_message: load s9, "W" call UART_TX load s9, "e" call UART_TX load s9, " " call UART_TX load s9, "a" call UART_TX load s9, "r" call UART_TX load s9, "e" call UART_TX load s9, " " call UART_TX load s9, "t" call UART_TX load s9, "r" call UART_TX load s9, "y" call UART_TX load s9, "i" call UART_TX load s9, "n" call UART_TX load s9, "g" call UART_TX load s9, " " call UART_TX load s9, "t" call UART_TX load s9, "o" call UART_TX load s9, " " call UART_TX load s9, "a" call UART_TX load s9, "d" call UART_TX load s9, "d" call UART_TX load s9, " " call UART_TX load s9, "t" call UART_TX load s9, "h" call UART_TX load s9, "e" call UART_TX load s9, " " call UART_TX load s9, "c" call UART_TX load s9, "h" call UART_TX load s9, "a" call UART_TX load s9, "r" call UART_TX load s9, "a" call UART_TX load s9, "c" call UART_TX load s9, "t" call UART_TX load s9, "e" call UART_TX load s9, "r" call UART_TX load s9, " " call UART_TX return print_the_current_attempt_count_message: load s9, "T" call UART_TX load s9, "h" call UART_TX load s9, "e" call UART_TX load s9, " " call UART_TX load s9, "c" call UART_TX load s9, "o" call UART_TX load s9, "u" call UART_TX load s9, "n" call UART_TX load s9, "t" call UART_TX load s9, " " call UART_TX load s9, "o" call UART_TX load s9, "f" call UART_TX load s9, " " call UART_TX load s9, "t" call UART_TX load s9, "h" call UART_TX load s9, "a" call UART_TX load s9, "t" call UART_TX load s9, " " call UART_TX load s9, "c" call UART_TX load s9, "h" call UART_TX load s9, "a" call UART_TX load s9, "r" call UART_TX load s9, "a" call UART_TX load s9, "c" call UART_TX load s9, "t" call UART_TX load s9, "e" call UART_TX load s9, "r" call UART_TX load s9, " " call UART_TX load s9, "i" call UART_TX load s9, "n" call UART_TX load s9, " " call UART_TX load s9, "t" call UART_TX load s9, "h" call UART_TX load s9, "e" call UART_TX load s9, " " call UART_TX load s9, "c" call UART_TX load s9, "u" call UART_TX load s9, "r" call UART_TX load s9, "r" call UART_TX load s9, "e" call UART_TX load s9, "n" call UART_TX load s9, "t" call UART_TX load s9, " " call UART_TX load s9, "a" call UART_TX load s9, "t" call UART_TX load s9, "t" call UART_TX load s9, "e" call UART_TX load s9, "m" call UART_TX load s9, "p" call UART_TX load s9, "t" call UART_TX load s9, " " call UART_TX load s9, "i" call UART_TX load s9, "s" call UART_TX load s9, " " call UART_TX return print_count_in_the_input_message: load s9, "T" call UART_TX load s9, "h" call UART_TX load s9, "e" call UART_TX load s9, " " call UART_TX load s9, "c" call UART_TX load s9, "o" call UART_TX load s9, "u" call UART_TX load s9, "n" call UART_TX load s9, "t" call UART_TX load s9, " " call UART_TX load s9, "o" call UART_TX load s9, "f" call UART_TX load s9, " " call UART_TX load s9, "t" call UART_TX load s9, "h" call UART_TX load s9, "a" call UART_TX load s9, "t" call UART_TX load s9, " " call UART_TX load s9, "c" call UART_TX load s9, "h" call UART_TX load s9, "a" call UART_TX load s9, "r" call UART_TX load s9, "a" call UART_TX load s9, "c" call UART_TX load s9, "t" call UART_TX load s9, "e" call UART_TX load s9, "r" call UART_TX load s9, " " call UART_TX load s9, "i" call UART_TX load s9, "n" call UART_TX load s9, " " call UART_TX load s9, "t" call UART_TX load s9, "h" call UART_TX load s9, "e" call UART_TX load s9, " " call UART_TX load s9, "i" call UART_TX load s9, "n" call UART_TX load s9, "p" call UART_TX load s9, "u" call UART_TX load s9, "t" call UART_TX load s9, " " call UART_TX load s9, "s" call UART_TX load s9, "t" call UART_TX load s9, "r" call UART_TX load s9, "i" call UART_TX load s9, "n" call UART_TX load s9, "g" call UART_TX load s9, " " call UART_TX load s9, "i" call UART_TX load s9, "s" call UART_TX load s9, " " call UART_TX return print_the_we_are_adding_the_new_character_message: load s9, "W" call UART_TX load s9, "e" call UART_TX load s9, " " call UART_TX load s9, "w" call UART_TX load s9, "i" call UART_TX load s9, "l" call UART_TX load s9, "l" call UART_TX load s9, " " call UART_TX load s9, "t" call UART_TX load s9, "r" call UART_TX load s9, "y" call UART_TX load s9, " " call UART_TX load s9, "t" call UART_TX load s9, "o" call UART_TX load s9, " " call UART_TX load s9, "a" call UART_TX load s9, "d" call UART_TX load s9, "d" call UART_TX load s9, " " call UART_TX load s9, "t" call UART_TX load s9, "h" call UART_TX load s9, "a" call UART_TX load s9, "t" call UART_TX load s9, " " call UART_TX load s9, "c" call UART_TX load s9, "h" call UART_TX load s9, "a" call UART_TX load s9, "r" call UART_TX load s9, "a" call UART_TX load s9, "c" call UART_TX load s9, "t" call UART_TX load s9, "e" call UART_TX load s9, "r" call UART_TX load s9, "." call UART_TX load s9, a'x call UART_TX return print_found_a_solution_message: load s9, "F" call UART_TX load s9, "o" call UART_TX load s9, "u" call UART_TX load s9, "n" call UART_TX load s9, "d" call UART_TX load s9, " " call UART_TX load s9, "a" call UART_TX load s9, " " call UART_TX load s9, "p" call UART_TX load s9, "e" call UART_TX load s9, "r" call UART_TX load s9, "m" call UART_TX load s9, "u" call UART_TX load s9, "t" call UART_TX load s9, "a" call UART_TX load s9, "t" call UART_TX load s9, "i" call UART_TX load s9, "o" call UART_TX load s9, "n" call UART_TX load s9, " " call UART_TX return print_the_end_message: load s9, "T" call UART_TX load s9, "h" call UART_TX load s9, "e" call UART_TX load s9, " " call UART_TX load s9, "e" call UART_TX load s9, "n" call UART_TX load s9, "d" call UART_TX load s9, "!" call UART_TX load s9, a'x call UART_TX return print_the_length_of_the_current_attempt_message: load s9, "T" call UART_TX load s9, "h" call UART_TX load s9, "e" call UART_TX load s9, " " call UART_TX load s9, "l" call UART_TX load s9, "e" call UART_TX load s9, "n" call UART_TX load s9, "g" call UART_TX load s9, "t" call UART_TX load s9, "h" call UART_TX load s9, " " call UART_TX load s9, "o" call UART_TX load s9, "f" call UART_TX load s9, " " call UART_TX load s9, "t" call UART_TX load s9, "h" call UART_TX load s9, "e" call UART_TX load s9, " " call UART_TX load s9, "c" call UART_TX load s9, "u" call UART_TX load s9, "r" call UART_TX load s9, "r" call UART_TX load s9, "e" call UART_TX load s9, "n" call UART_TX load s9, "t" call UART_TX load s9, " " call UART_TX load s9, "a" call UART_TX load s9, "t" call UART_TX load s9, "t" call UART_TX load s9, "e" call UART_TX load s9, "m" call UART_TX load s9, "p" call UART_TX load s9, "t" call UART_TX load s9, " " call UART_TX load s9, "i" call UART_TX load s9, "s" call UART_TX load s9, " " call UART_TX return ;Now follows some boilerplate code ;we use in our Computer Architecture ;classes... CONSTANT LED_PORT, 00 CONSTANT HEX1_PORT, 01 CONSTANT HEX2_PORT, 02 CONSTANT UART_TX_PORT, 03 CONSTANT UART_RESET_PORT, 04 CONSTANT SW_PORT, 00 CONSTANT BTN_PORT, 01 CONSTANT UART_STATUS_PORT, 02 CONSTANT UART_RX_PORT, 03 ; Tx data_present CONSTANT U_TX_D, 00000001'b ; Tx FIFO half_full CONSTANT U_TX_H, 00000010'b ; TxFIFO full CONSTANT U_TX_F, 00000100'b ; Rxdata_present CONSTANT U_RX_D, 00001000'b ; RxFIFO half_full CONSTANT U_RX_H, 00010000'b ; RxFIFO full CONSTANT U_RX_F, 00100000'b UART_RX: INPUT sA, UART_STATUS_PORT TEST sA, U_RX_D JUMP NZ, input_not_empty LOAD s0, s0 JUMP UART_RX input_not_empty: INPUT s9, UART_RX_PORT RETURN UART_TX: INPUT sA, UART_STATUS_PORT TEST sA, U_TX_F JUMP NZ, UART_TX OUTPUT s9, UART_TX_PORT RETURN 

As far as I've tested it, it seems to work. But I am not sure how legible it is. I've tried to make it as legible as possible by using long label names and using nameregs sometimes, as well as code indentation.

\$\endgroup\$
0

    1 Answer 1

    4
    \$\begingroup\$

    naming nit: an imperative print_foo label would be more usual than printing_foo, whatever.

    define constant string

    The UART runs at a fixed rate, so it's not like "optimize for speed" is relevant here. I can't imagine any set of time - space tradeoffs or engineering constraints that would motivate generating this code:

    print_the_introduction_message: load s9, "E" call UART_TX load s9, "n" call UART_TX ... 

    If you really desire that generated machine code as output, at least create a macro so dealing with e.g. "E" takes a single line rather than two.

    But what should replace this code is:

    introduction_message: defstring "Enter a short ..." print_the_introduction_message: load s9, introduction_message call print_string 

    Use a wide enough register for a pointer, if s9 is too narrow. Use NUL terminated strings if you like, or a (length, data) tuple.

    The print_string utility routine will loop over the input, making calls to UART_TX as it goes. There's already some fragments in the OP code that show how to do that.

    \$\endgroup\$
    8
    • \$\begingroup\$I want to generate that machine code because I have almost limitless EPROM memory (for storing instructions), but I only have 256 bytes of RAM. Storing those strings in RAM seems wasteful, doesn't it?\$\endgroup\$CommentedApr 12 at 14:54
    • 2
      \$\begingroup\$I don’t understand the “store in RAM” remark. An origin directive or similar should let you allocate a string up in your favorite EPROM address space, and then another origin directive would let you continue on with machine code, keeping it all together. In general, I would expect that the author of an assembly file would have complete control over the memory layout of where things go. I would be very surprised if a DEFBYTE or DEFWORD directive used scratchpad RAM storage, rather than adding output bytes to the read only .text segment. An init routine might copy data down to RAM.\$\endgroup\$
      – J_H
      CommentedApr 12 at 17:33
    • \$\begingroup\$Hmmm, it doesn’t even need to be NUL terminated. Over in codereview.stackexchange.com/questions/295873/… we see an example where the author found the dollar sign “$” character a convenient terminator.\$\endgroup\$
      – J_H
      CommentedApr 12 at 17:41
    • 2
      \$\begingroup\$As someone who spent a lot of time worrying about page zero on 6502 machines, I can’t imagine why that is a desirable architectural feature. But if that is the engineering constraint, then I recommend defining a few routines in EPROM that fill a ram buffer with various constant strings. This allows a more natural calling interface when requesting output to the serial UART device. With judicious use of macros, there should be no need to use more than one source line per character.\$\endgroup\$
      – J_H
      CommentedApr 12 at 18:14
    • 3
      \$\begingroup\$That’s not necessary. You could, for example, use the M4 macro pre-processor to send revised source code into the existing assembler. // i’m just saying that the existing OP source code is distracting. It is not the best way to express the high-level idea to some maintenance engineer who will look at this in a year or two.\$\endgroup\$
      – J_H
      CommentedApr 12 at 20:30

    Start asking to get answers

    Find the answer to your question by asking.

    Ask question

    Explore related questions

    See similar questions with these tags.