Когда-то в одном из ZX-РЕВЮ был подробнейший разбор этой темы. В каком номере - сейчс не скажу. Но был точно.
Вид для печати
Если не экономить память, то есть очень дубовый способ. Пусть программа в памяти, набираем в строке редактирования RUN (без enter). Сохраняем системные переменные и саму программу. Теперь когда надо запустить возвращаем системные переменные и программу на место и переходим по адресу 12DDh. Несомненно этот способ можно улучшить и оптимизировать, но если других вариантов пока нет, то он работает.
я кстати делал похожим способом, только кажется в первой строке исполнялось pause 0,
запустив сохранял память, потом сжимал ну и после разжима делал jp в ПЗУ
Для сохранения памяти нужно входить в TR-DOS и делать сохранение области с #5B00 и до конца памяти. Но при этом же не сохранится команда RUN, она же не будет набрана.
я сохранял память под эмулем.
в ZXreview скорее всего делали автостарт программы в составе кодового блока.
первая строка бейсика что-то типа
1 save "test" code 23552,1704
2 текст программы
на момент отгрузки в переменных будет следующая строка/оператор
но это явно не твой случай
..........
вспомнил. я делал перехват на адресе #2D2B; BC=№номер строки
загрузив программу на бейсике ставил BreakPoint и выполнял gotoX
после этого сохранял всю память, сжимал и после загрузки/разжатия (важно правильно выставить стек)
делал jp #2d2b
..........
этот способ я подсмотрел в игре I of the Mask
Если программа на бейсике занимает не всю память, то стоит ограничиться только ей (посмотреть в отладчике эмулятора где она оканчивается) + системные переменные до нее.
Сохранение из TR-DOS обязательное условие (его не было в посте с вопросом)? Если нет, то goodboy написал про сохранение из эмулятора.
Еще я забыл важный момент. Стартовые условия могут быть разные, поэтому лучше задать ld iy,5C3Ah. Содержимое стека, насколько помню, в "моем" варианте сохранять не обязательно.
Способов запустить бейсик-программу из ассемблера существует великое множество, но все они должны быть основаны на анализе дизассемблера бейсика (Ian Logan, Frank O'Hara, "The complete ZX Spectrum ROM disassembly"). Потому, что документированных и облегчённых способов запуска нет, а остальные подразумевают "обман" в той или иной форме, подстановка бейсику того, что он увидит так, как хочется автору.
Вариент - изучить процедуру "Load" с кассеты. Там после загрузки заголовка сначала ликвидируется "старая", находящаяся в памяти, программа. Затем выделяется память под новую программу и её переменные. И, наконец, загружается и запускается новая программа.
Изучив процедуру "Load", можно реализовать её заново в своём коде, выбросив оттуда лишнее и вставив недостающее.
Что я только что и проделал. Для понимания изложенного ниже требуется скачать и открыть Логана и ОХару.
Интересующая нас часть процедуры "Load" находится по адресу 0x0873 под названием "LD-PROG".
Сначала вызовом процедуры "RECLAIM-1" освобождается память от "старой" программы. Затем вызовом "MAKE-ROOM" выделяется память под новую программу и её переменные. Освобождение и выделение памяти через "RECLAIM-1" и "MAKE-ROOM" освобождают программиста от заботы о системных переменных в этих процессах.
После этого из кассетного заголовка извлекается длина программы без учёта длины её переменных и устанавливается системная переменная "VARS" на начало области переменных.
Далее номер строки, с которой программа должна запуститься, заносится в системную переменную "NEWPPC", а номер оператора в строке (системная переменная NSPPC) - обнуляется.
Остальное - дело техники. В подготовленную память просто загружается блок с кассеты и идёт возврат в основной цикл интерпретации, где загруженная программа начинает исполняться.
Если ассемблерная программа была вызвана из бейсика (например, по RANDOMIZE USR) - то больше ничего делать не надо, можно просто вернуться из USR.
- - - Добавлено - - -
Добавка. Если ассемблерная программа была вызвана не через USR, а каким-то другим способом - то точка входа в интерпретатор для начала исполнения программы - это 0x1B7d, "STMT-R-1".
Перед переходом на неё необходимо загрузить указатель стека из системной переменной ERR-SP: LD SP,(23613)
- - - Добавлено - - -
Если же системные переменные испорчены, и требуется их полная инициализация - то она находится в бейсике по адресам 11EF-12A2. Объём этого кода короче, чем сохранённая копия всех системных переменных.
- - - Добавлено - - -
Ещё немного подумал. Возврат из USR, описанный выше, может привести к сбою, так как USR - это функция, являющаяся частью выражения. Если для команды LOAD допустимо возвращаться с подменой программы, то для USR - нет.
В случае LOAD идёт возврат из исполнения команды на цикл исполнения программы. Так как системная переменная NSPPC была обнулена, то поиск строки к исполнению начинается заново, что и приводит к запуску загруженной программы без учёта того, что находилось в области памяти, где была команда LOAD и что следовало за ней.
Но вызов ассемблерной программы через USR - это не команда, а часть выражения. USR - это функция, а выражение может продолжаться после неё. Таким образом, если ассемблерная программа перепахала память, где находился вызов функции USR - то вычисление выражения будет продолжено с того же места, а так как там уже находится другая программа - то скорее всего это приведёт к ошибке C Nonsense in BASIC.
Так что запуск программы только через STMT-R-1 и инициализацию стека.
Кое-какие результаты есть: программа работает, но при попытке её остановка и выхода в бейсик, всё подвисает.
Вероятнее всего, адрес возврата в стеке (ERR_SP) неправильный. Каким образом ты добился запуска программы?
Сначала инициализировал системные переменные (взял код из ПЗУ по адресам по адресам 11EF-12A2).
Дальше взял кусок кода из процедуры LD-PROG. Формирую header бейсик файла, подставляю туда нужные данные (длина файла, длина бейсик-части, стартовая строка), дальше, если я правильно понял, в коде резервируется место для альтернативного header'а, куда сохраняются данные о текущей бейсик-программе в памяти, на основании которых удаляется текущая бейсик-программа и резервируется место для новой программы.
Потом загружаю бейсик программу в нужные адреса памяти, загружаю указатель стека из системной переменной ERR-SP: LD SP,(23613) и делаю переход на 0x1B7d, "STMT-R-1".
Программа запускается (у меня простейшая программа, выводящая числа на экран в цикле). Но как только я её останавливаю через Break, всё виснет.
Понятно. В таком случае, думаю, нужно после LD SP,(23613) сделать следующее:
тем самым прописывается нужный адрес возврата при ошибке (в том числе 0 OK).Код:POP HL
LD HL,1303H ; MAIN-4 Error entry point
PUSH HL
JP 1B7DH
Насколько я помню по книге "Как написать игру на ассемблере", при выходе в Бейсик нужно восстанавливать регистровые пары IY и HL' вроде. Но лучше уточнить в книге.
Хорошо, что напомнил. Устанавливать IY на значение 0x5C3A - это, конечно, необходимо при любых делах с бейсиком. Даже при работе прерываний для опроса клавиатуры бейсик использует этот регистр и требует, чтобы в нём содержалось это значение.
Но вот насчёт HL' - это зависит от точки входа в бейсик. Вероятно, в книге "Как написать игру" имелся в виду возврат из функции USR - а это происходит куда-то в недра "калькулятора" и процедуры вычисления выражений. Вход же в бейсик на точку STMT-R-1 - это совсем другое дело, и там содержимое регистра HL' роли не играет.
А почему не посмотрите архив исходников TR-DOS Navigator'а?
Там как-раз так BASIC-программа и запускается.
Файл TRDNC.ASM: процедура EXIT.
Файл COMMENTS.TXT: описание в разделе "Запуск файлов и выход из TRDN".
Дело в том, что из бутов, коммандеров и навигаторов программа часто запускается путём исполнения команды "RUN" в TR-DOS. Это самый простой способ. И тогда уже TR-DOS занимается выделением памяти и запуском, а не коммандер. Если ты уверен, что в коммандере программа запускается именно на низком уровне, наподобие того, как я рекомендовал - то подскажи. В противном случае жизни не хватит копаться во всех коммандерах и разочаровываться.
Prusak, как твои успехи? Ты поборол проблему сбоя по завершении программы?
Ребят хочу сделать девушке романтический мини-сюрприз . Скинте плз листинг отрисовки сердца в zxbasic . Кому не сложно
Поэтому я и порекомендавал почитать файл COMMENTS.TXT в архиве исходников TRDN. Не зря же мы его писали. Там все кратко и по-русски. :) Если информация заинтересует - можно посмотреть и сами исходники. А появятся вопросы - спрашивайте. Лучше в теме про TRDN. :)Цитата:
Сообщение от Barmaley_m
- - - Добавлено - - -
Теперь надо проверить правильно ли выставлен RAMTOP и указывает ли на дно машинного стека 23613; на дне должен быть адрес системной процедуры обработки ошибки.
По теме запуска бейсик программы "с ноля". Совместными усилиями проблема решена.
Нужно было на стек "положить" адрес #1303.
Всем причастным спасибо за помощь :)
Именно в таком виде задачу по запуску BASIC-программы мне решать не приходилось, и она меня заинтересовала.Цитата:
Сообщение от Prusak
Во вложении исходный ассемблерный текст и откомпилированный вариант моего решения. Образ диска имеет структуру каталогов Directory System (но на это внимание можно не обращать). Подробности в файле install.txt.
Работа кода происходит так.
- Обнуляется область памяти под системные переменные системы ZX Spectrum (за основу взят код из TR-DOS).
- По новой организуется область системных переменных и инициализация рабочих областей. Переменные TR-DOS не организовываются.
- Выделяется место под BASIC-программу и переносятся туда ее данные.
- Запускается BASIC-программа.
Попутно решена и эта задача. BASIC-программа в коде - рисует на экране сердце. :DЦитата:
Сообщение от Narick
На чём запускать будешь? У девушки есть железный спек?
Могу поделиться своим "мини-сюрпризом для девушки", который я делал в 1995-1997гг. Это плата с Z80, AY, ПЗУ и ОЗУ. Подключается 7-сегментный индикатор и 7 кнопок. Можно проигрывать несколько музык на AY в формате ProTracker 2. Также реализованы часы, будильник и др.
Железный спек есть у меня . Она кодерша C++ так что думаю оценит( мой уровень в любом кодинге стремиться к 0 . Лет 20 не практиковался ) . Схемой поделиться ? Я не паяльник я ломльник ))) . Но все равно буду благодарен
- - - Добавлено - - -
Спс ща на эмуле тест проведу и на реал
кто подскажет, можно ли с помощью FOR перичислять переменные ?
например у меня есть строка:
3005 POKE USR A$,I1: POKE USR A$+1,I2: POKE USR A$+2,I3: POKE USR A$+3,I4: POKE USR A$+4,I5: POKE USR A$+5,I6: POKE USR A$+6,I7: POKE USR A$+7,I8
Я её хочу записать так:
FOR g= 1 TO 8: POKE USR A$+g,I(g): NEXT g
но мне выдаётся ошибка 2 variable not found.
можно это как-то обойти ?
ps. в ближайшее время будет обновление программки.
понятно.
спасибо за разъяснение.
ещё один вопрос.
имеется такая строчка:
10 INPUT g: IF g<0 OR g>255 THEN GO TO 10
вводится значение g от 0 до 255.
но, есть ошибка.
если ввести вместо цифр какие-то буквы или команду - программа вывалится в ошибку.
как-то можно запретить вводить в INPUT буквы и команды ?
Можно запрашивать строку, а потом конвертить в число (обрабатывая "ошибки"), но это тоже не панацея.
ZEman, обязательно нужен ручной ввод числового значения?
Как вариант, можно организовать его как ввод симовольной переменной с последующим преобразованием в число. Правда, получится, весьма громоздкая конструкция.
- - - Добавлено - - -
Например, вот такая:
10 INPUT LINE g$: IF LEN g$<1 OR LEN g$>3 THEN GOTO 10
12 IF LEN g$=3 AND CODE g$(1)>47 AND CODE g$(1)<51 THEN
IF CODE g$(2)>47 AND CODE g$(2)<54 THEN
IF CODE g$(3)>47 AND CODE g$(3)<54 THEN
LET g=(CODE g$(3)-48)+(CODE g$(2)-48)*10+(CODE g$(1)-48)*100: GOTO 22
14 IF LEN g$=2 AND CODE g$(1)>47 AND CODE g$(1)<58 THEN
IF CODE g$(2)>47 AND CODE g$(2)<58 THEN
LET g=(CODE g$(2)-48)+(CODE g$(1)-48)*10: GOTO 22
18 IF LEN g$=1 AND CODE g$(1)>47 AND CODE g$(1)<58 THEN
LET g=CODE g$(1)-48: GOTO 22
20 GOTO 10
22 STOP
Есть же функция преобразования символов в чисто, правда не помню, как она реагирует на нецифровые символы.
Black Cat / Era CG, есть обратная функция - STR$.
Беда в том, что команда INPUT, может принимать в качестве входных числовых данных, любую белиберду. Алгебраические выражения и имена переменных.
Видимо потом буду делать через inkey$ и let.
Так меньше проблем будет.
ZEman, я же, тремя сообщениями выше накидал рабочий вариант. Чем не нравится? :)
null_device, вариант неплохой.
но, Я стремлюсь к тому чтобы выжать из программы как можно больше свободной памяти, сохранив при этом все имеющеюся фишки программы.
то-есть ничего не удаляется, весь функционал остаётся тем-же, но при этом получаешь больше памяти.
Через INKEY$ самое нормальное.
А если INPUT A$, то выводятся поганые кавычки еще, раздражали в своё время.
В ZX Like Pascal, кстати, я решил эту проблему кардинально во встроенной процедуре обработки ошибок. Если для числовой переменной A юзер вводит в readln(A) не число или число больше, чем поддерживает тип, то его введенная строка стирается и запрашивается заново.
Rararura 1.9.5
новая версия программы.
изменений не так много, в основном я занимался оптимизацией программы и старался получить в ней как-можно больше свободной памяти.
также исправил пару серьёзных ошибок программы и сделал её намного быстрей.
список изменений:
- исправлена ошибка с установкой символа в нижнем правом углу, в текстовом редакторе.
- исправлена ошибка с загрузкой нового шрифта при выборе символов для Multiselect mode.
- исправлена ошибка с выбором главного символа.
- удалён режим отладки для поворота символов.
- большая оптимизация программы.
- небольшой прирост скорости в работе программы.
- получено почти 7 кб свободной памяти.
через пару - тройку месяцев выпущу ещё одну, скорее всего последнюю версию данной программы, в которой я добавлю много интересного.