• avatar aa-dav
  • 1
Недавно были опубликованы исходники порта Doom на SNES созданного Рэнди Линденом считай что своими силами (id software вообще поначалу не была в курсе): gbx.ru/?showtopic=142214
По ссылке я новость написал с минимумом технических подробностей (но история сама, имхо, интересная), но сам же заинтересовался чипом SuperFX — это 16-битный процессор с архитектурой созданной под влиянием идей RISC который на 16-битной SNES позволял эффективно рисовать 3Д-графику — у ЦП SNES с этим есть ряд проблем. А у SuperFX прям как у Z80Next есть команда PutPixel и много прочего. Чип SuperFX впаивался в картридж SNES аки маппер в денди и рулил и педалил 3Д-графоний на 16 битах.

Думаю краткий обзор архитектуры SuperFX станет предметом моей следующей статьи, но тут распишу идею из него которая мне тоже понравилась и которую в таком виде нигде не видел.
Опкоды там как правило однобайтовые, но бывают префиксы.
Шестнадцать 16-битных регистров во многих инструкциях кодируются в четырёх битах как в статье: 0xAB, где A — код инструкции, а B — код регистра. Из этого правила есть немало исключений, но рассмотрим, например, операцию сложения:

ADD R5

В своей первичной форме она рассматривает R0 как аккумулятор и к нему прибавляет указанный в инструкции регистр R5. Т.е. берёт аккумулятор и R5, складывает их и результат записывает обратно в аккумулятор. Окей.
Однако можно временно на одну эффективную инструкцию сменить что будет являться приёмником операции — это делает инструкция TO:

TO R4
ADD R5

Здесь эффект будет таков, что сумма R0 и R5 будет записана в R4. После выполнения ADD приёмник по умолчанию опять станет R0.
Точно так же есть однобайтовая инструкция FROM которая так же меняет временно какой регистр будет служить первым операндом:

FROM R3
TO R4
ADD R5

Выполнит следующее: сумма R5 и R3 запишется в R4, а аккумулятор окажется вообще не при делах.
Для еще больше краткости есть однобайтовая же инструкция WITH которая сразу выставляет и FROM и TO в один и тот же указанный регистр.
Но и это еще не всё — WITH взводит еще один внутренний флаг который модифицирует поведение инструкций FROM и TO если они встречаются после неё. В SuperFX отсутствует специализированная команда MOVE, зато если после WITH сразу же идёт FROM, то происходит копирование из регистра указанного во FROM в регистре запомненном в WITH. И наоборот — инструкция TO скопирует из регистра запомненного по FROM в регистр указанный в себе.

FROM Rn ; код 0xBn - выставляет Sreg в n
TO Rn   ; код 0x1n - выставляет Dreg в n
WITH Rn ; код 0x2n - выставляет и Sreg и Dreg в n

Довольно забавная система команд — байтово-ориентированная, но постоянно на каких то полухаках, префиксах и сменах текущих целей и назначений.
Каждый боролся за плотность кода как мог. :)))
Ахаха:D А всё началось с того, что я попросил Виктора впилить ldix и lddx как хоть какую-то альтернативу блиттеру, который они наотрез отказались делать. А дальше всё вышло из под контроля:D
Ну если не лезть внутрь ЦП, то это вполне реальный путь и он всё-равно будет теоретически намного быстрее обычного калькулятора, т.к. процессору останется исполнить ну десяток-два максимум инструкций.
Но вообще надо аккуратно исследовать вопрос — ведь калькулятор это в сути своей пресолиднейший кусок ROM, т.к. он и есть все функции бейсика включая USR которая должна обратно вывалиться в режим процессора.
дык, как и говорю, по im0 (либо пзу менять/подставлять озу)
+ еще загрузить корректный указатель стека кроме HL
как-то не особо «просто» уже всё это
Калькулятор держит стек в памяти как и ряд переменных в basic vars позволяющих определить где он заканчивается. Поэтому технически можно было бы обставить это дело таким образом, что код в RST 28 каким то образом запускает процесс калькулятора как нечто внешнее (накормив тем же адресом откуда надо выполнять инструкции), а по сигналу завершения берёт HL из известных переменных бейсика как он в общем то и делает скорее всего в оригинале.
Это как? Внешний доступ к памяти возможен, к регистрам — нет, а ведь в них по итогу калькуляторных процедур определённые значения ожидаются. Разве что обманом заставить проц по im0 выполнить команды загрузок, да еще нужные значения им подсунуть. Твой аух сумеет разве такое?
  • avatar tsl
  • 1
Последнее достаточно забавно, и мне даже нравится. В качестве FPU можно использовать AYX-32 (про который тут когда-нибудь будет статья). Самое простое — код по $0028 поменять на вызовы команд по портам АУ.
Ну насколько я понимаю, пока DMA перебрасывает данные процессор остановлен и прерывание тоже не приходит. Отличие в том, что во время переброски данных z80DMA всегда DI на Z80, а это очень неудобно. И я думаю в zxnDMA более упощенный, хотя не проверял, но вряд ли там всё возможности реализованы.
Это если развернуть фразу — значит в оригинальном z80DMA — этого делать нельзя?? хмм… И в чем же проявляется отличие, если на пальцах?
Так то я все демки для z80DMA написанные пересмотрел, работают в большинстве своем наверное правильно, как авторы задумывали. Но большинство работает и в режиме zxnDMA, иногда даже лучше, чем в нативном.
В эмулях работает DMA пока плоховато :( Хотелось бы поточнее эмууляцию.
c push моя идея… уж больно нравилась она мне в x86. test тоже полезная)
Главное отличие, что в burst mode можно теперь с прерыванием im2 работать. Я очень долго за это бился (:
P.S. Да по названию и «hidden message» легко гуглится второй вариант тут: soranews24.com/2012/12/19/obscene-messages-from-developer-discovered-in-1980s-nes-game/
И надо сказать он во многих очень важных вещах отличается от данного, но проясняет некоторые моменты. Такое ощущение что переводчики с японского были сильны в разных предложениях.
А это сообщение есть на английском? :)
Не понял вопроса. Английские тексты по ссылке в посте можно прочитать.
Причём замечу, что основа моего перевода взята по ссылке, но некоторые обороты речи были настолько непонятными, что я нашёл еще один вариант перевода на второго сообщения и понял из него что имеется ввиду, но ссылку на него потерял в итоге. Хотя если искать наверняка вылезет опять в результатах поиска.
Найсу!

