Другое > Hard'n'Soft

Доработка Burn2Slot

<< < (2/2)

Sharpnull:
Talking_Sword, да, да. Но я бы в case 2 оставил только return, а в default перед return вывод ошибки, что нет такого типа.
UPD: Лучше не использовать "проваливание", break/return забывают случайно и компилятор может жаловаться, для этого даже сделали [[fallthrough]] в C++17, чтобы сказать компилятору о намерениях (https://en.cppreference.com/w/cpp/language/attributes/fallthrough).

wolfer:
Будь ты проклят С++ новых стандартов))

Все просто, return делает выход из вашей функции в произвольном месте, за ним ничего уже не выполнится, можно не писать.
break будет переходом на следующий оператор за циклом, или у Вас тут за закрывающей операторный скобкой оператора switch. Используйте если хотите сделать только один из n выборов, иначе можно не писать, и код будет проваливаться на следующие проверки и дефолт

Беларус учит русский:
Тема перешла на основы программирования, ну да ладно. Явно ведь делаешь для хакинга ромов?

--- Цитата: Talking_Sword от 22 Ноябрь 2023, 21:52:29 ---с if-else на switch, так как теперь нужен выбор из трех вариантов
--- Конец цитаты ---
If-Else можно продолжать:

--- Код: ---if(chipType == 0){
   eraseSector22XX(addr);}

else
if(chipType == 1){
   for(int smallAddr = addr; smallAddr < addr + 0x8000; smallAddr += 0x2000)
   eraseSectorIntel(smallAddr);}

else
if(chipType == 2){
   eraseSharp();}

else{
   return;}
--- Конец кода ---

Talking_Sword:

--- Цитата: perfect_genius от 23 Ноябрь 2023, 00:05:33 ---Явно ведь делаешь для хакинга ромов?
--- Конец цитаты ---
Нет.
--- Цитата: perfect_genius от 23 Ноябрь 2023, 00:05:33 ---If-Else можно продолжать:
--- Конец цитаты ---
Знаю, но слышал, что этим увлекаться не стоит, якобы switch эффективнее. Думаю, может кто-нибудь здесь знает такого разработчика YandereDev? Слышал, что причина тормознутости его игры как раз в том, что он злоупотребляет if-else.

Спасибо всем за советы. Не смотря на предостережения от Sharpnull, все-таки решил убрать return и break из case 2. Chip Erase не запустилось два раза, а это значит, что без break переходит на следующий вариант (в принципе, я знал об этом, но не уверен, стал бы он переходить на default), а также return прерывает функцию вместе с работающим в ней циклом.

Правда скомпилировалось не сразу - в одном месте забыл восклицательный знак в "!=", а потом еще удивлялся, про какую же lvalue говорит мне компилятор. А в функции writeByWord вообще умудрился как-то уничтожить одну "родную" фигурную скобку, когда вставлял туда свой switch.

Но когда исправил ошибки, код заработал с перврго раза. Сегодня уже попробовал прошить LH28F800BJE - микросхема прошилась и даже не сдохла после двух раз (первый раз прошил другой ROM, во второй вернул "старый"). Также прошил MX29LV320E - тоже прошилась нормально.

Осталась только загвоздка с Device ID. В программе просто захардкожены несколько Device ID:


--- Код: ---if (((flashid >> 8) & 0xFF) == 0x22 || flashid == 0x7E7E || flashid == 0x57 || flashid == 0xF8)
--- Конец кода ---

То есть, если программа не "видит" знакомого Device ID, то считает, что микросхема не определилась. Стоит обратить еще внимание на это: ((flashid >> 8) & 0xFF) == 0x22 - на сколько я понимаю, это проверка только старшего байта, а у многих микросхем старший байт Device ID = 0x22. Таким образом, видимо автор пытался охватить большее количество микросхем, не прописывая все их Device ID.

Тем не менее, у многих, но не у всех - есть микросхемы, у которых Device ID "не подходит", но при этом у них такая же система комманд, и Burn2Slot потенциально может их прошить. У меня например есть TC58FVB160AFT (Device ID=0x0043), SST39VF1601 (Device ID=0x23BH), SST39VF1602 (Device ID=0x23AH). Чисто в теории, в программе нужно сделать какую-то "базу данных" по Device ID, как это уже сделано с Manufacturer ID в файле "ID.H". Но этих Device ID просто море, нужно в интернете найти какой-то список, пока не нашел. Плюс ко всему, надо еще придумать, как программа будет перебирать их все. Но судя по всему, так и делают - нашел пример.

