Использование SDCC для разработки программ под ZX

Старый спектрумистский форум

Moderator: Shaos

User avatar
Shaos
Admin
Posts: 24080
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Использование SDCC для разработки программ под ZX

Post by Shaos »

В продолжение темы Программирование на компиляторах ЯВУ для ретро ЭВМ
barsik wrote:На форумах только и встречаются пользователи его, SDCC, ZDK88 и ещё IAR (но его трудно скачать и он платный)...
С некоторого времени z88dk перестал быть частью Debian (хотя с десяток лет назад был), а вот sdcc до сих пор остаётся одним из стандартных пакетов:

Code: Select all

root@amd64s:/# aptitude search sdcc
i   sdcc                                                      - Small Device C Compiler                                            
p   sdcc:i386                                                 - Small Device C Compiler                                            
i   sdcc-doc                                                  - Small Device C Compiler (documentation)                            
i A sdcc-libraries                                            - Small Device C Compiler (libraries)                                
i   sdcc-ucsim                                                - Micro-controller simulator for SDCC                                
p   sdcc-ucsim:i386                                           - Micro-controller simulator for SDCC                                

root@amd64s:/# aptitude show sdcc
Package: sdcc                            
Version: 3.5.0+dfsg-2+b1
State: installed
Automatically installed: no
Priority: optional
Section: electronics
Maintainer: Gudjon I. Gudjonsson <gudjon@gudjon.org>
Architecture: amd64
Uncompressed Size: 6,819 k
Depends: sdcc-libraries (= 3.5.0+dfsg-2), libc6 (>= 2.14), libgcc1 (>= 1:3.4), libstdc++6 (>= 5.2)
Recommends: sdcc-doc
Suggests: python, sdcc-ucsim
Conflicts: sdcc:i386
Breaks: sdcc-ucsim (< 3.5.0), sdcc-ucsim:i386 (< 3.5.0)
Replaces: sdcc-ucsim (< 3.5.0), sdcc-ucsim:i386 (< 3.5.0)
Description: Small Device C Compiler
 SDCC is a C compiler for the Intel MCS51 family, HC08, PIC, GameBoy Z80, DS80S390, Z80, Z180 and STM8 microcontrollers. 
 
 This package includes the compiler, assemblers and linkers.
Homepage: http://sdcc.sourceforge.net
Tags: devel::compiler, devel::lang:c, devel::machinecode, hardware::embedded, interface::commandline, role::program,
      scope::utility, works-with::software:source
Поэтому я решил таки заморочиться и научиться компилировать сишные программки под ZX Spectrum на SDCC.

После некоторого гугления я нашёл вот такую микродемку, написанную под SDCC с исходниками:

https://speccy.pl/archive/prod.php?id=223
sdcc_scroll.gif
Мне удалось пересобрать это в моём дебияне в том sdcc, что там есть (см. выше), но с изменённым скриптом сборки (поменял последние 2 команды - первод из HEX в BIN и создание TAP-файла):

Code: Select all

sdasz80 -o crt0.rel crt0.s
sdcc -mz80 --reserve-regs-iy --opt-code-speed --max-allocs-per-node 100000 --code-loc 0x800A --data-loc 0 --no-std-crt0 crt0.rel scroll.c -o scroll.ihx
objcopy -I ihex -O binary scroll.ihx scroll.bin
./bin2tap scroll.bin 32768 TAPE
где bin2tap это моя программа для генерации TAP-файлов, которая использует файл TAPE который есть бейсик-загрузчик кодовых блоков с адреса 32768 (оба взяты из моего nedoPC SDK). Полный исходник программы bin2tap.c можно найти под спойлером (версия от 14 июля 2024 года):

 bin2tap.c

Code: Select all

/* BIN2TAP.C - Alexander Shabarshin  24-OCT-2000 */
/* 17-JAN-2023 - added ability to set optional BASIC loader */
/* 14-JUL-2024 - added ability to give decimal or hexadecimal address */

/* THIS CODE IS PUBLIC DOMAIN - USE IT ON YOUR OWN RISK */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#pragma pack(1)

typedef struct _header
{
  unsigned char type; /* 3 - for code */
  char name[10]; /* spaces for end */
  unsigned short length;
  unsigned short start;
  unsigned short word; /* 0x8000 */
} header;

