Login

Subversion Repositories NedoOS

Rev

Rev 206 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

1986ВЕ1Т
Код можно исполнять только из ПЗУ и области ОЗУ 0x20100000 (16K), из внешнего ОЗУ (с адреса, например, 0x60000000, но не 0x50000000).
Адрес перехода должен быть нечётным, иначе hardfault.
Чтение слов только выровненному адресу, иначе hardfault.
Система команд Thumb1 с небольшими дополнениями (используем только Thumb1).
После сброса читает PC=[4]

Для работы с внешней памятью надо настроить много регистров.

Внешняя память ОЗУ размером 1М видна с адресов 0x50000000, 0x60000000 и др.
Старший бит адреса (A19) перекрывает кнопку RIGHT.
При побайтовой записи путает чётные-нечётные байты.
Не работает в режиме LOW8 (с любыми LOW16, ENDIAN).
В режиме LOW16 дублирует пары байт, так работать нельзя.
В режиме ENDIAN процессор меняет 0..3<->3..0, так что после этого уже путаются чётные-нечётные слова, что тоже бесполезно.

Как исправить:
надо вынуть перемычки PC9-BE0, PC10-BE1, PC11-BE2, PC12-BE3
и установить провода PC9-BE1, PC10-BE0, PC11-BE3, PC12-BE2.
После этого всё правильно читается по байтам и по словам.
Можно поставить память больше, т.к. CS на A20,A21 мы выставляем вручную.
На отладочной плате A19 пересекается с кнопкой RIGHT, но теоретически можно сделать проводок от кнопки на другую ножку (поставил на PF2 вместо A31).

С проводами при CPU_CLK = 96 МГц (настройка из примера) получился делитель WAIT_STATE минимум "7" (2+4+2), т.е. 12 МГц (>83 нс). Даже при "4" (2+2+1) работает только половина теста памяти (с проводами).
При CPU_CLK = 128 МГц (как получить 144 МГц из 8 МГц? надо другой осциллятор HSE?) делитель WAIT_STATE минимум "8" (3+4+2), т.е. 14.2 МГц (>70 нс) - видимо, при "6" (2+3+2) и "7" (2+4+2) неудачные растактовки.
Сама микросхема памяти имеет "Время выборки по адресу и сигналу nСЕ1
и CE2 не более 30 нс", "Время цикла считывания информации мин 30 нс", "Время цикла записи информации мин 30 нс".
По доке на микросхему ОЗУ и при чтении, и при записи не нужна задержка адреса после снятия управляющих сигналов.
Минимальная работающая ручная растактовка 2+4+0, т.е. 21.3 МГц (47 нс). Не работает 1+4+0, т.е. 25.6 МГц (39 нс).
Для сравнения, скорость встроенного ПЗУ: 16 байт за 40 нс (странно, что работает, когда в EEPROM_CMD Delay=0!!!).

Кэшируется ли доступ к внешнему ОЗУ? В документации на 1986ВЕ1Т упоминаются только настройки кэширования и буферизации для DMA.

В J-Em v2 с Фитоном можно установить только 2 брякпойнта и только в ПЗУ. Поэтому точки останова ставим либо вручную в программе, либо вручную в окне дизасма или дампа.




для ARM thumb понадобится таблица констант, без которой никак
в thumb нет способа присваивания по частям!!!

на ВЕ9x есть (TODO!):
70FFF64F      MOV   R0,#0FFFFH
70FFF6C7      MOVT  R0,#07FFFH
71FFF64F      MOV   R1,#0FFFFH
71FFF6C1      MOVT  R1,#01FFFH
0100F04F???   MOV   R1,#00000H
0100F2C2      MOVT  R1,#02000H
21A2F64D      MOV   R1,#0DAA2H
110FF6CC      MOVT  R1,#0C90FH
5451F64E      MOV   R4,#0ED51H
4487F2C6      MOVT  R4,#06487H
3733F24F      MOV   R7,#0F333H
5704F2CB      MOVT  R7,#0B504H
0700F04F???   MOV   R7,#00000H
0700F2C0      MOVT  R7,#00000H
                             v0=инверсия HHHH?
%0hhh RRRR LLLL LLLL, 1111 0hi0 0100 HHHH = MOV  RR,HhLL
%0hhh RRRR LLLL LLLL, 1111 0hi0 1100 HHHH = MOVT RR,ThLL
                            ^bit12

