В этой статье мы углубимся в процесс создания преобразователя дробей в десятичные, проценты и обратно для 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.