А при чем здесь вообще подтяжка на CLK?
Компы сами по себе работают стабильно.
На системный разъем тактовый сигнал через инвертор идет.
Вид для печати
А при чем здесь вообще подтяжка на CLK?
Компы сами по себе работают стабильно.
На системный разъем тактовый сигнал через инвертор идет.
Не вижу где, например в Max 128 CLK на разъем идет через какой-то инвертор.
В МАХе нет. Там напрямую с ПЛИСины.
А при чем тут это? Разговор вроде про подтяжку CLK на тактовом входе процессора шел.
Divmmc и nanoSD - это версии одного и того же устройства, прошивки для 9572 у них одинаковы?
Я нашел только jed-файл версии 1.0-1, но у меня с ним nanosd не стартует: после включения и сброса с убирающимися полосками - матрас.
То есть высокий уровень на /romcs выставляется после сброса исправно, но на этом все. Пока не пойму, где накосячил, решил вот узнать, а то ли вообще я в нее заливал ?
ПЗУ прошито esxdos 0.8.8, jedec-файл в xilinx заливал вот этот:
http://aticatac.altervista.org/portale/?q=node/13 , прошилось все без вопросов.
С чего начинать дебаг ? Тактовую посмотрю (осциллографа пока нет), ПЗУшка вроде должна быть прошита (пытался вместо нее засунуть РФ2 с тестом памяти, чтоб увидеть разницу - но ее нет, /romoe с ПЛИСки неактивный). Что еще, есть идеи?
Уже хорошо, что хоть не ошибся устройством )
Покупал у Павла все кучкой вместе с платой. Точнее, с двумя платами - там их две на листе. Отдельно покупал только мелочевку - транзисторы, конденсаторы, светодиоды, панельку - однорядный цанговый сокет - резал его по 14 пин и запаивал под 28c64 в DIP - это чтоб 7592 была вся в доступе, а она наполовину под ПЗУшкой находится.
Разъем брутфорсить не пытался, вроде смысле на было, а вот пайку на ногах плиски уже всю прозванивал, в т ч попарно соседние ноги. Впрочем, там плата с белой маской и все шикарно смотрится на просвет лампочкой или телефоном. И с пайкой-то все хорошо...
Еще один тупой вопрос: а esxdos без вставленной карты sd вообще себя как-то проявляет ? Например, ругается ли, что носителя нет ? Или может он в этом случае ПЗУ и вырубает ?
Смысл в том что, прозвонив можно удостовериться, что адресные линии и линии шины данных не замкнуты. Здесь имелось в виду, чтобы прозвонить ША и ШД на КЗ, просто на разъеме их легче прозванивать, чем на выводах микросхем.
Во время загрузки Вы увидите, что SD карта не примонтировалась, и соответственно не загрузятся файлы ESXDOS.SYS, NMI.SYS и BETADISK.SYS. Кстати если будет проблема с клоком, то и тут, просто, SD карта не примонтируется. Однако после всего этого Спектрум просто вывалится в SOS 48 ну и естественно не будут выполняться команды ESXDOS.
https://pic.maxiol.com/thumbs2/15931...xdosload01.jpg
Если при включении выполняется кусок штатного ПЗУ (черный экран, полоски убираются), то вероятность залепона на шинах крайне мала, разве что старшие адресные линии. Но проверю, спасибо за мысль.
А для чего в цепи CLK стоит триггер шмидта, да еще и после АГ3 - какую проблему он решает ?
Периодически возвращаюсь к своей плате nanoSD - пока результата нету.
Уже и спек другой (тоже Ленин1, уже с корректировкой дешифрации клавиатуры и зарубленным кемпстоном), на разъеме а-ля ZXBUS вытащено все, что требуется divmmc - /NMI, подтянутый к единице, /ROMCS в ПЗУ выведен через диодное "ИЛИ" на ZXBUS 25B (подача единицы отрубает внутреннее ПЗУ). Но итог - "все те же на манеже".
При запуске или сброс в бейсик48 с мигающим курсором сразу после Ltd (и не реагирует ни на клавиатуру, ни на NMI), или меняющийся мусор. А reset выполняется с моментальной перерисовкой белого экрана и заставки бейсика48, НО без очистки экрана и убирающихся полосок ! Через некоторое время это все может перейти в состояние с цветным мусором на экране и уже не сбрасываться в бейсик до выключения. Индикатор выбранной SD-карты может гореть, может не гореть - зависит от какой-то случайности.
ПЗУ считывал и оно живое, в нем ESXDOS 0.8.8. Пайку ПЛИС и всех компонентов, насколько можно, проверил.
Если вынуть ПЗУ из nanoSD (у меня в панельке) - должен ли отображаться матрас ? У меня вместо него мусор.
Существует ли где-то описание логики работы divmmc ? С указанием портов, адресных окон, логики переключения страниц ОЗУ и перехвата обращений по точкам входа в обработчики ? (адреса последних я увидел в исходниках прошивки, но что там должно быть и как оно работает - не понял).
Надо отлаживать как-то по частям, пока не пойму, как.
В теме на барахолке довольно много инфы
https://zx-pk.com/forum/viewtopic.php?f=7&t=10557
Да, там есть схемы и инфа по сборке, в т ч по ошибкам разводки сокета sd в первых версиях платы. Ну и собственно процесс допиливания платы до тиражной версии.
А вот бы еще найти что-то по логике работы самого устройства - с точки зрения софтового управления узлами. Ну чтоб проверить адекватность реакции ПЛИС в отлаживаемом экземпляре. Существует такое ?
Тут исходники для CPLD от автора https://github.com/mprato/DivMMC/blo...mmc/divmmc.vhd
Тут что-то по проблеме тактирования данного устройства http://blog.tynemouthsoftware.co.uk/...mc-future.html
P.S. На Ленинграде-2 у меня не заработало.
За вторую ссылку спасибо, буду вникать - видимо там внятно расписано, зачем был применен триггер шмидта на сигнале clk и прочие хитрости с тактовым сигналом (в nanosd применен еще одновибратор с вариацией выбора прямого/инверсного выхода - тоже пока не разобрался, зачем).
А на ленинграде он как не заработал ? Спек стартовал ? esxdos или какая там была прошитая ось - инициализировался ? Или показывал матрас при включении ? И заработал ли он на чем-то другом, кроме ленинграда ?
Исходники вчера тоже смотрел, хочу попробовать собрать на чем-то более знакомом (альтера уже стала почти родной, а xilinx со мной чего-то не дружит). Жду альтеру 7128s, может быть получится всю эту схему в 5 вольтах пересоздать и чего-нибудь с ней добиться.
Забавно, у них там действительно непонятно что было от модели к модели. У некоторых 'хиленький меандр' больше похож на полупериоды синусоиды.
Просмотрел. Ребята воевали за универсальность устройства и совместимость со всеми старыми и новыми машинами, в которых бывает как одинарный, так и двойной rom, а также теми, у кого вообще нет clock на коннекторе.
Главный вывод у них из всего этого - можно использовать автономный генератор и вообще не привязываться к качеству CLK и его наличию. У них работало стабильно в частотах от 3,9 до 4,2 мгц, в серию оно пошло с кристаллом на 4 мгц, а нужно оно только для тактирования spi на картах памяти и совершенно не требует синхронности со спеком (раздел Breakthrough).
Однако, прозрение )
Из этого следует, что все эти танцы с бубном для наших клонов действительно нужно выкинуть. Максимум - скорректировать уровень для 3-вольтовой логики.
Мне это тоже не совсем ясно, но вот кусок исходника CPLD.
И это единственное место, где обрабатывается состояние clock. Здесь по спаду clock происходит либо смена состояния передачи (idle -> sample), либо чтение шины данных в регистр для передачи (состояне меняется sample -> transmit), либо выполняется один цикл из 16 обмена по SPI, в каждом нечетном из которых формируется один импульс spi_clock - чтение и запись бита. Больше clock ни к чему не привязан и синхронность с циклами CPU вроде как и не нужна.
Данные на шине данных тоже формируются только на основе /iorq, /rd и /m1 и тоже не зависят от тактовых импульсов проца:Код:-- spi transmission/reception
-- Update transmission state
process(clock, reset)
begin
if reset = '0' then
transState <= IDLE;
TState <= (others => '0');
fromSDByte <= (others => '1');
toSDByte <= (others => '1');
toCPUByte <= (others => '1');
elsif falling_edge(clock) then
case transState is
when IDLE => -- Intercept a new transmission request (port 0x3F)
if address = zxmmc_spi_port and iorq='0' and m1='1' then -- If there is a transmission request, prepare to SAMPLE the databus
transState <= SAMPLE;
end if;
when SAMPLE =>
if wr = '0' then -- If it is a SEND request, sample the CPU data bus
toSDByte <= D;
end if;
transState <= TRANSMIT; -- then start the transmission
when TRANSMIT =>
TState <= TState + 1;
if TState < 15 then
if TState(0) = '1' then
toSDByte <= toSDByte(6 downto 0)&'1';
fromSDByte <= fromSDByte(6 downto 0)& spi_datain;
end if;
else
if TState = 15 then -- transmission is completed; intercept if there is a new transmission request
if address = zxmmc_spi_port and iorq='0' and m1='1'and wr='0' then
toSDByte <= D;
transState <= TRANSMIT;
else -- else we'll go in IDLE state.
transState <= IDLE;
-- TState <= "0000";
end if;
toCPUByte <= fromSDByte(6 downto 0)& spi_datain;
end if;
end if;
when OTHERS =>
null;
end case;
end if;
-- SPI SD Card pins
SPI_clock <= TState(0);
spi_dataout <= toSDByte(7);
end process;
Вот и вопрос: а зачем тут нужна синхронность с циклами CPU ?Код:D <= toCPUByte when (address = zxmmc_spi_port) and (iorq = '0') and (rd = '0') and m1='1' else "ZZZZZZZZ";
Не знаю как со стороны софта выполняется ожидание передачи байта по spi, но могу предположить, что там просто цепочка nop-ов в сумме на 16 тактов процессора. Тогда становится логичным, почему упомянутая частота генератора должна быть равна или НЕМНОГО выше процессорной - чтобы обмен прошел за это число тактов. И при автономном генераторе лучше, чтоб была выше (рассинхронизация обмена в пределах одного такта CPU не вызовет задержки обмена по spi).
Поправьте меня, если несу пургу, но хочется хоть что-то в этом понять.
- - - Updated - - -
Аха, клево, значит конфигурация памяти в DivIDE рулится в основном через порт управления #E3. В нижних таблицах показаны значения маппирования ROM (0000-1FFF) и банков RAM (#0000-1FFF и #2000-3FFF) и показаны точки входа маппирования RAM для перехвата ряда адресов (reset, nmi, int im2, trdos и неких процедур load и save).
И наверное в DivMMC оно все так же, коли все работает с одним и тем же esxdos.
Эт чо получается, там из огромной озухи используется всего четыре страницы по 8К ?? Я думал, что bank(3 downto 0) - это четырехразрядный номер банка, а оказывается работают только bank0-bank3 и это просто прямые сигналы выбора одного из 4 банков ?
В DivMMC номер банка 6-разрядный и вроде как в него пишется действительно номер страницы, но еще надо искать, сколько этих страниц адресуется реальным ПО
А вот то, что вверху таблицы, относится только к управлению ATA-устройством и для SD неприменимо.Код:elsif rising_edge(divideio) then
bank(5 downto 0) <= D(5 downto 0);
mapram <= D(6) or mapram;
conmem <= D(7);
end if;
Собственно, вот тут немного подробностей по divmmc в разделе "Some techtalk". Возможно не скажу ничего нового, но для меня это было находкой: DivMMC - это гибрид из 1) DivIDE в части маппирования 8К-страниц памяти ROM+RAM и управления ей через регистр конфигурации (порт #E3) и из 2) ZXMMC в части обмена с картой памяти по SPI. Только здесь для SPI используются порты #E7 (zxmmc_control_port) и #EB (zxmmc_spi_port) вместо #1F и #3F соответственно.
В итоге мы имеем два почти независимых устройства и первое всего слегка сложнее порта конфигурации #7FFD, причем ему не нужен clock. ПЗУ должно мапиться в нижние 8К сразу после reset-а.
Но на Ленине этого не происходит ((
Конфликтовать divmmc на ленинграде может разве что с портом кемпстон-джойстика - все три адреса портов divmmc имеют A0=1 и в исходном Ленине при чтении любого из портов #E3, #E7, #EB отзовется кемпстон. У меня кемпстон зарублен (/CS мультиплексоров выбирается только при A0=0) и соот-но конфликта нет. Но и не в этом причина.
У меня есть DivIDE 5.7C, который точно работал на Арлекине. При подключении его к Ленину я тоже вижу МАТРАС. То есть при сбросе у него /ROMCS правильно встает в единицу, отключает штатное ПЗУ, но он не включает свое. Есть идеи, почему ?
Во всем Ленине из читаемых портов - только клавиатура, кемпстон и tape in.
Из записываемых - только #FE (бордюр, спикер, tape out).
Записываемые у меня поправлены для неконфликта с AY по A0=0 и они нам сейчас неинтересны, т.к. у divmmc все три порта имеют A0=1 и в #FE никак не попадут.
В читаемых портах клавиатура и tape in - это все #xxFE (A0=0), с divmmc не пересекаются.
А вот кемпстон при A0=1 мог пересекаться, но это тоже исправлено - мультиплексоры клавы/кемспстона сейчас отзываются только на клаву (A0=0).
Вот схема проделанного безобразия:
https://yadi.sk/i/qwYbOS9jkC15Og
Пытаюсь понять как работает 'маппер' в DivIDE/DivMMC. Эскпериментирую в emu, а там, глядишь и в реале, на рассыпухе, есть желание его сделать.
Если представить карту памяти, то получается 8 вариантов.
Два бита из регистра управления Е3h, CONMEM-бит_7 и MAPRAM-бит_6 и бит, назову его trap - активация пеключения при попадании в определенные адреса.
если судить из этого описания DivIDE:
--------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------Цитата:
So, when CONMEM is set, there is:
0000-1fffh - EEPROM/EPROM/NOTHING(if empty socket), and this area is flash-writable if EPROM jumper is open.
2000-3fffh - 8k bank, selected by BANK 0..1 bits, always writable.
When MAPRAM is set, but CONMEM is zero, and entrypoint was reached:
0000-1fffh - Bank No.3, read-only
2000-3fffh - 8k bank, selected by BANK 0..1. If it's different from Bank No.3, it's writable.
When MAPRAM is zero, CONMEM is zero, EPROM jumper is closed and entrypoint was reached:
0000-1fffh - EEPROM/EPROM/NOTHING(if empty socket, so open jumper in this case), read-only.
2000-3fffh - 8k bank, selected by BANK 0..1, always writable.
Otherwise, there's normal speccy memory layout. No modified ROM, no shit.
вариант 1) получается, что при CONMEM==1 не имеет значение состояние бит MAPRAM и trap, всегда будет 'DivROM' и некая страница 'DivRAM'
при CONMEM==0 получаем:
вариант 2) MAPRAM==1, trap==1, когда первые 8КБ, это третья страница 'DivRAM' только чтение, а вторые 8КБ, это некая страница 'DivRAM'
вариант 3) MAPRAM==0, trap==1, повторяем вариант 1)
вариант 4-8) все остальные варианты, это обычное ПЗУ ZX48.
итого:
если CONMEM==0, MAPRAM==0, trap==0 карта=0, вариант 4)
0000-3fffh 16k normal speccy EEPROM memory layout
если CONMEM==0, MAPRAM==0, trap==1 карта=1, вариант 3)
0000-1fffh - EEPROM/EPROM/NOTHING(if empty socket, so open jumper in this case), read-only.
2000-3fffh - 8k bank, selected by BANK 0..1, always writable.
если CONMEM==0, MAPRAM==1, trap==0 карта=2, вариант 4)
0000-3fffh 16k normal speccy EEPROM memory layout
если CONMEM==0, MAPRAM==1, trap==1 карта=3, вариант 2)
0000-1fffh - Bank No.3, read-only
2000-3fffh - 8k bank, selected by BANK 0..1. If it's different from Bank No.3, it's writable.
если CONMEM==1, MAPRAM==0, trap==0 карта=4, вариант 1)
если CONMEM==1, MAPRAM==0, trap==1 карта=5
если CONMEM==1, MAPRAM==1, trap==0 карта=6
если CONMEM==1, MAPRAM==1, trap==1 карта=7
0000-1fffh - EEPROM/EPROM/NOTHING(if empty socket), and this area is flash-writable if EPROM jumper is open.
2000-3fffh - 8k bank, selected by BANK 0..1 bits, always writable.
--------------------------------------------------------------------------------------------------------------------
вот так я дополняю конфигурацию в emu ZX_Spectrum_48:
Скрытый текст
cpu : z80 {
debug=cas
debug=trap
mem=mm
int[FF]=vid.irq
port[a3]=hdd.data8[0]
port[a7]=hdd.data8[1]
port[ab]=hdd.data8[2]
port[af]=hdd.data8[3]
port[b3]=hdd.data8[4]
port[b7]=hdd.data8[5]
port[bb]=hdd.data8[6]
port[bf]=hdd.data8[7]
port[E3]=portE3
port[E7]=sdcard.ss
port[EB]=sdcard.data8
port[FD]=portFD
port[FE]=sys.data[0]
}
biosESX : Memory {
rom="ZX\esxmmc.bin"
}
mem2 : Memory {
size=20000
frame[0].size=2000
frame[0].page=portE3.portA[0-3]
}
mem2p : MemMap {
page[3]=portE3.portA[3]
page[2]=portE3.portA[2]
page[1]=portE3.portA[1]
page[0]=portE3.portA[0]
map[15][0000-1FFF]=mem2[1e000]
map[14][0000-1FFF]=mem2[1c000]
map[13][0000-1FFF]=mem2[1a000]
map[12][0000-1FFF]=mem2[18000]
map[11][0000-1FFF]=mem2[16000]
map[10][0000-1FFF]=mem2[14000]
map[9][0000-1FFF]=mem2[12000]
map[8][0000-1FFF]=mem2[10000]
map[7][0000-1FFF]=mem2[e000]
map[6][0000-1FFF]=mem2[c000]
map[5][0000-1FFF]=mem2[a000]
map[4][0000-1FFF]=mem2[8000]
map[3][0000-1FFF].ro=mem2[6000]
map[2][0000-1FFF]=mem2[4000]
map[1][0000-1FFF]=mem2[2000]
map[0][0000-1FFF]=mem2[0000]
}
mm : MemMap {
page[2]=portE3.portA[7]
page[1]=portE3.portA[6]
page[0]=trap.output
map[0][0000-3FFF]=bios[0000]
map[0][4000-FFFF]=mem1[0000]
map[1][0000-1FFF]=biosESX[0000]
map[1][2000-3FFF]=mem2.frame[0]
map[1][4000-FFFF]=mem1[0000]
map[2][0000-3FFF]=bios[0000]
map[2][4000-FFFF]=mem1[0000]
map[4][0000-1FFF]=biosESX[0000]
map[4][2000-3FFF]=mem2.frame[0]
map[4][4000-FFFF]=mem1[0000]
map[5][0000-1FFF]=biosESX[0000]
map[5][2000-3FFF]=mem2.frame[0]
map[5][4000-FFFF]=mem1[0000]
map[3][0000-1FFF].ro=mem2[6000]
map[3][2000-3FFF]=mem2p
map[3][4000-FFFF]=mem1[0000]
map[6][0000-1FFF]=biosESX[0000]
map[6][2000-3FFF]=mem2.frame[0]
map[6][4000-FFFF]=mem1[0000]
map[7][0000-1FFF]=biosESX[0000]
map[7][2000-3FFF]=mem2.frame[0]
map[7][4000-FFFF]=mem1[0000]
initpage=0
}
portE3 : K580ww55 {
}
trap : exec-sensor {
range[0000-0001]=1
range[0008-0009]=1
range[0038-0039]=1
range[0066-0067]=1
range[04c6-04c7]=1
range[0562-0563]=1
range[3D00-3DFF]=1
range[1FF8-1FFF]=0
}
sdcard : sd-mmc {
image="zx\SanF2.raw"
}
hdd : cf-ide {
drive[0].image="zx\SanF2.raw"
drive[0].geometry=1024C16H63S
; ca a (cat a)
}
[свернуть]
но ничего не работает.
Переключение DivROM и страниц DivRAM в отладчике видно, но при попытке из DivROM вывести текст приглашения, идет вызов функции ПЗУ ZX48, там далее, вызов на rst 8, его перехват(trap) на DivROM, а вот обратно возврат происходит в пустую страницу DivRAM 0х2246...
Получается, что то не так с распределением страниц, где ошибка, может кто подсказать?
Нашел пару ошибок в конфигурации, исправил сообщение выше, теперь fatware и tbios находят мастер ide диск, а вот ESXdos никаких признаков жизни не подает.
Смущает в описании DivIDE, что записав один раз бит MAPRAM, можно его уже не указывать при установке страниц, а карта памяти будет как при установленном бите. В конфигурации выше это не учитывается, так ли это обязательно, и, вообще, правильно ли я это понимаю?
Не пойму способ переключения к основной ПЗУ ZX:
Цитата:
The one-instruction delay can be used to distinguish between nested calls to
the same place. To do this you should place different instructions at the
entry point address than is in the original ROM. The first call will execute
the original instruction, but any subsequent call will execute the
instruction in the paged-in memory.
Задержка в одну инструкцию может использоваться, чтобы различать вложенные вызовы
в одно и то же место. Для этого вы должны разместить другие инструкции на
адрес в основном ПЗУ. Первым вызовом будет выполнена
исходная инструкция, но любой последующий вызов выполнит
инструкцию в DivRAM странице памяти.
что это значит, может кто это прояснить?Цитата:
This is particularly useful for avoiding nested NMI calls, which can not be
easily implemented using hardware. It also allows the divIDE to use INTs for
timing. When divIDE code is excuted, external calls will map divIDE out and
continue at the original code at 0038h, but nested INTs can jump to
different code.
Это особенно полезно для обработки вложенных вызовов NMI, которые не могут быть
легко реализуемы аппаратно. Это также позволяет divIDE использовать прерывания INT для
учета времени. Когда выполняется код divIDE, внешние вызовы отключат divIDE и
продолжат исполнение исходного кода с 0038h, но вложенные прерывания INT перейдут к выполнению
другого кода.
существует некая задержка в одну инструкцию на переключение? эта задержка актуальна только на возврат к основной ПЗУ? сама возможность такой задержки на одну инструкцию триггерная?
как то я совсем запутался...
Несколько раз прочитал и тоже не пойму, почему это one instruction delay. Может это плохой перевод с испанского/польского/еще какого-то неведомого языка ? Задержка-то не на одну инструкцию, а на один вход в адрес - скорее, 'one call delay'. Исключает вложенные вызовы nmi-обработчика из самого же себя. Первый вызов, например, на 0038h выполняет код оригинального ПЗУ, второй вызов по этому же адресу мапит какую-то из страниц divide и выполняет переход на код, который находится в ней.
Также позволяет использовать INT для тайминга в divIDE- первый вызов по INT-у отключит пзу divIDE и выполнит оригинальный обработчик основного пзу, второй же вызов к этому адресу уже будет выполнять код из пзу divIDE (вот тут я не пониамаю, что будет с третьим и последующими).
А где можно почитать сей доблестный документ ? Я одно время очень искал, но так и не нашел описания логики для divIDE/mmc.
Сам документ найти не проблема, на этой страничке в разделе technical documentation - divIDE programming model, это будет версия 1.03, а в архиве, в разделе download - FATware 0.14a, версия 1.04 (сравнил их построчно, отличий, по сути, нет).
есть у меня еще, вероятно одно из первых описаний:
Скрытый текст
Цитата:
DivIDE programming model
------------------------
DivIDE interacts with ZX Spectrum using I/O accesses or automatically by
replacing original ZX-ROM with its own memory, when CPU fetch from an
entry-point is detected (and such behavior is somehow allowed).
DivIDE contains 8 kB ROM (could be not present, EPROM or EEPROM, in the third
case it's in-system reprogrammable) and 32-512 kB RAM. DivIDE can use system
from 3rd 8k bank of its RAM, this is suitable especially for safe system
development. Accidental EEPROM damage (due to unlucky out from crashed code)
is fused by the on-board jumper.
All ports are decoded using A0..A7 address-wires only. So you can access all
eight IDE-registers from so caled command block (rrr=0..7) at addresses
xxxx xxxx 101r rr11. Other divIDE features are controlled using dedicated
port at address xxxx xxxx 1110 0011, which belongs to divIDE CONTROL REGISTER.
IDE command block registers
---------------------------
[ DATA REGISTER (R/W) ]
xxxx xxxx 1010 0011, 0a3h, 163
This register serves for reading or writing sectors. It's 16-bit wide, so
divIDE is joining write-pairs into words and splitting readed words into bytes.
When reading from this register, each ODD access will return low byte of
readed word (while high byte is stored into latch and buffer pointer is shifted
to next word). Each EVEN access will return that high byte, stored in previous
read access to DATA REGISTER.
When writing to DATA REGISTER, each ODD access will store the byte into latch.
Each EVEN access will join the previously stored low portion with actual byte
(considered to be high portion), and this word is written into harddrive (and
next word in harddrive buffer is pointed).
After any access to non-data command block registers (rrr=1..7) or to divIDE
control register, following DATA REGISTER access is considered to be ODD.
Accesses outside divIDE ports cannot change the EVEN/ODD state. After reset or
power-on, this state is unknown.
[ ERROR REGISTER (R) / FEATURES REGISTER (W) ]
xxxx xxxx 1010 0111, 0a7h, 167
[ SECTOR COUNT REGISTER (R/W) ]
xxxx xxxx 1010 1011, 0abh, 171
[ SECTOR NUMBER REGISTER (R/W) (too LBA bits 0..7) ]
xxxx xxxx 1010 1111, 0afh, 175
[ CYLINDER LOW REGISTER (R/W) (too LBA bits 8..15) ]
xxxx xxxx 1011 0011, 0b3h, 179
[ CYLINDER HIGH REGISTER (R/W) (too LBA bits 16..23) ]
xxxx xxxx 1011 0111, 0b7h, 183
[ DRIVE/HEAD REGISTER (R/W) (too LBA bits 24..28) ]
xxxx xxxx 1011 1011, 0bbh, 187
[ STATUS REGISTER (R) / COMMAND REGISTER (W) ]
xxxx xxxx 1011 1111, 0bfh, 191
For detailed desription of mentioned registers have a look at
http://www.t13.org .
DivIDE control register
-----------------------
[ CONTROL REGISTER (Write Only) ]
xxxx xxxx 1110 0011, 0e3h, 227
This register is write-only (readed data will be unknown). All bits are reset to
'0' after each power-on. Unimplemented bits, marked 'X', should be zeroed for
future compatibility issues with more than 32kB RAM DivIDEs.
7 6 5 4 3 2 1 0
[ CONMEM , MAPRAM, X, X, X, X, BANK1, BANK0 ]
Bits BANK1 and BANK0 select the 8k bank, which normally appears in area
2000-3fffh, when divide memory is mapped.
Bit MAPRAM can be set to '1' only (when it's '1', only power-on can return it
to '0'). This bit allows 8k bank No.3 to act as EPROM/EEPROM, and write-protects
it. Set it when system image is loaded into bank No.3 and you want to safe probe
it till the next power-on. Set it also when you haven't EPROM/EEPROM, and you
want to use system. (Because u will possibly re-install it from MAPRAM mode, you
will need CONMEM to override writeprotect. Because after returning to BASIC you
rely on original ROM, you must reset automapper, which could be left in
undesired state by previous bus transactions. Because it could be done only by
fetching code from off-area, u must set DI, then call 1ffbh ('RET'), ten CONMEM, loading image,
releasing CONMEM and setting MAPRAM, then EI. Then the return is safe.)
Bit CONMEM forces EPROM/EEPROM to 0000-1fffh and by BANK 1..0 selected bank to
area 2000-3fffh, regardless to the actual divIDE state or to physical presence
of EPROM/EEPROM. Bank in area 2000-3fffh is always writable, and in 0000-1fffh
always appears EEPROM/EPROM, which is writable when EPROM jumper is open. Use
it in third-party utilities for loading system or modules, or in system's
auto-upgrade process.
Memory mapping
--------------
Memory mapping could be invoked manually (by setting CONMEM), or automatically
(CPU has fetched opcode form an entry-point). Automatic mapping is active
only if EPROM/EEPROM is present (jumper EPROM is closed) or bit MAPRAM is set.
Automatic mapping occurs at the begining of refresh cycle after fetching
opcodes (M1 cycle) from 0000h, 0008h, 0038h, 0066h, 04c6h and 0562h. It's
also mapped instantly (100ns after /MREQ of that fetch is falling down) after
executing opcode from area 3d00..3dffh. Memory is automatically disconnected in
refresh cycle of the instruction fetch from so called off-area, which is
1ff8-1fffh.
The one-instruction delay could be used to distinguish between nested calls to
the same place. For such trick you will place different instruction at the
entrypoint address, than is in original ZX ROM. So the first call wil execute
original instruction, but subsequent one will jump to another code, because
divIDE memory was already mapped, with its changed opcode. It's great for 100%
avoidance of nested NMI, which cannot be implemented using pure combinatorial
hardware workaround. It allows divIDE to use INT for timing, when divIDE code is
performed (external calls will map later divIDE off and continue in #38h
original service, but nested INTs can jump to another work, and mapping off is
of course undesirable there).
In automatic mapping, when MAPRAM is set, in location 0000h-1fffh appears
write-protected Bank No.3, instead of EEPROM/EPROM. The meaning-priority is
(from lowest to highest) EPROM jumper -> MAPRAM -> CONMEM. So because that
jumper is no more significant when MAPRAM or even CONMEM is set, it's used
to distinguish between fused or unfused EEPROM state for CONMEM mode.
So, when CONMEM is set, there is:
0000-1fffh - EEPROM/EPROM/NOTHING(if empty socket), and this area is
flash-writable if EPROM jumper is open.
2000-3fffh - 8k bank, selected by BANK 0..1 bits, always writable.
When MAPRAM is set, but CONMEM is zero, and entrypoint was reached:
0000-1fffh - Bank No.3, read-only
2000-3fffh - 8k bank, selected by BANK 0..1. If it's different from Bank No.3,
it's writable.
When MAPRAM is zero, CONMEM is zero, EPROM jumper is closed and entrypoint was
reached:
0000-1fffh - EEPROM/EPROM/NOTHING(if empty socket, so open jumper in this case),
read-only.
2000-3fffh - 8k bank, selected by BANK 0..1, always writable.
Otherwise, there's normal speccy memory layout. No modified ROM, no shit.
And, that's all, Folks! Do you think, it's too complex? Read it once again.
Do you still think, it's not sane? Feel free to ask me (Zilog), my email is
xcimbal@quick.cz. I hope you will enjoy this piece of hardware, i have spent
months for optimising this marvelous piece of shit.
With regards
Zilog
[свернуть]
опять же, это сути текущего вопроса не раскрывает.
Казательно вызовов, на мой взгляд, тут именно речь идет об одной инструкции, а не всем обработчике.
Возможно, если мы находимся в DivROM, и вызываем код самой же DivROM, то вызов идет без задержки, а если же код исполняется в основной ROM и идет вызов на адрес, где должен сработать trap, то первая инструкция выбирается из основной ROM, а вторая из подмененой страницы DivROM/RAM.
Смотрю исходники fuse-1.5.7, как там организовано переключение, но не вижу ни каких 'хитростей'.
Инструкция может быть разной длины и выполняться за разное количество тактов. В железе такого умного контродя точно не реализовано (заглядывая в прошивку cpld), так что вряд ли речь про одну инструкцию. Если б речь была про однотактовую инструкцию или обязательный nop в начале обработчика, об этом бы написали отдельно.
Если я правильно понимаю этот абзац:
то получается, что есть разница в логике автомаппера при обработке областей 0000h, 0008h, 0038h, 0066h, 04c6h and 0562h и 3d00..3dffh. Для первой группы выполнится опкод основной ROM, и только после произойдет переключение на DivROM, а для второй группы (это наш TrDos) подмена произойдет сразу же. Отключение же произойдет с задержкой...Цитата:
Automatic mapping occurs at the begining of refresh cycle after fetching
opcodes (M1 cycle) from 0000h, 0008h, 0038h, 0066h, 04c6h and 0562h. It's
also mapped instantly (100ns after /MREQ of that fetch is falling down) after
executing opcode from area 3d00..3dffh. Memory is automatically disconnected in
refresh cycle of the instruction fetch from so called off-area, which is
1ff8-1fffh.
Залез я в исходники эмулятора spediv, который поддерживает DivIDE, и вот что увидел в функции обработчика шага опкода:
переключение карт памяти может быть как перед извлечением опкода, так и после извлечения опкода.Цитата:
#ifdef HAVE_DIVIDE
divide_premap(PC);
#endif
nextop = *PCP;
#ifdef HAVE_DIVIDE
divide_postmap(PC);
#endif
PC++;
Соответственно вот так выглядят обработчики попадания в адреса:
и здесь же видно, что автомаппер снимается только после извлечения опкода.Цитата:
void divide_premap(int addr) {
// "fetch state"
// mapper logic, see divIDE documentation for more info
// check for divide memory connecting betadisk entry points
if ((addr & 0xff00) == 0x3d00)
divide_automap = 1;
divide_mapper();
}
void divide_postmap(int addr) {
// "M1 state"
// mapper logic, see divIDE documentation for more info
// check for divide memory connecting entry points
if ((addr == 0x0000) ||
(addr == 0x0008) ||
(addr == 0x0038) ||
(addr == 0x0066) ||
(addr == 0x04C6) ||
(addr == 0x0562)) divide_automap = 1;
// check for original memory connecting entry points
if ((addr & 0xfff8) == 0x1ff8) {
divide_automap = 0;
}
divide_mapper();
}
а это уже остальная обработка распределения памяти, в соответствии с битами CONMEM и MAPRAM (текста много):
Скрытый текст
void divide_mapper() {
// if CONMEM is set, connect EEPROM (read only if JP2 is closed) and selected RAM bank (read/write)
if (DIVIDE_CONMEM(divide_int_port)) { // map eeprom+ram
if ((divide_memstate != 1) || divide_bank_changed) {
memcpy(PRNM(proc).mem, divide_eeprom, 0x2000);
memcpy(PRNM(proc).mem + 0x2000, divide_ram[DIVIDE_BANK(divide_int_port)], 0x2000);
}
divide_memstate = 1;
divide_bank_changed = 0;
return;
}
// if CONMEM isn't set and MAPRAM is set and:
// 1) if we reached "connecting" entry point, connect RAM #3 bank (read only) and selected RAM bank (if it is 3 it is too read only, else it is writable)
// 2) if we reached "disconnecting" entry point, connect original ZX Speccy ROM
if (DIVIDE_MAPRAM(divide_int_port)) {
// check for mb02 layout
if (!divide_jp2 && (DIVIDE_BANK(divide_int_port) > 1 || divide_memstate == 3)) {
if ((divide_memstate != 3) || divide_bank_changed) {
memcpy(PRNM(proc).mem, divide_ram[DIVIDE_MB02_BANK(divide_int_port)*2], 0x2000);
memcpy(PRNM(proc).mem + 0x2000, divide_ram[DIVIDE_MB02_BANK(divide_int_port)*2+1], 0x2000);
}
divide_memstate = 3;
divide_bank_changed = 0;
return;
}
if (divide_automap) { // map ram3+ram
if ((divide_memstate != 2) || divide_bank_changed) {
memcpy(PRNM(proc).mem, divide_ram[3], 0x2000);
memcpy(PRNM(proc).mem + 0x2000, divide_ram[DIVIDE_BANK(divide_int_port)], 0x2000);
}
divide_memstate = 2;
divide_bank_changed = 0;
} else { // map original_rom
if (divide_memstate) {
memcpy(PRNM(proc).mem, orig_rom, 0x4000);
}
divide_memstate = 0;
divide_bank_changed = 0;
}
return;
}
// if JP2 is closed and:
// 1) if we reached "connecting" entry point, connect EEPROM (read only) and selected RAM bank (read/write)
// 2) if we reached "disconnecting" entry point, connect original ZX Speccy ROM
if (divide_jp2) {
if (divide_automap) { // map eeprom+ram
if ((divide_memstate != 1) || divide_bank_changed) {
memcpy(PRNM(proc).mem, divide_eeprom, 0x2000);
memcpy(PRNM(proc).mem + 0x2000, divide_ram[DIVIDE_BANK(divide_int_port)], 0x2000);
}
divide_memstate = 1;
divide_bank_changed = 0;
} else { // map original_rom
if (divide_memstate) {
memcpy(PRNM(proc).mem, orig_rom, 0x4000);
}
divide_memstate = 0;
divide_bank_changed = 0;
}
return;
}
// else connect original ZX Speccy ROM
if (divide_memstate) { // map original_rom
memcpy(PRNM(proc).mem, orig_rom, 0x4000);
}
divide_memstate = 0;
divide_bank_changed = 0;
}
void divide_put_mem(int addr, byte *ptr, byte val) {
switch (divide_memstate) {
case 0:
// original ZX Speccy ROM - no update memory
break;
case 1:
// EEPROM + selected RAM bank
if (addr<0x2000) {
// is EEPROM writable?
if (divide_jp2) break;
*ptr=val;
// we have to make this change in divide memory too (not really mapped, only copied)
divide_eeprom[addr]=val;
divide_image_changed=1;
break;
}
*ptr=val;
// we have to make this change in divide memory too (not really mapped, only copied)
divide_ram[DIVIDE_BANK(divide_int_port)][addr-0x2000]=val;
break;
case 2:
// RAM #3 bank + selected RAM bank
// if it is 0k-8k page, write is disabled
// if it is 8k-16k page, write is disabled if is selected RAM #3 bank
if (addr<0x2000 || DIVIDE_BANK(divide_int_port)==3) break;
*ptr=val;
// we have to make this change in divide memory too (not really mapped, only copied)
divide_ram[DIVIDE_BANK(divide_int_port)][addr-0x2000]=val;
break;
case 3:
if (!divide_mb02_write_enable) break;
*ptr=val;
if (addr<0x2000)
divide_ram[DIVIDE_MB02_BANK(divide_int_port)*2][addr]=val;
else
divide_ram[DIVIDE_MB02_BANK(divide_int_port)*2+1][addr-0x2000]=val;
break;
default:
// printf("unknown divide state %d\n", divide_memstate);
;
}
}[свернуть]
Не знаю что такое ни первое, ни второе. Но идея с переключением уже понятна. Не понятно другое, а для чего использовать вариант с 'пост' переключением? при наличии варианта 'пред' переключения сразу же при попадании на адрес? ну ловить не 0008, а 0009, не 0038, а 0039 и тд. Вариант 'пост' в аппаратной реализации требует поймать попадания в адрес, защелкнуть признак попадания и в момент рефреша этот признак активировать, после чего все сбросить. К чему эти движения?
https://zx-pk.ru/threads/32145-zesarux-9-0.html
Первое.
А второе - это альтернатива DivMMC, но в отличие от сабжа - с исходниками. Но если разобрался - то конечно не нужно.
Делаю очередной подход с целью прикрутить divmmc к русским клонам, в частности, к Ленину.
Неудобно дебажить плату на xc9572xl при неясной ее работоспособности. Поэтому все воссоздал в теплых 5 вольтах на альтере epm7128slc84, ОЗУ
KM681000BLP-7L (128к*8), ПЗУ SST39SF020 (256к*8, но разумеется, из нее работает только нижних 8К) - у нее вход /WR кинул на +5в и к CPLD не подключал, т.к это не то ПЗУ, которое можно прошивать внутри платы.
Плюс ардуиновский модуль microSD-карты с 5-вольтовым питанием и буферами на *hc125 - но его пока даже не подключил, т к не могу разобраться со страницами памяти и запуском esxdos.
Исходники от Mario Prato пересобрались под мою CPLD без вопросов, распределил ноги в соответствии с монтажом и прошил.
В Ленине линия /RDROM, идущая к /OE штатного ПЗУ разорвана резистором 680 ом, вход /OE микросхемы вынесен на ZXBUS для подключения сигнала /romoe1 с divmmc (отключает внутреннее ПЗУ). /NMI отделен от всех прочих неиспользуемых, подтянут к +5в и выведен на разъем ZXBUS. Остальные линии вроде как не требуют внимания.
Прошил esxdos 0.8.5, включил. Но не тут-то было - стартуем с красивыми цветными узорами и на этом все.
Ожидалось увидеть хотя бы старт esxdos и ошибку поиска карт памяти, а дальше бы я занимался уже дебагом чтения SD. Но не тут-то было.
Вот варианты цветных узоров при старте - а вдруг будет информативным ? )
Вложение 73863Вложение 73862Вложение 73864
Пытался прошить Fatware - тоже при старте не увидел ничего здравого.
Если прошиваю в ПЗУ тест памяти (например Хахонова) - он стартует и прекрасно отрабатывает весь. То есть ПЗУ мапится при включении правильно.
Без ПЗУ в DivMMC отображается матрас - тоже все правильно.
Если снять перемычку EPROM на DIVMMC (режим перепрошивки для обновления), то стартует бейсик48 (или меню128 - у меня управление страницей ПЗУ128 отключаемое), откуда можно запустить загрузку с ленты и загрузить тестер ОЗУ DIVRAMKA.TAP (взял у VELESOFTа). Так вот тест 16 страниц ОЗУ (в сумме 128К) проходит успешно. То есть ОЗУ тоже мапится правильно.
Вложение 73865
Вопрос к тем, кто встраивал DivMMC в свои проекты на CPLD/FPGA - были ли какие-то особенности с запуском ESXDOS ? Что-то приходилось допиливать относительно версии 1.0 у Prato ?
Дешифрация портов и возможные конфликты на ленине уже обсуждались выше, у меня все подозреваемые (вроде бы) были устранены.
Что еще может мешать запуску ESXDOS ?
Покопался я тут в дизассмеблированном esxdos 0.8.5 и 0.8.8 с целью изучить набор используемых там портов, чтоб понять, где в русской железке может быть конфликт.
Потом скачал исходники этого самого "UnoDosTres". И первое время пытался найти отличия... А ощущения такие, что сорсы UnoDOS3 - это и есть дизассемблированный ESXDOS с автонумерованными метками, расписанными константами [системные вызовы, порты в/в] и вяло расписанными комментариями по тем кускам кода, которые оказались понятны - то есть комменты не от авторов кода.
https://github.com/cheveron/unodos-wolf
Сборка UNODOS3 выполняется кусками в разные бинарники, головной из которых длиной 8192 шьется в ПЗУ, а хвосты с адресов $2000 и $3000 склеиваются в один файл .SYS, который потом кладется на карту и грузится при старте системы в какую-то из страниц ОЗУ.
И поэтому вопрос про ESXDOS (да, я до сих пор его живьем не видел !) - может и он грузится так же ?
Если да, то у него не утилиты на карте лежат, а часть его тела ? Он вообще что-либо без карты отображать должен ?
И известно ли кому-нибудь, что было сделано с пентагоном, чтобы заставить вот это работать ?
https://www.youtube.com/watch?v=wyw-HhmTMOc
Ну то есть просто отключена дешифрация адресного диапазона и триггер трдоса не работает.
В остальном у пентагона2014 выбор всех устройств ввода-вывода аналогичен все русским спекам (т е ни о какой дешифрации по всей шине адреса речи не идет).
В чем тогда заключается сложность запустить это на наших клонах вроде ленина ? Чего им не хватает ?