9.5 Эмуляция SENS
После того как я пришёл к выводу, что SENS это выход мультиплексора. Проблем с его реализацией не возникло. Хотя я очень долго пытался побороть желание всё это запихнуть в модуль CXD2545_CPU уж некоторые части слишком похожие были. Но потом решил, что лучше два маленьких хоть и похожих модуля, чем один огромный.
module CXD2545_SENS(
input sclk,
input clk,
input data,
input xlat,
input [15:0] sens_data,
output reg sens
);
reg [3:0] cnt;
reg [7:0] shift_reg;
reg [3:0] select_reg;
reg prev_clk;
reg prev_xlat;
always @(posedge sclk) begin
if((prev_xlat == 1'b1) && (xlat == 1'b0)) begin
cnt <= 0;
shift_reg[7:0] <= 0;
end else begin
if((prev_clk == 1'b0) && (clk == 1'b1)) begin
shift_reg[7:0] <= {data, shift_reg[7:1]};
if(cnt < 7) begin
cnt <= cnt + 1'b1;
end else begin
select_reg <= {data, shift_reg[7:5]};
cnt <= 0;
end
end
end
prev_xlat <= xlat;
prev_clk <= clk;
sens <= sens_data[select_reg];
end
endmodule
Ничего сложного тут нет, всё это я уже описывал и раньше. Только немного уточнений:
Имя | Описание |
sclk | Выход тактовой частоты процессора |
clk | Вход CLOK от CXD2545 |
data | Вход DATA от CXD2545 |
xlat | Вход XLAT от CXD2545 |
sens_data | Вход 16 сигналов |
sens | Выход этого самого SENS |
Чтобы управлять статусом этих пинов в систему был добавлен ещё один модуль PIO, на который и были подключены почти все пины SENS, кроме COUT:
CXD2545_SENS sens_inst(
.sclk(CPU_CLK),
.clk(REG_CLK),
.data(REG_DATA),
.xlat(REG_XLAT),
.sens_data({SENS_PIN[15:13], trc_toggle, SENS_PIN[11:0]}),
.sens(sens_out)
);
На самом деле всё это, наверное, усложнено и есть куда более простой вариант, но меня пугали всякие слова типа метастабильность и синхронный дизайн.
module CXD2545_SENS(
input clk,
input data,
input xlat,
input [15:0] sens_data,
output wire sens
);
reg [3:0] cnt;
reg [7:0] shift_reg;
reg [3:0] select_reg;
always @(posedge clk or negedge xlat) begin
if(xlat == 1'b0) begin
cnt <= 0;
shift_reg[7:0] <= 0;
end else begin
shift_reg[7:0] <= {data, shift_reg[7:1]};
if(cnt < 7) begin
cnt <= cnt + 1'b1;
end else begin
select_reg <= {data, shift_reg[7:5]};
cnt <= 0;
end
end
end
assign sens = sens_data[select_reg];
endmodule
9.5 Эмуляция COUT
Посмотрев снятые логи, я увидел, что приставка смотрит на COUT только когда использует «дальнее позиционирование» при помощи каретки. Поэтому было принято решение. Гнать туда меандр постоянно, но надо было угадать с частотой. Между двумя запросами COUT был промежуток примерно две миллисекунды, это где-то 250 герц максимум, что успеет воспринять приставка в таком темпе. Но это прям оочень максимум. Поэтому сразу сделал так чтобы можно было настраивать его, и по-хорошему наверно имело смысл повесить его на шину AvalonMM но было лень. В итоге родился такой модуль:
module CXD2545_TRACK_COUNTER(
input clk,
input [15:0] div,
input [15:0] toggle_cnt,
input trigger,
output reg toggle_clk,
output reg [31:0] track_count
);
reg [32:0] cnt_50;
reg [32:0] cnt_div_50;
reg prev_trigger;
reg [30:0] trc_cnt;
reg trk_clk;
always @(posedge clk) begin
if(cnt_50 < div) begin
cnt_50 <= cnt_50 + 1'b1;
end else begin
cnt_50 <= 0;
trk_clk <= ~trk_clk;
if(cnt_div_50 < 256) begin
cnt_div_50 <= cnt_div_50 + 1'b1;
end else begin
cnt_div_50 <= 0;
toggle_clk <= ~toggle_clk;
end
if((prev_trigger == 1'b1) && (trigger == 1'b0)) begin
track_count <= {1'b1, trc_cnt};
end else if((prev_trigger == 1'b0) && (trigger == 1'b1)) begin
trc_cnt <= 0;
track_count <= 0;
end else begin
trc_cnt <= trc_cnt + 1'b1;
end
prev_trigger <= trigger;
end
end
endmodule
Имя | Описание |
clk | Выход тактовой частоты процессора |
div | Предделитель частоты |
toggle_cnt | Делитель частоты, полученной от предделителя |
trigger | Триггер запуска и остановки счетчика выданых импульсов |
toggle_clk | Выход COUT |
track_count | Число треков которые мы насчитали между сигналами триггера |
CXD2545_TRACK_COUNTER trc_cnt_inst(
.clk(CPU_CLK),
.div(trc_div),
.toggle_cnt(256),
.toggle_clk(trc_toggle),
.trigger(trc_cnt_en),
.track_count(track_count)
);
И вот там где стоит константа 256, нужно было завести значение регистра 0xB, но так как оно приставкой всегда ставилось именно в 256, я решил, что и так сойдёт. После связки всего этого воедино, и теста в аудио плеере. Оказалось, что приставка нормально воспринимает пределитель 720 и выше. Игры тоже нормально грузились. И я начал проходить FF7, неспешно решая, всякие мелкие проблемы. Однако на ледяном уровне которые идёт после сноуборда(там где можно замерзнуть), приставке начало сносить крышу. Она металась лазером туда сюда, и нормально не работала. Глюк был плавающий, то есть нормально повторению не поддавался. В итоге я вывел на клавиатуру подстройку этого предделителя, и побаловавшись подобрал значение 1400 при котором и позиционирование было быстрое, и глюков не вызывало. В общем, в этом месте я получил рабочий эмулятор. Всем спасибо за внимание.
Не совсем. Остались ещё всякие мелочи, которые были в процессе, но хронологию их появления я не помню.
10. Всякие мелочи
10.1 A SGDMA, не умеет прерывать передачу
Да вот такой SGDMA бяка. Если началась передача, то остановить её уже не получится, он с головой уходит в работу и слышать ничего не хочет. Есть, конечно, вариант сделать ему ресет через регистр, но вот, что говорит официальная документация:
Executing a software reset when a DMA transfer is active may result in permanent bus lockup until the next system reset. Hence, Altera recommends that you use the software reset as
your last resort.
В общем можно всю шину завесить, и придётся вообще делать полный ресет, всей системе. Казалось бы что плохого. А вот что приставка отдала команду прыгнуть на несколько треков вперед. А у нас после этой команды успевают прилететь субканальные данные последнего посланного трека. Она это видит и понимает, что спозиционировалась не туда. И дает команду ешё прыгнуть, тут прилетает нормальный трек, но команда позиционирования уже улетела, и мы, выполнив ее, снова возвращаем не то, что надо. В общем, такое бывает редко, но могло задержать чтения нужного трека. Чаще она просто лишний раз шлет сигнал остановки привода и всё. Чтобы решить эту маленькую но проблему, я сделал модуль:
module avalon_st_drainer (
input wire clk, // clock.clk
input wire reset, // reset_sink.reset_n
output wire out_valid, // out.valid
output wire out_sof, // .startofpacket
output wire out_eof, // .endofpacket
output wire [31:0] out_data, // .data
output wire [1:0] out_empty, // .empty
input wire out_ready, // .ready
input wire in_valid, // in.valid
input wire in_sof, // .startofpacket
input wire in_eof, // .endofpacket
input wire [31:0] in_data, // .data
input wire [1:0] in_empty, // .empty
output wire in_ready, // .ready
input wire drain // conduit_end.export
);
assign out_eof = ((drain == 1'b0) && (lock_drain == 1'b0)) ? in_eof : 1'b0;
assign out_valid = ((drain == 1'b0) && (lock_drain == 1'b0)) ? in_valid : 1'b0;
assign in_ready = ((drain == 1'b0) || (in_sof == 1'b1)) ? out_ready : 1'b1;
assign out_sof = in_sof;
assign out_empty = in_empty;
assign out_data = in_data;
reg lock_drain;
always @(negedge clk) begin
if(drain == 1'b1) begin
lock_drain <= 1'b1;
end else begin
if(in_sof == 1'b1) begin
lock_drain <= 1'b0;
end
end
end
endmodule
Логика работы простая, модуль реализует сигналы шин Avalon-ST выхода и выхода. В обычном состоянии он просто шлёт вход на выход. Если пришёл сигнал drain модуль выставляет флаг lock_drain. И блокирует передачу сигнала out_valid чтобы модули, стоящие за ним, думали что данных нет. При этом сигнал in_ready наоборот рапортует, что готов принимать данные, в итоге данные принимаются, но не уходят. При поступлении сигнала in_sof, lock_drain сбрасывается в ноль и модуль просто начинает работать, посылая копию входа на выход. Управляется всё это опять же через обычный PIO.
Финальная версия SOPC теперь выглядит вот так:
10.2 Позиционирование гораздо хуже чем в оригинале
По факту оказалось, что приставка всё равно промахивается меньше при длинных переходах, чем мой код. Почему так происходит, я уже знал. Диск увеличивается от центра к краю, и длинна окружности растет. Данные же записаны с неизменным интервалом. И получается, что в конце диска на один оборот мы имеем больше секторов, чем в начале. Привод, ориентируясь на скорость поступления данных, регулирует скорость вращения диска, поэтому данные с привода, идут потоком равномерным. Но вот прыжок на один трек, в начале диска и в конце дают разный результат. Я где то читал(где уже не помню), что SUP-CPU имеет таблицу коррекции и при помощи неё он рассчитывает на сколько треков прыгнуть, чтобы оказаться в нужном месте. Я даже пытался её найти в прошивке, но надо сказать безуспешно. Тогда я написал письмо Martin'у Korth также известному, как Nocash с просьбой помочь в этом вопросе. Он достаточно быстро ответил, за, что ему огромное спасибо. И прислал нужные таблицы, с кусками ассемблерного кода, и пояснениями как оно все работает. Таблица была устроена следующим образом, в ней около 80 элементов(вообще там несколько таблиц для дисков с разным объемом записанных данных, но из за ошибки все равно используются только первые 71 элемент). И каждый элемент указывает сколько каждая минута звучания(ну и данных по совместительству) занимает треков. То есть элемент номер 4 у нас был 0xDD, значит 3 минута звучания, занимает 221 трек. А 57 элемент 0x6D, то есть 58 минута диска уже всего 109 треков. Приставка рассчитывает по этим данным как далеко переместить каретку. Я видоизменил таблицу, так чтобы мне было с ней удобно работать. И добавил в свой код, после чего позиционирование стало в разы лучше.
10.3 Вылет за пределы LeadOut
Иногда ещё до добавления правильно позиционирования, бывали моменты, когда мы улетали за пределы LeadOut. На SD карте обычно там был уже мусор, или образ другого диска. Поэтому приставку не хило колбасило. И заканчивалось перечитыванием TOC и попыткой повторить чтение данных. Это решилось просто, в заголовоке которые идёт в начале образа SD карты, описаны три параметра, первый это первый сектор образа, второй начало зоны LeadOut, и третий длина образа. Если мы вдруг оказались за пределами образа, я выполняю прыжок на начало зона LeadOut. Работает отлично.
11. Ответы на вопросы которые возможно у вас возникнут
Что нужно чтобы сделать такое на микроконтроллере ибо FPGA дорого и сложно?
Насколько я понимаю, основная заморочка это сигнал CDBCLK он должен, быть четко засинхронизирован с приставкой иначе на музыке точно будут щелчки. С остальными всё проще. Думаю идеально найти контролер, который может делать шину I2S с параметрами 24 бита на канал, и 24 бита слово. Либо 16 бит на канал и 24 на слово. STM32 когда я смотрел, вроде бы так не умели. Скорей всего отлично подойдут PSoC 5 и возможно ESP32, но в последних, не уверен. Сигналы управления шиной данных CXD2545 медленные порядка 70 килогерц, шины субканала порядка 133 килогерц, думаю можно ногодрыком реализовать. Ну, или SPI попробовать сконфигурировать для этого. SENS не смотря, что это мультиплексор, в целом приставкой читается как регистр. То есть посылает на шину данных, что именно хочет увидеть, а потом через паузу небольшую читает значения ноги SENS. Так что можно сильно не заморачиваться, и тоже сделать ногодрыком.
Планируются ли ещё работы в этом направлении?
В целом да, есть несколько идей:
- подключится к шине команд SUB-CPU чтобы точно знать куда позиционироваться
- полностью выкинуть SUB-CPU, работать вместо него и CXD2545
- эмулировать работу лазера чтобы можно было подключить к любой PS
- сделать модуль работы с SD картой через SDIO а не SPI
У всего есть свои проблемы. Пункт первый мало интересен. Так как почти ничего нового не даст. Пункт второй тут очень желателен логический анализатор на 32 канала, в целом там хватит и 20 но у меня сейчас только 15 канальный(один канал умер). И тратится на 32 канала, пока не хочется. Конечно, появится возможность грузить игры по сети, и всё остальное, что может дать полный контроль подсистемы привода, но анализатора пока в наличии нет. А изготовления своего подзаморожено. Третий вариант самый захватывающий. Но он требует реверсить схему платы PU-18 либо PU-8 последний вариант мне больше нравится. И потом разводить свою плату с CXD2545/CX2510 чтобы удобно отлаживать. Идея заняться есть, но пока руки не доходя, особенно до разводки платы. Ну а работа с картой через, SDIO как бы тоже не так уж и интересно.
12. Послесловие
Вот теперь точно всё. Эмулятор готов. Работоспособность подтверждена практикой. Проект для меня получился очень интересным, хоть и невероятно длинным. Опыта с ним я хлебнул на славу. Но многое из того, с чем столкнулся не однократно пригодилось в жизни. В общем радиоэлектроника и программирование бывают очень интересными. А получить рабочие устройство это не передаваемое чувство радости и гордости. Поэтому если хотели попробовать этим заняться, возможно самое время. Не факт, что получится с первого раза, Но как говорится терпенье и труд
PS. Чуть позже(1-2 недели) весь код(Си и Verilog) проекта будет выложен на гитхабе, мне просто очень хочется его немного «причесать». А затягивать из за этого последнюю часть не хотелось.
PSS. Если вас вдруг заинтересовало как хранятся данные на CD, вы прочитали указанную во второй части книгу. И вам хочется пощупать как же выглядит этот EFM сигнал в жизни(мне однажды очень захотелось). Здесь лежит файл снятого EFM сигнала, и частоты с пина C16M, которая должна меняться в зависимости от скорости данных. Когда то мне удалось вытащить из этого сигнала порядка двух полных секторов.
PSSS. Ну вот теперь уж точно конец.
Комментарии (22)
hf35
25.05.2022 13:08+1Нет планов довести это до коммерческого продукта? Я же правильно понимаю в отличии от PSIO или тем более XStation - это чистый эмулятор привода - можно будет брать любую ревизию, вытащить шлейфы привода - воткнуть эмулятор и всё просто будет работать без пайки доп. компонентов на плату? Я думаю оно бы пользовалось неплохим спросом
VBKesha Автор
25.05.2022 13:10тем более XStation — это чистый эмулятор привода
Судя по всему это как раз близкий аналог XStation. Эмулятор лазера, это пока только идея. И ценность его ИМХО больше в том, что скорей всего он подойдёт и для других приставок. Но начну ли я его делать это вопрос.
HardWrMan
25.05.2022 18:36+1Пункт второй тут очень желателен логический анализатор на 32 канала, в целом там хватит и 20 но у меня сейчас только 15 канальный(один канал умер). И тратится на 32 канала, пока не хочется. Конечно, появится возможность грузить игры по сети, и всё остальное, что может дать полный контроль подсистемы привода, но анализатора пока в наличии нет. А изготовления своего подзаморожено.
Как я уже говорил, у меня есть как тушка с CXD2545 на борту, так и 32 канальный ЛА, который работает на USB3 и способен вытягивать в режиме потока все 32 канала на приличной скорости. Речь за DSLogic U3Pro32: https://www.dreamsourcelab.com/product/dslogic-series/ Я им PATA интерфейс грабил уже. Если что надо - запишу без проблем.
Hidden text
PATA IDE
akhalat
25.05.2022 22:41+1вообще там несколько таблиц для дисков с разным объемом записанных данных, но из за ошибки все равно используются только первые 71 элемент
То есть это прям в прошивках самих приставок ошибка?PSSS. Ну вот теперь уж точно конец.
Даже жалко, с удовольствием почитал бы ещё подобных статей про работу с железом «старых» приставок.VBKesha Автор
25.05.2022 22:55+1То есть это прям в прошивках самих приставок ошибка?
Да, не факт что всех, потому что прошивки SUB-CPU отличаются. А так да. Но по сути эту сулит максимум чуть медленным позиционированием в конце диска. Ну сам SUB-CPU это вообще отдельный микроконтроллер. с вроде бы однократным программированием. Сама приставка отдает команды ему какой сектор ей надо, а уже он делает всё остальное.Даже жалко
Рад, что понравилось.
VelocidadAbsurda
Спасибо! Было очень захватывающе!
Вставлю 5 коп. о 32-канальном анализаторе: если вдруг кусается цена - очень рекомендую присмотреться к Hantek 4032L, 32 канала/400msps/2Гбита памяти/поддержка в Sigrok/PulseView по сравнимой с DSLogic цене.
VBKesha Автор
По виду здороват конечно. но по техническим характеристикам вроде бы даже очень ничего. А по цене сейчас он на 10К дешевле, чем DSLogic.
sintech
Посмотрите на Digilent Digital discovery, 32 канала ЛА, открытый API и еще много полезного.
VBKesha Автор
Судя по всему у него нет встроенной памяти. Без памяти я себе брать не стану, эти грабли уже пройдены.
HardWrMan
Важен не обьём набортной памяти а интерфейс сопряжения. USB3 есть только у DSLogic. А USB2 это очень медленно, даже для 16 каналов. После покупки DSLogic U3Pro32 я забросил все свои остальные, а их есть у меня. Сравнение возможностей порта для потокового режима:
VBKesha Автор
Оххх, у меня был очень негативный опыт общения с анализаторами которые, чисто stream mode. Он даже был не у меня а моих коллег. У меня всё работало как раз отлично. А вот у коллег начинались веселости. Из разряда если флешка воткнута в комп, то анализатор говорил, что пропускной не хватает и хватать на указанной скорости не буду. Это правда было на seale но осадочек остался. Хотя на моем компе он работал идеально даже подключенный через хаб на мониторе. А у других глючил на чистом USB30.
HardWrMan
Да, такое было у Saleae, которые 8 канальные на одном процессоре Cypress. Те могли дропнуть стрим даже просто так, если какой-то софт дополнительно работал в фоне - плавали, знаем. А вот 16ти канальный с FPGA на борту тот же Saleae такой фигнёй не страдал, да ещё и RLE сжатие применял для малого числа каналов (почти 100МГц для 1 канала можно выставить и оно реально работает). Что касается DSLogic, то они не только stream, у них есть буфер. Для логиков с USB3 это 2G (одинаково как для 16 так и для 32), для USB2 только 256М.
Что касается моей помощи, то я буду записывать на машину с отличным USB3, ОЗУ в 64ГБ (+ быстрый PCIEx M2 SSD) и Core i7 9700KF, так что никаких дропов там не будет.
VBKesha Автор
У нас оригинальный Logic 8 Pro, с USB3.0 там вроде как тоже сапртан 6 должен стоять. но я не разбирал.
HardWrMan
Это, видимо, из новых ревизий, если там USB3 настоящий.
***
Заглянул к ним на сайт - действительно, спартан + тот же кипарис, только поновее, с USB3. Но, блин, что-то ценник у них совсем не гуманный, если сравнивать с DSLogic... Не, конечно у них он и раньше был не совсем гуманным, но клоны помогали (мой Saleae16 - точно клон), но блин сейчас прям вообще хуже стало. Интересно, раньше на их сайте была страничка с плачем, что их детям нечего кушать из-за пиратов продукции, а сейчас что-то не могу найти.
VBKesha Автор
Если я не ошибаюсь это был 2015/2016 год.
Да он всю жизнь у них такой. Нам его для работы купили, поэтому ценник значения не особо играл. Но себе я взял клон DSLogic.
sintech
U3Pro32 выглядит интересно, как то я пропустил его появление.
Посмотрел на их софт, это же ведь допиленный Sigrok с его кучей протоколов, но последний релиз 1.1.2 — (2020-05-11) двухгодичной давности немного расстраивает.
У Digilent есть форум на котором их сотрудник пилит фичи и исправляет баги в бета версии софта практически по запросу.
HardWrMan
Да, только вот под сигрок/dreamsource декодеры пишутся на Python, прямо в блокноте. У Saleae изначально надо было компилировать DLL в MVS, недавно они так же перешли на Python. И я уже написал более десятка декодеров нестандартных интерфейсов для своих нужд, что считаю больше плюсом, чем запрос оного у разраба (ведь тогда придётся делиться инфой, что невозможно при NDA). А стекирование декодеров вообще бомба: например, карту памяти вешаем на SDIO/SPI, ставим декодер на интерфейс, а уже к выхлопу декодера подключаем декодер команд карты памяти. А уже к нему можно подцепить даже высокоуровневый анализ данных карты, например FAT. Единственная проблема софта это стабильность на очень длительных записях. И тут я говорю, например, про запись битстрима JTAG @50MHz в течение пяти минут, которую пытается распарсить штатный декодер. Старые версии программ выпадали чаще, а свежие работают стабильнее.
sintech
В Digilent WaveForms custom декодеры пишутся на JS прямо в программе, но на больших объемах данных это довольно сильно тормозит.
В плане доработок я говорил скорее про системные и интерфейсные вещи.
По количеству декодеров sigrok без сомнения вне конкуренции.
Интересно, существую ли ЛА более 32 каналов в бюджете до 500$ и не гробы типа старых HP/Agilent.
sintech
Там 2 гигабита DDR3 памяти, этого достаточно для 1 секунды захвата всех 32 каналов на частоте 100мгц.
VBKesha Автор
Понятно, интересно, надо на их софт посмотреть.