Возвращаюсь в Basic :) Не знаю даже зачем, в ZX-играх часто выход - это кнопка reset. Хотя если углубиться, то надо делать возможность выхода в TR-DOS.
Вид для печати
Возвращаюсь в Basic :) Не знаю даже зачем, в ZX-играх часто выход - это кнопка reset. Хотя если углубиться, то надо делать возможность выхода в TR-DOS.
Ну, собсна, если отказаться от выхода, то никакого специального кода для перехода в "48 с открытым портом" не надо. Просто не шли ничего в #7ffd и будет тебе щастье. А можешь и слать, лишь бы не включал 5-й бит, не писал в буфер принтера и на выходе была бы впечатана 0-я страница.
Собсна, изначальная твой проблема (про то, что мог оставить коммандер после себя) решается так: ld a,#10: out (#7ffd),a, больше ничего и не надо. Кстати, я загнался по поводу стека и обработки ошибок. SDCC же на старте программы выставляет стек сам? А как выглядит код завернешния программы, что там со стеком происходит? Что будет, если функциями модуля Basic сделать PRINT AT 255,255 или INK 255?
Алекс, SDCC использует код инициализации в crt0, который в ZXDev выглядит так:
Библиотека Basic имеет процедуры Init и Quit, причём по варианту для каждого режима прерываний - DI, IM1 и IM2. Исходники живут в ZXDev/Lib/C/Basic.c, но продублирую:Код:.module crt0
.globl _main
jp _main
Модуль Basic мог бы инициализироваться автоматически, но я тогда сделал так, и уже потом не стал менять, оправдываясь тем, что некоторым процедурам не нужна инициализация.Код:void Basic_Init_DI (void)
{
__asm
DI
// LD IY,#0x5C3A
RES 4,1(IY) /* RESET OF 128K FLAG */
__endasm;
} //Basic_Init_DI
/*--------------------------------- Cut here ---------------------------------*/
void Basic_Init_IM1 (void)
{
__asm
RES 4,1(IY) /* RESET OF 128K FLAG */
__endasm;
} //Basic_Init_IM1
/*--------------------------------- Cut here ---------------------------------*/
void Basic_Init_IM2 (void) __naked {
__asm
RES 4,1(IY) /* RESET OF 128K FLAG */
; ************************************************
; * Set IM2 mode (need for correct work with IY) *
; ************************************************
LD HL,#IM2PROC$
IMON$:
LD A,#24 ; код команды JR
LD (#65535),A
LD A,#195 ; код команды JP
LD (#65524),A
LD (#65525),HL ; в HL - адрес обработчика прерываний
LD HL,#0xFE00 ; построение таблицы для векторов прерываний
LD DE,#0xFE01
LD BC,#256 ; размер таблицы минус 1
LD (HL),#0xFF ; адрес перехода #FFFF (65535)
LD A,H ; запоминаем старший байт адреса таблицы
LDIR ; заполняем таблицу
DI ; запрещаем прерывания на время
; установки второго режима
LD I,A ; задаем в регистре I старший байт адреса
; таблицы для векторов прерываний
IM 2 ; назначаем второй режим прерываний
EI ; разрешаем прерывания
RET
IM2PROC$:
PUSH AF
PUSH BC
PUSH DE
PUSH HL
PUSH IX
PUSH IY
__endasm;
}
void Basic__IM2ADR (void) {
__asm
CALL IM2RET$
POP IY
POP IX
POP HL
POP DE
POP BC
POP AF
EI
IM2RET$:
__endasm;
} //Basic_Init_IM2
/*--------------------------------- Cut here ---------------------------------*/
void Basic_Quit_DI (void)
{
__asm
LD HL,#0x2758
EXX
LD IY,#0x5C3A
EI
__endasm;
} //Basic_Quit_DI
/*--------------------------------- Cut here ---------------------------------*/
void Basic_Quit_IM1 (void)
{
__asm
LD HL,#0x2758
EXX
LD IY,#0x5C3A
__endasm;
} //Basic_Quit_IM1
/*--------------------------------- Cut here ---------------------------------*/
void Basic_Quit_IM2 (void)
{
__asm
DI
LD HL,#0x2758
EXX
LD IY,#0x5C3A
LD A,#0x3F
LD I,A
IM 1
EI
__endasm;
} //Basic_Quit_IM2
Советуешь в Basic.Init добавить команды ld a,#10: out (#7ffd),a ?
Корректность аргумента INK я не проверяю (для скорости). А ПЗУ'шный вариант AT работает через RST 16:
Странный синтаксис записи чисел...
# во встроенном ассемблере SDCC - обязательный признак литерала. Это не я придумал. :(
Все там почти хорошо. Я бы вот только не стал бы сбрасывать флаг 128-го BASIC'а, при обработке ошибок можно словить ахтунг. Кстати сказать, он при запуске скорее всего сброшен - USR работает в ПЗУ 48. Вместо этого лучше действительно принудительно впечатывать 0-ю страницу как минимум перед установкой IM 2 (а лучше всегда, она гарантированно быстрая). Перед впечтаыванием должно быть SP < #c000, это, я полагаю, делает BASIC-загрузчик командой CLEAR.
Скорее всего, флаг 128-го BASIC'а сбрасывается здесь чтобы спокойно использовать память буфера принтера.
А почему нельзя оставить активную страницу? Просто я подумал: а вдруг машкод программы юзера перекроет границу #C000? Значит впечатывать 0-ю страницу нужно до загрузки машкода в память, т.е. не иначе как из лоадера, а не из уже загруженного и запущенного кода.
Случай видится требующим особого подхода. Т.е. если пишется программа для >=128k, нужно разработать специальную библиотеку для работы со страницами, вторым экраном и т.д.
В общем, поковырялся я в коде ПЗУ по поводу этого флага. Давай все же сначала поймем какую цель ты преследуешь. Из программы на Обероне можно выйти обычным способом, по ret на стеке с продолжением исполнения программы на BASIC'е? Если да, то принудительный переход в BASIC - это не дело. Если выход только по Halt(N), то можно перейти в 48K, только переход надо сделать тем кодом, который прислал тебе Wlodek. Кстати, а буфер принтера так критичен?
По большому счету, можно. Мы пришли к этому из-за того, что вектор прерывания лежит в #fe00...#feff, поэтому с #с000 должна быть впечатана быстрая страница. Во всем зоопарке фирменный машин быстрые страницы - только 0 и 2, а коммандер может оставить после себя впечатанной любую, в том числе и медленную страницу, то есть, есть небольшой риск получить на фирменной машине снег.
Итого: Принудительно впечатывать страницу 0 есть смысл только при использовании IM 2.
Да, это я облажался. Впечатывать страницу надо в загрузчике после CLEAR и перед загрузкой машкода (POKE 23388,16: OUT (32765),16).
Да, можно.
Тут играет роль мой специфический подход к кодированию для Спектрума, который, видимо, сформировался так потому что у меня не было 128k и я не ставил цели поддержать верхнюю память, но активно пользовался буфером принтера - для хранения переменных или как временный буфер, например, для скроллинга. Поэтому закономерно желание использовать буфер для этих целей вместо нахождения там непонятных для меня переменных 128k-BASIC'а. Я специально пишу про свой субъективный взгляд на эти вещи, чтобы вы видели перспективу. Дизайн библиотеки Basic нужно менять под 128k.
Да, притом из лоадера. Либо же использовать для этого специальную библиотеку, которую, быть может, кто-то разработает, если она ему понадобится.
Я начал разрабатывать утилиту makezx (на Обероне) - аналог bin2tap, порождающую Basic-лоадер, надо бы предусмотреть в ней такое впечатывание.
Ну как бы в целом общая рекомендация: коли ZXDev - инструмент разработки и набор библиотек, то использовать буфер принтера и отключать 128К явно не стоит. Потенциально может появиться продукт на 128-м BASIC'е, который захочет использовать код на Обероне или C или просто библиотеки ZXDev как подпрограммы - он обидится, если машкод принудительно включит 48К. Не надо делать втихаря неожиданнх для разработчика вещей.
- - - Добавлено - - -
Не получится. На Спектруме нельзя гарантированно узнать какая страница впечатана на момент вызова кода.
- - - Добавлено - - -
А лучше сразу под менеджер памяти с кастомными драйверами. Например, будет неплохо смотреться расширение - возможность печати симвла (строки) с указанием номера (адреса) шрифта и логического номера страницы, в которой шрифт лежит. Или запуск AY-проигрывателя с кодом и музыкой в произвольной странице. Или хотя бы просто загрузка некой более-менее самостоятельной библиотеки (как вариант - быстрая математика из Beta Basic) в страницу и вызов кода из нее.