From 3cc7d115e17ca28838af17a2cb275bc2a61d2431 Mon Sep 17 00:00:00 2001 From: Stefan Schramm Date: Fri, 3 Nov 2023 12:47:36 +0100 Subject: [PATCH 1/2] Add support for generic binary format for ZX Spectrum --- MACHINES.md | 11 +++- .../examples/formats/zxspectrum/Makefile | 2 +- .../examples/formats/zxspectrum/rl.bin | Bin 0 -> 147 bytes retroload-lib/src/Examples.ts | 8 +++ retroload-lib/src/common/Utils.ts | 9 +++ .../apple2/Apple2HalfPeriodProcessor.ts | 14 +--- retroload-lib/src/encoding/AdapterProvider.ts | 2 + .../adapter/ZxSpectrumGenericAdapter.ts | 61 ++++++++++++++++++ 8 files changed, 92 insertions(+), 15 deletions(-) create mode 100644 retroload-lib/examples/formats/zxspectrum/rl.bin create mode 100644 retroload-lib/src/encoding/adapter/ZxSpectrumGenericAdapter.ts diff --git a/MACHINES.md b/MACHINES.md index 421c621..a3dbd21 100644 --- a/MACHINES.md +++ b/MACHINES.md @@ -263,12 +263,19 @@ BASIC programs can be loaded and started by LOAD "" RUN -(`J`, `"`, `"`, `ENTER`, ..., `R`, `ENTER`") +(`J`, `"`, `"`, `ENTER`, ..., `R`, `ENTER`) -Machine language programs can be started by +Machine language programs can loaded by LOAD "" CODE + +(`J`, `"`, `"`, `EXTEND MODE`, `I`, `ENTER`) + +...and started by + PRINT USR 32768 +(`P`, `EXTEND MODE`, `L`, `ENTER`) + where `32768` is their entry address. diff --git a/retroload-lib/examples/formats/zxspectrum/Makefile b/retroload-lib/examples/formats/zxspectrum/Makefile index 49b23be..0cb1bf5 100644 --- a/retroload-lib/examples/formats/zxspectrum/Makefile +++ b/retroload-lib/examples/formats/zxspectrum/Makefile @@ -1,6 +1,6 @@ include ../Makefile.inc -all: rl.bas.tap rl.bin.tap rl.bas.tzx rl.bin.tzx +all: rl.bas.tap rl.bin.tap rl.bas.tzx rl.bin.tzx rl.bin # https://github.com/weiju/zxtaputils %.tzx: %.tap diff --git a/retroload-lib/examples/formats/zxspectrum/rl.bin b/retroload-lib/examples/formats/zxspectrum/rl.bin new file mode 100644 index 0000000000000000000000000000000000000000..b16e07f8e8e7377fb5388e28fd4283585d7870b6 GIT binary patch literal 147 zcmZSNZs7XIaN;_%#1CFw{D7A?$TcL$-^bt4MbFvamzUQy!qGRt$5p}2KS&`eLLoT7 o)j1?6)K@{n$ Date: Fri, 3 Nov 2023 17:42:26 +0100 Subject: [PATCH 2/2] Add support for generic BASIC formats for ZX Spectrum --- MACHINES.md | 2 + .../examples/formats/zxspectrum/Makefile | 10 ++- .../formats/zxspectrum/number_array.dat | Bin 0 -> 23 bytes .../examples/formats/zxspectrum/rl.bas | Bin 222 -> 190 bytes .../examples/formats/zxspectrum/rl.txt | 9 +++ retroload-lib/src/Examples.ts | 18 +++++- .../adapter/ZxSpectrumGenericAdapter.ts | 58 +++++++++++++++--- 7 files changed, 85 insertions(+), 12 deletions(-) create mode 100644 retroload-lib/examples/formats/zxspectrum/number_array.dat create mode 100644 retroload-lib/examples/formats/zxspectrum/rl.txt diff --git a/MACHINES.md b/MACHINES.md index a3dbd21..38ea5e6 100644 --- a/MACHINES.md +++ b/MACHINES.md @@ -265,6 +265,8 @@ BASIC programs can be loaded and started by (`J`, `"`, `"`, `ENTER`, ..., `R`, `ENTER`) +Note: Some programs may start automatically after loading. + Machine language programs can loaded by LOAD "" CODE diff --git a/retroload-lib/examples/formats/zxspectrum/Makefile b/retroload-lib/examples/formats/zxspectrum/Makefile index 0cb1bf5..8f17661 100644 --- a/retroload-lib/examples/formats/zxspectrum/Makefile +++ b/retroload-lib/examples/formats/zxspectrum/Makefile @@ -1,15 +1,19 @@ include ../Makefile.inc -all: rl.bas.tap rl.bin.tap rl.bas.tzx rl.bin.tzx rl.bin +all: rl.bas.tap rl.bin.tap rl.bas.tzx rl.bin.tzx rl.bas rl.bin # https://github.com/weiju/zxtaputils %.tzx: %.tap tzxmerge -o $@ $< # https://github.com/weiju/zxtaputils -%.bas.tap: %.bas +%.bas.tap: %.txt bas2tap $< $@ +# https://github.com/weiju/zxtaputils +%.bas: %.txt + bas2tap --format plain $< $@ + # https://github.com/weiju/zxtaputils %.bin.tap: %.bin tapify --objtype code --filename RL --startaddr 32768 $< $@ @@ -24,4 +28,4 @@ all: rl.bas.tap rl.bin.tap rl.bas.tzx rl.bin.tzx rl.bin retroload -o $@ $< clean: - rm -f *.wav *.tap *.tzx *.bin + rm -f *.wav *.tap *.tzx *.bin *.bas diff --git a/retroload-lib/examples/formats/zxspectrum/number_array.dat b/retroload-lib/examples/formats/zxspectrum/number_array.dat new file mode 100644 index 0000000000000000000000000000000000000000..f748420476050baa5535d9440a33da9d18df2e85 GIT binary patch literal 23 XcmZQ%VPIeo2Vw>-5Wx!~R2dim1swo+ literal 0 HcmV?d00001 diff --git a/retroload-lib/examples/formats/zxspectrum/rl.bas b/retroload-lib/examples/formats/zxspectrum/rl.bas index a29d731b9217546afcd036ac3689f1557ae2218a..f73e1c9f811e476386fcaa30d7ff5731f96f80b3 100644 GIT binary patch literal 190 zcmZSJQfBz7q>CRY@iK@oF?{7^kP`$d4ss0%^7rv~bkTG6_XSF6fTfH;=D0>U`Ud#8 zD!BOvDMUpm1P8b}hXjTCDrh)4275Yd0u|eU6}w3Q6@!d$by0Bib5U@OaCHt1adlAy Mst5q9h$6~a04}pA;Q#;t literal 222 zcmaLRJr08~42I#kK85S49YE0XJBGxSkO+xPkRtAX5QNlZ#Pjoha$TX9c?}OL?vLQ} zr|`{ = { + name: 'zxtype', + label: 'File type', + description: 'ZX Spectrum: File type. Known types: 0 = BASIC program, 1 = array of numbers, 2 = array of characters, 3 = binary program (default). Arrays will be assigned the names a() or a$().', + argument: 'type', + required: false, + common: false, + type: 'text', + parse: (v) => v === '' ? typeBinary : parseInt(v, 16), +}; + +const typeProgram = 0; +const typeNumberArray = 1; +const typeCharArray = 2; const typeBinary = 3; /** * https://faqwiki.zxnet.co.uk/wiki/Spectrum_tape_interface - * https://faqwiki.zxnet.co.uk/wiki/TAP_format */ const definition: AdapterDefinition = { @@ -24,6 +35,8 @@ const definition: AdapterDefinition = { options: [ nameOption, + typeOption, + loadOption, ], identify(_filename: string, _ba: BufferAccess) { @@ -32,7 +45,36 @@ const definition: AdapterDefinition = { encode(recorder: RecorderInterface, ba: BufferAccess, options: OptionContainer) { const name = options.getArgument(nameOption); - const type = typeBinary; // TODO: option + const type = options.getArgument(typeOption); + + let param1; + let param2; + switch (type) { + case typeProgram: + // Misusing the loadOption in this case for the autostart parameter (BASIC line number). + param1 = options.getArgument(loadOption) ?? 0x8000; + param2 = ba.length(); + break; + case typeNumberArray: + param1 = 0x8100; // a() + param2 = 0x8000; + break; + case typeCharArray: + param1 = 0xc100; // a$() + param2 = 0x8000; + break; + case typeBinary: + param1 = options.getArgument(loadOption) ?? 0x8000; + param2 = 0x8000; + break; + default: + Logger.info(`Warning: The specified file type ${type} is not known. Known types: 0 (BASIC program), 1 (number array), 2 (string array), 3 (binary data)`); + param1 = 0x8000; + param2 = 0x8000; + break; + } + // The array names a() and a$() stored at the tape doesn't seem to matter. + // The computer uses the name specified on loading (LOAD "" CODE b()). const e = new ZxSpectrumTzxEncoder(recorder); e.begin(); @@ -42,8 +84,8 @@ const definition: AdapterDefinition = { headerBlockBa.writeUint8(type); headerBlockBa.writeAsciiString(name, 10, 0x20); headerBlockBa.writeUint16Le(ba.length()); - headerBlockBa.writeUint16Le(0x8000); // param1 - headerBlockBa.writeUint16Le(0x8000); // param2 + headerBlockBa.writeUint16Le(param1); + headerBlockBa.writeUint16Le(param2); headerBlockBa.writeUint8(calculateChecksum8Xor(headerBlockBa.slice(0, 18))); e.recordStandardSpeedDataBlock(headerBlockBa);