;Pi calculation for CPUville 8-bit processor ;Macro definitions for three levels of nested call and ret #define call0(address) \return: .set $+15\ ldm return\ stm return_jump0+1\ ldm return+1\ stm return_jump0+2 #defcont \ jmp address\ .dw $+2 #define ret0 \ jmp return_jump0 #define call1(address) \return: .set $+15\ ldm return\ stm return_jump1+1\ ldm return+1\ stm return_jump1+2 #defcont \ jmp address\ .dw $+2 #define ret1 \ jmp return_jump1 #define call2(address) \return: .set $+15\ ldm return\ stm return_jump2+1\ ldm return+1\ stm return_jump2+2 #defcont \ jmp address\ .dw $+2 #define ret2 \ jmp return_jump2 #define call3(address) \return: .set $+15\ ldm return\ stm return_jump3+1\ ldm return+1\ stm return_jump3+2 #defcont \ jmp address\ .dw $+2 #define ret3 \ jmp return_jump3 #define callA(address) \return: .set $+15\ ldm return\ stm return_jumpA+1\ ldm return+1\ stm return_jumpA+2 #defcont \ jmp address\ .dw $+2 #define retA \ jmp return_jumpA ;Other macros #define write_newline \ ldm new_line\ stm ws_inst+1\ ldm new_line+1\ stm ws_inst+2\ call0(write_string) #define write_tabs \ ldm two_tabs\ stm ws_inst+1\ ldm two_tabs+1\ stm ws_inst+2\ call0(write_string) ;ROM monitor subroutines, associated variables, and call return jump addresses monitor_warm_start .equ 0098h write_string .equ 05E7h ;level 0 subroutine ws_inst .equ 0833h ;place string address here byte_to_hex_pair .equ 06B4h ;level 0 subroutine byte .equ 0812h ;location of byte for subroutine char_pair .equ 080Ah ;location of returned character pair hex_pair_to_byte .equ 0654h ;level 1 subroutine get_line .equ 058Dh ;level 0 subroutine buff_low .equ 80h ;get_line buffer address 0880h as bytes buff_high .equ 08h buffer .equ 0880h ;get_line buffer address as word return_jump0 .equ 083Fh ;needed for call and ret macros return_jump1 .equ 0842h return_jump2 .equ 0845h .org 0900h ;Page 1 at 0800h is for monitor stuff return .db 1fh ;placeholder for first definition of variable label -- NOP jmp start ;Variables and constants for pi program new_line .dw $+2 .db 0dh,0ah,0 two_tabs .dw $+2 .db 09h,09h,0 heading_str .dw $+2 .text "Sides" .db 09h,09h ;horizontal tab .text "Pi" .db 0 hex_str_buff .dw $+2 .fill 30,0 dec_str_buff .dw $+2 .fill 30,0 dec_out_str .dw $+2 .fill 30,0 range_err_hi .dw $+2 .db 0dh,0ah .text "Range error high" .db 0dh,0ah,0 range_err_lo .dw $+2 .db 0dh,0ah .text "Range error low" .db 0dh,0ah,0 frac_table_addr .dw $+2 frac_table .db 40h,4Bh,4Ch ;used by float-to-decimal for forming decimal fractions .db 0A0h,25h,26h ;values stored little-endian .db 0D0h,12h,13h .db 68h,89h,09h .db 0B4h,0C4h,04h .db 5Ah,62h,02h .db 2Dh,31h,01h .db 96h,98h,00h .db 4Bh,4Ch,00h .db 26h,26h,00h .db 13h,13h,00h .db 89h,09h,00h .db 0C5h,04h,00h .db 62h,02h,00h .db 31h,01h,00h .db 99h,00h,00h .db 4Ch,00h,00h .db 26h,00h,00h .db 13h,00h,00h .db 0Ah,00h,00h .db 05h,00h,00h .db 02h,00h,00h .db 01h,00h,00h frac_table_ptr .dw 00h,00h table_index .db 00h hex_frac .db 00h,00h,00h ;long word little-endian exponent: .db 00h sign: .db 00h exponent_a: .db 00h exponent_b: .db 00h exponent_c: .db 00h exponent_x: .db 00h exponent_test: .db 00h char .db 00h byte_a .db 00h byte_b .db 00h byte_c .db 00h byte_d .db 00h long_a: .db 00h,00h,00h ;for 24-bit values long_b: .db 00h,00h,00h long_c: .db 00h,00h,00h long_d: .db 00h,00h,00h long_r: .db 00h,00h,00h double_long_a: .db 00h,00h,00h,00h,00h,00h ;for 48-bit values double_long_b: .db 00h,00h,00h,00h,00h,00h double_long_c: .db 00h,00h,00h,00h,00h,00h rs_carry_in: .db 00h rs_carry_out: .db 00h ls_carry_in: .db 00h ls_carry_out: .db 00h divide_rounds: .db 00h fp_a: .db 00h,00h,00h,00h fp_b: .db 00h,00h,00h,00h fp_c: .db 00h,00h,00h,00h fp_d: .db 00h,00h,00h,00h fp_x: .db 00h,00h,00h,00h fp_test: .db 00h,00h,00h,00h fp_square: .db 00h,00h,00h,00h fp_pi_a: .db 00h,00h,00h,00h fp_pi_b: .db 00h,00h,00h,00h fp_pi_c: .db 00h,00h,00h,00h fp_pi_d: .db 00h,00h,00h,00h fp_pi_a_squared: .db 00h,00h,00h,00h fp_pi_b_squared: .db 00h,00h,00h,00h fp_pi_c_squared: .db 00h,00h,00h,00h fp_pi_d_squared: .db 00h,00h,00h,00h fp_sides: .db 00h,00h,00h,00h fp_2pi: .db 00h,00h,00h,00h fp_pi: .db 00h,00h,00h,00h pi_cycles: .db 00h shift_steps .db 00h dec_out_ptr .dw 0000h int_flag .db 00h ;Extra return jumps for level 3 and A calls return_jump3 jmp 0000h return_jumpA jmp 0000h ;Start of code ;Debug -- test long_to_dec_str debug write_newline call0(get_line) ldm buffer stm char_pair ldm buffer+1 stm char_pair+1 call1(hex_pair_to_byte) stm fp_a ldm buffer+2 stm char_pair ldm buffer+3 stm char_pair+1 call1(hex_pair_to_byte) stm fp_a+1 ldm buffer+4 stm char_pair ldm buffer+5 stm char_pair+1 call1(hex_pair_to_byte) stm fp_a+2 ldm buffer+6 stm char_pair ldm buffer+7 stm char_pair+1 call1(hex_pair_to_byte) stm fp_a+3 callA(float_to_dec) write_newline ldm dec_out_str stm ws_inst+1 ldm dec_out_str+1 stm ws_inst+2 call0(write_string) write_newline jmp debug ;Calculate pi ;Uses polygons inside a circle with radius 1 ;Start with square, double sides each cycle ;Perimeter approaches 2pi as sides of polygon increase ;Initialize variables start: write_newline ldm heading_str stm ws_inst+1 ldm heading_str+1 stm ws_inst+2 call0(write_string) write_newline ldi 40h ;fp_sides contains number of sides stm fp_sides ;0x40800000 is fp for four (start with square) ldi 80h stm fp_sides+1 ldi 0 stm fp_sides+2 stm fp_sides+3 ldi 3Fh ;fp_a equals one to start stm fp_pi_a ;0x3F800000 is fp for one ldi 80h stm fp_pi_a+1 ldi 0 stm fp_pi_a+2 stm fp_pi_a+3 ldi 3Fh ;fp_b equals one to start stm fp_pi_b ;0x3F800000 is fp for one ldi 80h stm fp_pi_b+1 ldi 0 stm fp_pi_b+2 stm fp_pi_b+3 ldi 13 ;number of cycles (doublings of polygon sides) stm pi_cycles pi_loop: ;Calculate fp_c, which is edge length ;fp_pi_c equals square root of fp_pi_a squared plus fp_pi_b squared ;First square fp_pi_a, result in fp_pi_a_squared ldm fp_pi_a stm fp_a stm fp_b ldm fp_pi_a+1 stm fp_a+1 stm fp_b+1 ldm fp_pi_a+2 stm fp_a+2 stm fp_b+2 ldm fp_pi_a+3 stm fp_a+3 stm fp_b+3 call0(multiply_float) ldm fp_c stm fp_pi_a_squared ldm fp_c+1 stm fp_pi_a_squared+1 ldm fp_c+2 stm fp_pi_a_squared+2 ldm fp_c+3 stm fp_pi_a_squared+3 ;Next square fp_pi_b, result in fp_pi_b_squared ldm fp_pi_b stm fp_a stm fp_b ldm fp_pi_b+1 stm fp_a+1 stm fp_b+1 ldm fp_pi_b+2 stm fp_a+2 stm fp_b+2 ldm fp_pi_b+3 stm fp_a+3 stm fp_b+3 call0(multiply_float) ldm fp_c stm fp_pi_b_squared ldm fp_c+1 stm fp_pi_b_squared+1 ldm fp_c+2 stm fp_pi_b_squared+2 ldm fp_c+3 stm fp_pi_b_squared+3 ;Next add pi_square_a and pi_square_b, result in fp_pi_c_squared ldm fp_pi_a_squared stm fp_a ldm fp_pi_a_squared+1 stm fp_a+1 ldm fp_pi_a_squared+2 stm fp_a+2 ldm fp_pi_a_squared+3 stm fp_a+3 ldm fp_pi_b_squared stm fp_b ldm fp_pi_b_squared+1 stm fp_b+1 ldm fp_pi_b_squared+2 stm fp_b+2 ldm fp_pi_b_squared+3 stm fp_b+3 call0(add_float) ldm fp_c stm fp_pi_c_squared ldm fp_c+1 stm fp_pi_c_squared+1 ldm fp_c+2 stm fp_pi_c_squared+2 ldm fp_c+3 stm fp_pi_c_squared+3 ;Next calculate square root of fp_pi_c_squared, result in fp_pi_c ldm fp_pi_c_squared stm fp_x ldm fp_pi_c_squared+1 stm fp_x+1 ldm fp_pi_c_squared+2 stm fp_x+2 ldm fp_pi_c_squared+3 stm fp_x+3 callA(sqrt_float) ldm fp_test stm fp_pi_c ldm fp_test+1 stm fp_pi_c+1 ldm fp_test+2 stm fp_pi_c+2 ldm fp_test+3 stm fp_pi_c+3 ;Have edge length in fp_pi_c, can now calculate pi, result in fp_pi ;First calculate total perimeter length ldm fp_sides stm fp_a ldm fp_sides+1 stm fp_a+1 ldm fp_sides+2 stm fp_a+2 ldm fp_sides+3 stm fp_a+3 ldm fp_pi_c stm fp_b ldm fp_pi_c+1 stm fp_b+1 ldm fp_pi_c+2 stm fp_b+2 ldm fp_pi_c+3 stm fp_b+3 call0(multiply_float) ;Multiplication result will be in fp_c ;Divide fp_c by two and transfer result to fp_pi ldm fp_c ;divide by two by subtracting one from exponent stm byte_a call3(shift_left_one) ;First extract exponent stm exponent_c ldm fp_c+1 ;Check for bit 0 of exponent andi 10000000b jpz cpi_next_1 ;if bit 0 zero, done ldm exponent_c ;if bit 0 one, set it ori 00000001b stm exponent_c cpi_next_1: ldm exponent_c ;decrement exponent (divide by two) dec stm exponent_c stm byte_a call3(shift_right_one) ;put exponent back in fp_c stm fp_c ldm exponent_c ;check bit 0 of exponent andi 00000001b jpz cpi_next_2 ;bit 0 is zero, set fp_c+1 bit 7 to zero ldm fp_c+1 ;bit 0 is one, set to one ori 10000000b stm fp_c+1 jmp cpi_next_3 cpi_next_2: ldm fp_c+1 ;bit 0 is zero, set to zero andi 01111111b stm fp_c+1 cpi_next_3: ldm fp_c stm fp_pi ldm fp_c+1 stm fp_pi+1 ldm fp_c+2 stm fp_pi+2 ldm fp_c+3 stm fp_pi+3 ;Display sides and pi ldm fp_sides stm fp_a ldm fp_sides+1 stm fp_a+1 ldm fp_sides+2 stm fp_a+2 ldm fp_sides+3 stm fp_a+3 callA(float_to_dec) ldm dec_out_str stm ws_inst+1 ldm dec_out_str+1 stm ws_inst+2 call0(write_string) write_tabs ldm fp_pi stm fp_a ldm fp_pi+1 stm fp_a+1 ldm fp_pi+2 stm fp_a+2 ldm fp_pi+3 stm fp_a+3 callA(float_to_dec) ldm dec_out_str stm ws_inst+1 ldm dec_out_str+1 stm ws_inst+2 call0(write_string) write_newline ldm pi_cycles dec jpz pi_done stm pi_cycles ;If not done, prepare for next cycle ;First double the sides ldm fp_sides ;multiply fp_sides by two by adding one to exponent stm byte_a call3(shift_left_one) ;extract exponent stm exponent_c ldm fp_sides+1 ;check bit 0 of exponent andi 10000000b jpz pi_next_A ;if 0, set it to zero ldm exponent_c ;if one, set it to one ori 00000001b stm exponent_c jmp pi_next_1 pi_next_A: ldm exponent_c andi 11111110b stm exponent_c pi_next_1: ldm exponent_c ;add one to exponent inc stm exponent_c stm byte_a call3(shift_right_one) ;reassemble float stm fp_sides ldm exponent_c ;check bit 0 of exponent andi 00000001b jpz pi_next_B ldm fp_sides+1 ;set one ori 10000000b stm fp_sides+1 jmp pi_next_2 pi_next_B: ldm fp_sides+1 ;set zero andi 01111111b stm fp_sides+1 ;The next fp_pi_b is current fp_pi_c divided by two pi_next_2: ldm fp_pi_c ;make fp_pi_b equal to current fp_pi_c stm fp_pi_b ldm fp_pi_c+1 stm fp_pi_b+1 ldm fp_pi_c+2 stm fp_pi_b+2 ldm fp_pi_c+3 stm fp_pi_b+3 ldm fp_pi_b ;divide fp_pi_b by two by subtracting one from exponent stm byte_a call3(shift_left_one) ;extract exponent, puts zero in bit 0 stm exponent_c ldm fp_pi_b+1 ;check bit 0 of exponent andi 10000000b jpz pi_next_3 ;done if zero ldm exponent_c ;if one, set bit 7 of exponent ori 00000001b stm exponent_c pi_next_3: ldm exponent_c ;subtract one from exponent (decrement) dec stm exponent_c ;Put exponent back into fp_pi_b ldm exponent_c stm byte_a call3(shift_right_one) stm fp_pi_b ldm exponent_c ;check bit 0 of exponent andi 00000001b jpz pi_next_4 ;if zero, set bit to 0 ldm fp_pi_b+1 ;if one,set bit to one ori 10000000b stm fp_pi_b+1 jmp pi_next_5 pi_next_4: ldm fp_pi_b+1 ;set bit to zero andi 01111111b stm fp_pi_b+1 ;Set fp_pi_d to square root of one minus fp_pi_b squared. Use macros and subroutine ;First square fp_pi_b, result in fp_pi_b_squared pi_next_5: ldm fp_pi_b stm fp_a stm fp_b ldm fp_pi_b+1 stm fp_a+1 stm fp_b+1 ldm fp_pi_b+2 stm fp_a+2 stm fp_b+2 ldm fp_pi_b+3 stm fp_a+3 stm fp_b+3 call0(multiply_float) ldm fp_c stm fp_pi_b_squared ldm fp_c+1 stm fp_pi_b_squared+1 ldm fp_c+2 stm fp_pi_b_squared+2 ldm fp_c+3 stm fp_pi_b_squared+3 ;Next calculate 1-fp_pi_b_squared, result in fp_pi_d_squared ldi 3Fh ;fp one is 0x3F800000 stm fp_a ldi 80h stm fp_a+1 ldi 0 stm fp_a+2 stm fp_a+3 ldm fp_pi_b_squared stm fp_b ldm fp_pi_b_squared+1 stm fp_b+1 ldm fp_pi_b_squared+2 stm fp_b+2 ldm fp_pi_b_squared+3 stm fp_b+3 call0(subtract_float) ldm fp_c stm fp_pi_d_squared ldm fp_c+1 stm fp_pi_d_squared+1 ldm fp_c+2 stm fp_pi_d_squared+2 ldm fp_c+3 stm fp_pi_d_squared+3 ;Last do square root of result, result in fp_pi_d ldm fp_pi_d_squared stm fp_x ldm fp_pi_d_squared+1 stm fp_x+1 ldm fp_pi_d_squared+2 stm fp_x+2 ldm fp_pi_d_squared+3 stm fp_x+3 callA(sqrt_float) ldm fp_test stm fp_pi_d ldm fp_test+1 stm fp_pi_d+1 ldm fp_test+2 stm fp_pi_d+2 ldm fp_test+3 stm fp_pi_d+3 ;Next calculate new fp_pi_a which is one minus fp_pi_d ldi 3Fh ;fp one is 0x3F800000 stm fp_a ldi 80h stm fp_a+1 ldi 0 stm fp_a+2 stm fp_a+3 ldm fp_pi_d stm fp_b ldm fp_pi_d+1 stm fp_b+1 ldm fp_pi_d+2 stm fp_b+2 ldm fp_pi_d+3 stm fp_b+3 call0(subtract_float) ldm fp_c stm fp_pi_a ldm fp_c+1 stm fp_pi_a+1 ldm fp_c+2 stm fp_pi_a+2 ldm fp_c+3 stm fp_pi_a+3 ;Now ready to calculate side length and pi jmp pi_loop pi_done: jmp monitor_warm_start ;Subroutine to arithmetic shift left one a byte ;Call as level 3 subroutine ;Byte to shift passed in byte_a ;Returns with shifted byte in accumulator ;Uses byte_c and byte_d as temp storage shift_left_one: ldm byte_a ;byte to shift stm byte_c ;byte to shift to temp storage ldi 0 stm byte_d ;clear byte_d ldm byte_c andi 01000000b ;check bit 6 jpz slo_check_bit_5 ;leave bit 7 as zero, check next bit ldi 10000000b ;set bit 7 to 1 orm byte_d stm byte_d slo_check_bit_5: ldm byte_c andi 00100000b jpz slo_check_bit_4 ldi 01000000b orm byte_d stm byte_d slo_check_bit_4: ldm byte_c andi 00010000b jpz slo_check_bit_3 ldi 00100000b orm byte_d stm byte_d slo_check_bit_3: ldm byte_c andi 00001000b jpz slo_check_bit_2 ldi 00010000b orm byte_d stm byte_d slo_check_bit_2: ldm byte_c andi 00000100b jpz slo_check_bit_1 ldi 00001000b orm byte_d stm byte_d slo_check_bit_1: ldm byte_c andi 00000010b jpz slo_check_bit_0 ldi 00000100b orm byte_d stm byte_d slo_check_bit_0: ldm byte_c andi 00000001b jpz slo_done ldi 0000010b orm byte_d stm byte_d slo_done ldm byte_d ret3 ;Subroutine to arithmetic shift right one a byte ;Call as level 3 subroutine ;Byte to shift passed byte_a ;Returns with shifted byte in accumulator ;Uses byte_c and byte_d as temp storage shift_right_one: ldm byte_a ;byte to shift stm byte_c ;byte to shift to temp storage ldi 0 stm byte_d ;clear byte_d ldm byte_c andi 00000010b ;check bit 1 jpz sro_check_bit_2 ;leave bit bit 0 as zero, check next bit ldi 00000001b ;set bit 0 to 1 orm byte_d stm byte_d sro_check_bit_2: ldm byte_c andi 00000100b ;check bit 2 jpz sro_check_bit_3 ;zero, go to next bie ldi 00000010b ;one, set D reg bit 1 to 1 orm byte_d stm byte_d sro_check_bit_3: ldm byte_c andi 00001000b jpz sro_check_bit_4 ldi 00000100b orm byte_d stm byte_d sro_check_bit_4: ldm byte_c andi 00010000b jpz sro_check_bit_5 ldi 00001000b orm byte_d stm byte_d sro_check_bit_5: ldm byte_c andi 00100000b jpz sro_check_bit_6 ldi 00010000b orm byte_d stm byte_d sro_check_bit_6: ldm byte_c andi 01000000b jpz sro_check_bit_7 ldi 00100000b orm byte_d stm byte_d sro_check_bit_7: ldm byte_c andi 10000000b jpz sro_done ldi 01000000b orm byte_d stm byte_d sro_done: ldm byte_d ret3 ;Subroutine to shift left one a 24-bit value ;24-bit value in long_c ;Call as level 2 subroutine ;Shifted long returned in long_c shift_left_long: ldm long_c+2 stm byte_c andi 10000000b ;check leftmost bit stm ls_carry_out ;save for carry-in at next step ldm byte_c stm byte_a ;shift subroutine needs byte in byte_a call3(shift_left_one) stm long_c+2 ;store shifted byte ldm ls_carry_out stm ls_carry_in ;carry-out becomes carry-in for next shift ldm long_c+1 ;get next byte to shift stm byte_c ;temp storage andi 10000000b stm ls_carry_out ;save carry-out before shift ldm byte_c stm byte_a call3(shift_left_one) ;shift one left stm byte_c ;temp store shifted byte ldm ls_carry_in jpz lsl_no_carry_in_1 ;carry-in? ldi 00000001b ;no, skip carry-in orm byte_c ;yes, put carry in bit 0 and store jmp lsl_store_1 lsl_no_carry_in_1: ldm byte_c ;no carry, get shifted byte back and lsl_store_1: stm long_c+1 ;store shifted byte ldm ls_carry_out stm ls_carry_in ;carry-out becomes carry-in for next shift ldm long_c ;get next byte to shift stm byte_c ;temp storage andi 10000000b stm ls_carry_out ;save carry-out ldm byte_c stm byte_a call3(shift_left_one) stm byte_c ;temp store shifted byte ldm ls_carry_in jpz lsl_no_carry_in_2 ;carry-in? ldi 00000001b ;no, skip carry-in orm byte_c ;yes, put carry in bit 0 and store jmp lsl_store_2 lsl_no_carry_in_2: ldm byte_c ;no carry, get shifted byte back and lsl_store_2: stm long_c ;store shifted byte ret2 ;Subroutine to shift right one a 24-bit value ;Call as level 2 subroutine ;24-bit value in long_d ;Returns shifted long in long_d shift_right_long: ldm long_d stm byte_c andi 00000001b ;check rightmost bit stm rs_carry_out ;save for carry-in at next step ldm byte_c stm byte_a ;shift routine needs byte in byte_a call3(shift_right_one) stm long_d ;store shifted byte ldm rs_carry_out stm rs_carry_in ;carry-out becomes carry-in for next shift ldm long_d+1 ;get next byte to shift stm byte_c ;temp storage andi 00000001b ;check rightmost bit stm rs_carry_out ;save carry-out before shift ldm byte_c stm byte_a call3(shift_right_one) stm byte_c ;temp store shifted byte ldm rs_carry_in jpz rsl_no_carry_in_1 ;carry-in? ldi 10000000b ;no, skip carry-in orm byte_c ;yes, put carry in bit 7 and store jmp rsl_store_1 rsl_no_carry_in_1: ldm byte_c ;no carry, get shifted byte back and rsl_store_1: stm long_d+1 ;store shifted byte ldm rs_carry_out stm rs_carry_in ;carry-out becomes carry-in for next shift ldm long_d+2 ;get last byte to shift stm byte_a ;no need to check carry out call3(shift_right_one) stm byte_c ;temp store shifted byte ldm rs_carry_in jpz rsl_no_carry_in_2 ;carry-in? ldi 10000000b ;no, skip carry-in orm byte_c ;yes, put carry in bit 7 and store jmp rsl_store_2 rsl_no_carry_in_2: ldm byte_c ;no carry, get shifted byte back and rsl_store_2: stm long_d+2 ;store shifted byte ret2 ;Subroutine to shift left one a 48-bit value ;48-bit value in double_long_a ;Call as level 2 subroutine ;Result in double_long_a sh_left_double ldm double_long_a+5 stm byte_c andi 10000000b ;check leftmost bit stm ls_carry_out ;save for carry-in at next step ldm byte_c stm byte_a call3(shift_left_one) stm double_long_a+5 ;store shifted byte ldm ls_carry_out stm ls_carry_in ;carry-out becomes carry-in for next shift ldm double_long_a+4 ;get next byte to shift stm byte_c ;temp storage andi 10000000b stm ls_carry_out ;save carry-out before shift ldm byte_c stm byte_a call3(shift_left_one) ;shift one left stm byte_c ;temp store shifted byte ldm ls_carry_in jpz ls_no_carry_in_1 ;carry-in? ldi 00000001b ;no, skip carry-in orm byte_c ;yes, put carry in bit 0 and store jmp ls_store_1 ls_no_carry_in_1: ldm byte_c ;no carry, get shifted byte back and ls_store_1: stm double_long_a+4 ;store shifted byte ldm ls_carry_out stm ls_carry_in ;carry-out becomes carry-in for next shift ldm double_long_a+3 ;get next byte to shift stm byte_c ;temp storage andi 10000000b stm ls_carry_out ;save carry-out ldm byte_c stm byte_a call3(shift_left_one) stm byte_c ;temp store shifted byte ldm ls_carry_in jpz ls_no_carry_in_2 ;carry-in? ldi 00000001b ;no, skip carry-in orm byte_c ;yes, put carry in bit 0 and store jmp ls_store_2 ls_no_carry_in_2: ldm byte_c ;no carry, get shifted byte back and ls_store_2: stm double_long_a+3 ;store shifted byte ldm ls_carry_out stm ls_carry_in ;carry-out becomes carry-in for next shift ldm double_long_a+2 ;get next byte to shift stm byte_c ;temp storage andi 10000000b stm ls_carry_out ;save carry-out ldm byte_c stm byte_a call3(shift_left_one) stm byte_c ;temp store shifted byte ldm ls_carry_in jpz ls_no_carry_in_3 ;carry-in? ldi 00000001b ;no, skip carry-in orm byte_c ;yes, put carry in bit 0 and store jmp ls_store_3 ls_no_carry_in_3: ldm byte_c ;no carry, get shifted byte back and ls_store_3: stm double_long_a+2 ;store shifted byte ldm ls_carry_out stm ls_carry_in ;carry-out becomes carry-in for next shift ldm double_long_a+1 ;get next byte to shift stm byte_c ;temp storage andi 10000000b stm ls_carry_out ;save carry-out ldm byte_c stm byte_a call3(shift_left_one) stm byte_c ;temp store shifted byte ldm ls_carry_in jpz ls_no_carry_in_4 ;carry-in? ldi 00000001b ;no, skip carry-in orm byte_c ;yes, put in bit 0 and store jmp ls_store_4 ls_no_carry_in_4: ldm byte_c ;no carry, get shifted byte back and ls_store_4: stm double_long_a+1 ;store shifted byte ldm ls_carry_out stm ls_carry_in ;carry-out becomes carry-in for next shift ldm double_long_a stm byte_a ;get next byte to shift call3(shift_left_one) stm byte_c ;temp store shifted byte ldm ls_carry_in jpz ls_no_carry_in_5 ;carry-in? ldi 00000001b ;no, skip carry-in orm byte_c ;yes, put in bit 7 and store jmp ls_store_5 ls_no_carry_in_5: ldm byte_c ;no carry, get shifted byte back and ls_store_5: stm double_long_a ;store shifted byte ret2 ;Subroutine to shift right one a 48-bit value ;48-bit value in double_long_a ;Call as level 2 subroutine ;shifted value returned in double_long_a sh_right_double ldm double_long_a stm byte_c andi 00000001b ;check rightmost bit stm rs_carry_out ;save for carry-in at next step ldm byte_c stm byte_a ;shift routine needs byte in byte_a call3(shift_right_one) stm double_long_a ;store shifted byte ldm rs_carry_out stm rs_carry_in ;carry-out becomes carry-in for next shift ldm double_long_a+1 ;get next byte to shift stm byte_c ;temp storage andi 00000001b stm rs_carry_out ;save carry-out before shift ldm byte_c stm byte_a call3(shift_right_one) ;shift one right stm byte_c ;temp store shifted byte ldm rs_carry_in jpz rs_no_carry_in_1 ;carry-in? ldi 10000000b ;no, skip carry-in orm byte_c ;yes, put carry in bit 7 and store jmp rs_store_1 rs_no_carry_in_1: ldm byte_c ;no carry, get shifted byte back and rs_store_1: stm double_long_a+1 ;store shifted byte ldm rs_carry_out stm rs_carry_in ;carry-out becomes carry-in for next shift ldm double_long_a+2 ;get next byte to shift stm byte_c ;temp storage andi 00000001b stm rs_carry_out ;save carry-out ldm byte_c stm byte_a call3(shift_right_one) stm byte_c ;temp store shifted byte ldm rs_carry_in jpz rs_no_carry_in_2 ;carry-in? ldi 10000000b ;no, skip carry-in orm byte_c ;yes, put carry in bit 7 and store jmp rs_store_2 rs_no_carry_in_2: ldm byte_c ;no carry, get shifted byte back and rs_store_2: stm double_long_a+2 ;store shifted byte ldm rs_carry_out stm rs_carry_in ;carry-out becomes carry-in for next shift ldm double_long_a+3 ;get next byte to shift stm byte_c ;temp storage andi 00000001b stm rs_carry_out ;save carry-out ldm byte_c stm byte_a call3(shift_right_one) stm byte_c ;temp store shifted byte ldm rs_carry_in jpz rs_no_carry_in_3 ;carry-in? ldi 10000000b ;no, skip carry-in orm byte_c ;yes, put carry in bit 7 and store jmp rs_store_3 rs_no_carry_in_3: ldm byte_c ;no carry, get shifted byte back and rs_store_3: stm double_long_a+3 ;store shifted byte ldm rs_carry_out stm rs_carry_in ;carry-out becomes carry-in for next shift ldm double_long_a+4 ;get next byte to shift stm byte_c ;temp storage andi 00000001b stm rs_carry_out ;save carry-out ldm byte_c stm byte_a call3(shift_right_one) stm byte_c ;temp store shifted byte ldm rs_carry_in jpz rs_no_carry_in_4 ;carry-in? ldi 10000000b ;no, skip carry-in orm byte_c ;yes, put in bit 7 and store jmp rs_store_4 rs_no_carry_in_4: ldm byte_c ;no carry, get shifted byte back and rs_store_4: stm double_long_a+4 ;store shifted byte ldm rs_carry_out stm rs_carry_in ;carry-out becomes carry-in for next shift ldm double_long_a+5 ;get next byte to shift stm byte_a call3(shift_right_one) stm byte_c ;temp store shifted byte ldm rs_carry_in jpz rs_no_carry_in_5 ;carry-in? ldi 10000000b ;no, skip carry-in orm byte_c ;yes, put in bit 7 and store jmp rs_store_5 rs_no_carry_in_5: ldm byte_c ;no carry, get shifted byte back and rs_store_5: stm double_long_a+5 ;store shifted byte ret2 ;Multiply long integers, using shift and add ;Call as level 1 subroutine ;Long words passed in long_a and long_b ;Product returned in double_long_b ;Uses double_long_a to hold multiplicand for shifting ;Uses double_long_b for 48-bit addition ;Uses long_c for mask for multiplicand bits in long_b multiply_long: ldi 0 stm double_long_a ;clear multiplicand word stm double_long_a+1 stm double_long_a+2 stm double_long_a+3 stm double_long_a+4 stm double_long_a+5 stm double_long_b ;clear product word stm double_long_b+1 stm double_long_b+2 stm double_long_b+3 stm double_long_b+4 stm double_long_b+5 stm long_c stm long_c+1 ldi 00000001b ;mask for multiplicand b bits stm long_c+2 ldm long_a+2 stm double_long_a+5 ;place multiplicand a in double_long_a ldm long_a+1 stm double_long_a+4 ldm long_a stm double_long_a+3 mult_long_loop: ldm long_b+2 ;check bit in multiplicand b with mask andm long_c+2 ;mask in long_c jpz mult_long_next_1 ;need to check all 3 bytes jmp mult_long_add ;bit is one, add mult_long_next_1: ldm long_b+1 andm long_c+1 jpz mult_long_next_2 jmp mult_long_add mult_long_next_2: ldm long_b andm long_c jpz mult_long_shift ;bit is zero, don't add, shift multiplicand mult_long_add: ldm double_long_b+5 ;bit is one, add multiplicand a to product b addm double_long_a+5 ;48-bit addition stm double_long_b+5 ;product will accumulate in double_long_b ldm double_long_b+4 adcm double_long_a+4 stm double_long_b+4 ldm double_long_b+3 adcm double_long_a+3 stm double_long_b+3 ldm double_long_b+2 adcm double_long_a+2 stm double_long_b+2 ldm double_long_b+1 adcm double_long_a+1 stm double_long_b+1 ldm double_long_b adcm double_long_a stm double_long_b ;partial product in double_long_b mult_long_shift: call2(sh_left_double) ;shifts multiplicand in double_long_a call2(shift_left_long) ;shifts mask in long_c left one ldm long_c ;check long_c if zero (24 shifts done) orm long_c+1 orm long_c+2 jpz mult_long_done ;mask bytes all zeros, done jmp mult_long_loop ;not zero, keep multiplying mult_long_done ret1 ;Subroutine for 24-bit division ;Call as level 1 ;Divisor passed in long_a ;Dividend passed in long_b ;Divisor and dividend words must be left-aligned before passing ;Does not check for zero divisor ;Uses double_long_a, b and c and long_d for calculation ;Quotient returned in long_c ;Remainder returned in long_r divide_long: ldi 0 ;clear variables used in calculation stm double_long_a stm double_long_a+1 stm double_long_a+2 stm double_long_a+3 stm double_long_a+4 stm double_long_a+5 stm double_long_b stm double_long_b+1 stm double_long_b+2 stm double_long_b+3 stm double_long_b+4 stm double_long_b+5 stm double_long_c stm double_long_c+1 stm double_long_c+2 stm double_long_c+3 stm double_long_c+4 stm double_long_c+5 stm long_c ;clear quotient stm long_c+1 stm long_c+2 ldi 10000000b ;Set up mask to OR-in quotient bits stm long_d ldi 0 stm long_d+1 stm long_d+2 ldi 24 stm divide_rounds ;maximum rounds of division ldm long_a ;set up divisor and dividend in 48-bit words stm double_long_a ;divisor ldm long_a+1 stm double_long_a+1 ldm long_a+2 stm double_long_a+2 ldm long_b ;dividend stm double_long_b ldm long_b+1 stm double_long_b+1 ldm long_b+2 stm double_long_b+2 long_divide_loop: ldm double_long_b+5 ;48-bit subtraction of divisor from dividend subm double_long_a+5 ;B - A is dividend - divisor stm double_long_c+5 ;result placed in double_long_c ldm double_long_b+4 ;move through bytes right to left sbbm double_long_a+4 stm double_long_c+4 ldm double_long_b+3 sbbm double_long_a+3 stm double_long_c+3 ldm double_long_b+2 ;move through bytes right to left sbbm double_long_a+2 stm double_long_c+2 ldm double_long_b+1 ;move through bytes right to left sbbm double_long_a+1 stm double_long_c+1 ldm double_long_b ;move through bytes right to left sbbm double_long_a stm double_long_c ;double_long_c now has result of subtraction jpc long_quotient_one ;no borrow, put 1 in quotient and replace dividend ldm divide_rounds ;borrow, leave 0 in quotient dec ;check if reached divide limit jpz long_divide_done ;24 rounds done, quit stm divide_rounds ;more rounds to do, go on call2(shift_right_long) ;shift mask in long_d right one jmp long_divisor_shift ;do not replace dividend, shift divisor long_quotient_one: ldm long_c ;place a one in quotient word orm long_d ;uses long_d as mask for quotient bits stm long_c ldm long_c+1 orm long_d+1 stm long_c+1 ldm long_c+2 orm long_d+2 stm long_c+2 ldm double_long_c ;replace dividend with subtracted dividend stm double_long_b ldm double_long_c+1 stm double_long_b+1 ldm double_long_c+2 stm double_long_b+2 ldm double_long_c+3 stm double_long_b+3 ldm double_long_c+4 stm double_long_b+4 ldm double_long_c+5 stm double_long_b+5 ldm double_long_b ;check if remainder zero orm double_long_b+1 orm double_long_b+2 orm double_long_b+3 orm double_long_b+4 orm double_long_b+5 jpz long_divide_done ;remainder zero, quit ldm divide_rounds ;remainder not zero, check if reached divide limit dec jpz long_divide_done ;24 rounds done, quit stm divide_rounds ;more rounds to do, go on call2(shift_right_long) ;subroutine shifts mask in long_d one right long_divisor_shift: call2(sh_right_double) ;shift divisor in double_long_a one position jmp long_divide_loop long_divide_done: ldm double_long_c+5 ;put remainder in long_r stm long_r+2 ldm double_long_c+4 stm long_r+1 ldm double_long_c+3 stm long_r ret1 ;Subroutine for division of floating point numbers ;Call as level 0 subroutine ;Performs fp_a divided by fp_b (that is, fp_a is dividend, fp_b is divisor) ;Uses long_a, long_b, long_c and long_d to perform calculation ;Quotient returned in fp_c ;Does not check for zero divisor divide_float: ;Calculate sign of quotient first (same as in multiplication) ldm fp_a xorm fp_b ;sign of result is XOR of signs of products andi 10000000b ;mask off remaining bits stm sign ;sign is 8-bit mask used to OR-in the sign bit ;Calculate exponent of quotient (same as in multiplication, except subtract exp of fp_b from exp fp_a ;Get exponent of a ldm fp_a ;need to get bit 0 of exponent from bit 7 of stm byte_a call3(shift_left_one) ;fp_a+1 and combine with the rest of the stm exponent_a ;exponent from fp_a ldm fp_a+1 ;is bit 7 one? andi 10000000b jpz dfp_next_2 ;no, skip OR-in (will have a zero from shift) ldm exponent_a ori 00000001b ;yes, OR-in a 1 in bit 0 of exponent byte stm exponent_a ;Remove exponent bias and save dfp_next_2: ldm exponent_a ;exponent_a has biased exponent subi 127 ;exponent bias stm exponent_a ;exponent_a has unbiased exponent ;Get exponent of b ldm fp_b ;need to get bit 0 of exponent from bit 7 of stm byte_a call3(shift_left_one) ;fp_a+1 and combine with the rest of the stm exponent_b ;exponent from fp_a ldm fp_b+1 ;is bit 7 one? andi 10000000b jpz dfp_next_3 ;no, skip OR-in (will have a zero from shift) ldm exponent_b ori 00000001b ;yes, OR-in a 1 in bit 0 of exponent byte stm exponent_b ;Remove exponent bias and save dfp_next_3: ldm exponent_b ;exponent_a has biased exponent subi 127 ;exponent bias stm exponent_b ;exponent_a has unbiased exponent ;Subtract unbiased exponents and save ldm exponent_a ;subtract unbiased exponents A - B subm exponent_b stm exponent_c ;exponent_c has unbiased exponent of quotient ;Divide significands ldm fp_a+1 ;need to set leftmost bit of significand to one ori 10000000b ;this bit is implied but not stored in fp stm long_b ;for divide_long routine, divisor must be ldm fp_a+2 ;in long_a, dividend in long_b stm long_b+1 ldm fp_a+3 stm long_b+2 ldm fp_b+1 ori 10000000b stm long_a ldm fp_b+2 stm long_a+1 ldm fp_b+3 stm long_a+2 call1(divide_long) ;returns quotient in long_c, remainder in long_r ;Rounding code after division ;If remainder returned in long_r is greater than or equal to half the divisor in long_a, add one to quotient in long_c ;First divide long_a by 2 using right shift, and add one if rightmost-bit one (round quotient up) ldm long_a ;put long_a into long_d stm long_d ldm long_a+1 stm long_d+1 ldm long_a+2 stm long_d+2 call2(shift_right_long) ;shifts long_d (divide by 2) ;long_d now holds long_a (divisor) divided by 2, subtract this from the remainder in long_r ldm long_r+2 ;long_r minus long_d subm long_d+2 ;do not store the result, only interested in final borrow ldm long_r+1 sbbm long_d+1 ldm long_r sbbm long_d jpc dfp_skip_3 ;no borrow jmp dfp_loop_1 ;borrow, so no round up (one-half divisor greater than rem.) dfp_skip_3 ldm long_c+2 ;no borrow, so round up quotient 24-bit add one addi 1 stm long_c+2 ldm long_c+1 adci 0 stm long_c+1 ldm long_c adci 0 stm long_c ;Normalize quotient dfp_loop_1: ldm long_c ;check leftmost bit of quotient andi 10000000b ;test leftmost bit of quotient jpz dfp_skip_4 jmp dfp_next_5 ;normalized, assemble final fp dfp_skip_4 call2(shift_left_long) ;not normalized, shift left and dec exponent ldm exponent_c dec stm exponent_c jmp dfp_loop_1 ;Assemble final fp dfp_next_5: ldm exponent_c ;First byte is sign bit and bits 7 to 1 of exponent addi 127 ;get quotient exponent and add bias stm exponent_c ;exponent_c now has biased exponent stm byte_a call3(shift_right_one) ;move over for sign bit orm sign ;put sign bit in stm fp_c ;First byte done ldm long_c ;get first byte of mantissa stm fp_c+1 ;store in second byte of fp ldm exponent_c ;check bit 0 of biased exponent andi 00000001b ;test bit 0 of exponent jpz dfp_skip_5 ;bit is 0, mask off bit 7 of fp_c+1 jmp dfp_next_6 ;bit is one, leave one in bit 7 of fp_c+1 dfp_skip_5 ldm fp_c+1 andi 01111111b stm fp_c+1 dfp_next_6: ldm long_c+1 ;get second and third quotient bytes stm fp_c+2 ldm long_c+2 stm fp_c+3 ;complete fp quotient now assembled in fp_c ret0 ;Subroutine to multiply two floating-point variables ;Call as level 0 subroutine ;Multiplies fp_a and fp_b ;Result in fp_c ;Uses long_a, long_b, and long_c multiply_float: ;Calculate sign of product first ldm fp_a xorm fp_b ;sign of result is XOR of signs of products andi 10000000b ;mask off remaining bits stm sign ;sign is 8-bit mask used to OR-in the sign bit ;Calculate exponent of product ;Get exponent of a ldm fp_a ;need to get bit 0 of exponent from bit 7 of stm byte_a call3(shift_left_one) ;fp_a+1 and combine with the rest of the stm exponent_a ;exponent from fp_a ldm fp_a+1 ;is bit 7 one? andi 10000000b jpz mfp_next_2 ;no, skip OR-in (will have a zero from shift) ldm exponent_a ori 00000001b ;yes, OR-in a 1 in bit 0 of exponent byte stm exponent_a ;Remove exponent bias and save mfp_next_2: ldm exponent_a ;exponent_a has biased exponent subi 127 ;exponent bias stm exponent_a ;exponent_a has unbiased exponent ;Get exponent of b ldm fp_b ;need to get bit 0 of exponent from bit 7 of stm byte_a call3(shift_left_one) ;fp_a+1 and combine with the rest of the stm exponent_b ;exponent from fp_a ldm fp_b+1 ;is bit 7 one? andi 10000000b jpz mfp_next_3 ;no, skip OR-in (will have a zero from shift) ldm exponent_b ori 00000001b ;yes, OR-in a 1 in bit 0 of exponent byte stm exponent_b ;Remove exponent bias and save mfp_next_3: ldm exponent_b ;exponent_a has biased exponent subi 127 ;exponent bias stm exponent_b ;exponent_a has unbiased exponent ;Add unbiased exponents and save ldm exponent_a ;add exponents addm exponent_b stm exponent_c ;exponent_c has unbiased exponent of product ;Multiply significands ldm fp_a+1 ;need to set leftmost bit of significand to one ori 10000000b ;this bit is implied but not stored in fp stm long_a ldm fp_a+2 stm long_a+1 ldm fp_a+3 stm long_a+2 ldm fp_b+1 ori 10000000b stm long_b ldm fp_b+2 stm long_b+1 ldm fp_b+3 stm long_b+2 call1(multiply_long) ;Normalize product ldm double_long_b ;put product in double_long_a for shift stm double_long_a ldm double_long_b+1 stm double_long_a+1 ldm double_long_b+2 stm double_long_a+2 ldm double_long_b+3 stm double_long_a+3 ldm double_long_b+4 stm double_long_a+4 ldm double_long_b+5 stm double_long_a+5 mfp_loop_1: ldm double_long_a ;check leftmost bit of product andi 10000000b jpz mfp_skip_3 ;not normalized, shift left and dec exponent jmp mfp_next_5 ;normalized, assemble final fp mfp_skip_3 call2(sh_left_double) ldm exponent_c dec stm exponent_c jmp mfp_loop_1 ;Rounding code ;Check high bit of double_long_a+3 ;If zero, no rounding (that is, round down) ;If one, check rest of bits in double_long_a+3, +4 and +5 ;If all zeros, round down ;If any ones, round up (add one to long word made of double_long_a, +1, +2) ;If rounding up produces carry-out, shift result right and increase exponent before assembling mfp_next_5: ldm double_long_a+3 andi 10000000b ;is bit 7 zero? jpz mfp_no_round ;yes, no round ldm double_long_a+3 ;no, check rest of long word for ones andi 01111111b ;mask off high bit orm double_long_a+4 orm double_long_a+5 jpz mfp_no_round ;no other zeros, no round mfp_round_up: ldm double_long_a+2 ;24-bit add one to three high bytes addi 1 stm double_long_a+2 ldm double_long_a+1 adci 0 stm double_long_a+1 ldm double_long_a adci 0 stm double_long_a jpc mfp_skip_6 ;carry-out, need to shift right and inc exponent jmp mfp_no_round ;no carry-out, assemble final fp product mfp_skip_6 call2(sh_right_double) ldm double_long_a ;if shift, need to put 1 back in leftmost ori 10000000b stm double_long_a ldm exponent_c inc stm exponent_c ;Assemble final fp mfp_no_round: ldm exponent_c ;First byte is sign bit and bits 7 to 1 addi 128 ;add bias+1 (normalized result has binary point after second digit) stm exponent_c ;exponent_c now has biased exponent stm byte_a call3(shift_right_one) ;move over for sign bit orm sign ;put sign bit in stm fp_c ;First byte done ldm double_long_a ;get first byte of mantissa stm fp_c+1 ;store in second byte of fp ldm exponent_c ;check bit 0 of biased exponent andi 00000001b ;test bit 0 of exponent jpz mfp_skip_7 jmp mfp_next_6 ;bit is one, leave one in bit 7 of fp_c+1 mfp_skip_7 ldm fp_c+1 ;bit is 0, mask off bit 7 of fp_c+1 andi 01111111b stm fp_c+1 mfp_next_6: ldm double_long_a+1 ;get second and third product bytes stm fp_c+2 ldm double_long_a+2 stm fp_c+3 ;complete fp product now assembled in fp_c ret0 ;Code to add two positive floating-point numbers ;Call as level 0 subroutine ;Addends passed in fp_a and fp_b ;Uses long_a and long_b, long_c, exponent_a, exponent_b and exponent_c in calculation ;Sum returned in fp_c add_float: ;Extract mantissas from float ldm fp_a+1 ;restore 1 to leftmost bit ori 10000000b stm long_a ;store mantissa in long word ldm fp_a+2 stm long_a+1 ldm fp_a+3 stm long_a+2 ldm fp_b+1 ori 10000000b stm long_b ldm fp_b+2 stm long_b+1 ldm fp_b+3 stm long_b+2 ;Extract exponents from float ldm fp_a ;get exponent_a stm byte_a call3(shift_left_one) ;push off sign bit, put zero in bit 0 stm exponent_a ldm fp_a+1 andi 10000000b ;get low-order bit of exponent jpz af_next_1 ;if zero, move on ldm exponent_a ;if one, make bit 0 one ori 00000001b stm exponent_a af_next_1: ldm fp_b ;get exponent_b same way stm byte_a call3(shift_left_one) stm exponent_b ldm fp_b+1 andi 10000000b jpz af_next_2 ldm exponent_b ori 00000001b stm exponent_b ;Compare exponents af_next_2: ldm exponent_a subm exponent_b ;does a-b jpc af_skip_1 ;exponent_b is less than or equal to exponent_a jmp af_next_3 ;exponent_b is greater than exponent_a af_skip_1 jpz af_add ;exponent_b is equal to exponent_a jmp af_next_4 ;exponent_b is less than exponent_a ;exponent_b > a -- shift mantissa of fp_a right and increment exponent_a until exponents equal af_next_3: ldm long_a stm long_d ldm long_a+1 stm long_d+1 ldm long_a+2 stm long_d+2 af_loop_1: call2(shift_right_long) ;subroutine shifts long_d ldm exponent_a inc stm exponent_a subm exponent_b jpz af_align_a_done ;exponents equal, done jmp af_loop_1 ;not done, continue to shift af_align_a_done: ldm long_d ;put shifted mantissa back in long_a stm long_a ldm long_d+1 stm long_a+1 ldm long_d+2 stm long_a+2 jmp af_add ;exponent_a > b -- shift mantissa of fp_b right and increment exponent_b until exponents equal af_next_4: ldm long_b stm long_d ldm long_b+1 stm long_d+1 ldm long_b+2 stm long_d+2 af_loop_2: call2(shift_right_long) ;subroutine shifts long_d ldm exponent_b inc stm exponent_b subm exponent_a jpz af_align_b_done ;exponents equal, done jmp af_loop_2 ;not done, continue to shift af_align_b_done: ldm long_d ;put shifted mantissa back in long_b stm long_b ldm long_d+1 stm long_b+1 ldm long_d+2 stm long_b+2 ;24-bit add of adjusted mantissas (exponents are equal) af_add: ldm exponent_a stm exponent_c ;final exponent of sum ldm long_a+2 addm long_b+2 stm long_c+2 ldm long_a+1 adcm long_b+1 stm long_c+1 ldm long_a adcm long_b stm long_c jpc af_skip_2 ;carry-out, shift right mantissa and inc exp jmp af_done ;no carry-out, done with math ;Carry-out from add, need to shift sum right and increment exponent af_skip_2 ldm long_c ;need to put sum in long_d for shift_right_long subroutine stm long_d ldm long_c+1 stm long_d+1 ldm long_c+2 stm long_d+2 call2(shift_right_long) ldm long_d ori 10000000b ;put 1 from carry-out in high-bit stm long_c ;store shifted mantissa in long_c ldm long_d+1 stm long_c+1 ldm long_d+2 stm long_c+2 ldm exponent_c ;increment exponent inc stm exponent_c ;Math done, assemble floating point af_done: ldm exponent_c ;First fp byte is sign bit and exp bits 7 to 1 stm byte_a call3(shift_right_one) ;move over for sign bit (zero here for positive) stm fp_c ;First byte done ldm long_c ;get first byte of mantissa stm fp_c+1 ;store in second byte of fp ldm exponent_c ;check bit 0 of biased exponent andi 00000001b ;test bit 0 of exponent jpz af_skip_3 jmp afp_next_6 ;bit is one, leave one in bit 7 of fp_c+1 af_skip_3 ldm fp_c+1 ;bit is 0, mask off bit 7 of fp_c+1 andi 01111111b stm fp_c+1 afp_next_6: ldm long_c+1 ;get second and mantissa bytes stm fp_c+2 ldm long_c+2 stm fp_c+3 ;complete fp quotient now assembled in fp_c ret0 ;Code to subtract two positive floating-point numbers ;Call as level 0 subroutine ;Numbers passed in fp_a and fp_b ;Performs fp_a - fp_b ;Uses long_a and long_b, long_c, exponent_a, exponent_b and exponent_c in calculation ;Difference returned in fp_c subtract_float: ldm fp_a+1 ;extract mantissas from float ori 10000000b ;restore 1 to leftmost bit stm long_a ldm fp_a+2 stm long_a+1 ldm fp_a+3 stm long_a+2 ldm fp_b+1 ori 10000000b ;restore 1 to leftmost bit stm long_b ldm fp_b+2 stm long_b+1 ldm fp_b+3 stm long_b+2 ;Result can be negative, so clear sign variable ldi 0 stm sign ;0 for positive result, 1 for negative ;Extract exponents from float ldm fp_a ;get exponent_a stm byte_a call3(shift_left_one) ;push off sign bit, sets bit 0 to 0 stm exponent_a ldm fp_a+1 andi 10000000b ;get low-order bit of exponent of fp_a jpz sf_next_1 ;if zero, leave it (will have 0 from shift) ldm exponent_a ;if one, put into exponent_a ori 00000001b stm exponent_a sf_next_1: ldm fp_b ;get exponent_b stm byte_a call3(shift_left_one) ;push off sign bit, sets bit 0 to 0 stm exponent_b ldm fp_b+1 andi 10000000b ;get low-order bit of exponent jpz sf_next_2 ;if zero, leave it ldm exponent_b ;if one, set it ori 00000001b stm exponent_b ;Compare exponents sf_next_2: ldm exponent_a subm exponent_b ;do a-b jpc sf_skip_1 ;exponent_a greater than or equal to exponent_b jmp sf_next_3 ;exponent_b is greater than exponent_a sf_skip_1 jpz sf_subtract ;exponent_a is equal to exponent_b jmp sf_next_4 ;exponent_a is greater than exponent_b ;Exponent_b > a -- shift long_a right and increment exponent_a until exponents equal sf_next_3: ldm long_a stm long_d ldm long_a+1 stm long_d+1 ldm long_a+2 stm long_d+2 sf_loop_1: call2(shift_right_long) ;subroutine shifts long_d ldm exponent_a inc stm exponent_a subm exponent_b jpz sf_align_a_done ;exponents equal, done jmp sf_loop_1 ;not done, continue to shift sf_align_a_done: ldm long_d ;put shifted mantissa back in long_a stm long_a ldm long_d+1 stm long_a+1 ldm long_d+2 stm long_a+2 jmp sf_subtract ;Exponent_a > b -- shift b right and increment exponent until exponents equal sf_next_4: ldm long_b stm long_d ldm long_b+1 stm long_d+1 ldm long_b+2 stm long_d+2 sf_loop_2: call2(shift_right_long) ;subroutine shifts long_d ldm exponent_b inc stm exponent_b subm exponent_a jpz sf_align_b_done ;exponents equal, done jmp sf_loop_2 ;not done, continue to shift sf_align_b_done: ldm long_d ;put shifted mantissa back in long_b stm long_b ldm long_d+1 stm long_b+1 ldm long_d+2 stm long_b+2 ;24-bit subtract of adjusted mantissas (exponents are equal) sf_subtract: ldm exponent_a stm exponent_c ;save the equalized exponent ldm long_a+2 ;does 24-bit a - b subm long_b+2 stm long_c+2 ldm long_a+1 sbbm long_b+1 stm long_c+1 ldm long_a sbbm long_b stm long_c jpc sf_skip_2 ;no borrow jmp sf_next_5 ;borrow requested, result negative sf_skip_2 ldm long_c ;result zero or positive, check if zero orm long_c+1 orm long_c+2 jpz sf_zero ;result zero, quit jmp sf_loop_3 ;result positive ;Subtraction result negative, long_c is a negative integer ;Final fp will have negative sign, with positive mantissa sf_next_5: ldi 10000000b ;change sign to negative stm sign ;Negate long_c (two's complement) ldm long_c ;complement long_c not stm long_c ldm long_c+1 not stm long_c+1 ldm long_c+2 not stm long_c+2 ;24-bit add 1 to long_c to finish two's complement ldm long_c+2 addi 1 stm long_c+2 ldm long_c+1 adci 0 stm long_c+1 ldm long_c adci 0 stm long_c ;Long_c now has two's complement of negative result, or positive result ;Normalize by shifting left long_c and decrementing exponent_c sf_loop_3: ldm long_c ;check for leftmost 1 andi 10000000b jpz sf_skip_4 ;shifting not done jmp sf_done ;shifting done sf_skip_4 call2(shift_left_long) ;shift long_c and decrement exponent ldm exponent_c dec stm exponent_c jmp sf_loop_3 ;Math done, assemble floating point sf_done: ldm exponent_c stm byte_a call3(shift_right_one) ;move over for sign bit orm sign ;OR-in sign bit stm fp_c ;First byte done ldm long_c ;get first byte of mantissa stm fp_c+1 ;store in second byte of fp ldm exponent_c ;check bit 0 of biased exponent andi 00000001b ;test bit 0 of exponent jpz sf_skip_5 jmp sf_next_6 ;bit is one, leave one in bit 7 of fp_c+1 sf_skip_5 ldm fp_c+1 ;bit is 0, mask off bit 7 of fp_c+1 andi 01111111b stm fp_c+1 sf_next_6: ldm long_c+1 ;get second and mantissa bytes stm fp_c+2 ldm long_c+2 stm fp_c+3 ;complete fp quotient now assembled in fp_c ret0 sf_zero: ldi 0 ;special zero fp value is 0x00000000 stm fp_c stm fp_c+1 stm fp_c+2 stm fp_c+3 ret0 ;Code for computing the square root of a positive floating point number ;Uses "Babylonian" method ;Call as level A subroutine ;Floating point number passed in fp_x ;Uses fp_a, fp_b, fp_c, fp_square ;Square root returned in fp_test ;Extract exponent from float sqrt_float: ldm fp_x ;get exponent_x stm byte_a call3(shift_left_one) ;push off sign bit stm exponent_x ldm fp_x+1 andi 10000000b ;get low-order bit of exponent jpz sqrt_next_1 ;if zero, leave it ldm exponent_x ;if one, set it ori 00000001b stm exponent_x sqrt_next_1: ldm exponent_x ;remove bias from exponent subm 127 stm exponent_x ;Create seed value (initial square root estimate) ldm exponent_x jpm sqrt_skip_1 ;if exponent negative, shift left jmp sqrt_next_a ;for positive exponent, shift right sqrt_skip_1 not ;2's complement negation of negative exponent inc stm byte_a call3(shift_left_one) ;for negative exponent need to shift left negated not ;convert back to negative inc jmp sqrt_next_b sqrt_next_a: stm byte_a call3(shift_right_one) ;divide exponent by 2 sqrt_next_b: addi 127 ;restore bias stm exponent_test ;Create floating point value from seed exponent ldm exponent_test stm byte_a call3(shift_right_one) stm fp_test ldm exponent_test andi 00000001b jpz sqrt_next_2 ldi 10000000b sqrt_next_2: stm fp_test+1 ;seed in fp_test will be 1 to the exponent_test power ldi 0 stm fp_test+2 stm fp_test+3 sqrt_loop: ldm fp_test ;multiply fp_test by itself (square it) stm fp_a stm fp_b ldm fp_test+1 stm fp_a+1 stm fp_b+1 ldm fp_test+2 stm fp_a+2 stm fp_b+2 ldm fp_test+3 stm fp_a+3 stm fp_b+3 call0(multiply_float) ldm fp_c ;square of test root into fp_square stm fp_square ldm fp_c+1 stm fp_square+1 ldm fp_c+2 stm fp_square+2 ldm fp_c+3 stm fp_square+3 ldm fp_x ;get ratio of fp_square and stm fp_a ;the original number fp_x ldm fp_x+1 stm fp_a+1 ldm fp_x+2 stm fp_a+2 ldm fp_x+3 stm fp_a+3 ldm fp_square stm fp_b ldm fp_square+1 stm fp_b+1 ldm fp_square+2 stm fp_b+2 ldm fp_square+3 stm fp_b+3 call0(divide_float) ;Extract exponent from fp_c (which is ratio between the square of the test root and fp_x) ldm fp_c stm byte_a call3(shift_left_one) ;also clears sign bit stm exponent_x ldm fp_c+1 ;check bit 0 of exponent andi 10000000b jpz sqrt_next_3 ;exponent bit 0 is zero, continue ldm exponent_x ;exponent bit 0 is one, set bit ori 00000001b stm exponent_x sqrt_next_3: ldi 127 ;is ratio small enough? subm exponent_x jpz sqrt_skip_2 ;exponent of ratio = 0, ratio close to 1 jmp sqrt_next_4 ;see if exponent of ratio -1 ;if exponent of ratio 0, check mantissa bytes for zeros sqrt_skip_2 ldm fp_c+1 ;for exponent of ratio = 0, stm byte_a ;check mantissa bytes for zeros call3(shift_left_one) ;knock off high order bit (last bit of exponent) orm fp_c+2 jpz sqrt_skip_3 ;first two bytes of mantissa zero, check third jmp sqrt_next_5 ;ratio not close enough, make new root and try again sqrt_skip_3 ldm fp_c+3 andi 11111100b jpz sqrt_done ;ratio close enough to 1, quit jmp sqrt_next_5 ;ratio not close enough, make new root and try again sqrt_next_4: ldi 126 subm exponent_x ;is ratio small enough? jpz sqrt_skip_4 ;exponent of ratio = -1, ratio could be close to 1 jmp sqrt_next_5 ;exponent neither 127 or 126, make new root ;if exponent of ratio -1, check mantissa bytes for ones sqrt_skip_4 ldi 01111111b ;high bit will be zero because exp is 126 subm fp_c+1 ;if fp_c+1 all 1's, result will be zero jpz sqrt_skip_5 ;might be close enough, check rest of bytes jmp sqrt_next_5 ;not close enough, make new root and try again sqrt_skip_5 ldm fp_c+2 ;check next byte xori 11111111b ;result zero if all bits are ones jpz sqrt_skip_6 ;might be close enough, check last byte jmp sqrt_next_5 ;not close enough, make new root and try again sqrt_skip_6 ldm fp_c+3 ;check last byte andi 11111100b ;sets bits 0 and 1 to zero xori 11111100b ;checks bits 2 to 7 if ones jpz sqrt_done ;ratio close enough to 1, quit ;Make new test root ;First divide fp_x (in fp_a) by last test root (in fp_b) ;Quotient returned if fp_c sqrt_next_5: ldm fp_x stm fp_a ldm fp_x+1 stm fp_a+1 ldm fp_x+2 stm fp_a+2 ldm fp_x+3 stm fp_a+3 ldm fp_test stm fp_b ldm fp_test+1 stm fp_b+1 ldm fp_test+2 stm fp_b+2 ldm fp_test+3 stm fp_b+3 call0(divide_float) ;Add test root to quotient ldm fp_c stm fp_a ldm fp_c+1 stm fp_a+1 ldm fp_c+2 stm fp_a+2 ldm fp_c+3 stm fp_a+3 ldm fp_test stm fp_b ldm fp_test+1 stm fp_b+1 ldm fp_test+2 stm fp_b+2 ldm fp_test+3 stm fp_b+3 call0(add_float) ;Divide sum by two ldm fp_c stm fp_a ldm fp_c+1 stm fp_a+1 ldm fp_c+2 stm fp_a+2 ldm fp_c+3 stm fp_a+3 ldi 40h ;fp for two is 0x40000000 stm fp_b ldi 0 stm fp_b+1 stm fp_b+2 stm fp_b+3 call0(divide_float) ;New quotient becomes new test root ldm fp_c stm fp_test ldm fp_c+1 stm fp_test+1 ldm fp_c+2 stm fp_test+2 ldm fp_c+3 stm fp_test+3 jmp sqrt_loop sqrt_done: retA ;Subroutine to convert a 24-bit hex integer to a decimal string ;Hex integer passed in long_a ;Uses long_b for temp storage ;Decimal string returned in dec_str_buff ;Call as level 0 subroutine ;Start with ten-millions long_to_dec_str ldi 30h ;character for zero stm char l2d_loop_1 ldm long_a+2 ;rightmost byte subi 80h ;ten-millions hex is 0x989680 stm long_b+2 ;24-bit subtraction ldm long_a+1 sbbi 96h stm long_b+1 ldm long_a sbbi 98h stm long_b jpc l2d_next_1 ;no borrow jmp l2d_next_2 ;borrow, done with ten-millions l2d_next_1 ldm char inc stm char ldm long_b stm long_a ldm long_b+1 stm long_a+1 ldm long_b+2 stm long_a+2 jmp l2d_loop_1 l2d_next_2 ldm char stm dec_str_buff+2 ;ten-millions place ;Millions ldi 30h ;character for zero stm char l2d_loop_2 ldm long_a+2 ;rightmost byte subi 40h ;millions hex is 0x0F4240 stm long_b+2 ;24-bit subtraction ldm long_a+1 sbbi 42h stm long_b+1 ldm long_a sbbi 0Fh stm long_b jpc l2d_next_3 ;no borrow jmp l2d_next_4 ;borrow, done with millions l2d_next_3 ldm char ;increment digit inc stm char ldm long_b ;replace long_a with result of subtraction stm long_a ldm long_b+1 stm long_a+1 ldm long_b+2 stm long_a+2 jmp l2d_loop_2 ;loop again l2d_next_4 ldm char stm dec_str_buff+3 ;millions place ;Hundred-thousands ldi 30h ;character for zero stm char l2d_loop_3 ldm long_a+2 ;rightmost byte subi 0A0h ;hundred-thousand hex is 0x0186A0 stm long_b+2 ;24-bit subtraction ldm long_a+1 sbbi 86h stm long_b+1 ldm long_a sbbi 01h stm long_b jpc l2d_next_5 ;no borrow jmp l2d_next_6 ;borrow, done with hundred-thousands l2d_next_5 ldm char ;increment digit inc stm char ldm long_b ;replace long_a with result of subtraction stm long_a ldm long_b+1 stm long_a+1 ldm long_b+2 stm long_a+2 jmp l2d_loop_3 ;loop again l2d_next_6 ldm char stm dec_str_buff+4 ;hundred-thousands place ;Ten-thousands ldi 30h ;character for zero stm char l2d_loop_4 ldm long_a+2 ;rightmost byte subi 10h ;ten-thousand hex is 0x002710 stm long_b+2 ;24-bit subtraction ldm long_a+1 sbbi 27h stm long_b+1 ldm long_a sbbi 00h stm long_b jpc l2d_next_7 ;no borrow jmp l2d_next_8 ;borrow, done with ten-thousands l2d_next_7 ldm char ;increment digit inc stm char ldm long_b ;replace long_a with result of subtraction stm long_a ldm long_b+1 stm long_a+1 ldm long_b+2 stm long_a+2 jmp l2d_loop_4 ;loop again l2d_next_8 ldm char stm dec_str_buff+5 ;ten-thousands place ;Thousands ldi 30h ;character for zero stm char l2d_loop_5 ldm long_a+2 ;rightmost byte subi 0E8h ;One-thousand hex is 0x0003E8 stm long_b+2 ;24-bit subtraction ldm long_a+1 sbbi 03h stm long_b+1 ldm long_a sbbi 00h stm long_b jpc l2d_next_9 ;no borrow, not done jmp l2d_next_10 ;borrow, done with one-thousands l2d_next_9 ldm char ;increment digit inc stm char ldm long_b ;replace long_a with result of subtraction stm long_a ldm long_b+1 stm long_a+1 ldm long_b+2 stm long_a+2 jmp l2d_loop_5 ;loop again l2d_next_10 ldm char stm dec_str_buff+6 ;one-thousands place ;Hundreds ldi 30h ;character for zero stm char l2d_loop_6 ldm long_a+2 ;rightmost byte subi 64h ;One-hundred hex is 0x000064 stm long_b+2 ;24-bit subtraction ldm long_a+1 sbbi 00h stm long_b+1 ldm long_a sbbi 00h stm long_b jpc l2d_next_11 ;no borrow, not done jmp l2d_next_12 ;borrow, done with one-hundreds l2d_next_11 ldm char ;increment digit inc stm char ldm long_b ;replace long_a with result of subtraction stm long_a ldm long_b+1 stm long_a+1 ldm long_b+2 stm long_a+2 jmp l2d_loop_6 ;loop again l2d_next_12 ldm char stm dec_str_buff+7 ;hundreds place ;Tens ldi 30h ;character for zero stm char l2d_loop_7 ldm long_a+2 ;rightmost byte subi 0Ah ;Ten hex is 0x00000A stm long_b+2 ;24-bit subtraction ldm long_a+1 sbbi 00h stm long_b+1 ldm long_a sbbi 00h stm long_b jpc l2d_next_13 ;no borrow, not done jmp l2d_next_14 ;borrow, done with tens l2d_next_13 ldm char ;increment digit inc stm char ldm long_b ;replace long_a with result of subtraction stm long_a ldm long_b+1 stm long_a+1 ldm long_b+2 stm long_a+2 jmp l2d_loop_7 ;loop again l2d_next_14 ldm char stm dec_str_buff+8 ;tens place ;Ones ldi 30h ;character for zero stm char l2d_loop_8 ldm long_a+2 ;rightmost byte subi 01h ;One hex is 0x000001 stm long_b+2 ;24-bit subtraction ldm long_a+1 sbbi 00h stm long_b+1 ldm long_a sbbi 00h stm long_b jpc l2d_next_15 ;no borrow, not done jmp l2d_next_16 ;borrow, done with ones l2d_next_15 ldm char ;increment digit inc stm char ldm long_b ;replace long_a with result of subtraction stm long_a ldm long_b+1 stm long_a+1 ldm long_b+2 stm long_a+2 jmp l2d_loop_8 ;loop again l2d_next_16 ldm char stm dec_str_buff+9 ;ones place ldi 0 stm dec_str_buff+10 ;terminating zero ret0 ;Subroutine to convert a binary float to a decimal fixed-point string ;Float passed in fp_a ;String returned in dec_out_str ;Uses long_d and long_c as temp storage ;Call as level A subroutine float_to_dec ldm fp_a ;get exponent from float stm byte_a call3(shift_left_one) stm exponent_a ldm fp_a+1 ;Check bit 0 of exponent andi 10000000b jpz f2d_next_1 ;if zero, done ldm exponent_a ;if one, set it ori 00000001b stm exponent_a f2d_next_1 ldm exponent_a ;remove bias from exponent subi 127 stm exponent_a ldm fp_a+1 ;get mantissa stm long_a ldm fp_a+2 stm long_a+1 ldm fp_a+3 stm long_a+2 ldm long_a ;make sure high bit is one ori 10000000b stm long_a ldm exponent_a jpm f2d_next_2 ;negative exponent subi 24 ;check range of positive exponent jpc f2d_err_hi ;out of range high (exp 24 or greater) jmp f2d_next_3 ;in range, shift f2d_next_2 not ;negate exponent inc subi 24 ;check range jpc f2d_err_lo ;out of range low (exp -24 or less) jmp f2d_next_4 ;in range, shift ;Positive exponent in range f2d_next_3 ldi 23 subm exponent_a stm shift_steps ;number of times to shift right to get integer part ldm long_a ;shift_right_long needs value in long_d stm long_d ldm long_a+1 stm long_d+1 ldm long_a+2 stm long_d+2 f2d_loop_1 ldm shift_steps jpz f2d_next_5 ;done shifting dec ;not done, shift and loop stm shift_steps call2(shift_right_long) jmp f2d_loop_1 ;Convert integer portion to decimal string f2d_next_5 ldm long_a ;save unshifted mantissa temporarily in long_c stm long_c ldm long_a+1 stm long_c+1 ldm long_a+2 stm long_c+2 ldm long_d ;place shifted mantissa in long_a stm long_a ldm long_d+1 stm long_a+1 ldm long_d+2 stm long_a+2 call0(long_to_dec_str) ;result in dec_str_buff ;This section uses an indexed ldm and stm instructions to transfer digits to the output string ldm dec_out_str ;initialize output string pointer stm dec_out_ptr ldm dec_out_str+1 stm dec_out_ptr+1 ldm fp_a ;check sign bit andi 10000000b jpz f2d_skip_1 ;positive, skip minus sign placement ldi 2Dh ;minus sign stm dec_out_str+2 ;place in output string ldm dec_out_ptr ;increment output string pointer inc stm dec_out_ptr ldm dec_out_ptr+1 adci 0 stm dec_out_ptr+1 f2d_skip_1 ldm dec_str_buff ;Get address of source buffer stm f2d_loop_2+1 ;Place as target of indexed ldm instruction ldm dec_str_buff+1 stm f2d_loop_2+2 f2d_loop_2 ldm 0000h ;address will change during program run jpz f2d_next_7 ;string terminator, done with transfer subi 30h ;skip leading zeros jpz f2d_next_6 addi 30h ;restore ASCII value for non-zero character jmp f2d_skip_2 f2d_next_6 ldm f2d_loop_2+1 ;increment address of ldm instruction inc ;low byte of source address stm f2d_loop_2+1 ldm f2d_loop_2+2 ;high byte of source address adci 0 stm f2d_loop_2+2 jmp f2d_loop_2 f2d_skip_2 stm char ldm f2d_loop_2+1 ;pass address to next indexed ldm stm f2d_loop_3+1 ldm f2d_loop_2+2 stm f2d_loop_3+2 ldm dec_out_ptr ;Get target buffer pointer stm f2d_indx_stm+1 ;Place as target of indexed stm instruction ldm dec_out_ptr+1 stm f2d_indx_stm+2 ldm char f2d_indx_stm stm 0000h ;indexed store instruction ldm f2d_indx_stm+1 ;increment address of stm instruction inc stm f2d_indx_stm+1 ldm f2d_indx_stm+2 adci 0 stm f2d_indx_stm+2 ldm f2d_loop_3+1 ;increment address of ldm instruction inc ;low byte of source address stm f2d_loop_3+1 ldm f2d_loop_3+2 ;high byte of source address adci 0 stm f2d_loop_3+2 f2d_loop_3 ldm 0000h jpz f2d_next_7 ;string terminator jmp f2d_indx_stm f2d_next_7 ldm f2d_indx_stm+1 ;save pointer stm f2d_indx_stm2+1 ldm f2d_indx_stm+2 stm f2d_indx_stm2+2 ldi 2Eh ;dot character f2d_indx_stm2 stm 0000h ;place decimal point character in output string ldm f2d_indx_stm2+1 inc stm f2d_indx_stm3+1 stm dec_out_ptr ;save string pointer ldm f2d_indx_stm2+2 adci 0 stm f2d_indx_stm3+2 stm dec_out_ptr+1 ldi 30h ;zero character f2d_indx_stm3 stm 0000h ;place zero after decimal point ldm f2d_indx_stm3+1 inc stm f2d_indx_stmA+1 ldm f2d_indx_stm3+2 adci 0 stm f2d_indx_stmA+2 ldi 0 f2d_indx_stmA stm 0000h ;string termination (in case no fraction) ;Get fraction part from fp with positive or zero exponent ldm frac_table_addr ;initialize fraction table pointer stm frac_table_ptr ldm frac_table_addr+1 stm frac_table_ptr+1 ldi 00h ;initialize hex_frac to zero stm hex_frac stm hex_frac+1 stm hex_frac+2 ldm long_c ;get unshifted mantissa back stm long_a ;store in long_a ldm long_c+1 stm long_a+1 ldm long_c+2 stm long_a+2 ldm exponent_a ;unbiased positive exponent stm shift_steps ;number of shifts to get fraction bits to left ldi 1 stm int_flag ;1 if fp integer, 0 if not f2d_frac_loop1 call2(shift_left_long) ;shifts long_c ldm shift_steps dec jpz f2d_frac_loop2 stm shift_steps jmp f2d_frac_loop1 f2d_frac_loop2 call2(shift_left_long) ldm long_c ;check if frac part zero orm long_c+1 orm long_c+2 jpz f2d_frac_done ;yes, shifting done ldi 0 stm int_flag ;indicates fp is not an integer ldm long_c ;no andi 10000000b ;one in leftmost bit? jpz f2d_next_9 ;no, go to next step ldm frac_table_ptr ;yes, add partial fraction stm f2d_indx_ldm1+1 ldm frac_table_ptr+1 stm f2d_indx_ldm1+2 f2d_indx_ldm1 ldm 0000h ;program will place target stm long_b ;temp store of fraction part ldm f2d_indx_ldm1+1 ;increment pointer inc stm f2d_indx_ldm2+1 ldm f2d_indx_ldm1+2 adci 0 stm f2d_indx_ldm2+2 f2d_indx_ldm2 ldm 0000h stm long_b+1 ldm f2d_indx_ldm2+1 inc stm f2d_indx_ldm3+1 ldm f2d_indx_ldm2+2 adci 0 stm f2d_indx_ldm3+2 f2d_indx_ldm3 ldm 0000h stm long_b+2 ldm f2d_indx_ldm3+1 ;increment pointer inc stm frac_table_ptr ;and store ldm f2d_indx_ldm3+2 adci 0 stm frac_table_ptr+1 ldm hex_frac addm long_b stm hex_frac ldm hex_frac+1 adcm long_b+1 stm hex_frac+1 ldm hex_frac+2 adcm long_b+2 stm hex_frac+2 jmp f2d_frac_loop2 f2d_next_9 ldm frac_table_ptr ;increment table pointer addi 3 stm frac_table_ptr ldm frac_table_ptr+1 adci 0 stm frac_table_ptr+1 jmp f2d_frac_loop2 f2d_frac_done ldm int_flag ;is fp an integer? jpz f2d_skip_3 ;no, create dec frac string jmp f2d_next_10 ;yes, all done f2d_skip_3 ldm long_a ;store long_a (needed? maybe not) stm long_c ldm long_a+1 stm long_c+1 ldm long_a+2 stm long_c+2 ldm hex_frac+2 ;put hex_frac into long_a and stm long_a ;reverse byte order because ldm hex_frac+1 ;long_to_dec_str expects stm long_a+1 ;big-endian long value ldm hex_frac stm long_a+2 call0(long_to_dec_str) ;Transfer decimal fraction string from dec_str_buff to dec_out_str ldm dec_str_buff ;Get address of source buffer inc ;Skip first character stm f2d_loop_4+1 ;Place as target of indexed ldm instruction ldm dec_str_buff+1 adci 0 stm f2d_loop_4+2 ldm dec_out_ptr ;Get target buffer pointer stm f2d_indx_stm4+1 ;Place as target of indexed stm instruction ldm dec_out_ptr+1 stm f2d_indx_stm4+2 f2d_loop_4 ldm 0000h ;address will change during program run f2d_indx_stm4 stm 0000h ;indexed store instruction jpz f2d_next_10 ;string terminator, done with transfer ldm f2d_indx_stm4+1 ;increment address of stm instruction inc stm f2d_indx_stm4+1 ldm f2d_indx_stm4+2 adci 0 stm f2d_indx_stm4+2 ldm f2d_loop_4+1 ;increment address of ldm instruction inc ;low byte of source address stm f2d_loop_4+1 ldm f2d_loop_4+2 ;high byte of source address adci 0 stm f2d_loop_4+2 jmp f2d_loop_4 f2d_next_10 retA ;Negative exponent in range f2d_next_4 jmp f2d_quit ;Exponent out-of-range errors f2d_err_hi ldm range_err_hi stm ws_inst+1 ldm range_err_hi+1 stm ws_inst+2 call0(write_string) jmp f2d_quit f2d_err_lo ldm range_err_lo stm ws_inst+1 ldm range_err_lo+1 stm ws_inst+2 call0(write_string) f2d_quit retA return .set 0900h ;assembler needs variable label set back to original value .end