Дзенская задачка про TMS320C25

Тема в разделе "WASM.ZEN", создана пользователем Black_mirror, 27 янв 2007.

  1. Black_mirror

    Black_mirror Active Member

    Публикаций:
    0
    Регистрация:
    14 окт 2002
    Сообщения:
    1.035
    Для решения задачки необходимы некоторые сведения об этом процессоре. В архиве находится дока с описанием всех команд этого процессора. Но самую необходимую информацию я попытаюсь привести здесь.

    Процессор является 16и-разрядным процессором гарвардской архитектуры, то есть код отдельно, данные отдельно (на самом деле шина одна, но с программной точки зрения всё выглядит именно так). Минимальной адресуемой единицей является одно 16и-разрядное слово. Команда занимает одно или два слова. Если команда занимает два слова, то второе слово является 16и-разрядным операндом который используется по усмотрению команды, то есть может быть адресом памяти данных или программ, являться константой учавствующей в вычислениях или загружаемой в регистр.

    В процессоре есть 32х разрядный аккумулятор ACC, восемь 16и-разрядных адресных регистров ar0-ar7, 9и-разрядный регистр номера текущей страницы DP, 3х разрядный указатель текущего адресного регистра ARP и некоторые другие регистры которые которые не имеют отношения к нашей задаче.

    В большинстве команд младшие 8 бит первого слова команды занимает адресное выражение (далее addr_expr). Это может быть 7и-разрядная константа к которой слева приписываются 9 бит номера текущей страницы (берётся из регистра DP) для получения полного 16и разрядного адреса или одно из следующих выражений:
    *,N - в качестве адреса используется содержимое текущего адресного регистра
    *+,N - после использования текущий адресный регистр увеличивается на 1
    *-,N - после использования текущий адресный регистр уменьшается на 1
    *0+,N - после использования к текущему адресному регистру прибавляется ar0
    *0-,N - после использования из текущего адресного регистра вычитается ar0
    *br0+,N - после использования к текущему адресному регистру прибавляется ar0 с реверсивным распространением переноса
    *br0-,N - после использования из текущего адресного регистра вычитается ar0 с реверсивным распространением переноса
    N это не обязательный параметр который может принимать значения от 0 до 7 и если присутствует, то загружается в ARP. То есть N определяет какой адресный регистр будет текущим при выполнении следующей команды. Если N отсутствует, то в следующей команде текущим останется тот же самый регистр.

    В данном процессоре имеется аппаратный стек на 8 уровней. Используется в следующих командах:
    call label - вызов подпрограммы, адрес следующей команды помещается в стек
    cala - аналогично, только адрес подпрограммы берётся из младшего слова ACC
    push - младшее слово ACC помещается в стек
    pop - слово из стека извлекается в ACC с заполнением старших разрядов нулями
    pshd addr_expr - слово из памяти помещается в стек
    popd addr_expr - слово из стека извлекается в память
    ret - возврат из подпрограммы
    trap - программное прерывание(по сути вызов подпрограммы с адресом 1E)
    Все перечисленные команды занимают 1 слово за исключением команды call которая занимает 2 слова.

    Всего в процессоре 3 внутренних и может быть подключено до 3х внешних источников прерываний. Таблица прерываний находится в памяти программ и начинается с 0 адреса, но имеет весьма странный вид:
    0000 b start - отсюда начинается выполнение программы при снятии сигнала RESET, так как далее начинается код обработчика в эти 2 слова поместим команду перехода
    0002 b int0 - переход к обработчику нулевого внешнего прерывания
    0004 b int1 - переход к обработчику первого внешнего прерывания
    0006 b int2 - переход к обработчику второго внешнего прерывания
    0008 дыра в 16 слов

    0018 b timer - переход к обработчику прерывания от таймера
    следующие два прерывания относятся к последовательному порту
    001A b recv - переход к обработчику прерывания возникающего при приёме слова
    001C b send - переход к обработчику прерывания возникающего при передаче слова
    001E b _trap - здесь начинается код обработчика прерывания по команде trap

    При возникновении прерывания адрес следующей команды сохраняется в стеке, а обработка других прерываний запрещается пока не будет выполнена команда eint. Прерывания будут разрешены только когда выполнится команда следующая за командой eint. Для возврата из прерывания используется пара команд eint/ret. Для обработчика trap команду перехода ставить не обязательно, можно сразу начинать писать полезные команды. Так же можно поступить с int2 пока не упрёмся с обработчик прерывания от таймера.

    Команды загрузки и сохранения:
    ldpk N - в DP загружается 9и-разрядный номер страницы
    larp arN - в ARP загружается номер регистра который станет текущим для следующей команды
    lark arN,const8 - загрузка 8-разрядной константы в указаный адресный регистр
    lack const8 - загрузка 8-разрядной константы в ACC
    lac addr_expr - загрузка ACC из указанной ячейки
    sacl addr_expr - сохранение младшего слова ACC в указанной ячейке
    lar arN,addr_expr - загрузка arN из указанной ячейки
    sar arN,addr_expr - сохранение arN в указанной ячейке
    lrlk arN,const16 - загрузка 8-разрядной константы в указаный адресный регистр
    lalk const16 - загрузка 8-разрядной константы в ACC
    Сложение/вычитание:
    addk/subk const8 - прибавление/вычитание 8-разрядной константы к ACC
    add/sub addr_expr - прибавление к ACC содержимого указанной ячейки
    adlk/sblk const16 - прибавление/вычитание 16-разрядной константы к ACC
    adrk/sbrk arN,const8 - прибавление/вычитание 8-разрядной константы к arN
    mar addr_expr - эта команда не обращается к памяти, но она модифицирует текущий адресный регистр как указанно в выражении, и еще может загрузить в ARP номер следующего регистра
    Префикс повторения:
    rptk const8 - следующая команда будет выполнена const8+1 раз
    rpt addr_expr - а здесь счётчик считывается из ячейки памяти, но всё равно используются только младшие 8 бит.
    Все перечисленные команды, кроме команд с const16 занимают 1 слово, команды с const16 занимают два слова.

    Команды пересылки память-память:
    blkp addr_expr,addr16 - содержимое ячейки памяти программ с адресом addr16 копируется в ячейку памяти данных указанную в адресном выражении
    blkd addr_expr,addr16 - содержимое ячейки памяти данных с адресом addr16 копируется в ячейку памяти данных указанную в адресном выражении
    tblr addr_expr - содержимое ячейки памяти программ с адресом равным младшему слову ACC копируется в ячейку памяти данных указанную в адресном выражении
    tblw addr_expr - содержимое ячейки памяти данных указанной в адресном выражении копируется в ячейку памяти программ с адресом равным младшему слову ACC
    blkp/blkd занимают 2 слова
    tblr/tblw занимают 1 слово


    После выполнения этих команд содержимое текущего адресного регистра изменяется как указано в адресном выражении. Если использовать эти команды с префиксом повторения, то после копирования каждого слова будет изменяться не только текущий адресный регистр, но также addr16 или адрес взятый из ACC(сам ACC после выполнения tblr или tblw не изменится) будут увеличиваться на 1.
    Если предположить что текущий регистр ar0, ar0 = 1000, ACC=2000, то с префиксом повторения данные команды сделают следующее:
    rptk N-1
    blkp/blkd *+,3000 ;скопирует N слов из памяти программ/данных начиная с адреса 3000 в память данных по адресу 1000

    rptk N-1
    tblr *+ ;скопирует N слов из памяти программ начиная с адреса 2000 в память данных по адресу 1000

    rptk N-1
    tblw *+ ;скопирует N слов из памяти данных начиная с адреса 1000 в память программ по адресу 2000


    Вроде всё необходимое для решения написал, теперь можно приступить к самой задачке:

    Команды записи константы в память в системе команд процессора нет. Поэтому в программе часто встречается код вида(предполагается что перед выполнением такого кода текущий регистр - ar0):
    lalk value16 ; загрузка 16-разрядной константы в ACC
    lrlk ar0,addr16 ; загрузка адреса ячейки(тоже константа) куда нужно записать константу в ar0
    sacl * ; сохранение константы в указанной ячейке
    Данный код занимает 5 слов.
    Если последние 2 команды заменить на
    ldpk addr16 >> 7
    sacl addr16 & 7Fh
    То код будет занимать 4 слова, но при этом меняется текущая страница, и её придётся востанавливать что опять даёт 5 слов.
    Можно ли написать такую подпрограммку, чтобы код её вызова и передачи ей value16 и addr16 занимал 3 слова? Поместить все константы в нулевую страницу или заменить их 8 битными чтобы использовать lack/lark не возможно.

    PS: Правильное решение писать только после того как другие напишут хотябы пару не правильных 8)