1   2   3   4   5   6   7
Ім'я файлу: Арх_комп_КСД12_Гайдук_КР.pdf
Розширення: pdf
Розмір: 997кб.
Дата: 13.02.2022
скачати
Пов'язані файли:
пояснительная_записка.doc
10. Подпрограммы пересылки данных К подпрограммам пересылки данных отнесены подпрограммы, выполняющие копирование содержимого одного из составных регистров (A, B, C) в соответствующую область памяти, и обратно. Например, вот подпрограммы, первая из которых копирует содержимое регистра A в область памяти, предназначенную для хранения юлианской даты (см. раздела вторая выполняет обратную операцию
;*******************************************************************************
; Load A To JD
;*******************************************************************************
LoadAToJD: sts jdate, pA sts jdate+1, mAH sts jdate+2, mAM sts jdate+3, mAL ret
;*******************************************************************************
; Load JD To A
;*******************************************************************************
LoadJDToA: lds pA, jdate lds mAH, jdate+1 lds mAM, jdate+2 lds mAL, jdate+3 ret К данным подпрограммам также отнесены макросы занесения содержимого составных регистров в стеки извлечения данных из стека обратно в составные регистры. Например
;*******************************************************************************
; PUSH A
;*******************************************************************************
.macro PushA push pA push mAH push mAM

35 push mAL
.endm
;*******************************************************************************
; POP A
;*******************************************************************************
.macro PopA pop mAL pop mAM pop mAH pop pA
.endm Здесь же имеются подпрограммы копирования содержимого одного составного регистра в другой. Например
;*******************************************************************************
; MOV A -> B
;*******************************************************************************
MovAToB: mov pB, pA mov mBH, mAH mov mBM, mAM mov mBL, mAL ret
;*******************************************************************************
; MOV A -> C
;*******************************************************************************
MovAToC: mov _pC, pA mov mCH, mAH mov mCM, mAM mov mCL, mAL ret Подпрограммы пересылки данных описаны в файле def_macro.asm. Помимо собственно подпрограмм пересылок данных, этот файл содержит также подпрограммы очистки регистров и настройки стека. Например
;*******************************************************************************
; Настройка верхушки стека.
;*******************************************************************************
.macro InitStack ldi temp, High(RAMEND) out sph, temp ldi temp, Low(RAMEND) out spl, temp
.endm
;*******************************************************************************
; CLR для регистра A.
;*******************************************************************************
ClrA: clr pA clr mAH clr mAM clr mAL ret

36 В файле def_macro.asm описано очень много подпрограмм и макросов, но все они довольно однотипные, поэтому здесь не приводятся, и вынесены в приложение 3.
11. Некоторые тригонометрические функции и корень квадратный К данным функциям отнесены подпрограммы извлечения корня квадратного, нахождения синуса, нахождения косинуса, нахождения арктангенса, которые описаны в файлах fsqrt.asm,
fsin.asm, fcos.asm и farctg.asm соответственно. При вычислении разных функций могут использоваться одни и те же области SRAM (в частности, даже те, которые используются астрономическими функциями. Поэтому, дабы не создавать новые функции пересылки данных, используются функции, применяющиеся в других модулях. Например, при вычислении корня используется функция LoadTToA, которая, вообще-то, используется для пересылки юлианских столетий из памяти в регистр A. Но ее применение здесь допустимо, т.к. содержимое соответствующей области памяти (хранящей значение юлианских столетий) к моменту применения тригонометрических функций и функции извлечения корня нас уже не интересует.
11.1 Вычисление квадратного корня вещественного числа Квадратный корень вычисляется известным методом, применяемым даже для ручного расчета
1. делим исходное число на какое-либо, меньшее его
2. находим среднее арифметическое частного и делителя
3. полученное среднее арифметическое используется как новый делитель исходно числа
4. процесс повторяется итерационно до тех пор, пока разность между двумя последовательными средними значениями не станет меньше заданной погрешности. Несмотря на простоту метода, полученный ряд сходится очень быстро. Разложение вряд Тейлора здесь неприменимо по ряду причин есть ограничение на диапазон аргумента – он может быть только меньше 2; ряд очень медленно сходится придется считать большие факториалы, либо вообще реализовывать гамма-функцию, что крайне нерационально. Точность вычисления – 6 знаков после запятой. Код подпрограммы
;*******************************************************************************
;
; Извлечение корня квадратного из положительного вещественного числа.
; Точность – 6 знаков после запятой.
;
;*******************************************************************************
SqrtF:

37
; Находим число, меньшее данного - первое sr1. rcall AToBuf ; x -> buf ldi mAL, 2 rcall IntToFloat ; A = 2.0 rcall AToSum ; sum = 2.0 rcall BufToB ; B = x rcall swapAB ; A = x, B = 2 rcall DivF ; A = A/B = x/2 rcall AToFact ; sr1 -> fact rcall ClrA ; A = 0 rcall LoadAToT ; T = sr2 = 0
; Начинаем итерационное приближение.
SqrtF1: rcall BufToA ; A = x rcall FactToB ; B = sr1 rcall DivF ; A = x/sr1 = d rcall FactToB ; B <- sr1 rcall AddF ; A = d+sr1 rcall SumToB ; B <- 2 rcall DivF ; A <- (d+sr1)/2 = sr2
PushA ; sr2 -> stack
; Расчет разности. rcall MovAToB ; sr2 -> B rcall LoadTToA ; sr2_pred -> A rcall SubF rcall AbsF ; A = |sr2_pred-sr2|
; Точность - +/-0,0000001 - 6 знаков после запятой. ldi pb, 0x35 ; B <- 0.000001 ldi mbH, 0x86 ldi mbM, 0x37 ldi mbL, 0xbd rcall SubF ; |sr2_pred-sr2| - 0.000001 rcall swapAB
PopA ; A <- sr2 rcall AToFact ; sr2 -> sr1 rcall LoadAToT ; sr2_pred
; Проверка |sr2_pred-sr2| - 0.000001 >= 0? ori pB, 0x00 brpl SqrtF1 ret Пример

A sqrt(A)
A in HEX sqrt(A) (теор) in HEX sqrt(A) (практ.) in HEX
1.365 1,168332 3faeb852 3f958be8 3f958be8
11.2 Вычисление синуса Синус числа вычисляется посредством разложения функции вряд Тейлора. Точность вычисления – 6 знаков после запятой. Код подпрограммы
;*******************************************************************************
;
; Расчет синуса (аргумент в радианах.
;

38
;*******************************************************************************
; Расчет синуса посредством разложения функции вряд Тейлора.
SinF: rcall AToBuf ; A -> buf rcall AToSum ; A -> sum; х – первое слагаемое, кладем в сумматор.
; Инициализация. rcall AToPowX ; powx = x = x^1 ldi mAL, 1 rcall IntToFloat rcall AToFact ; fact = 1 ldi sgn, 1 ; s = 1. Знак. ldi temp, 2 mov ct_t, temp ; Счетчик итераций. В регистр r15 через temp.
; sum = x, powx = x, fact = 1, ct_t = 2, sgn = 1.
; Первый члену нас уже есть, начинаем сразу считать второй. rcall ClrA ; A = 0 rcall LoadAToT ; T = sin_pred = 0
SinF1:
; Получаем факториал. ldi mAL, 2 rcall IntToFloat ; A = 2
PushA ; 2 to stack mov mAL, ct_t rcall IntToFloat ; A = i rcall MovAToB ; B = i
PopA ; A = 2 rcall MulF ; A = 2*i
PushA ; 2*i to stack ldi mAL, 2 rcall IntToFloat ; A = 2 rcall MovAToB ; B = 2
PopA ; A = 2*i rcall SubF ; 2*i-2
PushA ; 2*i-2 to stack два раза.
PushA ldi mAL, 1 rcall IntToFloat ; A = 1 rcall MovAToB ; B = 1
PopA ; A = 2*i-2 rcall AddF ; A = 2*i-1 rcall MovAToB ; B = 2*i-1
PopA ; A = 2*i-2 rcall MulF ; A = (2*i-2)(2*i-1) rcall FactToB ; B = f rcall MulF ; A = f*(2*i-2)(2*i-1) rcall AToFact ; fact to mem.
; Получаем степень х. rcall PowXToA ; A = powx rcall BufToB ; B = x rcall MulF ; A = powx*x rcall BufToB rcall MulF ; A = powx*x*x rcall AToPowX ; powx -> mem
; Знак слагаемого. ldi temp, 0xFF ; Инверсия знака. (+1) <-> (-1) eor sgn, temp ori sgn, 0x01 mov mAL, sgn rcall IntToFloat ; A = sign
; Находим текущее слагаемое. rcall MovAToB ; B = sign rcall PowXToA ; A = x^(2i-1) rcall MulF ; A = s*x^(2i-1)

39 rcall FactToB ; B = (2i-1)! rcall DivF ; A = s*x^(2n-1)/(2n-1)! rcall SumToB ; Добавляем в сумматор. rcall AddF rcall AToSum ; sum to mem.
; Увеличиваем счетчик. inc ct_t
; Расчет разности. rcall MovAToB ; sin -> B rcall LoadTToA ; sin_pred -> A rcall SubF rcall AbsF ; A = |sin_pred-sin|
; Точность - +/-0,0000001 - 6 знаков после запятой. ldi pb, 0x35 ; B <- 0.000001 ldi mbH, 0x86 ldi mbM, 0x37 ldi mbL, 0xbd rcall SubF ; A = |sin_pred-sin| - 0.000001
PushA ; delta to stack rcall SumToB ; B = sin rcall swapAB ; A = sin rcall LoadAToT ; sin -> sin_pred
PopB ; delta to B.
; Проверка |sin_pred-sin| - 0.000001 >= 0? ori pB, 0x00 brpl SinF2
SinF2: sbrs pB, 7 ; Пропустить, если разн. отрицательная. rjmp SinF1
; Exit. rcall SumToB rcall MovBToA ret Пример

A sin(A)
A in HEX sin(A) (теор) in HEX sin(A) (практ.) in HEX
1.365 0,9788986 3faeb852 3f7a9919 3f7a9919
11.3 Вычисление косинуса Косинус числа, также как синус, вычисляется посредством разложения функции вряд Тейлора. Точность вычисления – 6 знаков после запятой. Код подпрограммы
;*******************************************************************************
;
; Расчет косинуса (аргумент в радианах.
;
;*******************************************************************************
CosF:

40 rcall AToBuf ; A -> buf
; Инициализация. ldi mAL, 1 rcall IntToFloat rcall AToSum ; A -> sum; 1 – первое слагаемое, кладем в сумматор. rcall AToPowX ; powx = 1 rcall AToFact ; fact = 1 ldi sgn, 1 ; s = 1. Знак. ldi temp, 1 mov ct_t, temp ; Счетчик итераций. В регистр r15 через temp.
; sum = 1, powx = 1, fact = 1, ct_t = 1, sgn = 1.
; Первый члену нас уже есть, начинаем сразу считать второй. rcall ClrA ; A = 0 rcall LoadAToT ; T = Cos_pred = 0
CosF1:
; Получаем факториал. ldi mAL, 2 rcall IntToFloat ; A = 2
PushA ; 2 to stack mov mAL, ct_t rcall IntToFloat ; A = i rcall MovAToB ; B = i
PopA ; A = 2 rcall MulF ; A = 2*i
PushA ; 2*i to stack ldi mAL, 1 rcall IntToFloat ; A = 1 rcall MovAToB ; B = 1
PopA ; A = 2*i rcall SubF ; 2*i-1
PushA ; 2*i-1 to stack два раза.
PushA ldi mAL, 1 rcall IntToFloat ; A = 1 rcall MovAToB ; B = 1
PopA ; A = 2*i-1 rcall AddF ; A = 2*i rcall MovAToB ; B = 2*i
PopA ; A = 2*i-1 rcall MulF ; A = (2*i-1)(2*i) rcall FactToB ; B = f rcall MulF ; A = f*(2*i-1)(2*i) rcall AToFact ; fact to mem.
; Получаем степень х. rcall PowXToA ; A = powx rcall BufToB ; B = x rcall MulF ; A = powx*x rcall BufToB rcall MulF ; A = powx*x*x rcall AToPowX ; powx -> mem
; Знак слагаемого. ldi temp, 0xFF ; Инверсия знака. (+1) <-> (-1) eor sgn, temp ori sgn, 0x01 mov mAL, sgn rcall IntToFloat ; A = sign
; Находим текущее слагаемое. rcall MovAToB ; B = sign rcall PowXToA ; A = x^(2i) rcall MulF ; A = s*x^(2i) rcall FactToB ; B = (2i)! rcall DivF ; A = s*x^(2n)/(2n)!

41 rcall SumToB ; Добавляем в сумматор. rcall AddF rcall AToSum ; sum to mem.
; Увеличиваем счетчик. inc ct_t
; Расчет разности. rcall MovAToB ; Cos -> B rcall LoadTToA ; Cos_pred -> A rcall SubF rcall AbsF ; A = |Cos_pred-Cos|
; Точность - +/-0,0000001 - 6 знаков после запятой. ldi pb, 0x35 ; B <- 0.000001 ldi mbH, 0x86 ldi mbM, 0x37 ldi mbL, 0xbd rcall SubF ; A = |Cos_pred-Cos| - 0.000001
PushA ; delta to stack rcall SumToB ; B = Cos rcall swapAB ; A = Cos rcall LoadAToT ; Cos -> Cos_pred
PopB ; delta to B.
; Проверка |Cos_pred-Cos| - 0.000001 >= 0? ori pB, 0x00 brpl CosF2
CosF2: sbrs pB, 7 ; Пропустить, если разн. отрицательная. rjmp CosF1
; Exit. rcall SumToB rcall MovBToA ret Пример

A cos(A)
A in HEX cos(A) (теор) in HEX cos(A) (практ.) in HEX
1.365 0,2043467 3faeb852 3e514043 3e514045
11.4 Вычисление арктангенса Стандартное разложение арктангенса вряд Тейлора имеет ограничение – аргумент должен быть в интервале (-1;+1). Поэтому, аргументы, модуль которых меньше единицы, считаются путем разложения арктангенса вряд Тейлора, а для прочих значений использованы следующие разложения При x > 1: tan^-1(x) = Pi/2 - 1/x + 1/(3*x^3) - 1/(5*x^5) + 1/(7*x^7)-… При При хи Разложение вряд Тейлора (х < 1): tan^-1(x) = x - x^3/3 + x^5/5 - x^7/7 + … Код подпрограммы
;*******************************************************************************
;
; Расчет арктангенса.
;
;*******************************************************************************
; Расчет арктангенса посредством разложения функции вряд Проверяем аргумент на равенство единице. ldi mAL, 1 rcall IntToFloat ; A = 1 rcall BufToB rcall swapAB rcall AbsF rcall SubF ; A = |x|-1 rcall cp_A_0 ; A = 0? breq ArctgF3 rjmp ArctgF4
; x = 1 || x = -1
ArctgF3: rcall BufToA ori pA, 0x00 brpl ArctgF7
; x = -1 ldi pA, 0xBf ; -pi/4 ldi mAH, 0x49 ldi mAM, 0x0f ldi mAL, 0xdb rjmp EndArctgF ; arctg(-1) = -pi/4
; x = 1
ArctgF7: ldi pA, 0x3f ; pi/4 ldi mAH, 0x49 ldi mAM, 0x0f ldi mAL, 0xdb rjmp EndArctgF ; arctg(1) = pi/4
; x != 1 && x != -1
ArctgF4:
; Проверяем величину модуля. |x| < 1? ldi mAL, 1 rcall IntToFloat ; A = 1 rcall BufToB rcall swapAB rcall AbsF rcall SubF ; A = |x|-1 ori pA, 0x00 brpl ArctgF5
ArctgF5: sbrs pA, 7 ; Пропустить, если разн. отрицательная.

43 rjmp ArctgF6
; Модуль меньше единицы. Обычное разложение вряд Тейлора. rcall BufToA rcall AToSum ; A -> sum; х – первое слагаемое, кладем в сумматор.
; Инициализация. rcall AToPowX ; powx = x = x^1 ldi mAL, 1 rcall IntToFloat rcall AToFact ; divider = 1 ldi sgn, 1 ; s = 1. Знак. ldi temp, 2 mov ct_t, temp ; Счетчик итераций. В регистр r15 через temp.
; sum = x, powx = x, divider = 1, ct_t = 1, sgn = 1.
; Первый члену нас уже есть, начинаем сразу считать второй. rcall ClrA ; A = 0 rcall LoadAToT ; T = Arctg_pred = 0
ArctgF1:
; Получаем делитель. ldi mAL, 2 rcall IntToFloat ; A = 2
PushA ; 2 to stack mov mAL, ct_t rcall IntToFloat ; A = i
PopB ; B = 2 rcall MulF ; A = 2*i
PushA ; 2*i to stack ldi mAL, 1 rcall IntToFloat ; A = 1
PopB ; B = 2*i rcall swapAB rcall SubF ; A = 2*i-1 rcall AToFact ; 2*i-1 to mem.
; Получаем степень х. rcall PowXToA ; A = powx rcall BufToB ; B = x rcall MulF ; A = powx*x rcall BufToB rcall MulF ; A = powx*x*x rcall AToPowX ; powx -> mem
; Знак слагаемого. ldi temp, 0xFF ; Инверсия знака. (+1) <-> (-1) eor sgn, temp ori sgn, 0x01 mov mAL, sgn rcall IntToFloat ; A = sign
; Находим текущее слагаемое. rcall MovAToB ; B = sign rcall PowXToA ; A = x^(2i-1) rcall MulF ; A = s*x^(2i-1) rcall FactToB ; B = (2i-1) rcall DivF ; A = s*x^(2n-1)/(2n-1) rcall SumToB ; Добавляем в сумматор. rcall AddF rcall AToSum ; sum to mem.
; Увеличиваем счетчик. inc ct_t
; Расчет разности. rcall MovAToB ; Arctg -> B rcall LoadTToA ; Arctg_pred -> A rcall SubF rcall AbsF ; A = |Arctg_pred-Arctg|

44
; Точность - +/-0,0000001 - 6 знаков после запятой. ldi pb, 0x35 ; B <- 0.000001 ldi mbH, 0x86 ldi mbM, 0x37 ldi mbL, 0xbd rcall SubF ; A = |Arctg_pred-Arctg| - 0.000001
PushA ; delta to stack rcall SumToB ; B = Arctg rcall swapAB ; A = Arctg rcall LoadAToT ; Arctg -> Arctg_pred
PopB ; delta to B.
; Проверка |Arctg_pred-Arctg| - 0.000001 >= 0? ori pB, 0x00 brpl ArctgF2
ArctgF2: sbrs pB, 7 ; Пропустить, если разн. отрицательная. rjmp ArctgF1 rjmp EndArctgF
; |x| > 1
ArctgF6: ldi mAL, -1 rcall IntToFloat ; A = -1 rcall BufToB ; B = x rcall DivF ; A = -1/x rcall AToSum ; A -> sum. Первое слагаемое в сумматор.
; Инициализация. rcall BufToA rcall AToPowX ; powx = x = x^1 ldi mAL, 1 rcall IntToFloat rcall AToFact ; divider = 1 ldi sgn, -1 ; s = -1. Знак. ldi temp, 2 mov ct_t, temp ; Счетчик итераций. В регистр r15 через temp.
; sum = -1/x, powx = x, divider = 1, ct_t = 2, sgn = -1.
; Первый члену нас уже есть, начинаем сразу считать второй. rcall ClrA ; A = 0 rcall LoadAToT ; T = Arctg_pred = 0
ArctgF8:
; Получаем делитель. ldi mAL, 2 rcall IntToFloat ; A = 2
PushA ; 2 to stack mov mAL, ct_t rcall IntToFloat ; A = i
PopB ; B = 2 rcall MulF ; A = 2*i
PushA ; 2*i to stack ldi mAL, 1 rcall IntToFloat ; A = 1
PopB ; B = 2*i rcall swapAB rcall SubF ; A = 2*i-1 rcall AToFact ; 2*i-1 to mem.
; Получаем степень х. rcall PowXToA ; A = powx rcall BufToB ; B = x rcall MulF ; A = powx*x rcall BufToB

45 rcall MulF ; A = powx*x*x rcall AToPowX ; powx -> mem
; (2*i-1)*x^(2i-1) rcall FactToB ; 2*i-1 rcall MulF ; (2*i-1)*x^(2i-1) rcall AToFact ; (2*i-1)*x^(2i-1) to mem.
; Знак слагаемого. ldi temp, 0xFF ; Инверсия знака. (+1) <-> (-1) eor sgn, temp ori sgn, 0x01 mov mAL, sgn rcall IntToFloat ; A = sign
; Находим текущее слагаемое. rcall FactToB ; B = (2*i-1)*x^(2i-1) rcall MulF ; A = s*(2*i-1)*x^(2i-1)
PushA ldi mAL, 1 rcall IntToFloat ; A = 1
PopB rcall DivF ; A = 1/(s*x^(2n-1)/(2n-1)) rcall SumToB ; Добавляем в сумматор. rcall AddF rcall AToSum ; sum to mem.
; Увеличиваем счетчик. inc ct_t
; Расчет разности. rcall MovAToB ; Arctg -> B rcall LoadTToA ; Arctg_pred -> A rcall SubF rcall AbsF ; A = |Arctg_pred-Arctg|
; Точность - +/-0,0000001 - 6 знаков после запятой. ldi pb, 0x35 ; B <- 0.000001 ldi mbH, 0x86 ldi mbM, 0x37 ldi mbL, 0xbd rcall SubF ; A = |Arctg_pred-Arctg| - 0.000001
PushA ; delta to stack rcall SumToB ; B = Arctg rcall swapAB ; A = Arctg rcall LoadAToT ; Arctg -> Arctg_pred
PopB ; delta to B.
; Проверка |Arctg_pred-Arctg| - 0.000001 >= 0? ori pB, 0x00 brpl ArctgF9
ArctgF9: sbrs pB, 7 ; Пропустить, если разн. отрицательная. rjmp ArctgF8
; Добавление pi/2 или -pi/2. rcall BufToA ori pA, 0x00 brpl ArctgF10 ldi pb, 0xbf ; -pi/2 ldi mbH, 0xc9 ldi mbM, 0x0f ldi mbL, 0xdb rcall LoadTToA

46 rcall AddF rjmp EndArctgF
ArctgF10: rcall LoadTToA ldi pb, 0x3f ; pi/2 ldi mbH, 0xc9 ldi mbM, 0x0f ldi mbL, 0xdb rcall AddF
EndArctgF: ret Пример

A arctg(A)
A in HEX arctg(A) (теор) in HEX arctg(A) (практ.) in HEX
1.365 0,9385241 3faeb852 3f70431e
3f704320

1   2   3   4   5   6   7

скачати

© Усі права захищені
написати до нас