Но я пока не знаю, где бы взять базу данных по этим самым ID, и как их проверять. Пока придумал только довольно костыльный метод - до посылания комманды идентификации считываю данные по адресам 0x0 и 0x1, затем после комманды считываю значения по этим же самым адресам - если они изменились, то значит считаю, что микросхема откликнулась. Но это не очень хороший метод, плюс ко всему, подумал, что так не получится корректно определить busType.

P.S.: Кстати, нашел ошибку в ID.h - в case MACRONIX_ID автор забыл break. А ведь у меня микросхемы фирмы Macronix определялись как "Sharp" в Burn2Slot. Я это сразу заметил, но сначала не предал значения - думал, может у Macronix как-то изменился Manufacturer ID, может у меня какая-то старая микросхема, у которой Manufacturer ID как у Sharp. Ну или может купили производство Flash-памяти у Sharp, а ID остался старый.

Но оказалось там просто нет break, а так как сразу за Macronix идет Sharp, то его функция и возвращала.

Sharpnull:

--- Цитата: Talking_Sword от 23 Ноябрь 2023, 16:53:03 ---слышал, что этим увлекаться не стоит, якобы switch эффективнее.
--- Конец цитаты ---
В сети есть обсуждение, switch действительно чаще работает быстрее, но обычно никто не пишет if (i==0) {} else if (i==1) {} else if (i==2) {} ... Эта запись тоже странная:

