создание SCL с помощью sjasm

  • Автор темы Автор темы Shiny
  • Дата начала Дата начала

Shiny

Легенда
Пользователь
Сообщения
42
Счётчик реакций
12
Очки
275
В связи с встреченными неточностями хотелось бы рассмотреть формат SCL
Описание ZX Modules неточное
Speccy.info

Бинарный файл в .scl
Assembler Z80:
    device zxspectrum128

    macro    sectors datab,datae

 IF low (datae-datab)=0
   db high (datae-datab)
 ELSE
   db (1+high (datae-datab))
 ENDIF

    endm

    org $8000-14*1-9
scl_b:
;заголовок
 db "SINCLAIR"
 db 1; один файл

; файл 1
;    12345678t
 db "girl    C" ;имя файла длиной 8 байт, тип 1 байт
 dw 16384;адрес кодового блока
 dw end-begin;размер
 db (end-begin+255)/256

; данные файлов
begin
 incbin "girl.scr"
end
 align 256 ; выравнивание секторов
scl_e:

    savebin "test.scl",scl_b,scl_e-scl_b; сохранить файл
; подсчет и запись контрольной суммы
    LUA

    local fp
    local checksum
    
    fp = assert(io.open("test.scl", "rb"))
    checksum=0
    while true do
        local byte = fp:read(1)
        if byte==nil then
            break
        end
        checksum=checksum+string.byte(byte)
    end
    assert(fp:close())
    print("writing",string.format("%08X",checksum))
    fp = assert(io.open("test.scl", "a"))

    for i=1,4 do
        fp:write(string.char(checksum%256))
        checksum=math.floor(checksum/256)
    end

--    assert(fp:flush())
    assert(fp:close())
    ENDLUA
строка org $8000-14*1-9 - подготовка заголовка файла - слово "SINCLAIR" 8 байт, следующий байт- количество файлов, для бинарного файла равен 1.
После заголовка SCL следуют заголовки файлов:
db "girl C" ;имя файла длиной 8 байт, тип 1 байт
dw 16384;стартовый адрес кодового блока
dw end-begin;размер файла
db (end-begin+255)/256; количество секторов файла.

После заголовков файлов располагаются данные:
begin
incbin "girl.scr"
end
align 256 ; выравнивание секторов, например файл размером 1 байт займет 256 байт.

Подсчитать контрольную сумму можно с помощью LUA. Здесь используется только имя test.scl

SCL-моноблок
Этот трюк известен старой школе: Сначала подготавливается загрузчик на ассемблере, расположенный в строке 1 REM кодовый блок. строка 2 - вызов программы-загрузки. Вслед за программой добавляются файлы, которые будут загружены. После готового варианта нужно удалить оставшиеся файлы и изменить размер секторов программы на Basic в заголовке. Подобную операцию можно сделать с помощью Perfect Commander, выбрав файлы и нажав клавишу Z, подтвердив объединение, нажав Y.
В примере сделан сборка выдранного crackintro:
Assembler Z80:
    device zxspectrum128

entrya=$100
    org entrya-14*1-9
scl_b:
 db "SINCLAIR"
 db 1; количество файлов
;-файл 1
file1:
;    12345678t
 db "WestBankB"
 dw basic_e-basic_b-4;start
 dw basic_e-basic_b-4;длина
 db (scl_e-basic_b+255)/256

; org entrya
basic_b:
 db #00,#01;номер строки
 DW EndLine1 - Line1
