• avatar SAA
  • 0
Монитор попроще чем виртуальная машина Возняка. Ваше исследование почитаю с удовольствием! :)
  • avatar SAA
  • 0
Хорошее замечание, включу в пример, часть кода. LINK — это регистр в который попадает значение IP для следующей инструкции, в случае записи в IP. То есть в случае с переходом (записью адреса перехода в IP) следующая инструкция на которую будет указывать IP это туда куда надо вернутся.

#label -> IP  ; Переход на адрес label и запись адреса следующей инструкции в LINK
R1 -> ALU.A
.........
label:
..............
LINK -> IP         ; возврат на команду R1 -> ALU.A


Можно сохранять LINK как и в случае с LR в ARM либо в ОЗУ, либо один из регистров общего назначения. Допустим R4 это стек.

; push LINK
R4 -> ADDR
LINK -> DATA    ; LINK 16 битный регистр, будет записан в память как слово за два такта
R4 -> ALU.A
#2 -> ALU.B
ADD -> R4       ; R4 += 2
; pop LINK
R4 -> ALU.A
#-2 -> ALU.B
ADD -> R4
ADD -> ADDR
DATA -> IP       ;  IP - 16-битный регистр, буден считан за два такта
  • avatar aa-dav
  • 1
P.S.
И еще по вашему процессору я не понял как делается CALL — LR вроде есть, но непонятно что в него записывать.
  • avatar aa-dav
  • 1
Стив Возняк неплохо это показал запихнув в 256 байт монитор для Apple-I
О! Спасибо за напоминание про плотность кода и виртуальный процессор Возняка — у меня ведь есть новый материал на эту тему. :)
  • avatar SAA
  • 1
А вот очень хороший пример! Действительно либо адрес в 16бит и борьба за каждый байт (ЕМНИП, Стив Возняк неплохо это показал запихнув в 256 байт монитор для Apple-I), либо 24/32 бита — «счастье всем и никто не уйдет обиженным». Адресного пространства так много что ARM выделяет в нем области для манипуляцией битами. :)

P.S. Статья про SuperFX будет крайне интересна!
  • 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.