более того, в некоторых арифметических операциях есть ограничение на байтовые константы (ASR/LSL до 31, двухадресный ADD/SUB до 7, а MOV,CMP и одноадресный ADD/SUB до 0xff)
AND,ORR,EOR только в регистрах двухадресно
или делать все константы через ld:jr:dw? предсказывается идеально, в кэш ложится идеально, только одна лишняя команда и надо учитывать выравнивание на 4 (.ALIGN  2 на выходе выравнивает на 4, можно прямо его и использовать, только тогда надо уникальную метку для джампа!)
LDR Rr,[PC,#0xNN] NN = 0x000...0x3fc (кратно 4) только вперёд!!! интересно, от какого PC
%0100 1rrr NNNN NNNN
на адресе 062a команда LDR Rr,[PC,#0x00] читает из 062c (там лежит 44ff,42ba, в регистр попадает 42ba44ff)
на адресе 061c команда LDR Rr,[PC,#0x00] читает из 0620 (там лежит d00f,07d9, в регистр попадает 07d9d00f)

в PUSH можно указать список регистров (только R0..R7 и LR):
PUSH {R0,R2,R7,LR}
%1011 010L 7654 3210
в POP можно указать список регистров (только R0..R7 и PC):
POP {R0,R2,R7,PC}
%1011 110P 7654 3210


короткий переход (-800..+800):
B addr
%1110 0sLL LLLL LLLL (S с дополнением до 2)
L домножается до 2 и прибавляется к PC+4!!! (без округления до 4)

длинный переход (-400000..+400000):
BL addr
%1111 0sHH HHHH HHHH
%1111 1LLL LLLL LLLL
HL домножается до 2 и прибавляется к PC после конца команды, т.е. PC+4 (без округления до 4)

все ветвления короткие:
BEQ addr (==)
%1101 0000 sLLL LLLL
BNE addr (!=)
%1101 0001 sLLL LLLL
BCS 2
BCC 3
BMI 4
BPL 5
BVS 6
BVC 7
BHI 8
BLS 9
BGE a (>=)
BLT b (<)
BGT c (>)
BLE d (<=)
L домножается до 2 и прибавляется к PC+4!!! (без округления до 4)
заранее не узнать, далеко ли надо прыгать вперёд - то есть в if/while надо длинный переход с коротким обходом

переход по регистру:
BX Rr
%0100 0111 0rrr r000
BLX Rr
%0100 0111 1rrr r000

switch?
SWI n
%1101 1111 nnnn nnnn
что делает?
в Миландре там svc #N


MOVS R,r
%0000 0000 00rr rRRR
MOV R,r
%0100 0110 Rrrr rRRR
MVNS R,r
%0100 0011 11rr rRRR


LDR R,[r,N*4]
%0110 1NNN NNrr rRRR
STR R,[r,N*4]
%0110 0NNN NNrr rRRR


ADDS R,r,a
%0001 100a aarr rRRR 

ADDS R,r,N
%0001 110N NNrr rRRR 

todo грузить R0 в начале процедуры, а переменные адресовать относительно начала их блока (у этой процедуры). Если переменная слишком далеко, то адресовать через другой регистр (тогда уж присвоить его), а R0 не портить.
А как же тогда вызовы? После вызовов надо опять грузить R0, желательно из той же константы, но если она далеко, то из новой такой же.

todo сдвиги инлайн командами

todo добавить недостающие команды типа REV



Keil:
  Example 9.  Placing literal pools

        AREA     Loadcon, CODE, READONLY
        ENTRY                              ; Mark first instruction to execute
start
        BL       func1                     ; Branch to first subroutine
        BL       func2                     ; Branch to second subroutine
stop
        MOV      r0, #0x18                 ; angel_SWIreason_ReportException
        LDR      r1, =0x20026              ; ADP_Stopped_ApplicationExit
        SVC      #0x123456                 ; ARM semihosting (formerly SWI)
func1
        LDR      r0, =42                   ; => MOV R0, #42
        LDR      r1, =0x55555555           ; => LDR R1, [PC, #offset to
                                           ; Literal Pool 1]
        LDR      r2, =0xFFFFFFFF           ; => MVN R2, #0
        BX       lr
        LTORG                              ; Literal Pool 1 contains
                                           ; literal Ox55555555
func2
        LDR      r3, =0x55555555           ; => LDR R3, [PC, #offset to
                                           ; Literal Pool 1]
        ; LDR r4, =0x66666666              ; If this is uncommented it
                                           ; fails, because Literal Pool 2
                                           ; is out of reach
        BX       lr
LargeTable
        SPACE    4200                      ; Starting at the current location,
                                           ; clears a 4200 byte area of memory
                                           ; to zero
        END                                ; Literal Pool 2 is empty

        
        
        
Procedure Call Standard for the ARM Architecture (AAPCS).
4 Using Assembly and Intrinsics in C or C++ Code 4.3 Calling assembly functions from C and C++
The AAPCS describes a contract between caller functions and callee functions. For example, for integer or pointer types, it specifies that:
- Registers R0-R3 pass argument values to the callee function, with subsequent arguments passed on the stack.
- Register R0 passes the result value back to the caller function.
- Caller functions must preserve R0-R3 and R12, because these registers are allowed to be corrupted by the callee function.
- Callee functions must preserve R4-R11 and LR, because these registers are not allowed to be corrupted by the callee function. 
R13=SP
R14=LR (link register, адрес возврата)
R15=PC

у нас сейчас не так: r0=rtemp, r1..r4 - регистры данных (r1=результат), параметры не передаются в регистрах
r7=0xff
r8=0x00
r5,r6 свободны