Line1:
 db #EA ; REM
     res 4,(iy+1)
    xor a:out ($FE),a
    ld hl,$5AFF,de,$5AFe,bc,$1B00-1,(hl),0:lddr

    macro trload mema,secs
 ld hl,mema
 ld bc,5+secs*256
 ld de,(#5CF4)
 call $3d13
    endm

    macro pokeb addr,byt
        ld a,byt,(addr),a
    endm

x2:
 di
    ld a,$10,bc,$7FFD:out (c),a

    di
     ld sp,$5fff
     trload $6018,$A0
     call $6018
    pokeb $6241,6
    pokeb $6242,$97
    pokeb $6235,$72
    pokeb $6236,$E3
     jp $61a8
 jr $
;------------------------------
 db #0D
EndLine1:
 db #00,#02
 DW EndLine2 - Line2
Line2:
;border not pi
 db 231,195,167
 db #3A; :
 
 db #20,#FD,#B0,#22,#32,#34,#35,#37,#35,#22;clear val "24575"
 db #3A; :
 db #F9,#C0,#28,#35;randomize usr (5+256*peek val "23635"+peek val "23636"
 db #0E,#00,#00,#05,#00,#00,#2B
 db #32,#35,#36
 db #0E,#00,#00,#00,#01,#00,#2A,#BE

 db #B0
 db #22,#32,#33,#36,#33,#36,#22;"23635"
 db #2B;???
 db #BE
 db #B0
 db #22,#32,#33,#36,#33,#35,#22;"23636"
 db #29,#0D;)
 db #80
 db #AA,1,0;;;;;;;;;;;;;autorun line,change program length to -4, e.g. 83-4=79
EndLine2:
basic_e:

;данные секторов
 align 256; выравнивание BASIC файла по секторам
 incbin "wb1.bin"
 align 256; выравнивание кодового блока по секторам

scl_e: ; сохранение файла и под счет контрольной суммы
    savebin "huj.scl",scl_b,scl_e-scl_b

    LUA

    local fp
    local checksum
-- never rename file
    fp = assert(io.open("huj.scl", "rb"))
    checksum=0
    while true do
        local byte = fp:read(1)
        if byte==nil then
            break
        end
        checksum=checksum+string.byte(byte)
    end
    assert(fp:close())
    print("writing",string.format("%08X",checksum))
    fp = assert(io.open("huj.scl", "a"))

    for i=1,4 do
        fp:write(string.char(checksum%256))
        checksum=math.floor(checksum/256)
    end

    assert(fp:close())
-- имя файла из заголовка
    local ss=""
    for i=0,7,1 do
        ss=ss..string.char( sj.get_byte( sj.get_label("file1")+i ) )
    end

    ss=ss:match "^%s*(.-)%s*$"
--  print(ss)
    os.remove(ss..".scl")
    os.rename("huj.scl", ss..".scl")

    ENDLUA
Здесь в заголовке SCL указан один файл и заголовок будет только для одного файла.
Программа Basic формируется в исходном тексте
Бейсик ZX:
1 REM загрузчик
2 BORDER NOT PI:CLEAR VAL "24575":RANDOMIZE USR (5+256*PEEK VAL "23635"+PEEK VAL "23636")

Вслед за программой добавлен один кодовый блок wb1.bin, оба файла выравниваются по секторам:
align 256; выравнивание BASIC файла по секторам
incbin "wb1.bin"
align 256; выравнивание кодового блока по секторам

Завершение исходного текста - подсчет контрольной суммы и запись в формате SCL

Загрузка кодового блока из Basic
Assembler Z80:
    device zxspectrum128

    macro    sectors datab,datae

 IF low (datae-datab)=0
   db high (datae-datab)
 ELSE
   db (1+high (datae-datab))
 ENDIF

    endm

    org $8000-14*2-9
scl_b:
;header_b:
 db "SINCLAIR"
 db 2;два файла
;-1st
file1:
;    12345678t
 db "sw1k    B"
 dw basic_e-basic_b-4;start
 dw basic_e-basic_b-4;length?
 db (basic_e-basic_b+255)/256; количество секторов BASIC
;    12345678t
;-2nd
 db "sw1k    C"
 dw $8000;start address of code block
 dw end-begin;size of code
 db(end-begin+255)/256; количество секторов кодового блока

;BASIC
 align 256
basic_b:
 db #00,10;номер строки
 DW EndLine1 - Line1
Line1:

 db 231 ; border
 db 195 ; not
 db 167 ; pi
 db ":"
 db 218 ; paper
 db 195 ; not
 db 167 ; pi
 db ":"
 db 217 ; ink
 db 195 ; not
 db 167 ; pi
 db ":"


 db $FD;clear
 db $B0;val
 db $22,"24575",$22,":"
 db $F9;randomize
 db $C0;usr
 db $B0;val
 db $22,"15619",$22,":"
 db $EA;rem
 db ":"
 db $EF;load
 db $22,"sw1k",$22
 db $AF;code
 db #0D
EndLine1:

 db #00,20;номер строки
 DW EndLine2 - Line2
Line2:
 db $F9;randomize
 db $C0;usr
 db $B0;val
 db $22,"25600",$22
 db #0D
EndLine2:

 db #80;for autorun
 db #AA,10,0
basic_e:

 align 256
begin
 incbin "sw1k.code"
end
 align 256
scl_e:

    savebin "test.scl",scl_b,scl_e-scl_b

    LUA

    local fp
    local checksum
    
    fp = assert(io.open("test.scl", "rb"))
    checksum=0
    while true do
        local byte = fp:read(1)
        if byte==nil then
            break
        end
        checksum=checksum+string.byte(byte)
    end
    assert(fp:close())
    print("writing",string.format("%08X",checksum))
    fp = assert(io.open("test.scl", "a"))

    for i=1,4 do
        fp:write(string.char(checksum%256))
        checksum=math.floor(checksum/256)
    end

--    assert(fp:flush())
    assert(fp:close())
--name
    local ss=""
    for i=0,7,1 do
        ss=ss..string.char( sj.get_byte( sj.get_label("file1")+i ) )
    end

    ss=ss:match "^%s*(.-)%s*$"
--  print(ss)
    os.rename("test.scl", ss..".scl")

    ENDLUA
В этом примере в заголовке SCL указано два файла - Basic, который состоит из простой загрузки и кодовый блок, заранее скомпилированный. Последняя процедура изменена - название создаваемого файла берется из заголовков.
 

Вложения

А еще можно в моноблоке все строки сделать 0 и автостарт 0, тогда листинг ломается.

А еще так:

Assembler Z80:
 db #20,#FD,#B0,#22,#32,#34,#35,#37,#35,#22;clear val "24575"
 db #3A; :
 db #F9,#C0,#30;randomize usr 0
 db #0E,#00,#00,64,93,#00,#0D
 db #80
 db #AA,0,0

в листинге выглядит как: RANDOMIZE USR 0 а запускает 23867+5=23872.
 
Кстати, сейчас проверил без checksum, scl открывается во Fuse и Spectaculator без проблем. Видимо все забили на checksum.
 
Насчет контрольной суммыDizzy прав, современные эмуляторы часто её игнорируют.
 
FAR Manager неровно дышит к контрольной сумме(дышал)
 
Как всё сложно. sjasm не зря называют ужасм, но даже он не требует таких ужасов)
  • Смысл тратить время на выгрузку (и потенциальную отладку) SCL из ужасма, если можно выгрузить TRD и добавить в конец вашего Makefile/build.bat директиву для конверсии TRD в SCL через, например, trx2x?
  • Смысл генерировать BASIC врукопашную, если Busy-soft сделал такую вещь как BasicLib, которая входит в sjasmplus, причём в той же директории есть примеры использования?
