diff --git a/.gitignore b/.gitignore index 173ca5b..98d4dcf 100644 --- a/.gitignore +++ b/.gitignore @@ -23,6 +23,7 @@ SAIMPORT.X SAEXPORT.X SAMAKE SAMAKE.X +SAMAC build.sh compile.sh !build/48/specasm/ @@ -30,6 +31,7 @@ compile.sh !bas/128/*.TAP !bas/*.TAP build/48/specasm/release/ +build/128/specasm/release/ !build/next/specasm/ !build/128/specasm/ build/next/specasm/release/ @@ -40,3 +42,4 @@ build/next/unit/tests/ examples/hello/hello examples/hello/hello.x .DS_Store +.vscode \ No newline at end of file diff --git a/README.md b/README.md index 0bba2b8..60b7b69 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,22 @@ # Specasm -Specasm is a Z80 assembler designed to run on the 48k and 128k ZX Spectrum and the ZX Spectrum Next. It requires an SD card solution running ESXDOS 0.87 or greater to function on the 48Kb and 128Kb ZX Spectrum. For detailed information about how Specasm works, please see the [documentation](https://github.com/markdryan/specasm/blob/master/docs/specasm.md). To get started, carry on reading. +Specasm is a Z80 assembler designed to run on the 48k and 128k ZX Spectrums and the ZX Spectrum Next. It requires an SD card solution running ESXDOS 0.87 or greater to function on the 48Kb and 128Kb ZX Spectrum. For detailed information about how Specasm works, please see the [documentation](https://github.com/markdryan/specasm/blob/master/docs/specasm.md). To get started, carry on reading. ## Getting Started [Download](https://github.com/markdryan/specasm/releases) the latest release of Specasm appropriate for your Spectrum and unzip the contents of the file into the root directory of your SD card. > [!TIP] -> There are three different Zip files available, specasm48.zip for the 48kb, specasm128.zip for the 128kb Spectrum, and specasmnext.zip for the ZX Spectrum Next. You must download the appropriate version for your machine. +> There are two different Zip files available, specasm.zip for the 48kb and 128kb Spectrums, and specasmnext.zip for the ZX Spectrum Next. The specasm.zip file contains separate binaries and install scripts for both the 48kb and 128kb versions. You must download the appropriate version for your machine. -You should now have a folder in your root directory called SPECASM. It should look something like this if you downloaded specasm48.zip +You should now have a folder in your root directory called SPECASM. It should look something like this if you downloaded specasm.zip ![Installing](/docs/install.png) -Now navigate to the INSTALL.BAS file, which is a BASIC program, and press **ENTER** to execute it. On the 48kb or 128kb Spectrum this will use ESXDOS's **.launcher** command to set up some command line short cuts for the tap files in the SPECASM directory. It will also copy some executables to the /bin folder. On the ZX Spectrum Next it will copy the various executable programs that compose Specasm to the /dot folder. +To install Specasm you need to run a short BASIC program. Run INST48.BAS when installing on a 48kb Spectrum, INST128.BAS when installing on a 128kb Spectrum and INSTALL.BAS when running on the Next. Navigate to the appropriate install file and press **ENTER** to execute it. On the 48kb or 128kb Spectrum this will use ESXDOS's **.launcher** command to set up some command line short cuts for the tap files in the SPECASM directory. It will also copy some executables to the /bin folder. On the ZX Spectrum Next it will copy the various executable programs that compose Specasm to the /dot folder. + +> [!TIP] +> Note on previous releases of Specasm, there were separate zip files just for the 48kb and the 128kb Spectrums and users ran a BASIC script called INSTALL.BAS to install Specasm on these machines. From release v11 onwards, the zip files for the 48kb and 128kb Spectrums have been combined and you must run INST48.BAS or INST128.BAS to install the correct version. If you run the wrong install program by mistake just run REMOVE.BAS to uninstall Specasm and then execute the correct installer. ## Reinstalling Specasm diff --git a/asm/sald128/sald128.s b/asm/sald128/sald128.s index 524f1a0..23bbf0b 100644 --- a/asm/sald128/sald128.s +++ b/asm/sald128/sald128.s @@ -8,6 +8,7 @@ dw calib dw bank0 dw bank4 dw bank6 +dw bank3 dw bank1 .calib @@ -32,8 +33,10 @@ dw bank1 align 4 .bank128 db 16,20,22,17 +db 19 .bankPlus2a db 16,17,19,20 +db 22 .bank0 ld c, 0 @@ -44,10 +47,12 @@ db 16,17,19,20 .bank6 ld c, 2 jr switchBank +.bank3 + ld c, 4 + jr switchBank .bank1 ld c, 3 - .switchBank ld a, (=cpuid) cp 126 diff --git a/bas/128/INST128.BAS b/bas/128/INST128.BAS new file mode 100755 index 0000000..6f57f9c Binary files /dev/null and b/bas/128/INST128.BAS differ diff --git a/bas/128/specld.tap b/bas/128/specld.tap index ede33ec..a1a56cc 100644 Binary files a/bas/128/specld.tap and b/bas/128/specld.tap differ diff --git a/bas/48/INSTALL.BAS b/bas/48/INST48.BAS similarity index 100% rename from bas/48/INSTALL.BAS rename to bas/48/INST48.BAS diff --git a/bas/next/MAC.BAS b/bas/next/MAC.BAS new file mode 100755 index 0000000..b8c7356 Binary files /dev/null and b/bas/next/MAC.BAS differ diff --git a/build/128/specasm/Make.include b/build/128/specasm/Make.include index 7d0991e..b8aba84 100644 --- a/build/128/specasm/Make.include +++ b/build/128/specasm/Make.include @@ -58,6 +58,9 @@ editor_buffers.o: editor_buffers.c editor_buffers.h line.h \ error.h scratch.o: scratch.c scratch.h line.h error.h analysis_banked.o: analysis.c state.h state_base.h line_common.h line.h error.h strings.h +doc_banked.o: doc.c doc.h editor.h error.h line.h line_common.h peer.h peer_zx.h scratch.h util_print_zx.h +descra2l_banked.o: descra2l.c descra2l.h +descrm2z_banked.o: descrm2z.c descrm2z.h %.o: %.c zcc $(CFLAGS) -o $@ -c $< diff --git a/build/128/specasm/Makefile b/build/128/specasm/Makefile index 7779962..4fbcc9e 100644 --- a/build/128/specasm/Makefile +++ b/build/128/specasm/Makefile @@ -37,6 +37,15 @@ editor_extra_banked.o: editor_extra.c analysis_banked.o: analysis.c $(CC) $(CFLAGS) -DSPECASM_128_BANKED -o $@ --codesegBANK_6 --constsegBANK_6 --datasegBANK_6 -c $< +doc_banked.o: doc.c + $(CC) $(CFLAGS) -DSPECASM_128_BANKED -o $@ --codesegBANK_3 --constsegBANK_3 --datasegBANK_3 -c $< + +descra2l_banked.o: descra2l.c + $(CC) $(CFLAGS) -DSPECASM_128_BANKED -o $@ --codesegBANK_3 --constsegBANK_3 --datasegBANK_3 -c $< + +descrm2z_banked.o: descrm2z.c + $(CC) $(CFLAGS) -DSPECASM_128_BANKED -o $@ --codesegBANK_3 --constsegBANK_3 --datasegBANK_3 -c $< + clipboard.o: clipboard.c $(CC) $(CFLAGS) -DSPECASM_128_BANKED -o $@ -c $< @@ -67,7 +76,10 @@ SPECASM = \ ld_parse_banked.o \ editor_banked.o \ editor_extra_banked.o \ - analysis_banked.o + analysis_banked.o \ + doc_banked.o \ + descra2l_banked.o \ + descrm2z_banked.o specasm_bare.tap: $(SPECASM) $(CC) $(CFLAGS) -zorg=32768 -m -startup=31 -o $@ $^ -pragma-include:zpragma.inc $(CZFLAGS) @@ -80,8 +92,9 @@ specasm.tap: specasm_bare.tap sald128/sald128 z88dk-appmake +zx -b specasm_bare_BANK_0.bin -o bank0.tap --org 49152 --noloader z88dk-appmake +zx -b specasm_bare_BANK_4.bin -o bank4.tap --org 49152 --noloader z88dk-appmake +zx -b specasm_bare_BANK_6.bin -o bank6.tap --org 49152 --noloader + z88dk-appmake +zx -b specasm_bare_BANK_3.bin -o bank3.tap --org 49152 --noloader z88dk-appmake +zx -b sald128/sald128 -o sald128.tap --org 32768 --noloader - cat ../../../bas/128/specld.tap sald128.tap bank0.tap bank4.tap bank6.tap specasm_bare.tap > specasm.tap + cat ../../../bas/128/specld.tap sald128.tap bank0.tap bank4.tap bank6.tap bank3.tap specasm_bare.tap > sa128.tap clean: - rm -rf specasm *.zip -rf unitzx sald128 @@ -91,12 +104,15 @@ clean: release: - rm -rf release mkdir -p release/specasm - cp specasm.tap release/specasm + cp sa128.tap release/specasm cp ../../48/specasm/salink.tap release/specasm + cp ../../48/specasm/specasm.tap release/specasm + cp ../../48/specasm/SAMAC_CODE.bin release/specasm/SAMAC cp ../../../COPYING release/specasm sed 's/```//g' ../../../docs/specasm.md > release/specasm/specasm.txt cp ../../48/specasm/SAMAKE ../../48/specasm/SAIMPORT ../../48/specasm/SAEXPORT ../../48/specasm/*.X release/specasm - cp ../../../bas/48/INSTALL.BAS release/specasm + cp ../../../bas/128/INST128.BAS release/specasm + cp ../../../bas/48/INST48.BAS release/specasm cp ../../../bas/48/REMOVE.BAS release/specasm ../../../buildlib.sh `realpath release` 128 specasm - cd release && zip -r specasm128.zip specasm + cd release && zip -r specasm.zip specasm diff --git a/build/48/specasm/Make.include b/build/48/specasm/Make.include index f5cadc9..4e93224 100644 --- a/build/48/specasm/Make.include +++ b/build/48/specasm/Make.include @@ -54,6 +54,7 @@ queued_files.o: queued_files.c peer.h error.h peer_zx.h \ editor_buffers.o: editor_buffers.c editor_buffers.h line.h \ error.h scratch.o: scratch.c scratch.h line.h error.h +samac.o: samac.c error.h line.h scratch.h state.h state_base.h strings.h %.o: %.c zcc $(CFLAGS) -o $@ -c $< diff --git a/build/48/specasm/Makefile b/build/48/specasm/Makefile index de7d857..9932aa7 100644 --- a/build/48/specasm/Makefile +++ b/build/48/specasm/Makefile @@ -1,7 +1,7 @@ VPATH=../../../src .PHONY: all -all: specasm.tap salink.tap SAEXPORT SAIMPORT SAMAKE +all: specasm.tap salink.tap SAEXPORT SAIMPORT SAMAKE SAMAC CC=zcc CFLAGS=+zx -SO3 --opt-code-size --max-allocs-per-node200000 -Cs "--disable-warning 85" -clib=sdcc_iy @@ -9,6 +9,9 @@ CFLAGS=+zx -SO3 --opt-code-size --max-allocs-per-node200000 -Cs "--disable-warni util_print_acc_zx.o: util_print_acc_zx.asm $(CC) $(CFLAGS) -o $@ -c $< +samac_cmds.o: samac_cmds.asm + $(CC) $(CFLAGS) -o $@ -c $< + include Make.include SPECASM = \ @@ -75,9 +78,24 @@ SAMAKE =\ peer_file_zx.o \ peer_zx.o +SAMAC = \ + samac.o \ + samac_cmds.o \ + ld_parse.o \ + line_common.o \ + line_dump.o \ + line_dump_common.o \ + line_parse.o \ + line_parse_common.o \ + scratch.o \ + state_base.o \ + state_dump.o \ + state_parse.o \ + peer_zx.o + specasm.tap: $(SPECASM) - $(CC) $(CFLAGS) -zorg=24310 -startup=31 -o specasm-bare $^ -create-app + $(CC) $(CFLAGS) -m -zorg=24310 -startup=31 -o specasm-bare $^ -create-app cat ../../../bas/48/SPECLD.TAP specasm-bare.tap > specasm.tap salink.tap: $(SALINK) @@ -93,19 +111,10 @@ SAIMPORT: $(SAIMPORT) SAMAKE: $(SAMAKE) $(CC) $(CFLAGS) -startup=30 -o $@ $(SAMAKE) -subtype=dotx -Cz"--clean" -create-app +SAMAC: $(SAMAC) + $(CC) $(CFLAGS) -m -zorg=30720 -pragma-output="CLIB_MALLOC_HEAP_SIZE=0" -pragma-output="REGISTER_SP=-1" -startup=31 -o $@ $^ + clean: - rm -rf specasm *.zip -rf unitzx - - rm *.X *.o *.bin *.tap SAIMPORT SAEXPORT SAMAKE - -.PHONY: release -release: - - rm -rf release - mkdir -p release/specasm - cp specasm.tap salink.tap release/specasm - cp ../../../COPYING release/specasm - sed 's/```//g' ../../../docs/specasm.md > release/specasm/specasm.txt - cp SAMAKE SAIMPORT SAEXPORT *.X release/specasm - cp ../../../bas/48/INSTALL.BAS release/specasm - cp ../../../bas/48/REMOVE.BAS release/specasm - ../../../buildlib.sh `realpath release` 48 specasm - cd release && zip -r specasm48.zip specasm + - rm *.X *.o *.bin *.tap SAIMPORT SAEXPORT SAMAKE SAMAC + diff --git a/build/next/specasm/Make.include b/build/next/specasm/Make.include index b0bfaed..f2fb459 100644 --- a/build/next/specasm/Make.include +++ b/build/next/specasm/Make.include @@ -82,6 +82,10 @@ editor_buffers.o: editor_buffers.c editor_buffers.h line.h \ error.h scratch.o: scratch.c scratch.h line.h error.h analysis_banked.o: analysis.c state.h state_base.h line_common.h line.h error.h strings.h +doc_banked.o: doc.h editor.h error.h line.h line_common.h peer.h peer_zx.h scratch.h util_print_zx.h +descra2l_banked.o: descra2l.c descra2l.h +descrm2z_banked.o: descrm2z.c descrm2z.h +samac.o: samac.c error.h line.h scratch.h state.h state_base.h strings.h %.o: %.c zcc $(CFLAGS) -o $@ -c $< diff --git a/build/next/specasm/Makefile b/build/next/specasm/Makefile index 87f8dfc..b93268c 100644 --- a/build/next/specasm/Makefile +++ b/build/next/specasm/Makefile @@ -1,13 +1,16 @@ VPATH=../../../src .PHONY: all -all: SPECASM SALINK SAEXPORT SAIMPORT SAMAKE +all: SPECASM SALINK SAEXPORT SAIMPORT SAMAKE SAMAC CC=zcc CFLAGS=+zxn -SO3 --opt-code-size --max-allocs-per-node200000 -Cs "--disable-warning 85" -clib=sdcc_iy -DSPECASM_TARGET_NEXT -DSPECASM_TARGET_NEXT_OPCODES CZFLAGS=-Cz="--clean --fullsize --main-fence 0xDE00" SACZFLAGS=-Cz="--clean --fullsize --main-fence 0xBFFE" +samac_cmds_next.o: samac_cmds_next.asm + $(CC) $(CFLAGS) -o $@ -c $< + util_print_acc_next.o: util_print_acc_next.asm $(CC) $(CFLAGS) -o $@ -c $< @@ -53,6 +56,15 @@ queued_files_banked.o: queued_files.c link_obj_banked.o: link_obj.c $(CC) $(CFLAGS) -DSPECASM_NEXT_BANKED -o $@ --codesegBANK_45_H --constsegBANK_45_H --datasegBANK_45_H -c $< +doc_banked.o: doc.c + $(CC) $(CFLAGS) -DSPECASM_NEXT_BANKED -o $@ --codesegBANK_47_L --constsegBANK_47_L --datasegBANK_47_L -c $< + +descra2l_banked.o: descra2l.c + $(CC) $(CFLAGS) -DSPECASM_NEXT_BANKED -o $@ --codesegBANK_47_H --constsegBANK_47_H --datasegBANK_47_H -c $< + +descrm2z_banked.o: descrm2z.c + $(CC) $(CFLAGS) -DSPECASM_NEXT_BANKED -o $@ --codesegBANK_48_H --constsegBANK_48_H --datasegBANK_48_H -c $< + clipboard.o: clipboard.c $(CC) $(CFLAGS) -DSPECASM_NEXT_BANKED -o $@ -c $< @@ -80,7 +92,10 @@ SPECASM = \ state_dump_banked.o \ editor_banked.o \ editor_extra_banked.o \ - analysis_banked.o + analysis_banked.o \ + doc_banked.o \ + descra2l_banked.o \ + descrm2z_banked.o SALINK = \ salink.o \ @@ -127,6 +142,23 @@ SAMAKE =\ peer_file_next.o \ peer_next.o +SAMAC = \ + samac.o \ + samac_cmds_next.o \ + ld_parse.o \ + line_common.o \ + line_dump.o \ + line_dump_common.o \ + line_parse.o \ + line_parse_common.o \ + error.o \ + scratch.o \ + state_base.o \ + state_dump.o \ + state_parse.o \ + peer_next.o + + SPECASM: $(SPECASM) $(CC) $(CFLAGS) -m -startup=31 -o $@ $^ -pragma-include:zpragmasa.inc -subtype=dotn $(SACZFLAGS) -create-app @@ -142,9 +174,13 @@ SAIMPORT: $(SAIMPORT) SAMAKE: $(SAMAKE) $(CC) $(CFLAGS) -startup=30 -o $@ $(SAMAKE) -subtype=dotn -Cz"--clean" -create-app +SAMAC: $(SAMAC) + $(CC) $(CFLAGS) -zorg=28736 -pragma-output="CLIB_MALLOC_HEAP_SIZE=0" -pragma-output="REGISTER_SP=-1" -startup=31 -o $@ $^ + + clean: - rm -rf specasm *.zip - - rm *.X *.o *.bin SPECASM SALINK SAIMPORT SAEXPORT SAMAKE + - rm *.X *.o *.bin *.map SPECASM SALINK SAIMPORT SAEXPORT SAMAKE SAMAC SAMAC_CODE.bin .PHONY: release release: @@ -153,7 +189,9 @@ release: cp ../../../COPYING release/specasm sed 's/```//g' ../../../docs/specasm.md > release/specasm/specasm.txt cp SPECASM SALINK SAIMPORT SAEXPORT SAMAKE release/specasm + cp SAMAC_CODE.bin release/specasm/SAMAC cp ../../../bas/next/INSTALL.BAS release/specasm cp ../../../bas/next/REMOVE.BAS release/specasm + cp ../../../bas/next/MAC.BAS release/specasm ../../../buildlib.sh `realpath release` next cd release && zip -r specasmnext.zip specasm diff --git a/docs/install.png b/docs/install.png index 34973fb..2e244cf 100644 Binary files a/docs/install.png and b/docs/install.png differ diff --git a/docs/specasm.md b/docs/specasm.md index d95e490..d43217a 100644 --- a/docs/specasm.md +++ b/docs/specasm.md @@ -78,6 +78,12 @@ The Next and the Spectrum 128 versions of Specasm provide two additional command | t | Displays the number of M cycles and T states the selected code will take to execute. Specasm prints two numbers for each value, a minimum and a maximum. The value is likely to be inaccurate for instructions whose running times depend on runtime state, e.g., LDIR. | | fl | Displays the flags modified by a selected block of code. | +The Next and the Spectrum 128 versions of Specasm provide a help command that describes each of the mnemonics supported by the assembler. A brief description of each mnemonic is provided, along with its various encodings, timings and the flags it affects. The Next version of Specasm includes documentation for the ZXN opcodes, which are identified by the string "zxn" highlighted in red in the top left hand corner of the screen. + +| Command | Description | +|---------|-------------| +| h [mnemonic] | Enters the help system. Takes one optional argument, a mnemonic, which, when given, displays information on that mnemonic. Help for "adc" is shown when the command is used without a argument. Use the arrow keys to navigate inside the help system. Pressing a letter takes you to the first mnemonic that begins with that letter. Pressing any key other than a letter or left and right exits help. | + Finally, the Next and the Spectrum 128 versions of Specasm have a garbage collection command to reclaim unused strings. See the *Limitations* section below for more details. | Command | Description | @@ -764,6 +770,24 @@ The 'p' argument can be omitted if one of the .x files in the current directory On the Spectrum Next, the generate .p file can be run from the browser which will execute it in the built-in ZX81 emulator. +## Jupiter Ace Support + +Specasm itself does run on the Jupiter Ace, but it can be used to cross assemble Ace programs from the Spectrum. The samake shipped with Version v11 and above of Specasm can be used to generate Jupiter Ace tap files. There are two samake sub commands for the Ace. + +- **ace** generates a tap file containing the linked binary of the current project. The tap file can be loaded with `0 0 bload ` and then run with ` call`. +- **autoace** generates a auto-running tap file. The tap file can be loaded and run with a single command; `0 0 bload autorun`. For this to work, the project needs to have an org address of 15451. + +So to create an auto-running tap file for the Ace simply add an `org 15451` statement to your program, link it and type + +``` +CLEAR 32767 +.samake autoace +``` + +> [!TIP] +> Note the CLEAR statement is not needed on the ZX Spectrum Next as .samake is implemented as a dotn file. + + ## Unit Tests Specasm v9 adds basic support for unit testing. Test content is placed in a .t file. .t files are binary files like .x files that can be edited by Specasm but are intended to contain test code only. .t files can be saexported and saimported to and from .ts source files. .t files can be included in the same directory as the .x files that constitute the main program. When salink is run it builds a main binary out of all the .x files in the project. In Specasm v9, if the project contains any .t files, it will also generate a second binary that contains the contents of all the .t and all the .x files in the project. The second binary has the same name as the main binary with a '.tst' extension appended. @@ -980,3 +1004,68 @@ zx81 ... ``` +## Scripting support + +Specasm does not directly support macros. It does support numeric expressions but these are mostly used for constants and for address calculations. It has no facility to programmatically generate assembly language code or data directives directly in its source files. Although Specasm itself doesn't provide a macro language your ZX Spectrum does (Sinclair BASIC). Rather than trying to squeeze a custom macro language into Specasm, versions v11 and above of Specasm allow you to use your Spectrum's native language to programmatically create .x files. So while Specasm doesn't support macros it is scriptable. The way this works differs on the ZX Spectrum and the Spectrum Next. + +### Scripting on the ZX Spectrum + +To create a new Specasm script on the ZX Spectrum, simply use the samake **mac** sub command. This sub command creates a new Specasm BASIC script. If used without arguments the name of that script is mac.bas. If an argument is provided the script file name is derived from the argument. The script contains a single line of code that loads and executes a BASIC extension. Once executed the extension initialises a new .x file in memory and adds four new commands to Sinclair BASIC, each of which begins with a '*'. These are + +- \*asm which accepts one string argument which is expected to be a valid line of Specasm code. The line is assembled and appended to the in memory .x file. +- \*load which accepts one string argument, the path of an .x file, and loads that file into memory, replacing the contents of the previous in memory .x file. +- \*new which accepts no arguments and resets the in memory .x file. +- \*save which accepts one string argument, the path of an .x file, and saves the in memory .x file to the given path. + +For example, to create and load a new Specasm script type + +``` +CLEAR 32767 +.samake mac +LOAD * "mac.bas" +``` + +Then add the following lines and run the program. + +``` +20 *asm ".sinwaveY" +30 FOR n=0 to 255 +40 *asm "db " + STR$(88+INT(80*SIN(n/128*PI))) +50 NEXT n +60 *save "sin.x" +RUN +``` + +You should end up with a .x file that contains the y coordinates of a sine wave, e.g., + +``` +.sinwaveY +db 88 +db 89 +db 91 +db 93 +db 95 +... +``` + +One consequence of the way the extensions work is that line 10 of each Specasm script needs to be executed before you can start entering the new Specasm BASIC commands. This is not an issue the first time you create a script, as the first time you load the script it will only contain one line, line 10, which will be automatically executed. It may however be an issue if you want to re-edit the script at a later stage. If you load or merge the file without executing it, you will not be able to add new Specasm commands. To edit the script you'll need to execute line 10. I usually do this by executing NEW and then merging the file (so it doesn't execute). I then add `15 STOP` to the program to prevent all but the first line from executing, run it and then delete line 15. The Specasm BASIC extension commands can then be freely used. + +### Scripting on the ZX Spectrum Next + +The mechanism used to extend Sinclair BASIC on the ZX Spectrum does not work on the ZX Spectrum Next. It may be possible to use a variation of the same trick to get it to work, but it's not worth the effort. Next BASIC has procedures so we can just use them instead. A macro file can be created in the same way on the Next as on the ZX Spectrum. Simply type + +``` +.samake mac +``` + +This will generate a BASIC program that loads and executes some machine code. The machine code initialises a new .x file in memory and then sets up some entry points that can be used to manipulate the file. These entry points can be acccessed from the BASIC program via 4 pre-supplied procedures; PROCasm, PROCloadx, PROCnewx and PROCsavex. These procedures have the same use as the Sinclair BASIC extensions with similar names described above. For example, to create the sin.x file in Next BASIC, we would add the following code to the generated macro. + +``` +20 PROC asm(".sinwaveY") +30 FOR n=0 to 255 +40 PROC asm("db " + STR$(88+INT(80*SIN(n/128*PI)))) +50 NEXT n +60 PROCsavex("sin.x") +``` + +Unlike the macros on the ZX Spectrum, there's no need to execute a Specasm macro on the Next before editing it. \ No newline at end of file diff --git a/src/descra2l.c b/src/descra2l.c new file mode 100644 index 0000000..1cab786 --- /dev/null +++ b/src/descra2l.c @@ -0,0 +1,278 @@ +/* + * Copyright contributors to Specasm + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "descra2l.h" + +const char specasm_doc_adc[] = + "The second argument and the carry flag are added to the " + "contents of the destination register."; + +const char specasm_doc_add[] = + "The second argument is added to the contents of the " + "destination register."; + +const char specasm_doc_add_16[] = + "The second argument is added to the contents of the " + "destination register. The carry flag is set according " + "to the result of the addition. h represents carry from " + "bit 11."; + +#ifdef SPECASM_TARGET_NEXT_OPCODES +const char specasm_doc_add_rra[] = + "A is added to the destination register. Carry flag undefined."; +const char specasm_doc_add_16imm[] = + "The 16 bit immediate in the second argument is added to the " + "destination register."; +#endif + +const char specasm_doc_align[] = + "The align directive takes one immediate argument that must be " + "a power of 2, >= 2 and <= 256. It inserts null bytes into " + "the binary until the requested alignment is achieved. The " + "number of t-states consumed by an align directive is the " + "number of bytes inserted * 4."; + +const char specasm_doc_and[] = "The result of a bitwise AND of a and the " + "argument is stored in a."; + +const char specasm_doc_bit[] = + "Sets the zero flag to 1 if bit n of the 2nd operand " + "is 0, or to 0 if bit N is 1."; + +#ifdef SPECASM_TARGET_NEXT_OPCODES +const char specasm_doc_brlc[] = + "Rotates de left by the value in the lower nibble of b."; +const char specasm_doc_bsla[] = + "Shifts de left by the value in the bottom 5 bits of b."; +const char specasm_doc_bsra[] = + "Performs an arithmetic right shift of de by the value in the " + "bottom 5 bits of b."; +const char specasm_doc_bsrf[] = + "Shifts de right by the value in the bottom 5 bits of b. " + "The vacated bits are set to 1."; +const char specasm_doc_bsrl[] = + "Performs a logical right shift of de by the value in the " + "bottom 5 bits of b."; +#endif + +const char specasm_doc_call[] = + "Pushes the PC on the stack and jumps to nn. The conditional " + "version of the instruction takes fewer t-states to execute " + "if the call is not taken."; + +const char specasm_doc_ccf[] = "Inverts the carry flag."; + +const char specasm_doc_cp[] = + "The operand is subtracted from a setting the " + "flags accordingly. The result of the subtraction is " + "discarded."; + +const char specasm_doc_cpd[] = + "(hl) is subtracted from a and the flags are set " + "accordingly. The result is discarded. bc and hl are " + "decremented. The p flag is set if bc != 0 after the " + "instruction has finished and is otherwise reset."; + +const char specasm_doc_cpdr[] = + "(hl) is subtracted from a and the flags are set accordingly. " + "The result is discarded. bc and hl are decremented. If bc>0 " + "and the result of the subtraction is != 0 cpdr " + "repeats. The p flag is set if bc!=0 after cpdr has " + "finished and is otherwise reset. The slower timings apply " + "when cpdr repeats."; + +const char specasm_doc_cpi[] = + "(hl) is subtracted from a and the flags are set accordingly. " + "The result is discarded. bc is decremented while hl is " + "incremented. The p flag is set if bc != 0 after the cpi has " + "finished and is otherwise reset."; + +const char specasm_doc_cpir[] = + "(hl) is subtracted from a and the flags are set accordingly. " + "The result is discarded. bc is decremented while hl is " + "incremented. If bc>0 and the result of the subtraction is != 0" + " cpir repeats. The p flag is set if bc!=0 after cpir " + "has finished and is otherwise reset. The slower " + "timings apply when the cpir repeats."; + +const char specasm_doc_cpl[] = "Invert a."; + +const char specasm_doc_daa[] = + "Conditionally adjusts a for BCD addition and subtraction."; + +const char specasm_doc_db[] = + "Stores up to 4 bytes in the program binary. All ns must be " + "formatted in the same way. Only one byte can be specified if " + "an expression is used."; + +const char specasm_doc_dec[] = "The specified operand is decremented by 1."; + +const char specasm_doc_di[] = "Disables maskable interrupts."; + +const char specasm_doc_djnz[] = + "b is decremented by 1. If the result is>0 the cpu jumps to " + "PC+2+n, where n is a signed 8 byte. djnz executes " + "more quickly when the jump it not taken."; + +const char specasm_doc_ds[] = "Stores c copies of the byte n in the binary."; + +const char specasm_doc_dw[] = + "Stores up to 2 words in the program binary. All nns must be " + "formatted in the same way. Only one word can be specified if " + "an expression is used."; + +const char specasm_doc_ei[] = "Enables maskable interrupts."; + +const char specasm_doc_ex[] = + "The contents of the two operands are exchanged. " + "ex af, af' affects all the flags while the other forms of the " + "instruction have no effect on the flags."; + +const char specasm_doc_exx[] = "Exchange bc, de and hl with bc', de', hl'."; + +const char specasm_doc_halt[] = + "CPU execution is suspended until the next interrupt or reset."; + +const char specasm_doc_im[] = + "Sets the interrupt mode. With im 2 the MSB of the vector " + "address is taken from the i register."; + +const char specasm_doc_in[] = + "Reads a byte from the device identified by bc and stores it in r."; + +const char specasm_doc_in2[] = + "Reads a byte from the device adddress whose MSB is " + "taken from a and whose LSB is n. The byte is " + "stored in a."; + +const char specasm_doc_inc[] = "The specified operand is incremented by 1."; + +const char specasm_doc_ind[] = + "A byte is read from the device identified by bc and stored " + "in (hl). b and hl are decremented."; + +const char specasm_doc_indr[] = + "A byte is read from the device identified by bc and stored " + "(hl). b and hl are decremented. If bc!=0 indr " + "repeats. indr consumes more t-states when it " + "repeats."; + +const char specasm_doc_ini[] = + "A byte is read from the device identified by bc " + "and stored in (hl). b is decremented and h is incremented."; + +const char specasm_doc_inir[] = + "A byte is read from the device identified by bc " + "and stored in (hl). b is decremented and h is incremented. " + "If bc!=0 inir repeats. inir consumes more t-states when it " + "repeats."; + +const char specasm_doc_jp[] = + "Jump to the last operand if the condition is met or no " + "condition is supplied. Instruction consumes fewer t-states " + "if condition is not met."; + +#ifdef SPECASM_TARGET_NEXT_OPCODES +const char specasm_doc_jp_c[] = + "Jumps to address formed from the address of the next instruction " + "and data read from an io port. Bit 14 and 15 are taken " + "from the PC of the next instruction. Bits 0-5 are 0. Bits " + "6-13 come from an implicit in (c)."; +#endif + +const char specasm_doc_jr[] = + "Jump to PC+2+n if the condition is met or no condition is " + "supplied. Range of jump is -126 + 129 bytes. Instruction " + "consumes fewer t-states if condition is not met."; + +const char specasm_doc_ld1[] = + "Loads register pair from an immediate value or from an " + "absolute address."; + +const char specasm_doc_ld2[] = + "Loads sp with the value of another 16 bit register pair."; + +const char specasm_doc_ld3[] = + "Loads byte register an immediate value or another register."; + +const char specasm_doc_ld4[] = + "Stores a byte register to the memory location provided " + "by the first operand."; + +const char specasm_doc_ld5[] = + "Loads a 16 bit value from a register into an absolute " + "address."; + +const char specasm_doc_ld6[] = + "Stores an 8 bit immediate to the memory location provided " + "by the first operand."; + +const char specasm_doc_ld7[] = + "Indirectly loads a byte into register using the pointer given " + "in the second operator."; + +const char specasm_doc_ld8[] = + "Instructions to load and store the interrupt vector and " + "memory refresh registers to and from a."; + +const char specasm_doc_ldd[] = + "Load (hl) into (de). hl, de and bc are decremented."; + +#ifdef SPECASM_TARGET_NEXT_OPCODES +const char specasm_doc_lddrx[] = + "Load (hl) into (de) if (hl)!=a. hl and bc are decremented while " + "de is incremented. If bc!=0 lddrx repeats. lddrx consumes more " + "t-states when it repeats."; +const char specasm_doc_lddx[] = + "Load (hl) into (de) if (hl)!=a. de is incremented. bc and " + "hl are decremented."; +#endif + +const char specasm_doc_lddr[] = + "Load (hl) into (de). hl, de and bc are decremented. If " + "bc!=0 lddr repeats. lddr consumes more t-states when it " + "repeats."; + +const char specasm_doc_ldi[] = + "Load (hl) into (de). Both hl and de are incremented while bc " + "is decremented."; + +const char specasm_doc_ldir[] = + "Load (hl) into (de). Both hl and de are incremented while bc " + "is decremented. If bc!=0 ldir repeats. ldir " + "consumes more t-states when it repeats."; + +#ifdef SPECASM_TARGET_NEXT_OPCODES +const char specasm_doc_ldirx[] = + "Load (hl) into (de) if (hl)!=a. hl and de are incremented while " + "bc is decremented. If bc!=0 ldirx repeats. ldirx consumes more " + "t-states when it repeats."; + +const char specasm_doc_ldix[] = + "Load (hl) into (de) if (hl)!=a. Both hl and de " + "are incremented while bc is decremented."; + +const char specasm_doc_ldpirx[] = + "Load the byte whose address is formed from the top 13 bits of hl " + "and bottom 3 bits of de into (de) if the byte != a. de is incremented " + "while bc is decremented. If bc!=0 ldpirx repeats. ldpirx consumes more " + "t-states when it repeats."; + +const char specasm_doc_ldws[] = + "Load (hl) into (de) and increment l and d. The v flag is set " + "if d was $7f before incremented."; + +#endif \ No newline at end of file diff --git a/src/descra2l.h b/src/descra2l.h new file mode 100644 index 0000000..9ec01ff --- /dev/null +++ b/src/descra2l.h @@ -0,0 +1,99 @@ +/* + * Copyright contributors to Specasm + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef DESCRA2L_H +#define DESCRA2L_H + +extern const char specasm_doc_adc[]; +extern const char specasm_doc_add[]; +extern const char specasm_doc_add_16[]; +#ifdef SPECASM_TARGET_NEXT_OPCODES +extern const char specasm_doc_add_rra[]; +extern const char specasm_doc_add_16imm[]; +#endif +extern const char specasm_doc_align[]; +extern const char specasm_doc_and[]; +extern const char specasm_doc_bit[]; + +#ifdef SPECASM_TARGET_NEXT_OPCODES +extern const char specasm_doc_brlc[]; +extern const char specasm_doc_bsla[]; +extern const char specasm_doc_bsra[]; +extern const char specasm_doc_bsrf[]; +extern const char specasm_doc_bsrl[]; +#endif + +extern const char specasm_doc_call[]; +extern const char specasm_doc_ccf[]; +extern const char specasm_doc_cp[]; +extern const char specasm_doc_cpd[]; +extern const char specasm_doc_cpdr[]; +extern const char specasm_doc_cpi[]; +extern const char specasm_doc_cpir[]; +extern const char specasm_doc_cpl[]; +extern const char specasm_doc_daa[]; +extern const char specasm_doc_db[]; +extern const char specasm_doc_dec[]; +extern const char specasm_doc_di[]; +extern const char specasm_doc_djnz[]; +extern const char specasm_doc_ds[]; +extern const char specasm_doc_dw[]; +extern const char specasm_doc_ei[]; +extern const char specasm_doc_ex[]; +extern const char specasm_doc_exx[]; +extern const char specasm_doc_halt[]; +extern const char specasm_doc_im[]; +extern const char specasm_doc_in[]; +extern const char specasm_doc_in2[]; +extern const char specasm_doc_inc[]; +extern const char specasm_doc_ind[]; +extern const char specasm_doc_indr[]; +extern const char specasm_doc_ini[]; +extern const char specasm_doc_inir[]; +extern const char specasm_doc_jp[]; + +#ifdef SPECASM_TARGET_NEXT_OPCODES +extern const char specasm_doc_jp_c[]; +#endif + +extern const char specasm_doc_jr[]; +extern const char specasm_doc_ld1[]; +extern const char specasm_doc_ld2[]; +extern const char specasm_doc_ld3[]; +extern const char specasm_doc_ld4[]; +extern const char specasm_doc_ld5[]; +extern const char specasm_doc_ld6[]; +extern const char specasm_doc_ld7[]; +extern const char specasm_doc_ld8[]; +extern const char specasm_doc_ldd[]; +extern const char specasm_doc_lddr[]; + +#ifdef SPECASM_TARGET_NEXT_OPCODES +extern const char specasm_doc_lddrx[]; +extern const char specasm_doc_lddx[]; +#endif + +extern const char specasm_doc_ldi[]; +extern const char specasm_doc_ldir[]; + +#ifdef SPECASM_TARGET_NEXT_OPCODES +extern const char specasm_doc_ldirx[]; +extern const char specasm_doc_ldix[]; +extern const char specasm_doc_ldpirx[]; +extern const char specasm_doc_ldws[]; +#endif + +#endif \ No newline at end of file diff --git a/src/descrm2z.c b/src/descrm2z.c new file mode 100644 index 0000000..baca1a6 --- /dev/null +++ b/src/descrm2z.c @@ -0,0 +1,179 @@ +/* + * Copyright contributors to Specasm + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "descrm2z.h" + +const char specasm_doc_map[] = "Instructs the linker to generate a map file."; + +#ifdef SPECASM_TARGET_NEXT_OPCODES +const char specasm_doc_mirror[] = "Reverses the order of the bits in a."; +const char specasm_doc_mul[] = "Let de = d * e."; +#endif + +const char specasm_doc_neg[] = "Let a = 0 - a."; + +#ifdef SPECASM_TARGET_NEXT_OPCODES +const char specasm_doc_nextreg[] = + "Stores the 2nd operand in the Next register identified by the first " + "operand."; +#endif + +const char specasm_doc_nop[] = "CPU does nothing for 1 m-cycle."; +const char specasm_doc_or[] = + "The result of a bitwise OR of a and the argument is stored " + "in a."; +const char specasm_doc_org[] = + "Assembler directive that sets the org address of the program, " + "i.e., the address the first byte in the .x or .t file that " + "contains the Main label is assembled at."; +const char specasm_doc_out1[] = + "Writes the register r to the device identified by bc."; +const char specasm_doc_out2[] = + "Writes a to the device at the adddress whose MSB " + "is taken from the a and whose LSB is n."; +const char specasm_doc_outd[] = + "b is decremented. (hl) is written to the device identified " + "by bc, where b has already been decremented. hl is " + "decremented."; +const char specasm_doc_outdr[] = + "b is decremented. (hl) is written to the device identified " + "by bc, where b has already been decremented. hl is " + "decremented. outdr repeats if b!=0. It consumes more t-states " + "when it repeats."; +const char specasm_doc_outi[] = + "b is decremented. (hl) is written to the device identified by " + "bc, where b has already been decremented. hl is incremented."; + +#ifdef SPECASM_TARGET_NEXT_OPCODES +const char specasm_doc_outinb[] = + "(hl) is written to the device identified by bc. hl is incremented."; +#endif + +const char specasm_doc_outir[] = + "b is decremented. (hl) is written to the device identified by " + "bc, where b has already been decremented. hl is incremented. " + "outir repeats if b!=0. It consumes more t-states " + "when it repeats."; + +#ifdef SPECASM_TARGET_NEXT_OPCODES +const char specasm_doc_pixelad[] = + "Stores in hl the address of the byte in the Spectrum's display file " + "that contains the pixel addressed by the x and y coordinates in " + "the e and d registers, respectively."; +const char specasm_doc_pixeldn[] = + "On entry hl should point to the start of an 8 bit pixel block in the " + "Spectrum's display file. On exit hl points to the same pixel block " + "one line down."; +#endif + +const char specasm_doc_pop[] = "Pops 2 bytes off the stack into the operand."; +const char specasm_doc_push[] = "Pushes the operand onto the stack."; + +#ifdef SPECASM_TARGET_NEXT_OPCODES +const char specasm_doc_push_imm[] = + "Pushes a 16 bit immediate onto the stack. The immediate is big endian " + "encoded."; +#endif + +const char specasm_doc_res[] = "Resets bit n in the second operand."; +const char specasm_doc_ret[] = + "If there is no condition or the condition is met, a word " + "is popped off the stack into the PC, from which program " + "execution continues. ret takes fewer cycles if the condition " + "is not met."; +const char specasm_doc_reti[] = + "Return from interrupt. A word is popped off the stack into PC." + " An ei must be executed prior to the reti to renable " + "maskable interrupts."; +const char specasm_doc_retn[] = + "Return from NMI. A word is popped off the stack into PC and " + "the maskable interrupts are re-enabled if they were enabled " + "before the NMI."; +const char specasm_doc_rl[] = + "The operand is shifted left by 1 bit. The carry flag " + "is moved into bit 0 of the operand and the old bit 7 of " + "the operand is moved into the carry flag."; +const char specasm_doc_rla[] = + "a is rotated left 1 bit. The carry flag is moved to bit 0 of " + "a and its old bit 7 is moved to the carry flag."; +const char specasm_doc_rlc[] = + "The operand is rotated left 1 bit. The old bit 7 is moved to " + "both the carry flag and bit 0 of the operand."; +const char specasm_doc_rlca[] = + "a is rotated left 1 bit. The old bit 7 is moved " + "to both the carry flag and bit 0 of a."; +const char specasm_doc_rld[] = "Let tmp = (hl) >> 4 " + "Let (hl) = ((hl) << 4)|(a & $f) " + "Let a = (a & $f0)|tmp"; +const char specasm_doc_rr[] = + "The operand is shifted right by 1 bit. The carry flag " + "is moved into bit 7 of the operand and the old bit 0 of " + "the operand is moved into the carry flag."; +const char specasm_doc_rra[] = + "a is shifted right 1 bit. The carry flag is " + "moved into bit 7 of a and the old contents of a's " + "bit 0 are moved into the carry flag."; +const char specasm_doc_rrc[] = + "The operand is rotated right by 1 bit. Its old bit 0 is " + "moved into both the carry flag and bit 7 of the operand."; +const char specasm_doc_rrca[] = + "a is rotated right by 1 bit. a's old bit 0 is " + "moved into both the carry flag and bit 7 of a."; +const char specasm_doc_rrd[] = "Let tmp = a << 4 " + "Let a = (a & $f0)|((hl) & $f) " + "Let (hl) = tmp | ((hl) >> 4)"; +const char specasm_doc_rst[] = + "The PC is pushed to the stack and the CPU jumps to the " + "address n. Valid values of n are 0, 8, 16, 24, 32, 40, 48," + " and 56."; +const char specasm_doc_sbc[] = + "The second argument and the carry flag are subtracted from " + "the contents of the destination register, either a or hl."; +const char specasm_doc_scf[] = "Sets the carry flag."; +const char specasm_doc_set[] = "Sets bit n in the second operand."; + +#ifdef SPECASM_TARGET_NEXT_OPCODES +const char specasm_doc_setae[] = + "Let a = $80 >> (e & 7). " + "Used to set a bit corresponding to a pixel in the Spectrum's display " + "file, where the x coordinate of the pixel is in e."; +#endif + +const char specasm_doc_sla[] = + "The operand is shifted left by 1 bit. Bit 0 " + "is set to 0. Bit 7 is moved into the carry flag."; +const char specasm_doc_sra[] = + "The operand is arithmetically shifted right by 1 bit. Bit 7 " + "remains unchanged. Bit 0 is moved into the carry flag."; +const char specasm_doc_srl[] = + "The operand is logically shifted right by 1 bit. Bit 7 is " + "set to 0. Bit 0 is moved into the carry flag."; +const char specasm_doc_sub[] = "The operand is subracted from a."; + +#ifdef SPECASM_TARGET_NEXT_OPCODES +const char specasm_doc_swapnib[] = "Swaps the nibbles in a."; +const char specasm_doc_test[] = + "ANDs the immediate operand with a, sets the flags and discards " + "the result."; +#endif + +const char specasm_doc_xor[] = + "The result of a bitwise XOR of a and the argument is stored " + "in a."; +const char specasm_doc_zx81[] = + "Linker directive that causes string and character literals to " + "be transliterated from ASCII to ZX81 encoding. It also sets " + "org address to 16514."; diff --git a/src/descrm2z.h b/src/descrm2z.h new file mode 100644 index 0000000..8b5683d --- /dev/null +++ b/src/descrm2z.h @@ -0,0 +1,96 @@ +/* + * Copyright contributors to Specasm + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef DESCRM2Z_H +#define DESCRM2Z_H + +extern const char specasm_doc_map[]; + +#ifdef SPECASM_TARGET_NEXT_OPCODES +extern const char specasm_doc_mirror[]; +extern const char specasm_doc_mul[]; +#endif + +extern const char specasm_doc_neg[]; + +#ifdef SPECASM_TARGET_NEXT_OPCODES +extern const char specasm_doc_nextreg[]; +#endif + +extern const char specasm_doc_nop[]; +extern const char specasm_doc_or[]; +extern const char specasm_doc_org[]; +extern const char specasm_doc_out1[]; +extern const char specasm_doc_out2[]; +extern const char specasm_doc_outi[]; + +#ifdef SPECASM_TARGET_NEXT_OPCODES +extern const char specasm_doc_outinb[]; +#endif + +extern const char specasm_doc_outir[]; +extern const char specasm_doc_outd[]; +extern const char specasm_doc_outdr[]; + +#ifdef SPECASM_TARGET_NEXT_OPCODES +extern const char specasm_doc_pixelad[]; +extern const char specasm_doc_pixeldn[]; +#endif + +extern const char specasm_doc_pop[]; +extern const char specasm_doc_push[]; + +#ifdef SPECASM_TARGET_NEXT_OPCODES +extern const char specasm_doc_push_imm[]; +#endif + +extern const char specasm_doc_res[]; +extern const char specasm_doc_ret[]; +extern const char specasm_doc_reti[]; +extern const char specasm_doc_retn[]; +extern const char specasm_doc_rl[]; +extern const char specasm_doc_rla[]; +extern const char specasm_doc_rlc[]; +extern const char specasm_doc_rlca[]; +extern const char specasm_doc_rld[]; +extern const char specasm_doc_rr[]; +extern const char specasm_doc_rra[]; +extern const char specasm_doc_rrc[]; +extern const char specasm_doc_rrca[]; +extern const char specasm_doc_rrd[]; +extern const char specasm_doc_rst[]; +extern const char specasm_doc_sbc[]; +extern const char specasm_doc_scf[]; +extern const char specasm_doc_set[]; + +#ifdef SPECASM_TARGET_NEXT_OPCODES +extern const char specasm_doc_setae[]; +#endif + +extern const char specasm_doc_sla[]; +extern const char specasm_doc_sra[]; +extern const char specasm_doc_srl[]; +extern const char specasm_doc_sub[]; + +#ifdef SPECASM_TARGET_NEXT_OPCODES +extern const char specasm_doc_swapnib[]; +extern const char specasm_doc_test[]; +#endif + +extern const char specasm_doc_xor[]; +extern const char specasm_doc_zx81[]; + +#endif \ No newline at end of file diff --git a/src/doc.c b/src/doc.c new file mode 100644 index 0000000..a1652a3 --- /dev/null +++ b/src/doc.c @@ -0,0 +1,2773 @@ +/* + * Copyright contributors to Specasm + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include "descra2l.h" +#include "descrm2z.h" +#include "doc.h" +#include "editor.h" +#include "line_common.h" +#include "peer.h" +#include "scratch.h" + +#include + +#ifdef SPECASM_NEXT_BANKED +void specasm_descr_bank(const char *ins_name); +#endif + +#define SPECASM_DOC_ENCODING_X 16 +#define SPECASM_DOC_M_CYCLES_X 27 +#define SPECASM_DOC_T_STATES_X 30 + +struct specasm_ins_form_t_ { + const char *form; + const char *encoding; + uint8_t m_cycles; + uint8_t t_states; +}; + +typedef struct specasm_ins_form_t_ specasm_ins_form_t; + +/* clang-format off */ + +#define SPECASM_DOC_ADC_FORMS 0 +#define SPECASM_DOC_ADC_NUM_FORMS 6 +#define SPECASM_DOC_ADD1_FORMS \ + (SPECASM_DOC_ADC_FORMS + SPECASM_DOC_ADC_NUM_FORMS) +#define SPECASM_DOC_ADD1_NUM_FORMS 5 +#define SPECASM_DOC_ADD2_FORMS \ + (SPECASM_DOC_ADD1_FORMS + SPECASM_DOC_ADD1_NUM_FORMS) +#define SPECASM_DOC_ADD2_NUM_FORMS 1 +#define SPECASM_DOC_ADD3_FORMS \ + (SPECASM_DOC_ADD2_FORMS + SPECASM_DOC_ADD2_NUM_FORMS) +#define SPECASM_DOC_ADD3_NUM_FORMS 1 +#define SPECASM_DOC_ADD4_FORMS \ + (SPECASM_DOC_ADD3_FORMS + SPECASM_DOC_ADD3_NUM_FORMS) +#define SPECASM_DOC_ADD4_NUM_FORMS 1 + +#ifdef SPECASM_TARGET_NEXT_OPCODES +#define SPECASM_DOC_ADD5_FORMS \ + (SPECASM_DOC_ADD4_FORMS + SPECASM_DOC_ADD4_NUM_FORMS) +#define SPECASM_DOC_ADD5_NUM_FORMS 1 +#define SPECASM_DOC_ADD6_FORMS \ + (SPECASM_DOC_ADD5_FORMS + SPECASM_DOC_ADD5_NUM_FORMS) +#define SPECASM_DOC_ADD6_NUM_FORMS 1 +#define SPECASM_DOC_ALIGN_FORMS \ + (SPECASM_DOC_ADD6_FORMS + SPECASM_DOC_ADD6_NUM_FORMS) +#else +#define SPECASM_DOC_ALIGN_FORMS \ + (SPECASM_DOC_ADD4_FORMS + SPECASM_DOC_ADD4_NUM_FORMS) +#endif + +#define SPECASM_DOC_ALIGN_NUM_FORMS 1 +#define SPECASM_DOC_AND_FORMS \ + (SPECASM_DOC_ALIGN_FORMS + SPECASM_DOC_ALIGN_NUM_FORMS) +#define SPECASM_DOC_AND_NUM_FORMS 5 +#define SPECASM_DOC_BIT_FORMS \ + (SPECASM_DOC_AND_FORMS + SPECASM_DOC_AND_NUM_FORMS) +#define SPECASM_DOC_BIT_NUM_FORMS 4 + +#ifdef SPECASM_TARGET_NEXT_OPCODES +#define SPECASM_DOC_BRLC_FORMS \ + (SPECASM_DOC_BIT_FORMS + SPECASM_DOC_BIT_NUM_FORMS) +#define SPECASM_DOC_BRLC_NUM_FORMS 1 +#define SPECASM_DOC_BSLA_FORMS \ + (SPECASM_DOC_BRLC_FORMS + SPECASM_DOC_BRLC_NUM_FORMS) +#define SPECASM_DOC_BSLA_NUM_FORMS 1 +#define SPECASM_DOC_BSRA_FORMS \ + (SPECASM_DOC_BSLA_FORMS + SPECASM_DOC_BSLA_NUM_FORMS) +#define SPECASM_DOC_BSRA_NUM_FORMS 1 +#define SPECASM_DOC_BSRF_FORMS \ + (SPECASM_DOC_BSRA_FORMS + SPECASM_DOC_BSRA_NUM_FORMS) +#define SPECASM_DOC_BSRF_NUM_FORMS 1 +#define SPECASM_DOC_BSRL_FORMS \ + (SPECASM_DOC_BSRF_FORMS + SPECASM_DOC_BSRF_NUM_FORMS) +#define SPECASM_DOC_BSRL_NUM_FORMS 1 +#define SPECASM_DOC_CALL_FORMS \ + (SPECASM_DOC_BSRL_FORMS + SPECASM_DOC_BSRL_NUM_FORMS) +#else +#define SPECASM_DOC_CALL_FORMS \ + (SPECASM_DOC_BIT_FORMS + SPECASM_DOC_BIT_NUM_FORMS) +#endif + +#define SPECASM_DOC_CALL_NUM_FORMS 3 +#define SPECASM_DOC_CCF_FORMS \ + (SPECASM_DOC_CALL_FORMS + SPECASM_DOC_CALL_NUM_FORMS) +#define SPECASM_DOC_CCF_NUM_FORMS 1 +#define SPECASM_DOC_CP_FORMS \ + (SPECASM_DOC_CCF_FORMS + SPECASM_DOC_CCF_NUM_FORMS) +#define SPECASM_DOC_CP_NUM_FORMS 5 +#define SPECASM_DOC_CPD_FORMS \ + (SPECASM_DOC_CP_FORMS + SPECASM_DOC_CP_NUM_FORMS) +#define SPECASM_DOC_CPD_NUM_FORMS 1 +#define SPECASM_DOC_CPDR_FORMS \ + (SPECASM_DOC_CPD_FORMS + SPECASM_DOC_CPD_NUM_FORMS) +#define SPECASM_DOC_CPDR_NUM_FORMS 2 +#define SPECASM_DOC_CPI_FORMS \ + (SPECASM_DOC_CPDR_FORMS + SPECASM_DOC_CPDR_NUM_FORMS) +#define SPECASM_DOC_CPI_NUM_FORMS 1 +#define SPECASM_DOC_CPIR_FORMS \ + (SPECASM_DOC_CPI_FORMS + SPECASM_DOC_CPI_NUM_FORMS) +#define SPECASM_DOC_CPIR_NUM_FORMS 2 +#define SPECASM_DOC_CPL_FORMS \ + (SPECASM_DOC_CPIR_FORMS + SPECASM_DOC_CPIR_NUM_FORMS) +#define SPECASM_DOC_CPL_NUM_FORMS 1 +#define SPECASM_DOC_DAA_FORMS \ + (SPECASM_DOC_CPL_FORMS + SPECASM_DOC_CPL_NUM_FORMS) +#define SPECASM_DOC_DAA_NUM_FORMS 1 +#define SPECASM_DOC_DB_FORMS \ + (SPECASM_DOC_DAA_FORMS + SPECASM_DOC_DAA_NUM_FORMS) +#define SPECASM_DOC_DB_NUM_FORMS 4 +#define SPECASM_DOC_DEC1_FORMS \ + (SPECASM_DOC_DB_FORMS + SPECASM_DOC_DB_NUM_FORMS) +#define SPECASM_DOC_DEC1_NUM_FORMS 4 +#define SPECASM_DOC_DEC2_FORMS \ + (SPECASM_DOC_DEC1_FORMS + SPECASM_DOC_DEC1_NUM_FORMS) +#define SPECASM_DOC_DEC2_NUM_FORMS 3 +#define SPECASM_DOC_DI_FORMS \ + (SPECASM_DOC_DEC2_FORMS + SPECASM_DOC_DEC2_NUM_FORMS) +#define SPECASM_DOC_DI_NUM_FORMS 1 +#define SPECASM_DOC_DJNZ_FORMS \ + (SPECASM_DOC_DI_FORMS + SPECASM_DOC_DI_NUM_FORMS) +#define SPECASM_DOC_DJNZ_NUM_FORMS 2 +#define SPECASM_DOC_DS_FORMS \ + (SPECASM_DOC_DJNZ_FORMS + SPECASM_DOC_DJNZ_NUM_FORMS) +#define SPECASM_DOC_DS_NUM_FORMS 1 +#define SPECASM_DOC_DW_FORMS \ + (SPECASM_DOC_DS_FORMS + SPECASM_DOC_DS_NUM_FORMS) +#define SPECASM_DOC_DW_NUM_FORMS 2 +#define SPECASM_DOC_EI_FORMS \ + (SPECASM_DOC_DW_FORMS + SPECASM_DOC_DW_NUM_FORMS) +#define SPECASM_DOC_EI_NUM_FORMS 1 +#define SPECASM_DOC_EX_FORMS \ + (SPECASM_DOC_EI_FORMS + SPECASM_DOC_EI_NUM_FORMS) +#define SPECASM_DOC_EX_NUM_FORMS 5 +#define SPECASM_DOC_EXX_FORMS \ + (SPECASM_DOC_EX_FORMS + SPECASM_DOC_EX_NUM_FORMS) +#define SPECASM_DOC_EXX_NUM_FORMS 1 +#define SPECASM_DOC_HALT_FORMS \ + (SPECASM_DOC_EXX_FORMS + SPECASM_DOC_EXX_NUM_FORMS) +#define SPECASM_DOC_HALT_NUM_FORMS 1 +#define SPECASM_DOC_IM_FORMS \ + (SPECASM_DOC_HALT_FORMS + SPECASM_DOC_HALT_NUM_FORMS) +#define SPECASM_DOC_IM_NUM_FORMS 3 +#define SPECASM_DOC_IN1_FORMS \ + (SPECASM_DOC_IM_FORMS + SPECASM_DOC_IM_NUM_FORMS) +#define SPECASM_DOC_IN1_NUM_FORMS 1 +#define SPECASM_DOC_IN2_FORMS \ + (SPECASM_DOC_IN1_FORMS + SPECASM_DOC_IN1_NUM_FORMS) +#define SPECASM_DOC_IN2_NUM_FORMS 1 +#define SPECASM_DOC_INC1_FORMS \ + (SPECASM_DOC_IN2_FORMS + SPECASM_DOC_IN2_NUM_FORMS) +#define SPECASM_DOC_INC1_NUM_FORMS 4 +#define SPECASM_DOC_INC2_FORMS \ + (SPECASM_DOC_INC1_FORMS + SPECASM_DOC_INC1_NUM_FORMS) +#define SPECASM_DOC_INC2_NUM_FORMS 3 +#define SPECASM_DOC_IND_FORMS \ + (SPECASM_DOC_INC2_FORMS + SPECASM_DOC_INC2_NUM_FORMS) +#define SPECASM_DOC_IND_NUM_FORMS 1 +#define SPECASM_DOC_INDR_FORMS \ + (SPECASM_DOC_IND_FORMS + SPECASM_DOC_IND_NUM_FORMS) +#define SPECASM_DOC_INDR_NUM_FORMS 2 +#define SPECASM_DOC_INI_FORMS \ + (SPECASM_DOC_INDR_FORMS + SPECASM_DOC_INDR_NUM_FORMS) +#define SPECASM_DOC_INI_NUM_FORMS 1 +#define SPECASM_DOC_INIR_FORMS \ + (SPECASM_DOC_INI_FORMS + SPECASM_DOC_INI_NUM_FORMS) +#define SPECASM_DOC_INIR_NUM_FORMS 2 +#define SPECASM_DOC_JP_FORMS \ + (SPECASM_DOC_INIR_FORMS + SPECASM_DOC_INIR_NUM_FORMS) +#define SPECASM_DOC_JP_NUM_FORMS 6 + +#ifdef SPECASM_TARGET_NEXT_OPCODES +#define SPECASM_DOC_JP_C_FORMS \ + (SPECASM_DOC_JP_FORMS + SPECASM_DOC_JP_NUM_FORMS) +#define SPECASM_DOC_JP_C_NUM_FORMS 1 +#define SPECASM_DOC_JR_FORMS \ + (SPECASM_DOC_JP_C_FORMS + SPECASM_DOC_JP_C_NUM_FORMS) +#else +#define SPECASM_DOC_JR_FORMS \ + (SPECASM_DOC_JP_FORMS + SPECASM_DOC_JP_NUM_FORMS) +#endif + +#define SPECASM_DOC_JR_NUM_FORMS 3 +#define SPECASM_DOC_LD1_FORMS \ + (SPECASM_DOC_JR_FORMS + SPECASM_DOC_JR_NUM_FORMS) +#define SPECASM_DOC_LD1_NUM_FORMS 7 +#define SPECASM_DOC_LD2_FORMS \ + (SPECASM_DOC_LD1_FORMS + SPECASM_DOC_LD1_NUM_FORMS) +#define SPECASM_DOC_LD2_NUM_FORMS 3 +#define SPECASM_DOC_LD3_FORMS \ + (SPECASM_DOC_LD2_FORMS + SPECASM_DOC_LD2_NUM_FORMS) +#define SPECASM_DOC_LD3_NUM_FORMS 2 +#define SPECASM_DOC_LD4_FORMS \ + (SPECASM_DOC_LD3_FORMS + SPECASM_DOC_LD3_NUM_FORMS) +#define SPECASM_DOC_LD4_NUM_FORMS 6 +#define SPECASM_DOC_LD5_FORMS \ + (SPECASM_DOC_LD4_FORMS + SPECASM_DOC_LD4_NUM_FORMS) +#define SPECASM_DOC_LD5_NUM_FORMS 4 +#define SPECASM_DOC_LD6_FORMS \ + (SPECASM_DOC_LD5_FORMS + SPECASM_DOC_LD5_NUM_FORMS) +#define SPECASM_DOC_LD6_NUM_FORMS 3 +#define SPECASM_DOC_LD7_FORMS \ + (SPECASM_DOC_LD6_FORMS + SPECASM_DOC_LD6_NUM_FORMS) +#define SPECASM_DOC_LD7_NUM_FORMS 5 +#define SPECASM_DOC_LD8_FORMS \ + (SPECASM_DOC_LD7_FORMS + SPECASM_DOC_LD7_NUM_FORMS) +#define SPECASM_DOC_LD8_NUM_FORMS 4 +#define SPECASM_DOC_LDD_FORMS \ + (SPECASM_DOC_LD8_FORMS + SPECASM_DOC_LD8_NUM_FORMS) +#define SPECASM_DOC_LDD_NUM_FORMS 1 +#define SPECASM_DOC_LDDR_FORMS \ + (SPECASM_DOC_LDD_FORMS + SPECASM_DOC_LDD_NUM_FORMS) +#define SPECASM_DOC_LDDR_NUM_FORMS 2 + +#ifdef SPECASM_TARGET_NEXT_OPCODES +#define SPECASM_DOC_LDDRX_FORMS \ + (SPECASM_DOC_LDDR_FORMS + SPECASM_DOC_LDDR_NUM_FORMS) +#define SPECASM_DOC_LDDRX_NUM_FORMS 2 +#define SPECASM_DOC_LDDX_FORMS \ + (SPECASM_DOC_LDDRX_FORMS + SPECASM_DOC_LDDRX_NUM_FORMS) +#define SPECASM_DOC_LDDX_NUM_FORMS 1 +#define SPECASM_DOC_LDI_FORMS \ + (SPECASM_DOC_LDDX_FORMS + SPECASM_DOC_LDDX_NUM_FORMS) +#else +#define SPECASM_DOC_LDI_FORMS \ + (SPECASM_DOC_LDDR_FORMS + SPECASM_DOC_LDDR_NUM_FORMS) +#endif + +#define SPECASM_DOC_LDI_NUM_FORMS 1 +#define SPECASM_DOC_LDIR_FORMS \ + (SPECASM_DOC_LDI_FORMS + SPECASM_DOC_LDI_NUM_FORMS) +#define SPECASM_DOC_LDIR_NUM_FORMS 2 + +#ifdef SPECASM_TARGET_NEXT_OPCODES +#define SPECASM_DOC_LDIRX_FORMS \ + (SPECASM_DOC_LDIR_FORMS + SPECASM_DOC_LDIR_NUM_FORMS) +#define SPECASM_DOC_LDIRX_NUM_FORMS 2 +#define SPECASM_DOC_LDIX_FORMS \ + (SPECASM_DOC_LDIRX_FORMS + SPECASM_DOC_LDIRX_NUM_FORMS) +#define SPECASM_DOC_LDIX_NUM_FORMS 1 +#define SPECASM_DOC_LDPIRX_FORMS \ + (SPECASM_DOC_LDIX_FORMS + SPECASM_DOC_LDIX_NUM_FORMS) +#define SPECASM_DOC_LDPIRX_NUM_FORMS 2 +#define SPECASM_DOC_LDWS_FORMS \ + (SPECASM_DOC_LDPIRX_FORMS + SPECASM_DOC_LDPIRX_NUM_FORMS) +#define SPECASM_DOC_LDWS_NUM_FORMS 1 +#define SPECASM_DOC_MAP_FORMS \ + (SPECASM_DOC_LDWS_FORMS + SPECASM_DOC_LDWS_NUM_FORMS) +#define SPECASM_DOC_MAP_NUM_FORMS 1 +#define SPECASM_DOC_MIRROR_FORMS \ + (SPECASM_DOC_MAP_FORMS + SPECASM_DOC_MAP_NUM_FORMS) +#define SPECASM_DOC_MIRROR_NUM_FORMS 1 +#define SPECASM_DOC_MUL_FORMS \ + (SPECASM_DOC_MIRROR_FORMS + SPECASM_DOC_MIRROR_NUM_FORMS) +#define SPECASM_DOC_MUL_NUM_FORMS 1 +#define SPECASM_DOC_NEG_FORMS \ + (SPECASM_DOC_MUL_FORMS + SPECASM_DOC_MUL_NUM_FORMS) +#define SPECASM_DOC_NEG_NUM_FORMS 1 +#define SPECASM_DOC_NEXTREG_FORMS \ + (SPECASM_DOC_NEG_FORMS + SPECASM_DOC_NEG_NUM_FORMS) +#define SPECASM_DOC_NEXTREG_NUM_FORMS 2 +#define SPECASM_DOC_NOP_FORMS \ + (SPECASM_DOC_NEXTREG_FORMS + SPECASM_DOC_NEXTREG_NUM_FORMS) +#else +#define SPECASM_DOC_MAP_FORMS \ + (SPECASM_DOC_LDIR_FORMS + SPECASM_DOC_LDIR_NUM_FORMS) +#define SPECASM_DOC_MAP_NUM_FORMS 1 +#define SPECASM_DOC_NEG_FORMS \ + (SPECASM_DOC_MAP_FORMS + SPECASM_DOC_MAP_NUM_FORMS) +#define SPECASM_DOC_NEG_NUM_FORMS 1 +#define SPECASM_DOC_NOP_FORMS \ + (SPECASM_DOC_NEG_FORMS + SPECASM_DOC_NEG_NUM_FORMS) +#endif + +#define SPECASM_DOC_NOP_NUM_FORMS 1 +#define SPECASM_DOC_OR_FORMS \ + (SPECASM_DOC_NOP_FORMS + SPECASM_DOC_NOP_NUM_FORMS) +#define SPECASM_DOC_OR_NUM_FORMS 5 +#define SPECASM_DOC_ORG_FORMS \ + (SPECASM_DOC_OR_FORMS + SPECASM_DOC_OR_NUM_FORMS) +#define SPECASM_DOC_ORG_NUM_FORMS 1 +#define SPECASM_DOC_OUT1_FORMS \ + (SPECASM_DOC_ORG_FORMS + SPECASM_DOC_ORG_NUM_FORMS) +#define SPECASM_DOC_OUT1_NUM_FORMS 1 +#define SPECASM_DOC_OUT2_FORMS \ + (SPECASM_DOC_OUT1_FORMS + SPECASM_DOC_OUT1_NUM_FORMS) +#define SPECASM_DOC_OUT2_NUM_FORMS 1 +#define SPECASM_DOC_OUTD_FORMS \ + (SPECASM_DOC_OUT2_FORMS + SPECASM_DOC_OUT2_NUM_FORMS) +#define SPECASM_DOC_OUTD_NUM_FORMS 1 +#define SPECASM_DOC_OUTDR_FORMS \ + (SPECASM_DOC_OUTD_FORMS + SPECASM_DOC_OUTD_NUM_FORMS) +#define SPECASM_DOC_OUTDR_NUM_FORMS 2 +#define SPECASM_DOC_OUTI_FORMS \ + (SPECASM_DOC_OUTDR_FORMS + SPECASM_DOC_OUTDR_NUM_FORMS) +#define SPECASM_DOC_OUTI_NUM_FORMS 1 + +#ifdef SPECASM_TARGET_NEXT_OPCODES +#define SPECASM_DOC_OUTINB_FORMS \ + (SPECASM_DOC_OUTI_FORMS + SPECASM_DOC_OUTI_NUM_FORMS) +#define SPECASM_DOC_OUTINB_NUM_FORMS 1 +#define SPECASM_DOC_OUTIR_FORMS \ + (SPECASM_DOC_OUTINB_FORMS + SPECASM_DOC_OUTINB_NUM_FORMS) +#define SPECASM_DOC_OUTIR_NUM_FORMS 2 + +#define SPECASM_DOC_PIXELAD_FORMS \ + (SPECASM_DOC_OUTIR_FORMS + SPECASM_DOC_OUTIR_NUM_FORMS) +#define SPECASM_DOC_PIXELAD_NUM_FORMS 1 +#define SPECASM_DOC_PIXELDN_FORMS \ + (SPECASM_DOC_PIXELAD_FORMS + SPECASM_DOC_PIXELAD_NUM_FORMS) +#define SPECASM_DOC_PIXELDN_NUM_FORMS 1 +#define SPECASM_DOC_POP_FORMS \ + (SPECASM_DOC_PIXELDN_FORMS + SPECASM_DOC_PIXELDN_NUM_FORMS) +#else +#define SPECASM_DOC_OUTIR_FORMS \ + (SPECASM_DOC_OUTI_FORMS + SPECASM_DOC_OUTI_NUM_FORMS) +#define SPECASM_DOC_OUTIR_NUM_FORMS 2 +#define SPECASM_DOC_POP_FORMS \ + (SPECASM_DOC_OUTIR_FORMS + SPECASM_DOC_OUTIR_NUM_FORMS) +#endif + +#define SPECASM_DOC_POP_NUM_FORMS 3 +#define SPECASM_DOC_PUSH_FORMS \ + (SPECASM_DOC_POP_FORMS + SPECASM_DOC_POP_NUM_FORMS) +#define SPECASM_DOC_PUSH_NUM_FORMS 3 + +#ifdef SPECASM_TARGET_NEXT_OPCODES +#define SPECASM_DOC_PUSH_IMM_FORMS \ + (SPECASM_DOC_PUSH_FORMS + SPECASM_DOC_PUSH_NUM_FORMS) +#define SPECASM_DOC_PUSH_IMM_NUM_FORMS 1 +#define SPECASM_DOC_RES_FORMS \ + (SPECASM_DOC_PUSH_IMM_FORMS + SPECASM_DOC_PUSH_IMM_NUM_FORMS) +#else +#define SPECASM_DOC_RES_FORMS \ + (SPECASM_DOC_PUSH_FORMS + SPECASM_DOC_PUSH_NUM_FORMS) +#endif +#define SPECASM_DOC_RES_NUM_FORMS 4 +#define SPECASM_DOC_RET_FORMS \ + (SPECASM_DOC_RES_FORMS + SPECASM_DOC_RES_NUM_FORMS) +#define SPECASM_DOC_RET_NUM_FORMS 3 +#define SPECASM_DOC_RETI_FORMS \ + (SPECASM_DOC_RET_FORMS + SPECASM_DOC_RET_NUM_FORMS) +#define SPECASM_DOC_RETI_NUM_FORMS 1 +#define SPECASM_DOC_RETN_FORMS \ + (SPECASM_DOC_RETI_FORMS + SPECASM_DOC_RETI_NUM_FORMS) +#define SPECASM_DOC_RETN_NUM_FORMS 1 +#define SPECASM_DOC_RL_FORMS \ + (SPECASM_DOC_RETN_FORMS + SPECASM_DOC_RETN_NUM_FORMS) +#define SPECASM_DOC_RL_NUM_FORMS 4 +#define SPECASM_DOC_RLA_FORMS \ + (SPECASM_DOC_RL_FORMS + SPECASM_DOC_RL_NUM_FORMS) +#define SPECASM_DOC_RLA_NUM_FORMS 1 +#define SPECASM_DOC_RLC_FORMS \ + (SPECASM_DOC_RLA_FORMS + SPECASM_DOC_RLA_NUM_FORMS) +#define SPECASM_DOC_RLC_NUM_FORMS 4 +#define SPECASM_DOC_RLCA_FORMS \ + (SPECASM_DOC_RLC_FORMS + SPECASM_DOC_RLC_NUM_FORMS) +#define SPECASM_DOC_RLCA_NUM_FORMS 1 +#define SPECASM_DOC_RLD_FORMS \ + (SPECASM_DOC_RLCA_FORMS + SPECASM_DOC_RLCA_NUM_FORMS) +#define SPECASM_DOC_RLD_NUM_FORMS 1 +#define SPECASM_DOC_RR_FORMS \ + (SPECASM_DOC_RLD_FORMS + SPECASM_DOC_RLD_NUM_FORMS) +#define SPECASM_DOC_RR_NUM_FORMS 4 +#define SPECASM_DOC_RRA_FORMS \ + (SPECASM_DOC_RR_FORMS + SPECASM_DOC_RR_NUM_FORMS) +#define SPECASM_DOC_RRA_NUM_FORMS 1 +#define SPECASM_DOC_RRC_FORMS \ + (SPECASM_DOC_RRA_FORMS + SPECASM_DOC_RRA_NUM_FORMS) +#define SPECASM_DOC_RRC_NUM_FORMS 4 +#define SPECASM_DOC_RRCA_FORMS \ + (SPECASM_DOC_RRC_FORMS + SPECASM_DOC_RRC_NUM_FORMS) +#define SPECASM_DOC_RRCA_NUM_FORMS 1 +#define SPECASM_DOC_RRD_FORMS \ + (SPECASM_DOC_RRCA_FORMS + SPECASM_DOC_RRCA_NUM_FORMS) +#define SPECASM_DOC_RRD_NUM_FORMS 1 +#define SPECASM_DOC_RST_FORMS \ + (SPECASM_DOC_RRD_FORMS + SPECASM_DOC_RRD_NUM_FORMS) +#define SPECASM_DOC_RST_NUM_FORMS 1 +#define SPECASM_DOC_SBC_FORMS \ + (SPECASM_DOC_RST_FORMS + SPECASM_DOC_RST_NUM_FORMS) +#define SPECASM_DOC_SBC_NUM_FORMS 6 +#define SPECASM_DOC_SCF_FORMS \ + (SPECASM_DOC_SBC_FORMS + SPECASM_DOC_SBC_NUM_FORMS) +#define SPECASM_DOC_SCF_NUM_FORMS 1 +#define SPECASM_DOC_SET_FORMS \ + (SPECASM_DOC_SCF_FORMS + SPECASM_DOC_SCF_NUM_FORMS) +#define SPECASM_DOC_SET_NUM_FORMS 4 + +#ifdef SPECASM_TARGET_NEXT_OPCODES +#define SPECASM_DOC_SETAE_FORMS \ + (SPECASM_DOC_SET_FORMS + SPECASM_DOC_SET_NUM_FORMS) +#define SPECASM_DOC_SETAE_NUM_FORMS 1 +#define SPECASM_DOC_SLA_FORMS \ + (SPECASM_DOC_SETAE_FORMS + SPECASM_DOC_SETAE_NUM_FORMS) +#else +#define SPECASM_DOC_SLA_FORMS \ + (SPECASM_DOC_SET_FORMS + SPECASM_DOC_SET_NUM_FORMS) +#endif + +#define SPECASM_DOC_SLA_NUM_FORMS 4 +#define SPECASM_DOC_SRA_FORMS \ + (SPECASM_DOC_SLA_FORMS + SPECASM_DOC_SLA_NUM_FORMS) +#define SPECASM_DOC_SRA_NUM_FORMS 4 +#define SPECASM_DOC_SRL_FORMS \ + (SPECASM_DOC_SRA_FORMS + SPECASM_DOC_SRA_NUM_FORMS) +#define SPECASM_DOC_SRL_NUM_FORMS 4 +#define SPECASM_DOC_SUB_FORMS \ + (SPECASM_DOC_SRL_FORMS + SPECASM_DOC_SRL_NUM_FORMS) +#define SPECASM_DOC_SUB_NUM_FORMS 5 + +#ifdef SPECASM_TARGET_NEXT_OPCODES +#define SPECASM_DOC_SWAPNIB_FORMS \ + (SPECASM_DOC_SUB_FORMS + SPECASM_DOC_SUB_NUM_FORMS) +#define SPECASM_DOC_SWAPNIB_NUM_FORMS 1 +#define SPECASM_DOC_TEST_FORMS \ + (SPECASM_DOC_SWAPNIB_FORMS + SPECASM_DOC_SWAPNIB_NUM_FORMS) +#define SPECASM_DOC_TEST_NUM_FORMS 1 +#define SPECASM_DOC_XOR_FORMS \ + (SPECASM_DOC_TEST_FORMS + SPECASM_DOC_TEST_NUM_FORMS) +#else +#define SPECASM_DOC_XOR_FORMS \ + (SPECASM_DOC_SUB_FORMS + SPECASM_DOC_SUB_NUM_FORMS) + +#endif +#define SPECASM_DOC_XOR_NUM_FORMS 5 + +static const specasm_ins_form_t specasm_forms[] = { + /* SPECASM_DOC_ADC_FORMS */ + {"a,r", "88+r", 1, 4}, + {"a,n", "CE n", 2, 7}, + {"a,(hl)", "8E", 2, 7}, + {"a,(ix+d)", "DD 8E d", 5, 19 }, + {"a,(iy+d)", "FD 8E d", 5, 19 }, + {"hl,rr", "ED 4A+rr", 4, 15 }, + + /* SPECASM_DOC_ADD1_FORMS */ + {"a,r", "80+r", 1, 4}, + {"a,n", "C6 n", 2, 7}, + {"a,(hl)", "86", 2, 7}, + {"a,(ix+d)", "DD 86 d", 5, 19 }, + {"a,(iy+d)", "FD 86 d", 5, 19 }, + + /* SPECASM_DOC_ADD2_FORMS */ + {"hl,rr", "9+rr", 3, 11 }, + + /* SPECASM_DOC_ADD3_FORMS */ + {"ix,rr", "DD 9+rr", 4, 15 }, + + /* SPECASM_DOC_ADD4_FORMS */ + {"iy,rr", "FD 9+rr", 4, 15 }, + +#ifdef SPECASM_TARGET_NEXT_OPCODES + /* SPECASM_DOC_ADD5_FORMS */ + {"rr,a", "ED 30+rr", 2, 8 }, + + /* SPECASM_DOC_ADD6_FORMS */ + {"rr,nn", "ED 34+nn", 4, 16 }, +#endif + /* SPECASM_DOC_ALIGN_FORMS */ + {"n", "0", 1, 4 }, + + /* SPECASM_DOC_AND_FORMS */ + {"r", "A0+r", 1, 4}, + {"n", "E6 n", 2, 7}, + {"(hl)", "A6", 2, 7}, + {"(ix+d)", "DD A6 d", 5, 19 }, + {"(iy+d)", "FD A6 d", 5, 19 }, + + /* SPECASM_DOC_BIT_FORMS */ + {"n,r", "CB 40+n+r", 2, 8}, + {"n,(hl)", "CB 46+n", 3, 12}, + {"n,(ix+d)", "DDCBd46+n", 5, 20}, + {"n,(iy+d)", "FDCBd46+n", 5, 20}, + +#ifdef SPECASM_TARGET_NEXT_OPCODES + /* SPECASM_DOC_BRLC_FORMS */ + {"de,b", "ED 2C", 2, 8}, + + /* SPECASM_DOC_BSLA_FORMS */ + {"de,b", "ED 28", 2, 8}, + + /* SPECASM_DOC_BSRA_FORMS */ + {"de,b", "ED 29", 2, 8}, + + /* SPECASM_DOC_BSRF_FORMS */ + {"de,b", "ED 2B", 2, 8}, + + /* SPECASM_DOC_BSRL_FORMS */ + {"de,b", "ED 2A", 2, 8}, +#endif + /* SPECASM_DOC_CALL_FORMS */ + {"nn", "CD n n", 5, 17}, + {"cc,nn", "C4+cc n n", 5, 17}, + {"cc,nn", "C4+cc n n", 3, 10}, + + /* SPECASM_DOC_CCF_FORMS */ + {"", "3F", 1, 4}, + + /* SPECASM_DOC_CP_FORMS */ + {"r", "B8+r", 1, 4}, + {"n", "FE n", 2, 7}, + {"(hl)", "BE", 2, 7}, + {"(ix+d)", "DD BE d", 5, 19 }, + {"(iy+d)", "FD BE d", 5, 19 }, + + /* SPECASM_DOC_CPD_FORMS */ + {"", "ED A9", 4, 16}, + + /* SPECASM_DOC_CPDR_FORMS */ + {"", "ED B9", 4, 16}, + {"", "ED B9", 5, 21}, + + /* SPECASM_DOC_CPI_FORMS */ + {"", "ED A1", 4, 16}, + + /* SPECASM_DOC_CPIR_FORMS */ + {"", "ED B1", 4, 16}, + {"", "ED B1", 5, 21}, + + /* SPECASM_DOC_CPL_FORMS */ + {"", "2F", 1, 4}, + + /* SPECASM_DOC_DAA_FORMS */ + {"", "27", 1, 4}, + + /* SPECASM_DOC_DB_FORMS */ + {"n", "n", 0, 0}, + {"n,n", "n n", 0, 0}, + {"n,n,n", "n n n", 0, 0}, + {"n,n,n,n", "n n n n", 0, 0}, + + /* SPECASM_DOC_DEC1_FORMS */ + {"r", "5+r", 1, 4}, + {"(hl)", "35", 3, 11}, + {"(ix+d)", "DD 35 d", 6, 23 }, + {"(iy+d)", "FD 35 d", 6, 23 }, + + /* SPECASM_DOC_DEC2_FORMS */ + {"rr", "B+rr", 1, 6}, + {"ix", "DD 2B", 2, 10 }, + {"iy", "FD 2B", 2, 10 }, + + /* SPECASM_DOC_DI_FORMS */ + {"", "F3", 1, 4}, + + /* SPECASM_DOC_DJNZ_FORMS */ + {"n", "10 n", 2, 8}, + {"n", "10 n", 3, 13}, + + /* SPECASM_DOC_DS_FORMS */ + {"c n", "n c times", 0, 0}, + + /* SPECASM_DOC_DW_FORMS */ + {"nn", "nn", 0, 0}, + {"nn,nn", "nn nn", 0, 0}, + + /* SPECASM_DOC_EI_FORMS */ + {"", "FB", 1, 4}, + + /* SPECASM_DOC_EX_FORMS */ + {"af, af'", "08", 1, 4}, + {"de, hl", "EB", 1, 4}, + {"sp, (hl)", "E3", 5, 19}, + {"(sp), ix", "DD E3", 6, 23}, + {"(sp), iy", "FD E3", 6, 23}, + + /* SPECASM_DOC_EXX_FORMS */ + {"", "D9", 1, 4}, + + /* SPECASM_DOC_HALT_FORMS */ + {"", "76", 1, 4}, + + /* SPECASM_DOC_IM_FORMS */ + {"0", "ED 46", 2, 8}, + {"1", "ED 56", 2, 8}, + {"2", "ED 5E", 2, 8}, + + /* SPECASM_DOC_IN1_FORMS */ + {"r, (c)", "ED 40+r", 3, 12}, + + /* SPECASM_DOC_IN2_FORMS */ + {"a, (n)", "DB n", 3, 11}, + + /* SPECASM_DOC_INC1_FORMS */ + {"r", "4+r", 1, 4}, + {"(hl)", "34", 3, 11}, + {"(ix+d)", "DD 34 d", 6, 23 }, + {"(iy+d)", "FD 34 d", 6, 23 }, + + /* SPECASM_DOC_INC2_FORMS */ + {"rr", "3+rr", 1, 6}, + {"ix", "DD 23", 2, 10 }, + {"iy", "FD 23", 2, 10 }, + + /* SPECASM_DOC_IND_FORMS */ + {"", "ED AA", 4, 16}, + + /* SPECASM_DOC_INDR_FORMS */ + {"", "ED BA", 4, 16}, + {"", "ED BA", 5, 21}, + + /* SPECASM_DOC_INI_FORMS */ + {"", "ED A2", 4, 16}, + + /* SPECASM_DOC_INIR_FORMS */ + {"", "ED B2", 4, 16}, + {"", "ED B2", 5, 21}, + + /* SPECASM_DOC_JP_FORMS */ + {"nn", "C3 n n", 3, 10}, + {"(hl)", "E9", 1, 4}, + {"(ix)", "DD E9", 2, 8}, + {"(iy)", "FD E9", 2, 8}, + {"cc,nn", "C2+cc n n", 3, 12}, + {"cc,nn", "C2+cc n n", 2, 7}, + +#ifdef SPECASM_TARGET_NEXT_OPCODES + /* SPECASM_DOC_JP_C_FORMS */ + {"(c)", "ED 98", 3, 13}, +#endif + + /* SPECASM_DOC_JR_FORMS */ + {"n", "18 n", 3, 12}, + {"cc,n", "40+cc n", 3, 12}, + {"cc,n", "40+cc n", 2, 7}, + + /* SPECASM_DOC_LD1_FORMS */ + {"rr,nn", "1+rr n n", 3, 10}, + {"ix,nn", "DD 21 n n", 4, 14}, + {"iy,nn", "FD 21 n n", 4, 14}, + {"hl,(nn)","2A n n", 5, 16}, + {"rr,(nn)", "ED 4A+rr", 6, 20}, + {"ix,(nn)", "DD 2A n n", 6, 20}, + {"iy,(nn)", "FD 2A n n", 6, 20}, + + /* SPECASM_DOC_LD2_FORMS */ + {"sp,hl", "F9", 1, 6}, + {"sp,ix", "DD F9", 2, 10}, + {"sp,iy", "FD F9", 2, 10}, + + /* SPECASM_DOC_LD3_FORMS */ + {"r,n", "6+r n", 2, 7}, + {"r,r'", "40+r+(r'/8)", 1, 4}, + + /* SPECASM_DOC_LD4_FORMS */ + {"(bc),a", "02", 2, 7}, + {"(de),a", "12", 2, 7}, + {"(hl),r", "70+r", 2, 7}, + {"(ix+d),r", "DD 70+r d", 5, 19}, + {"(iy+d),r", "FD 70+r d", 5, 19}, + {"(nn),a", "32 n n", 4, 13}, + + /* SPECASM_DOC_LD5_FORMS */ + {"(nn), hl", "22 nn", 5, 16}, + {"(nn), rr", "ED 43+rr nn", 6, 20}, + {"(nn), ix", "DD 22 nn", 6, 20}, + {"(nn), iy", "FD 22 nn", 6, 20}, + + /* SPECASM_DOC_LD6_FORMS */ + {"(hl),n", "36 n", 3, 10}, + {"(ix+d),n", "DD 36 d n", 5, 19}, + {"(iy+d),n", "FD 36 d n", 5, 19}, + + /* SPECASM_DOC_LD7_FORMS */ + {"r,(hl)", "46+r", 2, 7}, + {"a,(bc)", "0A", 2, 7}, + {"a,(de)", "1A", 2, 7}, + {"r,(ix+d)","DD 46 d", 5, 19}, + {"r,(iy+d)","FD 46 d", 5, 19}, + + /* SPECASM_DOC_LD8_FORMS */ + {"a,i", "ED 57", 2, 9}, + {"a,r", "ED 5F", 2, 9}, + {"i,a", "ED 47", 2, 9}, + {"r,a", "ED 4F", 2, 9}, + + /* SPECASM_DOC_LDD_FORMS */ + {"", "ED A8", 4, 16}, + + /* SPECASM_DOC_LDDR_FORMS */ + {"", "ED B8", 4, 16}, + {"", "ED B8", 5, 21}, + +#ifdef SPECASM_TARGET_NEXT_OPCODES + /* SPECASM_DOC_LDDRX_FORMS */ + {"", "ED BC", 4, 16}, + {"", "ED BC", 5, 21}, + + /* SPECASM_DOC_LDDX_FORMS */ + {"", "ED AC", 4, 16}, +#endif + + /* SPECASM_DOC_LDI_FORMS */ + {"", "ED A0", 4, 16}, + + /* SPECASM_DOC_LDIR_FORMS */ + {"", "ED B0", 4, 16}, + {"", "ED B0", 5, 21}, + +#ifdef SPECASM_TARGET_NEXT_OPCODES + /* SPECASM_DOC_LDIRX_FORMS */ + {"", "ED B4", 4, 16}, + {"", "ED B4", 5, 21}, + + /* SPECASM_DOC_LDIX_FORMS */ + {"", "ED A4", 4, 16}, + + /* SPECASM_DOC_LDPIRX_FORMS */ + {"", "ED B7", 4, 16}, + {"", "ED B7", 5, 21}, + + /* SPECASM_DOC_LDWS_FORMS */ + {"", "ED A5", 4, 16}, +#endif + /* SPECASM_DOC_MAP_FORMS */ + {"", "", 0, 0}, + +#ifdef SPECASM_TARGET_NEXT_OPCODES + /* SPECASM_DOC_MIRROR_FORMS */ + {"a", "ED 24", 2, 8}, + + /* SPECASM_DOC_MUL_FORMS */ + {"d,e", "ED 30", 2, 8}, +#endif + + /* SPECASM_DOC_NEG_FORMS */ + {"", "ED 44", 2, 8}, + +#ifdef SPECASM_TARGET_NEXT_OPCODES + /* SPECASM_DOC_NEXTREG_FORMS */ + {"n,a", "ED 92 n", 4, 17}, + {"n,m", "ED 91 n m", 5, 20}, +#endif + /* SPECASM_DOC_NOP_FORMS */ + {"", "0", 1, 4}, + + /* SPECASM_DOC_OR_FORMS */ + {"r", "B8+r", 1, 4}, + {"n", "F6 n", 2, 7}, + {"(hl)", "B6", 2, 7}, + {"(ix+d)", "DD B6 d", 5, 19 }, + {"(iy+d)", "FD B6 d", 5, 19 }, + + /* SPECASM_DOC_ORG_FORMS */ + {"nn","", 0, 0}, + + /* SPECASM_DOC_OUT1_FORMS */ + {"(c), r", "ED 41+r", 3, 12}, + + /* SPECASM_DOC_OUT2_FORMS */ + {"(n), a", "D3 n", 3, 11}, + + /* SPECASM_DOC_OUTD_FORMS */ + {"","ED AB", 4, 16}, + + /* SPECASM_DOC_OUTDR_FORMS */ + {"","ED BB", 4, 16}, + {"","ED BB", 5, 21}, + + /* SPECASM_DOC_OUTI_FORMS */ + {"","ED A3", 4, 16}, + +#ifdef SPECASM_TARGET_NEXT_OPCODES + /* SPECASM_DOC_OUTINB_FORMS */ + {"","ED 90", 4, 16}, +#endif + /* SPECASM_DOC_OUTIR_FORMS */ + {"","ED B3", 4, 16}, + {"","ED B3", 5, 21}, + +#ifdef SPECASM_TARGET_NEXT_OPCODES + /* SPECASM_DOC_PIXELAD_FORMS */ + {"","ED 94", 2, 8}, + + /* SPECASM_DOC_PIXELDN_FORMS */ + {"","ED 93", 2, 8}, +#endif + /* SPECASM_DOC_POP_FORMS */ + {"rr", "C1+rr", 3, 10}, + {"ix", "DD E1", 4, 14}, + {"iy", "FD E1", 4, 14}, + + /* SPECASM_DOC_PUSH_FORMS */ + {"rr", "C5+rr", 3, 11}, + {"ix", "DD E5", 4, 15}, + {"iy", "FD E5", 4, 15}, + +#ifdef SPECASM_TARGET_NEXT_OPCODES + /* SPECASM_DOC_PUSH_IMM_FORMS */ + {"nm", "ED 8A n m", 6, 23}, +#endif + /* SPECASM_DOC_RES_FORMS */ + {"n,r", "CB 80+b+r", 2, 8}, + {"n,(hl)", "CB 86+n", 4, 15}, + {"n,(ix+d)", "DDCBd86+n", 6, 23}, + {"n,(iy+d)", "FDCBd86+n", 6, 23}, + + /* SPECASM_DOC_RET_FORMS */ + {"", "C9", 3, 10}, + {"cc", "C0+cc", 1, 5}, + {"cc", "C0+cc", 3, 10}, + + /* SPECASM_DOC_RETI_FORMS */ + {"", "ED 4D", 4, 14}, + + /* SPECASM_DOC_RETN_FORMS */ + {"", "ED 45", 4, 14}, + + /* SPECASM_DOC_RL_FORMS */ + {"r", "CB 10+r", 2, 8}, + {"(hl)", "CB 16", 4, 15}, + {"(ix+d)", "DD CB d 16", 6, 23 }, + {"(iy+d)", "FD CB d 16", 6, 23 }, + + /* SPECASM_DOC_RLA_FORMS */ + {"", "17", 1, 4}, + + /* SPECASM_DOC_RLC_FORMS */ + {"r", "CB r", 2, 8}, + {"(hl)", "CB 06", 4, 15}, + {"(ix+d)", "DD CB d 06", 6, 23 }, + {"(iy+d)", "FD CB d 06", 6, 23 }, + + /* SPECASM_DOC_RLCA_FORMS */ + {"", "07", 1, 4}, + + /* SPECASM_DOC_RLD_FORMS */ + {"", "ED 6F", 5, 18}, + + /* SPECASM_DOC_RR_FORMS */ + {"r", "CB 18+r", 2, 8}, + {"(hl)", "CB 1E", 4, 15}, + {"(ix+d)", "DD CB d 1E", 6, 23 }, + {"(iy+d)", "FD CB d 1E", 6, 23 }, + + /* SPECASM_DOC_RRA_FORMS */ + {"", "1F", 1, 4}, + + /* SPECASM_DOC_RRC_FORMS */ + {"r", "CB 8+r", 2, 8}, + {"(hl)", "CB 0E", 4, 15}, + {"(ix+d)", "DD CB d 0E", 6, 23 }, + {"(iy+d)", "FD CB d 0E", 6, 23 }, + + /* SPECASM_DOC_RRCA_FORMS */ + {"", "0F", 1, 4}, + + /* SPECASM_DOC_RRD_FORMS */ + {"", "ED 67", 5, 18}, + + /* SPECASM_DOC_RST_FORMS */ + {"n", "C3+n", 3, 11}, + + /* SPECASM_DOC_SBC_FORMS */ + {"a,r", "98+r", 1, 4}, + {"a,n", "DE n", 2, 7}, + {"a,(hl)", "9E", 2, 7}, + {"a,(ix+d)", "DD 9E d", 5, 19 }, + {"a,(iy+d)", "FD 9E d", 5, 19 }, + {"hl,rr", "ED 42+rr", 4, 15 }, + + /* SPECASM_DOC_SCF_FORMS */ + {"", "37", 1, 4}, + + /* SPECASM_DOC_SET_FORMS */ + {"n,r", "CB C0+b+r", 2, 8}, + {"n,(hl)", "CB C6+n", 4, 15}, + {"n,(ix+d)", "DDCBdC6+n", 6, 23}, + {"n,(iy+d)", "FDCBdC6+n", 6, 23}, + +#ifdef SPECASM_TARGET_NEXT_OPCODES + /* SPECASM_DOC_SETAE_FORMS */ + {"", "ED 95", 2, 8}, +#endif + /* SPECASM_DOC_SLA_FORMS */ + {"r", "CB 20+r", 2, 8}, + {"(hl)", "CB 26", 4, 15}, + {"(ix+d)", "DD CB d 26", 6, 23 }, + {"(iy+d)", "FD CB d 26", 6, 23 }, + + /* SPECASM_DOC_SRA_FORMS */ + {"r", "CB 28+r", 2, 8}, + {"(hl)", "CB 2E", 4, 15}, + {"(ix+d)", "DD CB d 2E", 6, 23 }, + {"(iy+d)", "FD CB d 2E", 6, 23 }, + + /* SPECASM_DOC_SRL_FORMS */ + {"r", "CB 38+r", 2, 8}, + {"(hl)", "CB 3E", 4, 15}, + {"(ix+d)", "DD CB d 3E", 6, 23 }, + {"(iy+d)", "FD CB d 3E", 6, 23 }, + + /* SPECASM_DOC_SUB_FORMS */ + {"r", "A0+r", 1, 4}, + {"n", "D6 n", 2, 7}, + {"(hl)", "96", 2, 7}, + {"(ix+d)", "DD 96 d", 5, 19 }, + {"(iy+d)", "FD 96 d", 5, 19 }, + +#ifdef SPECASM_TARGET_NEXT_OPCODES + /* SPECASM_DOC_SWAPNIB_FORMS */ + {"", "ED 23", 2, 8}, + + /* SPECASM_DOC_TEST_FORMS */ + + {"n", "ED 27 n", 3, 11}, +#endif + + /* SPECASM_DOC_XOR_FORMS */ + {"r", "A8+r", 1, 4}, + {"n", "EE n", 2, 7}, + {"(hl)", "AE", 2, 7}, + {"(ix+d)", "DD AE d", 5, 19 }, + {"(iy+d)", "FD AE d", 5, 19 }, +}; + +#define SPECASM_DOC_MAX_REG_ENCODING (SPECASM_BYTE_REG_IY+1) + +struct specasm_ins_doc_t_ { + char name[8]; + uint8_t forms; + uint8_t num_forms; + uint8_t reg_encoding; + uint8_t bits; + uint8_t all_cc; +#ifdef SPECASM_TARGET_NEXT_OPCODES + uint8_t zxn; +#endif + const char *description; + const char *flags; +}; + +typedef struct specasm_ins_doc_t_ specasm_ins_doc_t; + +static const char* const reg_names[] = { + "a", + "b", + "c", + "d", + "e", + "h", + "l", + "bc", + "de", + "hl", + "af", + "sp", + "ix", + "iy" +}; + +const uint8_t reg_encodings[][SPECASM_DOC_MAX_REG_ENCODING] = { + { 8, 1, 2, 3, 4, 5, 6, 1, 17, 33, 0, 49 }, + { 8, 1, 2, 3, 4, 5, 6 }, + { 0, 0, 0, 0, 0, 0, 0, 1, 17, 33, 0, 49 }, + { 0, 0, 0, 0, 0, 0, 0, 1, 17, 0, 0, 49, 33 }, + { 0, 0, 0, 0, 0, 0, 0, 1, 17, 0, 0, 49, 0, 33}, + { 57, 1, 9, 17, 25, 33, 49}, + { 0, 0, 0, 0, 0, 0, 0, 1, 17, 33, 49 }, + { 0, 0, 0, 0, 0, 0, 0, 4, 3, 2, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 3, 2, 1, 0 }, +}; + +/* + * Must be in the same order as the opcode_table in line_parse.c. + */ + +const static specasm_ins_doc_t docs[] = { + { + "adc", + SPECASM_DOC_ADC_FORMS, + SPECASM_DOC_ADC_NUM_FORMS, + 1, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_adc, + "XX X X0X", + }, + { + "add", + SPECASM_DOC_ADD1_FORMS, + SPECASM_DOC_ADD1_NUM_FORMS, + 2, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_add, + "XX X X0X", + }, + { + "add", + SPECASM_DOC_ADD2_FORMS, + SPECASM_DOC_ADD2_NUM_FORMS, + 3, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_add_16, + " X 0X", + }, + { + "add", + SPECASM_DOC_ADD3_FORMS, + SPECASM_DOC_ADD3_NUM_FORMS, + 4, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_add_16, + " X 0X", + }, + { + "add", + SPECASM_DOC_ADD4_FORMS, + SPECASM_DOC_ADD4_NUM_FORMS, + 5, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_add_16, + " X 0X", + }, + #ifdef SPECASM_TARGET_NEXT_OPCODES + { + "add", + SPECASM_DOC_ADD5_FORMS, + SPECASM_DOC_ADD5_NUM_FORMS, + 8, + 0, + 0, + 1, + specasm_doc_add_rra, + " ?", + }, + { + "add", + SPECASM_DOC_ADD6_FORMS, + SPECASM_DOC_ADD6_NUM_FORMS, + 9, + 0, + 0, + 1, + specasm_doc_add_16imm, + NULL, + }, + #endif + { + "align", + SPECASM_DOC_ALIGN_FORMS, + SPECASM_DOC_ALIGN_NUM_FORMS, + 0, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_align, + NULL, + }, + { + "and", + SPECASM_DOC_AND_FORMS, + SPECASM_DOC_AND_NUM_FORMS, + 2, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_and, + "XX 1 X00", + }, + { + "bit", + SPECASM_DOC_BIT_FORMS, + SPECASM_DOC_BIT_NUM_FORMS, + 2, + 8, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_bit, + "?X 1 ?0 ", + }, +#ifdef SPECASM_TARGET_NEXT_OPCODES + { + "brlc", + SPECASM_DOC_BRLC_FORMS, + SPECASM_DOC_BRLC_NUM_FORMS, + 0, + 0, + 0, + 1, + specasm_doc_brlc, + NULL, + }, + { + "bsla", + SPECASM_DOC_BSLA_FORMS, + SPECASM_DOC_BSLA_NUM_FORMS, + 0, + 0, + 0, + 1, + specasm_doc_bsla, + NULL, + }, + { + "bsra", + SPECASM_DOC_BSRA_FORMS, + SPECASM_DOC_BSRA_NUM_FORMS, + 0, + 0, + 0, + 1, + specasm_doc_bsra, + NULL, + }, + { + "bsrf", + SPECASM_DOC_BSRF_FORMS, + SPECASM_DOC_BSRF_NUM_FORMS, + 0, + 0, + 0, + 1, + specasm_doc_bsrf, + NULL, + }, + { + "bsrl", + SPECASM_DOC_BSRL_FORMS, + SPECASM_DOC_BSRL_NUM_FORMS, + 0, + 0, + 0, + 1, + specasm_doc_bsrl, + NULL, + }, + +#endif + { + "call", + SPECASM_DOC_CALL_FORMS, + SPECASM_DOC_CALL_NUM_FORMS, + 0, + 0, + 8, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_call, + NULL, + }, + { + "ccf", + SPECASM_DOC_CCF_FORMS, + SPECASM_DOC_CCF_NUM_FORMS, + 0, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_ccf, + " ? 0X" + }, + { + "cp", + SPECASM_DOC_CP_FORMS, + SPECASM_DOC_CP_NUM_FORMS, + 2, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_cp, + "XX X X1X", + }, + { + "cpd", + SPECASM_DOC_CPD_FORMS, + SPECASM_DOC_CPD_NUM_FORMS, + 0, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_cpd, + "XX X X1 ", + }, + { + "cpdr", + SPECASM_DOC_CPDR_FORMS, + SPECASM_DOC_CPDR_NUM_FORMS, + 0, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_cpdr, + "XX X X1 ", + }, + { + "cpi", + SPECASM_DOC_CPI_FORMS, + SPECASM_DOC_CPI_NUM_FORMS, + 0, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_cpi, + "XX X X1 ", + }, + { + "cpir", + SPECASM_DOC_CPIR_FORMS, + SPECASM_DOC_CPIR_NUM_FORMS, + 0, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_cpir, + "XX X X1 ", + }, + { + "cpl", + SPECASM_DOC_CPL_FORMS, + SPECASM_DOC_CPL_NUM_FORMS, + 0, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_cpl, + " 1 1 ", + }, + { + "daa", + SPECASM_DOC_DAA_FORMS, + SPECASM_DOC_DAA_NUM_FORMS, + 0, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_daa, + "XX X X X", + }, + { + "db", + SPECASM_DOC_DB_FORMS, + SPECASM_DOC_DB_NUM_FORMS, + 0, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_db, + NULL, + }, + { + "dec", + SPECASM_DOC_DEC1_FORMS, + SPECASM_DOC_DEC1_NUM_FORMS, + 6, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_dec, + "XX X X1 ", + }, + { + "dec", + SPECASM_DOC_DEC2_FORMS, + SPECASM_DOC_DEC2_NUM_FORMS, + 3, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_dec, + NULL, + }, + { + "di", + SPECASM_DOC_DI_FORMS, + SPECASM_DOC_DI_NUM_FORMS, + 0, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_di, + NULL, + }, + { + "djnz", + SPECASM_DOC_DJNZ_FORMS, + SPECASM_DOC_DJNZ_NUM_FORMS, + 0, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_djnz, + NULL, + }, + { + "ds", + SPECASM_DOC_DS_FORMS, + SPECASM_DOC_DS_NUM_FORMS, + 0, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_ds, + NULL, + }, + { + "dw", + SPECASM_DOC_DW_FORMS, + SPECASM_DOC_DW_NUM_FORMS, + 0, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_dw, + NULL, + }, + { + "ei", + SPECASM_DOC_EI_FORMS, + SPECASM_DOC_EI_NUM_FORMS, + 0, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_ei, + NULL, + }, + { + "ex", + SPECASM_DOC_EX_FORMS, + SPECASM_DOC_EX_NUM_FORMS, + 0, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_ex, + "XXXXXXXX", + }, + { + "exx", + SPECASM_DOC_EXX_FORMS, + SPECASM_DOC_EXX_NUM_FORMS, + 0, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_exx, + NULL, + }, + { + "halt", + SPECASM_DOC_HALT_FORMS, + SPECASM_DOC_HALT_NUM_FORMS, + 0, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_halt, + NULL, + }, + { + "im", + SPECASM_DOC_IM_FORMS, + SPECASM_DOC_IM_NUM_FORMS, + 0, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_im, + NULL, + }, + { + "in", + SPECASM_DOC_IN1_FORMS, + SPECASM_DOC_IN1_NUM_FORMS, + 6, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_in, + "XX X X0 ", + }, + { + "in", + SPECASM_DOC_IN2_FORMS, + SPECASM_DOC_IN2_NUM_FORMS, + 0, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_in2, + NULL, + }, + { + "inc", + SPECASM_DOC_INC1_FORMS, + SPECASM_DOC_INC1_NUM_FORMS, + 6, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_inc, + "XX X X0 ", + }, + { + "inc", + SPECASM_DOC_INC2_FORMS, + SPECASM_DOC_INC2_NUM_FORMS, + 3, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_inc, + NULL, + }, + { + "ind", + SPECASM_DOC_IND_FORMS, + SPECASM_DOC_IND_NUM_FORMS, + 0, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_ind, + "?X ? ?1 ", + }, + { + "indr", + SPECASM_DOC_INDR_FORMS, + SPECASM_DOC_INDR_NUM_FORMS, + 0, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_indr, + "?1 ? ?1 " + }, + { + "ini", + SPECASM_DOC_INI_FORMS, + SPECASM_DOC_INI_NUM_FORMS, + 0, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_ini, + "?X ? ?1 ", + }, + { + "inir", + SPECASM_DOC_INIR_FORMS, + SPECASM_DOC_INIR_NUM_FORMS, + 0, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_inir, + "?1 ? ?1 " + }, + { + "jp", + SPECASM_DOC_JP_FORMS, + SPECASM_DOC_JP_NUM_FORMS, + 0, + 0, + 8, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_jp, + NULL, + }, +#ifdef SPECASM_TARGET_NEXT_OPCODES + { + "jp", + SPECASM_DOC_JP_C_FORMS, + SPECASM_DOC_JP_C_NUM_FORMS, + 0, + 0, + 0, + 1, + specasm_doc_jp_c, + "?? ? ???" + }, +#endif + { + "jr", + SPECASM_DOC_JR_FORMS, + SPECASM_DOC_JR_NUM_FORMS, + 0, + 0, + 8, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_jr, + NULL, + }, + { + "ld", + SPECASM_DOC_LD1_FORMS, + SPECASM_DOC_LD1_NUM_FORMS, + 3, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_ld1, + NULL, + }, + { + "ld", + SPECASM_DOC_LD2_FORMS, + SPECASM_DOC_LD2_NUM_FORMS, + 0, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_ld2, + NULL, + }, + { + "ld", + SPECASM_DOC_LD3_FORMS, + SPECASM_DOC_LD3_NUM_FORMS, + 6, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_ld3, + NULL, + }, + { + "ld", + SPECASM_DOC_LD4_FORMS, + SPECASM_DOC_LD4_NUM_FORMS, + 2, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_ld4, + NULL, + }, + { + "ld", + SPECASM_DOC_LD5_FORMS, + SPECASM_DOC_LD5_NUM_FORMS, + 3, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_ld5, + NULL, + }, + { + "ld", + SPECASM_DOC_LD6_FORMS, + SPECASM_DOC_LD6_NUM_FORMS, + 0, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_ld6, + NULL, + }, + { + "ld", + SPECASM_DOC_LD7_FORMS, + SPECASM_DOC_LD7_NUM_FORMS, + 6, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_ld7, + NULL, + }, + { + "ld", + SPECASM_DOC_LD8_FORMS, + SPECASM_DOC_LD8_NUM_FORMS, + 0, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_ld8, + NULL, + }, + { + "ldd", + SPECASM_DOC_LDD_FORMS, + SPECASM_DOC_LDD_NUM_FORMS, + 0, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_ldd, + " 0 X0 ", + }, + { + "lddr", + SPECASM_DOC_LDDR_FORMS, + SPECASM_DOC_LDDR_NUM_FORMS, + 0, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_lddr, + " 0 00 ", + }, + +#ifdef SPECASM_TARGET_NEXT_OPCODES + { + "lddrx", + SPECASM_DOC_LDDRX_FORMS, + SPECASM_DOC_LDDRX_NUM_FORMS, + 0, + 0, + 0, + 1, + specasm_doc_lddrx, + NULL, + }, + { + "lddx", + SPECASM_DOC_LDDX_FORMS, + SPECASM_DOC_LDDX_NUM_FORMS, + 0, + 0, + 0, + 1, + specasm_doc_lddx, + NULL, + }, +#endif + { + "ldi", + SPECASM_DOC_LDI_FORMS, + SPECASM_DOC_LDI_NUM_FORMS, + 0, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_ldi, + " 0 X0 ", + }, + { + "ldir", + SPECASM_DOC_LDIR_FORMS, + SPECASM_DOC_LDIR_NUM_FORMS, + 0, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_ldir, + " 0 00 ", + }, +#ifdef SPECASM_TARGET_NEXT_OPCODES + { + "ldirx", + SPECASM_DOC_LDIRX_FORMS, + SPECASM_DOC_LDIRX_NUM_FORMS, + 0, + 0, + 0, + 1, + specasm_doc_ldirx, + NULL, + }, + { + "ldix", + SPECASM_DOC_LDIX_FORMS, + SPECASM_DOC_LDIX_NUM_FORMS, + 0, + 0, + 0, + 1, + specasm_doc_ldix, + NULL, + }, + { + "ldpirx", + SPECASM_DOC_LDPIRX_FORMS, + SPECASM_DOC_LDPIRX_NUM_FORMS, + 0, + 0, + 0, + 1, + specasm_doc_ldpirx, + NULL, + }, + { + "ldws", + SPECASM_DOC_LDWS_FORMS, + SPECASM_DOC_LDWS_NUM_FORMS, + 0, + 0, + 0, + 1, + specasm_doc_ldws, + "XX X X0 ", + }, +#endif + { + "map", + SPECASM_DOC_MAP_FORMS, + SPECASM_DOC_MAP_NUM_FORMS, + 0, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_map, + NULL, + }, +#ifdef SPECASM_TARGET_NEXT_OPCODES + { + "mirror", + SPECASM_DOC_MIRROR_FORMS, + SPECASM_DOC_MIRROR_NUM_FORMS, + 0, + 0, + 0, + 1, + specasm_doc_mirror, + NULL, + }, + { + "mul", + SPECASM_DOC_MUL_FORMS, + SPECASM_DOC_MUL_NUM_FORMS, + 0, + 0, + 0, + 1, + specasm_doc_mul, + NULL, + }, +#endif + { + "neg", + SPECASM_DOC_NEG_FORMS, + SPECASM_DOC_NEG_NUM_FORMS, + 0, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_neg, + "XX X X1X", + }, +#ifdef SPECASM_TARGET_NEXT_OPCODES + { + "nextreg", + SPECASM_DOC_NEXTREG_FORMS, + SPECASM_DOC_NEXTREG_NUM_FORMS, + 0, + 0, + 0, + 1, + specasm_doc_nextreg, + NULL, + }, +#endif + { + "nop", + SPECASM_DOC_NOP_FORMS, + SPECASM_DOC_NOP_NUM_FORMS, + 0, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_nop, + NULL, + }, + { + "or", + SPECASM_DOC_OR_FORMS, + SPECASM_DOC_OR_NUM_FORMS, + 2, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_or, + "XX 0 X00", + }, + { + "org", + SPECASM_DOC_ORG_FORMS, + SPECASM_DOC_ORG_NUM_FORMS, + 0, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_org, + NULL, + }, + { + "out", + SPECASM_DOC_OUT1_FORMS, + SPECASM_DOC_OUT1_NUM_FORMS, + 6, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_out1, + NULL, + }, + { + "out", + SPECASM_DOC_OUT2_FORMS, + SPECASM_DOC_OUT2_NUM_FORMS, + 0, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_out2, + NULL, + }, + { + "outd", + SPECASM_DOC_OUTD_FORMS, + SPECASM_DOC_OUTD_NUM_FORMS, + 0, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_outd, + "?X ? ?1 ", + }, + { + "outdr", + SPECASM_DOC_OUTDR_FORMS, + SPECASM_DOC_OUTDR_NUM_FORMS, + 0, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_outdr, + "?1 ? ?1 ", + }, + { + "outi", + SPECASM_DOC_OUTI_FORMS, + SPECASM_DOC_OUTI_NUM_FORMS, + 0, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_outi, + "?X ? ?1 ", + }, +#ifdef SPECASM_TARGET_NEXT_OPCODES + { + "outinb", + SPECASM_DOC_OUTINB_FORMS, + SPECASM_DOC_OUTINB_NUM_FORMS, + 0, + 0, + 0, + 1, + specasm_doc_outinb, + "?? ? ???", + }, +#endif + { + "outir", + SPECASM_DOC_OUTIR_FORMS, + SPECASM_DOC_OUTIR_NUM_FORMS, + 0, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_outir, + "?1 ? ?1 ", + }, +#ifdef SPECASM_TARGET_NEXT_OPCODES + { + "pixelad", + SPECASM_DOC_PIXELAD_FORMS, + SPECASM_DOC_PIXELAD_NUM_FORMS, + 0, + 0, + 0, + 1, + specasm_doc_pixelad, + NULL, + }, + { + "pixeldn", + SPECASM_DOC_PIXELDN_FORMS, + SPECASM_DOC_PIXELDN_NUM_FORMS, + 0, + 0, + 0, + 1, + specasm_doc_pixeldn, + NULL, + }, +#endif + { + "pop", + SPECASM_DOC_POP_FORMS, + SPECASM_DOC_POP_NUM_FORMS, + 7, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_pop, + NULL, + }, + { + "push", + SPECASM_DOC_PUSH_FORMS, + SPECASM_DOC_PUSH_NUM_FORMS, + 7, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_push, + NULL, + }, +#ifdef SPECASM_TARGET_NEXT_OPCODES + { + "push", + SPECASM_DOC_PUSH_IMM_FORMS, + SPECASM_DOC_PUSH_IMM_NUM_FORMS, + 0, + 0, + 0, + 1, + specasm_doc_push_imm, + NULL, + }, +#endif + { + "res", + SPECASM_DOC_RES_FORMS, + SPECASM_DOC_RES_NUM_FORMS, + 2, + 8, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_res, + NULL, + }, + { + "ret", + SPECASM_DOC_RET_FORMS, + SPECASM_DOC_RET_NUM_FORMS, + 0, + 0, + 8, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_ret, + NULL, + }, + { + "reti", + SPECASM_DOC_RETI_FORMS, + SPECASM_DOC_RETI_NUM_FORMS, + 0, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_reti, + NULL, + }, + { + "retn", + SPECASM_DOC_RETN_FORMS, + SPECASM_DOC_RETN_NUM_FORMS, + 0, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_retn, + NULL, + }, + { + "rl", + SPECASM_DOC_RL_FORMS, + SPECASM_DOC_RL_NUM_FORMS, + 2, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_rl, + "XX 0 X0X", + }, + { + "rla", + SPECASM_DOC_RLA_FORMS, + SPECASM_DOC_RLA_NUM_FORMS, + 0, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_rla, + " 0 0X", + }, + { + "rlc", + SPECASM_DOC_RLC_FORMS, + SPECASM_DOC_RLC_NUM_FORMS, + 2, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_rlc, + "XX 0 X0X", + }, + { + "rlca", + SPECASM_DOC_RLCA_FORMS, + SPECASM_DOC_RLCA_NUM_FORMS, + 0, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_rlca, + " 0 0X", + }, + { + "rld", + SPECASM_DOC_RLD_FORMS, + SPECASM_DOC_RLD_NUM_FORMS, + 0, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_rld, + "XX 0 X0 ", + }, + { + "rr", + SPECASM_DOC_RR_FORMS, + SPECASM_DOC_RR_NUM_FORMS, + 2, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_rr, + "XX 0 X0X", + }, + { + "rra", + SPECASM_DOC_RRA_FORMS, + SPECASM_DOC_RRA_NUM_FORMS, + 0, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_rra, + " 0 0X", + }, + { + "rrc", + SPECASM_DOC_RRC_FORMS, + SPECASM_DOC_RRC_NUM_FORMS, + 2, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_rrc, + "XX 0 X0X", + }, + { + "rrca", + SPECASM_DOC_RRCA_FORMS, + SPECASM_DOC_RRCA_NUM_FORMS, + 0, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_rrca, + " 0 0X", + }, + { + "rrd", + SPECASM_DOC_RRD_FORMS, + SPECASM_DOC_RRD_NUM_FORMS, + 0, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_rrd, + "XX 0 X0 ", + }, + { + "rst", + SPECASM_DOC_RST_FORMS, + SPECASM_DOC_RST_NUM_FORMS, + 0, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_rst, + NULL, + }, + { + "sbc", + SPECASM_DOC_SBC_FORMS, + SPECASM_DOC_SBC_NUM_FORMS, + 1, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_sbc, + "XX X X1X", + }, + { + "scf", + SPECASM_DOC_SCF_FORMS, + SPECASM_DOC_SCF_NUM_FORMS, + 0, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_scf, + " 0 01" + }, + { + "set", + SPECASM_DOC_SET_FORMS, + SPECASM_DOC_SET_NUM_FORMS, + 2, + 8, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_set, + NULL, + }, +#ifdef SPECASM_TARGET_NEXT_OPCODES + { + "setae", + SPECASM_DOC_SETAE_FORMS, + SPECASM_DOC_SETAE_NUM_FORMS, + 0, + 0, + 0, + 1, + specasm_doc_setae, + NULL, + }, +#endif + { + "sla", + SPECASM_DOC_SLA_FORMS, + SPECASM_DOC_SLA_NUM_FORMS, + 2, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_sla, + "XX 0 X0X", + }, + { + "sra", + SPECASM_DOC_SRA_FORMS, + SPECASM_DOC_SRA_NUM_FORMS, + 2, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_sra, + "XX 0 X0X", + }, + { + "srl", + SPECASM_DOC_SRL_FORMS, + SPECASM_DOC_SRL_NUM_FORMS, + 2, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_srl, + "XX 0 X0X", + }, + { + "sub", + SPECASM_DOC_SUB_FORMS, + SPECASM_DOC_SUB_NUM_FORMS, + 2, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_sub, + "XX X X1X", + }, +#ifdef SPECASM_TARGET_NEXT_OPCODES + { + "swapnib", + SPECASM_DOC_SWAPNIB_FORMS, + SPECASM_DOC_SWAPNIB_NUM_FORMS, + 0, + 0, + 0, + 1, + specasm_doc_swapnib, + NULL, + }, + { + "test", + SPECASM_DOC_TEST_FORMS, + SPECASM_DOC_TEST_NUM_FORMS, + 0, + 0, + 0, + 1, + specasm_doc_test, + "XX X X?X", + }, +#endif + { + "xor", + SPECASM_DOC_XOR_FORMS, + SPECASM_DOC_XOR_NUM_FORMS, + 2, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_xor, + "XX 0 X00", + }, + { + "zx81", + SPECASM_DOC_MAP_FORMS, + SPECASM_DOC_MAP_NUM_FORMS, + 0, + 0, + 0, +#ifdef SPECASM_TARGET_NEXT_OPCODES + 0, +#endif + specasm_doc_zx81, + NULL, + }, +}; + +/* clang-format on */ + +const uint8_t max_docs = sizeof(docs) / sizeof(specasm_ins_doc_t); + +static uint8_t prv_pretty_print(uint8_t y, const char *text) +{ + uint8_t i; + + while (*text) { + memset(scratch, ' ', SPECASM_LINE_MAX_LEN); + scratch[SPECASM_LINE_MAX_LEN] = 0; + for (i = 0; *text && i < SPECASM_LINE_MAX_LEN; i++) { + scratch[i] = *text++; + } + + if (i == SPECASM_LINE_MAX_LEN) { + for (i = i - 1; scratch[i] != ' '; i--) { + text--; + scratch[i] = ' '; + if (i == 0) + break; + } + } + + specasm_util_print(scratch, 0, y++, PAPER_BLACK | INK_WHITE); + } + + return y; +} + +static void prv_justify_num(uint8_t num) +{ + char *s = scratch; + + if (num < 10) { + s[0] = ' '; + s++; + } + itoa(num, s, 10); +} + +static uint8_t prv_print_register_encoding(const specasm_ins_doc_t *doc, + uint8_t y) +{ + uint8_t i; + uint8_t reg_encoding; + const char *reg_name; + char *s2; + char *rr_start = NULL; + const uint8_t *enc; + char *s = scratch; + + if (!doc->reg_encoding) + return y; + + enc = (const uint8_t *)®_encodings[doc->reg_encoding - 1]; + + for (i = 0; i < SPECASM_DOC_MAX_REG_ENCODING; i++) { + reg_encoding = enc[i]; + if (reg_encoding) { + if ((i > 6) && !rr_start) + rr_start = s; + s += 3; + } + } + + memset(scratch, ' ', SPECASM_LINE_MAX_LEN); + if (!rr_start) { + scratch[15] = 'r'; + } else if (rr_start == scratch) { + scratch[14] = 'r'; + scratch[15] = 'r'; + } else { + scratch[(rr_start - scratch) / 2] = 'r'; + s2 = SPECASM_LINE_MAX_LEN + scratch; + s = &rr_start[((s2 - rr_start) / 2)]; + s -= 3; + *s = 'r'; + s[1] = 'r'; + } + specasm_util_print(scratch, 0, y, PAPER_WHITE | INK_BLACK); + y++; + + s = scratch; + memset(scratch, ' ', SPECASM_LINE_MAX_LEN); + for (i = 0; i < SPECASM_DOC_MAX_REG_ENCODING; i++) { + reg_encoding = enc[i]; + if (reg_encoding) { + s2 = s; + reg_name = reg_names[i]; + if (!reg_name[1]) + s2++; + memcpy(s2, reg_name, strlen(reg_name)); + s += 3; + } + } + specasm_util_print(scratch, 0, y, PAPER_BLUE | INK_WHITE); + + memset(scratch, ' ', SPECASM_LINE_MAX_LEN); + s = scratch; + for (i = 0; i < SPECASM_DOC_MAX_REG_ENCODING; i++) { + reg_encoding = enc[i]; + if (reg_encoding) { + reg_encoding--; + s2 = s; + if (reg_encoding < 16) + s2++; + itoa(reg_encoding, s2, 16); + s2[strlen(s2)] = ' '; + s += 3; + } + } + + specasm_util_print(scratch, 0, y + 1, PAPER_BLACK | INK_WHITE | 64); + + return y + 3; +} + +static void prv_print_flags(uint8_t y, const char *flags) +{ + if (!flags) + return; + + specasm_util_print("sz-h-pnc", 12, y, PAPER_BLUE | INK_WHITE); + y++; + specasm_util_print("Flags", 5, y, PAPER_BLACK | INK_WHITE); + specasm_util_print(flags, 12, y, PAPER_BLACK | INK_WHITE | 64); +} + +static uint8_t prv_print_bits_encoding(const specasm_ins_doc_t *doc, uint8_t y) +{ + uint8_t i; + uint8_t x; + uint8_t num; + char *s; + + if (!doc->bits) + return y; + + memset(scratch, ' ', SPECASM_LINE_MAX_LEN); + scratch[15] = 'n'; + specasm_util_print(scratch, 0, y, PAPER_WHITE | INK_BLACK); + y++; + + memset(scratch, ' ', SPECASM_LINE_MAX_LEN); + s = scratch; + for (i = 0; i < 8; i++) { + s[2] = i + '0'; + s += 4; + } + specasm_util_print(scratch, 0, y, PAPER_BLUE | INK_WHITE); + y++; + + for (i = 0; i < 8; i++) { + num = doc->bits * i; + itoa(num, scratch, 16); + x = (i * 4) + 1; + if (num < 16) + x++; + specasm_util_print(scratch, x, y, PAPER_BLACK | INK_WHITE); + } + + return y + 2; +} + +static uint8_t prv_print_cc_encoding(const specasm_ins_doc_t *doc, uint8_t y) +{ + uint8_t i; + uint8_t x; + uint8_t num; + uint8_t limit; + char *s; + + if (!doc->all_cc) + return y; + + memset(scratch, ' ', SPECASM_LINE_MAX_LEN); + scratch[14] = 'c'; + scratch[15] = 'c'; + specasm_util_print(scratch, 0, y, PAPER_WHITE | INK_BLACK); + y++; + + if (strcmp(doc->name, "jr")) { + limit = 8; + specasm_util_print(" nz z nc c po pe p m ", 0, y, + PAPER_BLUE | INK_WHITE); + } else { + limit = 4; + specasm_util_print(" nz z nc c ", 0, y, + PAPER_BLUE | INK_WHITE); + } + y++; + + for (i = 0; i < limit; i++) { + num = doc->all_cc * i; + itoa(num, scratch, 16); + x = (i * 4) + 1; + if (num < 16) + x++; + specasm_util_print(scratch, x, y, PAPER_BLACK | INK_WHITE); + } + + return y + 2; +} + +static void prv_draw_help(uint8_t ins_id) +{ + uint8_t x; + uint8_t i; + uint8_t y; + uint8_t col; + const specasm_ins_doc_t *doc = &docs[ins_id]; + const specasm_ins_form_t *form; + const char *ins_name = doc->name; + uint8_t ins_name_len = strlen(ins_name); + + specasm_cls(PAPER_BLACK | INK_WHITE); + x = (SPECASM_LINE_MAX_LEN / 2) - (strlen(ins_name) >> 1); + + memset(scratch, ' ', SPECASM_LINE_MAX_LEN); + scratch[SPECASM_LINE_MAX_LEN] = 0; + memcpy(&scratch[x], ins_name, ins_name_len); + + specasm_util_print(scratch, 0, 0, PAPER_BLUE | INK_WHITE | 64); +#ifdef SPECASM_TARGET_NEXT_OPCODES + if (doc->zxn) + specasm_util_print("zxn", 0, 0, PAPER_BLUE | INK_RED | 64); +#endif + y = 2; + memcpy(scratch, "Opcode Encoding M T", + SPECASM_LINE_MAX_LEN); + specasm_util_print(scratch, 0, y, PAPER_BLUE | INK_WHITE); + y++; + col = PAPER_BLACK | INK_WHITE; + form = &specasm_forms[doc->forms]; + for (i = 0; i < doc->num_forms; i++) { + col ^= 1 << 6; + x = 0; + specasm_util_print(ins_name, x, y, col); + x += ins_name_len + 1; + specasm_util_print(form->form, x, y, col); + specasm_util_print(form->encoding, SPECASM_DOC_ENCODING_X, y, + col); + prv_justify_num(form->m_cycles); + specasm_util_print(scratch, SPECASM_DOC_M_CYCLES_X, y, col); + prv_justify_num(form->t_states); + specasm_util_print(scratch, SPECASM_DOC_T_STATES_X, y, col); + y++; + form++; + } + + y = prv_print_register_encoding(doc, y + 1); + y = prv_print_bits_encoding(doc, y); + y = prv_print_cc_encoding(doc, y); +#ifdef SPECASM_NEXT_BANKED + specasm_descr_bank(ins_name); +#endif + y = prv_pretty_print(y, doc->description); + prv_print_flags(y + 1, doc->flags); +} + +static uint8_t prv_find_mnemomic(const char *ins_name) +{ + uint8_t m; + uint8_t l; + uint8_t r; + int res; + + if (strcmp(ins_name, docs[0].name) < 0) + return 0; + + l = 0; + r = max_docs - 1; + + while (l <= r) { + m = (l + r) >> 1; + res = strcmp(docs[m].name, ins_name); + if (res < 0) { + l = m + 1; + } else if (res > 0) { + if (m == 0) + break; + r = m - 1; + } else { + for (; m > 0 && !strcmp(docs[m - 1].name, ins_name); + m--) + ; + return m; + } + } + + /* + * Opcode not found. Let's return something close. + */ + + if ((r < max_docs - 1) && (ins_name[0] != docs[r].name[0]) && + (ins_name[0] == docs[r + 1].name[0])) + r++; + + return r; +} + +void specasm_help_banked(const char *ins_name) +{ + uint8_t id; + uint8_t k; + char jmp[2]; + uint8_t redraw = 1; + + jmp[1] = 0; + + id = prv_find_mnemomic(ins_name); + do { + if (redraw) + prv_draw_help(id); + do { + specasm_sleep_ms(50); + } while (!(k = in_inkey())); + + redraw = 0; + if (k == SPECASM_KEY_LEFT) { + if (id > 0) { + id--; + redraw = 1; + } + } else if (k == SPECASM_KEY_RIGHT) { + if (id < max_docs - 1) { + id++; + redraw = 1; + } + } else if (k >= 'a' && k <= 'z') { + jmp[0] = k; + id = prv_find_mnemomic(jmp); + redraw = 1; + } else { + break; + } + } while (1); + + specasm_cls(PAPER_BLACK | INK_WHITE); +} diff --git a/src/doc.h b/src/doc.h new file mode 100644 index 0000000..5fc8d75 --- /dev/null +++ b/src/doc.h @@ -0,0 +1,22 @@ +/* + * Copyright contributors to Specasm + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +*/ + +#ifndef SPECASM_DOC_H +#define SPECASM_DOC_H + +void specasm_help(const char *ins_name); + +#endif diff --git a/src/editor.c b/src/editor.c index bb5c841..9d49287 100644 --- a/src/editor.c +++ b/src/editor.c @@ -12,11 +12,12 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. -*/ + */ #include "editor.h" #include "editor_buffers.h" #if defined(SPECASM_TARGET_NEXT_OPCODES) || defined(SPECASM_TARGET_128) +#include "doc.h" #include "editor_extra.h" #endif #include "line.h" @@ -25,7 +26,6 @@ #include "scratch.h" #include "state.h" - #include #include @@ -105,8 +105,9 @@ static void specasm_dump_line_e(unsigned int l, uint8_t r, uint8_t inv) (void)specasm_text_print(scratch, 0, r, col); return; } - for (i = SPECASM_LINE_MAX_OPCODE + 1; (i < SPECASM_LINE_MAX_LEN) && - (scratch[i] != ';'); i++); + for (i = SPECASM_LINE_MAX_OPCODE + 1; + (i < SPECASM_LINE_MAX_LEN) && (scratch[i] != ';'); i++) + ; scratch[i] = 0; (void)specasm_text_print(scratch, 0, r, col); if (i < SPECASM_LINE_MAX_LEN - 2) { @@ -512,6 +513,11 @@ static void prv_exit_command_mode(uint8_t m) static uint8_t prv_single_char_command_e(uint8_t ch) { uint8_t reset = 0; +#if defined(SPECASM_TARGET_NEXT_OPCODES) || defined(SPECASM_TARGET_128) +#ifndef UNITTESTS + char start_help[2]; +#endif +#endif switch (ch) { case 'n': @@ -561,6 +567,17 @@ static uint8_t prv_single_char_command_e(uint8_t ch) case 'v': specasm_selecting_clip_paste_e(); break; +#ifndef UNITTESTS + case 'h': + start_help[0] = 'a'; + start_help[1] = 0; + specasm_text_set_flash(col, row, 0); + specasm_help(start_help); + specasm_text_set_flash(col, row, SPECASM_FLASH); + specasm_draw_screen(line - row); + specasm_draw_status(); + break; +#endif #endif default: err_type = SPECASM_ERROR_BAD_COMMAND; @@ -687,6 +704,14 @@ static uint8_t prv_long_command_e(char *com, uint8_t len) return 0; } else if ((com[0] == 'f') && (com[1] == 'l') && !com[2]) { specasm_selecting_flags(); +#ifndef UNITTESTS + } else if (com[0] == 'h' && com[1] == ' ') { + specasm_text_set_flash(col, row, 0); + specasm_help(&com[2]); + specasm_text_set_flash(col, row, SPECASM_FLASH); + specasm_draw_screen(line - row); + specasm_draw_status(); +#endif #endif } else { err_type = SPECASM_ERROR_BAD_COMMAND; @@ -1193,7 +1218,6 @@ static uint8_t prv_select_block_down(uint16_t adj) return 1; } - static uint8_t prv_select_block_up(uint8_t adj) { unsigned int new_line; diff --git a/src/editor_extra.c b/src/editor_extra.c index df9d8ed..b8e10a8 100644 --- a/src/editor_extra.c +++ b/src/editor_extra.c @@ -12,7 +12,7 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. -*/ + */ #if defined(SPECASM_TARGET_NEXT_OPCODES) || defined(SPECASM_TARGET_128) #include @@ -27,6 +27,15 @@ #include "scratch.h" #include "state.h" +static void prv_restore_line_buf(const char *command) +{ + memset(line_buf, ' ', SPECASM_LINE_MAX_LEN); + line_buf[0] = '>'; + line_buf[2] = command[0]; + if (command[1]) + line_buf[3] = command[1]; +} + static void prv_clip_copy_e(const char *command) { unsigned int i; @@ -49,11 +58,7 @@ static void prv_clip_copy_e(const char *command) * We need to put line_buf back the way it was. */ - memset(line_buf, ' ', SPECASM_LINE_MAX_LEN); - line_buf[0] = '>'; - line_buf[2] = command[0]; - if (command[1]) - line_buf[3] = command[1]; + prv_restore_line_buf(command); } void specasm_selecting_clip_copy_e(void) @@ -102,6 +107,7 @@ uint8_t specasm_selecting_clip_cut_e(void) void specasm_selecting_clip_paste_e(void) { uint16_t i; + specasm_error_t paste_err = SPECASM_ERROR_OK; uint16_t ptr = 0; uint16_t line_count = specasm_clip_get_line_count(); @@ -118,15 +124,23 @@ void specasm_selecting_clip_paste_e(void) specasm_parse_line_e(i, line_buf); /* - * This can't really error unless there's some memory - * corruption. If we return an error here we'll need - * to reset line_buf. As this cannot happen it's not - * worth the code to do it. We'll clear the error here - * to prevent the corrupted line_buf from being used - * when the command prompt is redisplayed. + * Although the line is guaranteed to be syntactically correct + * we could still get an error, if for example, there are no + * strings left. When this happens in the editor, you can't add + * the line, but here the line is already added, and then + * corrupted by the failed call to specasm_parse_line_e, so + * we'll need to set it back to empty before reporting the + * error. */ + if (err_type != SPECASM_ERROR_OK) { + state.lines.lines[i].type = SPECASM_LINE_TYPE_EMPTY; + prv_restore_line_buf("v"); + paste_err = err_type; + err_type = SPECASM_ERROR_OK; + specasm_delete_lines(i, line + line_count); + break; + } - err_type = SPECASM_ERROR_OK; ptr = specasm_clip_get_line(ptr, line_buf); i++; } @@ -135,6 +149,7 @@ void specasm_selecting_clip_paste_e(void) select_end = select_start = 0; specasm_draw_status(); } + err_type = paste_err; } void specasm_selecting_cycles(void) diff --git a/src/error.c b/src/error.c index d9ab9c2..4073660 100644 --- a/src/error.c +++ b/src/error.c @@ -16,8 +16,6 @@ #include "error.h" -specasm_error_t err_type; - /* clang-format off */ const char* error_msgs[SPECASM_MAX_ERRORS] = { diff --git a/src/samac.c b/src/samac.c new file mode 100644 index 0000000..73760d7 --- /dev/null +++ b/src/samac.c @@ -0,0 +1,191 @@ +/* + * Copyright contributors to Specasm + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "error.h" +#include "scratch.h" +#include "state.h" + +#include +static char samac_scratch[SPECASM_MAX_SCRATCH + 1]; + +extern void specasm_samac_init(void); +void specasm_samac_new(void) { specasm_state_reset(); } + +/* + * TODO: Copied from editor.c. Banking makes sharing of the function trickier, + * so it's better to factorize this code in it's own commit. Best not to + * duplicate it long term in case we add more file types. Note the code + * is a bit different as in the editor we subtract one from the length to + * get rid of the l or s and also I think the length is 1 less than it should + * be, so refactor with caution. + */ + +static char *prv_complete_filename_e(char *com, uint8_t len) +{ + char *com2; + + while (*com == ' ') { + ++com; + len--; + } + + /* + * Do we already have a valid extension? + */ + + com2 = com + (len - 1); + if ((len >= 3) && ((*com2 == 't') || (*com2 == 'x'))) { + com2--; + if (*com2 == '.') + return com; + } + + while ((com2 > com) && (*com2 != '.') && (*com2 != '/')) + com2--; + + /* + * We've got another extension where there shouldn't be one. + */ + + if (*com2 == '.') { + err_type = SPECASM_ERROR_BAD_FNAME; + return NULL; + } + + /* + * If we get here the last part of the file name does not contain an + * extension. There must be an extension so we'll add the default + * one before loading, '.x'. + */ + + if (len + 2 >= SPECASM_MAX_SCRATCH) { + err_type = SPECASM_ERROR_BAD_FNAME; + return NULL; + } + com2 = com + len; + com2[0] = '.'; + com2[1] = 'x'; + com2[2] = 0; + + return com; +} + +specasm_error_t specasm_samac_asm(const char *str, uint16_t len) +{ + uint8_t i; + specasm_error_t err; + char *ptr; + uint16_t cur_line = state.lines.num_lines; + + if (len > SPECASM_LINE_MAX_LEN) + return SPECASM_ERROR_NO_ROOM_IN_LINE; + + specasm_append_empty_line_e(); + if ((err_type != SPECASM_ERROR_OK) || (len == 0)) + return err_type; + + memset(samac_scratch, ' ', SPECASM_LINE_MAX_LEN); + + /* + * Similar to saimport, we'll ignore characters < ' ' + */ + ptr = samac_scratch; + for (i = 0; i < (uint8_t)len; i++) { + if (str[i] >= 32) + *ptr++ = str[i]; + } + samac_scratch[SPECASM_LINE_MAX_LEN] = 0; + + specasm_parse_line_e(cur_line, samac_scratch); + if (err_type != SPECASM_ERROR_OK) + goto on_error; + + specasm_format_line_e(samac_scratch, cur_line); + if (err_type != SPECASM_ERROR_OK) + goto on_error; + + return SPECASM_ERROR_OK; + +on_error: + err = err_type; + specasm_delete_lines(cur_line, cur_line + 1); + err_type = SPECASM_ERROR_OK; + return err; +} + +specasm_error_t specasm_samac_load(const char *str, uint16_t len) +{ + const char *fname; + specasm_error_t err; + + if (len >= SPECASM_MAX_SCRATCH) + return SPECASM_ERROR_BAD_FNAME; + + memcpy(samac_scratch, str, len); + samac_scratch[len] = 0; + + fname = prv_complete_filename_e(samac_scratch, len); + if (err_type != SPECASM_ERROR_OK) + goto on_error; + + specasm_load_e(fname); + if (err_type != SPECASM_ERROR_OK) + goto on_error; + + return SPECASM_ERROR_OK; + +on_error: + err = err_type; + if (err_type != SPECASM_ERROR_OPEN) + specasm_state_reset(); + err_type = SPECASM_ERROR_OK; + return err; +} + +specasm_error_t specasm_samac_save(const char *str, uint16_t len) +{ + const char *fname; + specasm_error_t err; + + if (len >= SPECASM_MAX_SCRATCH) + return SPECASM_ERROR_BAD_FNAME; + + memcpy(samac_scratch, str, len); + samac_scratch[len] = 0; + + fname = prv_complete_filename_e(samac_scratch, len); + if (err_type != SPECASM_ERROR_OK) + goto on_error; + + specasm_save_e(fname); + if (err_type != SPECASM_ERROR_OK) + goto on_error; + + return SPECASM_ERROR_OK; + +on_error: + err = err_type; + err_type = SPECASM_ERROR_OK; + return err; +} + +int main(int argc, char *argv[]) +{ + specasm_init_dump_table(); + specasm_state_reset(); + specasm_samac_init(); + return 0; +} diff --git a/src/samac_cmds.asm b/src/samac_cmds.asm new file mode 100644 index 0000000..bf49dd6 --- /dev/null +++ b/src/samac_cmds.asm @@ -0,0 +1,366 @@ +; Copyright contributors to Specasm +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. + +SECTION code_compiler + +PUBLIC _specasm_samac_init +EXTERN _specasm_samac_new +EXTERN _specasm_samac_asm +EXTERN _specasm_samac_load +EXTERN _specasm_samac_save + +; Some SPECASM errors map to BASIC errors. For everything else there's +; "Invalid Argument" + +defc SPECASM_ERROR_TOO_MANY_LINES = 2 +defc SPECASM_ERROR_NUM_TOO_BIG = 21 +defc SPECASM_ERROR_BAD_FNAME = 23 + +; Addresses of ROM routines and System variables we need to subvert the error +; handling code. + +defc CLEARSP=$1097 +defc CLSLWR=$d6e +defc COPYBUF=$ecd +defc EXPTSTG=$1c8c +defc INCCHAD=$0074 +defc OUTCODE=$15ef +defc OUTNUM=$1a1b +defc POMSGE=$c0a +defc SETMIN=$16b0 +defc STKFTCH=$2bf1 +defc STMRET=$1b76 + +defc CHADD=23645 +defc DEFAD=23563 +defc ERRNR=23610 +defc ERRSP=23613 +defc PPC=23621 +defc STRM6=23574 +defc XPTR=23647 + +_specasm_samac_init: + ld hl, (ERRSP) + ld de, extend + ld (hl), e + inc hl + ld (hl), d + ret + +synend: + pop hl + bit 7, (iy+1) + jr z, exit + jp (hl) + +exit: + ld (iy+0), 255 + ld hl, extend + push hl + jp STMRET + +error: + bit 7, (iy+1) + jr nz, runer + +syner: + ld hl, extend + push hl + ld hl, (CHADD) + ld (XPTR), hl + jp 4791 + +runer: + res 5, (iy+1) + bit 1, (iy+48) + call nz, COPYBUF + ld a, (ERRNR) + inc a + push af + ld hl, 0 + ld (DEFAD), hl + ld (iy+38), h + ld (iy+55), h + inc hl + ld (STRM6), hl + call SETMIN + call CLSLWR + set 5, (iy+2) + pop af + ld b, a + cp 10 + jr c, numcod + add a, 7 + +numcod: + call OUTCODE + ld a, 32 + rst 16 + ld a, b + ld de, 5009 + call POMSGE + xor a + ld de, 5430 + call POMSGE + ld bc, (PPC) + call OUTNUM + ld a, 58 + rst 16 + ld b, 0 + ld c, (iy+13) + call OUTNUM + call CLEARSP + ld a, (ERRNR) + ld (iy+0), 255 + ld hl, extend + push hl + jp 4968 + +fnameErr: + ld a, $e + jr exerr +numErr: + ld a, $a + jr exerr +noRoomErr: + ld a, $f + jr exerr +argErr: + ld a, 9 +exerr: + ld (ERRNR), a + jp error + +; Entry point to our added Specasm commands. +extend: +; error needs to be Nonsense in +; Basic and next char needs to +; be a '*' + ld a, (ERRNR) + cp 11 + jp nz, error + ld hl, (CHADD) + ld a, (hl) + cp '*' + jp nz, error + rst 24 + jp parse + +; Each command is 8 bytes +; length 1 byte +; name 3 to 4 bytes +; args 1 byte (0 or 1) +; handler address +; optional padding byte + +commands: +db 3, "asm" +db 1 +dw asmH +db 0 +db 3, "new" +db 0 +dw newH +db 0 +db 4, "load" +db 1 +dw loadH +db 4, "save" +db 1 +dw saveH +comEnd: + +defc comCnt=(comEnd-commands)>>3 + +; returns if no match +parse: + ld de, (CHADD) + ld (chaddSv), de + ld hl, commands + ld (comSave), hl + ld c, comCnt +findCom: + ld b, (hl) + inc hl +parseLoop: + push hl + rst 32 + pop hl + cp (hl) + jr z, checkNext + dec c + jr z, parseBad + ld de, (chaddSv) + ld (CHADD), de + ld hl, (comSave) + ld de, 8 + add hl, de + ld (comSave), hl + jr findCom +checkNext: + inc hl + djnz parseLoop + push hl + call INCCHAD + pop hl + ld b, a + xor a + cp (hl) + jr nz, parseEnd + ld a, b + cp 13 + jr z, parseEnd + cp ':' + jr z, parseEnd + jr parseBad +parseEnd: + ld a, b + inc hl + ld e, (hl) + inc hl + ld d, (hl) + ex de, hl + ; a has 1st ch of parameter + jp (hl) +parseBad: + ld de, (chaddSv) + ld (CHADD), de + jp error +comSave: +dw 0 +chaddSv: +dw 0 + +samac_error: + or a + ret z + pop hl + cp SPECASM_ERROR_BAD_FNAME + jp z, fnameErr + cp SPECASM_ERROR_NUM_TOO_BIG + jp z, numErr + cp SPECASM_ERROR_TOO_MANY_LINES + jp z, noRoomErr + jp argErr + +asmH: + call EXPTSTG + bit 6, (iy+1) + jp nz, argErr + call synend + call STKFTCH + + ; note as we're calling into C code here we + ; need to duplicate what the z88dk crt does and + ; preserve certain registers and disable interrupts. + ; Otherwise it all gets a bit crashy. + + di + push iy + exx + push hl + exx + + push bc + push de + call _specasm_samac_asm + ld a, l + pop de + pop bc + + exx + pop hl + exx + pop iy + ei + + call samac_error + jp exit + +newH: + call synend + + di + push iy + exx + push hl + exx + + call _specasm_samac_new + + exx + pop hl + exx + pop iy + ei + + jp exit + +loadH: + call EXPTSTG + bit 6, (iy+1) + jp nz, argErr + call synend + call STKFTCH + + di + push iy + exx + push hl + exx + + push bc + push de + call _specasm_samac_load + ld a, l + pop de + pop bc + + exx + pop hl + exx + pop iy + ei + + call samac_error + jp exit + +saveH: + call EXPTSTG + bit 6, (iy+1) + jp nz, argErr + call synend + call STKFTCH + + di + push iy + exx + push hl + exx + + push bc + push de + call _specasm_samac_save + ld a, l + pop de + pop bc + + exx + pop hl + exx + pop iy + ei + + call samac_error + jp exit diff --git a/src/samac_cmds_next.asm b/src/samac_cmds_next.asm new file mode 100644 index 0000000..2c91d10 --- /dev/null +++ b/src/samac_cmds_next.asm @@ -0,0 +1,184 @@ +; Copyright contributors to Specasm +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. + +SECTION code_compiler + +PUBLIC _specasm_samac_init +EXTERN _specasm_samac_new +EXTERN _specasm_samac_asm +EXTERN _specasm_samac_load +EXTERN _specasm_samac_save +EXTERN _error_msgs + +defc SPECASM_SAMAC_ORG_ADDRESS = 28736 +defc SPECASM_SAMAC_TABLE = SPECASM_SAMAC_ORG_ADDRESS - 64 +defc SPECASM_SAMAC_BUF_ADDRESS = SPECASM_SAMAC_TABLE + 24 + +_specasm_samac_init: + ld bc, asmH + ld (SPECASM_SAMAC_TABLE), bc + + ld bc, loadH + ld (SPECASM_SAMAC_TABLE + 2), bc + + ld bc, newH + ld (SPECASM_SAMAC_TABLE + 4), bc + + ld bc, saveH + ld (SPECASM_SAMAC_TABLE + 6), bc + + ; 56 bytes left for the buffer. Let's set them to 0. + ld hl, SPECASM_SAMAC_TABLE + 8 + ld de, SPECASM_SAMAC_TABLE + 9 + xor a + ld (hl), a + ld bc, 55 + ldir + + ret + +; in: +; a contains error number +; out: +; bc contain pointer to error string + +find_error: + or a + jr nz, got_an_error + ld bc, 0 + ret + +got_an_error: + sla a + ld h, 0 + ld l, a + ld bc, _error_msgs + add hl, bc + ld c, (hl) + inc hl + ld b, (hl) + ret + +find_len: + ld hl, SPECASM_SAMAC_BUF_ADDRESS + xor a + ld b, 40 +find_len_loop: + cp (hl) + jr z, find_len_end + inc hl + djnz find_len_loop +find_len_end: + ld a, 40 + sub b + ld c, a + ld b, 0 + ret + +asmH: + ; note as we're calling into C code here we + ; need to duplicate what the z88dk crt does and + ; preserve certain registers and disable interrupts. + ; Otherwise it all gets a bit crashy. + + di + push iy + exx + push hl + exx + + call find_len + push bc + push SPECASM_SAMAC_BUF_ADDRESS + call _specasm_samac_asm + ld a, l + pop de + pop bc + + exx + pop hl + exx + pop iy + ei + + call find_error + ret + +newH: + + di + push iy + exx + push hl + exx + + call _specasm_samac_new + + exx + pop hl + exx + pop iy + ei + + ld bc, 0 + + ret + +loadH: + di + push iy + exx + push hl + exx + + call find_len + push bc + push SPECASM_SAMAC_BUF_ADDRESS + call _specasm_samac_load + ld a, l + pop de + pop bc + + exx + pop hl + exx + pop iy + ei + + call find_error + ret + +saveH: + di + push iy + exx + push hl + exx + + call find_len + push bc + push SPECASM_SAMAC_BUF_ADDRESS + call _specasm_samac_save + ld a, l + pop de + pop bc + + exx + pop hl + exx + pop iy + ei + + call find_error + ret diff --git a/src/samake.c b/src/samake.c index 26227b9..541f24f 100644 --- a/src/samake.c +++ b/src/samake.c @@ -12,7 +12,7 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. -*/ + */ #include #include @@ -29,9 +29,22 @@ #define SAMAKE_TARGET_TYPE_TAP 2 #define SAMAKE_TARGET_TYPE_P 3 #define SAMAKE_TARGET_TYPE_TST 4 +#define SAMAKE_TARGET_TYPE_MAC 5 +#define SAMAKE_TARGET_TYPE_ACE 6 +#define SAMAKE_TARGET_TYPE_AUTOACE 7 #define SAMAKE_CODE_BUF_SIZE 1024 +/* + * We could use an ORG address of 32768 for the SAMAC binary, but + * this would be cutting it a bit fine, leaving only 500 or so bytes + * free. If the code grew in a subsequent release we'd end up having + * to lower the ORG address and this would break users' macros. So + * let's leave ourselves some room. + */ + +#define SAMAC_ORG_ADDRESS 30720 + static char bin_name[MAX_FNAME + 1]; static char app_name[MAX_FNAME + 1]; static uint8_t bin_name_len; @@ -39,6 +52,7 @@ static char start_address[6] = "32768"; static char clear_address[6] = "32767"; static char fsize_file_address[6] = "60000"; static uint16_t org_address = 0x8000; +static const char *samac_name = "/specasm/SAMAC"; static uint16_t basic_prog_len; static uint8_t got_org; uint8_t got_zx81; @@ -67,6 +81,17 @@ static union { static specasm_dirent_t dirent; +static uint8_t prv_write_code_e(specasm_handle_t in_f, specasm_handle_t out_f, + uint8_t checksum); + +static void prv_set_org_address(uint16_t sa) +{ + org_address = sa; + (void)utoa(sa, start_address, 10); + sa--; + (void)utoa(sa, clear_address, 10); +} + static uint8_t prv_parse_obj_e(const char *fname) { uint16_t i; @@ -102,11 +127,8 @@ static uint8_t prv_parse_obj_e(const char *fname) return 1; } else if (!got_org && (line->type == SPECASM_LINE_TYPE_ORG)) { sa = *((uint16_t *)&line->data.op_code[0]); - org_address = sa; + prv_set_org_address(sa); got_org = 1; - (void)utoa(sa, start_address, 10); - sa--; - (void)utoa(sa, clear_address, 10); if (bin_name[0] && got_zx81) return 1; } else if (!got_zx81 && @@ -173,21 +195,27 @@ static void prv_find_bin_name_e(const char *dirname, uint8_t target_type) specasm_closedir(dir); } -static void prv_make_app_name(const char *type) +static void prv_make_app_name_gen(const char *type, const char *name, + uint8_t len) { uint8_t ext_pos; - uint8_t bin_name_len_plus_ext; + uint8_t len_plus_ext; - bin_name_len_plus_ext = bin_name_len + strlen(type) + 1; - if (bin_name_len_plus_ext > MAX_FNAME) - ext_pos = bin_name_len - (bin_name_len_plus_ext - MAX_FNAME); + len_plus_ext = len + strlen(type) + 1; + if (len_plus_ext > MAX_FNAME) + ext_pos = len - (len_plus_ext - MAX_FNAME); else - ext_pos = bin_name_len; - strcpy(app_name, bin_name); + ext_pos = len; + strcpy(app_name, name); app_name[ext_pos] = '.'; strcpy(&app_name[ext_pos + 1], type); } +static void prv_make_app_name(const char *type) +{ + prv_make_app_name_gen(type, bin_name, bin_name_len); +} + static uint8_t *prv_write_address(uint8_t *ptr, const char *address) { *ptr++ = 0xb0; /* VAL */ @@ -296,20 +324,10 @@ static specasm_handle_t prv_open_bin_e(uint16_t *bin_size) return 0; } -static void prv_make_bas_e(void) +static void prv_create_bas_file_e(void) { specasm_handle_t f; - uint16_t bin_size; - - /* Check bin file exists and is not too big. */ - - f = prv_open_bin_e(&bin_size); - if (err_type != SPECASM_ERROR_OK) - return; - specasm_file_close_e(f); - err_type = SPECASM_ERROR_OK; - prv_make_app_name("bas"); #ifdef SPECASM_TARGET_NEXT prv_make_basic_file(0, bin_name, bin_name_len); #else @@ -337,6 +355,94 @@ static void prv_make_bas_e(void) specasm_remove_file(app_name); } +static void prv_make_bas_e(void) +{ + specasm_handle_t f; + uint16_t bin_size; + + /* Check bin file exists and is not too big. */ + + f = prv_open_bin_e(&bin_size); + if (err_type != SPECASM_ERROR_OK) + return; + specasm_file_close_e(f); + err_type = SPECASM_ERROR_OK; + + prv_make_app_name("bas"); + prv_create_bas_file_e(); +} + +#ifndef SPECASM_TARGET_NEXT +static void prv_make_mac_e(const char *apn) +{ + specasm_handle_t f; + uint16_t bin_size; + + /* Check bin file exists and is not too big. */ + + f = prv_open_bin_e(&bin_size); + if (err_type != SPECASM_ERROR_OK) + return; + specasm_file_close_e(f); + err_type = SPECASM_ERROR_OK; + + if (!strchr(apn, '.')) { + prv_make_app_name_gen("bas", apn, strlen(apn)); + } else { + if (strlen(apn) > MAX_FNAME) { + err_type = SPECASM_ERROR_BAD_FNAME; + return; + } + strcpy(app_name, apn); + } + + prv_create_bas_file_e(); +} + +/* + * For the next macros we're just going to copy a template file from + * the /specasm directory. We're not going to generate anything. The + * file is a little too large to encode in the samake binary. + */ + +#else +static void prv_copy_next_mac_e(const char *dir) +{ + specasm_handle_t in_f; + specasm_handle_t out_f; + + if (strcmp(dir, ".")) { + if (!strchr(dir, '.')) { + prv_make_app_name_gen("bas", dir, strlen(dir)); + } else { + if (strlen(dir) > MAX_FNAME) { + err_type = SPECASM_ERROR_BAD_FNAME; + return; + } + strcpy(app_name, dir); + } + } else { + strcpy(app_name, "mac.bas"); + } + + in_f = specasm_file_ropen_e("/specasm/MAC.BAS"); + if (err_type != SPECASM_ERROR_OK) + return; + + out_f = specasm_file_wopen_e(app_name); + if (err_type != SPECASM_ERROR_OK) { + specasm_file_close_e(in_f); + return; + } + + (void)prv_write_code_e(in_f, out_f, 0); + +on_error: + specasm_file_close_e(out_f); + specasm_file_close_e(in_f); +} +#endif + static void prv_make_basic_header(void) { uint8_t i; @@ -350,7 +456,8 @@ static void prv_make_basic_header(void) container.tap_block[2] = 0; /* Flag byte, 0 = header */ container.tap_block[3] = 0; /* Type byte, 0 = program */ - /* Copy the name of the BASIC file, we'll just use the bin file */ + /* Copy the name of the BASIC file, we'll just use the bin file + */ memset(&container.tap_block[4], ' ', 10); memcpy(&container.tap_block[4], bin_name, name_len); @@ -387,7 +494,8 @@ static void prv_make_code_header(uint16_t bin_size) container.tap_block[2] = 0; /* Flag byte, 0 = header */ container.tap_block[3] = 3; /* Type byte, 0 = program */ - /* Copy the name of the BASIC file, we'll just use the bin file */ + /* Copy the name of the BASIC file, we'll just use the bin file + */ memset(&container.tap_block[4], ' ', 10); memcpy(&container.tap_block[4], bin_name, name_len); @@ -412,10 +520,10 @@ static void prv_make_code_header(uint16_t bin_size) container.tap_block[23] = 0xff; } -static uint8_t prv_write_code_e(specasm_handle_t in_f, specasm_handle_t out_f) +static uint8_t prv_write_code_e(specasm_handle_t in_f, specasm_handle_t out_f, + uint8_t checksum) { uint16_t i; - uint8_t checksum = 0xff; size_t read; for (;;) { @@ -435,6 +543,207 @@ static uint8_t prv_write_code_e(specasm_handle_t in_f, specasm_handle_t out_f) return checksum; } +static void prv_make_ace_e(void) +{ + specasm_handle_t out_f; + specasm_handle_t in_f; + uint16_t bin_size; + uint16_t i; + uint16_t data_block_size; + uint8_t checksum = 0; + uint8_t ace_name_len = bin_name_len; + + prv_make_app_name("tap"); + in_f = prv_open_bin_e(&bin_size); + if (err_type != SPECASM_ERROR_OK) + return; + + if (ace_name_len > 10) + ace_name_len = 10; + + memset(&basic_buf[3], 0x20, 24); + basic_buf[0] = 26; /* header block size LSB */ + basic_buf[1] = 0; /* header block size MSB */ + basic_buf[2] = 32; /* file type (byte) */ + memcpy(&basic_buf[3], bin_name, ace_name_len); + memcpy(&basic_buf[13], &bin_size, sizeof(bin_size)); + memcpy(&basic_buf[15], &org_address, sizeof(org_address)); + + for (i = 2; i < 27; i++) + checksum ^= basic_buf[i]; + basic_buf[27] = checksum; + data_block_size = bin_size + 1; + memcpy(&basic_buf[28], &data_block_size, sizeof(data_block_size)); + + out_f = specasm_file_wopen_e(app_name); + if (err_type != SPECASM_ERROR_OK) { + specasm_file_close_e(in_f); + return; + } + + specasm_file_write_e(out_f, basic_buf, 30); + if (err_type != SPECASM_ERROR_OK) + goto on_error; + + /* + * Now write out code file and compute the checksum. + */ + + checksum = prv_write_code_e(in_f, out_f, 0); + if (err_type != SPECASM_ERROR_OK) + goto on_error; + + specasm_file_write_e(out_f, &checksum, 1); + if (err_type != SPECASM_ERROR_OK) + goto on_error; + + specasm_file_close_e(in_f); + specasm_file_close_e(out_f); + return; + +on_error: + specasm_file_close_e(in_f); + specasm_file_close_e(out_f); + specasm_remove_file(app_name); +} + +/* + * Template based on: + * https://github.com/McKlaud76/JACE-TAP-templates/blob/main/asm/AUTORUN_template.asm + */ + +/* clang-format off */ + +static const uint8_t aceauto_template[] = { + /* TAP Header Block (0-27). All data is constant */ + 0x1a, 0x00, 0x20, 'a', 'u', 't', 'o', 'r', + 'u', 'n', 0x20, 0x20, 0x20, 0x1f, 0x00, 0xe0, + 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0xbb, + + /* TAP Data Block (28-61). Binary file name and checksum are overwritten */ + 0x20, 0x00, 0x00, 'L', 'O', 'A', 'D', 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, /* Binary file name, offset 36 */ + 0x20, 'R', 'U', 'N', 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x00, /* checksum, offset 61 */ + + /* TAP Header Block (62-89). Binary file name, file length, STKBOT and checksum are overwritten */ + 0x1a, 0x00, 0x00, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, /* Binary file name, offset 65 */ + 0x00, 0x00, /* File length, offset 75 */ + 0x51, 0x3c, 0x58, 0x3c, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, + 0x00, 0x00, /* STKBOT, offset 87 */ + 0x00, /* checksum, offset 89 */ + + /* TAP Data Block (90-101). Data block length and word length overwritten */ + + 0x00, 0x00, /* Data block length, offset 90 */ + 'R', 'U', 0xce, + 0x00, 0x00, /* Word length, offset 95 */ + 0x49, 0x3c, 0x03, 0x5b, 0x3c + + /* Code starts here followed by checksum of entire data block. */ + }; + +/* clang-format on */ + +static void prv_make_autoace_e(void) +{ + specasm_handle_t out_f; + specasm_handle_t in_f; + uint16_t bin_size; + uint16_t i; + uint16_t word_size; + uint16_t stkbot; + uint8_t checksum; + uint8_t ace_name_len; + + if (org_address != 15451) { + printf("Bad ORG address %s, want 15451\n", start_address); + err_type = SAMAKE_ERROR_BAD_ORG; + return; + } + + prv_make_app_name("tap"); + in_f = prv_open_bin_e(&bin_size); + if (err_type != SPECASM_ERROR_OK) + return; + + memcpy(basic_buf, aceauto_template, sizeof(aceauto_template)); + + ace_name_len = bin_name_len; + if (ace_name_len > 10) + ace_name_len = 10; + + memcpy(&basic_buf[36], bin_name, ace_name_len); + + checksum = 0; + for (i = 30; i < 61; i++) + checksum ^= basic_buf[i]; + basic_buf[61] = checksum; + + memcpy(&basic_buf[65], bin_name, ace_name_len); + + word_size = bin_size + 10; + memcpy(&basic_buf[75], &word_size, sizeof(word_size)); + + stkbot = org_address + bin_size; + memcpy(&basic_buf[87], &stkbot, sizeof(stkbot)); + checksum = 0; + for (i = 64; i < 89; i++) + checksum ^= basic_buf[i]; + basic_buf[89] = checksum; + + /* + * length of block containing RUN word and code + */ + word_size++; + memcpy(&basic_buf[90], &word_size, sizeof(word_size)); + + /* + * length of word and code + */ + word_size -= 4; + memcpy(&basic_buf[95], &word_size, sizeof(word_size)); + + checksum = 0; + for (i = 92; i < 102; i++) + checksum ^= basic_buf[i]; + + out_f = specasm_file_wopen_e(app_name); + if (err_type != SPECASM_ERROR_OK) { + specasm_file_close_e(in_f); + return; + } + + specasm_file_write_e(out_f, basic_buf, 102); + if (err_type != SPECASM_ERROR_OK) + goto on_error; + + /* + * Now write out code file and compute the checksum. + */ + + checksum = prv_write_code_e(in_f, out_f, checksum); + if (err_type != SPECASM_ERROR_OK) + goto on_error; + + specasm_file_write_e(out_f, &checksum, 1); + if (err_type != SPECASM_ERROR_OK) + goto on_error; + + specasm_file_close_e(in_f); + specasm_file_close_e(out_f); + return; + +on_error: + specasm_file_close_e(in_f); + specasm_file_close_e(out_f); + specasm_remove_file(app_name); +} + static void prv_make_tap_e(void) { specasm_handle_t out_f; @@ -453,8 +762,8 @@ static void prv_make_tap_e(void) return; /* - * That's the header. Now we can write our BASIC program followed - * by the checksum. + * That's the header. Now we can write our BASIC program + * followed by the checksum. */ out_f = specasm_file_wopen_e(app_name); @@ -492,7 +801,7 @@ static void prv_make_tap_e(void) * Now write out code file and compute the checksum. */ - checksum = prv_write_code_e(in_f, out_f); + checksum = prv_write_code_e(in_f, out_f, 0xff); if (err_type != SPECASM_ERROR_OK) goto on_error; @@ -599,11 +908,11 @@ static void prv_make_p_e(void) uint16_t i; const uint8_t loader[] = {118, 0, 2, 11, 0, 249, 212, 197, - 11, 29, 34, 33, 29, 32, 11, 118}; + 11, 29, 34, 33, 29, 32, 11, 118}; const uint8_t footer[] = {118, 128}; if (got_org && strcmp(start_address, "16514")) { - printf("Bad ORG address %s, want 16514", start_address); + printf("Bad ORG address %s, want 16514\n", start_address); err_type = SAMAKE_ERROR_BAD_ORG; return; } @@ -626,7 +935,7 @@ static void prv_make_p_e(void) if (err_type != SPECASM_ERROR_OK) goto on_error; - (void)prv_write_code_e(in_f, out_f); + (void)prv_write_code_e(in_f, out_f, 0xff); if (err_type != SPECASM_ERROR_OK) goto on_error; @@ -926,9 +1235,22 @@ static void prv_make_tst_e(void) static void prv_make_e(const char *dir, uint8_t target_type) { - prv_find_bin_name_e(dir, target_type); - if (err_type != SPECASM_ERROR_OK) + const char *apn; + + if (target_type == SAMAKE_TARGET_TYPE_MAC) { +#ifdef SPECASM_TARGET_NEXT + prv_copy_next_mac_e(dir); return; +#else + strcpy(bin_name, samac_name); + bin_name_len = strlen(samac_name); + prv_set_org_address(SAMAC_ORG_ADDRESS); +#endif + } else { + prv_find_bin_name_e(dir, target_type); + if (err_type != SPECASM_ERROR_OK) + return; + } if (got_zx81 && (target_type != SAMAKE_TARGET_TYPE_P) && (target_type != SAMAKE_TARGET_TYPE_NONE)) { @@ -938,12 +1260,13 @@ static void prv_make_e(const char *dir, uint8_t target_type) } /* - * We could perform the opposite check here, that if you select p - * and your program doesn't include the zx81 directive then we report - * an error. The thing is though that this should still work, providing - * you set the org correctly and do the character conversion yourself. - * This might actually be something you want to do if you have some - * existing code that does the conversion at runtime. + * We could perform the opposite check here, that if you select + * p and your program doesn't include the zx81 directive then we + * report an error. The thing is though that this should still + * work, providing you set the org correctly and do the + * character conversion yourself. This might actually be + * something you want to do if you have some existing code that + * does the conversion at runtime. */ if (target_type == SAMAKE_TARGET_TYPE_NONE) @@ -951,25 +1274,46 @@ static void prv_make_e(const char *dir, uint8_t target_type) got_zx81 ? SAMAKE_TARGET_TYPE_P : SAMAKE_TARGET_TYPE_BAS; /* - * TODO, this check isn't really correct. Ideally we'd add the loading - * address of BASIC program and the size of the BASIC program and check - * that the resulting value isn't greater than org_address, but I can't - * figure out whether there's a fixed starting address for BASIC - * programs, so for now let's just print a warning. It's mainly there - * to stop people creating a loader for a dot program. + * TODO, this check isn't really correct. Ideally we'd add the + * loading address of BASIC program and the size of the BASIC + * program and check that the resulting value isn't greater than + * org_address, but I can't figure out whether there's a fixed + * starting address for BASIC programs, so for now let's just + * print a warning. It's mainly there to stop people creating a + * loader for a dot program. */ - if ((target_type != SAMAKE_TARGET_TYPE_P) && (org_address < 24000)) - printf("Warning: org %" PRIu16 " is very low\n", org_address); + if (org_address < 24000) { + switch (target_type) { + case SAMAKE_TARGET_TYPE_BAS: + case SAMAKE_TARGET_TYPE_TAP: + case SAMAKE_TARGET_TYPE_TST: + printf("Warning: org %" PRIu16 " is very low\n", + org_address); + break; + default: + break; + } + } - if (target_type == SAMAKE_TARGET_TYPE_BAS) + if (target_type == SAMAKE_TARGET_TYPE_ACE) { + prv_make_ace_e(); + } else if (target_type == SAMAKE_TARGET_TYPE_AUTOACE) { + prv_make_autoace_e(); + } else if (target_type == SAMAKE_TARGET_TYPE_BAS) { prv_make_bas_e(); - else if (target_type == SAMAKE_TARGET_TYPE_TAP) +#ifndef SPECASM_TARGET_NEXT + } else if (target_type == SAMAKE_TARGET_TYPE_MAC) { + apn = strcmp(dir, ".") ? dir : "mac"; + prv_make_mac_e(apn); +#endif + } else if (target_type == SAMAKE_TARGET_TYPE_TAP) { prv_make_tap_e(); - else if (target_type == SAMAKE_TARGET_TYPE_P) + } else if (target_type == SAMAKE_TARGET_TYPE_P) { prv_make_p_e(); - else + } else { prv_make_tst_e(); + } } int main(int argc, char *argv[]) @@ -998,6 +1342,12 @@ int main(int argc, char *argv[]) target_type = SAMAKE_TARGET_TYPE_BAS; } else if (!strcmp(argv[1], "tst")) { target_type = SAMAKE_TARGET_TYPE_TST; + } else if (!strcmp(argv[1], "mac")) { + target_type = SAMAKE_TARGET_TYPE_MAC; + } else if (!strcmp(argv[1], "ace")) { + target_type = SAMAKE_TARGET_TYPE_ACE; + } else if (!strcmp(argv[1], "autoace")) { + target_type = SAMAKE_TARGET_TYPE_AUTOACE; } else { err_type = SAMAKE_ERROR_USAGE; goto on_error; @@ -1014,10 +1364,14 @@ int main(int argc, char *argv[]) on_error: if (err_type != SPECASM_ERROR_OK) { - if (err_type < SPECASM_MAX_ERRORS) + if (err_type < SPECASM_MAX_ERRORS) { printf("%s\n", specasm_error_msg(err_type)); - else if (err_type == SAMAKE_ERROR_USAGE) - printf("Usage: samake (bas|tap) [dir]\n"); + } else if (err_type == SAMAKE_ERROR_USAGE) { + printf("Usage:\n"); + printf(" samake (bas|tap|p|tst) [dir]\n"); + printf(" samake (ace|autoace) [dir]\n"); + printf(" samake mac [macro filename]\n"); + } ret = 1; } else { printf("Created %s\n", app_name); diff --git a/src/specasm_trampolines_128.c b/src/specasm_trampolines_128.c index 9debf3c..09f778f 100644 --- a/src/specasm_trampolines_128.c +++ b/src/specasm_trampolines_128.c @@ -23,13 +23,15 @@ static uint8_t banks[] = { 0 + 16, 1 + 16, 4 + 16, - 6 + 16 + 6 + 16, + 3 + 16 }; #define SPECASM_128_PARSE_BANK 0 #define SPECASM_128_CLIP_BANK 1 #define SPECASM_128_DUMP_BANK 2 #define SPECASM_128_EDITOR_BANK 3 +#define SPECASM_128_HELP_BANK 4 #ifdef UNITTESTS #define SPECASM_128_UNIT_BANK 3 @@ -56,6 +58,7 @@ void specasm_format_line_banked_e(char *buf, unsigned int l); void specasm_draw_status_banked(void); void specasm_handle_key_press_banked(uint8_t k); void specasm_editor_reset_banked(void); +void specasm_help_banked(const char *ins_name); #ifdef UNITTESTS void specasm_peer_write_state_banked_e(const char *fname, uint16_t checksum); @@ -73,6 +76,7 @@ void specasm_trampolines_init(void) banks[SPECASM_128_CLIP_BANK] = 4 + 16; banks[SPECASM_128_DUMP_BANK] = 1 + 16; banks[SPECASM_128_EDITOR_BANK] = 3 + 16; + banks[SPECASM_128_HELP_BANK] = 6 + 16; } /* clang-format off */ @@ -270,6 +274,15 @@ void specasm_editor_reset(void) specasm_editor_reset_banked(); (void) prv_map_bank(bank); } + +void specasm_help(const char *ins_name) +{ + uint8_t bank; + + bank = prv_map_bank(banks[SPECASM_128_HELP_BANK]); + specasm_help_banked(ins_name); + (void) prv_map_bank(bank); +} #else void specasm_peer_write_state_e(const char *fname, uint16_t checksum) { diff --git a/src/specasm_trampolines_next.c b/src/specasm_trampolines_next.c index 2775f82..44133f4 100644 --- a/src/specasm_trampolines_next.c +++ b/src/specasm_trampolines_next.c @@ -12,7 +12,7 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. -*/ + */ #include #include @@ -23,6 +23,9 @@ #define SPECASM_NEXT_DUMP_BANK (44 << 1) #define SPECASM_NEXT_EDITOR_BANK (45 << 1) #define SPECASM_NEXT_CLIP_BANK (46 << 1) +#define SPECASM_NEXT_HELP_BANK (47 << 1) +#define SPECASM_NEXT_HELP_AL_BANK (47 << 1) + 1 +#define SPECASM_NEXT_HELP_MZ_BANK (48 << 1) + 1 #ifdef UNITTESTS #define SPECASM_NEXT_UNIT_BANK (45 << 1) @@ -51,6 +54,7 @@ void specasm_draw_status_banked(void); void specasm_handle_key_press_banked(uint8_t k); void specasm_editor_reset_banked(void); void specasm_editor_preload_banked(const char *fname); +void specasm_help_banked(const char *ins_name); #ifdef UNITTESTS void specasm_peer_write_state_banked_e(const char *fname, uint16_t checksum); @@ -64,7 +68,7 @@ char *specasm_get_long_imm_e(const char *str, long *val, uint8_t *flags) char *e; ZXN_WRITE_MMU6(_z_page_table[SPECASM_NEXT_PARSE_BANK]); - ZXN_WRITE_MMU7(_z_page_table[SPECASM_NEXT_PARSE_BANK+1]); + ZXN_WRITE_MMU7(_z_page_table[SPECASM_NEXT_PARSE_BANK + 1]); e = specasm_get_long_imm_banked_e(str, val, flags); ZXN_WRITE_MMU7(bank_h); ZXN_WRITE_MMU6(bank_l); @@ -72,14 +76,13 @@ char *specasm_get_long_imm_e(const char *str, long *val, uint8_t *flags) return e; } - void specasm_append_empty_line_e(void) { unsigned char bank_l = ZXN_READ_MMU6(); unsigned char bank_h = ZXN_READ_MMU7(); ZXN_WRITE_MMU6(_z_page_table[SPECASM_NEXT_PARSE_BANK]); - ZXN_WRITE_MMU7(_z_page_table[SPECASM_NEXT_PARSE_BANK+1]); + ZXN_WRITE_MMU7(_z_page_table[SPECASM_NEXT_PARSE_BANK + 1]); specasm_append_empty_line_banked_e(); ZXN_WRITE_MMU7(bank_h); ZXN_WRITE_MMU6(bank_l); @@ -91,7 +94,7 @@ void specasm_delete_lines(unsigned int start, unsigned int end) unsigned char bank_h = ZXN_READ_MMU7(); ZXN_WRITE_MMU6(_z_page_table[SPECASM_NEXT_PARSE_BANK]); - ZXN_WRITE_MMU7(_z_page_table[SPECASM_NEXT_PARSE_BANK+1]); + ZXN_WRITE_MMU7(_z_page_table[SPECASM_NEXT_PARSE_BANK + 1]); specasm_delete_lines_banked(start, end); ZXN_WRITE_MMU7(bank_h); ZXN_WRITE_MMU6(bank_l); @@ -103,7 +106,7 @@ void specasm_insert_lines_e(unsigned int l, unsigned int count) unsigned char bank_h = ZXN_READ_MMU7(); ZXN_WRITE_MMU6(_z_page_table[SPECASM_NEXT_PARSE_BANK]); - ZXN_WRITE_MMU7(_z_page_table[SPECASM_NEXT_PARSE_BANK+1]); + ZXN_WRITE_MMU7(_z_page_table[SPECASM_NEXT_PARSE_BANK + 1]); specasm_insert_lines_banked_e(l, count); ZXN_WRITE_MMU7(bank_h); ZXN_WRITE_MMU6(bank_l); @@ -115,7 +118,7 @@ void specasm_parse_line_e(unsigned int l, const char *str) unsigned char bank_h = ZXN_READ_MMU7(); ZXN_WRITE_MMU6(_z_page_table[SPECASM_NEXT_PARSE_BANK]); - ZXN_WRITE_MMU7(_z_page_table[SPECASM_NEXT_PARSE_BANK+1]); + ZXN_WRITE_MMU7(_z_page_table[SPECASM_NEXT_PARSE_BANK + 1]); specasm_parse_line_banked_e(l, str); ZXN_WRITE_MMU7(bank_h); ZXN_WRITE_MMU6(bank_l); @@ -130,7 +133,7 @@ uint8_t specasm_parse_mnemomic_e(const char *str, uint8_t i, unsigned char bank_h = ZXN_READ_MMU7(); ZXN_WRITE_MMU6(_z_page_table[SPECASM_NEXT_PARSE_BANK]); - ZXN_WRITE_MMU7(_z_page_table[SPECASM_NEXT_PARSE_BANK+1]); + ZXN_WRITE_MMU7(_z_page_table[SPECASM_NEXT_PARSE_BANK + 1]); e = specasm_parse_mnemomic_banked_e(str, i, line); ZXN_WRITE_MMU7(bank_h); ZXN_WRITE_MMU6(bank_l); @@ -145,7 +148,7 @@ void specasm_init_dump_table(void) unsigned char bank_h = ZXN_READ_MMU7(); ZXN_WRITE_MMU6(_z_page_table[SPECASM_NEXT_DUMP_BANK]); - ZXN_WRITE_MMU7(_z_page_table[SPECASM_NEXT_DUMP_BANK+1]); + ZXN_WRITE_MMU7(_z_page_table[SPECASM_NEXT_DUMP_BANK + 1]); specasm_init_dump_table_banked(); ZXN_WRITE_MMU7(bank_h); ZXN_WRITE_MMU6(bank_l); @@ -159,7 +162,7 @@ uint8_t specasm_dump_opcode_e(const specasm_line_t *line, char *buf) unsigned char bank_h = ZXN_READ_MMU7(); ZXN_WRITE_MMU6(_z_page_table[SPECASM_NEXT_DUMP_BANK]); - ZXN_WRITE_MMU7(_z_page_table[SPECASM_NEXT_DUMP_BANK+1]); + ZXN_WRITE_MMU7(_z_page_table[SPECASM_NEXT_DUMP_BANK + 1]); e = specasm_dump_opcode_banked_e(line, buf); ZXN_WRITE_MMU7(bank_h); ZXN_WRITE_MMU6(bank_l); @@ -174,7 +177,7 @@ void specasm_format_line_e(char *buf, unsigned int l) unsigned char bank_h = ZXN_READ_MMU7(); ZXN_WRITE_MMU6(_z_page_table[SPECASM_NEXT_DUMP_BANK]); - ZXN_WRITE_MMU7(_z_page_table[SPECASM_NEXT_DUMP_BANK+1]); + ZXN_WRITE_MMU7(_z_page_table[SPECASM_NEXT_DUMP_BANK + 1]); specasm_format_line_banked_e(buf, l); ZXN_WRITE_MMU7(bank_h); ZXN_WRITE_MMU6(bank_l); @@ -186,7 +189,7 @@ void specasm_clip_reset(void) unsigned char bank_h = ZXN_READ_MMU7(); ZXN_WRITE_MMU6(_z_page_table[SPECASM_NEXT_CLIP_BANK]); - ZXN_WRITE_MMU7(_z_page_table[SPECASM_NEXT_CLIP_BANK+1]); + ZXN_WRITE_MMU7(_z_page_table[SPECASM_NEXT_CLIP_BANK + 1]); specasm_clip_reset_banked(); ZXN_WRITE_MMU7(bank_h); ZXN_WRITE_MMU6(bank_l); @@ -198,7 +201,7 @@ void specasm_clip_add_line_e(const char *line) unsigned char bank_h = ZXN_READ_MMU7(); ZXN_WRITE_MMU6(_z_page_table[SPECASM_NEXT_CLIP_BANK]); - ZXN_WRITE_MMU7(_z_page_table[SPECASM_NEXT_CLIP_BANK+1]); + ZXN_WRITE_MMU7(_z_page_table[SPECASM_NEXT_CLIP_BANK + 1]); specasm_clip_add_line_banked_e(line); ZXN_WRITE_MMU7(bank_h); ZXN_WRITE_MMU6(bank_l); @@ -211,7 +214,7 @@ uint16_t specasm_clip_get_line(uint16_t ptr, char *buffer) unsigned char bank_h = ZXN_READ_MMU7(); ZXN_WRITE_MMU6(_z_page_table[SPECASM_NEXT_CLIP_BANK]); - ZXN_WRITE_MMU7(_z_page_table[SPECASM_NEXT_CLIP_BANK+1]); + ZXN_WRITE_MMU7(_z_page_table[SPECASM_NEXT_CLIP_BANK + 1]); e = specasm_clip_get_line_banked(ptr, buffer); ZXN_WRITE_MMU7(bank_h); ZXN_WRITE_MMU6(bank_l); @@ -226,7 +229,7 @@ uint16_t specasm_clip_get_line_count(void) unsigned char bank_h = ZXN_READ_MMU7(); ZXN_WRITE_MMU6(_z_page_table[SPECASM_NEXT_CLIP_BANK]); - ZXN_WRITE_MMU7(_z_page_table[SPECASM_NEXT_CLIP_BANK+1]); + ZXN_WRITE_MMU7(_z_page_table[SPECASM_NEXT_CLIP_BANK + 1]); e = specasm_clip_get_line_count_banked(); ZXN_WRITE_MMU7(bank_h); ZXN_WRITE_MMU6(bank_l); @@ -241,7 +244,7 @@ void specasm_draw_status(void) unsigned char bank_h = ZXN_READ_MMU7(); ZXN_WRITE_MMU6(_z_page_table[SPECASM_NEXT_EDITOR_BANK]); - ZXN_WRITE_MMU7(_z_page_table[SPECASM_NEXT_EDITOR_BANK+1]); + ZXN_WRITE_MMU7(_z_page_table[SPECASM_NEXT_EDITOR_BANK + 1]); specasm_draw_status_banked(); ZXN_WRITE_MMU7(bank_h); ZXN_WRITE_MMU6(bank_l); @@ -253,7 +256,7 @@ void specasm_handle_key_press(uint8_t k) unsigned char bank_h = ZXN_READ_MMU7(); ZXN_WRITE_MMU6(_z_page_table[SPECASM_NEXT_EDITOR_BANK]); - ZXN_WRITE_MMU7(_z_page_table[SPECASM_NEXT_EDITOR_BANK+1]); + ZXN_WRITE_MMU7(_z_page_table[SPECASM_NEXT_EDITOR_BANK + 1]); specasm_handle_key_press_banked(k); ZXN_WRITE_MMU7(bank_h); ZXN_WRITE_MMU6(bank_l); @@ -265,7 +268,7 @@ void specasm_editor_reset(void) unsigned char bank_h = ZXN_READ_MMU7(); ZXN_WRITE_MMU6(_z_page_table[SPECASM_NEXT_EDITOR_BANK]); - ZXN_WRITE_MMU7(_z_page_table[SPECASM_NEXT_EDITOR_BANK+1]); + ZXN_WRITE_MMU7(_z_page_table[SPECASM_NEXT_EDITOR_BANK + 1]); specasm_editor_reset_banked(); ZXN_WRITE_MMU7(bank_h); ZXN_WRITE_MMU6(bank_l); @@ -277,11 +280,32 @@ void specasm_editor_preload(const char *fname) unsigned char bank_h = ZXN_READ_MMU7(); ZXN_WRITE_MMU6(_z_page_table[SPECASM_NEXT_EDITOR_BANK]); - ZXN_WRITE_MMU7(_z_page_table[SPECASM_NEXT_EDITOR_BANK+1]); + ZXN_WRITE_MMU7(_z_page_table[SPECASM_NEXT_EDITOR_BANK + 1]); specasm_editor_preload_banked(fname); ZXN_WRITE_MMU7(bank_h); ZXN_WRITE_MMU6(bank_l); } + +void specasm_descr_bank(const char *ins_name) +{ + unsigned char bank = (ins_name[0] == 0 || ins_name[0] < 'm') + ? SPECASM_NEXT_HELP_AL_BANK + : SPECASM_NEXT_HELP_MZ_BANK; + ZXN_WRITE_MMU7(_z_page_table[bank]); +} + +void specasm_help(const char *ins_name) +{ + unsigned char bank_l = ZXN_READ_MMU6(); + unsigned char bank_h = ZXN_READ_MMU7(); + + ZXN_WRITE_MMU6(_z_page_table[SPECASM_NEXT_HELP_BANK]); + /* We'll set MMU7 when we're displaying the description. */ + specasm_help_banked(ins_name); + ZXN_WRITE_MMU7(bank_h); + ZXN_WRITE_MMU6(bank_l); +} + #else void specasm_peer_write_state_e(const char *fname, uint16_t checksum) { @@ -289,7 +313,7 @@ void specasm_peer_write_state_e(const char *fname, uint16_t checksum) unsigned char bank_h = ZXN_READ_MMU7(); ZXN_WRITE_MMU6(_z_page_table[SPECASM_NEXT_UNIT_BANK]); - ZXN_WRITE_MMU7(_z_page_table[SPECASM_NEXT_UNIT_BANK+1]); + ZXN_WRITE_MMU7(_z_page_table[SPECASM_NEXT_UNIT_BANK + 1]); specasm_peer_write_state_banked_e(fname, checksum); ZXN_WRITE_MMU7(bank_h); ZXN_WRITE_MMU6(bank_l); @@ -302,7 +326,7 @@ uint16_t specasm_peer_read_state_e(const char *fname) unsigned char bank_h = ZXN_READ_MMU7(); ZXN_WRITE_MMU6(_z_page_table[SPECASM_NEXT_UNIT_BANK]); - ZXN_WRITE_MMU7(_z_page_table[SPECASM_NEXT_UNIT_BANK+1]); + ZXN_WRITE_MMU7(_z_page_table[SPECASM_NEXT_UNIT_BANK + 1]); e = specasm_peer_read_state_banked_e(fname); ZXN_WRITE_MMU7(bank_h); ZXN_WRITE_MMU6(bank_l); diff --git a/src/state_base.c b/src/state_base.c index 6792e44..180c384 100644 --- a/src/state_base.c +++ b/src/state_base.c @@ -21,6 +21,7 @@ #include "state_base.h" specasm_state_t state; +specasm_error_t err_type; void specasm_state_reset(void) { diff --git a/src/state_base.h b/src/state_base.h index 73e721a..c6a9459 100644 --- a/src/state_base.h +++ b/src/state_base.h @@ -12,17 +12,17 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. -*/ + */ #ifndef SPECASM_STATE_READ_H #define SPECASM_STATE_READ_H #ifdef SPECASM_TARGET_NEXT_OPCODES -#define SPECASM_VERSION 0x800a -#define SPECASM_VERSION_STR "v10n" +#define SPECASM_VERSION 0x800b +#define SPECASM_VERSION_STR "v11n" #else -#define SPECASM_VERSION 10 -#define SPECASM_VERSION_STR "v10" +#define SPECASM_VERSION 11 +#define SPECASM_VERSION_STR "v11" #endif #include