В тази статия ще се задълбочим в процеса на създаване на преобразувател на дроб към десетичен знак, процент и обратен преобразувател за Commodore 64, използвайки асемблерен език (6510/6502). Този проект не само предоставя практическо приложение на уменията за програмиране на асемблиране, но също така ни позволява да изследваме носталгичния чар на компютрите от 80-те години.
Постановка на проблема
Носталгия по 80-те
Докато прекосяваме машината на времето, се озоваваме в 80-те години, където писането на математически програми за Commodore 64 не е просто хоби, а част от училищен курс. В тази статия започваме нашето пътуване, за да създадем преобразувател на дроби, на пръв поглед прост, но проницателен проект за усъвършенстване на езиковите ни умения за Асемблер.
Тази статия продължава темата, която започнах в предишни статии:
- „Ретро приключение: внедряване на калкулатор за съотношение на страните за Commodore 64 на множество езици за програмиране“
- Пътуване във времето от 80-те години: Математика на Commodore 64 с приближение по квадратен корен и разлагане на множители чрез асемблиране
Решение
Изграждане на BASIC прототип
Традиционно, ние започваме нашата реализация с прототип в BASIC. Прототипът служи като основа, която ни позволява да визуализираме структурата и цялостния дизайн на програмата.
Два забележителни аспекта на прототипа включват:
- Изпълнение на менюто: Ние определяме опциите на менюто.
- Изчисляване на експонента: Използване на дължината на текстово представяне на числа за изчисляване на степента.
Преминаване към асемблер
След като разгледахме множество подробности в предишни статии, ние ще се съсредоточим върху логиката на високо ниво на нашето решение за сглобяване, заедно с иновативните подходи, които сме възприели.
Работа с менюто
След настройката на екрана и показването на подсказка, функцията за показване на менюто заема централно място като първоначална функция на програмата. Тази функция ефективно показва елементи от менюто и обработва въведеното от потребителя. Ако потребителят въведе невалидна опция, програмата елегантно я игнорира. Впоследствие той извиква съответната процедура въз основа на въведеното от потребителя.
main: jsr prepare_screen jsr main_usage menu: jsr show_menu wait_for_continue: jsr getin beq wait_for_continue cmp #q_sym beq go_to_exit cmp #one_sym beq handle_decimal cmp #two_sym beq handle_fraction cmp #three_sym beq handle_percent jsr clearscreen jmp menu handle_decimal: jsr decimal_handler jmp continue_or_exit handle_fraction: jsr fraction_handler jmp continue_or_exit handle_percent: jsr percent_handler jmp continue_or_exit go_to_exit: jmp restore_and_exit continue_or_exit: jsr usage_at_exit wait_for_input: jsr getin beq wait_for_input cmp #q_sym bne continue jmp restore_and_exit continue: jsr clearscreen jmp menu restore_and_exit: jsr restore_screen rts
Десетично преобразуване
decimal_handler: jsr input_decimal jsr cursor_blink_off jsr calculate_den lda #<n ldy #>n jsr fp_load_ram_to_fac lda #<den ldy #>den jsr fp_mult ldx #<num ldy #>num jsr fp_store_fac_to_ram lda #<hundred ldy #>hundred jsr fp_load_ram_to_fac lda #<n ldy #>n jsr fp_mult ldx #<per ldy #>per jsr fp_store_fac_to_ram jsr show_results rts input_decimal: jsr input_decimal_prompt jsr input_string_proc jsr string_to_fp ldx #<n ldy #>n jsr fp_store_fac_to_ram jsr get_exponent_by_counter lda #space_sym jsr print_char lda #new_line jsr print_char rts
Нашата процедура за обработка на десетични числа приема десетичен знак като аргумент и го преобразува в дроб и процент. Тази рутина започва с процедура за въвеждане, подобна на нашата предишна дискусия. Ключовата разлика е в изчисляването на експонентата въз основа на въведения брой знаци.
get_exponent_by_counter: ldx counter dex txa sta e_counter lda number_strings clc adc counter sta address dec address lda #<(address) sta $22 lda #>(address) sta $23 lda #string_length jsr fp_string_to_fac ldx #<e ldy #>e jsr fp_store_fac_to_ram rts
Тази процедура прави следното:
- Намалява стойността на брояча с единица и съхранява получената стойност в броячите на показателите.
- Зарежда в акумулатора адреса на началото на масива от низово представяне на числа.
- Добавя към резултата брояча на въведените символи, записани в променлива.
- Тъй като отместването се брои от 0, намалява стойността с единица.
- След това пълният адрес на елемента на масива се зарежда с отместване.
- Низът на посочения адрес се преобразува в число с плаваща запетая и се съхранява в променливата e (експонента).
Масивът с числови низове изглежда по следния начин:
number_strings: .text "0" .byte $0 .text "1" .byte $0 .text "2" .byte $0 .text "3" .byte $0 .text "4" .byte $0 .text "5" .byte $0 .text "6" .byte $0 .text "7" .byte $0 .text "8" .byte $0 .text "9" .byte $0 .text "10" .byte $0 .text "11" .byte $0 .text "12" .byte $0 .text "13" .byte $0 .text "14" .byte $0 .text "15" .byte $0
След това в десетичния манипулатор се извиква процедура за изчисляване на знаменателя.
calculate_den: ldx e_counter dex beq handle_tenth txa sta counter lda #<ten ldy #>ten jsr fp_load_ram_to_fac mult_loop: lda #<ten ldy #>ten jsr fp_mult ldx counter dex beq end_loop txa sta counter jmp mult_loop end_loop: ldx #<den ldy #>den jsr fp_store_fac_to_ram jmp end_mult handle_tenth: lda #<ten ldy #>ten jsr fp_load_ram_to_fac ldx #<den ldy #>den jsr fp_store_fac_to_ram end_mult: rts
Тази рутина изчислява десет, захранвано от експонента, като използва умножение и стойността на e_counter, получена в предишната рутина.
Освен това получавам числителя, като умножа въведеното число по знаменателя.
И като умножа въведеното число по 100, получавам процента.
След това показвам резултата чрез отделна процедура.
show_results: lda #space_sym jsr print_char lda #new_line jsr print_char lda #<result_1 ldy #>result_1 jsr print_str lda #<n ldy #>n jsr fp_load_ram_to_fac jsr fp_to_str jsr print_str lda #new_line jsr print_char lda #<result_2 ldy #>result_2 jsr print_str lda #<num ldy #>num jsr fp_load_ram_to_fac jsr fp_to_str jsr print_str lda #<result_3 ldy #>result_3 jsr print_str lda #<den ldy #>den jsr fp_load_ram_to_fac jsr fp_to_str jsr print_str lda #new_line jsr print_char lda #<result_4 ldy #>result_4 jsr print_str lda #<per ldy #>per jsr fp_load_ram_to_fac jsr fp_to_str jsr print_str lda #new_line jsr print_char lda #new_line jsr print_char rts
Ограничения на тази реализация:
- Функцията работи само с дроби ‹ 1.
- Формат на въвеждане „.123“ без водеща нула.
Обработка на дроби
Процесорът на дроби приема аргументите на числителя и знаменателя, като ги преобразува в десетични знаци и проценти.
fraction_handler: jsr input_num_den jsr cursor_blink_off lda #<den ldy #>den jsr fp_load_ram_to_fac lda #<num ldy #>num jsr fp_div ldx #<n ldy #>n jsr fp_store_fac_to_ram lda #<hundred ldy #>hundred jsr fp_load_ram_to_fac lda #<n ldy #>n jsr fp_mult ldx #<per ldy #>per jsr fp_store_fac_to_ram jsr show_results rts
Десетична запетая се получава чрез разделяне на числителя на знаменателя.
Процентите се получават чрез умножаване на десетична запетая по 100.
Процентно преобразуване
Процентният манипулатор приема процентни стойности като вход и ги преобразува в дроби и десетични знаци.
percent_handler: jsr input_percents lda #<hundred ldy #>hundred jsr fp_load_ram_to_fac lda #<per ldy #>per jsr fp_div ldx #<n ldy #>n jsr fp_store_fac_to_ram lda #<per ldy #>per jsr fp_load_ram_to_fac ldx #<num ldy #>num jsr fp_store_fac_to_ram lda #<hundred ldy #>hundred jsr fp_load_ram_to_fac ldx #<den ldy #>den jsr fp_store_fac_to_ram jsr show_results rts
Десетична запетая се получава чрез разделяне на процент на 100.
Нормално: числител въведен процент знаменател 100.
Тази функция има ограничение: може да коригира обработката само на цели проценти.
Заключение
В това пътуване през математическото царство на Commodore 64, ние разработихме конвертор на дроби на асемблер. Можете да намерите пълния изходен код за тази програма [тук].
Ето пример за изпълнение
Двоичният файл е с размер 3220 байта.
Въпреки че училищната математика може да изглежда елементарна, тя предоставя отлична площадка за усъвършенстване на уменията за програмиране на сглобяване. Този проект демонстрира творческите възможности, които ерата на 80-те и Commodore 64 предлагат.
Докато продължаваме това вълнуващо пътешествие, ви каня да останете с мен за още математически приключения в света на програмирането на Commodore 64.