@@ -105,7 +105,7 @@ WRSNG:
105105 CALL FUNPK ; число печатается в буфер BUFOUT
106106 MOV #BUFOUT, R0
107107 CALL WRST ; выводим строку на экран
108- 9$: JMP @#000000
108+ 9$: JMP @#000000 ; возврат, адрес подставляется в начале
109109
110110;#####################################################################
111111;## WRST
@@ -896,6 +896,177 @@ GRIZT: MOV (SP)+,R3 ;
896896 MOV R2,R3 ; иначе восстанавливаем R2
8978972$: RETURN
898898
899+ ;#####################################################################
900+ ;## FRND
901+ ;## Need FADD
902+ ;## Need FSUB
903+ ;## Need FMUL
904+ ;## Need FDIV
905+ ; Генератор псевдо-случайных чисел.
906+ ; На основе кода процедуры RAN из реализации Бейсик Вильнюс для УКНЦ.
907+ ; На входе: (SP) адрес возврата
908+ ; (SP+2)(SP+4) = управляющий параметр:
909+ ; >0: получить очередное псевдо-случайное число
910+ ; <0: задаёт начальное значение
911+ ; 0: вернуть предыдущее псевдо-случайное число
912+ ; Результат: (SP)(SP+2) псевдо-случайное число в диапазоне [0,1)
913+ FRND:
914+ MOV (SP)+, FRND$X+2 ; сохраняем адрес для выхода
915+ TST (SP) ; проверяем старшее слово параметра
916+ BEQ 26$ ; параметр 0 => отдать текущее значение
917+ BPL 1$ ; > 0 => генерация следующего
918+ ; Параметр < 0 ? инициализация
919+ CLR RNDSAV ; сбросить сохранённое значение
920+ MOV #040311, FRND$I ; начальное состояние = PI/2
921+ MOV #007733, FRND$I+2
922+ 1$: MOV #FRND$I, R2 ; адрес состояния (старшее слово)
923+ MOV #FRND$I+2, R3 ; адрес состояния (младшее слово)
924+ MOV (R2), R0 ; загрузить текущее состояние
925+ MOV (R3), R1
926+ BEQ 21$ ; если ноль, особая инициализация
927+ ; state = (state * 3 + 1) mod 2^31
928+ ASL R1 ; умножить на 2
929+ ROL R0
930+ ADD (R2), R0 ; state*3
931+ ADD (R3), R1
932+ ADC R0
933+ ADD (R3), R0 ; + state (младшее слово) -> state*3 + 1
934+ BPL 2$ ; если нет переполнения знакового бита
935+ ADD #100000,R0 ; инвертировать знаковый бит
936+ ;RAN2:
937+ 2$: MOV R0, (R2) ; сохранить новое состояние в III
938+ MOV R1, (R3)
939+ MOV #201,R2 ; начальная экспонента = 129.
940+ 4$: ASL R1 ; нормализация:
941+ ROL R0 ; сдвигать мантиссу, пока старшая единица не выйдет в C
942+ BCS 23$
943+ DEC R2 ; уменьшать экспоненту
944+ BR 4$
945+ ;RAN3: Упаковка в формат float: знак = 0, экспонента = R2, мантисса из старших битов R0,R1
946+ 23$: CLRB R1
947+ BISB R0,R1
948+ SWAB R1
949+ CLRB R0
950+ BISB R2,R0
951+ SWAB R0
952+ ROR R0 ; знак = 0
953+ ROR R1
954+ BR 25$
955+ ;RAN1: Если состояние обнулилось (например, при инициализации нулём), используем (1,3)
956+ 21$: MOV #3,R1
957+ INC R0
958+ BR 2$
959+ ;RAN5:
960+ 25$: TST RNDSAV ; RNDSAV ещё не заполнено? первый вызов после инициализации
961+ BNE 27$ ; не ноль, значит уже было ? просто сохраняем новое
962+ ; Первое после инициализации: преобразуем целое состояние в float [0,1)
963+ MOV R1,-(SP) ; поместить полученное число (R0,R1) на стек
964+ MOV R0,-(SP)
965+ CLR R5 ; R5 = 0 (счётчик масштабирования)
966+ MOV 6(SP),-(SP) ; Дублируем число для операций
967+ MOV 6(SP),-(SP)
968+ BIC #100000,(SP) ; сбросить знак (работаем с положительным числом)
969+ ; Цикл приведения в диапазон [0,1)
970+ 13$: CMP #040200,(SP) ; сравнить старшее слово с 1.0
971+ BGT 11$ ; если > 1.0 -> уменьшить
972+ DEC R5 ; иначе увеличиваем счётчик
973+ BGE 15$ ; если R5 >= 0, выходим (достигли нужного интервала)
974+ ; Число < 1.0, но R5 < 0 -> нужно делить на 10.0
975+ CLR -(SP) ; константа 10.0 младшее слово
976+ MOV #041040,-(SP) ; константа 10.0 старшее слово
977+ CALL FDIV ; разделить число на 10.0
978+ BR 13$ ; продолжить цикл
979+ 11$: MOV SP,R2
980+ MOV (R2)+,6(R2) ; копирование числа
981+ MOV (R2)+,6(R2)
982+ INC R5
983+ BLE 15$
984+ CLR -(SP) ; константа 10.0 младшее слово
985+ MOV #041040,-(SP) ; константа 10.0 старшее слово
986+ CALL FMUL ; умножить на 10.0
987+ BR 13$ ; продолжить цикл
988+ ;
989+ 15$: ADD #4,SP ; удаляем временные копии числа
990+ ; Теперь требуется ещё отбросить целую часть
991+ CLR -(SP) ; константа 10.0 младшее слово
992+ MOV #041040,-(SP) ; константа 10.0 старшее слово
993+ CALL FDIV ; деление на 10.0
994+ CLR -(SP) ; положить 1.0 младшее слово
995+ MOV #040200,-(SP) ; положить 1.0 старшее слово
996+ CALL FADD ; сложить с 1.0
997+ CALL FSUB ; вычитание
998+ ;
999+ 17$: BIC #100000,(SP) ; сбросить знак результата
1000+ MOV SP,R2
1001+ MOV (R2)+, FRND$I ; сохранить результат в III
1002+ MOV (R2)+, FRND$I+2
1003+ MOV -(R2), R1 ; восстановить R0,R1
1004+ MOV -(R2), R0
1005+ ;RAN7:
1006+ 27$: MOV R1, RNDSAV+2 ; сохранить сгенерированное значение
1007+ MOV R0, RNDSAV
1008+ ;RAN6:
1009+ 26$: MOV RNDSAV+2, 2(SP) ; заменяем параметр на стеке на результат
1010+ MOV RNDSAV, (SP)
1011+ FRND$X: JMP @#000000 ; возврат, адрес подставляется в начале
1012+ ;
1013+ FRND$I: .WORD 040101, 027076 ; III: Рабочие ячейки FRND
1014+ RNDSAV: .WORD 040101, 027076 ; Предыдущее псевдо-случайное число: старшее, младшее
1015+
1016+ ;#####################################################################
1017+ ;## FSQR
1018+ ;## Need FADD
1019+ ;## Need FDIV
1020+ ;## Need ERRR
1021+ ; Квадратный корень из плавающего числа (float).
1022+ ; На основе кода процедуры SQRG из реализации Бейсик Вильнюс для УКНЦ.
1023+ ; Для отрицательных чисел выдаётся ошибка; для 0.0 результат 0.0.
1024+ ; Алгоритм: итерационный метод Ньютона с начальным приближением
1025+ ; На входе: (SP) - адрес возврата
1026+ ; (SP+2)(SP+4) - число с плавающей точкой (старшее слово, младшее слово)
1027+ ; На выходе: (SP)(SP+2) - результат
1028+ FSQR:
1029+ MOV (SP)+, FSQR$X+2 ; адрес возврата
1030+ CLR -(SP) ; выделить слово для счётчика итераций (3)
1031+ MOV SP,R4 ; R4 указывает на вершину стека (временный указатель)
1032+ TST (R4)+ ; пропустить младшее слово аргумента
1033+ MOV (R4), R1 ; R1 = старшее слово аргумента
1034+ BMI FSQR$K ; если отрицательное - ошибка
1035+ BEQ 0$ ; если ноль - результат 0
1036+ MOV #3,-(SP) ; счётчик итераций (3) на стек
1037+ ASR R1 ; экспоненту делим на 2 (приближение)
1038+ ADD #20100, R1 ; коррекция мантиссы (начальное приближение)
1039+ CLR -(SP) ; младшее слово приближения = 0
1040+ MOV R1, -(SP) ; старшее слово приближения на стек
1041+ CLR -(SP) ; младшее слово аргумента (0)
1042+ MOV (R4), -(SP) ; старшее слово аргумента (копия)
1043+ CLR -(SP) ; младшее слово для операции
1044+ MOV R1, -(SP) ; старшее слово приближения (второй операнд)
1045+ 3$: CALL FDIV ; деление: аргумент / приближение
1046+ CALL FADD ; сложение: (приближение + результат деления)
1047+ SUB #200, (SP) ; поделить результат на 2
1048+ DEC 4(SP) ; уменьшить счётчик итераций
1049+ BEQ 2$ ; если счётчик = 0, выходим
1050+ MOV 12(SP), -(SP) ; иначе скопировать тек.приближение для следующей итерации
1051+ MOV 12(SP), -(SP)
1052+ MOV 6(SP), -(SP)
1053+ MOV 6(SP), -(SP)
1054+ BR 3$ ; повторить
1055+ 2$: MOV (SP)+, R0 ; снять старшее слово результата
1056+ MOV (SP)+, R1 ; снять младшее слово результата
1057+ TST (SP)+ ; удалить счётчик итераций
1058+ BR FSQR$E ; получили результат, выходим
1059+ 0$: CLR R0 ; результат 0.0
1060+ CLR R1
1061+ ; R0,R1 - старшее и младшее слова результата
1062+ FSQR$E: MOV R0, (SP) ; заменяем старшее слово результатом
1063+ MOV R1, 2(SP) ; заменяем младшее слово
1064+ FSQR$X: JMP @#000000 ; возврат, адрес подставляется в начале
1065+ ;
1066+ FSQR$K: MOV FSQR$X+2, R5 ; откуда вызвали
1067+ MOV #3605., R0 ; Ошибка: корень из отрицательного числа
1068+ JMP ERRR
1069+
8991070;#####################################################################
9001071;## FADD
9011072;## Need ERRR
@@ -1155,7 +1326,7 @@ FMUL$M: MOV R0,10(SP) ;
11551326 MOV (SP)+,R4
11561327 MOV (SP)+,R5
11571328 CMP (SP)+,(SP)+ ; удаление числа B из стека
1158- FMUL$X: JMP @#000000 ; возврат
1329+ FMUL$X: JMP @#000000 ; возврат, адрес подставляется в начале
11591330;
11601331;MREZ0: Формирование нулевого результата
11611332FMUL$0: TST (SP)+ ; очистка стека
@@ -1302,7 +1473,7 @@ FDIV$D: MOV (SP)+,R4 ;
13021473FDIV$E: MOV (SP)+,R4 ; восстановление регистров
13031474 MOV (SP)+,R5
13041475 CMP (SP)+,(SP)+ ; удаление числа B из стека
1305- FDIV$X: JMP @#000000 ; возврат
1476+ FDIV$X: JMP @#000000 ; возврат, адрес подставляется в начале
13061477;
13071478;DALYT: Подпрограмма деления мантисс
13081479FDIV$T: ASL R5 ; сдвиг результата
0 commit comments