Вношу свою скромную лепту... Целочисленная арифметика Модуль разности:
ABSSub:
cmp r0,r1
blt ABSSubLeth
sub r0,r0,r1
b exitABSSub
ABSSubLeth:
sub r0,r1,r0
exitABSSub:
bx lr
Деление (простое):
myDel:
push {r1-r7,lr}
mov r2,r0
mov r0,0
loopMyDel:
sub r2,r1
bmi exitMyDel
add r0,1
b loopMyDel
exitMyDel:
pop {r1-r7,pc}
Деление (усложненное):
MyDel:
push {r2,r3,lr}
mov r2,0
LoopDel:
mov r3,r0
mul r3,r2
add r2,1
cmp r3,r1
blt LoopDel
cmp r3,r1
beq DelSub
sub r3,r1
sub r2,1
mul r0,r2
sub r0,r1,r0
cmp r3,r0
bge DelSub
DelNotSub:
add r2,1
DelSub:
mov r0,r2
pop {r2,r3,pc}
Корень квадратный (используется хитрый прием, но работает 100% ):
MySQRT:
push {r5-r7,lr}
mov r5,0
mov r6,1
startSQRT:
add r5,r6
add r6,2
cmp r5,r0
blt startSQRT
lsr r6,1
beq SQRTWithoutRound
mov r5,r6
mul r5,r5
sub r5,r0
sub r7,r6,1
mul r7,r7
sub r7,r0,r7
cmp r5,r7
ble SQRTWithoutRound
sub r6,1
SQRTWithoutRound:
mov r0,r6
pop {r5-r7,pc}
Расстояние между двумя точками (r0=x1,r1=y1,r2=x2,r3=x3): GetLength: push {r1-r4,lr} bl ABSSub mul r0,r0 mov r4,r0 mov r0,r2 mov r1,r3 bl ABSSub mul r0,r0 add r0,r4 bl MySQRT pop {r1-r4,pc} Графика Платформеннонезависимые: Рисует "блик". r0=centerX r1=centerY r2=radius
DrawBlick:
push {r0-r7,lr}
sub sp,16
str r2,sp,8
str r3,sp,12
add r6,r0,r2
cmp r6,128 ;Вместо 128 используйте ширину экрана в пикселях
ble RightNormal
mov r6,128 ;Вместо 128 используйте ширину экрана в пикселях
RightNormal:
add r7,r1,r2
cmp r7,128 ;Вместо 128 используйте высоту экрана в пикселях
ble DownNormal
mov r7,128 ;Вместо 128 используйте высоту экрана в пикселях
DownNormal:
str r6,sp
str r7,sp,4
sub r6,r0,r2
bpl LeftNormal
mov r6,0
LeftNormal:
sub r7,r1,r2
bpl UpNormal
mov r7,0
UpNormal:
mov r4,r0
mov r5,r1
mov r2,r6
BlickLoop:
mov r3,r5
mov r1,r2
push r2
mov r2,r7
mov r0,r4
bl GetLength
pop r2
mov r1,32
mul r1,r0
ldr r0,sp,8
bl MyDel
mov r1,32
sub r1,r0
bpl BlickNormal
mov r1,0
BlickNormal:
mov r0,r2
mov r2,r1
mov r1,r7
ldr r3,sp,12
bl SetPixelAlpha ;Используется платформеннозависимая функция (будет показан пример для сисол) add r2,r0,1
ldr r3,sp
cmp r2,r3
ble BlickLoop
mov r2,r6
ldr r3,sp,4
add r7,1
cmp r7,r3
ble BlickLoop
add sp,16
pop {r0-r7,pc}
Функции рисования различных прямоугольников:
;Инвертированный
;r0=x
;r1=y
;r2=w
;r3=h
DrawInvertRectangle:
push {r0-r3,LR}
add r2,r0
add r3,r1
LoopDrawInvertRectangle:
bl SetPixelInvert;Платформеннозависимая функция (будет показан пример для сисол)
add r0,1
cmp r0,r2
blt LoopDrawInvertRectangle
ldr r0,sp
add r1,1
cmp r1,r3
blt LoopDrawInvertRectangle
pop {r0-r3,PC}
;Осветленный
;r0=x
;r1=y
;r2=w
;r3=h
;r4=коэффициент осветления/затемнения (0-31 - осветление, 32-64 - затемнение)
DrawBrightnessRectangle:
push {r0-r4,LR}
add r4,r2,r0
add r3,r1
ldr r4,[sp+8]
LoopDrawBrightnessRectangle:
bl SetPixelBrightness
add r0,1
cmp r0,r4
blt LoopDrawBrightnessRectangle
ldr r0,sp
add r1,1
cmp r1,r3
blt LoopDrawInvertRectangle
pop {r0-r4,PC}
;r0=x
;r1=y
;r2=коэффициент осветления/затемнения (0-31 - осветление, 32-64 - затемнение)
SetPixelBrightness:
push {r0-r3,lr}
ldr r3,=0xffff
cmp r2,0x20
blt setBrPixel
mov r3,0xffff
sub r2,0x20
setBrPixel:
bl SetPixelAlpha
pop {r0-r3,pc}
;С прозрачностью
;r0=x
;r1=y
;r2=w
;r3=h
;r4=color
;r5=alpha
DrawAlphaRectangle:
push {r0-r3,r6,r7,LR}
add r2,r0
mov r6,r2
add r3,r1
mov r7,r3
mov r2,r5
mov r3,r4
LoopDrawAlphaRectangle:
bl SetPixelAlpha;Платформеннозависимая функция (будет показан пример для сисол)
add r0,1
cmp r0,r6
blt LoopDrawAlphaRectangle
ldr r0,sp
add r1,1
cmp r1,r7
blt LoopDrawAlphaRectangle
pop {r0-r3,r6,r7,PC}
Функция прорисовки границ инвертированного прямоугольника (по аналогии можно сделать и для полупрозрачного, и для любого другого прямоугольника): r0=left r1=top r2=width r3=height
DrawInversBox:
push {r0-r4,lr}
cmp r2,1
bne DIB1
bl DrawVLine
b exitDIB
DIB1:
cmp r3,1
bne DIB
bl DrawHLine
b exitDIB
DIB:
sub r4,r3,1
bl DrawHLine
add r1,r4
bl DrawHLine
sub r1,r4
sub r4,r2,1
bl DrawVLine
add r0,r4
bl DrawVLine
exitDIB:
pop {r0-r4,pc}
DrawVLine:
push {r1,r3,lr}
add r3,r1
LoopVLine:
bl SetPixelInvert
add r1,1
cmp r1,r3
blt LoopVLine
pop {r1,r3,pc}
DrawHLine:
push {r0,r2,lr}
add r2,r0
LoopHLine:
bl SetPixelInvert
add r0,1
cmp r0,r2
blt LoopHLine
pop {r0,r2,pc}
Платформеннозависимые: Функции для предыдущих примеров (x100):
;r0=x
;r1=y
SetPixelInvert:
push {r0-r2,lr}
lsl r0,1
lsl r1,8
add r1,r0
ldr r0,=vScreenMem
add r1,r0
ldrh r2,r1
mov r0,0xff
lsl r0,8
add r0,0xff
sub r0,r2
strh r0,r1
pop {r0-r2,pc}
.data
;r0=x
;r1=y
;r2=alpha
;r3=color
SetPixelAlpha:
push {r0-r7,LR}
lsl r0,1
lsl r5,r1,8
add r5,r0
ldr r0,=vScreenMem
add r5,r0
ldrh r0,r5
mov r1,r3
lsr r3,r0,11
lsr r6,r1,11
bl SetAlChanel
lsl r7,r6,11
lsl r3,r0,21
lsr r3,r3,27
lsl r6,r1,21
lsr r6,r6,27
bl SetAlChanel
lsl r4,r6,6
lsl r3,r0,27
lsr r3,r3,27
lsl r6,r1,27
lsr r6,r6,27
bl SetAlChanel
orr r6,r4
orr r6,r7
SetColor:
strh r6,r5
pop {r0-r7,PC}
SetAlChanel:
push {r4,lr}
mul r6,r2
mov r4,0x20
sub r4,r2
mul r3,r4
add r6,r3
lsr r6,5
pop {r4,pc}
Функции рисования для новых агере (D830):
.arm
.align 2
;Рисует прямоугольник c альфа-каналом:
;r0=alpha+color
;r1=rect
myDrawAlphaRect:
stmfd sp!,{r0-r7,lr}
ldr r7,=_pIdcObjByHandle
ldr r7,[r7]
ldr r7,[r7+0x48]
ldrh r6,[r1+6];Нижняя граница
ldrh r5,[r1+4];Верхняя граница
ldrh r4,[r1+2];Правая граница
ldrh r3,[r1+0];Левая граница
;Шаг вертикали:
mov r2,480
;Адаптация к буферу:
mov r3,r3 lsl 1
mov r4,r4 lsl 1
mul r5,r5,r2
mul r6,r6,r2
add r6,r6,r3
;Шаг вертикали (адаптированный):
sub r2,r2,r4
add r2,r2,r3
;Начинаем...
add r5,r5,r7
add r6,r6,r7
add r4,r4,r5
add r7,r3,r5
loopMyDrawRect:
ldrh r1,[r7+0]
bl getAlphaColor
STRH R1,[R7],2
cmp r7,r4
blt loopMyDrawRect
add r4,480
add r7,r7,r2
cmp r7,r6
ble loopMyDrawRect
ldmfd sp!,{r0-r7,lr}
bx lr
;Вернет в R1 опрозрачненный цвет
;по R0(основной цвет) и R1(подложка).
;17-22 биты (от 0 до 32)
;R0 - уровень непрозрачности.
getAlphaColor:
stmfd sp!,{r0,r2-r7}
mov r7,r0 lsr 16;Коэффициент непрозрачности
rsb r6,r7,32;Коэффициент прозрачности
;Выделяем синее
and r4,r1,0x1f;Цвет подложки
and r3,r0,0x1f;Цвет кисти
;склееваем по коэффициенту
;синий цвет:
mul r4,r4,r6
mul r3,r3,r7
add r3,r3,r4
;Компенсация:
mov r2,r3 lsr 5
;Выделяем зеленое
and r4,r1,0x7E0
and r3,r0,0x7E0;Цвет кисти
;Склееваем по коэффициенту
;зеленый цвет:
mul r4,r4,r6
mul r3,r3,r7
add r3,r3,r4
;Компенсация:
and r3,r3,0xFC00;Применяем маску для очищения лишних битов
orr r2,r2,r3 lsr 5;orr r2,r2,r3 lsr 5
;Выделяем красное
mov r4,r1 lsr 11;Цвет подложки
mov r3,r0 lsr 11;Цвет кисти
;Склееваем по коэффициенту
;зеленый цвет:
mul r4,r4,r6
mul r3,r3,r7
add r3,r3,r4
;Компенсация:
and r3,r3,0x3E0;Применяем маску для очищения лишних битов
orr r1,r2, r3 lsl 6
ldmfd sp!,{r0,r2-r7}
bx lr
.thumb
;Рисует "коробочку".
myDrawBox:
push {r0-r7,lr}
ldr r7=_pIdcObjByHandle
ldr r7,[r7]
ldr r7,[r7+0x48]
ldrh r2,[r1];Левая граница
ldrh r3,[r1+2];Правая граница
ldrh r4,[r1+4];Верхняя граница
ldrh r5,[r1+6];Нижняя граница
;Шаг по вертикали:
mov r1,240
lsl r1,1
;адаптация к буферу
lsl r2,1
lsl r3,1
mul r4,r1
mul r5,r1
add r4,r7
add r5,r7
add r6,r4,r2
add r4,r3
add r7,r5,r3
add r3,r5,r2
mov r2,r6
;Горизонтальный цикл:
myDrawBoxLoop1:
strh r0,[r2]
strh r0,[r3]
add r2,2
add r3,2
cmp r3,r7
blt myDrawBoxLoop1
;Вертикальный цикл
myDrawBoxLoop2:
strh r0,[r6]
strh r0,[r4]
add r6,r1
add r4,r1
cmp r4,r7
blt myDrawBoxLoop2
strh r0,[r4]
pop {r0-r7,pc}
Трассировка Код, добавляющий возможность трассировки для телефонов агере платформы (D830):
.equfile "Trace.h";кто не знает что это, тому можно это убрать :)
.equ TB 0x3016CA70;Буфер трассировки
.equ sprintf 0x204F106E;используется ф-ция с неограниченным числом параметров
.equ strcpy 0x204EFBA4;любой эквивалент
.equ strcat 0x204EFB3C;любой эквивалент
.equ strlen 0x204EFBBA;любой эквивалент
.equ p_GSMMalloc 0x0400010C
.equ p_GSMFree 0x04000110
.equ ATSendReplyByEG 0x2040FAF8;выводит строку R0 на порт UART0. Параметр R1 надо занулить.
/*
Как найти _sprintf, strcpy и strcat - ваши проблемы. Я изучал алгоритмы ф-ций (зная адрес одной из них).
Впринципе можно разобрать подходящий колбэк из прошивки от х140 и вашей и найти эти ф-ции.
TB тоже находится давольно легко (путем разбора какой-нибудь колбэк ф-ции, использующей трассировку).
Можно восспользоваться строками и функциям трассировки.
Для ATSendReplyByEG я предлагаю такой алгоритм. Найдите в прошивке строку "+LOGL:" (без кавычек).
Найдите где она используется. Сразу после adr на эту строку будет вызов ф-ции. Это и есть ATSendReplyByEG.
*/
;Свободный регион памяти. Я использую "мусор", которые разработчики так любезно оставили.
;Трассировка. R0=маска_вывода, R1..R3=значения_подстановки (необязательно).
;Используется буфер трассировки TB.
0x211010D8:
%myTrace:;если кто не знает, зачем тут '%', можно его не писать.
push {r0-r7,lr}
sub sp,8
;Добавим к маске адрес вызова:
;Выделим память:
bl strlen
add r0,4
ldr r1,=p_GSMMalloc
ldr r1,[r1]
bl call_by_R1
mov r6,r0
adr r1,="%X: ";Это для вывода LR (адреса вызова)
bl strcpy
mov r0,r6
ldr r1,[sp+8]
bl strcat
;Подготовим строку:
ldr r0,=TB
mov r1,r6
ldr r2,[sp+40];r2=LR
ldr r3,[sp+12];r3=R1
ldr r4,[sp+16];r4=R2
str r4,[sp] ;[sp]=R2
ldr r4,[sp+20];r4=R3
str r4,[sp+4];[sp+4]=R3
bl sprintf
;Выведем в порт:
mov r1,0
ldr r0,=TB
bl ATSendReplyByEG
;Освободим память:
ldr r1,=p_GSMFree
ldr r1,[r1]
mov r0,r6
bl call_by_R1
add sp,8
pop {r0-r7,pc}
.data
%trace:
push {r0-r7,lr}
sub sp,8
;Подготовим строку:
str r3,[sp]
mov r3,r2
mov r2,r1
mov r1,r0
ldr r0,=TB
bl sprintf
;Выведем в порт:
mov r1,0
ldr r0,=TB
bl ATSendReplyByEG
add sp,8
pop {r0-r7,pc}
call_by_R1:
bx r1
Низкоуровневое
.arm
;Функция, защищающая от кэширования.
;R0=Address, R1=Size
unCache:
STMFD SP!,{R0,R1,LR};Сохраняем регистры
ADD R1,R0;Получаем конечный адрес
;Получаем адреса, кратные 32
;(размеру "линии" DCache)
BIC R0,R0,0x1F
BIC R1,R1,0x1F
;Очистка кэша данных (Data Cache, DCache):
CacheLoop:
;Очистка одной "линии" кэша:
MCR p15,0,R0,c7,c14,1
;Инкримент цикла:
ADD R0,0x20;0x20 - размер "линии" кэша
;Сравнение с конечным адресом:
CMP R0,R1
;Условие продолжения (меньше или равно):
BLE CacheLoop
;Сброс ("дренаж") буфера записи:
MCR p15,0,R0,c7,c10,4;drain write buffer
;Обновление буфера команд
MCR p15, 0, r0, c7, c5, 0; invalidate icache (Instruction Cache)
LDMFD SP!,{R0,R1,PC};Загружаем регистры
.thumb
Ну и так, по мелочи...
;Возвращает в r0 число из строкового Hex-представления. В r0 - адрес строки хекса.
parseHex:
push {r1-r3,lr}
mov r1,8;Длинна записи.
mov r3,r0
mov r0,0
parseHexLoop:
ldrb r2,[r3]
sub r2,'0'
bmi parseHexError
cmp r2,9
ble parseHexDecimal
sub r2,7
parseHexDecimal:
lsl r0,4
add r0,r2
add r3,1
sub r1,1
bne parseHexLoop
parseHexError:
pop {r1-r3,pc}
;Записывает в память по адресу r1 данные из строкового
;Hex-представления. В r0 - адрес данных, в R2 - длинна.
stringHex:
push {r0,r1,r6,r7,lr}
mov r7,r0
add r6,r1,r2
stringHexLoop:
mov r0,r7
bl parseHex
str r0,r1
add r7,8
add r1,4
cmp r1,r6
blt stringHexLoop
pop {r0,r1,r6,r7,pc}
;Возвращает индекс последнего символа из r1 в строке из r0.
;Если символ не найден, будет возвращено 0. Индексация с 1.
%getLastCharPos:
push {r2-r4,lr}
mov r2,r0
mov r0,0
mov r4,0
getLastCharLoop:
ldrb r3,[r2]
cmp r3,0
beq exitLastChar
add r4,1
add r2,1
cmp r3,r1
bne getLastCharLoop
mov r0,r4
b getLastCharLoop
exitLastChar:
pop {r2-r4,pc}
;Копирует строку из r1 в r0 длинной строго r2
;(+в конце дописывается 0). Регистры не меняются.
%mycpystr:
push {r0-r3,lr}
add r2,r0
loopMycpystr:
ldrb r3,[r1]
strb r3,[r0]
add r1,1
add r0,1
cmp r0,r2
blt loopMycpystr
mov r3,0
strb r3,[r0]
pop {r0-r3,pc}
;Конвертирует LeftUnicode в Ansi. Строка передается в R1, записывается по адресу R0.
%myLeftUnicodeToAnsi:
push {r0-r3,lr}
mov r3,0xff
loopLeftUnicodeToAnsi:
ldrh r2,[r1]
cmp r2,0xff
ble oneByte
and r2,r3
add r2,0xB0
oneByte:
strb r2,[r0]
add r0,1
add r1,2
cmp r2,0
bne loopLeftUnicodeToAnsi
pop {r0-r3,pc}
Надеюсь, не утомил А вообще-то лучше как-то это все оформить иначе, чтобы не у каждого автора были набросаны функции, а функции распределены по разделам и у каждой конкретной функции подписан автор.