Files
snark13 c71e249a4e Add full compiler toolchain, libc, examples and reference docs
First substantive commit: the entire Sprinter C compiler tree on top of
the bare README+gitignore initial commit.

What's in here:
  bin/sprinter-cc        — driver script invoking SDCC + linker + mkexe
  libc/                  — Sprinter-specific libc layer over ESTEX/BIOS
                           (conio, gfx, io, mem, stdio + headers)
  runtime/               — crt0 variants (default/small/banked/minimal)
                           + heap + bank trampolines
  toolchain/             — mkexe (SprintEXE packer, C + tests)
  examples/              — 30 demo programs (gfx, file I/O, env, time, …)
  lib/Makefile           — builds the libc archive (sprinter.lib)
  docs/                  — converted Sprinter manuals + asm reference samples
  third_party/           — solid-c reference compiler dump + sdcc setup script
  release_docs/          — packaging / release notes

gitignore overhaul:
  • Drop dangerous blanket patterns: *.asm (would hide docs/samples/*.asm)
    and *.exe (case-insensitive match was hiding third_party/solid-c/*.EXE
    on macOS APFS).  Replaced with examples/*/*.{asm,exe,…} and lib/*.lib.
  • Restore tracking of toolchain/mkexe/tests/{one,big}.bin — those are
    INPUT fixtures, not build outputs.
  • Collapse the duplicated SDCC/C/Sdcc sections into one section per
    concern (build outputs / vendored / OS-junk).
  • Add .sprinter-cc-*/, build/ (catches lib/build/ too), .claude/.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-03 16:13:21 +03:00

218 lines
7.8 KiB
NASM
Executable File

intLibrary
assert intLibrary >= #8000
INT_TABLE_HI equ #be
INT_TABLE equ 256 * INT_TABLE_HI
; useLib: keybLibrary, memLibrary
; useRam: INT_TABLE_HI
; export var:
; intMode
; intFlagPlayAyMus
; intFlagPlayAyMusPageAdr
; export fn:
; intLibInit
; intSetGameInterrupt
; intRestoreDefaultInterrupt
; intWaitVsync
; Векторы прерываний:
; клавиатура - #ff
; кадровое - #ff
; CovoxBlaster - #ff (признак — порт #fe.bit7 = 1 и оно висит до захвата прерывания процом)
; CTC - #06 (LSB) (висит до захвата прерывания процом)
; возможно есть и другие - надо изучить
; СТС имеет 4 счётчика.
; идея в том, что:
; - счётчик №2 тактируется по знакоместам (1 тик = 1 знакоместо) с частотой 875 Кгц,
; - счётчик №3 тактируется от №2.
; эти два счётчика всегда работают в связке
; если один счётчик заставить отсчитать 2 пиксельных линии экрана (112 знакомест),
; а другой счётчик отсчитать 160 раз от первого, то получим одно срабатывание на 320 пиксельных линий — это полностью идентично кадровому прерыванию.
; Режимы прерываний
INT_MODE_SYS equ 0
INT_MODE_GAME equ 1
INT_MODE_VSYNC_HOOK equ 2
; Здесь храним текущий режим прерываний
intMode db INT_MODE_SYS
; Инициализация библиотеки
; запоминаем текущее состояние регистра i
; use: af
intLibInit
ld a,i
ld (_intDefaultRegI),a
ret
; Установка прерываний игры
; use: hl,af,i
intSetGameInterrupt
; Перед установкой CTC нам необходимо поймать кадровое прерывание
; (это важно т.к. у нас некоторые циклы работают с одним экраном до прихода луча развертки)
; Просто ei:halt не подойдет т.к. общий вектор для кадрового и клавиатурного прерываний
; и если в данный момент будут нажаты кнопки мы поймаем прерывание от них и окажемся в случайном месте кадра
; Делаем в несколько шагов:
; 1. Отключаем системные прерывания чтобы не мешались
; (т.к. они в том числе обрабатывают прерывания от клавиатуры и читают из неё данные)
; и устанавливаем пустой обработчик прерываний
; также сразу устанавливаем адрес обработки CTC
di
ld hl,_intHandlerCtc
ld (INT_TABLE + #06),hl
ld hl,_intHandlerNull
ld (INT_TABLE + #ff),hl
ld a,INT_TABLE_HI
ld i,a
im 2
ld a,INT_MODE_VSYNC_HOOK
ld (intMode),a
; 2. Далее ждем прерываний - если есть данные от клавиатуры, то это не кадровое
; если одновременно будет и кадровое и клавиатура - пропустим кадровое но тут нам это не страшно (дождемся следующего)
_vSyncHookLoop
ei
halt
di
in a,(COM_A)
bit 0,a ; проверить наличие данных от клавиатуры
jr z,_vSyncHookSuccess ; если нет данных значит поймали кадровое
in a,(DAT_A) ; считать байт
jr _vSyncHookLoop
; 3. Поймали кадровое прерывание
; Настраиваем CTC и устанавливаем прерывания игры
; Почему именно такие значения - надо читать доку по z84c15
_vSyncHookSuccess
ld a,#57 : out (CTC.Ch_2),a
ld a,112 : out (CTC.Ch_2),a
ld a,#d7 : out (CTC.Ch_3),a
ld a,160 : out (CTC.Ch_3),a
ld a,0 : out (CTC.Ch_0),a
ld hl,_intHandlerKeybOrFrame
ld (INT_TABLE + #ff),hl
ld a,INT_MODE_GAME
ld (intMode),a
;-------
; инициализируем CovoxBlaster
jp soundDeviceCovoxBlasterLib.init
; Пустой обработчик прерываний - нужен для определения от кого прерывание (см. intSetGameInterrupt)
; use: -
_intHandlerNull
di
call _intReti
ei: ret
_intReti
ei
reti
; Восстановление прерываний
; (обязательно делать перед использованием функций дос и биос)
; use: af, i
intRestoreDefaultInterrupt
di
ld a,1
out (CTC.Ch_3),a
ld a,INT_MODE_SYS
ld (intMode),a
ld a,#00
_intDefaultRegI equ $-1
ld i,a
im 1
ret
; Обработчик "кадровых" прерываний от CTC
; на выходе нужно именно reti если заменить на ret то прерывание от CTC больше не придет
; use: save & restore all used regs to stack
_intHandlerCtc
di
push hl,de,bc,af
ex af,af
push af
;-
ld a,1
ld (_vsyncFlag),a ; Устанавливаем флаг что пришло кадровое прерывание
;-
in a,(EmmWin.P1)
ld (_intEmmWinP1),a
call soundLib.intHandler
ld a,0
_intEmmWinP1 equ $-1
out (EmmWin.P1),a
;---
pop af
ex af,af
pop af,bc,de,hl
call _intReti
ei: ret
; Обработчик прерываний от клавиатуры и кадровых
; тут делаем только обработку прерываний от клавиатуры
; use: save & restore all used regs to stack
_intHandlerKeybOrFrame
di
push hl,de,bc,af
;---
call keybIntHandler
;di
;---
call soundDeviceCovoxBlasterLib.intHandler
;---
pop af,bc,de,hl
call _intReti
ei: ret
; Ожидаем начало фрейма (прерывание от СТС)
; Для этого сбрасываем (_vsyncFlag), делаем ei:halt и проверяем что дождались (_vsyncFlag)=1 - кадровое
; use: af
intWaitVsync
ld a,(intMode)
cp INT_MODE_SYS
jr z,_intWaitVsyncSys
;-
xor a
ld (_vsyncFlag),a
;-
if DEBUG_BORDER = 1
xor a: out(#fe),a
endif
;-
_intWaitVsyncLoop
ei
halt
;-
ld a,0
_vsyncFlag equ $-1
and a
jr z,_intWaitVsyncLoop
;-
if DEBUG_BORDER = 1
ld a,2: out(#fe),a
endif
;-
ret
; Ожидаем начало фрейма в режиме системных прерываний (ei:halt)
; можем поймать прерывание от клавиатуры вместо кадрового
; Наверное надо бы запретить вызывать intWaitVsync при системных прерываниях, например так:
; if DEBUG_IS_ON = 1
; ld hl,txtErrorIntWaitVsync
; jp debugShowError
; endif
; txtErrorIntWaitVsync db "ERROR: Call IntWaitVsync with system int", #00
_intWaitVsyncSys
call memCacheOffTemporary ;временно выключаем fastRam
ei
halt
jp memCacheRestoryState ;восстанавливаем состояние подключения fastRam