Просмотр полной версии : SDCC: Автоматизация
Предлагается публиковать всяческие утилитки, так или иначе автоматизирующие процесс создания программ в SDCC от компиляции до конечного продукта.
Также приветствуются настройки CMAKE, Code::Blocks, Eclipse, иных сред разработки, для работы с SDCC.
Прилагаю sdccscl.rex - скрипт, автоматизирующий процесс компиляции исходника на Си и преобразование в готовое к запуску приложение.
В двух словах: на входе исходник на Си, на выходе - SCL c BASIC-монолодером, содержащим и запускающим результат компиляции исходника. Исходник относительно скрипта может размещаться где-угодно.
В начале скрипта есть настройки, но реально из них можно менять только адрес стэка и список подключаемых библиотек, потому что иначе надо переделывать генерацию scl-файла.
К скрипту прилагается пример: scr.c. Программка должна заполнять спектрумовский экран кодом 0xAA, и она, таки, заполняет. :)
P.S. Для тех, кто в танке: для работы скрипта требуется наличие установленного интерпретатора Regina REXX.
Q-Master
06.07.2014, 19:48
Вариант на cmake. Правда пока без автоматизации. Прикручу чуть позже.
Я как-то попробовал, ничего не получилось. Вот это:
/* SCLView */
parse arg scl
if scl='?' then do
options prompt 'FILE/A: '
parse pull scl
end
if scl='' then do
say 'required argument missing'
say 'No file to view'
exit
end
scl=strip(scl,,' "')
if ~open(file,scl,'R') then do
say 'No file to view'
exit
end
if readch(file,8)~='SINCLAIR' then do
say 'File is not SCL format'
exit
end
say 'SCLView (R) View Utility Version 1.0 03-Dec-2000'
say ' (c) 2000 Alex Kovrigin, 2:5000/28.19'
say
say 'Name Start Length Sector'
say '---------- ----- ------ ------'
do c2d(readch(file))
say readch(file,8) readch(file)||right(c2d(reverse(readch(file,2))),7 )||right(c2d(reverse(readch(file,2))),8)||right(c2 d(readch(file)),8)
end
На Амиге пашет как танк.
Или так:
/* TAPView */
PARSE ARG TAPFILE
IF TAPFILE='?' THEN DO
OPTIONS PROMPT 'FILE/A: '
PARSE PULL TAPFILE
END
IF TAPFILE='' THEN DO
SAY 'required argument missing'
SAY 'No file to view'
EXIT
END
TAPFILE=STRIP(TAPFILE,,' "')
IF ~OPEN(FILE,TAPFILE,'R') THEN DO
SAY 'No file to view'
EXIT
END
FILELENGTH=SEEK(FILE,0,'E')
SEEK(FILE,0,'B')
SAY 'TAPView (R) View Utility Version 1.0 10-Dec-2000'
SAY ' (c) 2000 Alex Kovrigin, 2:5000/28.19'
SAY
SAY 'Type Name Length Start Size'
SAY '--------------- ---------- ------ ----- -----'
LOOP:
BLOCKLENGTH=C2D(REVERSE(READCH(FILE,2)))-2
FLAG=C2D(READCH(FILE,1))
IF FLAG=0&BLOCKLENGTH=17 THEN DO
TYPE=C2D(READCH(FILE,1))
SELECT
WHEN TYPE=0 THEN TYPE='Programm'
WHEN TYPE=1 THEN TYPE='Number Array'
WHEN TYPE=2 THEN TYPE='Character Array'
WHEN TYPE=3 THEN TYPE='Bytes'
OTHERWISE
END
NAME=READCH(FILE,10)
SIZE=C2D(REVERSE(READCH(FILE,2)))
START=C2D(REVERSE(READCH(FILE,2)))
IF TYPE='Program'&START>32767 THEN START=NONE
LENGTH=C2D(REVERSE(READCH(FILE,2)))
IF TYPE='Bytes' THEN LENGTH=''
SAY LEFT(TYPE,15)||RIGHT(NAME,12)||RIGHT(LENGTH,8)||RI GHT(START,7)||RIGHT(SIZE,7)
END
ELSE DO
SAY '-----Headerless--block-----'RIGHT(FLAG,15)||RIGHT(BLOCKLENGTH,7)
SEEK(FILE,BLOCKLENGTH)
END
IF SEEK(FILE,1)=FILELENGTH THEN EXIT
SIGNAL LOOP
Я как-то попробовал, ничего не получилось.
1. В функции STRIP третий аргумент должен быть одиночным символом, а у тебя строка из пробела и кавычки.
2. То же самое, плюс баг Regina: "бесхозное" значение функции выводится в консоль, поэтому приходится значение функции чему-то присваивать.
3. Чтобы включить все "плюшки" АмигаRexx, в начало программы нужно добавить строчки:
OPTIONS AREXX_SEMANTICS
OPTIONS AREXX_BIFS
Подправил - работает отлично, в том числе в Linux.
P.S. На усмотрение модератора, сообщения по поводу программирования на REXX можно переместить в отдельную тему "REXX на службе ZX".
Q-Master
07.07.2014, 22:55
Автоматизация, не обязательно, чтоб совсем полная, но ОБЛЕГЧАЮЩАЯ нудные процессы :) И для cmake, надо бы версию указать, а то там у каждой свои прибамбасы, как я понял.
Да надо-бы таргеты для создания образа прикрутить, просто некогда.
Насчет версии:
Обычно прямо в CMakeLists.txt пишется минимальная требуемая версия.
В данном случае:
cmake_minimum_required(VERSION 2.8)
Никаких заморочек которые сломались-бы в пост-идущих версиях там нет. Все просто как валенки. Ну и в теме с линковкой был выложен полный архив с проектом где все собирается cmake'ом. Лучше, наверное, посмотреть туда, т.к. там еще есть модули для сборки библиотек. Да и просто понятнее вариант.
Подправил - работает отлично.
Спасибо! Похоже сейчас мне масть и попрёт. ;) Я ещё не знаю как, но какой-то прилив сил ощущаю. Ещё раз спасибо!
Q-Master
08.07.2014, 22:06
Как раз тот тулчейн и отказался собирать под cmake 3.0 - уж не знаю почему. Так что, тут аккуратней надо.
Хм. Возможно там поменялись названия переменных. Надо проверить. Мне пока не на чем. У меня 2.8.
magicwc.rex, собиралка плагинов для WC по типу make.
Должна лежать в папке с исходниками плагина. Параметров не требует. Всё задаётся статично внутри скрипта.
На входе имена исходных файлов (Си, ассемблер, данные), а на выходе - плагин.WMF.
Имя плагина определяется по файлу для 0-й страницы.
Более подробно - памятка в конце скрипта.
Всё не тестировал, но прилагаемый пример компилится и работает. Об ошибках прошу докладывать незамедлительно.
Да что ж это такое творится с функцией seek()?
Она работает, указатель по хэндлеру передвигает куда надо, но возвращает всегда 0 (а должна возвращать установленную позицию от начала). TAPView из-за этого косяка только первый заголовок и показывает т.к.:
FILELENGTH=SEEK(FILE,0,'E') => FILELENGTH=0
...
IF SEEK(FILE,1)=FILELENGTH THEN EXIT => 0=0 вот оно из цикла и выходит
Я уже всю голову сломал. :v2_dizzy_wall:
Да что ж это такое творится с функцией seek()?
Она работает, указатель по хэндлеру передвигает куда надо, но возвращает всегда 0 (а должна возвращать установленную позицию от начала). TAPView из-за этого косяка только первый заголовок и показывает т.к.:
FILELENGTH=SEEK(FILE,0,'E') => FILELENGTH=0
...
IF SEEK(FILE,1)=FILELENGTH THEN EXIT => 0=0 вот оно из цикла и выходит
Я уже всю голову сломал. :v2_dizzy_wall:
Есть вещи, которые работают не так как должны или не работают :(
Но это можно обойти другими средствами REXX. Сейчас на работе. Позже подумаю, как решить твой вопрос.
Можно конечно. Вот есть функция EOF(), но она тоже как-то не так работает, кстати и на Амиге аналогично.
Можно конечно. Вот есть функция EOF(), но она тоже как-то не так работает, кстати и на Амиге аналогично.
Чтобы узнать длину файла или его существование использую функцию CHARS
Для произвольного доступа - CHARIN/CHAROUT
Что-то и с CHARS() не попёрло.
И тут идея — а чего я парюсь, если когда мы достигаем конца файла то BLOCKLENGTH=-2, потому как:
LOOP:
BLOCKLENGTH=C2D(REVERSE(READCH(FILE,2)))-2
Ну и влепил в сразу после этого строку
IF BLOCKLENGTH=-2 THEN EXIT
Соответственно предпоследнюю строку
IF SEEK(FILE,1)=FILELENGTH THEN EXIT
переделываем в
a=SEEK(FILE,1)
FILELENGTH нам уже не нужен, соответственно строки перед циклом:
FILELENGTH=SEEK(FILE,0,'E')
a = SEEK(FILE,0,'B') /* Regina REXX mistake: translating unused function result to console. Need to use any variable*/
можно смело выбросить
Работает.
Затем думаю, а почему бы не попробовать EOF() применить (который раньше не хотел работать в конце цикла). Ну и меняем нашу новопридуманную
IF BLOCKLENGTH=-2 THEN EXIT
на
IF EOF(FILE) THEN EXIT
И тоже всё замечательно работает.
Sergey, спасибо за моральную поддержку. :)
Опечатку нашел. Строку
WHEN TYPE=0 THEN TYPE='Programm'
заменить на
WHEN TYPE=0 THEN TYPE='Program'
иначе, при отсутствии автозапуска не будет подставляться слово NONE, а будет высвечиваться какое-нибудь 65535, что есть бред.
Раз автоматизация, то внесу свои 5 копеек. Давно хотел, но то забыл то некогда.
В SDCC есть один недостаток - он всегда делает для инициализированных статических переменных отдельную секцию с данными, которую называет _INITIALIZER.
После загрузки программы, содержимое секции _INITIALIZER должно быть скопировано в секцию _INITIALIZED и только потом вызывается main().
Это приводит к тому, что для загрузки программа требует больше памяти, а главное - это копирование совершенно бессмысленно.
Выхода два:
1. Объявлять все инициализированные переменные как const. Очень неправильный и некрасивый выход.
2. Скопировать содержимое секции _INITIALIZER в секцию _INITIALIZED после линковки, а секцию _INITIALIZER вообще удалить. Именно такой выход и реализован мной в скрипте на bash. Для работы скрипта нужен .map-файл и бинарь.
Во вложении лежит пример.
59054
Немного о структуре:
scripts/autoconfig - слздает файл autoconfig.asm из config.mk
scripts/bin2hob - умеет делать hobeta из бинарей с помощью z80asm
scripts/sdrmini - скрипт, который копирует содержимое секции _INITIALIZER в секцию _INITIALIZED и удаляет секцию _INITIALIZER
crt0.s - начальный "запускальщик"
main.c - пример программы
Makefile - сборочный скрипт
tools.mk - тут описаны утилиты для сборки
config.mk - конфигурация программы: стартовый адрес, стек собственный или вызывающего, разрешение-запрещение прерываний
Наберите make tap и получите два выходных tap-файла:
bzxtest.tap - файл с бейсик-загрузчиком.
czxtest.tap - только кодовый файл.
Для добавления своих файлов с исходниками достаточно изменить строку Makefile OBJ=main.rel на свою, например OBJ=main.rel myfile.rel
Если в каталоге будет файл на C myfile.с или на ассемблере myfile.s - то он автоматически будет скомпилирован.
Для работы всего этого, конечно, нужны sdcc, bin2tap, make, bash, dd, sed, grep, dz80, hex2bin, z80asm. В общем приличный набор каждого уважающего себя кодера для ZX:)
В основном спековские утилиты есть во втором вложении.
- - - Добавлено - - -
Что-то увлекло меня.
В общем облагородил систему сборки. Библиотеки в отдельном каталоге libsrc теперь. Автоматически пути генерируются. Автоматически подключаются к программе.
Собирается вся эта радость sdcc-3.6.0
Дополнительные утилиты прилагаю.
Засунул туда поддержку PS2 (в демке не используется), спрайтов, printfa куцего и сбацал микро-дему (шарики и музыка по кругу)
Сборочная среда с демкой.
59056
Утилиты.
59057
Автоматизируем дальше.
Разбил библиотеки и программы. Теперь можно компилировать множество программ с одними и теми же библиотеками, но настройки программы для каждой свои.
Библиотеки (исходники) лежат в libsrc, откомпиленные библиотеки - в libs.
Программы (исходники) лежат в apps, откомпиленные программы - в bin.
Настройки общие - в configs. Там отельные файлы:
apps.mk - список программ для сборки
library.mk - список собираемых библиотек
tools.mk - список утилит
crt0.mk - стартовый код. Для каждой программы от собирается со своими настройками, которые находятся в каталоге программы (файл apps/имя программы/config.mk).
Такой подход позволяет собирать программы с разными адресами расположения.
Ограничения. Имя программы должно совпадать с каталогом ее расположения. Например:
программа testapp распологается в каталоге apps/testapp и в файле apps/testapp/Makefile имя программы тоже указано как APP=testapp
59067
Переработал немного вывод, чтобы подключить стандартный printf().
Функции для позиционирования курсора, управления цветом и очистки экрана - в библиотеке libconio.
Есть ли поддержка float для z80 в sdcc - ЗАГАДКА. Функции компилируются и имеются в библиотеке. НО! попытка сделать любую операцию с float - ломает программу :(
Oleg N. Cher
22.12.2016, 19:55
Гм, слом программы может быть не из-за самого float, а из-за пристёгивания рантаймов. Там всё хитро, в коде есть окошко, забитое FF, если сделать его слишком маленьким - программа будет глючить. Надо поиграться адресами.
В ZXDev есть примеры, использующие тип float, которые собираются SDCC и работают. См. Flower, GraphSinus, Spiral в архиве. Используемый в Си-исходниках тип REAL определён в SYSTEM.h как
typedef float REAL;
59089
Что-то с библиотеками у меня.
Когда я делаю так:
float f=1.0f;
void main(){
f=f+0.1;
while(1);
}
то программа компилируется, но сбрасывается.
А когда я сам компилирую библиотечную функцию __fsadd() - то работает нормально.
Думаю, что дело в компиляторе.
Разобрался.
Нашел ошибку в скрипте, который перемещает инициализированные переменные из INITIALIZER в INITIALIZED.
Нет худа без добра. Вытащил все стандартные библиотеки для Z80 из SDCC и воткнул их в свою систему сборки.
Если нужна плавающая точка в printf(), то теперь достаточно поправить файл configs/printf_float.mk
Только вот засада, при использовании printf() с плавающей точкой размер программы сразу возрастает на 6Кбайт!
Если надо выводить только текстовые строки (с прокруткой, как в терминале) - то есть функция printf() в libconio. Она маленькая. Для управления экраном смотрите libconio.h (цвета, позиция курсора и проч).
В программе используется шрифт KOI8R (2Кбайта). Есть идея вынести его в отдельную библиотеку. Если он не нужен - то проще использовать системный.
Пробуйте, то что я накропал) Вдруг кому понравится)
Мои эксперименты с float показали, очевидную вещь - флоат дико тормозит, потому как написан на C.
Интересно, а имеется ли для 8080/z80 библиотека работы с float IEEE стандарта, написанная на ассемблере? Хотя бы + - * /?
blackmirror
27.12.2016, 14:43
SfS, а насколько дико? Вот здесь (http://www.smxrtos.com/ussw/gofast/gofast_z80_z180_64180.htm) есть табличка про некоторую библиотеку которая даёт в среднем 163 микросекунды на сложение, 693 на умножение и 905 на деление, на Z80 с частотой 6МГц. Если пересчитать в такты, то получается 978, 4158 и 5430 соответственно, чтобы понять много это или мало, можно прикинуть сколько тактов требует умножение 24x24. Если делать через три умножения формата 8x24, поместив один множитель в C:D:E, в A:H:L записав 0, а в B записывая очередной байт второго множителя, то выполнив 8 раз блок ADD HL,HL/ADC A,A/RL B/JR NC,Xn/ADD HL,DE/ADC A,C/JR NC,Xn/INC B/Xn: на выходе в B:A:H:L мы получим 32х разрядное произведение. Среднее время выполнения умножения 8X24 составляет 8*(11+4+8)+4*(7+12+11+4)+2*(7+12+4)=366 тактов, или 1098 тактов на вычисление всех трёх произведений, без учёта загрузки регистров и окончательного суммирования. Чтобы обработать знаки,порядки и всякие исключительные ситуации думаю еще тактов 500 потребуется, в общем по сравнению с существующими библиотеками максимальное ускорение которое можно получить переписав всё на ассемблер это 2-3 раза.
Два-три раза - это существенно.
А где такую "некоторую библиотеку" взять? Оно ж наверное несвободно.
blackmirror
28.12.2016, 12:21
SfS, у меня такое подозрение что библиотека входит в состав какого-то их продукта, но без регистрации даже документацию не почитать, а полей заполнять там нужно дофига. Есть упоминание про "We sell on 30-day free trial, so you can test it in your application". Еще интересная фраза "They are fast because they are written in assembly language and specifically optimized for each processor", но закрадывается подозрение что либо переводили с Си, либо для умножения мантиссы использовали умножение 32x32. Хотя может всё дело в том, что обработка IEEE 754 для Z80 не слишком удобна, поскольку приходится извлекать порядок из двух байт, прежде чем можно будет обрабатывать всякие NaN, INF и денормализованные числа. Еще и 4 возможных способа округления тоже наверно не очень способствуют компактности кода.
извлечение порядка и мантиссы несложно сделать.
я сейчас пробую написать сложение float+float на асме. Хочу заменить им стандартную сишную функцию для float и посмотреть разницу в скорости.
Error404
30.12.2016, 18:59
извлечение порядка и мантиссы несложно сделать.
я сейчас пробую написать сложение float+float на асме. Хочу заменить им стандартную сишную функцию для float и посмотреть разницу в скорости.
есть же готовые либы в исходниках, например от HitechC , они на ассемблере уже ЕМНИП
Oleg N. Cher
30.12.2016, 19:00
А вдруг SfS лучше сделает? :)
Ну поскольку я на новый год уезжал, то не сделал ещё вообще никак)
Ну вот и первые результаты. Пока теста скорости нет. Отлаживаю обработку.
Для скорости пришлось пожертвовать дополнительным скрытым битом, что для спека вполне нормально. 24бита точности хватит за глаза.
Кому интересно - программа называется testapp. В файле main.c вставляете свои значение переменных a= и b=, компилируете и запускаете в эмуле.
Пока вроде работает корректно.
Процедура сложения двух float'ов - в файле testapp/float.s.
Сделал 2 теста.
Один проверяет точность, второй на скорость.
Моя реализация сложения float в три с половиной раза быстрее того, что есть в библиотеке SDCC.
Точность чуть хромает иногда. Младший разряд. Но это гдето на одно сложений случайных чисел на 500.
Время мерял через int. Соответсвенно, у меня 300 сложений занимает 11*0.02=0.22сек. Стандартные 37*0.02=0.74сек.
Т.е. вариант стандартный 0.0025 сек на сложение.
Вариант мой: 0.00073 сек на сложение.
Все примерно, конечно.
Исходный код теста (testapp/main.c):
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <color.h>
#include <im2.h>
//
#include <stdint.h>
#include <string.h>
#include <math.h>
//
#define __SDCC_FLOAT_LIB 1
#include <float.h>
// Test iterations
#define iteration 300
float a=-0.5e-3;
float b=1.5e2;
union flong{
float f;
uint32_t l;
};
float fsadd(float a, float b)__naked;
/*
void fprint(float v){
union flong f;
f.f=v;
printf("%f [%.8lX]",f.f, f.l);
}
*/
// Correct addition
void test_1(){
union flong fl1;
union flong fl2;
//
float fa1;
float fa2;
//
int err;
int ok;
//
int i;
//
err=0;
ok=0;
//
printf("test_1() begin\n");
//
for(i=0; i<iteration; i++){
// Generage two floats
fl1.l = ((uint32_t)rand()) | (((uint32_t)rand())<<16);
fl2.l = ((uint32_t)rand()) | (((uint32_t)rand())<<16);
// Addition
fa1 = fl1.f + fl2.f;
fa2 = fsadd( fl1.f , fl2.f );
// Ok or Error
if( fa1 == fa2 ){
ok++;
}
else{
err++;
fl1.f=fa1;
fl2.f=fa2;
printf("\nerr: %.8lX,%.8lX\n", fl1.l, fl2.l);
printf("err: %.10f,%.10f\n", fl1.f, fl2.f);
}
//printf("[f1=%f] [f2=%f] ok=%i, err=%i\n", fl1.f, fl2.f, ok, err );
printf("ok=%i, err=%i\r", ok, err);
}
printf("\ntest_1() end\n");
}
//
static volatile int timer;
void timerhdl(){
timer++;
}
void fdummy(float f){}
float testArray1[iteration];
float testArray2[iteration];
// Speed addition
void test_2(){
int time0;
int time1;
//
int i;
//
printf("\ntest_2() begin\n");
//
printf("Generate arrays. Wait.\n");
for(i=0; i<iteration; i++){
// Generage two floats
testArray1[i] = ((uint32_t)rand()) | (((uint32_t)rand())<<16);
testArray2[i] = ((uint32_t)rand()) | (((uint32_t)rand())<<16);
}
// Standart
CLI();
timer=0;
im2SetHandler(timerhdl);
im2Set();
printf("Standart additions. Wait.\n");
SEI();
for(i=0; i<iteration; i++){
// Addition
fdummy(testArray1[i] + testArray2[i]);
}
time0 = timer;
// SfS
CLI();
timer=0;
im2SetHandler(timerhdl);
im2Set();
printf("SfS additions. Wait.\n");
SEI();
for(i=0; i<iteration; i++){
// Addition
fdummy(fsadd( testArray1[i], testArray2[i] ));
}
time1 = timer;
//
printf("Std add=%i, SfS add=%i\n",time0,time1);
//
printf("test_2() begin\n");
}
// Начало
void main(){
CLI();
//
ccls(ATTRN(YELLOW,BLACK));
print("Float running\n\n");
/*
printf("a=");fprint(a);putchar('\n');
printf("b=");fprint(b);putchar('\n');
printf("a+b= %f ",a+b);fprint(fsadd(a,b));putchar('\n');
printf("\nOk\n");
*/
test_1();
test_2();
//
while(1);
}
Для переключения в библиотеке стандартной и моей реализации, необходимо выставить символ SFS_FLOAT в файле configs/sfs_float.mk
Для запуска теста, надо ставить SFS_FLOAT=n (в библиотеке будет использоваться стандартная реализация сложения).
Если хочется попробовать мою реализацию в библиотеке, то ставьте SFS_FLOAT=y.
Oleg N. Cher
21.01.2017, 16:39
А хорошо бы вообще заиметь 24-битную вещ. арифметику для типа float и 32-битную для double, больше нет смысла на Z80 имхо. Но это к разработчикам компилеров. А так - вижу старания SfS, респектирую и понимаю как это всё трудно встроить в свой процесс разработки.
- - - Добавлено - - -
Аргумент против 5-байтного представления вещ. чисел (как это реализовано в ПЗУ ZX Spectrum) - слишком медленно.
Можно еще оптимальнее гораздо сделать, чем у меня. Это просто пока алгоритм неоптимальный.
Там где скорость нужна вообще проще фиксированной точкой обойтись.
Что касается "стараний", то изначально была идея сделать достаточно удобную сборочную среду. В общем это удалось. Ну а флоаты это просто интересно. Зарядка для ума и вспоминание ассемблера.
Кстати, а кто-нибудь смотрел архивчик со сборочной средой? Есть пожелания, предложения?
Какие либы вставить?
Выложил сюда. https://github.com/salextpuru/sdcc-noinit
1. Добавил файлы для KDevelop, если кто пользуется как я.
2. Добавил возможность создания WC-плагинов с соответствующей библиотекой. Пока что не сделал работу с файлами. Но в процессе.
Ну и куча мелочей.
Рядом лежат исходники PC-утилит для работы с форматами и прочим. https://github.com/salextpuru/speccy-toochain
Добавил библиотеку-драйвер для вывода на экран. Предназначена для вывода ТЕКСТА в различных режимах. Пока прототип. Задумка - универсальное описание текстовых экранов в различных видеорежимах. Пока сделан только ZX. Дальше будет текстовый типа ATM или TSConf. Если получится все как задумано, то и другие режимы попробую.
Добавлен драйвер родной ZX-клавиатуры https://github.com/salextpuru/sdcc-noinit
Теперь есть и ZX и PS2 напрямую. Попробую собрать все воедино с интерфейсом.
commit bdea4a4934d81dfa3b5f851b4a633b1b42040ecf (HEAD -> master, origin/master, origin/HEAD)
Author: Alexey
Date: Sat Aug 5 00:20:14 2017 +0700
Работоспсобный драйвер клавиатурного ввода. Пока только на одну клавишу.
Русский (KOI8-R) и латинский.
В силу убогости клавиатуры в 40 кнопок некоторые буквы висят на
SS+другая буква:
// Ъ - SS+ Ь
// Х - SS+ К
// Э - SS+ Ы
// Ж - SS+ Г
// Ю - SS+ У
// Б - SS+ В
// Ё - SS+ Е
Написаны два теста драйверов клавиатуры - PS2 и ZX. Интерфейс практически идентичный. Раскладка стандартной ZX на кириллице - угробищна. Но можно поменять.
https://github.com/salextpuru/sdcc-noinit commit 958ca10836daf207b5a8701e13e102aea71254a7
Начал писать доку. Если есть что сказать - скажите:) https://github.com/salextpuru/sdcc-noinit/blob/master/doc/sdcc-noinit.pdf
s_kosorev
07.08.2017, 12:25
думал дока про сабжевые тулсы писателя документа, а не очередной букварь "как компилирует компилятор"
думал дока про сабжевые тулсы писателя документа, а не очередной букварь "как компилирует компилятор"
1. Это заготовка доки. Там дальше и пойдет о том, что и как. Надо ж было с чего-то начать.
2. Не все знают то, что для тебя может быть "букварем".
3. Кратко дока именно про "сабжевые тулсы писателя" тут. Но её очень мало. https://github.com/salextpuru/sdcc-noinit/blob/master/README.md
- - - Добавлено - - -
Добавил про секции линкера и особенности SDCC
Добавлено немного про стартовый код и про добавление программ в систему сборки. https://github.com/salextpuru/sdcc-noinit/blob/master/doc/sdcc-noinit.pdf
s_kosorev
08.08.2017, 14:07
про HOME сюда по исходникам SDCC и доке, это для MSC51 если не указан атрубут banked, функция расположен в секции _HOME, в общем для Z80 рудимент (или даже недостижимая фича)
Добавлены разделы про локальные и глобальные области видимости. https://github.com/salextpuru/sdcc-noinit/blob/master/doc/sdcc-noinit.pdf
- - - Добавлено - - -
про HOME сюда по исходникам SDCC и доке, это для MSC51, в доке написано что все функции для MSC51 генеряться как banked а если указать атрибут nonbanked, функция расположен в секции _HOME, в общем для Z80 рудимент (или даже недостижимая фича)
Да оно и не надо.
У sdcc тулчейна всё таки одна нехорошая штука, это очень странный (непривычный) синтаксис z80 асма.
Если это не напрягает, но и нормально,
Иначе же,можно посмотреть в сторону z88dk.
Там вменяемый синтаксис асма (и sdcc заточен под этот асм).
а есть разница - 05(ix) или (ix+05) ?
лично меня не напрягает особо. дело привычки.
ужасм и пасмо на 5(ix) давятся
Добавил описание сборочных скриптов и ещё кучу всего помелочи. Пишу то, что обдумываю, потому не последовательно. https://github.com/salextpuru/sdcc-noinit/blob/master/doc/sdcc-noinit.pdf
- - - Добавлено - - -
ужасм и пасмо на 5(ix) давятся
ну я им сочуствую) не переделывать же все. А малой кровью другой асм к SDCC не прикручивается. В общем - закончу с описанием, а там посмотрим.
Добавлена полуигра, сделанная за 4 часа. Скрипт для конвертации спрайтов.
https://github.com/salextpuru/sdcc-noinit/tree/master/apps/game-loderunner
Вот собранная тапка.
61921
ну я им сочуствую)
а какой ассемблер понимает? тоже хочется посочувствовать пользователям.
Согласно опциям, генерит код в --asm= Define assembler name (rgbds/asxxxx/isas/z80asm)
я использую родной SDCCшый sdasz80. В принципе можно переделать и на другой какой. Но пока не замарачиваюсь. Там, кроме IX IY отличий в общем-то нет по синтаксису.
Обновлена дока.
Добавлено описание на тему "как добавить свою программу и библиотеку".
Добавлено описание на тему "что нам нужно, чтобы система сборки взлетела".
https://github.com/salextpuru/sdcc-noinit/blob/master/doc/sdcc-noinit.pdf
Добавлены разделы по передаче параметров в функции на ассемблере и возврату значений в С.
Добавлен глоссарий по утилитам и прочему.
https://github.com/salextpuru/sdcc-noinit/blob/master/doc/sdcc-noinit.pdf
Добавлены примеры функций, иллюстрирующие передачу и возврат значений.
Каталог apps/example-0. Добавлено описание примеров в документацию. (раздел 4.6. Примеры функций на ассемблере)
https://github.com/salextpuru/sdcc-noinit/blob/master/doc/sdcc-noinit.pdf
Тема уехала сюда: http://zx-pk.ru/threads/25944-s-chego-nachat/page9.html
Смотрелка TZX.
/* TZXView */
OPTIONS AREXX_BIFS
OPTIONS AREXX_SEMANTICS
PARSE ARG TZXFILE
IF TZXFILE='?' THEN DO
OPTIONS PROMPT 'FILE/A: '
PARSE PULL TZXFILE
END
IF TZXFILE='' THEN DO
SAY 'required argument missing'
SAY 'No file to view'
EXIT
END
TZXFILE=STRIP(TZXFILE,,'"')
TZXFILE=STRIP(TZXFILE,,' ')
IF ~OPEN(FILE,TZXFILE,'R') THEN DO
SAY 'No file to view'
EXIT
END
IF READCH(FILE,8)~='ZXTape!'X2C(1A) THEN DO
SAY 'This file is not TZX type'
EXIT
END
SAY 'TZXView (R) View Utility Version 1.0 04-Feb-2022'
SAY ' (c) 2022 Alex Kovrigin, 2:5000/111.47'
SAY TZXFILE 'ZXTape file revision' C2D(READCH(FILE,1))'.'RIGHT(C2D(READCH(FILE,1)),2, 0)
SAY
DO FOREVER
ID=C2X(READCH(FILE,1))
SELECT
WHEN ID=10 THEN DO
PAUSE=C2D(REVERSE(READCH(FILE,2)))
LENGTH=C2D(REVERSE(READCH(FILE,2)))
SAY 'ID'ID 'Standard speed data block. Pause after this block' PAUSE 'ms. Length' LENGTH
FLAG=C2D(READCH(FILE,1))
IF FLAG=0&LENGTH=19 THEN DO
TYPE=C2D(READCH(FILE,1))
SELECT
WHEN TYPE=0 THEN TYPE='Program'
WHEN TYPE=1 THEN TYPE='Number Array'
WHEN TYPE=2 THEN TYPE='Character Array'
WHEN TYPE=3 THEN TYPE='Bytes'
OTHERWISE
END
NAME=READCH(FILE,10)
SIZE=C2D(REVERSE(READCH(FILE,2)))
START=C2D(REVERSE(READCH(FILE,2)))
IF TYPE='Program'&START>32767 THEN START=NONE
LENGTH=C2D(REVERSE(READCH(FILE,2)))
IF TYPE='Bytes' THEN LENGTH=''
SAY ' Type Name Length Start Size'
SAY ' 'LEFT(TYPE,15)||RIGHT(NAME,12)||RIGHT(LENGTH,8)||R IGHT(START,7)||RIGHT(SIZE,7)
END
ELSE DO
SAY ' Type Flag Size'
SAY ' -----Headerless--block-----'RIGHT(FLAG,15)||RIGHT(LENGTH-2,7)
ENDLENGTH=SEEK(FILE,LENGTH-2)
END
ENDLENGTH=SEEK(FILE,1)
END
WHEN ID=11 THEN DO
ENDLENGTH=SEEK(FILE,13)
PAUSE=C2D(REVERSE(READCH(FILE,2)))
LENGTH=C2D(REVERSE(READCH(FILE,3)))
SAY 'ID'ID 'Turbo speed data block. Pause after this block' PAUSE 'ms. Length' LENGTH
FLAG=C2D(READCH(FILE,1))
IF FLAG=0&LENGTH=19 THEN DO
TYPE=C2D(READCH(FILE,1))
SELECT
WHEN TYPE=0 THEN TYPE='Program'
WHEN TYPE=1 THEN TYPE='Number Array'
WHEN TYPE=2 THEN TYPE='Character Array'
WHEN TYPE=3 THEN TYPE='Bytes'
OTHERWISE
END
NAME=READCH(FILE,10)
SIZE=C2D(REVERSE(READCH(FILE,2)))
START=C2D(REVERSE(READCH(FILE,2)))
IF TYPE='Program'&START>32767 THEN START=NONE
LENGTH=C2D(REVERSE(READCH(FILE,2)))
IF TYPE='Bytes' THEN LENGTH=''
SAY ' Type Name Length Start Size'
SAY ' 'LEFT(TYPE,15)||RIGHT(NAME,12)||RIGHT(LENGTH,8)||R IGHT(START,7)||RIGHT(SIZE,7)
END
ELSE DO
SAY ' Type Flag Size'
SAY ' -----Headerless--block-----'RIGHT(FLAG,15)||RIGHT(LENGTH-2,7)
ENDLENGTH=SEEK(FILE,LENGTH-2)
END
ENDLENGTH=SEEK(FILE,1)
END
WHEN ID=12 THEN DO
PAUSE=C2D(REVERSE(READCH(FILE,2)))
LENGTH=C2D(REVERSE(READCH(FILE,2)))
SAY 'ID'ID 'Pure tone. Length of pulse' PAUSE 'T-states. Number of pulses' LENGTH
ENDLENGTH=SEEK(FILE,0)
END
WHEN ID=13 THEN DO
LENGTH=C2D(READCH(FILE,1))
SAY 'ID'ID 'Pulse sequence. Number of pulses' LENGTH
ENDLENGTH=SEEK(FILE,LENGTH*2)
END
WHEN ID=14 THEN DO
ENDLENGTH=SEEK(FILE,5)
PAUSE=C2D(REVERSE(READCH(FILE,2)))
LENGTH=C2D(REVERSE(READCH(FILE,3)))
SAY 'ID'ID 'Pure data block. Pause after this block' PAUSE 'ms. Length' LENGTH
ENDLENGTH=SEEK(FILE,LENGTH)
END
WHEN ID=15 THEN DO
ENDLENGTH=SEEK(FILE,2)
PAUSE=C2D(REVERSE(READCH(FILE,2)))
ENDLENGTH=SEEK(FILE,1)
LENGTH=C2D(REVERSE(READCH(FILE,3)))
SAY 'ID'ID 'Direct recording. Pause after this block' PAUSE 'ms. Length' LENGTH
ENDLENGTH=SEEK(FILE,LENGTH)
END
WHEN ID=16 THEN DO
LENGTH=C2D(REVERSE(READCH(FILE,4)))
SAY 'ID'ID 'C64 ROM type data block. Block length' LENGTH
ENDLENGTH=SEEK(FILE,LENGTH)
END
WHEN ID=17 THEN DO
LENGTH=C2D(REVERSE(READCH(FILE,4)))
SAY 'ID'ID 'C64 turbo tape data block. Block length' LENGTH
ENDLENGTH=SEEK(FILE,LENGTH)
END
WHEN ID=18 THEN DO
LENGTH=C2D(REVERSE(READCH(FILE,4)))
PAUSE=C2D(REVERSE(READCH(FILE,2)))
SAY 'ID'ID 'CSW recording block. Pause after this block' PAUSE 'ms. Block length' LENGTH
ENDLENGTH=SEEK(FILE,LENGTH-2)
END
WHEN ID=19 THEN DO
LENGTH=C2D(REVERSE(READCH(FILE,4)))
PAUSE=C2D(REVERSE(READCH(FILE,2)))
SAY 'ID'ID 'Generalized data block. Pause after this block' PAUSE 'ms. Block length' LENGTH
ENDLENGTH=SEEK(FILE,LENGTH-2)
END
WHEN ID=20 THEN DO
PAUSE=C2D(REVERSE(READCH(FILE,2)))
IF PAUSE=0 THEN SAY 'ID'ID '''Stop the tape'' command'
ELSE SAY 'ID'ID 'Pause (silence)' PAUSE 'ms.'
ENDLENGTH=SEEK(FILE,0)
END
WHEN ID=21 THEN DO
LENGTH=C2D(READCH(FILE,1))
NAME=READCH(FILE,LENGTH)
SAY 'ID'ID 'Group start. Group name:' NAME
ENDLENGTH=SEEK(FILE,0)
END
WHEN ID=22 THEN DO
SAY 'ID'ID 'Group end'
ENDLENGTH=SEEK(FILE,0)
END
WHEN ID=23 THEN DO
SAY 'ID'ID 'Jump to block'
ENDLENGTH=SEEK(FILE,2)
END
WHEN ID=24 THEN DO
LENGTH=C2D(REVERSE(READCH(FILE,2)))
SAY 'ID'ID 'Loop start. Number of repetitions' LENGTH
ENDLENGTH=SEEK(FILE,0)
END
WHEN ID=25 THEN DO
SAY 'ID'ID 'Loop end'
ENDLENGTH=SEEK(FILE,0)
END
WHEN ID=26 THEN DO
LENGTH=C2D(REVERSE(READCH(FILE,2)))
SAY 'ID'ID 'Call sequence. Number of calls' LENGTH
ENDLENGTH=SEEK(FILE,LENGTH*2)
END
WHEN ID=27 THEN DO
SAY 'ID'ID 'Return from sequence'
ENDLENGTH=SEEK(FILE,0)
END
WHEN ID=28 THEN DO
LENGTH=C2D(REVERSE(READCH(FILE,2)))
PAUSE=READCH(FILE,1)
SAY 'ID'ID 'Select block: 'PAUSE
ENDLENGTH=SEEK(FILE,LENGTH-1)
END
WHEN ID=2A THEN DO
SAY 'ID'ID 'Stop tape if in 48K mode'
ENDLENGTH=SEEK(FILE,4)
END
WHEN ID=2B THEN DO
ENDLENGTH=SEEK(FILE,4)
PAUSE=C2D(READCH(FILE,1))
SELECT
WHEN PAUSE=0 THEN PAUSE='Low'
WHEN PAUSE=1 THEN PAUSE='High'
OTHERWISE
END
SAY 'ID'ID 'Set signal level. Signal level' PAUSE
ENDLENGTH=SEEK(FILE,0)
END
WHEN ID=30 THEN DO
LENGTH=C2D(READCH(FILE,1))
PAUSE=READCH(FILE,LENGTH)
SAY 'ID'ID 'Text description. Length' LENGTH
SAY ' 'PAUSE
ENDLENGTH=SEEK(FILE,0)
END
WHEN ID=31 THEN DO
PAUSE=C2D(READCH(FILE,1))
LENGTH=C2D(READCH(FILE,1))
CHAR=READCH(FILE,LENGTH)
SAY 'ID'ID 'Message block. Time for which the message should be displayed' PAUSE 's. Length' LENGTH
SAY ' 'CHAR
ENDLENGTH=SEEK(FILE,0)
END
WHEN ID=32 THEN DO
LENGTH=C2D(REVERSE(READCH(FILE,2)))
PAUSE=C2D(READCH(FILE,1))
SAY 'ID'ID 'Archive info. Number of text strings' PAUSE'. Length' LENGTH
ENDLENGTH=SEEK(FILE,LENGTH-1)
END
WHEN ID=33 THEN DO
LENGTH=C2D(READCH(FILE,1))
SAY 'ID'ID 'Hardware type'
ENDLENGTH=SEEK(FILE,LENGTH*3)
END
WHEN ID=34 THEN DO
SAY 'ID'ID 'Emulation info'
ENDLENGTH=SEEK(FILE,8)
END
WHEN ID=35 THEN DO
PAUSE=READCH(FILE,16)
LENGTH=C2D(REVERSE(READCH(FILE,4)))
SAY 'ID'ID 'Custom info block. Length of the custom info' LENGTH
SAY ' 'PAUSE
ENDLENGTH=SEEK(FILE,LENGTH)
END
WHEN ID=40 THEN DO
PAUSE=C2D(READCH(FILE,1))
SELECT
WHEN PAUSE=0 THEN PAUSE=Z80
WHEN PAUSE=1 THEN PAUSE=SNA
OTHERWISE
END
LENGTH=C2D(REVERSE(READCH(FILE,3)))
SAY 'ID'ID 'Snapshot block.' PAUSE'. Snapshot length' LENGTH
ENDLENGTH=SEEK(FILE,LENGTH)
END
WHEN ID=5A THEN DO
ENDLENGTH=SEEK(FILE,7)
SAY 'ID'ID 'Glue block. ZXTape file revision' C2D(READCH(FILE,1))'.'C2D(READCH(FILE,1))
ENDLENGTH=SEEK(FILE,0)
END
WHEN ID=00 THEN DO
SAY
SAY 'ID'ID', real length:' ENDLENGTH'. Please cut!'
EXIT
END
OTHERWISE DO
SAY
SAY 'ID'ID', length:' ENDLENGTH
EXIT
END
END
END
Примеры:
D:\util\regina\regina.exe D:\util\regina\TZXView.rex Cobra Force.tzx
TZXView (R) View Utility Version 1.0 04-Feb-2022
(c) 2022 Alex Kovrigin, 2:5000/111.47
Cobra Force.tzx ZXTape file revision 1.10
ID30 Text description. Length 28
Created with Ramsoft MakeTZX
ID10 Standard speed data block. Pause after this block 967 ms. Length 19
Type Name Length Start Size
Program Cobra 142 0 142
ID10 Standard speed data block. Pause after this block 2853 ms. Length 144
Type Flag Size
-----Headerless--block----- 255 142
ID10 Standard speed data block. Pause after this block 761 ms. Length 19
Type Name Length Start Size
Bytes loader 65024 512
ID10 Standard speed data block. Pause after this block 2930 ms. Length 514
Type Flag Size
-----Headerless--block----- 255 512
ID11 Turbo speed data block. Pause after this block 1 ms. Length 6914
Type Flag Size
-----Headerless--block----- 0 6912
ID11 Turbo speed data block. Pause after this block 760 ms. Length 40002
Type Flag Size
-----Headerless--block----- 0 40000
ID11 Turbo speed data block. Pause after this block 16079 ms. Length 6914
Type Flag Size
-----Headerless--block----- 0 6912
ID, length: 54643
D:\util\regina\regina.exe D:\util\regina\TZXView.rex Beach Head.tzx
TZXView (R) View Utility Version 1.0 04-Feb-2022
(c) 2022 Alex Kovrigin, 2:5000/111.47
Beach Head.tzx ZXTape file revision 1.20
ID32 Archive info. Number of text strings 2. Length 21
ID10 Standard speed data block. Pause after this block 984 ms. Length 19
Type Name Length Start Size
Program BEACH HEAD 795 0 847
ID10 Standard speed data block. Pause after this block 6094 ms. Length 849
Type Flag Size
-----Headerless--block----- 255 847
ID19 Generalized data block. Pause after this block 1971 ms. Block length 268
ID19 Generalized data block. Pause after this block 1952 ms. Block length 7160
ID19 Generalized data block. Pause after this block 310 ms. Block length 26369
ID19 Generalized data block. Pause after this block 0 ms. Block length 14408
ID, length: 49137
Powered by vBulletin® Version 4.2.5 Copyright © 2026 vBulletin Solutions, Inc. All rights reserved. Перевод: zCarot