--- Код: ---u16 ( *( read_word() ) )(u32 address)
{
switch(cart->busType) {
case 0: return read_word_rom;
case 1: return read_swapped_word_rom;
...
--- Конец кода ---
Сложно читать что возвращается, обычно пишут typedef для указателя на функцию, чтобы заменить на "Func read_word()". И я бы заменил на массив функций, чтобы записать Func read_word() { return func_arr[cart->busType]; }. Или можно просто делать нужный вызов void read_word(u32 address) { switch(cart->busType) { case 0: read_word_rom(address); ... }}, или, если нужны указатели на функции использовать func_arr[cart->busType], а обычный вызов - void read_word(u32 address) { func_arr[cart->busType](address); }, тогда вызов read_word() без доп. скобок.

--- Цитата: Talking_Sword от 23 Ноябрь 2023, 16:53:03 ---может кто-нибудь здесь знает такого разработчика YandereDev? Слышал, что причина тормознутости его игры как раз в том, что он злоупотребляет if-else.
--- Конец цитаты ---
Там вообще Unity, а значит Mono (вероятно C#). Увидел запись по поводу Yandere Simulator, что проблема в if else, но смысл не в замене на switch (что можно только в определённых случаях), а что там вообще не должно быть проверок. Т. е. проблема на уровне алгоритмов. Этот говнокодер не заслуживает внимания.

--- Цитата: Talking_Sword от 23 Ноябрь 2023, 16:53:03 ---Не смотря на предостережения от Sharpnull, все-таки решил убрать return и break из case 2.
--- Конец цитаты ---
Это конечно работает, но запутанно и ведёт к ошибкам.

--- Цитата: Talking_Sword от 23 Ноябрь 2023, 16:53:03 ---нашел ошибку в ID.h - в case MACRONIX_ID автор забыл break
--- Конец цитаты ---
Как я писал, частая ошибка. Там же char* manufactur = (char*)malloc(sizeof(char) * 12);, но ниже manufactur = "Alliance"; в getManufacturByID(), т. е. зачем-то выделяется память без очищения (free()) и указатель на неё теряется после вызова getManufacturByID(). Этот баг не проявится, т. к. утечка один раз за работу программы, а после завершения программы память возвращается.
UPD:

--- Цитата: Talking_Sword от 23 Ноябрь 2023, 16:53:03 ---Плюс ко всему, надо еще придумать, как программа будет перебирать их все.
--- Конец цитаты ---
Идентификаторы можно записать в массив и перебирать - медленно, но просто. Вместо кучи switch, можно использовать словари (std::unordered_map) или множества (std::set), которые быстро находят элемент или позволяют проверить наличие элемента. Также есть простой вариант с массивами: например, у нас id от 0 до 255, определяем массив:

--- Код: ---const char* arr[] = {
/* 00 */   "ID00"
/* 01 */ , "ID01"
...
/* FF */ , "IDFF"
};
--- Конец кода ---
Тогда простая инструкция быстро даёт значение по ключу: str = arr[id]. Это https://en.wikipedia.org/wiki/Lookup_table.

wolfer:
Современные компиляторы так оптимизируют ваш код, что что бы вы не писали, будет одинаково быстро :D

Sharpnull:

--- Цитата: wolfer от 25 Ноябрь 2023, 18:10:00 ---что бы вы не писали, будет одинаково быстро
--- Конец цитаты ---
Нет, не всегда. Года 3 назад я тестировал скорость своей программы для сжатия, использование do {} while (в одном месте), MinGW, под x86 работало быстрее, чем while {}, Visual Studio, под x64. В сумме разница между худшим и лучшим вариантом могла выйти в 2 раза по времени работы, а это простая консольная программа. После всех обновлений нужно тестировать заново и конфигурация моего ПК уже другая.

wolfer:

--- Цитата: Sharpnull от 25 Ноябрь 2023, 20:46:11 ---Нет, не всегда. Года 3 назад я тестировал скорость своей программы для сжатия, использование do {} while (в одном месте), MinGW, под x86 работало быстрее, чем while {}, Visual Studio, под x64. В сумме разница между худшим и лучшим вариантом могла выйти в 2 раза по времени работы, а это простая консольная программа. После всех обновлений нужно тестировать заново и конфигурация моего ПК уже другая.

--- Конец цитаты ---
Звучит весьма странно, х64 скорости тут не прибавит, Вы же понимаете. Ну адрес большей длины, на инструкцию jmp это как повлияет?) Вот именно VS оптимизирует все даже когда вы этого не хотите, весьма удивительно, что работает так. Скорее тут настройки проекта с отключенной оптимизацией по скорости и внутреннее содержимое цикла…
Но к моему утверждению это не относится, я же имел ввиду, что пиши хоть for, хоть while, хоть do while, результат после оптимизирующего компилятора может быть одинаковый, если компилятор один и тот же… И это не голословное утверждение, знаю о чем говорю

Добавлено позже:
Конечно, если написать неверный код и в одном случае выйдет больше вызовов требовательной к ресурсам функции, то и время работы программы изменится, но это как всегда дело не в бабине…

Sharpnull:

--- Цитата: wolfer от 25 Ноябрь 2023, 21:52:36 ---х64 скорости тут не прибавит, Вы же понимаете
--- Конец цитаты ---
Я не понимаю почему скорость падает на x64. Использовал size_t, intptr_t, поэтому возможно int32 быстрее int64 на x64 в том случае.

--- Цитата: wolfer от 25 Ноябрь 2023, 21:52:36 ---результат после оптимизирующего компилятора может быть одинаковый, если компилятор один и тот же… И это не голословное утверждение, знаю о чем говорю

--- Конец цитаты ---
Это очевидно, я писал, что "не всегда" и привёл свой пример в стандартной среде (MinGW/GCC с обычной оптимизацией -O2 и Visual Studio 2019 с обычным Release для пустой консольной программы).
--- Цитата: wolfer от 25 Ноябрь 2023, 21:52:36 ---Скорее тут настройки проекта с отключенной оптимизацией по скорости и внутреннее содержимое цикла…
--- Конец цитаты ---
Циклы такие, написал для https://godbolt.org:

--- Код: ---int fun1(unsigned char* src, unsigned spos, unsigned i, unsigned src_len) {
    unsigned cur_len = 0;
    do {
        cur_len++;
    } while ((cur_len < 256)
        && ((spos + 1) + cur_len < src_len)
        && src[(i + 1) + cur_len] == src[(spos + 1) + cur_len]);
    return cur_len;
}

int fun2(unsigned char* src, unsigned spos, unsigned i, unsigned src_len) {
    unsigned cur_len = 1;
    while ((cur_len < 256)
        && ((spos + 1) + cur_len < src_len)
        && src[(i + 1) + cur_len] == src[(spos + 1) + cur_len])
    {
        cur_len++;
    }
    return cur_len;
}
--- Конец кода ---
Я не разбираюсь в x86 asm и по x86-64 gcc 13.2 с -O2 не понял есть ли разница. Может зависеть от предсказаний процессора, внешнего цикла и т. п. По идее, чаще будет cur_len == 1 для обычных файлов, где повторов не много. Мне следовало тестировать на разных файлах, включая полностью из нулей. Проверку ((spos + 1) + cur_len < src_len) можно убрать для большей части файла, когда до конца данных далеко. Ещё можно сделать "размотку цикла", но там как повезёт.
Ладно, много оффтопа, я закончил.

Беларус учит русский:
Talking_Sword, я согласен с wolfer, что компиляторы хорошо оптимизируют. Поэтому тебе надо думать над твоей задачей, а не париться над оптимизацией.


--- Цитата: Sharpnull от 25 Ноябрь 2023, 17:23:46 ---обычно никто не пишет if (i==0) {} else if (i==1) {} else if (i==2) {}
--- Конец цитаты ---
Когда этот список условий крутится в цикле, то хочется с помощью break выходить из него, а не из switch. Устанавливать условие, ломающее цикл - некрасиво и лишние действия. goto тоже обычно некрасиво :)


--- Цитата: Sharpnull от 25 Ноябрь 2023, 23:12:19 ---Я не понимаю почему скорость падает на x64.
--- Конец цитаты ---
64 занимает место в кэше в два раза больше, чем 32.

Sharpnull:

--- Цитата: perfect_genius от 26 Ноябрь 2023, 01:24:03 ---64 занимает место в кэше в два раза больше, чем 32.
--- Конец цитаты ---
И правда, но можно использовать 32-битные числа в x64 приложении и у x64 с регистрами лучше.
Протестировал 4 варианта программы, в которой простое LZSS сжатие: Visual Studio (последняя) - x64 с 64 битными индексами, x64 с 32 битными индексами, x86, MinGW GCC x64 с 64 из MSYS2 (последний). Вышло по времени в секундах выполнения примерно: VS x64+64 и x64+32 - 17.4 с, VS x86 - 17.5 с, GCC x64 - от 15.5 до 17.5. С GCC не понял, сначала было около 15.5, потом то 17, то 16, а от VS стабильно 17.x. Как понимаю, из-за маленького кол-ва переменных, у меня не повлияла замена 64 на 32 бит чисел, а x86 может хуже работать из-за регистров, GCC лучше в среднем.
Дополнительно заменил цикл с do {} while на while () как выше, у GCC x64 осталось также (15-17 с), а вот VS x64+64 - 25.5 с. Разница в 1.46 раз из-за другой записи.
Для VS по умолчанию пустой проект Release. Для GCC такая компиляция:

--- Код: ---gcc -O2 -Wall -Wextra -static -static-libgcc ./main.c ./LZSS.c -o LZSS.exe
--- Конец кода ---
UPD: В этот раз толку от x86 не было, но тогда был немного другой код, другая версия VS и не проверял на GCC x86, Win7, FX-8300 (или Phenom II X4 945), а сейчас Win10, 5600X.

Talking_Sword:
О, вижу мои сообщения перенесли в отдельную тему. тем не менее, переименовал тему, так как она больше не о картриджах, а о правке кода Burn2Slot. Надеюсь, модераторы не будут сердиться.


--- Цитата: Sharpnull от 25 Ноябрь 2023, 17:23:46 ---Идентификаторы можно записать в массив и перебирать - медленно, но просто. Вместо кучи switch, можно использовать словари (std::unordered_map) или множества (std::set), которые быстро находят элемент или позволяют проверить наличие элемента. Также есть простой вариант с массивами: например, у нас id от 0 до 255, определяем массив:

--- Код: ---const char* arr[] = {
/* 00 */   "ID00"
/* 01 */ , "ID01"
...
/* FF */ , "IDFF"
};
--- Конец кода ---
Тогда простая инструкция быстро даёт значение по ключу: str = arr[id]. Это https://en.wikipedia.org/wiki/Lookup_table.
--- Конец цитаты ---
Про массив и сам думал, но мне кажется, это будет неэффективно, придется делать цикл, который проверяет каждый элемент массива, наверно будет долго. Словари или множества - для моего уровня это слишком сложно.
--- Цитата: perfect_genius от 26 Ноябрь 2023, 01:24:03 ---Talking_Sword, я согласен с wolfer, что компиляторы хорошо оптимизируют. Поэтому тебе надо думать над твоей задачей, а не париться над оптимизацией.
--- Конец цитаты ---
Протестую! Вот именно из-за таких программистов, которые думают над задачей, а не парятся над оптимизацией и выходит множество ПО, которое жрет память как не в себя, и ничего не может показать на устаревшем компьютере, хотя аналоги из прошлого делают то же самое, но при этом куда менее требовательны.

Sharpnull:

--- Цитата: Talking_Sword от 26 Ноябрь 2023, 06:23:15 ---Про массив и сам думал, но мне кажется, это будет неэффективно, придется делать цикл, который проверяет каждый элемент массива, наверно будет долго.
--- Конец цитаты ---
Нет, не долго. Вы говорите об эффективности, но не знаете как оптимизировать код, тогда никогда ничего не напишите. Нужно соблюдать баланс. Когда пишите для себя на скорую руку, нет смысла тратить время на оптимизацию, а в остальных случаях лучше сразу писать понятный код, используя эффективные методы и алгоритмы насколько возможно, которые не отнимают много времени.
На счёт getManufacturByID() из ID.h, в godbolt.org после оптимизаций (-O2) видны те же проверки каждого ID, единственная оптимизация, это объединение 0x01, 0x04, 0x1C, 0x1F, 0x20 в LUT с "пустыми" промежутками, как я писал про str = arr[id]. Там ещё написан SANYO_ID, но не используется.

VROdin:
Во-первых, спасибо всем, кто проявил интерес к моей программе, это радует и мотивирует заниматься тем чем я занимаюсь на текущий момент.
Во-вторых, в теме обсуждается компиляторы и их "магические" оптимизации, уверяю что доверять компилятору дело лично каждого, но оптимизировать алгоритмы стоит, так как нет уверенности в том что все компиляторы смогут разрулить говнокод правильно.
Отвечу на вопрос почему это было сделано так, а не как иначе, в контексте штуки написанной на коленке, за пару недель, это устраивало моим подребностям:
1)Добавить максимальную поддержку тех картриджей, информацию о которых я имел на тот момент.
2)Добавить автоматическое определение чипа, я не припомню ни одного приложения, которое делало это до B2S (немного графомании)
На текущий момент я занимаюсь переписыванием ядра приложения и выбрал для этого абсолютно иной подход, надеюсь это приведет к чуть большему числу положительных отзывов  :lol: и сдеалет процесс добавление новых картриджей проще