Любой кто наткнулся на это — извращенец! Есть еще одно сообщение в Pachi–Com на (компьютере) MSX… Если ты извращенец — купи и посмотри! Однако, там окинавский диалект!

А это сообщение есть на английском? :)
К слову о Си и 8-битных процессорах буквально на днях наткнулся на KickC: forums.nesdev.com/viewtopic.php?f=2&t=20187
Пытаясь максимально сохранять синтаксис Си компилятор просто возвращается к корням — ЭВМ из 60-х и не поддерживает рекурсию. И всё начинает работать гладко и шелковисто и компилироваться в бодрый и довольно рабочий код.
Тот же CC65 на следующем коде (очень для него неудачном):

void str_cpy( char *dst, char const *src ) {
   while ( *dst++ = *src++ ) {}
}

Рожает следующий тихий ужас:

.proc   _str_cpy: near
.segment        "CODE"
        jsr     pushax
L0006:  ldy     #$03
        jsr     ldaxysp
        sta     regsave
        stx     regsave+1
        jsr     incax1
        ldy     #$02
        jsr     staxysp
        lda     regsave
        ldx     regsave+1
        jsr     pushax
        ldy     #$03
        jsr     ldaxysp
        sta     regsave
        stx     regsave+1
        jsr     incax1
        ldy     #$02
        jsr     staxysp
        ldy     #$00
        lda     (regsave),y
        jsr     staspidx
        tax
        bne     L0006
        jmp     incsp4
.endproc

А вот KickC в своём асмосинтаксисе (как можно догадаться KickAssembler) делает почти оптимально:

str_cpy: {
    .label dst = 4
    .label src = 2
  __b1:
    // *dst++ = *src++
    ldy #0
    lda (src),y
    sta (dst),y
    // while ( *dst++ = *src++ )
    lda (dst),y
    inc.z dst
    bne !+
    inc.z dst+1
  !:
    inc.z src
    bne !+
    inc.z src+1
  !:
    cmp #0
    bne __b1
    // }
    rts
}

Весьма впечатляющий результат, хотя видно что еще есть куда работать.
Отсутствие локальных переменных еще позволяет производить оптимизацию с размещением переменных и параметров в одном и том же месте если они не пересекаются в callstack. Тоже недоступная для Си вещь даже если шлёпать static.
Вот такой эффект от того что как в древнем Fortran когда не было там еще ключевого слова RESURSIVE.
Если тебе реально нужны компиляторы Си, тебе нужно развивать другие вещи. Я бы начал с команд типа ld r,(rr+n), ld r,(rr+r), push nn (единственная стоящая команда выше, мне кажется), и всяких add rr,nn. Потому что я ещё никого не видел, кто бы сказал, что Си проще компилировать в 6502, чем в Z80. Но вообще заниматься компилятором Си сложнее, чем очень много чем другим.
Я это всё понимаю. Речь о другом. Даже если вы просто возьмёте и сделаете «Z80 на стероидах», просто с кучей однотактовых команд, ничего не меняя, это уже будет подразумевать что паттерны хорошего кода поменяются. Вот там выше aa-dav пишет про неэффективность LDIR, что зачастую правда, но только если речь идёт о скорости копирования. С точки зрения компактности кода LDIR очень эффективна, а по скорости — не более чем посредственна, так что вы не найдёте, например, декомпрессора на спектруме без LDIR. Т.е. даже медленная LDIR — очень даже пригождается.

Ваш перелопаченный Z80 потребует пересмотра вообще всех таких привычных соображений, во всяком случае с точки зрения хорошо оптимизированного кода. Поэтому невозможно вообще что-либо сказать, ни про твои доработки с сегментом регистров а-ля геймбой, ни про доработки некста. Без точной информации о скорости команд, разговор получится ни о чём.
  • avatar tsl
  • 0
По опкодам.
Либо префиксировать каждую команду, либо включать отдельный блок расширенной ISA. Префикс можно выбрать либо ED, либо из команд типа LD R,R — где реги одинаковые. Второй метод позволяет сильно экономить память — по объему и машциклам, а также дает неограниченную свободу воли в выборе опкодов. Для крайней совместимости предусмотреть защелку, блокирующую включение доп. опкодов.

По набору команд.
Основная цель — С компиляторы. Полагаю, 256 байт для регфайла достаточно. Должна быть общая арифметика, хотя бы 2-операндная, между любыми ячейками регистрового файла. Объединение соседних ячей в пары/четверки. Адресация ячеек как непосредственно, так и регистрами. Постинкремент и предекремент адресующих регов.

Над конкретным набором команд надо садиться и думать.
Ну и конечно, сначала опробовать все это в эмуляторе, что несложно.
  • avatar tsl
  • 0
Такты в ФПГА реализации не всегда боттлнек, кое-что можно значительно оптимизировать. В основном же существующие корки имеют растактовки для совместимости.
  • avatar tsl
  • 0
Я посмотрел, но там ВСЁ другое.