#pragma pack()

/* Convert string with hexadecimal number to integer */
int hex2i(char *s)
{
  char *ptr;
  long l = strtol(s,&ptr,16);
  if(*ptr) return -1;
  return (int)l;
}

int main(int argc,char **argv)
{
  int i,j,k;
  unsigned short start=0xE800;
  unsigned short size;
  unsigned char *ptr;
  header head;
  static char bin[100];
  static char tap[100];
  static char ldr[100];
  char *po;
  FILE *fbin;
  FILE *ftap;
  FILE *fldr;
  if(argc<2)
  {
     printf("\n\nBIN2TAP FILE.BIN [#E800] [LOADER.TAP]\n\n");
     return 0;
  }
  if(argc>2)
  {
     po = argv[2];
     if(*po=='#')
          start = hex2i(&po[1]);
     else start = atoi(po);
  }
  printf("START: 0x%4.4X (%i)\n",start,start);
  if(argc>3) strcpy(ldr,argv[3]);
  else *ldr = 0;
  strcpy(bin,argv[1]);
  strcpy(tap,bin);
  po = strchr(tap,'.');
  if(po!=NULL) *po=0;
  head.type = 3;
  strcpy(head.name,tap);
  for(i=strlen(tap);i<10;i++) head.name[i]=0x20;
  strcat(tap,".tap");
  head.start = start;
  head.word = 0x8000;
  fbin = fopen(bin,"rb");
  if(fbin==NULL)
  {
     printf("ERROR: Can't open file %s\n",bin);
     return -2;
  }
  ftap = fopen(tap,"wb");
  if(ftap==NULL)
  {
     printf("ERROR: Can't open file %s\n",tap);
     return -3;
  }
  fseek(fbin,0L,SEEK_END);
  head.length = ftell(fbin);
  fseek(fbin,0L,SEEK_SET);
  if(*ldr)
  {
     printf("LOADER %s\n",ldr);
     fldr = fopen(ldr,"rb");
     if(fldr)
     {
        fseek(fldr,0L,SEEK_END);
        k = ftell(fldr);
        fseek(fldr,0L,SEEK_SET);
        for(i=0;i<k;i++) fputc(fgetc(fldr),ftap);
        fclose(fldr);
     }
     else printf("ERROR\n");
  }
  size = sizeof(head)+2;
  fputc(size%256,ftap);
  fputc(size/256,ftap);
  fputc(0,ftap);
  ptr = (unsigned char*)&head;
  k = 0;
  for(i=0;i<size-2;i++)
  {
     j = ptr[i];
     fputc(j,ftap);
     k ^= j;
  }
  fputc(k,ftap);
  size = head.length+2;
  fputc(size%256,ftap);
  fputc(size/256,ftap);
  fputc(0xFF,ftap);
  k = 0;
  for(i=0;i<size-2;i++)
  {
     j = fgetc(fbin);
     fputc(j,ftap);
     k ^= j;
  }
  k=(~k)&0xFF;
  fputc(k,ftap);
  fclose(fbin);
  fclose(ftap);
  return 0;
}
Бейсик-загрузчик кодового блока с адреса #8000 (файл TAPE который надо указать третьим параметром):
tape.zip

