Другое > Hard'n'Soft
Доработка Burn2Slot
Talking_Sword:
У меня снова вопрос с некоторым уклоном в железо (скорее всего).
Покупал на Aliexpress картриджи под перепрошивку, но на этот раз попалась на них микросхема LH28F800BJE, а ее не поддерживает ни Burn2Slot, ни GBABF-SHN. Тут наверно я сам себе злобный Буратино, так как взял игру на 512 КБ, подумал, что большой объем для тех игр, которые хотел записать не нужен. Наверно, если бы взял что-то на 2 МБ, то могла бы попасться и какая-нибудь поддерживаемая микросхема.
Тем не менее, хочу попробовать дописать в Burn2Slot поддержку данной микросхемы.
Вопросы: вот Datasheet на микросхему. На странице 21 есть алгоритм в виде блок-схемы для прошивки одного слова\байта. На блок-схеме есть SR.7=, я так понимаю, это проверка Status Register, о котором написано на странице 18. Я так понимаю, нужно проверять бит 7. Для этого нужно считать информацию. Но там будет сразу считываться по 8, а может по 16 бит (не уверен, но шина 16-битная), и отображаться как шестнадцетиричное число.
А как в Си (Burn2Slot ведь на Си написан?) "посмотреть" отдельный бит?
Yoti:
--- Цитата: Talking_Sword от 17 Ноябрь 2023, 13:50:19 ---А как в Си (Burn2Slot ведь на Си написан?) "посмотреть" отдельный бит?
--- Конец цитаты ---
Есть битовый сдвиг, есть маска.
Talking_Sword:
Yoti, честно говоря, не слишком понятно. У меня с программированием не очень хорошо.
Можно ссылки на какие-нибудь статьи\уроки, где бы это понятно объяснялось? Желательно с примерами кода
Sharpnull:
--- Цитата: Talking_Sword от 17 Ноябрь 2023, 13:50:19 ---"посмотреть" отдельный бит?
--- Конец цитаты ---
Если num - числовой тип и используется в условии if, то варианты:
--- Код: ---if ((num & 0x80) == 0x80) {
// 7-й бит установлен
}
if (!!(num & 0x80)) {} // В JS стиле
if (!(num & 0x80)) {} // 7-й бит не установлен
if (num & 0x80) {} // Нехорошо, неявное преобразование
--- Конец кода ---
UPD: Поправил комменты. Побаловаться с кодом можно: https://www.onlinegdb.com/online_c++_compiler.
Talking_Sword:
Sharpnull, огромное спасибо, что бы я без вас делал! :thumbup:
И еще, "бесполезный" вопрос из разряда "просто интересно": num & 0x80 - это выглядит как логическая операция "И". Не совсем понял, а как это помогает "понять", установлен у нас 7-ой бит или нет?
По крайней мере, мне понятно, что 0x80 - это 10000000 в двоичной системе, то есть установленный 7-ой бит. А вот "if (!(num & 0x80)", по идее, чтобы условие if выполнялось, нужно, чтобы в скобках было true. А как "num & 0x80" дает true, если в num 7-ой бит будет равен "1"?
Sharpnull:
--- Цитата: Talking_Sword от 17 Ноябрь 2023, 18:12:55 ---num & 0x80 - это выглядит как логическая операция "И"
--- Конец цитаты ---
Это побитовая (битовая) операция "И", значит действия между соответствующими битами чисел. Логическое "И" записывается как &&.
--- Цитата: Talking_Sword от 17 Ноябрь 2023, 18:12:55 ---А вот "if (!(num & 0x80)", по идее, чтобы условие if выполнялось, нужно, чтобы в скобках было true. А как "num & 0x80" дает true, если в num 7-ой бит будет равен "1"?
--- Конец цитаты ---
В C ненулевое значение - "истина" и не было изначально true, false и bool. Поэтому if (!0x80) и if (!1) не выполняется всегда, а if (!0) выполняется всегда. Можно даже написать бесконечный цикл как while ("inf") {}. Замечу, "if (!(num & 0x80))" - условие выполняется, если 7-й бит не установлен.
Про if (num & 0x80) ошибся, думал было предупреждение (проверил, его нет в Visual Studio и GCC), с чем-то перепутал.
Talking_Sword:
--- Цитата: Sharpnull от 17 Ноябрь 2023, 18:37:28 ---В C ненулевое значение - "истина" и не было изначально true, false и bool. Поэтому if (!0x80) и if (!1) не выполняется всегда, а if (!0) выполняется всегда.
--- Конец цитаты ---
Спасибо, понятно.
Родил вот такой код на основе того, что посоветовал Sharpnull:
--- Код: ---void eraseSharp()
{
printTop("Chip Erase...");
write_word()(0x0, 0x70);
while(!(read_word()(0x0) & 0x80){
wait();
}
write_word()(0x0, 0x30);
write_word()(0x0, 0xD0);
while(!(read_word()(0x0) & 0x80){
wait();
}
printTop("Done.\n\n");
}
--- Конец кода ---
Марат:
И что этот код работает?
Пустые скобки после write_word выглядят странными. Также странно выглядит чтение read_word. В моём понимании должно быть так write_word(0x0, 0x70);
read_word() без всяких аргументов.
Sharpnull:
--- Цитата: Марат от 17 Ноябрь 2023, 20:24:53 ---Пустые скобки после write_word выглядят странными.
--- Конец цитаты ---
Функция возвращает функцию: https://github.com/vrodin/Burn2Slot/blob/master/arm9/source/app.cpp. UPD: Можно было бы сделать макрос или функцию обёртку, чтобы выглядело "нормально".
Talking_Sword:
--- Цитата: Марат от 17 Ноябрь 2023, 20:24:53 ---И что этот код работает?
--- Конец цитаты ---
Да, только что стер микросхему. Уря! :jumpy: Только забыл добавить "\n" после "Chip Erase...".
Теперь осталось только написать код прошивки (опираясь на исходный код Burn2Slot).
Добавлено позже:
Сделал код для прошивки:
--- Код: ---void writeWord22XX(u32 addr, u16 data)
{
write_word()(0x0, 0x70);
int timeout = 0x20000;
while(timeout && !(read_word()(0x0) & 0x80)){
timeout--;
wait();
}
write_word()(0x0, 0x40);
write_word_rom(addr, data);
timeout = 0x20000;
while(timeout && !(read_word()(0x0) & 0x80)){
timeout--;
wait();
}
}
--- Конец кода ---
И да, он работает. Заработало с первого раза! Даже сам не ожидал, что так легко получится.
Только сразу говорю, название функции "writeWord22XX", мягко так скажем, не соответствует действительности. Никакие "22XX" он прошить не сможет. Просто я хотел максимально упростить себе задачу, поэтому, просто заменил функцию "writeWord22XX" своей, чтобы не приходилось определять тип микросхемы, а затем выбирать на основе этого "правильную" функцию. Поддержка "нормальных" микросхем в моей модифицированной версии сломана, теперь она может прошивать только Sharp. Но я и не ставил цели сделать универсальную программу, цель была решить свою задачу, и реализация, как говорят по Английски "quick and dirty".
Но в будущем надо все-таки сделать отдельную функцию, и сделать определение типа микросхемы, чтобы выбрать правильную функцию.
P.S.: а вот перед тем, как стирать решил сравнить данные между двумя картриджами, так как покупал два одинаковых картриджа, данные в них должны совпадать. Делал это потому, что в теории, могут прислать картридж с битой памятью. Если данные в них не совпадут, значит один из них битый. И данные не совпали - один совпадал с No-Intro, у другого были расхождения в нескольких местах, ну и "родная" игра глючила как на приставке, так и на эмуляторе. Но при этом, когда перезаписал "плохой" картридж, то данные в него записались правильно, байт-в-байт. Странно, почему тогда "родная" игра была криво записана? Единственное, что могу предположить что может Flash-память какая-то "уставшая" и помнит данные только когда они недавно записаны, а потом "забывает".
Беларус учит русский:
Попробуй 0b10000000 вместо 0x80, вдруг твой компилятор поддерживает. Такое появилось в Си23, но было и до него в некоторых компиляторах.
(И, пожалуйста, не пиши национальности и названия языков с большой буквы. Не тащи в русский гадости из английского :))
Sharpnull:
--- Цитата: perfect_genius от 19 Ноябрь 2023, 00:38:18 ---Такое появилось в Си23, но было и до него в некоторых компиляторах.
--- Конец цитаты ---
У него C++, а там двоичные литералы с C++14. Я всё равно пишу в hex, двоичная запись занимает больше места. С разделителем пойдёт - 0b1000'0000.
Talking_Sword:
--- Цитата: perfect_genius от 19 Ноябрь 2023, 00:38:18 ---Си23
--- Конец цитаты ---
Цифра, я так понимаю год? Что-то совсем новое. Я больше тяготею к старым стандартам. В любом случае, так, как написал Sharpnull работает, а это самое главное.
Только единственное, что я сказал уже ранее, что надо бы еще сделать так, чтобы программа могла перезаписывать как и "22XX" так и Sharp. А то я сейчас заменил код для "обычных" микросхем, и их программа прошивать "разучилась".
Но похоже у меня это не получится сделать, так как для проверки кода нужна микросхема, на которой он будет проверяться, а я уже оба своих картриджа прошил нужными мне играми, и больше прошивать их не хочу.
--- Цитата: perfect_genius от 19 Ноябрь 2023, 00:38:18 ---Не тащи в русский гадости из английского :)
--- Конец цитаты ---
?
Беларус учит русский:
--- Цитата: Talking_Sword от 19 Ноябрь 2023, 12:39:29 ---Я больше тяготею к старым стандартам.
--- Конец цитаты ---
Тебе надо просто проверить, необязательно следовать каким-то стандартам, оно обратно совместимо, да и не совсем новый стандарт - в С++ появилось давно.
Цифра 1 в 0b10000000 - это твой седьмой бит. Так удобнее манипулировать отдельными битами вручную, чем лезть в калькулятор за 0x80.
0x40 вон шестой бит - 0b01000000.
--- Цитата: Talking_Sword от 19 Ноябрь 2023, 12:39:29 ---?
--- Конец цитаты ---
--- Цитата ---как говорят по Английски
из-за ломанного Английского
на оригинальной Японской
сплошь в Японском
играх на Японской
по Русски
картриджи с Русскими версиями
--- Конец цитаты ---
wolfer:
Проще функцию написать для универсальности, возвращающую 1 или 0, isBit(UINT number, int Count) какую-нибудь, с побитовым сдвигом вправо и & 1 в конце...
Sharpnull:
--- Цитата: wolfer от 20 Ноябрь 2023, 19:59:48 ---Проще функцию написать для универсальности
--- Конец цитаты ---
Нет, это и так просто (a & 0x80) и можно написать #define FLAG 0x0100 и (a & FLAG). Для C++ уже std::bitset, если хочется абстракций.
wolfer:
Не люблю плюсы, с89 достаточен для любых вычислительных или низкоуровневых задач. А у плюсов стандарт скачет и раздувается, я уже на последнем в код не втыкаю…
MetalliC:
--- Цитата: wolfer от 20 Ноябрь 2023, 22:08:02 ---с89 достаточен для любых вычислительных или низкоуровневых задач
--- Конец цитаты ---
достаточен, но как говорится, у С++ всё же есть пара плюсов :)
хотя бы те же темплейты (шаблоны), и да, приблизительно то же можно сделать на С с кучкой макросов, но спустя недельку сам нихрена не сможешь разобраться в куче своих же навороченых #define конструкций
wolfer:
--- Цитата: MetalliC от 21 Ноябрь 2023, 01:58:15 ---достаточен, но как говорится, у С++ всё же есть пара плюсов :)
хотя бы те же темплейты (шаблоны), и да, приблизительно то же можно сделать на С с кучкой макросов, но спустя недельку сам нихрена не сможешь разобраться в куче своих же навороченых #define конструкций
--- Конец цитаты ---
Естественно, для разработки больших проектов лучше сразу использовать плюсы. Я же не говорю, что у ник нет преимуществ, просто не люблю)) Так как во времена своей молодости мог позволить себе писать код в С стиле… А сейчас ностальгирую, как по сеге :D
Talking_Sword:
Продолжаю дорабатывать код Burn2Slot. Как говорил в прошлый раз, тогда заменил "родную" функцию для прошивки слова своей, так как хотел максимально упростить себе задачу. Но из-за этого программа "разучивается" работать с "обычными" микросхемами. Изначально думал, что потом постараюсь сделать так, чтобы программа смогла работать с любым типом микросхем, то есть не заменять, а добавить свою функцию к уже имеющимся в программе. Но не хотелось эксперементировать на своих картриджах, так как каждый цикл стирание\запись может стать для микросхемы последним, а для тестирования кода это нужно. Но решил все-таки рискнуть.
Код пока не запускал, есть вопросы.
Решил переделать с if-else на switch, так как теперь нужен выбор из трех вариантов:
--- Код: ---void erase(u32 needSpace)
{
for(int addr = 0; addr < needSpace; addr += 0x8000) {
switch(chipType) {
case 0:
eraseSector22XX(addr);
break;
case 1:
for(int smallAddr = addr; smallAddr < addr + 0x8000; smallAddr += 0x2000)
eraseSectorIntel(smallAddr);
break;
case 2:
eraseSharp();
return;
break;
default:
return;
}
printTop("\rERASE %d\%", (addr + 0x8000) * 100/needSpace );
}
printTop("\n");
}
--- Конец кода ---
Но суть в том, что в программе используется не полное, а "частичное" стирание, программа "расчищает" секторы под объем записываемого файла, остальные не трогает. Поэтому используется цикл, который выполняется столько раз, сколько секторов нужно стереть для записи файла. Но мне же было лень реализовывать посекторное стирание, поэтому в функции eraseSharp сделал Chip Erase - полное стирание, это удобно тем, что дал один раз комманду, а потом просто ждешь, когда микросхема сама себя сотрет. Но данную функцию нужно вызывать только один раз за прошивку.
Правильно ли я понимаю, что return; после вызова функции eraseSharp досрочно завершит цикл и прервет выполнение функции erase?
Также, прочитал здесь, что если не написать break;, то сразу начнут выполняться следующие операторы. Правильно ли я понимаю, что из case 2 можно смело убрать return; и break;, и после этого начнет выполняться default, в котором есть нужный нам return;?
Навигация
Перейти к полной версии