Проще говоря, делается так:

Assembler Z80:
    define TRD_FILENAME "test.trd"
    define SCR_NAME "sfrog$.C"
    define SCR_SIZE 2348
    
    device zxspectrum48 
    
    ; trd monoloader
     MODULE boot
    INCLUDE BasicLib.asm
    
Basic:
        db #00,#01        ; строка 01
        dw EndLine1 - Line1
Line1:
        db        #EA    ;REM
        DI
        ld        de,(#5CF4)
        ld        bc,#0A05        ; NN05, где NN=0A секторов (картинка)
        ld        hl,#61A8        ; адрес загрузки
        call     #3D13
        xor        a
        out        (#fe),a
        call    #61A8            ; распаковываем в экран
        ret
        
EndLine1:
    LINE : db clear,val,'"24999"',':',rand,usr,val,'"23872"',':',pause,notx,pi : LEND
EndBasic:
    ENDMODULE

    ORG        #61A8    ; 25000
SCREEN
    INCBIN  SCR_NAME,0,SCR_SIZE
end

    emptytrd TRD_FILENAME
    savetrd TRD_FILENAME, |"test.B", boot.Basic, boot.EndBasic - boot.Basic
    savetrd TRD_FILENAME, |SCR_NAME, SCREEN, SCR_SIZE
 

Вложения

  • test.zip
    test.zip
    416.5 КБ · Просмотры: 1
Последний раз редактировалось:
Назад
Вверх