и с подправленным crt0.s (правил чтобы всё начиналось с #8000):

Code: Select all

; minimal template for sdcc for zx spectrum programs
; init code starts at 0x8000
; main code starts at 0x800A
; stack is set to 0xfffe

    .globl _main

	.area _HEADER (ABS)

	.org    0x8000     ; 10 bytes in init section

init:
    di
	ld sp,#0xfffe      ; stack set to end of RAM
	call gsinit        ; sdcc init
    jp _main           ; just to be sure we start at main

code_and_data:
    .org 0x800A

    .area	_CODE      ; code and main function lands here
	.area	_DATA      ; global data section

gsinit:
    .area   _GSINIT    ; sdcc startup code
	.area   _GSFINAL
	ret
	
	.area	_HEAP

_HEAP_start::
(а кстати почему стек ставится в #FFFE? если надо поставить в конец памяти, то делаем LD SP,0 ведь SP всё равно декрементируется перед сохранением,
но если мы вдруг надумаем пользовательские символы UDG использовать, которые натолканы в конец памяти, то стек наверное надо поставить в #FF00)

Сишный исходник примера изобилует ассемблерными вставками типа таких:

Code: Select all

	__asm__ (" call #3503 "); 		// clear screen
...
	__asm__ (" ei ");			// enable interrupts
...
	__asm__ ("halt");		// wait for frame interrupt
или вот прямо целая функция может быть определена на асме:

Code: Select all

void srand_r() __naked {
  // use R registry to be more random
__asm
  	ld	a,r
	ld	hl,#_rand_c
	xor	a, (hl)
	ld	(hl),a
	ret
__endasm;
}
И этого в-принципе достаточно, чтобы начать что-то делать под ZX на ЯВУ :mrgreen:


P.S. Приаттачиваю архив с поправленным crt0.s (тут SP уже в #FF00 ставится):
You do not have the required permissions to view the files attached to this post.
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 24080
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Re: Использование SDCC для разработки программ под ZX

Post by Shaos »

На этот топик ссылается сегодняшняя статья на Хабре:

https://habr.com/ru/companies/diy_fest/articles/874792/

Там кстати интересная картинка из документации на SDCC приведена про то как передаются аргументы в функцию:
Screenshot from 2025-01-19 12-05-09.png
Если непонятно, то первая колонка - первый аргумент (выбираем тип), вторая колонка - второй аргумент (опять же выбираем тип), а третья колонка - все остальные аргументы (как можно догадаться они все идут в стэк).

К сожалению в той версии SDCC, что есть у меня (3.8.0), все аргументы суются в стэк...

P.S. Новый способ передачи аргументов появился только в SDCC 4.1.12:
Screenshot from 2025-01-19 18-24-04.png
https://msx.org/forum/msx-talk/development/sdcc-4112-a-game-changer-for-c-programming

P.P.S. Добавил в первое сообщение исходник своей программы BIN2TAP с бейсик-загрузчиком TAPE, чтобы никуда за ними ходить не надо было - теперь всё тут

P.P.P.S. Ещё заметил, что в статье --data-loc 0xa000 идёт как параметр компилятора - это адрес размещения сегмента данных (глобальные переменные), а у меня оно стоит в нуле (--data-loc 0) и судя по результатам сборки оно при таком раскладе просто толкает данные следом за кодом, что удобно т.к. если задавать адрес данных самому, то в бинарнике будет большая дырка между кодом и данными...
You do not have the required permissions to view the files attached to this post.
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 24080
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Re: Использование SDCC для разработки программ под ZX

Post by Shaos »

Shaos wrote: 19 Jan 2025 13:09 К сожалению в той версии SDCC, что есть у меня (3.8.0), все аргументы суются в стэк...

P.S. Новый способ передачи аргументов появился только в SDCC 4.1.12
В дебиане 12.8 уже должно быть то, что надо:

Code: Select all

aptitude show sdcc
Package: sdcc                            
Version: 4.2.0+dfsg-1
State: not installed
Priority: optional
Section: electronics
Maintainer: Debian Electronics Packaging Team <pkg-electronics-devel@alioth-lists.debian.net>
Architecture: amd64
Uncompressed Size: 9,232 k
Depends: sdcc-libraries (= 4.2.0+dfsg-1), libc6 (>= 2.34), libgcc-s1 (>= 3.4), libstdc++6 (>= 11), zlib1g (>= 1:1.2.0)
Recommends: sdcc-doc
Suggests: python, sdcc-ucsim
Breaks: sdcc-ucsim (< 3.5.0)
Replaces: sdcc-ucsim (< 3.5.0)
Description: Small Device C Compiler
 SDCC is a C compiler for the Intel MCS51 family, HC08, PIC, GameBoy Z80, DS80S390, Z80, Z180 and STM8 microcontrollers. 
 
 This package includes the compiler, assemblers and linkers.
Homepage: http://sdcc.sourceforge.net
Tags: devel::compiler, devel::lang:c, devel::library, devel::machinecode, hardware::embedded, implemented-in::c,
      interface::commandline, role::devel-lib, role::program, scope::utility, works-with::software:source
Я тут за главного - если что шлите мыло на me собака shaos точка net