HayaoYokogawa:

--- Цитата: VROdin от 10 Апрель 2024, 14:40:13 ---Во-первых, спасибо всем, кто проявил интерес к моей программе, это радует и мотивирует заниматься тем чем я занимаюсь на текущий момент.
Во-вторых, в теме обсуждается компиляторы и их "магические" оптимизации, уверяю что доверять компилятору дело лично каждого, но оптимизировать алгоритмы стоит, так как нет уверенности в том что все компиляторы смогут разрулить говнокод правильно.
Отвечу на вопрос почему это было сделано так, а не как иначе, в контексте штуки написанной на коленке, за пару недель, это устраивало моим подребностям:
1)Добавить максимальную поддержку тех картриджей, информацию о которых я имел на тот момент.
2)Добавить автоматическое определение чипа, я не припомню ни одного приложения, которое делало это до B2S (немного графомании)
На текущий момент я занимаюсь переписыванием ядра приложения и выбрал для этого абсолютно иной подход, надеюсь это приведет к чуть большему числу положительных отзывов  :lol: и сдеалет процесс добавление новых картриджей проще


--- Конец цитаты ---
И тебе спасибо за полезный софт  :thumbup:

Навигация

[0] Главная страница сообщений

[*] Предыдущая страница

Перейти к полной версии