dmagnetic-0.22/0000755000175000017500000000000013621220610012763 5ustar dettusdettusdmagnetic-0.22/LICENSE.txt0000644000175000017500000000241413621220604014612 0ustar dettusdettusCopyright 2019, dettus@dettus.net Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. dmagnetic-0.22/debug.sh0000644000175000017500000000010413621220604014403 0ustar dettusdettus#!/bin/sh gdb -tui --args ./dMagnetic -ini dMagnetic.ini corruption dmagnetic-0.22/testcode/0000755000175000017500000000000013621220604014600 5ustar dettusdettusdmagnetic-0.22/testcode/minitest.mag0000644000175000017500000000062013621220604017120 0ustar dettusdettusMaSc*f<<r<o<o<m< <X<<<<V<i<r<t<u<a<l< <m<a<c<h<i<n<e< <i<s< <r<u<n<n<i<n<g<.< <P<l<e<a<s<e< <p<r<e<s<s< <E<n<t<e<r<.< <>< dmagnetic-0.22/testcode/expected.log.bz20000644000175000017500000000150413621220604017600 0ustar dettusdettusBZh91AY&SY(j*^PX'Wb?QhڃLI@zi`QOSQ4hOTHhmM2fOG4C@ d4a10&4RѠ4CFD` 7*{P0TUEu-<+h^ aB"c9ctºZ]2. #FSMԝ=QՆ6gu׹]{jזZSV^ٚ&4==Mѥww, H ă H1 ă H1 ă H1 ă H 1D!EB4^ėR_K0$ş #include #include "vm68k.h" #include "linea.h" #include "default_callbacks.h" #define MAXMAGSIZE (1<<20) #define MAXGFXSIZE (1<<22) int main(int argc,char** argv) { FILE *f; int sizevm68k; int sizelineA; int sizeGUI; int retval=0; unsigned char* magloader; int magsize; unsigned char* gfxloader; int gfxsize; void *hVM68k; void *hLineA; void *hGUI; unsigned char* sharedMem; int unknownopcode; fprintf(stderr,"*** dMagnetic- magtest\n"); fprintf(stderr,"*** Use at your own risk\n"); fprintf(stderr,"*** (C)opyright 2019 by dettus@dettus.net\n"); fprintf(stderr,"*****************************************\n"); fprintf(stderr,"\n"); if (argc!=3) { fprintf(stderr,"Please run with %s MAGFILE.mag GFXFILE.gfx\n",argv[0]); fprintf(stderr," where MAGFILE.mag/GFXFILE.gfx is one of\n"); fprintf(stderr," pawn.mag pawn.gfx\n"); exit(0); } magloader=malloc((MAXMAGSIZE));fprintf(stderr,"allocating %7d bytes for loading mag files\n",(MAXMAGSIZE)); f=fopen(argv[1],"rb"); if (f==NULL) { fprintf(stderr,"error opening file %s\n",argv[1]); exit(0); } magsize=fread(magloader,sizeof(char),(MAXMAGSIZE),f); fclose(f); gfxloader=malloc((MAXGFXSIZE));fprintf(stderr,"allocating %7d bytes for loading gfx files\n",(MAXGFXSIZE)); f=fopen(argv[2],"rb"); if (f==NULL) { fprintf(stderr,"error opening file %s\n",argv[2]); exit(0); } gfxsize=fread(gfxloader,sizeof(char),(MAXGFXSIZE),f); fclose(f); retval=vm68k_getsize(&sizevm68k); retval=lineA_getsize(&sizelineA); retval=default_getsize(&sizeGUI); if (retval) {fprintf(stderr,"getsize returned %d\n",retval);exit(0);} hVM68k=malloc(sizevm68k);fprintf(stderr,"allocating %7d bytes for 68000 core\n",sizevm68k); hLineA=malloc(sizelineA);fprintf(stderr,"allocating %7d bytes for lineA core\n",sizelineA); hGUI=malloc(sizeGUI);fprintf(stderr,"allocating %7d bytes for the GUI\n",sizeGUI); sharedMem=malloc(65536);fprintf(stderr,"allocating %7d bytes for shared mem\n",65536); retval=vm68k_init(hVM68k,sharedMem,65536,0); retval=lineA_init(hLineA,sharedMem,65536,magloader,magsize,gfxloader,gfxsize); retval=default_open(hGUI,NULL,argc,argv); retval=lineA_setCBoutputChar(hLineA,default_cbOutputChar, hGUI); retval=lineA_setCBoutputString(hLineA,default_cbOutputString, hGUI); retval=lineA_setCBinputString(hLineA,default_cbInputString, hGUI); retval=lineA_setCBDrawPicture(hLineA,default_cbDrawPicture, hGUI); retval=lineA_setCBLoadGame(hLineA,default_cbLoadGame, hGUI); retval=lineA_setCBSaveGame(hLineA,default_cbSaveGame, hGUI); // the mag and gfx buffers are no longer necessary free(gfxloader); free(magloader); do { unsigned short opcode; unknownopcode=0; retval=vm68k_getNextOpcode(hVM68k,&opcode); if (retval==VM68K_OK) retval=lineA_substitute_aliases(hLineA,&opcode); if (retval==LINEA_OK) retval=vm68k_singlestep(hVM68k,opcode); if (retval!=VM68K_OK) retval=lineA_singlestep(hLineA,hVM68k,opcode); if (retval!=LINEA_OK && retval!=LINEA_OK_QUIT) { printf("\x1b[0m\n\x1b[0;37;44m unknown opcode %04X\x1b[0m\n",opcode); unknownopcode=1; } if (retval==LINEA_OK_QUIT) printf("\x1b[0m\n\x1b[0;37;44mGoodbye!\x1b[0m\n"); } while (!unknownopcode && !retval); } dmagnetic-0.22/testcode/instmatcher.c0000644000175000017500000000060313621220604017264 0ustar dettusdettus#include #include #include "vm68k_datatypes.h" #include "vm68k_decode.h" int main(int argc,char** argv) { int i; tVM68k_instruction inst; char name[16]; for (i=0;i<0xffff;i++) { vm68k_get_instructionname(vm68k_decode(i),name); printf("%04X: %s\n",i,name); } i=0x0880; vm68k_get_instructionname(vm68k_decode(i),name); printf("%04X: %s\n",i,name); } dmagnetic-0.22/testcode/runtest.sh0000755000175000017500000000040513621220604016642 0ustar dettusdettus#!/bin/sh echo "If all goes well, this script should say nothing." bzcat expected.log.bz2 >/tmp/expected.log ( echo "HELLO world" | ../dMagnetic -vcols 300 -vrows 300 -vmode high_ansi -vecho -mag minitest.mag )>/tmp/is.log diff /tmp/expected.log /tmp/is.log dmagnetic-0.22/testcode/gfxtest.c0000644000175000017500000000561413621220604016436 0ustar dettusdettus/* Copyright 2019, dettus@dettus.net Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include "picture.h" #include "gfx1loader.h" #define MAXGFXSIZE (1<<22) int main(int argc,char** argv) { FILE *f; int picnum; int i,j; void* gfxloader; int gfxsize; #define MAXXPM (1<<20) char* xpm; tPicture picture; fprintf(stderr,"*** dMagnetic- magtest\n"); fprintf(stderr,"*** Use at your own risk\n"); fprintf(stderr,"*** (C)opyright 2019 by dettus@dettus.net\n"); fprintf(stderr,"*****************************************\n"); fprintf(stderr,"\n"); if (argc!=3) { fprintf(stderr,"please run with %s GFXFILE.gfx PICNUM >output.xpm\n",argv[0]); return 0; } gfxloader=malloc(MAXGFXSIZE); picnum=atoi(argv[2]); f=fopen(argv[1],"rb"); gfxsize=fread(gfxloader,sizeof(char),MAXGFXSIZE,f); fclose(f); gfxloader_unpackpic(gfxloader,gfxsize,0,picnum,NULL,&picture); xpm=malloc(MAXXPM); gfxloader_picture2xpm(&picture,xpm,MAXXPM); #if 0 printf("/* XPM */\n"); printf("static char *xpm[] = {\n"); printf("/* columns rows colors chars-per-pixel */\n"); printf("\"%d %d 16 1 \",\n",picture.width,picture.height); for (i=0;i<16;i++) { printf("\"%c c #",i+'A'); printf("%02X",((picture.palette[i]>>8)&0x7)*0x24); printf("%02X",((picture.palette[i]>>4)&0x7)*0x24); printf("%02X",((picture.palette[i]>>0)&0x7)*0x24); printf("\",\n"); } printf("/* pixels */\n"); for (i=0;i. Pressing Enter should close dMagnetic. dmagnetic-0.22/testcode/minitest.gfx0000644000175000017500000000311013621220604017135 0ustar dettusdettusMaPiHdP0UU33s377wwWF肆  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVs jDl!0F˜#bCd`͚6|EBY"QrEB"QrEB"QrEB"QrEB"QrEB"QrEB"EE4 i ѼTZ*$)$TZ*.SBQhQhMEBEE3 jIcorruption_zwei.txt #cat corrupt.txt | ./dMagnetic -ini dMagnetic.ini corruption >corruption_zwei.txt #cat fish.txt | ./dMagnetic -ini dMagnetic.ini fish | tee fish_zwei.txt cat wonderland3.txt | ./dMagnetic -ini dMagnetic.ini wonderland | tee wonderland_zwei.txt dmagnetic-0.22/dMagnetic.ini0000644000175000017500000000321513621220604015363 0ustar dettusdettus;; you can download the files from https://msmemorial.if-legends.org/magnetic.php [FILES] pawnmag=/usr/local/share/games/magneticscrolls/pawn.mag pawngfx=/usr/local/share/games/magneticscrolls/pawn.gfx ;pawnmsdos=/usr/local/share/games/magneticscrolls/msdosversions/PAWN guildmag=/usr/local/share/games/magneticscrolls/guild.mag guildgfx=/usr/local/share/games/magneticscrolls/guild.gfx ;guildmsdos=/usr/local/share/games/magneticscrolls/msdosversions/GUILD jinxtermag=/usr/local/share/games/magneticscrolls/jinxter.mag jinxtergfx=/usr/local/share/games/magneticscrolls/jinxter.gfx corruptionmag=/usr/local/share/games/magneticscrolls/ccorrupt.mag corruptiongfx=/usr/local/share/games/magneticscrolls/ccorrupt.gfx fishmag=/usr/local/share/games/magneticscrolls/fish.mag fishgfx=/usr/local/share/games/magneticscrolls/fish.gfx mythmag=/usr/local/share/games/magneticscrolls/myth.mag mythgfx=/usr/local/share/games/magneticscrolls/myth.gfx wonderlandmag=/usr/local/share/games/magneticscrolls/wonder.mag wonderlandgfx=/usr/local/share/games/magneticscrolls/wonder.gfx ;; to configure the random number generator [RANDOM] mode=pseudo ;mode=real seed=12345 [DEFAULTGUI] rows=40 columns=120 #align=left align=block #align=right ;mode=none ;mode=monochrome mode=low_ansi ;mode=high_ansi ;mode=high_ansi2 ;low_ansi_characters=\\/|= ;low_ansi_characters=Thomas low_ansi_characters=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789$()[]#<>&*!|/+\\{}@ ;low_ansi_characters=\\/=IMS ;; activate the next one for a black background monochrome_characters=\ .-=+*x#@$X ;; activate the next one for a white background ;monochrome_characters=X$#x*+=-. sixel_resolution=800x600 dmagnetic-0.22/dMagnetic.10000644000175000017500000001773413621220604014757 0ustar dettusdettus.\" Process this file with .\" groff -man -Tascii dMagnetic.1 .\" .Dd February 11th, 2020 .Os OpenBSD .Dt dMagnetic 1 . .Sh NAME .Nm dMagnetic .Nd A Magnetic Scrolls Interpreter . . .Sh INTRODUCTION You wake up on a sunny August morning with birds singing, and the air fresh and clear. However, your joints are stiff and you have not woken up in your bedroom as you would have expected. Trying to recall what happened the night before, you manage to piece together a few brief glimpses to give the following account... .Sh SYNOPSIS . .Nm .Op Fl mag Ar MAGFILE.mag .Op Fl gfx Ar GFXFILE.gfx .br .Nm .Op Fl msdosdir Ar DIRECTORY/ .Op Fl vmode Ar high_ansi2 .br .Nm .Op Fl tworsc Ar DIRECTORY/TWO.RSC .Op Fl vmode Ar high_ansi .br .Nm .Op Fl ini Ar ini-file .Op GAME .br .Nm .Op Fl ini Ar ini-file .Op GAME .Op Fl vrows Ar ROWS .Op Fl vcols Ar COLUMNS .br .Nm .Op Fl ini Ar ini-file .Op GAME .Op Fl vmode Ar none .br .Nm .Op Fl ini Ar ini-file .Op GAME .Op Fl vmode Ar monochrome .br .Nm .Op Fl ini Ar ini-file .Op GAME .Op Fl vmode Ar low_ansi .br .Nm .Op Fl ini Ar ini-file .Op GAME .Op Fl vmode Ar high_ansi .br .Nm .Op Fl ini Ar ini-file .Op GAME .Op Fl vmode Ar high_ansi2 .br .Nm .Op Fl ini Ar ini-file .Op GAME .Op Fl vmode Ar sixel .Op Fl sres Ar 1024x768 .br .Nm .Op Fl ini Ar ini-file .Op GAME .Op Fl valign Ar left .br .Nm .Op Fl vlog Ar LOGFILE .Op Fl vecho .Nm .Op Fl help .Op Fl helpini .Op Fl v .Op Fl bsd .Sh DESCRIPTION .Nm is an interpreter for classic text adventure games, or interactive fiction, such as "The Pawn" or "The Guild of Thieves". The following games are being supported: .Bl -tag -width 10 .It "The Pawn" .It "The Guild of Thieves" .It "Jinxter" .It "Fish!" .It "Myth" .It "Corruption" .It "Wonderland" .El . .Sh GAME BINARIES Currently, binaries in the .mag and .gfx format from the magnetic scrolls memorial at https://msmemorial.if-legends.org/memorial.php are being supported. Once downloaded, their position has to be made available to .Nm by editing dMagnetic.ini first. .Sh STARTING THE GAME Once the game(s) have been downloaded, the .mag and .gfx files can be provided via .Pp .Nm -mag pawn.mag -gfx pawn.gfx .Pp Alternatively, binaries from the MSDOS version of "The Pawn" or "The Guild of Thieves" can be used. The directory, in which they are, has to be provided via .Pp .Nm -msdosdir DIRECTORY/ -vmode high_ansi .Pp It is recommended to use the .Op Fl vmode Ar high_ansi2 option, since this renders the half-tone images slightly different. .Pp A third option is to use the resource files from "Wonderland" or the magnetic scrolls collection. For this, the location of the file ending with "TWO.RSC" has to be provided. .Pp .Nm -tworsc DIRECTORY/TWO.RSC -vmode high_ansi .br .Nm -tworsc DIRECTORY/GTWO.RSC -vmode high_ansi .br The names of the other resource files is being calculated from that. .Pp It is also possible to edit the dMagnetic.ini file and start a specific game, by using one of .Pp .Nm -ini dMagnetic.ini pawn .br .Nm -ini dMagnetic.ini guild .br .Nm -ini dMagnetic.ini jinxter .br .Nm -ini dMagnetic.ini corruption .br .Nm -ini dMagnetic.ini fish .br .Nm -ini dMagnetic.ini myth .br .Nm -ini dMagnetic.ini wonderland .Pp When you see the prompt, the game is ready to accept your commands. For example EXAMINE CLOTHES. Or GO EAST. Or ASK KRONOS ABOUT THE WRISTBAND. .br .Sh LEAVING THE GAME Type in "QUIT". Duh! .Sh SAVING/LOADING PROGRESS The game can be saved at any type by typing SAVE, and loaded by typing LOAD. Followed by a filename. .Pp SAVE myprogress1.sav .br LOAD myprogress1.sav .Sh TEXT ALIGNMENT Changing the alignment of the output text can be done with the .ini file or the commandline. .br .Nm Fl valign Ar left .br .Nm Fl valign Ar block .br .Nm Fl valign Ar right .br .Sh GRAPHIC MODES .Nm has been developed with ANSI-consoles in mind. To select a video output that best suits your needs, please try one of the following . .Pp .Nm .Op Fl ini Ar ini-file .Op GAME .Op Fl vmode Ar none .br .Nm .Op Fl ini Ar ini-file .Op GAME .Op Fl vmode Ar monochrome .br .Nm .Op Fl ini Ar ini-file .Op GAME .Op Fl vmode Ar low_ansi .br .Nm .Op Fl ini Ar ini-file .Op GAME .Op Fl vmode Ar high_ansi .br .Nm .Op Fl ini Ar ini-file .Op GAME .Op Fl vmode Ar high_ansi2 .br .Pp To change the number of rows/columns to render the images, use .Pp .Nm .Op Fl ini Ar ini-file .Op GAME .Op Fl vcols Ar COLUMNS .br .Nm .Op Fl ini Ar ini-file .Op GAME .Op Fl vrows Ar ROWS .Pp Sixels are a signalling mode for some terminal emulators (like mlterm, or xterm -ti vt340 , for example), that offer the possibility of drawing high resolution images. It can be selected with .Pp .Nm .Op Fl ini Ar ini-file .Op GAME .Op Fl vmode Ar sixel .Op Fl sres Ar 1024x768 .Pp where the -sres option offers a way to scale the images. The maximum allowed width is 1024 pixels. .Sh GRAPHICS IN WONDERLAND AND THE MAGNETIC SCROLLS COLLECTION Before you can see the beautiful graphics in "Wonderland", or from the Magnetic Scrolls Collection, you have to type in "graphics" to enable them. .Sh COMMAND LINE OPTIONS .Op Fl bsd .br Shows the license. .Pp .Op Fl Fl help .br Shows the detailed help. .Pp .Op Fl Fl helpini .br Shows an example for a working dMagnetic.ini file. .Pp .Op Fl mag Ar MAGFILE.mag .Op Fl gfx Ar GFXFILE.gfx .br .Pp .Op Fl msdosdir Ar DIRECTORY/ .br .Pp .Op Fl tworsc Ar DIRECTORY/TWO.RSC .br .Nm is a Magnetic Scrolls Interpreter. To actually play the games, their binaries have to be provided. Either in the .mag and .gfx format from https://msmemorial.if-legends.org/magnetic.php, as the name of the directory in which the original MS-DOS version can be found, or as the location and the name of the second resource file TWO.RSC. .Pp .Op Fl ini Ar dMagnetic.ini pawn .br .Op Fl ini Ar dMagnetic.ini guild .br .Op Fl ini Ar dMagnetic.ini jinxter .br .Op Fl ini Ar dMagnetic.ini corruption .br .Op Fl ini Ar dMagnetic.ini fish .br .Op Fl ini Ar dMagnetic.ini pawn .br .Op Fl ini Ar dMagnetic.ini myth .br .Op Fl ini Ar dMagnetic.ini wonderland .br An alternative way to provide the location of the .mag and .gfx, or the directory name, is through a dMagnetic.ini file. See helpini or .Xr dMagneticini 5 for an example of a working dMagnetic.ini file. .br IT SHOULD BE NOTED that the default location for dMagnetic.ini is in the user's home directory. If the file is located there, "The Pawn", for example, can be started by typing .br .Nm pawn .br .Pp .Op Fl rmode Ar pseudo .Op Fl rseed Ar SEED .br .Op Fl rmode Ar real .br Certain elements of the game rely on chance. For this, the virtual machine within .Nm offers two possibilities: Playing against a "pseudo" random generator, which results in a certain degree of determinism. On the other hand, playing with "real" random values from the operating system, allows for a completely new experience. .Pp .Op Fl vrows Ar ROWS .br .Op Fl vcols Ar COLUMNS .br .Nm has been designed with terminal windows as main output in mind. The terminal window has a fixed number of rows and columns to print out text. Its size is limited, but it is used by .Nm to render the beautiful BEAUTIFUL pictures as well. To restrict the space in which they are rendered (in glorious ANSI art), those command set the upper limits. .br .Pp .Op Fl vecho .br When trying to run .Nm and redirecting the output into a file, the inputs are missing. This option reprints what was typed in, to allow for a spoilery script. .Pp .Op Fl vlog Ar LOGFILE.log .br Sort of a travel journal, this option lets you write the commands that where typed into a file. .br .Pp .Op Fl vmode Ar none .br .Op Fl vmode Ar monochrome .br .Op Fl vmode Ar low_ansi .br .Op Fl vmode Ar high_ansi .br .Op Fl vmode Ar high_ansi2 .br .Op Fl vmode Ar sixel .Op Fl sres Ar 1024x768 .br This option allows for selecting a different mode to render the images, should the actual one prove to be unsuitable for the preferred terminal program. .br .Pp .Op Fl version .br Shows the current version of .Nm . .Sh BUGS Report bugs to .An Aq dettus@dettus.net . Make sure to include DMAGNETIC somewhere in the subject. .Sh AUTHOR Written by .An Thomas Dettbarn .Sh SEE ALSO .Xr dMagneticini 5 dmagnetic-0.22/src/0000755000175000017500000000000013621220604013555 5ustar dettusdettusdmagnetic-0.22/src/loader/0000755000175000017500000000000013621220610015020 5ustar dettusdettusdmagnetic-0.22/src/loader/maggfxloader.c0000644000175000017500000006174413621220604017643 0ustar dettusdettus/* Copyright 2019, dettus@dettus.net Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // the purpose of this file is to figure out what kind of binaries the // user has. is it the .mag/.gfx one? or is it the original MS-DOS version? #include #include #include #include "configuration.h" #include "vm68k_macros.h" typedef struct _tGameInfo { char prefix[8]; // the prefix for the game's binaries. int disk1size; // the size of the DISK1.PIX file is in an indicator for the game being used. int version; // the interpreter version. } tGameInfo; // TODO: so far, i have understood the formats for PAWN, THE GUILD OF THIEVES and JINXTER // The others have some opcodes which I can not decode (yet) #define KNOWN_GAMES 5 const tGameInfo gameInfo[KNOWN_GAMES]={ {"PAWN", 209529,0}, {"GUILD", 185296,1}, {"JINX", 159027,2}, {"CORR", 160678,3}, {"FILE", 162541,3} }; int loader_huffman_unpack(char* magbuf,int* decodedbytes,FILE *f) { unsigned char huffsize; unsigned char hufftab[256]; int huffidx; unsigned short todo; unsigned char byte; unsigned char mask; unsigned char tmp[3]; int threebytes; int n; // this variable is getting rid of some compiler warnings. int magidx; magidx=0; n=fread(&huffsize,sizeof(char),1,f); n+=fread(hufftab,sizeof(char),huffsize,f); n+=fread(&todo,sizeof(short),1,f); // what are those two bytes? mask=0; huffidx=0; threebytes=0; while (!feof(f) || mask) { unsigned char branchr,branchl; unsigned char branch; if (mask==0) { n+=fread(&byte,sizeof(char),1,f); mask=0x80; } branchl=hufftab[2*huffidx+0]; branchr=hufftab[2*huffidx+1]; branch=(byte&mask)?branchl:branchr; if (branch&0x80) // the highest bit signals a terminal symbol. { huffidx=0; branch&=0x7f; // the terminal symbols from the tree are only 6 bits wide. // to extend this to 8 bits, the fourth symbol contains the // two MSB for the previous three: // 00AAAAAA 00BBBBBB 00CCCCCC 00aabbcc if (threebytes==3) { int i; threebytes=0; for (i=0;i<3;i++) { // add the 2 MSB to the existing 6. tmp[i]|=((branch<<2)&0xc0); // MSB first magbuf[magidx]|=(char)tmp[i]; magidx++; branch<<=2; // MSB first } } else { tmp[threebytes]=branch; threebytes++; } } else { huffidx=branch; } mask>>=1; } *decodedbytes=magidx; return (n==0); } int loader_msdos(char* msdosdir, char *magbuf,int* magsize, char* gfxbuf,int* gfxsize) { #define OPENFILE(filename) \ f=fopen((filename),"rb"); \ if (!f) \ { \ fprintf(stderr,"ERROR. Unable to open %s. Sorry.\n",(filename)); \ return -1; \ } FILE *f; char filename[1024]; int i; int gameid; int magsize0; int gfxsize0; magsize0=*magsize; gfxsize0=*gfxsize; *magsize=0; *gfxsize=0; // clear the headers. memset(gfxbuf,0,16); memset(magbuf,0,42); { int sizedisk1,sizedisk2,sizeindex; /////////////////////// GFX packing // the header of the GFX is always 16 bytes. // values are stored as BigEndians // 0.. 3 are the magic word 'MaP3' // 4.. 7 are the size of the GAME4 (index) file (always 256) // 8..11 are the size of the DISK1.PIX file // 12..15 are the size of the DISK2.PIX file // then the INDEX file (beginning at 16) // then the DISK1.PIX file // then the DISK2.PIX file // step 1: find out which game it is. snprintf(filename,1024,"%s/DISK1.PIX",msdosdir); OPENFILE(filename); sizedisk1=fread(&gfxbuf[16+256],sizeof(char),gfxsize0-16-256,f); fclose(f); gameid=-1; for (i=0;i=KNOWN_GAMES) { fprintf(stderr,"ERROR: Unable to recognize game\n"); return -2; } // step 2: read the binary files, and store them in the gfxbuffer snprintf(filename,1024,"%s/DISK2.PIX",msdosdir); OPENFILE(filename); sizedisk2=fread(&gfxbuf[16+256+sizedisk1],sizeof(char),gfxsize0-sizedisk1-16-256,f); fclose(f); snprintf(filename,1024,"%s/%s4",msdosdir,gameInfo[gameid].prefix); OPENFILE(filename); sizeindex=fread(&gfxbuf[16],sizeof(char),256,f); fclose(f); // step 3: add the header to the gfx buffer gfxbuf[0]='M';gfxbuf[1]='a';gfxbuf[2]='P';gfxbuf[3]='3'; WRITE_INT32BE(gfxbuf, 4,sizeindex); WRITE_INT32BE(gfxbuf, 8,sizedisk1); WRITE_INT32BE(gfxbuf,12,sizedisk2); *gfxsize=16+sizeindex+sizedisk1+sizedisk2; } ////////////////////////// done with GFX packing ////////////////////////// MAG packing { int codesize=0; int dictsize=0; int string0size=0; int string1size=0; int string2size=0; int magidx=0; magidx=42; magbuf[0]='M';magbuf[1]='a';magbuf[2]='S';magbuf[3]='c'; WRITE_INT32BE(magbuf,8,magidx); // the program for the 68000 machine is stored in the file ending with 1. snprintf(filename,1024,"%s/%s1",msdosdir,gameInfo[gameid].prefix); OPENFILE(filename); if (gameInfo[gameid].version>=3) // beginning with version 3, it is huffman-encoded. { if (loader_huffman_unpack(&magbuf[magidx],&codesize,f)) return -1; } else { codesize=fread(&magbuf[magidx],sizeof(char),magsize0-magidx,f); } fclose(f); magidx+=codesize; // the strings for the game are stored in the files ending with 3 and 2 snprintf(filename,1024,"%s/%s3",msdosdir,gameInfo[gameid].prefix); OPENFILE(filename); string1size=fread(&magbuf[magidx],sizeof(char),magsize0-magidx,f); fclose(f); magidx+=string1size; snprintf(filename,1024,"%s/%s2",msdosdir,gameInfo[gameid].prefix); OPENFILE(filename); string2size=fread(&magbuf[magidx],sizeof(char),magsize0-magidx,f); fclose(f); magidx+=string2size; if (gameInfo[gameid].version>=2) { // dictionaries are packed. dictsize=0; snprintf(filename,1024,"%s/%s0",msdosdir,gameInfo[gameid].prefix); OPENFILE(filename); if (loader_huffman_unpack(&magbuf[magidx],&dictsize,f)) return -1; fclose(f); magidx+=dictsize; } // TODO: what about the 5? WRITE_INT32BE(magbuf, 4,codesize+dictsize+string1size+string2size+42); WRITE_INT32BE(magbuf,14,codesize); string0size=string1size; if (string1size>=0x10000) { string2size+=(string1size-0x10000); string1size=0x10000; } WRITE_INT32BE(magbuf,18,string1size); WRITE_INT32BE(magbuf,22,string2size); WRITE_INT32BE(magbuf,26,dictsize); WRITE_INT32BE(magbuf,30,string0size); WRITE_INT32BE(magbuf,34,0); // undosize WRITE_INT32BE(magbuf,38,0); // undopc magbuf[13]=gameInfo[gameid].version; *magsize=magidx; } return 0; } // the purpose of this function is to use the naming of the "???one.rsc" file as a blueprint. int loader_mw_substituteOne(char* two_rsc,int num,char* output) { int i; int l; int onestart; int uppercase; char *names[10]={"zero","one","two","three","four","five","six","seven","eight","nine"}; l=strlen(two_rsc); onestart=-1; uppercase=0; for (i=0;i=10 || num<0) return 0; memcpy(output,two_rsc,strlen(two_rsc)); memcpy(&output[onestart],&names[num][0],strlen(names[num])); if (uppercase) { for (i=0;i=0x10000)?0x10000:0xe000); if (text1size>0x10000) text2size=text1size+dictsize-0x10000; else text2size=text1size+dictsize-0xe000; WRITE_INT32BE(magbuf,22,text2size); WRITE_INT32BE(magbuf,26,wtabsize); WRITE_INT32BE(magbuf,30,text1size); WRITE_INT32BE(magbuf,34,undosize); // undosize WRITE_INT32BE(magbuf,38,undopc); // undopc magidx=42; loader_mw_readresource(two_rsc,sizes,codeoffs,&magbuf[magidx],codesize); magidx+=codesize; loader_mw_readresource(two_rsc,sizes,textoffs,&magbuf[magidx],text1size); magidx+=text1size; loader_mw_readresource(two_rsc,sizes,dictoffs,&magbuf[magidx],dictsize); magidx+=dictsize; loader_mw_readresource(two_rsc,sizes,wtaboffs,&magbuf[magidx],wtabsize); magidx+=wtabsize; *bytes=magidx; // finishing patch if (wonderland) { if (READ_INT16BE(magbuf,0x67a2)==0xa62c) { magbuf[0x67a2]=0x4e; magbuf[0x67a3]=0x75; } } return 1; } int loader_magneticwindows(char* two_rsc, char *magbuf,int* magsize, char* gfxbuf,int* gfxsize) { int bytes; int sizes[10]={0}; *magsize=0; *gfxsize=0; printf("Pondering...\n"); if (!loader_mw_collectSizes(two_rsc,sizes,gfxbuf)) { fprintf(stderr,"unable to find resource files\n"); fprintf(stderr," please make sure that they are named TWO.RSC\n"); fprintf(stderr," CTWO.RSC or something similar.\n"); return 0; } if (loader_mw_mkmag(two_rsc,sizes,magbuf,&bytes)) { *magsize=bytes; } loader_mw_mkgfx(two_rsc,sizes,gfxbuf,&bytes); *gfxsize=bytes; return 1; } int loader_init(int argc,char** argv,FILE *f_inifile, char *magbuf,int* magsize, char* gfxbuf,int* gfxsize) { FILE *f; char magfilename[1024]; char gfxfilename[1024]; char msdosdirname[1024]; char tworscname[1024]; int gamenamegiven; int n; magfilename[0]=gfxfilename[0]=msdosdirname[0]=tworscname[0]=0; gamenamegiven=0; if ((retrievefromcommandline(argc,argv,"pawn",NULL,0)) || (retrievefromcommandline(argc,argv,"guild",NULL,0)) || (retrievefromcommandline(argc,argv,"jinxter",NULL,0)) || (retrievefromcommandline(argc,argv,"corruption",NULL,0)) || (retrievefromcommandline(argc,argv,"fish",NULL,0)) || (retrievefromcommandline(argc,argv,"myth",NULL,0)) || (retrievefromcommandline(argc,argv,"wonderland",NULL,0))) { gamenamegiven=1; } if (!f_inifile && gamenamegiven) { fprintf(stderr,"Game name was given, but no suitable .ini file found\n"); fprintf(stderr,"please run %s -helpini for more help\n",argv[0]); return 1; } if (retrievefromcommandline(argc,argv,"pawn",NULL,0)) { magfilename[0]=gfxfilename[0]=0; retrievefromini(f_inifile,"[FILES]","pawnmag",magfilename,sizeof(magfilename)); retrievefromini(f_inifile,"[FILES]","pawngfx",gfxfilename,sizeof(gfxfilename)); retrievefromini(f_inifile,"[FILES]","pawnmsdos",msdosdirname,sizeof(msdosdirname)); } if (retrievefromcommandline(argc,argv,"guild",NULL,0)) { magfilename[0]=gfxfilename[0]=0; retrievefromini(f_inifile,"[FILES]","guildmag",magfilename,sizeof(magfilename)); retrievefromini(f_inifile,"[FILES]","guildgfx",gfxfilename,sizeof(gfxfilename)); retrievefromini(f_inifile,"[FILES]","guildmsdos",msdosdirname,sizeof(msdosdirname)); retrievefromini(f_inifile,"[FILES]","guildtworsc",tworscname,sizeof(tworscname)); } if (retrievefromcommandline(argc,argv,"jinxter",NULL,0)) { magfilename[0]=gfxfilename[0]=0; retrievefromini(f_inifile,"[FILES]","jinxtermag",magfilename,sizeof(magfilename)); retrievefromini(f_inifile,"[FILES]","jinxtergfx",gfxfilename,sizeof(gfxfilename)); retrievefromini(f_inifile,"[FILES]","jinxtermsdos",msdosdirname,sizeof(msdosdirname)); } if (retrievefromcommandline(argc,argv,"corruption",NULL,0)) { magfilename[0]=gfxfilename[0]=0; retrievefromini(f_inifile,"[FILES]","corruptionmag",magfilename,sizeof(magfilename)); retrievefromini(f_inifile,"[FILES]","corruptiongfx",gfxfilename,sizeof(gfxfilename)); retrievefromini(f_inifile,"[FILES]","corruptionmsdos",msdosdirname,sizeof(msdosdirname)); retrievefromini(f_inifile,"[FILES]","corruptiontworsc",tworscname,sizeof(tworscname)); } if (retrievefromcommandline(argc,argv,"fish",NULL,0)) { magfilename[0]=gfxfilename[0]=0; retrievefromini(f_inifile,"[FILES]","fishmag",magfilename,sizeof(magfilename)); retrievefromini(f_inifile,"[FILES]","fishgfx",gfxfilename,sizeof(gfxfilename)); retrievefromini(f_inifile,"[FILES]","fishmsdos",msdosdirname,sizeof(msdosdirname)); retrievefromini(f_inifile,"[FILES]","fishtworsc",tworscname,sizeof(tworscname)); } if (retrievefromcommandline(argc,argv,"myth",NULL,0)) { magfilename[0]=gfxfilename[0]=0; retrievefromini(f_inifile,"[FILES]","mythmag",magfilename,sizeof(magfilename)); retrievefromini(f_inifile,"[FILES]","mythgfx",gfxfilename,sizeof(gfxfilename)); retrievefromini(f_inifile,"[FILES]","mythmsdos",msdosdirname,sizeof(msdosdirname)); } if (retrievefromcommandline(argc,argv,"wonderland",NULL,0)) { magfilename[0]=gfxfilename[0]=0; retrievefromini(f_inifile,"[FILES]","wonderlandmag",magfilename,sizeof(magfilename)); retrievefromini(f_inifile,"[FILES]","wonderlandgfx",gfxfilename,sizeof(gfxfilename)); retrievefromini(f_inifile,"[FILES]","wonderlandmsdos",msdosdirname,sizeof(msdosdirname)); retrievefromini(f_inifile,"[FILES]","wonderlandtworsc",tworscname,sizeof(tworscname)); } // command line parameters should overwrite the .ini parameters. if (retrievefromcommandline(argc,argv,"-mag",magfilename,sizeof(magfilename))) { gfxfilename[0]=0; msdosdirname[0]=0; tworscname[0]=0; } if (retrievefromcommandline(argc,argv,"-gfx",gfxfilename,sizeof(gfxfilename))) { msdosdirname[0]=0; tworscname[0]=0; } if (retrievefromcommandline(argc,argv,"-msdosdir",msdosdirname,sizeof(msdosdirname))) { gfxfilename[0]=magfilename[0]=0; tworscname[0]=0; } if (retrievefromcommandline(argc,argv,"-tworsc",tworscname,sizeof(tworscname))) { gfxfilename[0]=magfilename[0]=0; msdosdirname[0]=0; } if (tworscname[0]) { loader_magneticwindows(tworscname,magbuf,magsize,gfxbuf,gfxsize); } else if (msdosdirname[0]) { loader_msdos(msdosdirname,magbuf,magsize,gfxbuf,gfxsize); } else { if (magfilename[0] && !gfxfilename[0]) { // deducing the name of the gfx file from the mag file int l; int found; found=0; l=strlen(magfilename); fprintf(stderr,"Warning! -mag given, but not -gfx. Deducing filename\n"); if (l>=4) { if (strncmp(&magfilename[l-4],".mag",4)==0) { memcpy(gfxfilename,magfilename,l+1); found=1; gfxfilename[l-4]='.'; gfxfilename[l-3]='g'; gfxfilename[l-2]='f'; gfxfilename[l-1]='x'; } } if (!found) { fprintf(stderr,"filename did not end in .mag (lower case)\n"); return 0; } } if (!magfilename[0] && gfxfilename[0]) { // deducing the name of the mag from the gfx int l; int found; found=0; l=strlen(gfxfilename); fprintf(stderr,"warning! -gfx given, but not -mag. Deducing filename\n"); if (l>=4) { if (strncmp(&gfxfilename[l-4],".gfx",4)==0) { memcpy(magfilename,gfxfilename,l+1); found=1; magfilename[l-4]='.'; magfilename[l-3]='m'; magfilename[l-2]='a'; magfilename[l-1]='g'; } } if (!found) { fprintf(stderr,"filename did not end in .gfx (lower case)\n"); return 0; } } if ((!magfilename[0] || !gfxfilename[0])) { fprintf(stderr,"Please provide a game via commandline. Please use either\n"); fprintf(stderr," %s -mag MAGFILE.mag or %s -ini dMagnetic.ini pawn\n",argv[0],argv[0]); fprintf(stderr,"\n"); fprintf(stderr,"you need to provide a working dMagnetic.ini file\n"); fprintf(stderr,"please run %s -helpini for more help\n",argv[0]); return 1; } f=fopen(magfilename,"rb"); if (f==NULL) { fprintf(stderr,"ERROR: unable to open [%s]\n",magfilename); fprintf(stderr,"This interpreter needs a the game's binaries in the .mag and .gfx\n"); fprintf(stderr,"format from the Magnetic Scrolls Memorial webseiite. For details, \n"); fprintf(stderr,"see https://msmemorial.if-legends.org/memorial.php\n"); return -2; } n=fread(magbuf,sizeof(char),*magsize,f); fclose(f); *magsize=n; f=fopen(gfxfilename,"rb"); if (f==NULL) { fprintf(stderr,"ERROR: unable to open [%s]\n",gfxfilename); fprintf(stderr,"This interpreter needs a the game's binaries in the .mag and .gfx\n"); fprintf(stderr,"format from the Magnetic Scrolls Memorial webseiite. For details, \n"); fprintf(stderr,"see https://msmemorial.if-legends.org/memorial.php\n"); return -2; } n=fread(gfxbuf,sizeof(char),*gfxsize,f); *gfxsize=n; fclose(f); // at this point, they are stored in magbuf and gfxbuf. } return 0; } dmagnetic-0.22/src/loader/maggfxloader.h0000644000175000017500000000267213621220604017643 0ustar dettusdettus/* Copyright 2019, dettus@dettus.net Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef MAGGFXLOADER_H #define MAGGFXLOADER_H int loader_init(int argc,char** argv,FILE *f_inifile, char *magbuf,int* magsize, char* gfxbuf,int* gfxsize); #endif dmagnetic-0.22/src/gui/0000755000175000017500000000000013621220610014336 5ustar dettusdettusdmagnetic-0.22/src/gui/default_callbacks.c0000644000175000017500000005365613621220604020147 0ustar dettusdettus/* Copyright 2019, dettus@dettus.net Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // the purpose of this file is to provide a callback-fallback until proper // user interfaces have been established. It will do ;) #include #include #include #include "default_render.h" #include "picture.h" #include "configuration.h" #include "default_callbacks.h" #define MAGIC 0x68654879 // = yHeh, the place where I grew up ;) #define MAXTEXTBUFFER 1024 // maximum number of buffered characters #define MAXHEADLINEBUFFER 256 // maximum number of buffered headline characters typedef struct _tContext { unsigned int magic; // ansi output int columns; int rows; int mode; // 0=none. 1=ascii art. 2=ansi art. 3=high ansi. 4=high ansi2 // log the input FILE* f_logfile; int echomode; int capital; // =1 if the next character should be a capital letter. int lastchar; int jinxterslide; // THIS workaround makes the sliding puzzle in Jinxter solvable int headlineflagged; char low_ansi_characters[128]; // characters that are allowed for low ansi rendering char monochrome_characters[128]; // characters that are allowed for monochrome rendering // this is the line buffer. // text is stored here, before // being printed on the console. int textalign; // 0=left aligned. 1=block aligned int textlastspace; int textidx; char textoutput[MAXTEXTBUFFER]; int headlineidx; char headlineoutput[MAXHEADLINEBUFFER]; int screenheight; int screenwidth; } tContext; int default_flushOutputLeftAlign(tContext* pContext,int newline) { if (newline || pContext->textlastspace==-1) { pContext->textoutput[pContext->textidx++]=0; printf("%s",pContext->textoutput); pContext->textidx=0; } else { int i; int j; pContext->textoutput[pContext->textlastspace]=0; printf("%s\n",pContext->textoutput); j=0; for (i=pContext->textlastspace+1;itextidx;i++) { pContext->textoutput[j++]=pContext->textoutput[i]; } pContext->textidx=j; } pContext->textlastspace=-1; return 0; } int default_flushOutputRightAlign(tContext* pContext,int newline) { int i; if (newline || pContext->textlastspace==-1) { for (i=0;icolumns-pContext->textidx;i++) printf(" "); pContext->textoutput[pContext->textidx++]=0; printf("%s",pContext->textoutput); pContext->textidx=0; } else { int j; for (i=0;icolumns-pContext->textlastspace;i++) printf(" "); pContext->textoutput[pContext->textlastspace]=0; printf("%s\n",pContext->textoutput); j=0; for (i=pContext->textlastspace+1;itextidx;i++) { pContext->textoutput[j++]=pContext->textoutput[i]; } pContext->textidx=j; } pContext->textlastspace=-1; return 0; } int default_flushOutputBlockAlign(tContext* pContext,int newline) { if (newline || pContext->textlastspace==-1) { pContext->textoutput[pContext->textidx++]=0; printf("%s",pContext->textoutput); pContext->textidx=0; } else { int i; int j; int spacecnt; int rightmargin; int accu; spacecnt=0; rightmargin=pContext->columns-pContext->textlastspace; pContext->textoutput[pContext->textlastspace]=0; for (i=0;itextlastspace;i++) { if (pContext->textoutput[i]==' ') spacecnt++; } accu=0; for (i=0;itextlastspace;i++) { if (pContext->textoutput[i]!=' ') printf("%c",pContext->textoutput[i]); else { printf(" "); accu+=rightmargin; { while (accu>=spacecnt) { printf(" "); accu-=spacecnt; } } } } printf("\n"); j=0; for (i=pContext->textlastspace+1;itextidx;i++) { pContext->textoutput[j++]=pContext->textoutput[i]; } pContext->textidx=j; } pContext->textlastspace=-1; return 0; } int default_flushOutput(tContext* pContext,int newline) { switch(pContext->textalign) { case 1: return default_flushOutputBlockAlign(pContext,newline); case 2: return default_flushOutputRightAlign(pContext,newline); case 0: default: return default_flushOutputLeftAlign(pContext,newline); break; } return 0; } int default_cbOutputChar(void* context,char c,unsigned char controlD2,unsigned char flag_headline) { tContext *pContext=(tContext*)context; int newline; unsigned char c2; if (flag_headline && !pContext->headlineflagged) { pContext->headlineidx=0; } if (!flag_headline && pContext->headlineflagged) // after the headline ends, a new paragraph is beginning. { int i; pContext->capital=1; // obviously, this starts with a captial letter. pContext->headlineoutput[pContext->headlineidx]=0; // highlight the headline //printf("\x1b[0;30;47m%s\x1b[0m\n",pContext->headlineoutput); // first: remove the newlines from the headline text. for (i=0;iheadlineidx;i++) { if (pContext->headlineoutput[i]==0x0a) { pContext->headlineoutput[i]=0; pContext->headlineidx--; } } // second, print the ----[HEADLINE]- for (i=0;icolumns-pContext->headlineidx-3;i++) { printf("-"); } if (pContext->mode==2 || pContext->mode==3) // high or low ansi -> make the headline text pop out printf("[\x1b[0;30;47m%s\x1b[0m]-\n",pContext->headlineoutput); else printf("[%s]-\n",pContext->headlineoutput); /* // second, print the >>>> HEADLINE < for (i=0;icolumns-pContext->headlineidx-3;i++) { printf(">"); } printf(" %s <\n",pContext->headlineoutput); */ /* // second, print the //// HEADLINE / for (i=0;icolumns-pContext->headlineidx-3;i++) { printf("/"); } printf(" %s /\n",pContext->headlineoutput); */ } pContext->headlineflagged=flag_headline; newline=0; if ((unsigned char)c==0xff) { pContext->capital=1; } else { c2=c&0x7f; // the highest bit was an end marker for the hufman tree in the dictionary. // THE RULES FOR THE OUTPUT ARE: // replace tabs and _ with space. // the headline is printed in upper case letters. // after a . there has to be a space. // and after a . The next letter has to be uppercase. // multiple spaces are to be reduced to a single one. // the characters ~ and ^ are to be translated into line feeds. // the caracter 0xff makes the next one upper case. // after a second newline comes a capital letter. if (c2==9 || c2=='_') c2=' '; if (flag_headline && (c2==0x5f || c2==0x40)) c2=' '; // in a headline, those are the control codes for a space. if (controlD2 && c2==0x40) return 0; // end marker if (c2==0x5e || c2==0x7e) c2=0x0a; // ~ or ^ is actually a line feed. if (c2==0x0a && pContext->lastchar==0x0a) // after two consequitive newlines comes a capital letter. { pContext->capital=1; } if (c2=='.' || c2=='!' || c2==':' || c2=='?') // a sentence is ending. { pContext->capital=1; } if (((c2>='a' && c2<='z') || (c2>='A' && c2<='Z')) && (pContext->capital||flag_headline)) { pContext->capital=0; c2&=0x5f; // upper case } newline=0; if ( (pContext->lastchar=='.' || pContext->lastchar=='!' || pContext->lastchar==':' || pContext->lastchar=='?'|| pContext->lastchar==',' || pContext->lastchar==';') // a sentence as ended && ((c2>='A' && c2<='Z') ||(c2>='a' && c2<='z') ||(c2>='0' && c2<='9'))) // and a new one is beginning. { if (flag_headline) { if (pContext->headlineidxheadlineoutput[pContext->headlineidx++]=' '; // after those letters comes an extra space. } else { if (pContext->textidxtextlastspace=pContext->textidx; pContext->textoutput[pContext->textidx++]=' '; } } //pContext->lastchar=' '; } if (pContext->textidx>0 && pContext->lastchar==' ' && (c2==',' || c2==';' || c2=='.' || c2=='!')) // there have been some glitches with extra spaces, right before a komma. which , as you can see , looks weird. { pContext->textidx--; } if ( //allow multiple spaces in certain scenarios flag_headline || pContext->jinxterslide || pContext->lastchar!=' ' || c2!=' ') // combine multiple spaces into a single one. { if (c2==0x0a || (c2>=32 && c2<127 && c2!='@')) { if (flag_headline) { if (pContext->headlineidxheadlineoutput[pContext->headlineidx++]=c2&0x7f; } else if (pContext->textidx='0' && c2<='9')) pContext->jinxterslide=1; // a workaround regarding the sliding puzzle in jinxter. else if (c2!=' ') pContext->jinxterslide=0; // sometimes multiple spaces are bad, but in this case it is not. if (c2==' ') pContext->textlastspace=pContext->textidx; pContext->textoutput[pContext->textidx++]=c2; if (c2=='\n') newline=1; } pContext->lastchar=c2; } } if (newline || pContext->textidx>=pContext->columns || pContext->textidx>=511) { default_flushOutput(pContext,newline); } } return 0; } int default_cbOutputString(void* context,char* string,unsigned char controlD2,unsigned char flag_headline) { unsigned char c2; int i; i=0; c2=0; do { c2=string[i++]&0x7f; //if (c2==9) c2=' '; //if (c2>=32 && c2<127) printf("%c",c2); default_cbOutputChar(context,c2,controlD2,flag_headline); } while (c2>=32); return 0; } int default_cbInputString(void* context,int* len,char* string) { int l; tContext *pContext=(tContext*)context; //printf("? "); default_flushOutput(pContext,1); fflush(stdout); if (feof(stdin)) exit(0); if (fgets(string,256,stdin)==NULL) exit(0); if (pContext->echomode) { for (l=0;l='a' && string[l]<='z') { printf("%c",string[l]&0x5f); } else { printf("%c",string[l]); // print upper case letters. } } } if (pContext->f_logfile) { fprintf(pContext->f_logfile,"%s",string); fflush(pContext->f_logfile); } l=strlen(string); *len=l; pContext->capital=1; // the next line after the input is most definiately the beginning of a sentence! return 0; } int default_cbDrawPicture(void* context,tPicture* picture,int mode) { int i; int j; int rgb; int accux,accuy; tContext *pContext=(tContext*)context; int lastrgb; if (pContext->mode==0) return 0; // flush the output buffer default_cbOutputChar(context,'\n',0,0); if (pContext->mode==1) { default_render_monochrome(pContext->monochrome_characters,picture,pContext->rows,pContext->columns); } if (pContext->mode==2) { default_render_lowansi(pContext->low_ansi_characters,picture,pContext->rows,pContext->columns); } if (pContext->mode==3 || pContext->mode==4) { if (picture->halftones && pContext->mode==4) { accux=accuy=0; for (i=1;iheight-1;i+=2) { accuy+=pContext->rows*2; lastrgb=-1; if (accuy>=picture->height || i==picture->height-1) { accux=0; for (j=1;jwidth-1;j+=2) { accux+=pContext->columns*2; if (accux>=picture->width || j==picture->width-1) { unsigned int rgb1,rgb2,rgb3,rgb4; int red,green,blue; rgb1=picture->palette[(int)(picture->pixels[(i+0)*(picture->width)+j+0])]; rgb2=picture->palette[(int)(picture->pixels[(i+1)*(picture->width)+j+1])]; rgb3=picture->palette[(int)(picture->pixels[(i+0)*(picture->width)+j+1])]; rgb4=picture->palette[(int)(picture->pixels[(i+1)*(picture->width)+j+0])]; red=((rgb1>>8)&0xf)+((rgb2>>8)&0xf)+((rgb3>>8)&0xf)+((rgb4>>8)&0xf); green=((rgb1>>4)&0xf)+((rgb2>>4)&0xf)+((rgb3>>4)&0xf)+((rgb4>>4)&0xf); blue=((rgb1>>0)&0xf)+((rgb2>>0)&0xf)+((rgb3>>0)&0xf)+((rgb4>>0)&0xf); red/=4;green/=4;blue/=4; red*=32;green*=32;blue*=32; rgb=(red<<16)|(green<<8)|blue; if (rgb!=lastrgb) { printf("\x1b[48;2;%d;%d;%dm", red,green,blue); } printf(" "); lastrgb=rgb; accux-=picture->width; } } accuy-=picture->height; printf("\x1b[0m\n"); } } } else { accux=accuy=0; for (i=0;iheight;i++) { accuy+=pContext->rows; lastrgb=-1; if (accuy>=picture->height || i==picture->height-1) { accux=0; for (j=0;jwidth;j++) { accux+=pContext->columns; if (accux>=picture->width || j==picture->width-1) { rgb=picture->palette[(int)(picture->pixels[i*(picture->width)+j])]; if (rgb!=lastrgb) { printf("\x1b[48;2;%d;%d;%dm", ((rgb>>8)&0xf)*0x18, ((rgb>>4)&0xf)*0x18, ((rgb>>0)&0xf)*0x18); } printf(" "); lastrgb=rgb; accux-=picture->width; } } accuy-=picture->height; printf("\x1b[0m\n"); } } } } if (pContext->mode==5) // sixels { int i,j; int accux,accuy; int x,y; int screenheight; int screenwidth; printf("\n\x1bPq\n"); for (i=0;i<16;i++) { int red,green,blue; red=(picture->palette[i]>>8)&0xf; green=(picture->palette[i]>>4)&0xf; blue=(picture->palette[i]>>0)&0xf; red*=100;green*=100;blue*=100; red/=0x7;green/=0x7;blue/=0x7; printf("#%02d;2;%d;%d;%d",i,red,green,blue); } printf("\n"); x=0;y=0; accux=accuy=0; screenheight=pContext->screenheight; screenwidth=pContext->screenwidth; // find a good aspect ratio { float ratiox,ratioy; ratiox=(float)screenwidth/(float)(picture->width); ratioy=(float)screenheight/(float)(picture->height); if (ratioxwidth); screenheight=(int)(ratioy*(float)picture->height); } while (yheight) { int y0; int accuy0; int curpixel; accuy0=accuy; y0=y; for (i=0;i<16;i++) { printf("#%02d",i); x=0; accux=0; while (xwidth) { char bitmask; y=y0; accuy=accuy0; curpixel=picture->pixels[y*picture->width+x]; bitmask=0; for (j=0;j<6;j++) { bitmask>>=1; if (curpixel==i) bitmask|=0x20; accuy+=picture->height; if (accuy>=screenheight) { accuy-=screenheight; y++; if (yheight) { curpixel=picture->pixels[y*picture->width+x]; } else { curpixel=0; } } } while (accuxwidth; } accux-=screenwidth; x++; } printf("$\n"); } printf("-\n"); } printf("\x1b\\\n"); } return 0; } int default_cbSaveGame(void* context,char* filename,void* ptr,int len) { FILE *f; int n; f=fopen(filename,"wb"); if (!f) { printf("Unable to open file [%s]\n",(char*)ptr); return 0; } n=fwrite(ptr,sizeof(char),len,f); fclose(f); if (n==len) return 0; return -1; } int default_cbLoadGame(void* context,char* filename,void* ptr,int len) { FILE *f; int n; f=fopen(filename,"rb"); if (!f) { printf("Unable to open file [%s]\n",(char*)ptr); return 0; } n=fread(ptr,sizeof(char),len,f); fclose(f); if (n==len) return 0; return -1; } int default_getsize(int* size) { if (size==NULL) return DEFAULT_NOK; *size=sizeof(tContext); return DEFAULT_OK; } int default_open(void* hContext,FILE *f_inifile,int argc,char** argv) { tContext *pContext=(tContext*)hContext; char result[1024]; #define DEFAULT_LOW_ANSI_CHARACTERS 8 const char default_low_ansi_characters[DEFAULT_LOW_ANSI_CHARACTERS]="\\/|=L#T"; #define DEFAULT_MONOCHROME_CHARACTERS 14 const char default_monochrome_characters[DEFAULT_MONOCHROME_CHARACTERS]=" .:-=+*x#/@$X"; if (pContext==NULL) return DEFAULT_NOK; memset(pContext,0,sizeof(tContext)); pContext->magic=MAGIC; // the hiearchy is: first the default values. // if there is a .ini file, overwrite them with those values. // paramaters from the command line have the highest prioprity. pContext->rows=40; pContext->columns=120; pContext->mode=2; // 0=none. 1=monochrome. 2=low_ansi. 3=high_ansi. 4=high_ansi2, 5=sixel pContext->f_logfile=NULL; pContext->echomode=0; pContext->textalign=1; pContext->textidx=0; pContext->textlastspace=-1; pContext->screenwidth=320; pContext->screenheight=200; memcpy(pContext->low_ansi_characters,default_low_ansi_characters,sizeof(default_low_ansi_characters)); memcpy(pContext->monochrome_characters,default_monochrome_characters,sizeof(default_monochrome_characters)); if (f_inifile) { if (retrievefromini(f_inifile,"[DEFAULTGUI]","rows",result,sizeof(result))) { pContext->rows=atoi(result); } if (retrievefromini(f_inifile,"[DEFAULTGUI]","columns",result,sizeof(result))) { pContext->columns=atoi(result); } if (retrievefromini(f_inifile,"[DEFAULTGUI]","mode",result,sizeof(result))) { if (strncmp(result,"none",4)==0) pContext->mode=0; if (strncmp(result,"monochrome",10)==0) pContext->mode=1; if (strncmp(result,"low_ansi",8)==0) pContext->mode=2; if (strncmp(result,"high_ansi2",10)==0) pContext->mode=4; if (strncmp(result,"sixel",5)==0) pContext->mode=5; else if (strncmp(result,"high_ansi",9)==0) pContext->mode=3; } if (retrievefromini(f_inifile,"[DEFAULTGUI]","align",result,sizeof(result))) { if (strncmp(result,"left",4)==0) pContext->textalign=0; if (strncmp(result,"block",5)==0) pContext->textalign=1; if (strncmp(result,"right",5)==0) pContext->textalign=2; } if (retrievefromini(f_inifile,"[DEFAULTGUI]","low_ansi_characters",pContext->low_ansi_characters,sizeof(pContext->low_ansi_characters))) { } else { memcpy(pContext->low_ansi_characters,default_low_ansi_characters,DEFAULT_LOW_ANSI_CHARACTERS); } if (retrievefromini(f_inifile,"[DEFAULTGUI]","monochrome_characters",pContext->monochrome_characters,sizeof(pContext->monochrome_characters))) { } else { memcpy(pContext->monochrome_characters,default_monochrome_characters,DEFAULT_MONOCHROME_CHARACTERS); } if (retrievefromini(f_inifile,"[DEFAULTGUI]","sixel_resolution",result,sizeof(result))) { int i; int l; l=strlen(result); pContext->screenwidth=pContext->screenheight=0; for (i=0;iscreenwidth =atoi(&result[0]); pContext->screenheight=atoi(&result[i+1]); } } if (pContext->screenwidth==0 || pContext->screenwidth>1024 || pContext->screenheight==0) { printf("illegal parameter for sixelresultion. please use something like 1024x768\n"); return DEFAULT_NOK; } } } if (argc) { char result[64]; if (retrievefromcommandline(argc,argv,"-valign",result,sizeof(result))) { if (strncmp(result,"left",4)==0) pContext->textalign=0; else if (strncmp(result,"block",5)==0) pContext->textalign=1; else if (strncmp(result,"right",5)==0) pContext->textalign=2; else { printf("unknown parameter for -valign. please use one of\n"); printf("left "); printf("block "); printf("right "); printf("\n"); return DEFAULT_NOK; } } if (retrievefromcommandline(argc,argv,"-vmode",result,sizeof(result))) { if (strncmp(result,"none",4)==0) pContext->mode=0; else if (strncmp(result,"monochrome",10)==0) pContext->mode=1; else if (strncmp(result,"low_ansi",8)==0) pContext->mode=2; else if (strncmp(result,"high_ansi2",10)==0) pContext->mode=4; else if (strncmp(result,"sixel",5)==0) pContext->mode=5; else if (strncmp(result,"high_ansi",9)==0) pContext->mode=3; else { printf("unknown parameter for -vmode. please use one of\n"); printf("none "); printf("monochrome "); printf("low_ansi "); printf("high_ansi "); printf("high_ansi2 "); printf("sixel "); printf("\n"); return DEFAULT_NOK; } } if (retrievefromcommandline(argc,argv,"-vrows",result,sizeof(result))) { int rows; rows=atoi(result); if (rows<1 || rows>500) { printf("illegal parameter for -vrows. please use values between 1 and 500\n"); return DEFAULT_NOK; } pContext->rows=rows; } if (retrievefromcommandline(argc,argv,"-vcols",result,sizeof(result))) { int cols; cols=atoi(result); if (cols<1 || cols>600) { printf("illegal parameter for -vcols. please use values between 1 and 600\n"); return DEFAULT_NOK; } pContext->columns=cols; } if (retrievefromcommandline(argc,argv,"-vecho",NULL,0)) { pContext->echomode=1; } if (retrievefromcommandline(argc,argv,"-vlog",result,sizeof(result))) { fprintf(stderr,"Opening logfile [%s] for writing\n",result); pContext->f_logfile=fopen(result,"wb"); if (pContext->f_logfile==NULL) { fprintf(stderr,"Error opening logfile [%s]\n",result); exit(0); } } if (retrievefromcommandline(argc,argv,"-sres",result,sizeof(result))) { int i; int l; l=strlen(result); pContext->screenwidth=pContext->screenheight=0; for (i=0;iscreenwidth =atoi(&result[0]); pContext->screenheight=atoi(&result[i+1]); } } if (pContext->screenwidth==0 || pContext->screenwidth>1024 || pContext->screenheight==0) { printf("illegal parameter for -sres. please use something like 1024x768\n"); return DEFAULT_NOK; } } } return DEFAULT_OK; } dmagnetic-0.22/src/gui/xglk_callbacks.c0000644000175000017500000001646313621220604017463 0ustar dettusdettus/* Copyright 2019, dettus@dettus.net Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include //#include #include "picture.h" #include "glk.h" // the way i am writing this is: // callbacks do not yield any immediate results. // // the values are simply stored inside the context, and the text/picture is being // displayed with the input callback is being triggered. // #define MAGIC 0x4b4c4778 // = xGLK typedef struct _tContext { unsigned int magic; winid_t mainwin; winid_t statuswin; winid_t graphicwin; tPicture picture; char statustext[256]; int statusidx; char outputwindowtext[(1<<20)]; int outputidx; char lastchar; char headlineflagged; char capital; } tContext; int xglk_cbOutputChar(void* context,char c,unsigned char controlD2,unsigned char flag_headline) { tContext *pContext=(tContext*)context; unsigned char c2; if (pContext->magic!=MAGIC) return -1; if (c==0xff) { pContext->capital=1; } else { c2=c&0x7f; if (c2==9) c2=' '; if (flag_headline && (c2==0x5f || c2==0x40)) c2=' '; if (controlD2 && c2==0x40) return 0; // end marker if (c2==0x5e || c2==0x7e) c2=0x0a; // ~ or ^ is actually a line feed. if (c2>='a' && c2<='z' && (pContext->capital||flag_headline)) c2&=0x5f; // upper case if ((pContext->lastchar=='.' || pContext->lastchar=='!' || pContext->lastchar==':' || pContext->lastchar=='?') && c2>='a' && c2<='z') c2&=0x5f; // after a '.': captial letter if ((pContext->lastchar=='.' || pContext->lastchar=='!' || pContext->lastchar==':' || pContext->lastchar=='?'|| pContext->lastchar==',' || pContext->lastchar==';') && ((c2>='A' && c2<='Z') ||(c2>='a' && c2<='z') ||(c2>='0' && c2<='9'))) { if (flag_headline) pContext->statustext[pContext->statusidx++]=' '; else pContext->outputwindowtext[pContext->outputidx++]=' '; } if (pContext->lastchar!=' ' || c2!=' ') { if (c2==0x0a || (c2>=32 && c2<127 && c2!='@')) { if (flag_headline) pContext->statustext[pContext->statusidx++]=c2; else pContext->outputwindowtext[pContext->outputidx++]=c2; } } pContext->capital=0; pContext->lastchar=c2; pContext->statustext[pContext->statusidx]=0; pContext->outputwindowtext[pContext->outputidx]=0; } return 0; } int xglk_cbOutputString(void* context,char* string,unsigned char controlD2,unsigned char flag_headline) { tContext *pContext=(tContext*)context; unsigned char c2; int i; if (pContext->magic!=MAGIC) return -1; i=0; c2=0; do { c2=string[i++]&0x7f; //if (c2==9) c2=' '; //if (c2>=32 && c2<127) printf("%c",c2); xglk_cbOutputChar(context,c2,controlD2,flag_headline); } while (c2>=32); return 0; } int xglk_cbDrawPicture(void* context,tPicture* picture,int mode) { tContext *pContext=(tContext*)context; if (pContext->magic!=MAGIC) return -1; memcpy(&pContext->picture,picture,sizeof(tPicture)); return 0; } int xglk_getsize(int *size) { if (size==NULL) return -1; *size=sizeof(tContext); return 0; } int xglk_open(void* hContext) { tContext *pContext=(tContext*)hContext; if (pContext==NULL) return -1; memset(pContext,0,sizeof(tContext)); pContext->magic=MAGIC; pContext->mainwin=glk_window_open(0,0,0, wintype_TextBuffer,1); pContext->statuswin=glk_window_open(pContext->mainwin, winmethod_Above | winmethod_Fixed, 1, wintype_TextGrid, 0); pContext->graphicwin=glk_window_open (pContext->mainwin,winmethod_Above|winmethod_Proportional,60,wintype_Graphics, 0); return 0; } int xglk_cbSaveGame(void* context,char* filename,void* ptr,int len) { FILE *f; int n; f=fopen(filename,"wb"); if (!f) { printf("Unable to open file [%s]\n",(char*)ptr); return 0; } n=fwrite(ptr,sizeof(char),len,f); fclose(f); if (n==len) return 0; return -1; } int xglk_cbLoadGame(void* context,char* filename,void* ptr,int len) { FILE *f; int n; f=fopen(filename,"rb"); if (!f) { printf("Unable to open file [%s]\n",(char*)ptr); return 0; } n=fread(ptr,sizeof(char),len,f); fclose(f); if (n==len) return 0; return -1; } int xglk_cbInputString(void* context,int* len,char* string) { char commandbuf[256]; event_t ev; int l; tContext *pContext=(tContext*)context; if (pContext==NULL) return -1; memset(commandbuf,0,sizeof(commandbuf)); do { if (pContext->statusidx) { glk_set_window(pContext->statuswin); glk_window_clear(pContext->statuswin); glk_window_move_cursor(pContext->statuswin,0,0); glk_put_string(pContext->statustext); pContext->statusidx=0; } if (pContext->outputidx) { glk_set_window(pContext->mainwin); glk_put_string(pContext->outputwindowtext); pContext->outputidx=0; } if (pContext->picture.width && pContext->picture.height) { int i; int x,y; int xpix,ypix; int pixidx; unsigned int palette[16]; int linecomplete; glui32 width,height; glk_window_set_background_color(pContext->graphicwin,0x00000000); glk_window_clear(pContext->graphicwin); glk_window_get_size(pContext->graphicwin, &width, &height); for (i=0;i<16;i++) { palette[i] =(((pContext->picture.palette[i]>>8)&0xf)&0xf)*0x18;palette[i]<<=8; // Red palette[i]|=(((pContext->picture.palette[i]>>4)&0xf)&0xf)*0x18;palette[i]<<=8; // Green palette[i]|=(((pContext->picture.palette[i]>>0)&0xf)&0xf)*0x18; // Blue } pixidx=0; xpix=1; ypix=1; if (pContext->picture.width) xpix=width/pContext->picture.width; if (pContext->picture.height) ypix=height/pContext->picture.height; for (y=0;ypicture.height;y++) { for (x=0;xpicture.width;x++) { glk_window_fill_rect(pContext->graphicwin,palette[pContext->picture.pixels[pixidx++]],x*xpix,y*ypix,xpix,ypix); } } } glk_request_line_event(pContext->mainwin,commandbuf,255,0); do { glk_select(&ev); } while (ev.type!=evtype_LineInput);// && ev.type!=evtype_Arrange); // if (ev.type==evtype_Arrange) usleep(1000000); // wait for the window size to settle. } while (ev.type!=evtype_LineInput); l=strlen(commandbuf); commandbuf[l]=0x0a; // INPUTS need to be \n terminated. *len=l+1; memcpy(string,commandbuf,l+2); pContext->picture.width=0; pContext->picture.height=0; pContext->statusidx=0; pContext->outputidx=0; return 0; } dmagnetic-0.22/src/gui/default_render.h0000644000175000017500000000301113621220604017470 0ustar dettusdettus/* Copyright 2019, dettus@dettus.net Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef DEFAULT_RENDER_H #define DEFAULT_RENDER_H #include "picture.h" int default_render_lowansi(char* allowed,tPicture* picture,int rows,int cols); int default_render_monochrome(char* greyscales,tPicture* picture,int rows,int cols); #endif dmagnetic-0.22/src/gui/default_callbacks.h0000644000175000017500000000445313621220604020143 0ustar dettusdettus/* Copyright 2019, dettus@dettus.net Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // the purpose of this file is to provide a callback-fallback until proper // user interfaces have been established. It will do ;) #ifndef LINEA_DEFAULT_CALLBACKS_H #define LINEA_DEFAULT_CALLBACKS_H #include "picture.h" #define DEFAULT_OK 0 #define DEFAULT_NOK -1 // interface to the lineA int default_cbOutputChar(void* context,char c,unsigned char controlD2,unsigned char flag_headline); int default_cbOutputString(void* context,char* string,unsigned char controlD2,unsigned char flag_headline); int default_cbInputString(void* context,int* len,char* string); int default_cbDrawPicture(void* context,tPicture* picture,int mode); int default_cbSaveGame(void* context,char* filename,void* ptr,int len); int default_cbLoadGame(void* context,char* filename,void* ptr,int len); // interface to the main application int default_getsize(int* size); // if there is a .ini-file, extract the section for this user interface. the same goes for the command line parameters int default_open(void* hContext,FILE* f_inifile,int argc,char** argv); #endif dmagnetic-0.22/src/gui/default_render.c0000644000175000017500000005275313621220604017504 0ustar dettusdettus/* Copyright 2019, dettus@dettus.net Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include "default_render.h" #include "picture.h" int default_render_lowansi(char* allowed,tPicture* picture,int rows,int cols) { unsigned char maxplut[16]={0}; // the following table is a bitmap, representing all the available ASCII characters. unsigned long long asciibitmap[95]={ 0x0000000000000000, // 0x00180018183c3c18, // ! 0x0000000000003636, // " 0x0036367f367f3636, // # 0x000c1f301e033e0c, // $ 0x0063660c18336300, // % 0x006e333b6e1c361c, // & 0x0000000000030606, // ' 0x00180c0606060c18, // ( 0x00060c1818180c06, // ) 0x0000663cff3c6600, // * 0x00000c0c3f0c0c00, // + 0x060c0c0000000000, // , 0x000000003f000000, // - 0x000c0c0000000000, // . 0x000103060c183060, // / 0x003e676f7b73633e, // 0 0x003f0c0c0c0c0e0c, // 1 0x003f33061c30331e, // 2 0x001e33301c30331e, // 3 0x0078307f33363c38, // 4 0x001e3330301f033f, // 5 0x001e33331f03061c, // 6 0x000c0c0c1830333f, // 7 0x001e33331e33331e, // 8 0x000e18303e33331e, // 9 0x000c0c00000c0c00, // : 0x060c0c00000c0c00, // ; 0x00180c0603060c18, // < 0x00003f00003f0000, // = 0x00060c1830180c06, // > 0x000c000c1830331e, // ? 0x001e037b7b7b633e, // @ 0x0033333f33331e0c, // A 0x003f66663e66663f, // B 0x003c66030303663c, // C 0x001f36666666361f, // D 0x007f46161e16467f, // E 0x000f06161e16467f, // F 0x007c66730303663c, // G 0x003333333f333333, // H 0x001e0c0c0c0c0c1e, // I 0x001e333330303078, // J 0x006766361e366667, // K 0x007f66460606060f, // L 0x0063636b7f7f7763, // M 0x006363737b6f6763, // N 0x001c36636363361c, // O 0x000f06063e66663f, // P 0x00381e3b3333331e, // Q 0x006766363e66663f, // R 0x001e33380e07331e, // S 0x001e0c0c0c0c2d3f, // T 0x003f333333333333, // U 0x000c1e3333333333, // V 0x0063777f6b636363, // W 0x0063361c1c366363, // X 0x001e0c0c1e333333, // Y 0x007f664c1831637f, // Z 0x001e06060606061e, // [ 0x00406030180c0603, // BACKSLASH 0x001e18181818181e, // ] 0x0000000063361c08, // ^ 0xff00000000000000, // _ 0x0000000000180c0c, // ` 0x006e333e301e0000, // a 0x003b66663e060607, // b 0x001e3303331e0000, // c 0x006e33333e303038, // d 0x001e033f331e0000, // e 0x000f06060f06361c, // f 0x1f303e33336e0000, // g 0x006766666e360607, // h 0x001e0c0c0c0e000c, // i 0x1e33333030300030, // j 0x0067361e36660607, // k 0x001e0c0c0c0c0c0e, // l 0x00636b7f7f330000, // m 0x00333333331f0000, // n 0x001e3333331e0000, // o 0x0f063e66663b0000, // p 0x78303e33336e0000, // q 0x000f06666e3b0000, // r 0x001f301e033e0000, // s 0x00182c0c0c3e0c08, // t 0x006e333333330000, // u 0x000c1e3333330000, // v 0x00367f7f6b630000, // w 0x0063361c36630000, // x 0x1f303e3333330000, // y 0x003f260c193f0000, // z 0x00380c0c070c0c38, // { 0x0018181800181818, // | 0x00070c0c380c0c07, // } 0x0000000000003b6e // ~ }; const signed char greyrainbow[16][16]= // 0 { // basecolor 0 = black/grey { 8,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, { 8, 7,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, { 8, 7,15,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, // guild, pic 00 { 0, 8, 7,15,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, // guild, pic 14 { 0, 0, 8, 7,15,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, // pawn pic 05,pic07 { 0, 4, 8, 7,12,15,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, // pawn pic01, pic13 { 0, 4, 3, 8, 7,12,15,-1,-1,-1,-1,-1,-1,-1,-1,-1}, // pawn pic09, pic12 { 0, 4, 3, 8, 7,12,11,15,-1,-1,-1,-1,-1,-1,-1,-1}, { 0, 4, 3, 8, 8, 7,12,11,15,-1,-1,-1,-1,-1,-1,-1}, { 0, 4, 3, 8, 8, 7, 7,12,11,15,-1,-1,-1,-1,-1,-1}, { 0, 0, 4, 3, 8, 8, 7, 7,12,11,15,-1,-1,-1,-1,-1}, { 0, 0, 4, 3, 8, 8, 7, 7, 7,12,11,15,-1,-1,-1,-1}, { 0, 0, 4, 3, 8, 8, 7, 7, 7,12,11,15,15,-1,-1,-1}, { 0, 0, 4, 3, 8, 8, 8, 7, 7, 7,12,11,15,15,-1,-1}, { 0, 0, 4, 3, 8, 8, 8, 7, 7, 7, 7,12,11,15,15,-1}, { 0, 0, 4, 3, 8, 8, 8, 8, 7, 7, 7, 7,12,11,15,15} }; const signed char redrainbow[16][16]= { { 1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, { 1, 9,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, { 1, 5, 9,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, // pawn pic 06 { 1, 5, 9,15,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, // pawn pic 13 { 8, 1, 3, 9,13,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, // pawn pic 15,16 { 8, 1, 3, 7, 9,13,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, // pawn pic 15 { 1, 1, 3,11, 9,13,15,-1,-1,-1,-1,-1,-1,-1,-1,-1}, // pawn pic 07 { 0, 8, 3, 1, 5, 7, 9,11, 9,11,15,15,15,15,15,15}, // guild pic 05 { 0, 8, 1, 3, 5,13, 9,11,15,-1,-1,-1,-1,-1,-1,-1}, // guild pic 02, myth pic 00 { 0, 8, 1, 3, 5,13, 9,11,14,15,15,15,15,15,15,15}, // wonderland. pic36 { 0, 1, 1, 1, 5, 5,13, 9, 9,11,15,15,15,15,15,15}, // guild pic 01, pawn pic 03 { 0, 1, 1, 1, 5, 5,13, 9, 9,11,15,15,15,15,15,15}, { 0, 1, 1, 1, 5, 5,13, 9, 9,11,15,15,15,15,15,15}, { 0, 1, 1, 1, 5, 5,13, 9, 9,11,15,15,15,15,15,15}, { 0, 1, 1, 1, 5, 5,13, 9, 9,11,15,15,15,15,15,15}, { 0, 1, 1, 1, 5, 5,13, 9, 9,11,15,15,15,15,15,15} }; const signed char greenrainbow[16][16]= { { 2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, { 2,10,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, { 2, 6,14,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, // guild, pic 00 { 2, 6,10,14,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, // guild, pic 09, pic 15 { 8, 6, 2,10,14,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, // pawn pic 14 { 2, 2, 6,10,10,14,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, // pawn pic 00 { 8, 2, 6, 7,10,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1}, // guild pic 06 { 8, 2, 3, 6,14,11,10,15,-1,-1,-1,-1,-1,-1,-1,-1}, // wonderland, pic 104 { 3, 2, 2, 6, 6,12,14,10,10,-1,-1,-1,-1,-1,-1,-1}, { 3, 2, 2, 6, 6,12,14,10,10,15,15,15,15,15,15,15}, { 0, 8, 2, 2, 6, 6,10,12,12,14, 7,15,15,15,15,15}, // pic 4, pawn { 3, 2, 2, 6, 6,12,14,10,10,15,15,15,15,15,15,15}, { 3, 2, 2, 6, 6,12,14,10,10,15,15,15,15,15,15,15}, { 3, 2, 2, 6, 6,12,14,10,10,15,15,15,15,15,15,15}, { 3, 2, 2, 6, 6,12,14,10,10,15,15,15,15,15,15,15}, { 3, 2, 2, 6, 6,12,14,10,10,15,15,15,15,15,15,15} }; const signed char brownrainbow[16][16]= { { 3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, { 3,11,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, { 3, 7,11,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, // guild, pic 17 { 8, 7, 3,11,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, // guild, pic 15 { 1, 3, 9,11,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, { 8, 1, 3, 9,11, 7,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, // pawn, pic 01, guild pic 08 { 8, 1, 3, 3,11, 7,15,-1,-1,-1,-1,-1,-1,-1,-1,-1}, // pawn, pic 06, guild pic 07 { 1, 2, 2, 6, 6,14,11,11,-1,-1,-1,-1,-1,-1,-1,-1}, { 1, 1, 3, 3, 7,11,11,15,15,-1,-1,-1,-1,-1,-1,-1}, // guild, pic 10 { 1, 2, 2, 6, 6,12,14,11,11,15,15,15,15,15,15,15}, { 0, 8, 2, 2, 6, 6,10,12,12,14, 7,15,15,15,15,15}, { 1, 2, 2, 6, 6,12,14,11,11,15,15,15,15,15,15,15}, { 1, 2, 2, 6, 6,12,14,10,10,15,15,15,15,15,15,15}, { 1, 2, 2, 6, 6,12,14,10,10,15,15,15,15,15,15,15}, { 1, 2, 2, 6, 6,12,14,10,10,15,15,15,15,15,15,15}, { 1, 2, 2, 6, 6,12,14,10,10,15,15,15,15,15,15,15} }; const signed char bluerainbow[16][16]= { { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4}, { 4,12, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4}, { 4, 6,12, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4}, // pawn, pic 12 { 4, 6,14,12, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4}, // pawn, pic 10 { 4, 6, 7,14,12, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4}, // jinxter/pix 04 { 0, 4, 6, 7,14,12, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4}, // jinxter/pic 00, wonderland pic52 { 8, 4, 6, 7,14,12,13, 4, 4, 4, 4, 4, 4, 4, 4, 4}, // jinxter/pic 10, wonderland pic46 { 8, 4, 6, 7,14,13,12,15, 4, 4, 4, 4, 4, 4, 4, 4}, { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4}, { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4}, { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4}, { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4}, { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4}, { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4}, { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4}, { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4} }; const signed char magentarainbow[16][16]= { { 5,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, { 5,13,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, { 2, 5,13,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, { 5, 5,13,13,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, { 1, 5, 9,12,13,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5}, { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5}, { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5}, { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5}, { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5}, { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5}, { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5}, { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5}, { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5}, { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5}, { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5} }; const signed char cyanrainbow[16][16]= { { 6,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, { 6,14,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, // pawn, pic 09 { 6, 7,14,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, // guild, pic 17, pic 20 { 8, 6, 7,14,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, // GUILD, pic 21, guild pic 25 { 4, 6,10,12,14,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, // pawn, pic 08 { 4, 2, 6,10,12,14, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6}, // wonderland, pic 50 { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6}, { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6}, { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6}, { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6}, { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6}, { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6}, { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6}, { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6}, { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6}, { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6} }; // const char allowed[]={'M','d','j','7','#'}; // only use those characters to render the picture //const char allowed[]={ 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z', 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','y','u','v','w','x','y','z', '0','1','2','3','4','5','6','7','8','9', '$','(',')','[',']','#','<','>', '&','*','!','{','}','%'}; //,'/','+','\\','{','}','@','!' int cnt0; int x,y,a,c,i,j,k,p; // counting variables int minccnt,maxc; int maxpcnt,maxp; int accux,accuy; cnt0=0; // step one: // find a good substitute for the palette. // I did a lot of experimentation with this part! and i mean: A LOOOT! // the naiive approach would be to take the palette, and search for the nearest neighbour. // that did not produce satisfactory results. it took me a while to understand why. // the reason is simple: // think of a picture with grass. it is mostly green, but there are nuances. // a picture of a lake is mostly blue, but there are nuances. // // so what i did was to figure out how many colors of the palette are "blue", how many are "red", "green" and a like. // this is the "basecolor" of the palette's color. // then i figured out how many of those are there, and ordered them according to their intensity. // then i defined a "rainbow" of sorts, where i substituted each palette with the ansi color, based on their hierachy within the list. // // that might result in two original colors that are vastly different being mapped onto the same ansi color. still looks good. { unsigned int paletteinfo[16]; int basecolorcnt[7],basecoloridx[7]; #define BLACK 0 #define RED 1 #define GREEN 2 #define BROWN 3 #define BLUE 4 #define MAGENTA 5 #define CYAN 6 #define UNDEF 7 for (i=0;i<16;i++) paletteinfo[i]=0; for (i=0;i< 7;i++) basecolorcnt[i]=0; for (i=0;i< 7;i++) basecoloridx[i]=0; // 4 bit primary intensity // 4 bit secondary intensity // 4 bit secondary color // 4 bit basecolor (0=black/grey, 1=red, 2=green, 3=brown, 4=blue, 5=magenta, 6=cyan) //12 bit orig rgb // 4 bit orig pixel // for each color in the palette, find the basecolor. the one with the highest intensity. for (i=0;i<16;i++) { int r; int g; int b; int basecolor; int secondcolor; int primary; int secondary; secondcolor=0; r=(picture->palette[i]>>8)&0x7; g=(picture->palette[i]>>4)&0x7; b=(picture->palette[i]>>0)&0x7; primary=secondary=0; basecolor=0; if (r==g && r==b) {basecolor=BLACK;primary=(r+g+b)/3;secondary=UNDEF;} if (r>g && r>b) { basecolor=RED;primary=r;secondary=(g+b)/2; if (g>b) secondcolor=GREEN; else if (b>g) secondcolor=BLUE; else if (b==g) secondcolor=CYAN; } if (g>r && g>b) { basecolor=GREEN;primary=g;secondary=(r+b)/2; if (r>b) secondcolor=RED; else if (b>r) secondcolor=BLUE; else if (b==r) secondcolor=MAGENTA; } if (r==g && r>b) {basecolor=BROWN;primary=(r+g)/2;secondary=b;secondcolor=BLUE;} if (b>g && b>r) { basecolor=BLUE;primary=b;secondary=(g+r)/2; if (r>g) secondcolor=RED; else if (g>r) secondcolor=GREEN; else if (g==r) secondcolor=BROWN; } if (r==b && r>g) {basecolor=MAGENTA;primary=(r+b)/2;secondary=g;secondcolor=GREEN;} if (g==b && g>r) {basecolor=CYAN;primary=(g+b)/2;secondary=r;secondcolor=RED;} paletteinfo[i]=i; paletteinfo[i]|=(picture->palette[i]<<4); paletteinfo[i]|=(basecolor<<16); paletteinfo[i]|=(secondcolor<<20); paletteinfo[i]|=(secondary<<24); paletteinfo[i]|=(primary <<28); basecolorcnt[basecolor]++; // at the same time, count how many of a base color are in the palette } // then: sort the list according to the intensity of the base color. // since the information has been combined, this is easy. // i am waaaay to lazy to implement quick sort, so lets do bubble sort. for (i=0;i<16-1;i++) { unsigned int x; for (j=(i+1);j<16;j++) { if (paletteinfo[i]>paletteinfo[j]) { x=paletteinfo[i]; paletteinfo[i]=paletteinfo[j]; paletteinfo[j]=x; } } } // now, the list is ordered, with the less intense colors at the beginning for (i=0;i<16;i++) { int basecolor; int primary; int pixel; pixel=(paletteinfo[i]>>0)&0xf; basecolor =(paletteinfo[i]>>16)&0xf; primary =(paletteinfo[i]>>28)&0xf; if (basecolorcnt[basecolor]==1) // this base color has only one entry { if (primary>=4) maxplut[pixel]=basecolor+8; // high intensity. make it bright. else maxplut[pixel]=basecolor; } else if (basecolorcnt[basecolor]!=0) { // depending in the base color, pick the substitute color from the rainbow. if (basecolor==BLACK) maxplut[pixel]=greyrainbow[basecolorcnt[basecolor]-1][basecoloridx[basecolor]]; else if (basecolor==RED) maxplut[pixel]= redrainbow[basecolorcnt[basecolor]-1][basecoloridx[basecolor]]; else if (basecolor==GREEN) maxplut[pixel]= greenrainbow[basecolorcnt[basecolor]-1][basecoloridx[basecolor]]; else if (basecolor==BROWN) maxplut[pixel]= brownrainbow[basecolorcnt[basecolor]-1][basecoloridx[basecolor]]; else if (basecolor==BLUE) maxplut[pixel]= bluerainbow[basecolorcnt[basecolor]-1][basecoloridx[basecolor]]; else if (basecolor==MAGENTA) maxplut[pixel]= magentarainbow[basecolorcnt[basecolor]-1][basecoloridx[basecolor]]; else if (basecolor==CYAN) maxplut[pixel]= cyanrainbow[basecolorcnt[basecolor]-1][basecoloridx[basecolor]]; } basecoloridx[basecolor]++; } } // step 2: render the picture. use the color and the character that best represents a 8x8 block. y=0; accux=accuy=0; for (i=0;iheight;i++) { accuy+=rows; // since the output is smaller than the actual picture, count a few lines. // at some point, there are enough to print one character. if (accuy>=picture->height) { accux=0; x=0; for (j=0;jwidth;j++) { accux+=cols; if (accux>=picture->width) { unsigned long long pb; int scalex,scaley; scalex=(j-x)/8; scaley=(i-y)/8; if (scalex==0) scalex=1; if (scaley==0) scaley=1; // at this point, a rectangle from X:x..j, Y:y..i is being rendered. // first: find the most common characters and the most common color. // find within the rectangle the largest amount of pixels with the same color maxp=0; maxpcnt=0; for (p=0;p<16;p++) { int x2,y2; cnt0=0; for (x2=x;x2=0 && x2width && y2>=0 && y2height) if (picture->pixels[y2*picture->width+x2]==p) cnt0++; } } if (cnt0>maxpcnt) { maxpcnt=cnt0; maxp=p; } } // create a bitmap of the next 8x8 pixel block pb=0; for (k=0;k<64;k++) { int x2,y2; int line,row; /* // okay row=k/8; line=k%8; x2=x+4-1*line; y2=y+4-1*row; */ // okay row=k/8; line=k%8; x2=x+scalex*4-scalex*line; y2=y+scaley*4-scaley*row; pb<<=1; if (x2>=0 && x2width && y2>=0 && y2height) if (picture->pixels[y2*picture->width+x2]==maxp) pb|=1; } // compare the bitmap to the bitmap for a character. // find the one with the lowest number of mismatches minccnt=64; maxc=0; for (a=0;a>=1; } if ((cnt0)<=minccnt) { minccnt=cnt0; maxc=c; } } maxp=maxplut[maxp]; printf("\x1b[%d;%dm",maxp/8,30+maxp%8); if (maxc<32 || maxc>=127) printf(" "); else printf("%c",maxc); accux-=picture->width; x=j; // the next rectangle will begin at the edge of this one. } } accuy-=picture->height; y=i; // the next rectangle will begin in this line printf("\x1b[0m\n"); } } return 0; } int default_render_monochrome(char* greyscales,tPicture* picture,int rows,int cols) { int i; int j; int k,l; int y_up,y_down,x_left,x_right; int accux,accuy; int grey; int mingrey,maxgrey; int cnt; int cnt2; int p; int scalenum=strlen(greyscales); accux=accuy=0; mingrey=maxgrey=0; // first: try to find the brightest/darkest pixels y_up=0; cnt=0; for (i=0;iheight;i++) { accuy+=rows; if (accuy>=picture->height || i==picture->height-1) { accuy-=picture->height; y_down=i+1; x_left=0; for (j=0;jwidth;j++) { accux+=cols; if (accux>=picture->width || j==picture->width-1) { x_right=j+1; accux-=picture->width; // at this point, a rectangle between y_up,y_down, x_left,x_right contains the pixels that need to be greyscaled. grey=0; cnt2=0; for (k=y_up;kpixels[k*picture->width+l]; grey+=(picture->palette[p]>>8)&0x7; // red grey+=(picture->palette[p]>>4)&0x7; // green grey+=(picture->palette[p]>>0)&0x7; // blue cnt2++; } } grey/=cnt2; if (cnt==0 || grey>maxgrey) maxgrey=grey; if (cnt==0 || greyheight;i++) { accuy+=rows; if (accuy>=picture->height || i==picture->height-1) { accuy-=picture->height; y_down=i+1; x_left=0; for (j=0;jwidth;j++) { accux+=cols; if (accux>=picture->width || j==picture->width-1) { x_right=j+1; accux-=picture->width; // at this point, a rectangle between y_up,y_down, x_left,x_right contains the pixels that need to be greyscaled. grey=0; cnt2=0; for (k=y_up;kpixels[k*picture->width+l]; grey+=(picture->palette[p]>>8)&0x7; // red grey+=(picture->palette[p]>>4)&0x7; // green grey+=(picture->palette[p]>>0)&0x7; // blue cnt2++; } } grey/=cnt2; grey-=mingrey; grey*=(scalenum-1); grey/=(maxgrey-mingrey); printf("%c",greyscales[grey]); x_left=x_right; } } y_up=y_down; printf("\n"); } } return 0; } dmagnetic-0.22/src/gui/xglk_callbacks.h0000644000175000017500000000353713621220604017466 0ustar dettusdettus/* Copyright 2019, dettus@dettus.net Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef XGLK_CALLBACKS_H #define XGLK_CALLBACKS_H int xglk_cbOutputChar(void* context,char c,unsigned char controlD2,unsigned char flag_headline); int xglk_cbOutputString(void* context,char* string,unsigned char controlD2,unsigned char flag_headline); int xglk_cbDrawPicture(void* context,tPicture* picture,int mode); int xglk_getsize(int *size); int xglk_open(void* hContext); int xglk_cbSaveGame(void* context,char* filename,void* ptr,int len); int xglk_cbLoadGame(void* context,char* filename,void* ptr,int len); int xglk_cbInputString(void* context,int* len,char* string); #endif dmagnetic-0.22/src/toplevel/0000755000175000017500000000000013621220610015404 5ustar dettusdettusdmagnetic-0.22/src/toplevel/picture.h0000644000175000017500000000302213621220604017230 0ustar dettusdettus/* Copyright 2019, dettus@dettus.net Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef PICTURE_H #define PICTURE_H // the purpose of this file is to provide the data structure for the pictures. typedef struct _tPicture { unsigned int palette[16]; int height; int width; char pixels[262144]; char halftones; } tPicture; #endif dmagnetic-0.22/src/toplevel/dMagnetic.c0000644000175000017500000004044213621220604017452 0ustar dettusdettus/* Copyright 2019, dettus@dettus.net Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include "version.h" #include "configuration.h" #include "vm68k.h" #include "linea.h" #include "default_callbacks.h" #include "maggfxloader.h" #define MAXMAGSIZE (1<<20) #define MAXGFXSIZE (1<<22) int dMagnetic_init(void** hVM68k,void** hLineA,void* pSharedMem,int memsize,char* magbuf,int magsize,char* gfxbuf,int gfxsize) { int sizevm68k; int sizelineA; int retval; int version; // step 2: start the engine. retval=vm68k_getsize(&sizevm68k); if (retval) { fprintf(stderr,"ERROR: vm68k_getsize returned %d\n",retval); return retval; } retval=lineA_getsize(&sizelineA); if (retval) { fprintf(stderr,"ERROR: lineA_getsize returned %d\n",retval); return retval; } *hVM68k=malloc(sizevm68k); *hLineA=malloc(sizelineA); if (*hVM68k==NULL || *hLineA==NULL) { fprintf(stderr,"ERROR: unable to allocate memory for the engine\n"); return -1; } retval=lineA_init(*hLineA,pSharedMem,&memsize,magbuf,magsize,gfxbuf,gfxsize); if (retval) { fprintf(stderr,"ERROR: lineA_init returned %d\n",retval); return retval; } retval=lineA_getVersion(*hLineA,&version); if (retval) { fprintf(stderr,"ERROR: lineA_getversion returned %d\n",retval); return retval; } fprintf(stderr,"Initializing the 68K version %d VM\n",version); if (version==4) { fprintf(stderr,"\n"); fprintf(stderr,"---------------------------------------\n"); fprintf(stderr,"- Version 4 of the VM requires you to -\n"); fprintf(stderr,"- activate the graphics manually. Use -\n"); fprintf(stderr,"- the command GRAPHICS now -\n"); fprintf(stderr,"---------------------------------------\n"); fprintf(stderr,"\n"); } retval=vm68k_init(*hVM68k,pSharedMem,memsize,version); if (retval) { fprintf(stderr,"ERROR: vm68k_init returned %d\n",retval); return retval; } return 0; } int main(int argc,char** argv) { int i; char inifilename[1024]; int retval; FILE *f_inifile=NULL; void* hVM68k; void* hLineA; void* hGUI; void* pSharedMem; int sharedmemsize; int sizeGUI; int unknownopcode; char *homedir; char random_mode; unsigned int random_seed; int egamode; char* magbuf; char* gfxbuf; // figure out the location of the inifile. if (!(retrievefromcommandline(argc,argv,"--version",NULL,0))) { fprintf(stderr,"*** dMagnetic %d.%d%d\n",VERSION_MAJOR,VERSION_MINOR,VERSION_REVISION); fprintf(stderr,"*** Use at your own risk\n"); fprintf(stderr,"*** (C)opyright 2019 by dettus@dettus.net\n"); fprintf(stderr,"*****************************************\n"); fprintf(stderr,"\n"); #define LOCNUM 12 const char *locations[LOCNUM]={"/etc/","/usr/local/share/","/usr/local/share/games/","/usr/local/share/dMagnetic/","/usr/local/games/","/usr/local/games/dMagnetic/","/usr/share/","/usr/share/games/","/usr/share/dMagnetic/","/usr/games/","/usr/games/dMagnetic/","./"}; f_inifile=NULL; if (f_inifile==NULL) { homedir=getenv("HOME"); snprintf(inifilename,1023,"%s/dMagnetic.ini",homedir); f_inifile=fopen(inifilename,"rb"); } for (i=0;i0x7fffffff) { printf("illegal random seed. please use a value between %d and %d\n",1,0x7fffffff); return 0; } } } if (argc) { char result[64]; if (retrievefromcommandline(argc,argv,"-rmode",result,sizeof(result))) { if (result[0]=='p') random_mode=0; else if (result[0]=='r') random_mode=1; else { printf("illegal parameter for -rmode. please use one of "); printf("pseudo "); printf("real "); printf("\n"); return 0; } } if (retrievefromcommandline(argc,argv,"-rseed",result,sizeof(result))) { random_seed=atoi(result); if (random_seed<1 || random_seed>0x7fffffff) { printf("illegal parameter for -rseed. please use a value between %d and %d\n",1,0x7fffffff); return 0; } } } egamode=0; if (f_inifile) { char result[64]; if (retrievefromcommandline(argc,argv,"-ega",result,sizeof(result))) { egamode=1; } } if (f_inifile) fclose(f_inifile); magbuf=malloc(MAXMAGSIZE); gfxbuf=malloc(MAXGFXSIZE); // this is the main loop. do { int magsize; int gfxsize; magsize=MAXMAGSIZE; gfxsize=MAXGFXSIZE; if (magbuf==NULL || gfxbuf==NULL) { fprintf(stderr,"ERROR: unable to allocate memory for the data files\n"); return -1; } f_inifile=fopen(inifilename,"rb"); if (loader_init(argc,argv,f_inifile, magbuf,&magsize,gfxbuf,&gfxsize)) { return 1; } retval=dMagnetic_init(&hVM68k,&hLineA,pSharedMem,sharedmemsize,magbuf,magsize,gfxbuf,gfxsize); if (retval) { return 0; } retval|=lineA_configrandom(hLineA,random_mode,random_seed); retval|=lineA_setEGAMode(hLineA,egamode); // set the call back hooks for this GUI retval|=lineA_setCBoutputChar(hLineA,default_cbOutputChar, hGUI); retval|=lineA_setCBoutputString(hLineA,default_cbOutputString, hGUI); retval|=lineA_setCBinputString(hLineA,default_cbInputString, hGUI); retval|=lineA_setCBDrawPicture(hLineA,default_cbDrawPicture, hGUI); retval|=lineA_setCBLoadGame(hLineA,default_cbLoadGame, hGUI); retval|=lineA_setCBSaveGame(hLineA,default_cbSaveGame, hGUI); if (retval) { fprintf(stderr,"ERROR: setting the API hooks failed\n"); return 0; } ///////////////////////////////////////////// lineA_showTitleScreen(hLineA); // some versions of the game have a title screen. // everything is good. have fun playing! do { unsigned short opcode; unknownopcode=0; retval=vm68k_getNextOpcode(hVM68k,&opcode); if (retval==VM68K_OK) retval=lineA_substitute_aliases(hLineA,&opcode); if (retval==LINEA_OK) retval=vm68k_singlestep(hVM68k,opcode); if (retval!=VM68K_OK) retval=lineA_singlestep(hLineA,hVM68k,opcode); if (retval!=LINEA_OK && retval!=LINEA_OK_QUIT && retval!=LINEA_OK_RESTART) { fprintf(stderr,"\x1b[0m\n\x1b[0;37;44m Sorry. Unknown opcode %04X\x1b[0m\n",opcode); unknownopcode=1; } // if (retval==LINEA_OK_QUIT) printf("\x1b[0m\n\x1b[0;37;44mGoodbye!\x1b[0m\n"); } while (!unknownopcode && !retval); } while (retval==LINEA_OK_RESTART); free(gfxbuf); free(magbuf); // this concludes the main loop free(pSharedMem); free(hGUI); free(hLineA); free(hVM68k); return 1; } dmagnetic-0.22/src/toplevel/dMagnetic_xglk.c0000644000175000017500000002256713621220604020507 0ustar dettusdettus/* Copyright 2019, dettus@dettus.net Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include "version.h" #include "configuration.h" #include "vm68k.h" #include "linea.h" #include "glk.h" #include "glkstart.h" #include "xglk_callbacks.h" glkunix_argumentlist_t glkunix_arguments[] = { { NULL, glkunix_arg_End, NULL } }; #define MAXMAGSIZE (1<<20) #define MAXGFXSIZE (1<<22) int dMagnetic_init(void** hVM68k,void** hLineA,void* pSharedMem,int memsize,char* magfilename,char* gfxfilename) { int sizevm68k; int sizelineA; int retval; int version; char* magbuf; char* gfxbuf; int magsize; int gfxsize; FILE *f; // step 1: load the game binaries magbuf=malloc(MAXMAGSIZE); gfxbuf=malloc(MAXGFXSIZE); if (magbuf==NULL || gfxbuf==NULL) { fprintf(stderr,"ERROR: unable to allocate memory for the data files\n"); return -1; } f=fopen(magfilename,"rb"); if (f==NULL) { fprintf(stderr,"ERROR: unable to open [%s]\n",magfilename); return -2; } magsize=fread(magbuf,sizeof(char),MAXMAGSIZE,f); fclose(f); f=fopen(gfxfilename,"rb"); if (f==NULL) { fprintf(stderr,"ERROR: unable to open [%s]\n",gfxfilename); return -2; } gfxsize=fread(gfxbuf,sizeof(char),MAXGFXSIZE,f); fclose(f); // at this point, they are stored in magbuf and gfxbuf. // step 2: start the engine. retval=vm68k_getsize(&sizevm68k); if (retval) { fprintf(stderr,"ERROR: vm68k_getsize returned %d\n",retval); return retval; } retval=lineA_getsize(&sizelineA); if (retval) { fprintf(stderr,"ERROR: lineA_getsize returned %d\n",retval); return retval; } *hVM68k=malloc(sizevm68k); *hLineA=malloc(sizelineA); if (*hVM68k==NULL || *hLineA==NULL) { fprintf(stderr,"ERROR: unable to allocate memory for the engine\n"); return -1; } retval=lineA_init(*hLineA,pSharedMem,&memsize,magbuf,magsize,gfxbuf,gfxsize); if (retval) { fprintf(stderr,"ERROR: lineA_init returned %d\n",retval); return retval; } retval=lineA_getVersion(*hLineA,&version); if (retval) { fprintf(stderr,"ERROR: lineA_getversion returned %d\n",retval); return retval; } fprintf(stderr,"Initializing the 68K version %d VM\n",version); retval=vm68k_init(*hVM68k,pSharedMem,memsize,version); if (retval) { fprintf(stderr,"ERROR: vm68k_init returned %d\n",retval); return retval; } // the relevant data from the game binaries has been copied. free(gfxbuf); free(magbuf); return 0; } int glkunix_startup_code(glkunix_startup_t *data) { return TRUE; } void glk_main(void) { char inifilename[1024]; char magfilename[1024]; char gfxfilename[1024]; int retval; FILE *f_inifile=NULL; void* hVM68k; void* hLineA; void* hGlk; void* pSharedMem; int sharedmemsize; int sizeGUI; int unknownopcode; inifilename[0]=0; magfilename[0]=0; gfxfilename[0]=0; fprintf(stderr,"*** dMagnetic_xglk\n"); fprintf(stderr,"*** Use at your own risk\n"); fprintf(stderr,"*** (C)opyright 2019 by dettus@dettus.net\n"); fprintf(stderr,"*****************************************\n"); fprintf(stderr,"\n"); f_inifile=fopen("dMagnetic.ini","rb"); if (!f_inifile) { fprintf(stderr,"error opening %s\n",inifilename); return; } //if (retrievefromcommandline(argc,argv,"pawn",NULL,0)) if (0) { magfilename[0]=gfxfilename[0]=0; retval=retrievefromini(f_inifile,"[FILES]","pawnmag",magfilename,sizeof(magfilename)); retval=retrievefromini(f_inifile,"[FILES]","pawngfx",gfxfilename,sizeof(gfxfilename)); } if (1)//retrievefromcommandline(argc,argv,"guild",NULL,0)) { magfilename[0]=gfxfilename[0]=0; retval=retrievefromini(f_inifile,"[FILES]","guildmag",magfilename,sizeof(magfilename)); retval=retrievefromini(f_inifile,"[FILES]","guildgfx",gfxfilename,sizeof(gfxfilename)); } /* if (retrievefromcommandline(argc,argv,"guild",NULL,0)) { magfilename[0]=gfxfilename[0]=0; retval=retrievefromini(f_inifile,"[FILES]","guildmag",magfilename,sizeof(magfilename)); retval=retrievefromini(f_inifile,"[FILES]","guildgfx",gfxfilename,sizeof(gfxfilename)); } if (retrievefromcommandline(argc,argv,"jinxter",NULL,0)) { magfilename[0]=gfxfilename[0]=0; retval=retrievefromini(f_inifile,"[FILES]","jinxtermag",magfilename,sizeof(magfilename)); retval=retrievefromini(f_inifile,"[FILES]","jinxtergfx",gfxfilename,sizeof(gfxfilename)); } if (retrievefromcommandline(argc,argv,"corruption",NULL,0)) { magfilename[0]=gfxfilename[0]=0; retval=retrievefromini(f_inifile,"[FILES]","corruptionmag",magfilename,sizeof(magfilename)); retval=retrievefromini(f_inifile,"[FILES]","corruptiongfx",gfxfilename,sizeof(gfxfilename)); } if (retrievefromcommandline(argc,argv,"fish",NULL,0)) { magfilename[0]=gfxfilename[0]=0; retval=retrievefromini(f_inifile,"[FILES]","fishmag",magfilename,sizeof(magfilename)); retval=retrievefromini(f_inifile,"[FILES]","fishgfx",gfxfilename,sizeof(gfxfilename)); } if (retrievefromcommandline(argc,argv,"myth",NULL,0)) { magfilename[0]=gfxfilename[0]=0; retval=retrievefromini(f_inifile,"[FILES]","mythmag",magfilename,sizeof(magfilename)); retval=retrievefromini(f_inifile,"[FILES]","mythgfx",gfxfilename,sizeof(gfxfilename)); } if (retrievefromcommandline(argc,argv,"wonderland",NULL,0)) { magfilename[0]=gfxfilename[0]=0; retval=retrievefromini(f_inifile,"[FILES]","wonderlandmag",magfilename,sizeof(magfilename)); retval=retrievefromini(f_inifile,"[FILES]","wonderlandgfx",gfxfilename,sizeof(gfxfilename)); } */ ///////////////////////////////////////////// init sharedmemsize=98304; pSharedMem=malloc(sharedmemsize); if (pSharedMem==NULL) { fprintf(stderr,"ERROR: unable to allocate shared memory\n"); return; } retval=xglk_getsize(&sizeGUI); if (retval) { fprintf(stderr,"ERROR. default_getsize returned %d\n",retval); return; } hGlk=malloc(sizeGUI); if (hGlk==NULL) { fprintf(stderr,"ERROR: unable to locate memory for the GLK\n"); return; } retval=xglk_open(hGlk); if (retval) { fprintf(stderr,"ERROR: opening the GUI failed\n"); return; } if (f_inifile) fclose(f_inifile); // this is the main loop. do { retval=dMagnetic_init(&hVM68k,&hLineA,pSharedMem,sharedmemsize,magfilename,gfxfilename); if (retval) { return; } // set the call back hooks for this GUI retval|=lineA_setCBoutputChar(hLineA,xglk_cbOutputChar, hGlk); retval|=lineA_setCBoutputString(hLineA,xglk_cbOutputString, hGlk); retval|=lineA_setCBinputString(hLineA,xglk_cbInputString, hGlk); retval|=lineA_setCBDrawPicture(hLineA,xglk_cbDrawPicture, hGlk); retval|=lineA_setCBLoadGame(hLineA,xglk_cbLoadGame, hGlk); retval|=lineA_setCBSaveGame(hLineA,xglk_cbSaveGame, hGlk); if (retval) { fprintf(stderr,"ERROR: setting the API hooks failed\n"); return; } ///////////////////////////////////////////// // everything is good. have fun playing! do { unsigned short opcode; unknownopcode=0; retval=vm68k_getNextOpcode(hVM68k,&opcode); if (retval==VM68K_OK) retval=lineA_substitute_aliases(hLineA,&opcode); if (retval==LINEA_OK) retval=vm68k_singlestep(hVM68k,opcode); if (retval!=VM68K_OK) retval=lineA_singlestep(hLineA,hVM68k,opcode); if (retval!=LINEA_OK && retval!=LINEA_OK_QUIT && retval!=LINEA_OK_RESTART) { fprintf(stderr,"\x1b[0m\n\x1b[0;37;44m Sorry. Unknown opcode %04X\x1b[0m\n",opcode); unknownopcode=1; } // if (retval==LINEA_OK_QUIT) printf("\x1b[0m\n\x1b[0;37;44mGoodbye!\x1b[0m\n"); } while (!unknownopcode && !retval); } while (retval==LINEA_OK_RESTART); // this concludes the main loop free(pSharedMem); free(hGlk); free(hLineA); free(hVM68k); return; } dmagnetic-0.22/src/toplevel/configuration.c0000644000175000017500000000677513621220604020441 0ustar dettusdettus/* Copyright 2019, dettus@dettus.net Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include "configuration.h" int retrievefromini(FILE *f,char* section,char* entry,char* retstring,int retstringspace) { char line[1024]; int i; int j; int l,ls,le; char lc; int state; int found; found=0; state=0; // state 0: search for the [section] // state 1: search for the entry= // state 2: done ls=strlen(section); le=strlen(entry); fseek(f,0,SEEK_SET); state=0; do { if (fgets(line,sizeof(line),f)==NULL) return 0; l=strlen(line); j=0; lc=0; // reduce the line: remove spaces, unless they are escaped. for (i=0;i=32) // escaped { line[j++]=c; // keep this character } else if (c==';' || c<32) { line[j++]=0; // terminate the line here } else if (c>32 && c!='\\') { line[j++]=c; } lc=c; } line[j]=0; l=strlen(line); if (l) { if (line[0]=='[' && state==0) // this is a section, see if it is a match. { int match; match=(ls==l); // cannot be a match for (i=0;ile && line[le]=='=') match=1; for (i=0;i(l-le)) { memcpy(retstring,&line[le+1],l-le); found=1; } } } } while (!feof(f) && state!=2 && !found); return found; } int retrievefromcommandline(int argc,char** argv,char* parameter, char* retstring,int retstringspace) { int i; int found; found=0; for (i=0;istrlen(argv[i+1])) { memcpy(retstring,argv[i+1],strlen(argv[i+1])+1); } else found=-2; } } } } } return found; } dmagnetic-0.22/src/toplevel/configuration.h0000644000175000017500000000301713621220604020430 0ustar dettusdettus/* Copyright 2019, dettus@dettus.net Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef CONFIGURATION_H #define CONFIGURATION_H int retrievefromini(FILE *f,char* section,char* entry,char* retstring,int retstringsize); int retrievefromcommandline(int argc,char** argv,char* parameter, char* retstring,int retstringspace); #endif dmagnetic-0.22/src/toplevel/version.h0000644000175000017500000000261713621220604017253 0ustar dettusdettus/* Copyright 2019, dettus@dettus.net Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef VERSION_H #define VERSION_H #define VERSION_MAJOR 0 #define VERSION_MINOR 2 #define VERSION_REVISION 2 #endif dmagnetic-0.22/src/engine/0000755000175000017500000000000013621220604015022 5ustar dettusdettusdmagnetic-0.22/src/engine/vm68k/0000755000175000017500000000000013621220610015772 5ustar dettusdettusdmagnetic-0.22/src/engine/vm68k/vm68k_decode.c0000644000175000017500000004226113621220604020424 0ustar dettusdettus/* Copyright 2019, dettus@dettus.net Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include "vm68k_datatypes.h" #include "vm68k_decode.h" // the purpose of this function is to perform a pattern matching to the instruction, and return the enumeration value. // the more bits are constant, the higher should be the matche's priority. tVM68k_instruction vm68k_decode(tVM68k_uword opcode) { tVM68k_instruction retval=VM68K_INST_UNKNOWN; // instructions with 16 constant bits if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xffff)==0x023c) retval=VM68K_INST_ANDItoCCR; //ANDItoCCR: 0000 0010 0011 1100 00000000dddddddd if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xffff)==0x027c) retval=VM68K_INST_ANDItoSR; //ANDItoSR: 0000 0010 0111 1100 dddddddddddddddd if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xffff)==0x0A3C) retval=VM68K_INST_EORItoCCR; //EORItoCCR: 0000 1010 0011 1100 00000000dddddddd if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xffff)==0x0A7C) retval=VM68K_INST_EORItoSR; //EORItoSR: 0000 1010 0111 1100 dddddddddddddddd if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xffff)==0x4AFC) retval=VM68K_INST_ILLEGAL; //ILLEGAL: 0100 1010 1111 1100 if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xffff)==0x4E71) retval=VM68K_INST_NOP; if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xffff)==0x003C) retval=VM68K_INST_ORItoCCR; //ORItoCCR: 0000 0000 0011 1100 00000000dddddddd if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xffff)==0x007C) retval=VM68K_INST_ORItoSR; //ORItoSR: 0000 0000 0111 1100 dddddddddddddddd if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xffff)==0x4E70) retval=VM68K_INST_RESET; //RESET: 0100 1110 0111 0000 if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xffff)==0x4E73) retval=VM68K_INST_RTE; //RTE: 0100 1110 0111 0011 if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xffff)==0x4E77) retval=VM68K_INST_RTR; //RTR: 0100 1110 0111 0111 if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xffff)==0x4E75) retval=VM68K_INST_RTS; //RTS: 0100 1110 0111 0101 if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xffff)==0x4E72) retval=VM68K_INST_STOP; //STOP: 0100 1110 0111 0010 iiiiiiiiiiiiiiii if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xffff)==0x4E76) retval=VM68K_INST_TRAPV; //TRAPV: 0100 1110 0111 0110 // instructions with 13 constant bits if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xfff8)==0x4E50) retval=VM68K_INST_LINK; //LINK: 0100 1110 0101 0yyy dddddddddddddddd if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xfff8)==0x4840) retval=VM68K_INST_SWAP; //SWAP: 0100 1000 0100 0yyy if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xfff8)==0x4E58) retval=VM68K_INST_UNLK; //UNLK: 0100 1110 0101 1yyy // instructions with 12 constant bits if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xfff0)==0x4E40) retval=VM68K_INST_TRAP; //TRAP: 0100 1110 0100 vvvv if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xfff0)==0x4E60) retval=VM68K_INST_MOVEUSP; //MOVE USP: 0100 1110 0110 dyyy // instructions with 10 constant bits if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xffc0)==0x0800) retval=VM68K_INST_BTSTB; //BTST.B: 0000 1000 00mm myyy 0000 0000 bbbb bbbb if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xffc0)==0x0840) retval=VM68K_INST_BCHGB; //BCHG.B: 0000 1000 01mm myyy if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xffc0)==0x0880) retval=VM68K_INST_BCLRI; //BCLRI: 0000 1000 10mm myyy if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xffc0)==0x08C0) retval=VM68K_INST_BSETB; //BSET.B: 0000 1000 11mm myyy if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xffc0)==0x44C0) retval=VM68K_INST_MOVEtoCCR; //MOVEtoCCR: 0100 0100 11mm myyy if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xffc0)==0x40C0) retval=VM68K_INST_MOVEfromSR; //MOVEfromSR:0100 0000 11mm myyy if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xffc0)==0x46C0) retval=VM68K_INST_MOVEtoSR; //MOVEtoSR: 0100 0110 11mm myyy if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xffc0)==0x4840) retval=VM68K_INST_PEA; //PEA: 0100 1000 01mm myyy if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xffc0)==0x4AC0) retval=VM68K_INST_TAS; //TAS: 0100 1010 11mm myyy if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xffC0)==0x4EC0) retval=VM68K_INST_JMP; //JMP: 0100 1110 11mm myyy if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xffC0)==0x4E80) retval=VM68K_INST_JSR; //JSR: 0100 1110 10mm myyy if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xfe38)==0x4800) retval=VM68K_INST_EXT; //EXT: 0100 100o oo00 0yyy // instructions with 9 constant bits if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xf0f8)==0x50C8) retval=VM68K_INST_DBcc; //DBcc: 0101 CCCC 1100 1yyy if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xf1f0)==0xC100) retval=VM68K_INST_ABCD; //ABCD: 1100 xxx1 0000 myyy if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xf1f0)==0x8100) retval=VM68K_INST_SBCD; //SBCD: 1000 xxx1 0000 ryyy if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xff80)==0x4880) retval=VM68K_INST_MOVEMregtomem; //MOVEM: 0100 1000 1smm myyy // reg to mem if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xff80)==0x4C80) retval=VM68K_INST_MOVEMmemtoreg; //MOVEM: 0100 1100 1smm myyy // mem to reg if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xf1C0)==0x01C0) retval=VM68K_INST_BSET; //BSET: 0000 xxx1 11mm myyy // instructions with 8 constant bits if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xff00)==0x4200) retval=VM68K_INST_CLR; //CLR: 0100 0010 ssmm myyy if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xff00)==0x0C00) retval=VM68K_INST_CMPI; //CMPI: 0000 1100 ssmm myyy if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xff00)==0x0A00) retval=VM68K_INST_EORI; //EORI: 0000 1010 ssmm myyy if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xff00)==0x0600) retval=VM68K_INST_ADDI; //ADDI: 0000 0110 ssmm myyy if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xff00)==0x0200) retval=VM68K_INST_ANDI; //ANDI: 0000 0010 ssmm myyy if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xff00)==0x0000) retval=VM68K_INST_ORI; //ORI: 0000 0000 ssmm myyy if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xff00)==0x4400) retval=VM68K_INST_NEG; //NEG: 0100 0100 ssmm myyy if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xff00)==0x4000) retval=VM68K_INST_NEGX; //NEGX: 0100 0000 ssmm myyy if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xff00)==0x4600) retval=VM68K_INST_NOT; //NOT: 0100 0110 ssmm myyy if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xff00)==0x0400) retval=VM68K_INST_SUBI; //SUBI: 0000 0100 ssmm myyy if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xff00)==0x4A00) retval=VM68K_INST_TST; //TST: 0100 1010 ssmm myyy if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xf0C0)==0xD0C0) retval=VM68K_INST_ADDA; //ADDA: 1101 rrrs 11mm myyy // IMPORTANT! THIS HAS TO COME BEFORE ADDX! if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xf130)==0xD100) retval=VM68K_INST_ADDX; //ADDX: 1101 xxx1 ss00 myyy // s=00,01,10=ADDX. 11=ADDA!! if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xf130)==0xC100) retval=VM68K_INST_EXG; //EXG: 1100 xxx1 oo00 oyyy if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xf0C0)==0x90C0) retval=VM68K_INST_SUBA; //SUBA: 1001 xxxo 11mm myyy // probably the same problem as ADDA/ADDX. if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xf130)==0x9100) retval=VM68K_INST_SUBX; //SUBX: 1001 yyy1 ss00 ryyy if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xf0C0)==0xB0C0) retval=VM68K_INST_CMPA; //CMPA: 1011 xxxo 11mm myyy /// IMPORANT! THIS HAS TO COME BEFORE CMPM! if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xf138)==0xb108) retval=VM68K_INST_CMPM; //CMPM: 1011 xxx1 ss00 1yyy // instructions with 7 constant bits if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xf1c0)==0x0140) retval=VM68K_INST_BCHG; //BCHG: 0000 rrr1 01mm myyy if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xf1c0)==0x0180) retval=VM68K_INST_BCLR; //BCLR: 0000 xxx1 10mm myyy if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xf1C0)==0x0100) retval=VM68K_INST_BTST; //BTST: 0000 xxx1 00mm myyy if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xf1C0)==0x81C0) retval=VM68K_INST_DIVS; //DIVS: 1000 xxx1 11mm myyy if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xf1C0)==0x80C0) retval=VM68K_INST_DIVU; //DIVU: 1000 xxx0 11mm myyy if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xf1C0)==0xC1C0) retval=VM68K_INST_MULS; //MULS: 1100 xxx1 11mm myyy if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xf1C0)==0xC0C0) retval=VM68K_INST_MULU; //MULU: 1100 xxx0 11mm myyy if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xf1C0)==0x41C0) retval=VM68K_INST_LEA; //LEA: 0100 xxx1 11mm myyy if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xf038)==0x0008) retval=VM68K_INST_MOVEP; //MOVEP: 0000 xxxo oo00 1yyy dddddddddddddddd // instructions with 6 constant bits if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xf018)==0xe018) retval=VM68K_INST_ROL_ROR; //ROL/ROR: 1110 cccd ssl1 1yyy if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xf018)==0xe010) retval=VM68K_INST_ROXL_ROXR; //ROXL/ROXR: 1110 cccd ssl1 0yyy if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xf0c0)==0x50C0) retval=VM68K_INST_SCC; //SCC: 0101 CCCC 11mm myyy if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xf140)==0x4100) retval=VM68K_INST_CHK; //CHK: 0100 xxx1 s0mm myyy if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xf018)==0xE008) retval=VM68K_INST_LSL_LSR; //LSL/LSR: 1110 cccd ssl0 1yyy if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xf018)==0xE000) retval=VM68K_INST_ASL_ASR; //ASL/ASR: 1110 cccd ssl0 0yyy // instructions with 5 constant bits if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xf100)==0x5000) retval=VM68K_INST_ADDQ; //ADDQ: 0101 ddd0 ssmm myyy if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xf100)==0xb100) retval=VM68K_INST_EOR; //EOR: 1011 xxx1 oomm myyy if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xf100)==0x7000) retval=VM68K_INST_MOVEQ; //MOVEQ: 0111 xxx0 dddd dddd if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xf000)==0x9000) retval=VM68K_INST_SUB; //SUB: 1001 xxx0 oomm myyy if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xf100)==0x5100) retval=VM68K_INST_SUBQ; //SUBQ: 0101 ddd1 ssmm myyy if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xC1C0)==0x0040) retval=VM68K_INST_MOVEA; //MOVEA: 00ss xxx0 01mm myyy // instructions with 4 constant bits // if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xf000)==0xD000) retval=VM68K_INST_ADD; //ADD: 1101 rrro oomm myyy if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xf000)==0xC000) retval=VM68K_INST_AND; //AND: 1100 xxxo oomm myyy if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xf000)==0x6000) retval=VM68K_INST_BCC; //BCC: 0110 CCCC dddd dddd if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xf000)==0xB000) retval=VM68K_INST_CMP; //CMP: 1011 xxx0 oomm myyy if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xf000)==0x8000) retval=VM68K_INST_OR; //OR: 1000 xxxo oomm myyy // instructions with 2 constant bits if (retval==VM68K_INST_UNKNOWN) if ((opcode&0xc000)==0x0000) retval=VM68K_INST_MOVE; //MOVE: 00ss xxxm mmMM Myyy return retval; } void vm68k_get_instructionname(tVM68k_instruction instruction,char* name) { switch(instruction) { case VM68K_INST_UNKNOWN : snprintf(name,16,"UNKNOWN");break; case VM68K_INST_ABCD : snprintf(name,16,"ABCD");break; case VM68K_INST_ADD : snprintf(name,16,"ADD");break; case VM68K_INST_ADDA : snprintf(name,16,"ADDA");break; case VM68K_INST_ADDI : snprintf(name,16,"ADDI");break; case VM68K_INST_ADDQ : snprintf(name,16,"ADDQ");break; case VM68K_INST_ADDX : snprintf(name,16,"ADDX");break; case VM68K_INST_AND : snprintf(name,16,"AND");break; case VM68K_INST_ANDI : snprintf(name,16,"ANDI");break; case VM68K_INST_ANDItoCCR : snprintf(name,16,"ANDItoCCR");break; case VM68K_INST_ANDItoSR : snprintf(name,16,"ANDItoSR");break; case VM68K_INST_ASL_ASR : snprintf(name,16,"ASL_ASR");break; case VM68K_INST_BCC : snprintf(name,16,"BCC");break; case VM68K_INST_BCHG : snprintf(name,16,"BCHG");break; case VM68K_INST_BCHGB : snprintf(name,16,"BCHGB");break; case VM68K_INST_BCLR : snprintf(name,16,"BCLR");break; case VM68K_INST_BCLRI : snprintf(name,16,"BCLRI");break; case VM68K_INST_BRA : snprintf(name,16,"BRA");break; case VM68K_INST_BSET : snprintf(name,16,"BSET");break; case VM68K_INST_BSETB : snprintf(name,16,"BSETB");break; //case VM68K_INST_BSR : snprintf(name,16,"BSR");break; case VM68K_INST_BTST : snprintf(name,16,"BTST");break; case VM68K_INST_BTSTB : snprintf(name,16,"BTSTB");break; case VM68K_INST_CHK : snprintf(name,16,"CHK");break; case VM68K_INST_CLR : snprintf(name,16,"CLR");break; case VM68K_INST_CMP : snprintf(name,16,"CMP");break; case VM68K_INST_CMPA : snprintf(name,16,"CMPA");break; case VM68K_INST_CMPI : snprintf(name,16,"CMPI");break; case VM68K_INST_CMPM : snprintf(name,16,"CMPM");break; case VM68K_INST_DBcc : snprintf(name,16,"DBcc");break; case VM68K_INST_DIVS : snprintf(name,16,"DIVS");break; case VM68K_INST_DIVU : snprintf(name,16,"DIVU");break; case VM68K_INST_EOR : snprintf(name,16,"EOR");break; case VM68K_INST_EORI : snprintf(name,16,"EORI");break; case VM68K_INST_EORItoCCR : snprintf(name,16,"EORItoCCR");break; case VM68K_INST_EORItoSR : snprintf(name,16,"EORItoSR");break; case VM68K_INST_EXG : snprintf(name,16,"EXG");break; case VM68K_INST_EXT : snprintf(name,16,"EXT");break; case VM68K_INST_ILLEGAL : snprintf(name,16,"ILLEGAL");break; case VM68K_INST_JMP : snprintf(name,16,"JMP");break; case VM68K_INST_JSR : snprintf(name,16,"JSR");break; case VM68K_INST_LEA : snprintf(name,16,"LEA");break; case VM68K_INST_LINK : snprintf(name,16,"LINK");break; case VM68K_INST_LSL_LSR : snprintf(name,16,"LSL_LSR");break; case VM68K_INST_MOVE : snprintf(name,16,"MOVE");break; case VM68K_INST_MOVEA : snprintf(name,16,"MOVEA");break; case VM68K_INST_MOVEtoCCR : snprintf(name,16,"MOVEtoCCR");break; case VM68K_INST_MOVEfromSR : snprintf(name,16,"MOVEfromSR");break; case VM68K_INST_MOVEtoSR : snprintf(name,16,"MOVEtoSR");break; case VM68K_INST_MOVEUSP : snprintf(name,16,"MOVEUSP");break; case VM68K_INST_MOVEMregtomem : snprintf(name,16,"MOVEMregtomem");break; case VM68K_INST_MOVEMmemtoreg : snprintf(name,16,"MOVEMmemtoreg");break; case VM68K_INST_MOVEP : snprintf(name,16,"MOVEP");break; case VM68K_INST_MOVEQ : snprintf(name,16,"MOVEQ");break; case VM68K_INST_MULS : snprintf(name,16,"MULS");break; case VM68K_INST_MULU : snprintf(name,16,"MULU");break; case VM68K_INST_NBCD : snprintf(name,16,"NBCD");break; case VM68K_INST_NEG : snprintf(name,16,"NEG");break; case VM68K_INST_NEGX : snprintf(name,16,"NEGX");break; case VM68K_INST_NOP : snprintf(name,16,"NOP");break; case VM68K_INST_NOT : snprintf(name,16,"NOT");break; case VM68K_INST_OR : snprintf(name,16,"OR");break; case VM68K_INST_ORI : snprintf(name,16,"ORI");break; case VM68K_INST_ORItoCCR : snprintf(name,16,"ORItoCCR");break; case VM68K_INST_ORItoSR : snprintf(name,16,"ORItoSR");break; case VM68K_INST_PEA : snprintf(name,16,"PEA");break; case VM68K_INST_RESET : snprintf(name,16,"RESET");break; case VM68K_INST_ROL_ROR : snprintf(name,16,"ROL_ROR");break; case VM68K_INST_ROXL_ROXR : snprintf(name,16,"ROXL_ROXR");break; case VM68K_INST_RTE : snprintf(name,16,"RTE");break; case VM68K_INST_RTR : snprintf(name,16,"RTR");break; case VM68K_INST_RTS : snprintf(name,16,"RTS");break; case VM68K_INST_SBCD : snprintf(name,16,"SBCD");break; case VM68K_INST_SCC : snprintf(name,16,"SCC");break; case VM68K_INST_STOP : snprintf(name,16,"STOP");break; case VM68K_INST_SUB : snprintf(name,16,"SUB");break; case VM68K_INST_SUBA : snprintf(name,16,"SUBA");break; case VM68K_INST_SUBI : snprintf(name,16,"SUBI");break; case VM68K_INST_SUBQ : snprintf(name,16,"SUBQ");break; case VM68K_INST_SUBX : snprintf(name,16,"SUBX");break; case VM68K_INST_SWAP : snprintf(name,16,"SWAP");break; case VM68K_INST_TAS : snprintf(name,16,"TAS");break; case VM68K_INST_TRAP : snprintf(name,16,"TRAP");break; case VM68K_INST_TRAPV : snprintf(name,16,"TRAPV");break; case VM68K_INST_TST : snprintf(name,16,"TST");break; case VM68K_INST_UNLK : snprintf(name,16,"UNLK");break; } } dmagnetic-0.22/src/engine/vm68k/vm68k_macros.h0000644000175000017500000001404713621220604020473 0ustar dettusdettus/* Copyright 2019, dettus@dettus.net Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef VM68K_MACROS_H #define VM68K_MACROS_H #include "vm68k_datatypes.h" #define READ_INT32BE(ptr,idx) (\ (((tVM68k_ulong)((ptr)[((idx)+0)])&0xff)<<24) |\ (((tVM68k_ulong)((ptr)[((idx)+1)])&0xff)<<16) |\ (((tVM68k_ulong)((ptr)[((idx)+2)])&0xff)<< 8) |\ (((tVM68k_ulong)((ptr)[((idx)+3)])&0xff)<< 0) |\ 0) #define READ_INT16BE(ptr,idx) (\ (((tVM68k_ulong)((ptr)[((idx)+0)])&0xff)<< 8) |\ (((tVM68k_ulong)((ptr)[((idx)+1)])&0xff)<< 0) |\ 0) #define READ_INT8BE(ptr,idx) (\ (((tVM68k_ulong)((ptr)[((idx)+0)])&0xff)<< 0) |\ 0) #define READ_INT32LE(ptr,idx) (\ (((unsigned int)((ptr)[((idx)+3)])&0xff)<<24) |\ (((unsigned int)((ptr)[((idx)+2)])&0xff)<<16) |\ (((unsigned int)((ptr)[((idx)+1)])&0xff)<< 8) |\ (((unsigned int)((ptr)[((idx)+0)])&0xff)<< 0) |\ 0) #define READ_INT16LE(ptr,idx) (\ (((unsigned int)((ptr)[((idx)+1)])&0xff)<< 8) |\ (((unsigned int)((ptr)[((idx)+0)])&0xff)<< 0) |\ 0) #define READ_INT8LE(ptr,idx) (\ (((unsigned int)((ptr)[((idx)+0)])&0xff)<< 0) |\ 0) #define WRITE_INT32BE(ptr,idx,val) {\ (ptr)[(idx)+3]=((tVM68k_ubyte)((val)>> 0)&0xff); \ (ptr)[(idx)+2]=((tVM68k_ubyte)((val)>> 8)&0xff); \ (ptr)[(idx)+1]=((tVM68k_ubyte)((val)>>16)&0xff); \ (ptr)[(idx)+0]=((tVM68k_ubyte)((val)>>24)&0xff); \ } #define WRITE_INT16BE(ptr,idx,val) {\ (ptr)[(idx)+1]=((tVM68k_ubyte)((val)>> 0)&0xff); \ (ptr)[(idx)+0]=((tVM68k_ubyte)((val)>> 8)&0xff); \ } #define WRITE_INT8BE(ptr,idx,val) {\ (ptr)[(idx)+0]=((tVM68k_ubyte)((val)>> 0)&0xff); \ } #define WRITE_INT32LE(ptr,idx,val) {\ (ptr)[(idx)+0]=((unsigned char)((val)>> 0)&0xff); \ (ptr)[(idx)+1]=((unsigned char)((val)>> 8)&0xff); \ (ptr)[(idx)+2]=((unsigned char)((val)>>16)&0xff); \ (ptr)[(idx)+3]=((unsigned char)((val)>>24)&0xff); \ } #define WRITE_INT16LE(ptr,idx,val) {\ (ptr)[(idx)+0]=((unsigned char)((val)>> 0)&0xff); \ (ptr)[(idx)+1]=((unsigned char)((val)>> 8)&0xff); \ } #define WRITE_INT8LE(ptr,idx,val) {\ (ptr)[(idx)+0]=((unsigned char)((val)>> 0)&0xff); \ } #define INITNEXT(pVM68k,next) \ (next).pcr=(pVM68k)->pcr; \ (next).a[0]=(pVM68k)->a[0]; \ (next).a[1]=(pVM68k)->a[1]; \ (next).a[2]=(pVM68k)->a[2]; \ (next).a[3]=(pVM68k)->a[3]; \ (next).a[4]=(pVM68k)->a[4]; \ (next).a[5]=(pVM68k)->a[5]; \ (next).a[6]=(pVM68k)->a[6]; \ (next).a[7]=(pVM68k)->a[7]; \ (next).d[0]=(pVM68k)->d[0]; \ (next).d[1]=(pVM68k)->d[1]; \ (next).d[2]=(pVM68k)->d[2]; \ (next).d[3]=(pVM68k)->d[3]; \ (next).d[4]=(pVM68k)->d[4]; \ (next).d[5]=(pVM68k)->d[5]; \ (next).d[6]=(pVM68k)->d[6]; \ (next).d[7]=(pVM68k)->d[7]; \ (next).override_sr=0; \ (next).sr=((pVM68k)->sr); \ (next).cflag=((pVM68k)->sr>>0)&1; \ (next).vflag=((pVM68k)->sr>>1)&1; \ (next).zflag=((pVM68k)->sr>>2)&1; \ (next).nflag=((pVM68k)->sr>>3)&1; \ (next).xflag=((pVM68k)->sr>>4)&1; \ (next).mem_we=0; \ (next).mem_addr[0]=0; \ (next).mem_size=0; \ (next).mem_value[0]=0; #define WRITEFLAGS(pVM68k,transaction) \ (pVM68k)->sr|=(tVM68k_uword)((transaction).cflag)<<0; \ (pVM68k)->sr|=(tVM68k_uword)((transaction).vflag)<<1; \ (pVM68k)->sr|=(tVM68k_uword)((transaction).zflag)<<2; \ (pVM68k)->sr|=(tVM68k_uword)((transaction).nflag)<<3; \ (pVM68k)->sr|=(tVM68k_uword)((transaction).xflag)<<4; #define READEXTENSIONBYTE(pVM68k,pNext) READ_INT8BE((pVM68k)->pMem,(pNext)->pcr+1);(pNext)->pcr+=2; #define READEXTENSIONWORD(pVM68k,pNext) READ_INT16BE((pVM68k)->pMem,(pNext)->pcr);(pNext)->pcr+=2; #define READEXTENSIONLONG(pVM68k,pNext) READ_INT32BE((pVM68k)->pMem,(pNext)->pcr);(pNext)->pcr+=4; #define READEXTENSION(pVM68k,pNext,datatype,operand) \ switch (datatype) \ { \ case VM68K_BYTE: operand=READEXTENSIONBYTE(pVM68k,pNext);break; \ case VM68K_WORD: operand=READEXTENSIONWORD(pVM68k,pNext);break; \ case VM68K_LONG: operand=READEXTENSIONLONG(pVM68k,pNext);break; \ default: operand=0;break; \ } #define READSIGNEDEXTENSION(pVM68k,pNext,datatype,operand) \ switch (datatype) \ { \ case VM68K_BYTE: operand=READEXTENSIONBYTE(pVM68k,pNext);operand=(tVM68k_slong)((tVM68k_sbyte)((operand)& 0xff));break; \ case VM68K_WORD: operand=READEXTENSIONBYTE(pVM68k,pNext);operand=(tVM68k_slong)((tVM68k_sword)((operand)&0xffff));break; \ case VM68K_LONG: operand=READEXTENSIONLONG(pVM68k,pNext);break; \ } #define PUSHWORDTOSTACK(pVM68k,pNext,x) {(pNext)->a[7]-=2;(pNext)->mem_addr[(pNext)->mem_we]=(pNext)->a[7];(pNext)->mem_size=VM68K_WORD;(pNext)->mem_value[(pNext)->mem_we]=x;(pNext)->mem_we++;} #define PUSHLONGTOSTACK(pVM68k,pNext,x) {(pNext)->a[7]-=4;(pNext)->mem_addr[(pNext)->mem_we]=(pNext)->a[7];(pNext)->mem_size=VM68K_LONG;(pNext)->mem_value[(pNext)->mem_we]=x;(pNext)->mem_we++;} #define POPWORDFROMSTACK(pVM68k,pNext,x) {tVM68k_uword y;y=READ_INT16BE((pVM68k)->pMem,(pNext)->a[7]);(pNext)->a[7]+=2;x=((x)&0xffff0000)|(y&0xffff);} #define POPLONGFROMSTACK(pVM68k,pNext,x) {x=READ_INT32BE((pVM68k)->pMem,(pNext)->a[7]);(pNext)->a[7]+=4;} #endif dmagnetic-0.22/src/engine/vm68k/vm68k_loadstore.c0000644000175000017500000002602013621220604021170 0ustar dettusdettus/* Copyright 2019, dettus@dettus.net Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include "vm68k.h" #include "vm68k_decode.h" #include "vm68k_datatypes.h" #include "vm68k_macros.h" #include "vm68k_loadstore.h" int vm68k_getbytesize(tVM68k_types size) { switch(size) { case VM68K_BYTE: return 1;break; case VM68K_WORD: return 2;break; case VM68K_LONG: return 4;break; default: return 0; } return 0; } // the way addresses are stored here is that memory addresses are >=0. <=0 addresses the registers. int vm68k_resolve_ea(tVM68k* pVM68k,tVM68k_next *pNext,tVM68k_types size, tVM68k_addrmodes addrmode,tVM68k_ubyte reg, tVM68k_uword legal,tVM68k_slong* ea) { tVM68k_sbyte bytesize; int retval; retval=VM68K_NOK_UNKNOWN_INSTRUCTION; bytesize=vm68k_getbytesize(size); if (addrmode==VM68K_AM_EXT) { switch ((tVM68k_addrmode_ext)reg) { case VM68K_AMX_W: if (legal&VM68K_LEGAL_AMX_W) { *ea=(tVM68k_sword)READEXTENSIONWORD(pVM68k,pNext); retval=VM68K_OK; } break; case VM68K_AMX_L: if (legal&VM68K_LEGAL_AMX_L) { *ea=(tVM68k_slong)READEXTENSIONLONG(pVM68k,pNext); retval=VM68K_OK; } break; case VM68K_AMX_data: if (legal&VM68K_LEGAL_AMX_DATA) { *ea=pNext->pcr; switch (size) { case VM68K_BYTE: *ea+=1;pNext->pcr+=2;break; case VM68K_WORD: pNext->pcr+=2;break; case VM68K_LONG: pNext->pcr+=4;break; default: retval=VM68K_NOK_UNKNOWN_INSTRUCTION; } retval=VM68K_OK; } break; case VM68K_AMX_PC: if (legal&VM68K_LEGAL_AMX_PC) { *ea=READEXTENSIONWORD(pVM68k,pNext); *ea=(tVM68k_sword)(*ea)+pVM68k->pcr; retval=VM68K_OK; } break; case VM68K_AMX_INDEX_PC: if (legal&VM68K_LEGAL_AMX_INDEX_PC) { *ea=READEXTENSIONWORD(pVM68k,pNext); *ea=*ea+pVM68k->pcr; *ea=*ea+pVM68k->a[reg]*bytesize; // TODO: data or addrreg? retval=VM68K_NOK_UNKNOWN_INSTRUCTION; // TODO: lets decide when we stumble upon this mode } break; } } else { switch (addrmode) { case VM68K_AM_DATAREG: if (legal&VM68K_LEGAL_AM_DATAREG) { *ea=DATAREGADDR(reg); retval=VM68K_OK; } break; case VM68K_AM_ADDRREG: if (legal&VM68K_LEGAL_AM_ADDRREG) { *ea=ADDRREGADDR(reg); retval=VM68K_OK; } break; case VM68K_AM_INDIR: if (legal&VM68K_LEGAL_AM_INDIR) { *ea=(pVM68k->a[reg])%pVM68k->memsize; retval=VM68K_OK; } break; case VM68K_AM_POSTINC: if (legal&VM68K_LEGAL_AM_POSTINC) { *ea=pVM68k->a[reg]; pNext->a[reg]+=bytesize; retval=VM68K_OK; } break; case VM68K_AM_PREDEC: if (legal&VM68K_LEGAL_AM_PREDEC) { pNext->a[reg]-=bytesize; *ea=pNext->a[reg]; retval=VM68K_OK; } break; case VM68K_AM_DISP16: if (legal&VM68K_LEGAL_AM_DISP16) { *ea=(tVM68k_sword)READEXTENSIONWORD(pVM68k,pNext); *ea=(*ea)+pVM68k->a[reg]; retval=VM68K_OK; } break; case VM68K_AM_INDEX: if (legal&VM68K_LEGAL_AM_INDEX) { tVM68k_uword extword; // bit 15: =0 data, =1 addr reg // bit 14..12: regnum // bit 11: =0 index register is a signed word // =1 index register is a signed long // bit 10..8: UNKNOWN // bit 7..0: displacement, signed byte tVM68k_ubyte regX; tVM68k_sbyte displacement1; tVM68k_slong displacement2l; tVM68k_sword displacement2w; extword=(tVM68k_uword)READEXTENSIONWORD(pVM68k,pNext); regX=(extword>>12)&0x7; displacement1=(extword&0xff); if ((extword>>15)&1) { displacement2l=pVM68k->a[regX]; displacement2w=(pVM68k->a[regX]&0xffff); } else { displacement2l=pVM68k->d[regX]; displacement2w=(pVM68k->d[regX]&0xffff); } *ea=displacement1+(((extword>>11)&1)?displacement2l:displacement2w); *ea=(*ea)+pVM68k->a[reg]; retval=VM68K_OK; } break; default: retval=VM68K_NOK_INVALID_PTR;break; } } return retval; } // the way addresses are stored here is that memory addresses are >=0. <=0 addresses the registers. int vm68k_fetchoperand(tVM68k* pVM68k,tVM68k_bool extendsign,tVM68k_types size,tVM68k_slong ea,tVM68k_ulong* operand) { int retval; tVM68k_ulong op; op=0; if (ea>=0) // memory address { ea%=pVM68k->memsize; // just to be safe... retval=VM68K_OK; switch (size) { case VM68K_BYTE: op= READ_INT8BE(pVM68k->pMem,ea);break; case VM68K_WORD: op=READ_INT16BE(pVM68k->pMem,ea);break; case VM68K_LONG: op=READ_INT32BE(pVM68k->pMem,ea);break; default: retval=VM68K_NOK_INVALID_PTR;break; } } else { // register address if (ea>=DATAREGADDR(7) && ea<=DATAREGADDR(0)) { op=pVM68k->d[-ea+DATAREGADDR(0)]; retval=VM68K_OK; } else if (ea>=ADDRREGADDR(7) && ea<=ADDRREGADDR(0)) { op=pVM68k->a[-ea+ADDRREGADDR(0)]; retval=VM68K_OK; } else retval=VM68K_NOK_UNKNOWN_INSTRUCTION; } switch (size) { case VM68K_BYTE: op&= 0xff;if (extendsign) op=(tVM68k_slong)((tVM68k_sbyte)op);break; case VM68K_WORD: op&=0xffff;if (extendsign) op=(tVM68k_slong)((tVM68k_sword)op);break; default: break; } *operand=op; return retval; } int vm68k_calculateflags(tVM68k_next* pNext,tVM68k_ubyte flagmask,tVM68k_types size,tVM68k_ulong operand1,tVM68k_ulong operand2,tVM68k_uint64 result) { tVM68k_ubyte msb; tVM68k_ulong mask; tVM68k_sint64 maxval,minval; tVM68k_sint64 res; int retval; retval=VM68K_OK; mask=0; msb=0; maxval=0; minval=0; res=0; switch (size) { case VM68K_BYTE: msb= 8;mask= 0xff;maxval= 0x7fll;minval= -0x80ll;res=((tVM68k_sint64)((tVM68k_sbyte)(result& 0xff)));break; case VM68K_WORD: msb=16;mask= 0xffff;maxval= 0x7fffll;minval= -0x8000ll;res=((tVM68k_sint64)((tVM68k_sbyte)(result& 0xffff)));break; case VM68K_LONG: msb=32;mask=0xffffffff;maxval=0x7fffffffll;minval=-0x80000000ll;res=((tVM68k_sint64)((tVM68k_sbyte)(result&0xffffffff)));break; default: retval=VM68K_NOK_INVALID_PTR;break; } if (flagmask&FLAGC) pNext->cflag=((operand2^result)>>msb)&1; if (flagmask&FLAGZ) pNext->zflag=((result&mask)==0); if (flagmask&FLAGN) pNext->nflag=(result>>(msb-1))&1; // if (flagmask&FLAGV) pNext->vflag=((operand1^operand2^result)>>(msb-1))&1; //if (flagmask&FLAGV) pNext->vflag=((~(operand1^operand2)^result)>>(msb-1))&1; if (flagmask&FLAGV) pNext->vflag=((res>maxval)||(resxflag=pNext->cflag; if (flagmask&FLAGCZCLR) {pNext->cflag=0;pNext->vflag=0;} return retval; } int vm68k_calculateflags2(tVM68k_next* pNext,tVM68k_ubyte flagmask,tVM68k_instruction instruction,tVM68k_types datatype,tVM68k_ulong operand1,tVM68k_ulong operand2,tVM68k_uint64 result) { tVM68k_bool msb1,msb2,msbres; int retval=VM68K_OK; msb1=msb2=msbres=0; switch(datatype) { case VM68K_BYTE: msb1=(operand1>> 7)&1;msb2=(operand2>> 7)&1;msbres=(result>> 7)&1;break; case VM68K_WORD: msb1=(operand1>>15)&1;msb2=(operand2>>15)&1;msbres=(result>>15)&1;break; case VM68K_LONG: msb1=(operand1>>31)&1;msb2=(operand2>>31)&1;msbres=(result>>31)&1;break; default: retval=VM68K_NOK_INVALID_PTR;break; } pNext->zflag=(result==0); pNext->nflag=(msbres); switch (instruction) { case VM68K_INST_ADD: case VM68K_INST_ADDA: case VM68K_INST_ADDI: case VM68K_INST_ADDQ: case VM68K_INST_ADDX: // sr[0] <= (`Sm & `Dm) | (~`Rm & `Dm) | (`Sm & ~`Rm); // sr[1] <= (`Sm & `Dm & ~`Rm) | (~`Sm & ~`Dm & `Rm); pNext->cflag=(msb1&msb2)|((!msbres)&msb2)|(msb1&(!msbres)); pNext->xflag=pNext->cflag; pNext->vflag=(msb1&msb2&(!msbres))|((!msb1)&(!msb2)&msbres); break; case VM68K_INST_SUB: case VM68K_INST_SUBA: case VM68K_INST_SUBI: case VM68K_INST_SUBQ: case VM68K_INST_SUBX: // sr[0] <= (`Sm & ~`Dm) | (`Rm & ~`Dm) | (`Sm & `Rm); // sr[1] <= (~`Sm & `Dm & ~`Rm) | (`Sm & ~`Dm & `Rm); pNext->cflag=(msb1&(!msb2))|(msbres&(!msb2))|(msb1&msbres); pNext->xflag=pNext->cflag; pNext->vflag=((!msb1)&msb2&(!msbres))|(msb1&(!msb2)&msbres); break; case VM68K_INST_CMP: case VM68K_INST_CMPA: case VM68K_INST_CMPI: case VM68K_INST_CMPM: // sr[0] <= (`Sm & ~`Dm) | (`Rm & ~`Dm) | (`Sm & `Rm); // sr[1] <= (~`Sm & `Dm & ~`Rm) | (`Sm & ~`Dm & `Rm); pNext->cflag=(msb1&(!msb2))|(msbres&(!msb2))|(msb1&msbres); pNext->vflag=((!msb1)&msb2&(!msbres))|(msb1&(!msb2)&msbres); break; case VM68K_INST_AND: case VM68K_INST_EOR: case VM68K_INST_OR: case VM68K_INST_ANDI: case VM68K_INST_EORI: case VM68K_INST_ORI: default: pNext->cflag=0; pNext->vflag=0; break; } return retval; } int vm68k_storeresult(tVM68k* pVM68k,tVM68k_next* pNext,tVM68k_types size,tVM68k_slong ea,tVM68k_ulong result) { int retval; tVM68k_ulong uppermask; tVM68k_ulong lowermask; retval=VM68K_NOK_UNKNOWN_INSTRUCTION; switch (size) { case VM68K_BYTE:uppermask=0xffffff00;lowermask=~uppermask;break; case VM68K_WORD:uppermask=0xffff0000;lowermask=~uppermask;break; case VM68K_LONG:uppermask=0x00000000;lowermask=~uppermask;break; default: return 0; } if (ea>=0) // memory address { retval=VM68K_OK; ea%=pVM68k->memsize; // just to be safe... pNext->mem_size=size; pNext->mem_addr[pNext->mem_we]=ea; pNext->mem_value[pNext->mem_we]=result&lowermask; pNext->mem_we++; } else { // register address if (ea>=DATAREGADDR(7) && ea<=DATAREGADDR(0)) { int reg; reg=-ea+DATAREGADDR(0); pNext->d[reg]&=uppermask; pNext->d[reg]|=(result&lowermask); retval=VM68K_OK; } else if (ea>=ADDRREGADDR(7) && ea<=ADDRREGADDR(0)) { int reg; reg=-ea+ADDRREGADDR(0); pNext->a[reg]&=uppermask; pNext->a[reg]|=(result&lowermask); retval=VM68K_OK; } else retval=VM68K_NOK_UNKNOWN_INSTRUCTION; } return retval; } dmagnetic-0.22/src/engine/vm68k/vm68k_loadstore.h0000644000175000017500000001142413621220604021177 0ustar dettusdettus/* Copyright 2019, dettus@dettus.net Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef VM68K_LOADSTORE_H #define VM68K_LOADSTORE_H #include "vm68k_datatypes.h" // some helper defines #define DATAREGADDR(addr) (-((addr)+ 1)) #define ADDRREGADDR(addr) (-((addr)+10)) #define VM68K_LEGAL_AM_DATAREG (1<< 1) #define VM68K_LEGAL_AM_ADDRREG (1<< 2) #define VM68K_LEGAL_AM_INDIR (1<< 3) #define VM68K_LEGAL_AM_POSTINC (1<< 4) #define VM68K_LEGAL_AM_PREDEC (1<< 5) #define VM68K_LEGAL_AM_DISP16 (1<< 6) #define VM68K_LEGAL_AM_INDEX (1<< 7) #define VM68K_LEGAL_AMX_W (1<< 8) #define VM68K_LEGAL_AMX_L (1<< 9) #define VM68K_LEGAL_AMX_DATA (1<<10) #define VM68K_LEGAL_AMX_PC (1<<11) #define VM68K_LEGAL_AMX_INDEX_PC (1<<12) #define VM68K_LEGAL_CONTROLALTERATEADDRESSING (VM68K_LEGAL_AM_INDIR|VM68K_LEGAL_AM_DISP16|VM68K_LEGAL_AM_INDEX|VM68K_LEGAL_AMX_W|VM68K_LEGAL_AMX_L|VM68K_LEGAL_AMX_PC|VM68K_LEGAL_AMX_INDEX_PC) #define VM68K_LEGAL_CONTROLADDRESSING (VM68K_LEGAL_AM_INDIR|VM68K_LEGAL_AM_DISP16|VM68K_LEGAL_AM_INDEX|VM68K_LEGAL_AMX_W|VM68K_LEGAL_AMX_L|VM68K_LEGAL_AMX_PC|VM68K_LEGAL_AMX_INDEX_PC) #define VM68K_LEGAL_DATAADDRESSING ( VM68K_LEGAL_AM_DATAREG| VM68K_LEGAL_AM_INDIR| VM68K_LEGAL_AM_POSTINC| VM68K_LEGAL_AM_PREDEC| VM68K_LEGAL_AM_DISP16| VM68K_LEGAL_AM_INDEX| VM68K_LEGAL_AMX_W| VM68K_LEGAL_AMX_L| VM68K_LEGAL_AMX_DATA| VM68K_LEGAL_AMX_PC| VM68K_LEGAL_AMX_INDEX_PC ) #define VM68K_LEGAL_ALL ( VM68K_LEGAL_AM_DATAREG| VM68K_LEGAL_AM_ADDRREG| VM68K_LEGAL_AM_INDIR| VM68K_LEGAL_AM_POSTINC| VM68K_LEGAL_AM_PREDEC| VM68K_LEGAL_AM_DISP16| VM68K_LEGAL_AM_INDEX| VM68K_LEGAL_AMX_W| VM68K_LEGAL_AMX_L| VM68K_LEGAL_AMX_DATA| VM68K_LEGAL_AMX_PC| VM68K_LEGAL_AMX_INDEX_PC ) #define VM68K_LEGAL_DATAALTERATE ( VM68K_LEGAL_AM_DATAREG|VM68K_LEGAL_AM_INDIR|VM68K_LEGAL_AM_POSTINC| VM68K_LEGAL_AM_PREDEC| VM68K_LEGAL_AM_DISP16| VM68K_LEGAL_AM_INDEX| VM68K_LEGAL_AMX_W| VM68K_LEGAL_AMX_L) #define VM68K_LEGAL_MEMORYALTERATE ( VM68K_LEGAL_AM_INDIR|VM68K_LEGAL_AM_POSTINC| VM68K_LEGAL_AM_PREDEC| VM68K_LEGAL_AM_DISP16| VM68K_LEGAL_AM_INDEX| VM68K_LEGAL_AMX_W| VM68K_LEGAL_AMX_L) #define VM68K_LEGAL_ALTERABLEADRESSING (VM68K_LEGAL_AM_DATAREG|VM68K_LEGAL_AM_ADDRREG|VM68K_LEGAL_AM_INDIR|VM68K_LEGAL_AM_POSTINC|VM68K_LEGAL_AM_PREDEC|VM68K_LEGAL_AM_DISP16|VM68K_LEGAL_AM_INDEX| VM68K_LEGAL_AMX_W|VM68K_LEGAL_AMX_L) #define FLAGC (1<<0) #define FLAGV (1<<1) #define FLAGZ (1<<2) #define FLAGN (1<<3) #define FLAGX (1<<4) #define FLAGCZCLR (1<<5) // when set, the c and z flag are always cleared. #define FLAGS_ALL (FLAGC|FLAGV|FLAGZ|FLAGN|FLAGX) #define FLAGS_LOGIC (FLAGZ|FLAGN|FLAGCZCLR) // this function is calculating the number of bytes for a datatype int vm68k_getbytesize(tVM68k_types size); // this function is translating the addressmode/registerpair into a memory address int vm68k_resolve_ea(tVM68k* pVM68k,tVM68k_next *pNext,tVM68k_types size, tVM68k_addrmodes addrmode,tVM68k_ubyte reg, tVM68k_uword legal,tVM68k_slong* ea); // this function is loading the operand int vm68k_fetchoperand(tVM68k* pVM68k,tVM68k_bool extendsign,tVM68k_types size,tVM68k_slong ea,tVM68k_ulong* operand); // this function is calculting the status flags int vm68k_calculateflags(tVM68k_next* pNext,tVM68k_ubyte flagmask,tVM68k_types size,tVM68k_ulong operand1,tVM68k_ulong operand2,tVM68k_uint64 result); int vm68k_calculateflags2(tVM68k_next* pNext,tVM68k_ubyte flagmask,tVM68k_instruction instruction,tVM68k_types datatype,tVM68k_ulong operand1,tVM68k_ulong operand2,tVM68k_uint64 result); // this function is storing the result of the operation. int vm68k_storeresult(tVM68k* pVM68k,tVM68k_next* pNext,tVM68k_types size,tVM68k_slong ea,tVM68k_ulong result); #endif dmagnetic-0.22/src/engine/vm68k/vm68k_datatypes.h0000644000175000017500000000770713621220604021212 0ustar dettusdettus/* Copyright 2019, dettus@dettus.net Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef VM68K_DATATYPES_H #define VM68K_DATATYPES_H // the purpose of this file is to provide the shared datatypes needed for the virtual machine #ifdef __sgi__ typedef unsigned char tVM68k_bool; typedef unsigned char tVM68k_ubyte; typedef unsigned short tVM68k_uword; typedef unsigned int tVM68k_ulong; typedef unsigned long long tVM68k_uint64; typedef signed char tVM68k_sbyte; typedef signed short tVM68k_sword; typedef signed int tVM68k_slong; typedef signed long long tVM68k_sint64; #else #include // first of all: the standard data types. typedef uint_least8_t tVM68k_bool; typedef uint_least8_t tVM68k_ubyte; typedef uint_least16_t tVM68k_uword; typedef uint_least32_t tVM68k_ulong; typedef uint_least64_t tVM68k_uint64; typedef int_least8_t tVM68k_sbyte; typedef int_least16_t tVM68k_sword; typedef int_least32_t tVM68k_slong; typedef int_least64_t tVM68k_sint64; #endif // then a couple of enumerations. to make the sourcecode a little bit easier to read. typedef enum _tVM68k_types {VM68K_BYTE=0,VM68K_WORD=1,VM68K_LONG=2,VM68K_UNKNOWN=3} tVM68k_types; typedef enum _tVM68k_addrmodes { VM68K_AM_DATAREG=0, // Dn VM68K_AM_ADDRREG=1, // An VM68K_AM_INDIR=2, // (An) VM68K_AM_POSTINC=3, // (An)+ VM68K_AM_PREDEC=4, // -(An) VM68K_AM_DISP16=5, // (d16,An) VM68K_AM_INDEX=6, // (d8,An,Xn) VM68K_AM_EXT=7} tVM68k_addrmodes; typedef enum _tVM68k_addrmode_ext { VM68K_AMX_W=0, // (xxx),W VM68K_AMX_L=1, // (xxx),L VM68K_AMX_data=4, // # VM68K_AMX_PC=2, // (d16,PC) VM68K_AMX_INDEX_PC=3} // (d8,PC,Xn) tVM68k_addrmode_ext; // the internal structures typedef struct _tVM68k { tVM68k_ulong magic; // just so that the functions can identify a handle as this particular data structure tVM68k_ulong pcr; // program counter tVM68k_uword sr; // status register. // bit 0..4: CVZNX tVM68k_ulong a[8]; // address register tVM68k_ulong d[8]; // data register tVM68k_ubyte *pMem; // pointer to the memory tVM68k_ulong memsize; // TODO: check for violations. /////// VERSION PATCH tVM68k_ubyte version; } tVM68k; ////// this structure holds the state after the instruction has been decoded. ////// the reason i put it in here is to trace the changes. typedef struct _tVM68k_next { tVM68k_ulong pcr; // program counter tVM68k_bool override_sr; tVM68k_uword sr; tVM68k_bool cflag; tVM68k_bool vflag; tVM68k_bool zflag; tVM68k_bool nflag; tVM68k_bool xflag; // bit 0..4: CVZNX tVM68k_ulong a[8]; // address register tVM68k_ulong d[8]; // data register ////// memory queue tVM68k_types mem_size; tVM68k_ulong mem_addr[16]; tVM68k_ulong mem_value[16]; tVM68k_ubyte mem_we; } tVM68k_next; #endif dmagnetic-0.22/src/engine/vm68k/vm68k_decode.h0000644000175000017500000001247213621220604020432 0ustar dettusdettus/* Copyright 2019, dettus@dettus.net Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef VM68K_DECODE_H #define VM68K_DECODE_H #include "vm68k_datatypes.h" // this data structure makes the decoding process easier to read. typedef enum _tVM68k_instruction { VM68K_INST_UNKNOWN=0, VM68K_INST_ABCD, //1100xxx10000myyy VM68K_INST_ADD, //1101 rrro oomm myyy VM68K_INST_ADDA, //1101 rrro oomm myyy VM68K_INST_ADDI, //0000 0110 ssmm myyy VM68K_INST_ADDQ, //0101 ddd0 ssmm myyy VM68K_INST_ADDX, //1101 xxx1 ss00 myyy VM68K_INST_AND, //1100 xxxo oomm myyy VM68K_INST_ANDI, //0000 0010 ssmm myyy VM68K_INST_ANDItoCCR, //0000 0010 0011 1100 00000000dddddddd VM68K_INST_ANDItoSR, //0000 0010 0111 1100 dddddddddddddddd VM68K_INST_ASL_ASR, //1110 cccd ssl0 0yyy VM68K_INST_BCC, //0110 CCCC dddd dddd VM68K_INST_BCHG, //0000 xxx1 01mm myyy VM68K_INST_BCHGB, //0000 1000 10mm myyy VM68K_INST_BCLR, //0000 xxx1 10mm myyy VM68K_INST_BCLRI, //0000xxx110mmmyyy VM68K_INST_BRA, //0110 0000 dddd dddd VM68K_INST_BSET, //0000 xxx1 11mm myyy VM68K_INST_BSETB, //0000 1000 11mm myyy // VM68K_INST_BSR, //01100001dddddddd VM68K_INST_BTST, //0000 xxx1 00mm myyy VM68K_INST_BTSTB, //0000 1000 00mm myyy VM68K_INST_CHK, //0100xxxss0mmmyyy VM68K_INST_CLR, //0100 0010 ssmm myyy VM68K_INST_CMP, //1011 xxxo oomm myyy VM68K_INST_CMPA, //1011 xxxo oomm myyy VM68K_INST_CMPI, //0000 1100 ssmm myyy VM68K_INST_CMPM, //1011 xxx1 ss00 1yyy VM68K_INST_DBcc, //0101 CCCC 1100 1yyy VM68K_INST_DIVS, //1000xxx111mmmyyy VM68K_INST_DIVU, //1000xxx011mmmyyy VM68K_INST_EOR, //1011 xxxo oomm myyy VM68K_INST_EORI, //0000 1010 ssmm myyy VM68K_INST_EORItoCCR, //0000 1010 0011 1100 00000000dddddddd VM68K_INST_EORItoSR, //0000 1010 0111 1100 dddddddddddddddd VM68K_INST_EXG, //1100 xxx1 oooo oyyy VM68K_INST_EXT, //0100 100o oo00 0yyy VM68K_INST_ILLEGAL, //0100101011111100 VM68K_INST_JMP, //0100 1110 11mm myyy VM68K_INST_JSR, //0100 1110 10mm myyy VM68K_INST_LEA, //0100 xxx1 11mm myyy VM68K_INST_LINK, //0100111001010yyydddddddddddddddd VM68K_INST_LSL_LSR, //1110 cccd ssl0 1yyy VM68K_INST_MOVE, //00ss xxxm mmMM Myyy VM68K_INST_MOVEA, //00ss xxx0 01mm myyy VM68K_INST_MOVEtoCCR, //0100010011mmmyyy VM68K_INST_MOVEfromSR, //0100000011mmmyyy VM68K_INST_MOVEtoSR, //0100011011mmmyyy VM68K_INST_MOVEUSP, //010011100110dyyy VM68K_INST_MOVEMregtomem, //0100 1d00 1smm myyy VM68K_INST_MOVEMmemtoreg, //0100 1d00 1smm myyy VM68K_INST_MOVEP, //0000xxxooo001yyydddddddddddddddd VM68K_INST_MOVEQ, //0111xxx0dddddddd VM68K_INST_MULS, //1100xxx111mmmyyy VM68K_INST_MULU, //1100xxx011mmmyyy!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! VM68K_INST_NBCD, //1100xxx011mmmyyy!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! VM68K_INST_NEG, //0100 0100 ssmm myyy VM68K_INST_NEGX, //0100 0000 ssmm myyy VM68K_INST_NOP, //0100 1110 0111 0001 VM68K_INST_NOT, //0100 0110 ssmm myyy VM68K_INST_OR, //1000 xxxo oomm myyy VM68K_INST_ORI, //0000 0000 ssmm myyy VM68K_INST_ORItoCCR, //0000 0000 0011 1100 00000000dddddddd VM68K_INST_ORItoSR, //0000 0000 0111 1100 dddddddddddddddd VM68K_INST_PEA, //0100 1000 01mm myyy VM68K_INST_RESET, //0100111001110000 VM68K_INST_ROL_ROR, //1110 cccd ssl1 1yyy VM68K_INST_ROXL_ROXR, //1110 cccd ssl1 0yyy VM68K_INST_RTE, //0100 1110 0111 0011 VM68K_INST_RTR, //0100 1110 0111 0111 VM68K_INST_RTS, //0100 1110 0111 0101 VM68K_INST_SBCD, //1000xxx10000ryyy VM68K_INST_SCC, //0101 CCCC 11mm myyy VM68K_INST_STOP, //0100111001110010iiiiiiiiiiiiiiii VM68K_INST_SUB, //1001 xxxo oomm myyy VM68K_INST_SUBA, //1001 xxxo oomm myyy VM68K_INST_SUBI, //0000 0100 ssmm myyy VM68K_INST_SUBQ, //0101 ddd1 ssmm myyy VM68K_INST_SUBX, //1001 yyy1 ss00 ryyy VM68K_INST_SWAP, //0100100001000yyy VM68K_INST_TAS, //0100101011mmmyyy VM68K_INST_TRAP, //010011100100vvvv VM68K_INST_TRAPV, //0100111001110110 VM68K_INST_TST, //0100 1010 ssmm myyy VM68K_INST_UNLK, //0100111001011yyy } tVM68k_instruction; // opcodes are 16 bit values, this function translates them into an easier-to-handle enumeration. tVM68k_instruction vm68k_decode(tVM68k_uword opcode); // this function is for translating the enumeration into something human-readable. void vm68k_get_instructionname(tVM68k_instruction instruction,char* name); #endif dmagnetic-0.22/src/engine/vm68k/vm68k.c0000644000175000017500000007562013621220604017126 0ustar dettusdettus/* Copyright 2019, dettus@dettus.net Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ //#define DEBUG_PRINT #include #include #include #include "vm68k_datatypes.h" #include "vm68k_decode.h" #include "vm68k_loadstore.h" #include "vm68k_macros.h" #include "vm68k.h" #define MAGICVALUE 0x564A3638 // "VM68" tVM68k_bool vm68k_checkcondition(tVM68k* pVM68k,tVM68k_ubyte condition) { #define CFLAG(pVM68k) ((((pVM68k)->sr)>>0)&1) #define VFLAG(pVM68k) ((((pVM68k)->sr)>>1)&1) #define ZFLAG(pVM68k) ((((pVM68k)->sr)>>2)&1) #define NFLAG(pVM68k) ((((pVM68k)->sr)>>3)&1) #define XFLAG(pVM68k) ((((pVM68k)->sr)>>4)&1) tVM68k_bool condtrue; switch(condition) { case 0: condtrue=1;break; case 1: condtrue=0;break; case 2: //BHI high 0010 /C | /Z condtrue=!(CFLAG(pVM68k)|ZFLAG(pVM68k)); break; case 3: //LS low or same 0011 C & Z condtrue= (CFLAG(pVM68k)|ZFLAG(pVM68k)); break; case 4://BCC carry clear 0100 /C condtrue=!(CFLAG(pVM68k)); break; case 5://BCS carry set 0101 C condtrue= (CFLAG(pVM68k)); break; case 6://BNE not equal 0110 /Z condtrue=!(ZFLAG(pVM68k)); break; case 7://BEQ equal 0111 Z condtrue= (ZFLAG(pVM68k)); break; case 8://BVC overflow clear 1000 /V condtrue=!(VFLAG(pVM68k)); break; case 9://BVS overflow set 1001 V condtrue= (VFLAG(pVM68k)); break; case 10://BPL plus 1010 /N condtrue=!(NFLAG(pVM68k)); break; case 11://BMI minus 1011 N condtrue= (NFLAG(pVM68k)); break; case 12://BGE greater or equal 1100 (N & V) | (/N & /V), N and V are both set or both clear condtrue=!((NFLAG(pVM68k)^VFLAG(pVM68k))); break; case 13://BLT less than 1101 (N & /V) | (/N & V), N and V are either set or clear condtrue= ((NFLAG(pVM68k)^VFLAG(pVM68k))); break; case 14://BGT greater than 1110 (N & V & /Z) | (/N & /V & /Z) condtrue=!ZFLAG(pVM68k)&!((NFLAG(pVM68k)^VFLAG(pVM68k))); break; case 15://BLE less or equal 1111 condtrue=ZFLAG(pVM68k)|((NFLAG(pVM68k)^VFLAG(pVM68k))); break; default: condtrue=0; break; } return condtrue; } int vm68k_getsize(int* size) { if (size==NULL) return VM68K_NOK_INVALID_PTR; *size=sizeof(tVM68k); return VM68K_OK; } int vm68k_init(void* hVM68k,void* pSharedMem,int sharedmemsize,int version) { tVM68k* pVM68k=(tVM68k*)hVM68k; if (hVM68k==NULL) return VM68K_NOK_INVALID_PTR; if (pSharedMem==NULL) return VM68K_NOK_INVALID_PARAMETER; memset(hVM68k,0,sizeof(tVM68k)); pVM68k->magic=MAGICVALUE; pVM68k->pcr=0; pVM68k->a[7]=0xfffe; // stack pointer. set to the end of the memory. pVM68k->pMem=pSharedMem; pVM68k->memsize=sharedmemsize; pVM68k->version=version; return VM68K_OK; } int vm68k_singlestep(void *hVM68k,unsigned short opcode) { tVM68k* pVM68k=(tVM68k*)hVM68k; tVM68k_instruction instruction; tVM68k_ubyte addrmode; tVM68k_ubyte reg1,reg2; tVM68k_types datatype; tVM68k_next next; tVM68k_slong ea; tVM68k_ulong operand1,operand2; tVM68k_uint64 result; tVM68k_ubyte condition; tVM68k_sword displacement; tVM68k_bool direction; int retval; if (hVM68k==NULL) return VM68K_NOK_INVALID_PTR; if (pVM68k->magic!=MAGICVALUE) return VM68K_NOK_INVALID_PARAMETER; retval=VM68K_NOK_UNKNOWN_INSTRUCTION; instruction=vm68k_decode(opcode); // decode the opcode reg1=(opcode>>9)&0x7; addrmode=(opcode>>3)&0x7; reg2=(opcode>>0)&0x7; datatype=(tVM68k_types)(opcode>>6)&0x3; // branches condition=(opcode>>8)&0xf; displacement=(tVM68k_sword)((tVM68k_sbyte)(opcode&0xff)); // alu operations direction=(opcode>>8)&0x1; INITNEXT(pVM68k,next); switch(instruction) { case VM68K_INST_ADD: case VM68K_INST_CMP: case VM68K_INST_SUB: if (instruction==VM68K_INST_CMP) { retval=vm68k_resolve_ea(pVM68k,&next,datatype,addrmode,reg2,VM68K_LEGAL_ALL,&ea); } else { retval=vm68k_resolve_ea(pVM68k,&next,datatype,addrmode,reg2,direction?VM68K_LEGAL_MEMORYALTERATE:VM68K_LEGAL_ALL,&ea); } if (retval==VM68K_OK) retval=vm68k_fetchoperand(pVM68k,1,datatype,ea,&operand1); if (retval==VM68K_OK) retval=vm68k_fetchoperand(pVM68k,1,datatype,DATAREGADDR(reg1),&operand2); if (instruction==VM68K_INST_SUB || instruction==VM68K_INST_CMP) { if (direction) { result=operand1-operand2; } else { result=operand2-operand1; } } else { result=operand2+operand1; } if (retval==VM68K_OK) retval=vm68k_calculateflags2(&next,FLAGS_ALL,instruction,datatype,operand1,operand2,result); if (retval==VM68K_OK && instruction!=VM68K_INST_CMP) retval=vm68k_storeresult(pVM68k,&next,datatype,(direction)?ea:DATAREGADDR(reg1),result); break; case VM68K_INST_ADDA: case VM68K_INST_CMPA: case VM68K_INST_SUBA: if (datatype==VM68K_UNKNOWN) { tVM68k_types datatype2; tVM68k_types datatype3; datatype2=((opcode>>8)&1)?VM68K_LONG:VM68K_WORD; if (pVM68k->version==4) { datatype3=VM68K_LONG; } else { datatype3=datatype2; } retval=vm68k_resolve_ea(pVM68k,&next,datatype2,addrmode,reg2,VM68K_LEGAL_ALL,&ea); if (retval==VM68K_OK) retval=vm68k_fetchoperand(pVM68k,1,datatype2,ea,&operand2); if (retval==VM68K_OK) retval=vm68k_fetchoperand(pVM68k,1,datatype3,ADDRREGADDR(reg1),&operand1); if (instruction==VM68K_INST_SUBA || instruction==VM68K_INST_CMPA) { result=operand1-operand2; } else { result=operand2+operand1; } if (retval==VM68K_OK && instruction==VM68K_INST_CMPA) retval=vm68k_calculateflags2(&next,FLAGS_ALL,instruction,datatype2,operand1,operand2,result); if (retval==VM68K_OK && instruction!=VM68K_INST_CMPA) retval=vm68k_storeresult(pVM68k,&next,datatype3,ADDRREGADDR(reg1),result); } break; case VM68K_INST_ADDI: case VM68K_INST_CMPI: case VM68K_INST_SUBI: READEXTENSION(pVM68k,&next,datatype,operand1); retval=VM68K_OK; switch(datatype) { case VM68K_BYTE: operand1=(tVM68k_slong)((tVM68k_sbyte)(operand1& 0xff));break; case VM68K_WORD: operand1=(tVM68k_slong)((tVM68k_sword)(operand1& 0xffff));break; case VM68K_LONG: operand1=(tVM68k_slong)((tVM68k_slong)(operand1&0xffffffff));break; default: retval=VM68K_NOK_UNKNOWN_INSTRUCTION;break; } if (retval==VM68K_OK) retval=vm68k_resolve_ea(pVM68k,&next,datatype,addrmode,reg2,VM68K_LEGAL_DATAALTERATE,&ea); if (retval==VM68K_OK) retval=vm68k_fetchoperand(pVM68k,1,datatype,ea,&operand2); if (instruction==VM68K_INST_SUBI || instruction==VM68K_INST_CMPI) { result=operand2-operand1; // Checked 0c01 } else { result=operand2+operand1; } if (retval==VM68K_OK) retval=vm68k_calculateflags2(&next,FLAGS_ALL,instruction,datatype,operand1,operand2,result); if (retval==VM68K_OK && instruction!=VM68K_INST_CMPI) retval=vm68k_storeresult(pVM68k,&next,datatype,ea,result); break; case VM68K_INST_ADDQ: case VM68K_INST_SUBQ: { tVM68k_sbyte quick; tVM68k_bool version3_workaround; retval=vm68k_resolve_ea(pVM68k,&next,datatype,addrmode,reg2,VM68K_LEGAL_ALTERABLEADRESSING,&ea); if (retval==VM68K_OK) retval=vm68k_fetchoperand(pVM68k,1,datatype,ea,&operand2); quick=reg1; operand1=quick; if (operand1==0) operand1=8; if (instruction==VM68K_INST_SUBQ) { result=operand2-operand1; } else { result=operand2+operand1; } version3_workaround=next.zflag; // starting with version 3, the z-flag needed to be preserved. this was an inconsistency in the original engine, that just stuck. if (retval==VM68K_OK) retval=vm68k_calculateflags2(&next,FLAGS_ALL,instruction,datatype,operand1,operand2,result); if ((pVM68k->version>=3) && (instruction==VM68K_INST_ADDQ)) next.zflag=version3_workaround; if (retval==VM68K_OK && instruction!=VM68K_INST_CMPI) retval=vm68k_storeresult(pVM68k,&next,datatype,ea,result); } break; case VM68K_INST_EXG: { tVM68k_sbyte opmode; opmode=(opcode>>3)&0x1f; switch(opmode) { case 8: next.d[reg1]=pVM68k->d[reg2]; next.d[reg2]=pVM68k->d[reg1];break; // 01000= data registers. case 9: next.a[reg1]=pVM68k->a[reg2]; next.a[reg2]=pVM68k->a[reg1];break; // 01001= addr registers. case 17:next.d[reg1]=pVM68k->a[reg2]; next.a[reg2]=pVM68k->d[reg1];break; // 10001= data +addr registers. } retval=VM68K_OK; } break; case VM68K_INST_MOVEQ: { tVM68k_types datatype2; tVM68k_sbyte data; datatype2=VM68K_LONG; data=opcode&0xff; result=(tVM68k_slong)data; retval=vm68k_calculateflags(&next,FLAGS_LOGIC,datatype2,0,0,result); next.cflag=next.vflag=0; if (retval==VM68K_OK) retval=vm68k_storeresult(pVM68k,&next,datatype2,DATAREGADDR(reg1),result); } break; case VM68K_INST_AND: case VM68K_INST_EOR: case VM68K_INST_OR: // direction=1: -Dn -> // direction=0: Dn- -> Dn if (instruction==VM68K_INST_EOR) // TODO: is this really neessary? { retval=vm68k_resolve_ea(pVM68k,&next,datatype,addrmode,reg2,VM68K_LEGAL_ALL,&ea); } else { retval=vm68k_resolve_ea(pVM68k,&next,datatype,addrmode,reg2,direction?VM68K_LEGAL_MEMORYALTERATE:VM68K_LEGAL_ALL,&ea); } if (retval==VM68K_OK) retval=vm68k_fetchoperand(pVM68k,0,datatype,ea,&operand2); if (retval==VM68K_OK) retval=vm68k_fetchoperand(pVM68k,0,datatype,DATAREGADDR(reg1),&operand1); switch (instruction) { case VM68K_INST_AND: result=operand1&operand2;break; case VM68K_INST_EOR: result=operand1^operand2;break; case VM68K_INST_OR: result=operand1|operand2;break; default: retval=VM68K_NOK_UNKNOWN_INSTRUCTION;break; } if (retval==VM68K_OK) retval=vm68k_calculateflags(&next,FLAGS_LOGIC,datatype,operand1,operand2,result); if (retval==VM68K_OK) retval=vm68k_storeresult(pVM68k,&next,datatype,(direction)?ea:DATAREGADDR(reg1),result); break; case VM68K_INST_ANDI: case VM68K_INST_EORI: case VM68K_INST_ORI: READEXTENSION(pVM68k,&next,datatype,operand1); retval=vm68k_resolve_ea(pVM68k,&next,datatype,addrmode,reg2,VM68K_LEGAL_DATAALTERATE,&ea); if (retval==VM68K_OK) retval=vm68k_fetchoperand(pVM68k,0,datatype,ea,&operand2); switch (instruction) { case VM68K_INST_ANDI:result=operand1&operand2;break; case VM68K_INST_EORI:result=operand1^operand2;break; case VM68K_INST_ORI: result=operand1|operand2;break; default: retval=VM68K_NOK_UNKNOWN_INSTRUCTION;break; } if (retval==VM68K_OK) retval=vm68k_calculateflags(&next,FLAGS_LOGIC,datatype,operand1,operand2,result); if (retval==VM68K_OK) retval=vm68k_storeresult(pVM68k,&next,datatype,ea,result); break; case VM68K_INST_BCC: if (displacement==0) { displacement=READEXTENSIONWORD(pVM68k,&next); } if (condition==1) // BSR { PUSHLONGTOSTACK(pVM68k,&next,(next.pcr)); } if (vm68k_checkcondition(pVM68k,condition) || condition==1) { next.pcr=pVM68k->pcr+displacement; } retval=VM68K_OK; break; case VM68K_INST_MOVE: case VM68K_INST_MOVEA: { tVM68k_types datatype2; tVM68k_ubyte addrmode_dest; tVM68k_slong ea_dest; retval=VM68K_OK; switch ((opcode>>12)&0x3) { case 1: datatype2=VM68K_BYTE;break; case 3: datatype2=VM68K_WORD;break; case 2: datatype2=VM68K_LONG;break; default: retval=VM68K_NOK_UNKNOWN_INSTRUCTION; } addrmode_dest=(opcode>>6)&0x7; if (retval==VM68K_OK) retval=vm68k_resolve_ea(pVM68k,&next,datatype2,addrmode,reg2,VM68K_LEGAL_ALL,&ea); if (retval==VM68K_OK) retval=vm68k_fetchoperand(pVM68k,0,datatype2,ea,&operand2); // TODO: I had a problem here, when the addrmode was 7/4 and the size was BYTE. lets see what happens. if (retval==VM68K_OK) retval=vm68k_resolve_ea(pVM68k,&next,datatype2,addrmode_dest,reg1,(instruction==VM68K_INST_MOVE)?VM68K_LEGAL_DATAALTERATE:VM68K_LEGAL_ALL,&ea_dest); if (retval==VM68K_OK) result=operand2; if (retval==VM68K_OK && instruction!=VM68K_INST_MOVEA) retval=vm68k_calculateflags(&next,FLAGS_LOGIC,datatype2,0,operand2,result); if (retval==VM68K_OK) retval=vm68k_storeresult(pVM68k,&next,datatype2,ea_dest,result); } break; case VM68K_INST_NEG: case VM68K_INST_NEGX: case VM68K_INST_NOT: { retval=vm68k_resolve_ea(pVM68k,&next,datatype,addrmode,reg2,VM68K_LEGAL_DATAALTERATE,&ea); if (retval==VM68K_OK) retval=vm68k_fetchoperand(pVM68k,1,datatype,ea,&operand2); result=(instruction==VM68K_INST_NOT)?(~operand2):(0-operand2); result=result-((instruction==VM68K_INST_NEGX)&next.xflag); operand1=0; if (retval==VM68K_OK) retval=vm68k_calculateflags(&next,FLAGS_LOGIC,datatype,operand1,operand2,result); if (retval==VM68K_OK) retval=vm68k_storeresult(pVM68k,&next,datatype,ea,result); } break; case VM68K_INST_JMP: case VM68K_INST_JSR: { tVM68k_types datatype2; datatype2=VM68K_LONG; retval=vm68k_resolve_ea(pVM68k,&next,datatype2,addrmode,reg2,VM68K_LEGAL_CONTROLADDRESSING,&ea); operand2=ea; if (instruction==VM68K_INST_JSR && retval==VM68K_OK) { PUSHLONGTOSTACK(pVM68k,&next,(next.pcr)); } // TODO: why this way? switch (addrmode) { case VM68K_AM_INDIR: next.pcr=operand2%pVM68k->memsize; break; default: next.pcr=operand2; // wonderland break; } } break; case VM68K_INST_RTS: retval=VM68K_OK; POPLONGFROMSTACK(pVM68k,&next,next.pcr); //next.pcr%=pVM68k->memsize; // wonderland break; case VM68K_INST_ANDItoSR: case VM68K_INST_EORItoSR: case VM68K_INST_ORItoSR: case VM68K_INST_ANDItoCCR: case VM68K_INST_EORItoCCR: case VM68K_INST_ORItoCCR: retval=VM68K_OK; operand2=READEXTENSIONWORD(pVM68k,&next); operand1=0xffff; switch (instruction) { case VM68K_INST_ANDItoCCR: operand1&=0x1f; case VM68K_INST_ANDItoSR: operand2&=next.sr;break; case VM68K_INST_EORItoCCR: operand1&=0x1f; case VM68K_INST_EORItoSR: operand2^=next.sr;break; case VM68K_INST_ORItoCCR: operand1&=0x1f; case VM68K_INST_ORItoSR: operand2|=next.sr;break; default: retval=VM68K_NOK_UNKNOWN_INSTRUCTION;break; } result=operand1&operand2; next.override_sr=1; next.sr&=~operand1; next.sr|=operand2; break; case VM68K_INST_MOVEfromSR: { tVM68k_types datatype2; datatype2=VM68K_WORD; retval=vm68k_resolve_ea(pVM68k,&next,datatype2,addrmode,reg2,VM68K_LEGAL_DATAALTERATE,&ea); result=next.sr&0xffff; if (retval==VM68K_OK) retval=vm68k_storeresult(pVM68k,&next,datatype2,ea,result); } break; case VM68K_INST_MOVEtoCCR: case VM68K_INST_MOVEtoSR: { tVM68k_types datatype2; datatype2=VM68K_WORD; retval=vm68k_resolve_ea(pVM68k,&next,datatype2,addrmode,reg2,VM68K_LEGAL_DATAADDRESSING,&ea); if (retval==VM68K_OK) retval=vm68k_fetchoperand(pVM68k,0,datatype2,ea,&operand2); if (retval==VM68K_OK) { next.override_sr=1; next.sr=(instruction==VM68K_INST_MOVEtoCCR)?((next.sr&0xffe0)|(operand2&0x1f)):operand2; } } break; case VM68K_INST_MOVEMregtomem: { tVM68k_types datatype2; tVM68k_uword bitmask; int i; datatype2=((opcode>>6)&1)?VM68K_LONG:VM68K_WORD; retval=vm68k_resolve_ea(pVM68k,&next,datatype2,addrmode,reg2,VM68K_LEGAL_CONTROLALTERATEADDRESSING|VM68K_LEGAL_AM_PREDEC,&ea); // special case: the memory decrement should only be performed when the bitmask says so { for (i=0;i<8;i++) next.a[i]=pVM68k->a[i]; } if (retval==VM68K_OK) retval=vm68k_fetchoperand(pVM68k,0,datatype2,ea,&operand2); if (retval==VM68K_OK) bitmask=READEXTENSIONWORD(pVM68k,&next); if (retval==VM68K_OK) { for (i=0;i<8;i++) { if (bitmask&1) { // FIXME: technically not the stack. if (datatype2==VM68K_WORD) PUSHWORDTOSTACK(pVM68k,&next,pVM68k->a[7-i]); if (datatype2==VM68K_LONG) PUSHLONGTOSTACK(pVM68k,&next,pVM68k->a[7-i]); } bitmask>>=1; } for (i=0;i<8;i++) { if (bitmask&1) { // FIXME: technically not the stack. if (datatype2==VM68K_WORD) PUSHWORDTOSTACK(pVM68k,&next,pVM68k->d[7-i]); if (datatype2==VM68K_LONG) PUSHLONGTOSTACK(pVM68k,&next,pVM68k->d[7-i]); } bitmask>>=1; } } } break; case VM68K_INST_MOVEMmemtoreg: { tVM68k_types datatype2; tVM68k_uword bitmask; int i; datatype2=((opcode>>6)&1)?VM68K_LONG:VM68K_WORD; retval=vm68k_resolve_ea(pVM68k,&next,datatype2,addrmode,reg2,VM68K_LEGAL_CONTROLADDRESSING|VM68K_LEGAL_AM_POSTINC,&ea); // special case: the memory increment should only be performed when the bitmask says so { for (i=0;i<8;i++) next.a[i]=pVM68k->a[i]; } if (retval==VM68K_OK) bitmask=READEXTENSIONWORD(pVM68k,&next); if (retval==VM68K_OK) { for (i=0;i<8;i++) { if (bitmask&1) { // FIXME: not really the stack. if (datatype2==VM68K_WORD) { POPWORDFROMSTACK(pVM68k,&next,next.d[i]); } if (datatype2==VM68K_LONG) { POPLONGFROMSTACK(pVM68k,&next,next.d[i]); } } bitmask>>=1; } for (i=0;i<8;i++) { if (bitmask&1) { // FIXME: not really the stack. if (datatype2==VM68K_WORD) { POPWORDFROMSTACK(pVM68k,&next,next.a[i]); next.a[i]&=0xffff; } if (datatype2==VM68K_LONG) { POPLONGFROMSTACK(pVM68k,&next,next.a[i]); } } bitmask>>=1; } } } break; case VM68K_INST_EXT: { tVM68k_types datatype2=VM68K_UNKNOWN; switch ((opcode>>6)&0x3) { case 2: datatype2=VM68K_WORD;break; case 3: datatype2=VM68K_LONG;break; } switch (datatype2) { case VM68K_WORD: result=(tVM68k_sword)((tVM68k_sbyte)(pVM68k->d[reg2]& 0xff));retval=VM68K_OK; result=((pVM68k->d[reg2])&0xffff0000)|(((tVM68k_ulong)result)&0xffff); break; case VM68K_LONG: result=(tVM68k_slong)((tVM68k_sword)(pVM68k->d[reg2]&0xffff));retval=VM68K_OK;break; default: retval=VM68K_NOK_UNKNOWN_INSTRUCTION;break; } if (retval==VM68K_OK) retval=vm68k_calculateflags(&next,FLAGS_LOGIC,datatype2,0,0,result); if (retval==VM68K_OK) next.d[reg2]=result; } break; case VM68K_INST_PEA: retval=vm68k_resolve_ea(pVM68k,&next,VM68K_LONG,addrmode,reg2,VM68K_LEGAL_CONTROLADDRESSING,&ea); result=ea; if (retval==VM68K_OK) PUSHLONGTOSTACK(pVM68k,&next,result); break; case VM68K_INST_LEA: retval=vm68k_resolve_ea(pVM68k,&next,VM68K_LONG,addrmode,reg2,VM68K_LEGAL_CONTROLADDRESSING,&ea); result=ea%(pVM68k->memsize); if (retval==VM68K_OK) retval=vm68k_storeresult(pVM68k,&next,VM68K_LONG,ADDRREGADDR(reg1),result); break; case VM68K_INST_NOP: retval=VM68K_OK; break; case VM68K_INST_ASL_ASR: case VM68K_INST_LSL_LSR: case VM68K_INST_ROL_ROR: case VM68K_INST_ROXL_ROXR: { tVM68k_types datatype2; tVM68k_ubyte count; tVM68k_bool direction; int i; tVM68k_bool msb; tVM68k_bool lsb; tVM68k_ubyte bitnum; direction=(opcode>>8)&1; // 0=right. 1=left. if (datatype==VM68K_UNKNOWN) // memory shift { datatype2=VM68K_WORD; count=1; retval=vm68k_resolve_ea(pVM68k,&next,VM68K_LONG,addrmode,reg2,VM68K_LEGAL_MEMORYALTERATE,&ea); } else { datatype2=datatype; if ((opcode>>5)&1) { count=pVM68k->d[reg1]%64; } else // i/r=1 -> register. i/r=0 -> immedate { count=reg1; if (count==0) count=8; } retval=VM68K_OK; ea=DATAREGADDR(reg2); } if (retval==VM68K_OK) retval=vm68k_fetchoperand(pVM68k,0,datatype,ea,&operand2); switch (datatype2) { case VM68K_BYTE: bitnum= 8;break; case VM68K_WORD: bitnum=16;break; case VM68K_LONG: bitnum=32;break; default: retval=VM68K_NOK_UNKNOWN_INSTRUCTION;break; } next.vflag=0; for (i=0;i>(bitnum-1))&1; lsb=operand2&1; if (direction) // left shift { operand2<<=1; switch (instruction) { case VM68K_INST_ASL_ASR: case VM68K_INST_LSL_LSR: lsb=0;break; case VM68K_INST_ROL_ROR: lsb=msb;break; case VM68K_INST_ROXL_ROXR: lsb=next.xflag;break; default: retval=VM68K_NOK_UNKNOWN_INSTRUCTION;break; } operand2|=lsb; next.cflag=next.xflag=msb; // FIXME: reallY??? if (instruction!=VM68K_INST_ASL_ASR) next.vflag|=(prevmsb^(operand2>>(bitnum-1)))&1; // set overfloat flag if the msb is changed at any time. } else { /// right shift operand2>>=1; switch (instruction) { case VM68K_INST_ASL_ASR: msb=msb&1;break; case VM68K_INST_LSL_LSR: msb=0;break; case VM68K_INST_ROL_ROR: msb=lsb;break; case VM68K_INST_ROXL_ROXR: msb=next.xflag;break; default: retval=VM68K_NOK_UNKNOWN_INSTRUCTION;break; } operand2|=(msb<<(bitnum-1)); next.cflag=next.xflag=lsb; } } result=operand2; if (retval==VM68K_OK) retval=vm68k_calculateflags(&next,FLAGN|FLAGZ,datatype2,0,operand2,result); if (retval==VM68K_OK) retval=vm68k_storeresult(pVM68k,&next,datatype2,ea,result); } break; case VM68K_INST_BCLR: case VM68K_INST_BCHG: case VM68K_INST_BSET: case VM68K_INST_BTST: { tVM68k_ubyte bitnum; tVM68k_types datatype2; if (addrmode==VM68K_AM_DATAREG) { datatype2=VM68K_LONG; bitnum=32; } else { datatype2=VM68K_BYTE; bitnum=8; } retval=vm68k_resolve_ea(pVM68k,&next,datatype2,addrmode,reg2,VM68K_LEGAL_DATAALTERATE,&ea); if (retval==VM68K_OK) retval=vm68k_fetchoperand(pVM68k,0,datatype2,ea,&operand2); if (retval==VM68K_OK) { operand1=(1<<(next.d[reg1]%bitnum)); next.zflag=((operand2&operand1)==0); switch(instruction) { case VM68K_INST_BCLR: result=operand2&~operand1;break; case VM68K_INST_BCHG: result=operand2^ operand1;break; case VM68K_INST_BSET: result=operand2| operand1;break; default: result=0; break; } } if (retval==VM68K_OK && instruction!=VM68K_INST_BTST) retval=vm68k_storeresult(pVM68k,&next,datatype2,ea,result); } break; case VM68K_INST_BCLRI: case VM68K_INST_BCHGB: case VM68K_INST_BSETB: case VM68K_INST_BTSTB: { tVM68k_uword bitnum; tVM68k_types datatype2; bitnum=READEXTENSIONWORD(pVM68k,&next); datatype2=((addrmode==VM68K_AM_DATAREG)||(addrmode==VM68K_AM_ADDRREG))?VM68K_LONG:VM68K_BYTE; retval=vm68k_resolve_ea(pVM68k,&next,datatype2,addrmode,reg2,VM68K_LEGAL_DATAALTERATE,&ea); if (retval==VM68K_OK) retval=vm68k_fetchoperand(pVM68k,0,datatype2,ea,&operand2); if (retval==VM68K_OK) { operand1=(1<<(bitnum%32)); next.zflag=((operand2&operand1)==0); switch (instruction) { case VM68K_INST_BCLRI: result=~operand1&operand2;break; case VM68K_INST_BSETB: result=operand1|operand2;break; case VM68K_INST_BCHGB: result=operand1^operand2;break; default: result=0; break; } } if (retval==VM68K_OK && instruction!=VM68K_INST_BTSTB) retval=vm68k_storeresult(pVM68k,&next,datatype2,ea,result); } break; case VM68K_INST_ADDX: case VM68K_INST_SUBX: { tVM68k_slong ea_dest; tVM68k_bool rm; rm=(opcode>>3)&1; retval=vm68k_resolve_ea(pVM68k,&next,datatype,(rm?VM68K_AM_PREDEC:VM68K_AM_DATAREG),reg2,VM68K_LEGAL_AM_PREDEC|VM68K_LEGAL_AM_DATAREG,&ea); if (retval==VM68K_OK) retval=vm68k_fetchoperand(pVM68k,0,datatype,ea,&operand2); if (retval==VM68K_OK) retval=vm68k_resolve_ea(pVM68k,&next,datatype,(rm?VM68K_AM_PREDEC:VM68K_AM_DATAREG),reg1,VM68K_LEGAL_AM_PREDEC|VM68K_LEGAL_AM_DATAREG,&ea_dest); if (retval==VM68K_OK) retval=vm68k_fetchoperand(pVM68k,0,datatype,ea,&operand1); if (retval==VM68K_OK) operand1+=next.xflag; if (retval==VM68K_OK) if (instruction==VM68K_INST_SUBX) operand1=-operand1; if (retval==VM68K_OK) result=operand1+operand2; if (retval==VM68K_OK) if (result!=0) next.zflag=0; // special case if (retval==VM68K_OK) retval=vm68k_calculateflags(&next,FLAGS_ALL^FLAGZ,datatype,operand1,operand2,result); if (retval==VM68K_OK) retval=vm68k_storeresult(pVM68k,&next,datatype,ea,result); } break; case VM68K_INST_CMPM: { tVM68k_slong ea_dest; retval=vm68k_resolve_ea(pVM68k,&next,datatype,VM68K_AM_POSTINC,reg2,VM68K_LEGAL_AM_POSTINC,&ea); if (retval==VM68K_OK) retval=vm68k_fetchoperand(pVM68k,1,datatype,ea,&operand2); if (retval==VM68K_OK) retval=vm68k_resolve_ea(pVM68k,&next,datatype,VM68K_AM_POSTINC,reg1,VM68K_LEGAL_AM_POSTINC,&ea_dest); if (retval==VM68K_OK) retval=vm68k_fetchoperand(pVM68k,1,datatype,ea_dest,&operand1); if (retval==VM68K_OK) result=operand2-operand1; if (retval==VM68K_OK) retval=vm68k_calculateflags2(&next,FLAGS_ALL,instruction,datatype,operand1,operand2,result); } break; case VM68K_INST_CLR: { retval=vm68k_resolve_ea(pVM68k,&next,datatype,addrmode,reg2,VM68K_LEGAL_DATAALTERATE,&ea); result=0; if (retval==VM68K_OK) retval=vm68k_calculateflags(&next,FLAGS_LOGIC,datatype,0,0,result); if (retval==VM68K_OK) retval=vm68k_storeresult(pVM68k,&next,datatype,ea,result); } break; case VM68K_INST_DBcc: { retval=VM68K_OK; displacement=READEXTENSIONWORD(pVM68k,&next); if (!vm68k_checkcondition(pVM68k,condition)) { next.d[reg2]&=0xffff0000; next.d[reg2]|=(pVM68k->d[reg2]-1)&0xffff; if ((tVM68k_sword)next.d[reg2]>=0) next.pcr=pVM68k->pcr+displacement; } } break; case VM68K_INST_SWAP: { tVM68k_types datatype2; datatype2=VM68K_LONG; retval=vm68k_resolve_ea(pVM68k,&next,datatype2,VM68K_AM_DATAREG,reg2,VM68K_LEGAL_AM_DATAREG,&ea); if (retval==VM68K_OK) retval=vm68k_fetchoperand(pVM68k,0,datatype2,ea,&operand2); if (retval==VM68K_OK) result=((operand2>>16)&0xffff)|((operand2&0xffff)<<16); if (retval==VM68K_OK) next.nflag=(result>>31)&1; if (retval==VM68K_OK) next.zflag=(result==0); next.cflag=0; next.vflag=0; if (retval==VM68K_OK) retval=vm68k_storeresult(pVM68k,&next,datatype2,ea,result); } break; case VM68K_INST_SCC: { tVM68k_types datatype2; datatype2=VM68K_BYTE; result=(vm68k_checkcondition(pVM68k,condition))?0xff:0x00; retval=vm68k_resolve_ea(pVM68k,&next,datatype2,addrmode,reg2,VM68K_LEGAL_DATAALTERATE,&ea); if (retval==VM68K_OK) retval=vm68k_storeresult(pVM68k,&next,datatype2,ea,result); } break; case VM68K_INST_TST: { retval=vm68k_resolve_ea(pVM68k,&next,datatype,addrmode,reg2,VM68K_LEGAL_DATAALTERATE,&ea); if (retval==VM68K_OK) retval=vm68k_fetchoperand(pVM68k,0,datatype,ea,&operand2); if (retval==VM68K_OK) result=operand2; if (retval==VM68K_OK) retval=vm68k_calculateflags(&next,FLAGS_LOGIC,datatype,0,0,result); } break; case VM68K_INST_UNKNOWN: retval=VM68K_NOK_UNKNOWN_INSTRUCTION; break; default: { char tmp[16]; vm68k_get_instructionname(instruction,tmp); printf("UNIMPLEMENTED opcode %04X = %s\n",opcode,tmp); retval=VM68K_NOK_UNKNOWN_INSTRUCTION; } break; } if (retval==VM68K_OK) { pVM68k->pcr=next.pcr; pVM68k->sr&=0xffe0; if (next.override_sr==1) { pVM68k->sr=next.sr; } else { pVM68k->sr|=(next.cflag)<<0; pVM68k->sr|=(next.vflag)<<1; pVM68k->sr|=(next.zflag)<<2; pVM68k->sr|=(next.nflag)<<3; pVM68k->sr|=(next.xflag)<<4; } pVM68k->a[0]=next.a[0]; pVM68k->a[1]=next.a[1]; pVM68k->a[2]=next.a[2]; pVM68k->a[3]=next.a[3]; pVM68k->a[4]=next.a[4]; pVM68k->a[5]=next.a[5]; pVM68k->a[6]=next.a[6]; pVM68k->a[7]=next.a[7]; pVM68k->d[0]=next.d[0]; pVM68k->d[1]=next.d[1]; pVM68k->d[2]=next.d[2]; pVM68k->d[3]=next.d[3]; pVM68k->d[4]=next.d[4]; pVM68k->d[5]=next.d[5]; pVM68k->d[6]=next.d[6]; pVM68k->d[7]=next.d[7]; if (next.mem_we) { int i; for (i=0;ipMem, next.mem_addr[i],next.mem_value[i]& 0xff);break; case 1: WRITE_INT16BE(pVM68k->pMem,next.mem_addr[i],next.mem_value[i]& 0xffff);break; case 2: WRITE_INT32BE(pVM68k->pMem,next.mem_addr[i],next.mem_value[i]&0xffffffff);break; default: retval=VM68K_NOK_UNKNOWN_INSTRUCTION;break; } } } } return retval; } int vm68k_getNextOpcode(void* hVM68k,unsigned short* opcode) { tVM68k* pVM68k=(tVM68k*)hVM68k; if (hVM68k==NULL) return VM68K_NOK_INVALID_PTR; if (opcode==NULL) return VM68K_NOK_INVALID_PTR; if (pVM68k->magic!=MAGICVALUE) return VM68K_NOK_INVALID_PARAMETER; *opcode=READ_INT16BE(pVM68k->pMem,pVM68k->pcr); pVM68k->pcr+=2; #ifdef DEBUG_PRINT { int i; char tmp[16]; tVM68k_instruction inst; printf("\n\n\npcr:%06x ",pVM68k->pcr); printf("INST:%04X ",*opcode); printf("CVZN:%d%d%d%d ", (pVM68k->sr>>0)&1,(pVM68k->sr>>1)&1,(pVM68k->sr>>2)&1,(pVM68k->sr>>3)&1); printf("D:"); for (i=0;i<8;i++) printf("%08X:",pVM68k->d[i]); printf(" A:"); for (i=0;i<8;i++) printf("%08X:",pVM68k->a[i]); { unsigned long long sum; sum=0; for (i=0;imemsize;i++) sum+=READ_INT32BE(pVM68k->pMem,i); printf("MEMSUM:%llX ",sum); } inst=vm68k_decode(*opcode); vm68k_get_instructionname(inst,tmp); printf(" --> %s\n",tmp); fflush(stdout); } //if (*opcode==0x3031) breakme(); #endif return VM68K_OK; } dmagnetic-0.22/src/engine/include/0000755000175000017500000000000013621220604016445 5ustar dettusdettusdmagnetic-0.22/src/engine/include/linea.h0000644000175000017500000000611313621220604017707 0ustar dettusdettus/* Copyright 2019, dettus@dettus.net Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef LINEA_H #define LINEA_H #define LINEA_OK 0 #define LINEA_OK_QUIT 28844 #define LINEA_OK_RESTART 28816 #define LINEA_NOK_UNKNOWN_INSTRUCTION 1 #define LINEA_NOK_INVALID_PTR -1 #define LINEA_NOK_INVALID_PARAM -2 #define LINEA_NOK_NOT_ENOUGH_MEMORY -3 #include "picture.h" // callback pointers. typedef int (*cbLineAOutputChar)(void* context,char c,unsigned char controlD2,unsigned char flag_headline); typedef int (*cbLineAOutputString)(void* context,char* string,unsigned char controlD2,unsigned char flag_headline); typedef int (*cbLineAInputString)(void* context,int* len,char* string); typedef int (*cbLineADrawPicture)(void* context,tPicture* picture,int mode); typedef int (*cbLineASaveGame)(void* context,char* filename,void* ptr,int len); typedef int (*cbLineALoadGame)(void* context,char* filename,void* ptr,int len); // configuration functions int lineA_getsize(int* size); int lineA_init(void* hLineA,void* pSharedMem,int *sharedmemsize,void* pMag,int magsize,void* pGfx,int gfxsize); int lineA_configrandom(void* hLineA,char random_mode,unsigned int random_seed); int lineA_setEGAMode(void* hLineA,int egamode); int lineA_getVersion(void* hLineA,int* version); int lineA_setCBoutputChar(void* hLineA,cbLineAOutputChar pCB,void *context); int lineA_setCBoutputString(void* hLineA,cbLineAOutputString pCB,void* context); int lineA_setCBinputString(void* hLineA,cbLineAInputString pCB,void* context); int lineA_setCBDrawPicture(void* hLineA,cbLineADrawPicture pCB,void* context); int lineA_setCBSaveGame(void* hLineA,cbLineASaveGame pCB,void* context); int lineA_setCBLoadGame(void* hLineA,cbLineALoadGame pCB,void* context); int lineA_showTitleScreen(void* hLineA); // api int lineA_substitute_aliases(void* hLineA,unsigned short* opcode); int lineA_singlestep(void* hLineA,void* hVM68k,unsigned short opcode); #endif dmagnetic-0.22/src/engine/include/vm68k.h0000644000175000017500000000361713621220604017600 0ustar dettusdettus/* Copyright 2019, dettus@dettus.net Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef VM68K_H #define VM68K_H // the return value is =0, when everything is okay. #define VM68K_OK 0 #define VM68K_NOK_UNKNOWN_INSTRUCTION 1 #define VM68K_NOK_INVALID_PTR -1 #define VM68K_NOK_INVALID_PARAMETER -2 // this function tells how much memory needs to be mallocated for the handle; int vm68k_getsize(int* size); // as the name suggests, pSharedMem is shared among the cores. it typically holds the game code. int vm68k_init(void* hVM68k,void* pSharedMem,int sharedmemsize,int version); int vm68k_singlestep(void *hVM68k,unsigned short opcode); int vm68k_getNextOpcode(void* hVM68k,unsigned short* opcode); #endif dmagnetic-0.22/src/engine/linea/0000755000175000017500000000000013621220610016107 5ustar dettusdettusdmagnetic-0.22/src/engine/linea/gfx2loader.c0000644000175000017500000001245213621220604020317 0ustar dettusdettus/* Copyright 2019, dettus@dettus.net Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "vm68k_datatypes.h" #include "vm68k_macros.h" #include "linea.h" #include #define READ_INT32ME(ptr,idx) (\ (((tVM68k_ulong)((ptr)[((idx)+1)])&0xff)<<24) |\ (((tVM68k_ulong)((ptr)[((idx)+0)])&0xff)<<16) |\ (((tVM68k_ulong)((ptr)[((idx)+3)])&0xff)<< 8) |\ (((tVM68k_ulong)((ptr)[((idx)+2)])&0xff)<< 0) |\ 0) typedef struct _tGFX2_properties { tVM68k_bool is_animation; tVM68k_uword width; tVM68k_uword height; tVM68k_uword celnum; tVM68k_uword animnum; tVM68k_uword commandnum; tVM68k_uword framecnt; tVM68k_ulong offset_background; tVM68k_ulong offset_cels; tVM68k_ulong offset_animations; tVM68k_ulong offset_commands; } tGFX2_properties; int gfx2loader_findoffset(tVM68k_ubyte* gfx2buf,tVM68k_ulong gfx2bufsize,char* filename, tVM68k_slong* offset,tVM68k_slong* length) { int i; int j; int idx; int directorysize; *offset=0; *length=0; directorysize=READ_INT16LE(gfx2buf,4); // the size of the directory is always at this position. for (i=0;i OK } } return -1; } int gfx2loader_loadproperties(tGFX2_properties* pGFX2,tVM68k_ubyte* gfx2buf,tVM68k_ulong gfx2bufsize,tVM68k_ubyte version,char* filename) { int i; tVM68k_slong offset; tVM68k_slong length; tVM68k_slong idx; pGFX2->is_animation=0; pGFX2->width=0; pGFX2->height=0; pGFX2->framecnt=0; // first: find out where the picture/animation is within the gfx2buf // and find out it is an animation or not. if (!gfx2loader_findoffset(gfx2buf,gfx2bufsize,filename,&offset,&length)) { tVM68k_slong datasize; tVM68k_uword animword; idx=offset; pGFX2->offset_background=idx; datasize=READ_INT32ME(gfx2buf,idx+38); pGFX2->width=READ_INT16LE(gfx2buf,idx+42); pGFX2->height=READ_INT16LE(gfx2buf,idx+44); animword=READ_INT16LE(gfx2buf,idx+datasize+48); if (animword!=0x5ed0) { pGFX2->is_animation=1; // second: the animation cels. idx=offset+50+datasize; pGFX2->offset_cels=idx; pGFX2->celnum=READ_INT16LE(gfx2buf,idx); for (i=0;icelnum;i++) { int height1,width1,datasize1; int height2,width2,datasize2; datasize1=READ_INT32ME(gfx2buf,idx+4); width1=READ_INT16LE(gfx2buf,idx+8); height1=READ_INT16LE(gfx2buf,idx+10); width2=READ_INT16LE(gfx2buf,idx+datasize1+14); height2=READ_INT16LE(gfx2buf,idx+datasize1+16); if (height1==height2 && width1==width2) // the cel contains a transparency mask { datasize2=READ_INT16LE(gfx2buf,idx+datasize1+18); idx+=12+datasize1+6+datasize2; } else { // the cel does not contain a transparency mask. just width, height, size and a bitmap idx+=12+datasize1; } } idx+=2; // UNKNOWN // third: the animations, or "actors" pGFX2->offset_animations=idx; pGFX2->animnum=READ_INT16LE(gfx2buf,idx); idx+=2; idx+=2; // UNKNOWN for (i=0;ianimnum;i++) { int animsteps; animsteps=READ_INT16LE(gfx2buf,idx); idx+=2; idx+=2; // UNKNOWN idx+=2*animsteps; // X idx+=2*animsteps; // Y idx+=2*animsteps; // celnum idx+=2*animsteps; // UNKNOWN(*) } idx-=2; // remove the last UNKNOWN(*) // fourth: the commands, the "script" pGFX2->offset_commands=idx; pGFX2->commandnum=READ_INT16LE(gfx2buf,idx);idx+=2; pGFX2->framecnt=0; for (i=0;icommandnum;i++) { int cmd; cmd=READ_INT8BE(gfx2buf,idx);idx++; switch(cmd) { case 0x01: idx+=3;break; case 0x02: pGFX2->framecnt+=READ_INT8BE(gfx2buf,idx);idx++;break; case 0x03: break; case 0x04: idx+=3;break; case 0x05: idx+=3;break; default: break; } } } } return 0; } dmagnetic-0.22/src/engine/linea/linea.c0000644000175000017500000012153713621220604017357 0ustar dettusdettus/* Copyright 2019, dettus@dettus.net Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ //#define DEBUG_PRINT #include #include #include #include "linea.h" #include "gfx1loader.h" #include "vm68k_datatypes.h" #include "vm68k_macros.h" #define MAGICVALUE 0x42696e61 // ="Lina" typedef struct _tProperties { tVM68k_ubyte unknown1[5]; tVM68k_ubyte flags1; tVM68k_ubyte flags2; tVM68k_ubyte unknown2; tVM68k_uword parentobject; tVM68k_ubyte unknown3[2]; tVM68k_uword endflags; } tProperties; typedef struct _tLineA { tVM68k_ulong magic; tVM68k_ubyte version; // pointers to important memory sections. tVM68k_ubyte* pMem; tVM68k_ulong memsize; tVM68k_ulong codesize; tVM68k_ubyte* pStrings1; tVM68k_ulong string1size; // the strings for some adventures were stored in two parts, since they have gotten too big tVM68k_ulong string2size; // tVM68k_ubyte* pDict; tVM68k_ulong dictsize; tVM68k_ulong decsize; tVM68k_ubyte* pStringHuffman; tVM68k_ubyte* pUndo; tVM68k_ulong undosize; tVM68k_slong undopc; // pointers to the callback functions cbLineAOutputChar pcbOutputChar; void* contextOutputChar; cbLineAOutputString pcbOutputString; void* contextOutputString; cbLineAInputString pcbInputString; void* contextInputString; cbLineADrawPicture pcbDrawPicture; void* contextDrawPicture; cbLineASaveGame pcbSaveGame; void* contextSaveGame; cbLineALoadGame pcbLoadGame; void* contextLoadGame; // persistent memory for some A0xx instructions. tVM68k_slong random_state; tVM68k_bool random_mode; tVM68k_uword properties_offset; tVM68k_uword linef_subroutine; // version >0 tVM68k_uword linef_tab; // version >1 tVM68k_uword linef_tabsize; // version >1 tVM68k_uword properties_tab; // version >2 tVM68k_uword properties_size; // version >2 tVM68k_slong interrupted_byteidx; tVM68k_ubyte interrupted_bitidx; // input buffer queue. char inputbuf[256]; int level; int used; #define MAXMAGBUF 350000 #define MAXGFXBUF 3500000 // buffer for everything. Personally, I do not like restricting it. // on the other hand: I do not like mallocs spread around the code either. tVM68k_ubyte magbuf[MAXMAGBUF]; tVM68k_ulong magsize; tVM68k_ubyte gfxbuf[MAXGFXBUF]; tVM68k_ulong gfxsize; // prefer ega images when set. tVM68k_bool egamode; tPicture picture; } tLineA; tVM68k_ulong lineA_getrandom(tLineA* pLineA) { if (pLineA->random_mode==0) { pLineA->random_state*=1103515245ull; pLineA->random_state+=12345ull; } else { pLineA->random_state=rand(); } return pLineA->random_state&0x7fffffff; } int lineA_parsegamefiles(tLineA* pLineA,void* pMag,int magsize,void* pGfx,int gfxsize) { int idx; // first: store the mag and gfx data if (pMag==NULL) return LINEA_NOK_INVALID_PTR; if (magsize>MAXMAGBUF) return LINEA_NOK_NOT_ENOUGH_MEMORY; memcpy(pLineA->magbuf,pMag,magsize);pLineA->magsize=magsize; // lets start with the header. // @0 4 bytes "MaSc" // @4 9 bytes TODO // @13 1 byte version // @14 4 bytes codesize // @18 4 bytes string1size // @22 4 bytes string2size // @26 4 bytes dictsize // @30 4 bytes decsize // @34 4 bytes undosize // @38 4 bytes undopc // ---------- // @42 codesize bytes code // @42+codesize string1size bytes... // @... string2size // @... dictsize // @... undo if (pLineA->magbuf[0]!='M' || pLineA->magbuf[1]!='a' || pLineA->magbuf[2]!='S' || pLineA->magbuf[3]!='c') return LINEA_NOK_INVALID_PARAM; // since the magic word seemed to be okay, start reading the header. pLineA->version=pLineA->magbuf[13]; pLineA->codesize=READ_INT32BE(pLineA->magbuf,14); pLineA->string1size=READ_INT32BE(pLineA->magbuf,18); pLineA->string2size=READ_INT32BE(pLineA->magbuf,22); pLineA->dictsize=READ_INT32BE(pLineA->magbuf,26); pLineA->decsize=READ_INT32BE(pLineA->magbuf,30); pLineA->undosize=READ_INT32BE(pLineA->magbuf,34); pLineA->undopc=READ_INT32BE(pLineA->magbuf,38); ///////////////////////////////////// // the code section has to be copied into the shared memory section. // because the same section is writable. first: drain the memory. memset(pLineA->pMem,0,pLineA->memsize); if (pLineA->memsizecodesize) return LINEA_NOK_NOT_ENOUGH_MEMORY; pLineA->memsize=pLineA->codesize; if (pLineA->memsize<65536) pLineA->memsize=65536; idx=42; // the header held 42 bytes. memcpy(pLineA->pMem,&pLineA->magbuf[idx],pLineA->codesize); idx+=pLineA->codesize; // every other sections is just read-only. they can stay where they are. // for conveniance reasons, i am adding the pointers. pLineA->pStrings1=&pLineA->magbuf[idx];idx+=pLineA->string1size+pLineA->string2size; pLineA->pDict=&pLineA->magbuf[idx];idx+=pLineA->dictsize; pLineA->pUndo=&pLineA->magbuf[idx];idx+=pLineA->undosize; pLineA->pStringHuffman=&pLineA->pStrings1[pLineA->decsize]; pLineA->gfxsize=gfxsize; if (pGfx!=NULL) { memcpy(pLineA->gfxbuf,pGfx,gfxsize); } return LINEA_OK; } // the purpose of this function is to load the properties for a specific object. int lineA_loadproperties(tLineA* pLineA,tVM68k* pVM68k,tVM68k_uword objectnum,tVM68k_ulong* retaddr,tProperties* pProperties) { tVM68k_ulong addr; int i; if (pLineA->version>2 && (objectnum>pLineA->properties_size)) { addr=(pLineA->properties_size-objectnum)^0xffff; // TODO: WTF? addr*=2; addr+=pLineA->properties_tab; objectnum=READ_INT16BE(pVM68k->pMem,addr); } addr=pLineA->properties_offset+14*objectnum; for (i=0;i<5;i++) { pProperties->unknown1[i]=pVM68k->pMem[addr+i]; } pProperties->flags1=pVM68k->pMem[addr+5]; pProperties->flags2=pVM68k->pMem[addr+6]; pProperties->unknown2=pVM68k->pMem[addr+7]; pProperties->parentobject=READ_INT16BE(pVM68k->pMem,addr+8); for (i=0;i<2;i++) { pProperties->unknown3[i]=pVM68k->pMem[addr+i+10]; } pProperties->endflags=READ_INT16BE(pVM68k->pMem,addr+12); if (retaddr!=NULL) *retaddr=addr; return LINEA_OK; } int lineA_getsize(int* size) { if (size==NULL) return LINEA_NOK_INVALID_PTR; *size=sizeof(tLineA); return LINEA_OK; } int lineA_showTitleScreen(void* hLineA) { tLineA* pLineA=(tLineA*)hLineA; if (hLineA==NULL) return LINEA_NOK_INVALID_PTR; // the pc version has title screens. it would be a shame not to show them. if (pLineA->gfxsize) { if (pLineA->gfxbuf[0]=='M' && pLineA->gfxbuf[1]=='a' && pLineA->gfxbuf[2]=='P' && pLineA->gfxbuf[3]=='3') { gfxloader_unpackpic(pLineA->gfxbuf,pLineA->gfxsize,pLineA->version,30,NULL,&pLineA->picture,0); if (pLineA->pcbDrawPicture!=NULL) { pLineA->pcbDrawPicture(pLineA->contextDrawPicture,&pLineA->picture,1); } if (pLineA->pcbOutputChar!=NULL) { pLineA->pcbOutputString(pLineA->contextOutputString,"Press Enter",0,0); } // wait for an ENTER pLineA->level=0; pLineA->pcbInputString(pLineA->contextInputString,&pLineA->level,pLineA->inputbuf); pLineA->level=0; } } return LINEA_OK; } int lineA_substitute_aliases(void* hLineA,unsigned short* opcode) { tVM68k_uword inst; inst=*opcode; if ((inst&0xfe00)==0xA400) {inst&=0x01ff;inst|=0x6100;} // BSR if ((inst&0xfe00)==0xA200) {inst=0x4e75;} // RTS if ((inst&0xfe00)==0xA600) {inst&=0x01ff;inst|=0x4a00;} // TST if ((inst&0xfe00)==0xA800) {inst&=0x01ff;inst|=0x4800;} // MOVEM, register to memory (=0x4800) if ((inst&0xfe00)==0xAA00) {inst&=0x01ff;inst|=0x4C00;} // MOVEM, memory to register (=0x4C00) *opcode=inst; return LINEA_OK; } int lineA_init(void* hLineA,void* pSharedMem,int *sharedmemsize,void* pMag,int magsize,void* pGfx,int gfxsize) { tLineA* pLineA=(tLineA*)hLineA; int retval; if (hLineA==NULL) return LINEA_NOK_INVALID_PTR; memset(pLineA,0,sizeof(tLineA)); pLineA->magic=MAGICVALUE; pLineA->random_mode=0; pLineA->random_state=12345; pLineA->pMem=pSharedMem; pLineA->memsize=*sharedmemsize; pLineA->pcbOutputChar=NULL; pLineA->contextOutputChar=NULL; pLineA->pcbOutputString=NULL; pLineA->contextOutputString=NULL; pLineA->pcbInputString=NULL; pLineA->contextInputString=NULL; pLineA->pcbDrawPicture=NULL; pLineA->contextDrawPicture=NULL; pLineA->pcbSaveGame=NULL; pLineA->contextSaveGame=NULL; pLineA->pcbLoadGame=NULL; pLineA->contextLoadGame=NULL; retval=lineA_parsegamefiles(pLineA,pMag,magsize,pGfx,gfxsize); *sharedmemsize=pLineA->memsize; return retval; } int lineA_configrandom(void* hLineA,char random_mode,unsigned int random_seed) { tLineA* pLineA=(tLineA*)hLineA; if (hLineA==NULL) return LINEA_NOK_INVALID_PTR; if (pLineA->magic!=MAGICVALUE) return LINEA_NOK_INVALID_PARAM; if (random_mode!=0 && random_mode!=1) return LINEA_NOK_INVALID_PARAM; if (random_seed<1 || random_seed>0x7fffffff) return LINEA_NOK_INVALID_PARAM; pLineA->random_mode=random_mode; pLineA->random_state=random_seed; srand(random_seed); return 0; } int lineA_setEGAMode(void* hLineA,int egamode) { tLineA* pLineA=(tLineA*)hLineA; if (hLineA==NULL) return LINEA_NOK_INVALID_PTR; if (pLineA->magic!=MAGICVALUE) return LINEA_NOK_INVALID_PARAM; if (egamode!=0 && egamode!=1) return LINEA_NOK_INVALID_PARAM; pLineA->egamode=egamode; return 0; } int lineA_getVersion(void* hLineA,int* version) { tLineA* pLineA=(tLineA*)hLineA; if (pLineA==NULL) return LINEA_NOK_INVALID_PTR; if (version==NULL) return LINEA_NOK_INVALID_PTR; if (pLineA->magic!=MAGICVALUE) return LINEA_NOK_INVALID_PARAM; *version=pLineA->version; return LINEA_OK; } int lineA_singlestep(void* hLineA,void* hVM68k,unsigned short opcode) { tLineA* pLineA=(tLineA*)hLineA; tVM68k* pVM68k=(tVM68k*)hVM68k; int retval=LINEA_NOK_UNKNOWN_INSTRUCTION; if (pLineA==NULL) return LINEA_NOK_INVALID_PTR; if (pVM68k==NULL) return LINEA_NOK_INVALID_PTR; if (pLineA->magic!=MAGICVALUE) return LINEA_NOK_INVALID_PARAM; if (pLineA->version!=0 && (opcode&0xf000)==0xf000) // version 1 introduced programmable subroutines. // with version 2, it became programmable { // PUSHLONGTOSTACK(pVM68k,&next,next.pcr); if (pLineA->version==1) { // push long to stack pVM68k->a[7]-=4; WRITE_INT32BE(pVM68k->pMem,pVM68k->a[7],pVM68k->pcr); pVM68k->pcr=(pLineA->linef_subroutine)%pVM68k->memsize; } else { tVM68k_uword idx; tVM68k_sword base; idx=opcode&0x7ff; if (idx>=pLineA->linef_tabsize) { // so... at linef_tab is a list of jump-points. // the virtually, the pc jumps onto the address given by the opcode, and from there another XXXX samples on. if (!(opcode&0x0800)) // when it is a call to a subroutine { // push long to stack pVM68k->a[7]-=4; WRITE_INT32BE(pVM68k->pMem,pVM68k->a[7],pVM68k->pcr); pVM68k->pcr=(pLineA->linef_subroutine)%pVM68k->memsize; } idx=(opcode|0x0800); idx^=0xffff; base=READ_INT16BE(pVM68k->pMem,(pLineA->linef_tab+2*idx)); pVM68k->pcr=(pLineA->linef_tab+2*idx+base)%pVM68k->memsize; // jump, then jump again. } else { // push long to stack pVM68k->a[7]-=4; WRITE_INT32BE(pVM68k->pMem,pVM68k->a[7],pVM68k->pcr); pVM68k->pcr=(pLineA->linef_subroutine)%pVM68k->memsize; } } return LINEA_OK; } if ((opcode&0xff00)!=0xa000) return LINEA_NOK_INVALID_PARAM; retval=LINEA_OK; if ((opcode&0xff)<0xdd || (pLineA->version < 4 && (opcode&0xff) < 0xe4) || (pLineA->version < 2 && (opcode&0xff) < 0xed)) { lineA_getrandom(pLineA); // advance the random generator } switch (opcode) { case 0xa000: // getchar // the way i implemented the input is this: // i have a buffer, inputbuf[256]. holding the last input string. // when this instruction is called, one character is read and written into D1. // // when the buffer is empty, the callback function for inputs is called first. { if (pLineA->level==pLineA->used) { pLineA->level=0; pLineA->used=0; if (pLineA->pcbInputString!=NULL) { pLineA->pcbInputString(pLineA->contextInputString,&pLineA->level,pLineA->inputbuf); // callback to fill the input buffer. } else { fprintf(stderr,"INTERNAL ERROR: no input set!\n"); exit(0); } } if (pLineA->level>pLineA->used) // still characters in the buffer? { pVM68k->d[1]=pLineA->inputbuf[pLineA->used]; // yes. take one out pLineA->used++; // increase the read pointer for the next time. } } break; case 0xa0de: // version 3 (corruption) introduced this. the other implementation wrote a 1 into D1. { pVM68k->d[1]&=0xffffff00; pVM68k->d[1]|=0x01; } break; case 0xa0df: // version 3 (corruption) introduced this. { tVM68k_ubyte picname[9]; tVM68k_ubyte datatype; int i; datatype=READ_INT8BE(pVM68k->pMem,pVM68k->a[1]+2); for (i=0;i<8;i++) { picname[i]=READ_INT8BE(pVM68k->pMem,pVM68k->a[1]+3+i); } picname[8]=0; switch (datatype) { case 7: // show picture if (pLineA->gfxsize) { gfxloader_unpackpic(pLineA->gfxbuf,pLineA->gfxsize,pLineA->version,-1,picname,&pLineA->picture,pLineA->egamode); if (pLineA->pcbDrawPicture!=NULL) { pLineA->pcbDrawPicture(pLineA->contextDrawPicture,&pLineA->picture,2); } } break; default: break; } } break; case 0xa0e0: // unknown break; case 0xa0e1: // getstring, new feature by corruption! (version4) { int i; // the way i implemented the input is this: // i have a buffer, inputbuf[256]. holding the last input string. // when this instruction is being called, the argument is the output pointer in A1. // up to 256 bytes may be written there. A1 itself is being incremented, until // the end of the output is being reached. // // when the amount of bytes is either 256 or 1, D1 is set to 1. (TODO: why?) // // when the buffer is empty, the callback function for inputs is called first. lineA_getrandom(pLineA); // advance the random generator if (pLineA->level==pLineA->used) { pLineA->level=0; pLineA->used=0; if (pLineA->pcbInputString!=NULL) { pLineA->pcbInputString(pLineA->contextInputString,&pLineA->level,pLineA->inputbuf); // callback to fill the input buffer. } else { fprintf(stderr,"INTERNAL ERROR: no input set!\n"); exit(0); } } i=0; if (pLineA->level>pLineA->used) // still characters in the buffer? { tVM68k_ubyte c; do { c=pLineA->inputbuf[pLineA->used]; if (c==0) c='\n'; // apparently, the virtual machine wants its strings CR terminated. WRITE_INT8BE(pVM68k->pMem,(pVM68k->a[1]+i),c); pLineA->used++; // increase the read pointer for the next time. i++; } while (i<256 && pLineA->level>pLineA->used && c!='\n'); } pVM68k->a[1]+=(i-1); pVM68k->d[1]&=0xffff0000; if (i==256 || i==1) { pVM68k->d[1]|=1; } } break; case 0xa0e3: // this one apparently erases the picture if (pVM68k->d[1]==0) { if (pLineA->version<4 || pVM68k->d[6]==0) { // TODO: clear window } } break; case 0xa0e4: { pVM68k->a[7]+=4; // increase the stack pointer? maybe skip an entry or something? pVM68k->pcr=READ_INT32BE(pVM68k->pMem,pVM68k->a[7])%pVM68k->memsize; pVM68k->a[7]+=4; } break; case 0xa0e5: // set the Z-flag, RTS, introduced with jinxter. case 0xa0e6: // clear the Z-flag, RTS, introduced with jinxter. case 0xa0e7: // set the Z-flag, introduced with jinxter. case 0xa0e8: // clear the Z-flag, introduced with jinxter. { if (opcode==0xa0e5 || opcode==0xa0e7) // set zflag { pVM68k->sr|=(1<<2); // BIT 2 is the Z-flag } else { // clear z-flag pVM68k->sr&=~(1<<2); // BIT 2 is the Z-flag } if (opcode==0xa0e4 || opcode==0xa0e5 || opcode==0xa0e6) { // RTS: poplongfromstack(pcr); pVM68k->pcr=READ_INT32BE(pVM68k->pMem,pVM68k->a[7])%pVM68k->memsize; pVM68k->a[7]+=4; } } break; case 0xa0e9: { // strcpy a word from the dictionary into the memory. // source is in A1 // destination is A0 tVM68k_ubyte tmp; do { tmp=pLineA->pDict[pVM68k->a[1]++]; pVM68k->pMem[pVM68k->a[0]++]=tmp; } while (!(tmp&0x80)); } break; case 0xa0ea: // print a word from the dictionary. the beginning INDEX is stored in A1. the headline flag is signalled in D1. { unsigned char c; tVM68k_ubyte* dictptr; tVM68k_uword dictidx; if (pLineA->pDict==NULL || pLineA->dictsize==0) { retval=LINEA_NOK_INVALID_PTR; } else { dictptr=pLineA->pDict; dictidx=pVM68k->a[1]&0xffff; do { c=dictptr[dictidx++]; pLineA->pcbOutputChar(pLineA->contextOutputChar,c,pVM68k->d[2]&0xff,pVM68k->d[1]&0xff); } while (!(c&0x80)); pVM68k->a[1]&=0xffff0000; pVM68k->a[1]|=dictidx; } } break; case 0xa0eb: // write the byte stored in D1 into the dictionary at index A1 { pLineA->pDict[pVM68k->a[1]&0xffff]=pVM68k->d[1]&0xff; } break; case 0xa0ec: // read one byte stored @A1 from the dictionary. write it into register D0. (jinxter) { pVM68k->d[1]&=0xffffff00; pVM68k->d[1]|=pLineA->pDict[pVM68k->a[1]&0xffff]&0xff; } break; case 0xa0ed: // quit { retval=LINEA_OK_QUIT; } break; case 0xa0ee: // restart { retval=LINEA_OK_RESTART; } break; case 0xa0f0: { //printf("\x1b[1;37;44mLINEA: show picture %d mode %d\x1b[0m\n",pVM68k->d[0],pVM68k->d[1]); if (pVM68k->d[1] && pLineA->gfxsize) { gfxloader_unpackpic(pLineA->gfxbuf,pLineA->gfxsize,pLineA->version,pVM68k->d[0],NULL,&pLineA->picture,pLineA->egamode); if (pLineA->pcbDrawPicture!=NULL) { pLineA->pcbDrawPicture(pLineA->contextDrawPicture,&pLineA->picture,pVM68k->d[1]); } } } break; case 0xa0f1: { // skip some words in the input buffer tVM68k_ubyte* inputptr; tVM68k_uword inputidx; tVM68k_ubyte cinput; int i,n; inputptr=&pVM68k->pMem[pVM68k->a[1]&0xffff]; inputidx=0; n=(pVM68k->d[0])&0xffff; for (i=0;ia[1]+=inputidx; } break; case 0xa0f2: { tVM68k_uword objectnum; tProperties properties; int n; tVM68k_bool found; objectnum=(pVM68k->d[2])&0x7fff; n=pVM68k->d[4]&0x7fff; pVM68k->d[0]&=0xffff0000; pVM68k->d[0]|=pVM68k->d[2]&0xffff; found=0; retval=lineA_loadproperties(pLineA,pVM68k,objectnum,&pVM68k->a[0],&properties); do { if (properties.endflags&0x3fff) { found=1; } else { retval=lineA_loadproperties(pLineA,pVM68k,objectnum-1,NULL,&properties); if (objectnum==n) found=1; else objectnum--; } } while ((objectnum!=0) && !found); if (found) pVM68k->sr|=(1<<0); // bit 0 is the cflag pVM68k->d[2]&=0xffff0000; pVM68k->d[2]|=objectnum&0xffff; } break; case 0xa0f3: if (pLineA->pcbOutputChar!=NULL) { pLineA->pcbOutputChar(pLineA->contextOutputChar,pVM68k->d[1],pVM68k->d[2]&0xff,pVM68k->d[3]&0xff); } break; case 0xa0f4: { // TODO: version 0. The filename starts at A0. if (pLineA->pcbSaveGame!=NULL) { pLineA->pcbSaveGame(pLineA->contextSaveGame, (char*)&pVM68k->pMem[(pVM68k->a[0]&0xffff)], // filename &pVM68k->pMem[(pVM68k->a[1]&0xffff)], // ptr (pVM68k->d[1]&0xffff) // len ); } } break; case 0xa0f5: { // TODO: VERSION 0: filename starts at A0 if (pLineA->pcbLoadGame!=NULL) { pLineA->pcbLoadGame(pLineA->contextLoadGame, (char*)&pVM68k->pMem[(pVM68k->a[0]&0xffff)], // filename &pVM68k->pMem[(pVM68k->a[1]&0xffff)], // ptr (pVM68k->d[1]&0xffff) // len ); } } break; case 0xa0f6: // get random number (word), modulo D1. { tVM68k_ulong rand; tVM68k_uword limit; rand=lineA_getrandom(pLineA); // advance the random generator limit=(pVM68k->d[1])&0xff; if (limit==0) limit=1; rand%=limit; pVM68k->d[1]&=0xffff0000; pVM68k->d[1]|=(rand&0xffff); } break; case 0xa0f7: { // get a random value between 0 and 255, and write it to D0. tVM68k_ulong rand; rand=lineA_getrandom(pLineA); // advance the random generator pVM68k->d[0]&=0xffffff00; pVM68k->d[0]|=((rand+(rand>>8))&0xff); } break; case 0xa0f8: // write string { // strings are huffman-coded. // version 0: 'string2' holds the decoding tree in the first 256 bytes. // and the offset addresses for the bit streams in string1. // modes have bit 7 set. // // when the string is terminated with a \0 it ends. // when the string terminates with the sequence " @", it will be // extended. // // the extension will have the cflag set. // tVM68k_ulong idx; tVM68k_uword tmp; tVM68k_ubyte val; tVM68k_ubyte prevval; tVM68k_ulong byteidx; tVM68k_ubyte bitidx; char string[4096]; // TODO int stringidx; char c; if (!(pVM68k->sr&(1<<0))) // cflag is in bit 0. { byteidx=0; // start the byteidx and bitidx counter bitidx=0; idx=pVM68k->d[0]&0xffff; if (idx==0) byteidx=idx; // version 0: string 2 holds the table to decode the strings. // the decoder table is 256 bytes long. afterwards, a bunch of pointers // to bit indexes follow. else byteidx=READ_INT16BE(pLineA->pStringHuffman,(0x100+2*idx)); tmp=READ_INT16BE(pLineA->pStringHuffman,0x100); if (tmp && idx>=tmp) { byteidx+=pLineA->string1size; } } else { byteidx=pLineA->interrupted_byteidx; bitidx=pLineA->interrupted_bitidx; } val=0; stringidx=0; do { prevval=val; val=0; while (!(val&0x80)) // terminal symbols have bit 7 set. { tVM68k_ubyte bit; bit=pLineA->pStrings1[byteidx]; if (bit>>(bitidx)&1) { val=pLineA->pStringHuffman[0x80+val]; // =1 -> go to the right } else { val=pLineA->pStringHuffman[ val]; // =0 -> go to the left } bitidx++; if (bitidx==8) { bitidx=0; byteidx++; } } val&=0x7f; // remove bit 7. c=val; string[stringidx++]=c; } while (val!=0 && !(prevval==' ' && val=='@')); // end markers for the string are \0 and " @" if (prevval==' ' && val=='@') // extend the string next time this function is being called. { pVM68k->sr|=(1<<0); // set the cflag. cflag=bit 0. pLineA->interrupted_byteidx=byteidx; pLineA->interrupted_bitidx=bitidx; } else { pVM68k->sr&=~(1<<0); // clear the cflag. cflag=bit 0. } string[stringidx]=0; // string has been assembled. and is 0 terminated now print it. // perform the callback so that the string becomes visible. TODO: extended strings might be a problem!! if (pLineA->pcbOutputChar!=NULL) { pLineA->pcbOutputString(pLineA->contextOutputString,string,pVM68k->d[2]&0xff,pVM68k->d[3]&0xff); } } break; case 0xa0f9: //get inventory item(d0) { // there is a list of parent objects // // apparently, the structure of the properties is as followed: // byte 0..4: UNKNOWN // byte 5: Flags. // bit 0: is_described // byte 6: some flags // =bit 7: worn // =bit 6: bodypart // =bit 3: room // =bit 2: hidden // byte 8/9: parent object. the player is =0x0000 // byte 10..13: UNKNOWN // the data structure is a list. tVM68k_bool found; tVM68k_uword objectnum1; tVM68k_uword objectnum2; tProperties properties; found=0; // go backwards from the objectnumber for (objectnum1=pVM68k->d[0];objectnum1>0 && !found;objectnum1--) { objectnum2=objectnum1; do { // search for the parent retval=lineA_loadproperties(pLineA,pVM68k,objectnum2,&pVM68k->a[0],&properties); objectnum2=properties.parentobject; if ((properties.flags1&1) //is described || (properties.flags2&0xcc)) // worn, bodypart, room or hidden { objectnum2=0; // break the loop } else if (properties.parentobject==0) found=1; if (!(properties.flags2&1)) { objectnum2=0; // break the loop } } while (objectnum2); } // set the z-flag when the object was found. otherwise clear it. pVM68k->sr&=~(1<<2); // zflag is bit 2 if (found) pVM68k->sr|=(1<<2); pVM68k->d[0]&=0xffff0000; pVM68k->d[0]|=(objectnum1+1)&0xffff; // return value } break; case 0xa0fa: { // search the properties database for a match with the entry in D2. // starting adress is stored in A0. D3 is the variable counter. // d4 is the limit. for (;D3a[0]; pattern=pVM68k->d[2]; byte0word1=pVM68k->d[5]; pVM68k->sr&=~(1<<0); // cflag is bit 0; for (i=(pVM68k->d[3]&0xffff);i<(pVM68k->d[4]&0xffff) && !found;i++) { if (byte0word1) { value=READ_INT16BE(pVM68k->pMem,addr); value&=0x3fff; } else { value= READ_INT8BE(pVM68k->pMem,addr); value&=0xff; } addr+=14; if (value==pattern) { found=1; pVM68k->a[0]=addr; pVM68k->sr|=(1<<0); // cflag is bit 0. } } pVM68k->d[3]=i; } break; case 0xa0fb: { // skip D2 many words in the dictionary, that is pointed at by A1 tVM68k_ubyte* dictptr; tVM68k_uword dictidx; tVM68k_ubyte cdict; int i; int n; dictidx=0; if (pLineA->version==0 || pLineA->pDict==NULL || pLineA->dictsize==0) { dictptr=&pVM68k->pMem[pVM68k->a[1]&0xffff]; } else { //dictptr=pLineA->pDict; dictptr=&pLineA->pDict[pVM68k->a[1]&0xffff]; } n=(pVM68k->d[2]&0xffff); for (i=0;id[2]&=0xffff0000; // that was a counter pVM68k->a[1]+=dictidx; } break; case 0xa0fc: // skip D0 many words in the input buffer, as well as the dictionary. { tVM68k_ubyte* dictptr; tVM68k_ubyte* inputptr; tVM68k_uword dictidx; tVM68k_uword inputidx; int i,n; dictidx=0; inputidx=0; if (pLineA->version==0 || pLineA->pDict==NULL || pLineA->dictsize==0) { dictptr=&pVM68k->pMem[pVM68k->a[0]&0xffff]; // TODO: version 0. } else { dictptr=&pLineA->pDict[pVM68k->a[0]&0xffff]; } inputptr=&pVM68k->pMem[pVM68k->a[1]&0xffff]; n=(pVM68k->d[0])&0xffff; for (i=0;id[0]&=0xffff0000; // d0 was used as a counter pVM68k->a[0]+=dictidx; pVM68k->a[1]+=inputidx; } break; case 0xa0fd: pLineA->properties_offset=pVM68k->a[0]; if (pLineA->version!=0) { // version 1 introduced line F instructions pLineA->linef_subroutine=(pVM68k->a[3]&0xffff); if (pLineA->version>1) { // version 2 instruduced programmable instructions pLineA->linef_tab=(pVM68k->a[5])&0xffff; pLineA->linef_tabsize=(pVM68k->d[7]+1)&0xffff; } if (pLineA->version>2) { pLineA->properties_tab=(pVM68k->a[6])&0xffff; pLineA->properties_size=(pVM68k->d[6]); } } break; case 0xa0fe: { // register D0 conatins an object number. calculate the address in memory tVM68k_sword objectnum; tVM68k_ulong objectidx; if (pLineA->version>2 && (pVM68k->d[0]&0x3fff)>pLineA->properties_size) { pVM68k->d[0]&=0xffff7fff; // objectidx=((pLineA->properties_size-(pVM68k->d[0]&0x3fff))^0xffff); // TODO: I THINK THIS IS JUST A MODULO!!! objectidx=((pVM68k->d[0]&0x3fff)-pLineA->properties_size)-1; objectnum=READ_INT16BE(pVM68k->pMem,pLineA->properties_tab+objectidx*2); } else { if (pLineA->version>=2) { pVM68k->d[0]&=0xffff7fff; } else { pVM68k->d[0]&=0x00007fff; } objectnum=pVM68k->d[0]&0x7fff; } objectnum&=0x3fff; pVM68k->a[0]=pLineA->properties_offset+objectnum*14; } break; case 0xa0ff: { // so, here's what i know: (version 0) // the dictonary is stored at A3. // the word entered at A6 // there is a "bank" in register D6 // // the data structure is more or less plain. but the last char of each word has bit 7 set. // special characters 0x81=ENDOFDICT 0x82=BANKSEPARATOR are used. // // input: (A6) // output: (A2) // dict: (A3) // objects: (A1) { tVM68k_ubyte* dtabptr; tVM68k_ubyte* inputptr; tVM68k_ubyte* outputptr; tVM68k_ubyte* dictptr; tVM68k_ubyte* objectptr; tVM68k_ubyte* adjptr; tVM68k_uword inputidx; tVM68k_uword outputidx; tVM68k_uword outputidx2; tVM68k_uword dictidx; tVM68k_uword objectidx; tVM68k_uword adjidx; tVM68k_uword wordidx; tVM68k_ubyte bank; tVM68k_ubyte flag; tVM68k_bool matching; tVM68k_ubyte cinput1,cinput2; tVM68k_ubyte cdict; tVM68k_bool matchfound; tVM68k_ulong wordmatch; tVM68k_uword longestmatch; tVM68k_ubyte flag2; int i,j; longestmatch=0; flag2=0; inputptr =&pVM68k->pMem[pVM68k->a[6]]; if (pLineA->version==0 || pLineA->pDict==NULL || pLineA->dictsize==0) { dictptr=&pVM68k->pMem[pVM68k->a[3]&0xffff]; dtabptr=&pVM68k->pMem[pVM68k->a[5]&0xffff]; // version>0 } else { dictptr=&pLineA->pDict[pVM68k->a[3]&0xffff]; dtabptr=&pLineA->pDict[pVM68k->a[5]&0xffff]; // version>0 } outputptr =&pVM68k->pMem[pVM68k->a[2]]; objectptr =&pVM68k->pMem[pVM68k->a[1]]; adjptr =&pVM68k->pMem[pVM68k->a[0]]; inputidx=dictidx=objectidx=outputidx=adjidx=0; pVM68k->d[0]&=0xffff0000; // this regsiter was used during the adjective search. pVM68k->d[1]&=0xffff0000; // this regsiter was used during the adjective search. flag=0; bank=(pVM68k->d[6]&0xff); wordidx=0; cdict=0; matching=1; cinput1=cinput2=0; matchfound=0; pVM68k->d[0]&=0xffff0000; // the way the first loop works is this: // character by character, a word from the dictionary is compared to the input. // when a mismatch happens, the beginning of the next word is searched. -> matching=0; // while (cdict!=0x81) // 0x81 is the end marker of the dictionary { cdict=dictptr[dictidx++]; if (cdict==0x82) // bank separator { flag=0; inputidx=0; wordidx=0; bank++; matching=1; } else if (matching) { // actively comparing cinput1=inputptr[inputidx++]; // the current character cinput2=inputptr[inputidx]; // and the next onea if (pLineA->version!=0) { if (cdict==0x5f && (cinput2!=0 || cinput1==' ')) { flag=0x80; // the dictionary uses _ to signal objects that consist of longer words. "can of worms" thus becomes "can_of_worms". the matcher has to find it. cinput1='_'; // replace the space from the input with an _ to see if there is a match. } } if (cdict&0x80) // the end of an entry in the dictionary is marked by bit 7 being set. { matchfound=0; if ((cinput1&0x5f)==(cdict&0x5f)) // still a match. wonderful. { if (cinput2==0x27) // rabbit's (Wonderland) { tVM68k_ubyte cinput3; inputidx++; cinput3=inputptr[inputidx]; // store the letter after the ' into register D0. for example: rabbit's -> store the S pVM68k->d[0]&=0xffff0000; pVM68k->d[0]|=(cinput3)&0xff; pVM68k->d[0]|=0x200; } if (cdict!=0xa0 || pLineA->version<4) // corruption started using " " as word separator for multi-word objects { if (cinput2==0 || cinput2==0x20 || cinput2==0x27) matchfound=1; // and the input word ends as well. perfect match. } } else { if (pLineA->version==0 && inputidx>7) matchfound=1; // the first 7 characters matched. good enough. matching=0; } } else { // keep comparing. if (pLineA->version!=0) // version 1 introduced objects with multiple words. { if (cinput1==' ' && cdict==0x5f) // multiple word entry found { flag=1; cinput1=0x5f; // multiple word entries are marked by a _ instead of a space. this one makes sure that the next if() will work. } } if ((cinput1&0x5f)!=(cdict&0x5f) || (cdict&0x5f)==0x00 // FIXME ) { if (cinput2==' ' && pLineA->version==0 && inputidx>=7) matchfound=1; // the first 7 characters matched. good enough. matching=0; // there was a mismatch. } } } if (matchfound) { // the matches are stored in the following format: // bit 31..24 are a flag, which is =0 in version 0. // bit 23..16 is the bank. // bit 15..0 contain the matched word number in the bank. wordmatch =(((tVM68k_ulong)flag)<<24); wordmatch|=(((tVM68k_ulong)bank)<<16); wordmatch|=((tVM68k_ulong)wordidx); if (inputidx>=longestmatch) longestmatch=inputidx; WRITE_INT32BE(outputptr,outputidx,wordmatch); // store the candidates in the output location. outputidx+=4; // length of the result: 4 bytes. matchfound=0; } if (cdict&0x80 && cdict!=0x82 && !(pLineA->version>4 && cdict==0xa0)) // when the end of the word is reached. bit 7 is set. { wordidx++; matching=1; // start over inputidx=0; // start over. flag=0; } } WRITE_INT16BE(outputptr,outputidx,0xffff);// the end marker in the buffer is a 0xffff. // the output buffer holds outputidx/4 many results. if (pLineA->version!=0) // version 1 introduced synonyms. { // search the list of output words for (i=0;i>24)&0xff; bank=(wordmatch>>16)&0xff; wordidx=wordmatch&0xffff; if (bank==0x0b) { tVM68k_uword substword; substword=READ_INT16BE(dtabptr,wordidx*2); // TODO: version >1??? // the lower 5 bits are the bank. // the upper 11 bits in the substitute database are the actual word index. bank=substword&0x1f; wordidx=substword>>5; wordmatch=flag;wordmatch<<=8; wordmatch|=(bank&0xff);wordmatch<<=16; wordmatch|=wordidx&0xffff; WRITE_INT32BE(outputptr,i,wordmatch); } } } outputidx2=0; adjidx=0; for (i=0;i>24)&0xff; bank=(wordmatch>>16)&0xff; wordidx=wordmatch&0xffff; mismatch=0; obj=READ_INT16BE(objectptr,objectidx); if (obj && bank==6) { // first step: skip the adjectives that are not meant for this word. each adjective list is separated by a 0. for (j=0;jd[1]&=0xffff0000; if (mismatch==0) { flag2|=flag; wordmatch =flag2&0xff;wordmatch<<=8; wordmatch|=bank&0xff;wordmatch<<=16; wordmatch|=wordidx&0xffff; WRITE_INT32BE(outputptr,outputidx2,wordmatch); outputidx2+=4; } else { pVM68k->d[1]|=1; } } pVM68k->a[5]=pVM68k->a[6]; // flag2 being set denotes that there has been an object that is occupying multiple words. if (flag2 && outputidx) // that match is probably a better one, so move it to the front of the output word list. { for (i=0;ia[5]=pVM68k->a[6]+(longestmatch-3); } } pVM68k->a[2]+=outputidx2; // pVM68k->d[0]=0; pVM68k->a[6]=pVM68k->a[5]+1; } } break; default: printf("\n \x1b[0;37;44mUNIMPLEMENTED LINEA opcode %04X\x1b[0m\n",opcode); break; } return retval; } int lineA_setCBoutputChar(void* hLineA,cbLineAOutputChar pCB,void *context) { tLineA* pLineA=(tLineA*)hLineA; if (pLineA==NULL) return LINEA_NOK_INVALID_PTR; if (pLineA->magic!=MAGICVALUE) return LINEA_NOK_INVALID_PARAM; pLineA->pcbOutputChar=pCB; pLineA->contextOutputChar=context; return LINEA_OK; } int lineA_setCBoutputString(void* hLineA,cbLineAOutputString pCB,void* context) { tLineA* pLineA=(tLineA*)hLineA; if (pLineA==NULL) return LINEA_NOK_INVALID_PTR; if (pLineA->magic!=MAGICVALUE) return LINEA_NOK_INVALID_PARAM; pLineA->pcbOutputString=pCB; pLineA->contextOutputString=context; return LINEA_OK; } int lineA_setCBinputString(void* hLineA,cbLineAInputString pCB,void* context) { tLineA* pLineA=(tLineA*)hLineA; if (pLineA==NULL) return LINEA_NOK_INVALID_PTR; if (pLineA->magic!=MAGICVALUE) return LINEA_NOK_INVALID_PARAM; pLineA->pcbInputString=pCB; pLineA->contextInputString=context; return LINEA_OK; } int lineA_setCBDrawPicture(void* hLineA,cbLineADrawPicture pCB,void* context) { tLineA* pLineA=(tLineA*)hLineA; if (pLineA==NULL) return LINEA_NOK_INVALID_PTR; if (pLineA->magic!=MAGICVALUE) return LINEA_NOK_INVALID_PARAM; pLineA->pcbDrawPicture=pCB; pLineA->contextDrawPicture=context; return LINEA_OK; } int lineA_setCBLoadGame(void* hLineA,cbLineALoadGame pCB,void* context) { tLineA* pLineA=(tLineA*)hLineA; if (pLineA==NULL) return LINEA_NOK_INVALID_PTR; if (pLineA->magic!=MAGICVALUE) return LINEA_NOK_INVALID_PARAM; pLineA->pcbLoadGame=pCB; pLineA->contextLoadGame=context; return LINEA_OK; } int lineA_setCBSaveGame(void* hLineA,cbLineASaveGame pCB,void* context) { tLineA* pLineA=(tLineA*)hLineA; if (pLineA==NULL) return LINEA_NOK_INVALID_PTR; if (pLineA->magic!=MAGICVALUE) return LINEA_NOK_INVALID_PARAM; pLineA->pcbSaveGame=pCB; pLineA->contextSaveGame=context; return LINEA_OK; } dmagnetic-0.22/src/engine/linea/gfx1loader.c0000644000175000017500000006044713621220604020325 0ustar dettusdettus/* Copyright 2019, dettus@dettus.net Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "vm68k_datatypes.h" #include "vm68k_macros.h" #include "gfx1loader.h" #include "linea.h" // for the picture #include #include int gfxloader_gfx1(tVM68k_ubyte* gfxbuf,tVM68k_ulong gfxsize,tVM68k_ubyte version,int picnum,tPicture* pPicture) { int i; int retval; tVM68k_ulong picoffs; tVM68k_uword height; tVM68k_uword width; tVM68k_uword tablesize; tVM68k_ulong datasize; tVM68k_uword tableidx; tVM68k_ulong byteidx; tVM68k_ubyte bitidx; tVM68k_ubyte curbyte; tVM68k_ubyte curpixel; pPicture->halftones=0; // only gfx3 offers halftone pictures retval=0; picnum&=0xffff; picoffs=READ_INT32BE(gfxbuf,8+4*picnum); // the .gfx file starts with the index pointers to the actual picture data. // once the offset has been calculated, the actual picture data is as followed: // bytes 0..1: UNKNOWN // bytes 0x02..0x03: X1 // bytes 0x04..0x05: X2 // X2-X2=width // bytes 0x06..0x07: height // bytes 0x08..0x1b: UNKNOWN // bytes 0x1c..0x3b: palette. // bytes 0x3c..0x3d: size of the huffman table // bytes 0x3e..0x41: size of the data bit stream // // bytes 0x42+0x42+tablesize: huffman decoding table // bytes 0x42+tablesize..0x42+tablesize+datasize: bitstream curpixel=0; width=READ_INT16BE(gfxbuf,picoffs+4)-READ_INT16BE(gfxbuf,picoffs+2); height=READ_INT16BE(gfxbuf,picoffs+6); for (i=0;i<16;i++) { pPicture->palette[i]=READ_INT16BE(gfxbuf,picoffs+0x1c+2*i); } tablesize=READ_INT16BE(gfxbuf,picoffs+0x3c); // size of the huffman table datasize =READ_INT32BE(gfxbuf,picoffs+0x3e); // size of the bitstream // the huffman table contains links. if a bit in the stream is set, the upper 8 bits, otherwise the lower ones. // terminal symbols have bit 7 set. bitidx=8; // MSB first byteidx=picoffs+0x42+tablesize*2+2; tableidx=0; curbyte=READ_INT8BE(gfxbuf,byteidx); byteidx++; for (i=0;(i>bitidx)&1) // bit was set. read the higher 8 bits. { tableidx=(nxt>>8)&0xff; } else { tableidx=(nxt)&0xff; // bit was not set. read the lower 8 bits. } if (bitidx==0) { curbyte=READ_INT8BE(gfxbuf,byteidx); byteidx++; bitidx=8; // MSB first } } tableidx&=0x7f; // remove bit 7. if (tableidx>=0x10) // it bits 6..4 were set, the previous pixels are being repeated { tableidx-=0x10; } else { // since there are only 16 possible pixels, this is it. curpixel=tableidx; tableidx=1; // will become 0 in the next revelation. } } pPicture->pixels[i]=curpixel; tableidx--; } pPicture->height=height; pPicture->width=width; // the finishing touch: each line has to be XORed with the previous one. for (i=width;ipixels[i]^=pPicture->pixels[i-width]; } return retval; } // the gfx2 format introduced MIXED ENDIAN. #define READ_INT32ME(ptr,idx) (\ (((tVM68k_ulong)((ptr)[((idx)+1)])&0xff)<<24) |\ (((tVM68k_ulong)((ptr)[((idx)+0)])&0xff)<<16) |\ (((tVM68k_ulong)((ptr)[((idx)+3)])&0xff)<< 8) |\ (((tVM68k_ulong)((ptr)[((idx)+2)])&0xff)<< 0) |\ 0) int gfxloader_gfx2(tVM68k_ubyte* gfxbuf,tVM68k_ulong gfxsize,tVM68k_ubyte version,tVM68k_ubyte* picname,tPicture* pPicture) { int directorysize; int offset; //int length; int retval; int i; int j; int found; pPicture->width=0; pPicture->height=0; pPicture->halftones=0; // only gfx3 offers halftone pictures // the gfx2 buffer starts with the magic value, and then a directory directorysize=READ_INT16BE(gfxbuf,4); retval=0; // step 1: find the correct filename found=0; for (i=0;ipalette[i]=READ_INT16LE(gfxbuf,offset+4+2*i); } datasize=READ_INT32ME(gfxbuf,offset+38); pPicture->width=READ_INT16LE(gfxbuf,offset+42); pPicture->height=READ_INT16LE(gfxbuf,offset+44); // animmagic=READ_INT16LE(gfx2buf,offset+48+data_size); lumpsize=datasize/pPicture->height/4; // datasize=size of the picture. height: number of lines. thus: datasize/height=number of bytes per line. there are 4 lumps of bits per line. pixidx=0; for (y=0;yheight;y++) { tVM68k_ubyte byte0,byte1,byte2,byte3; tVM68k_ubyte mask; idx0=y*4*lumpsize+offset+48; idx1=idx0+1*lumpsize; idx2=idx0+2*lumpsize; idx3=idx0+3*lumpsize; for (x=0;xwidth;x+=8) { tVM68k_ubyte p; byte0=gfxbuf[idx0++]; byte1=gfxbuf[idx1++]; byte2=gfxbuf[idx2++]; byte3=gfxbuf[idx3++]; mask=(1<<7); // MSB FIRST for (i=0;i<8;i++) { p =(byte0&mask)?0x01:0; p|=(byte1&mask)?0x02:0; p|=(byte2&mask)?0x04:0; p|=(byte3&mask)?0x08:0; mask>>=1; if ((x+i)width) { pPicture->pixels[pixidx++]=p; } } } } } return retval; } #define MAXPICWIDTH 512 int gfxloader_gfx3(tVM68k_ubyte* gfxbuf,tVM68k_ulong gfxsize,tVM68k_ubyte version,int picnum,tPicture* pPicture) { // 0.. 3: 4 bytes "MaP3" // 4.. 8: 4 bytes length of index // 8..11: 4 bytes length of disk1.pix // 11..15: 4 bytes length of disk2.pix // then the index // then the disk1.pix data // then the disk2.pix data int retval; int offs1; int offs2; int offset; int indexoffs,indexlen; int disk1offs,disk1len; int disk2offs; int i,n; int huffsize; int tableidx; int byteidx; int unhufcnt; int pixelcnt; int state; unsigned char mask; unsigned char byte; unsigned int unpackedsize; int max_stipple; unsigned char pl_lut[128]; // lookup table for left pixels unsigned char pr_lut[128]; // lookup table for right pixels unsigned char xorbuf[MAXPICWIDTH*2]; // ring buffer, to perform an XOR over two lines of stipples unsigned char rgbbuf[16]; // RGB values are 6 bits wide. 2 bits red, 2 bits green, 2 bits blue. unsigned char last_stipple; int state_cnt; int height,width; picnum&=0xffff; pPicture->halftones=1; // this format offers half tones. indexlen=READ_INT32BE(gfxbuf, 4); disk1len=READ_INT32BE(gfxbuf, 8); // disk2len=READ_INT32BE(gfxbuf,12); indexoffs=16; disk1offs=indexoffs+indexlen; disk2offs=disk1offs+disk1len; retval=0; // step 1: find the offset of the picture within the index. // the way it is stored is that the offsets within disk1 are stored in the first half, // and the offsets for disk2 are in the second half. // in case the offset is -1, it must be in the other one. offs1=(tVM68k_slong)READ_INT32LE(gfxbuf,indexoffs+picnum*4); offs2=(tVM68k_slong)READ_INT32LE(gfxbuf,indexoffs+indexlen/2+picnum*4); if (picnum!=30 && offs1!=-1 && offs2!=-1) offs1=-1; // in case one picture is stored on both disks, prefer the second one. (due to reasons.) if (picnum==30 && offs1==-1 && offs2==-1) offs1=0; // special case: the title screen for the GUILD of thieves is the first picture in DISK1.PIX if (offs1!=-1) offset=offs1+disk1offs; // in case the index was found in the first half, use disk1 else if (offs2!=-1) offset=offs2+disk2offs; // in case the index was found in the second half, use disk2 else return -1; /// otherwise: ERROR // the picture is stored in layers. // the first layer is a hufman table. // this unpacks the second layer, which contains repitions // and a "stipple" table. from this, the actual pixels are being // calculated. huffsize=gfxbuf[offset+0]; unpackedsize=READ_INT16BE(gfxbuf,offset+huffsize+1); unpackedsize*=4; unpackedsize+=3; unpackedsize&=0xffff; // it was designed for 16 bit machines. pixelcnt=-1; unhufcnt=0; state=0; tableidx=0; mask=0; byteidx=offset+huffsize+2+1; // the beginning of the bitstream starts after the hufman table and the unpackedsize byte=0; width=0; height=0; memset(xorbuf,0,sizeof(xorbuf)); // initialize the xor buffer with 0 state_cnt=0; max_stipple=last_stipple=0; while (unhufcnt>=1; // MSB first. if (b&0x80) // leaves have the highest bit set. terminal symbols only have 7 bit. { tableidx=0; b&=0x7f; // terminal symbols have 7 bit // // // the second layer begins here switch (state) { case 0: // first state: the ID should be "0x77" if (b!=0x77) return -1; // illegal format state=1; break; case 1: // second byte is the number of "stipples" max_stipple=b; state=2; break; case 2: // width, stored as 2*6 bit Big Endian width<<=6; // 2*6 bit. big endian; width|=b&0x3f; state_cnt++; if (state_cnt==2) state=3; break; case 3: // height, stored as 2*6 bit Big Endian height<<=6; // 2*6 bit. big endian; height|=b&0x3f; state_cnt++; if (state_cnt==4) { if (height<=0 || width<=0) return -2; // error in decoding the height and the width pixelcnt=0; state_cnt=0; state=4; } break; case 4: // rgb values rgbbuf[state_cnt++]=b; if (state_cnt==16) { state_cnt=0; state=5; } break; case 5: // lookup-table to retrieve the left pixel value from the stipple pl_lut[state_cnt++]=b; if (state_cnt==max_stipple) { state_cnt=0; state=6; } break; case 6: // lookup-table to retrieve the right pixel value from the stipple pr_lut[state_cnt++]=b; if (state_cnt==max_stipple) { last_stipple=0; state_cnt=0; state=7; } break; case 7: case 8: // now for the stipple table // this is actually a third layer of encoding. // it contains terminal symbols [0... max_stipple) // // if the symbol is max_stipple, it means that the previous symbol is being repeated. n=0; if (state==8) // this character has been "escaped" { state=7; n=1; last_stipple=b; } else if (b=max_stipple. { // this is necessary for the XOR operation. state=8; n=0; } else if (b>max_stipple) { n=b-max_stipple; // repeat the previous stipple b=last_stipple; } } for (i=0;ipixels[pixelcnt++]=pl_lut[x]; pPicture->pixels[pixelcnt++]=pr_lut[x]; } break; } } else { tableidx=b; // non terminal -> traverse the tree further down } } pPicture->height=height; pPicture->width=width*2; // the other image formats have 9 bit wide rgb values. for (i=0;i<16;i++) { unsigned int red,green,blue; red =(rgbbuf[i]>>4)&0x3; green=(rgbbuf[i]>>2)&0x3; blue =(rgbbuf[i]>>0)&0x3; red*= 0x7; green*=0x7; blue*= 0x7; red/= 0x3; green/=0x3; blue/= 0x3; red&=0x7;green&=0x7;blue&=0x7; pPicture->palette[i] =( red<<8); pPicture->palette[i]|=(green<<4); pPicture->palette[i]|=( blue<<0); } return retval; } // the gfx4 format is used to handle the pictures from the Magnetic Windows system. // just like the gfx2, it starts with a directory. 6 byte picname, 4 bytes (little endian) offset, 4 bytes (little endian) length. // at the offset, the picture is being comprised of the tree (type 7) and image (type 6) from the Magnetic Windows resource files. // the tree is ALWAYS 609 bytes long. The size of the image varies. // // the huffman tree uses 9 bits to encode 8 bits: the first 32 bytes are a bitmask (MSB first). Then the branches/symbols follow. // if the bit from the bitmask is set, it is a terminal symbol. // 0x00...0x1f: LEFTMASK (0) // 0x20...0x11f: LEFTBRANCH // 0x120..0x13f: RIGHTMASK (1) // 0x140..0x23f: RIGHTBRANCH // Byte 0x240 escape character (for run level encoding) // Byte 0x241...0x250: EGA palette // Byte 0x251...0x260: EGA palette pairs // // // the image data looks like this: // 0x00..0x03: magic header // 0x04..0x23: 16x2 bytes RGB values (4 bits per channel, little endian, 0x0rgb) // 0x24..0x25: width // 0x26..0x27: height // 0x28..0x29: transparency placeholder // 0x2a..0x2b: size // 0x2c......: bit stream. MSB first. when the bit is set (=1), follow the RIGHT branch. // // the run level encoding is signalled by the escape character from the tree (byte 0x240). // in case the next character is 0xff, it actually an honest escape character. // if any other value follows, it is the repeat num. // the character AFTER that one is being repeated (4+repeat) number of times. // // each symbol is 8 bits large, 4 bits are the pixel. CAREFUL: bits 0..3 are the left, bits 4..7 are the right pixel // in case the width is not divisible by 2, bits 4..7 are being ignored. // // the xor is being performed line by line. // // note that the end of the image comes BEFORE the end of the bitstream. (due to a bug in the encoder) int gfxloader_gfx4(tVM68k_ubyte* gfxbuf,tVM68k_ulong gfxsize,tVM68k_ubyte version,tVM68k_ubyte* picname,tPicture* pPicture,int egamode) { #define SIZEOFTREE 609 int directorysize; int retval; int found; int i; int offset,length; int offset_vanilla,length_vanilla; int offset_ega,length_ega; int offset_anim,length_anim; int j; pPicture->width=0; pPicture->height=0; pPicture->halftones=0; // only gfx3 offers halftone pictures // the gfx4 buffer starts with the magic value, and then a directory retval=0; found=0; directorysize=READ_INT16BE(gfxbuf,4); offset=offset_ega=offset_anim=offset_vanilla=-1; length=length_ega=length_anim=length_vanilla=-1; for (i=0;i=15); stillimage=1; if (READ_INT32LE(gfxbuf,offset+length-4)!=STILLMAGIC) stillimage=0; // if they do not, it is an animation found=0; if (!ega && stillimage) { offset_vanilla=offset; length_vanilla=length; } if (ega) { offset_ega=offset; length_ega=length; } if (!stillimage) { offset_anim=offset; length_anim=length; } } } // in case the image was not found offset=-1; length=-1; if (egamode) { offset=offset_ega; length=length_ega; } if (offset==-1) { offset=offset_vanilla; length=length_vanilla; } if (offset==-1) { offset=offset_anim; length=length_anim; } if (offset==-1) { offset=offset_ega; length=length_ega; } if (offset!=-1 && length!=-1) found=1; if (found) { int treestart; int picstart; int size; int treeidx; int repnum; int rlestate; // for the run length encoding. state 0: if not the escape char, output. otherwise -> state 1. in state 1, if the symbol is 0xff, the output is the escapechar. otherwise, the repition number (sans 4) -> state 4. in state 4, repeat the symbol tVM68k_ubyte escapechar; tVM68k_ubyte byte; tVM68k_ubyte mask; treestart=offset+0; picstart=offset+SIZEOFTREE; // byte 0x240 in the tree is the escape symbol for the run level encoding escapechar=gfxbuf[treestart+0x240]; // bytes 0x04..0x23: RGB values for (i=0;i<16;i++) { pPicture->palette[i]=READ_INT16LE(gfxbuf,picstart+0x4+i*2); } // bytes 0x24,0x25= width // bytes 0x26,0x27= height pPicture->width=READ_INT16LE(gfxbuf,picstart+0x24); pPicture->height=READ_INT16LE(gfxbuf,picstart+0x26); // bytes 0x2a,0x2b= size of the bitstream (in bytes) size=READ_INT16LE(gfxbuf,picstart+0x2a); j=0; treeidx=0; mask=0; i=0; rlestate=0; repnum=1; // i is counting up the bytes in the bitstream. // j is counting up the pixels of the image while (((i<(length-SIZEOFTREE) && iwidth*pPicture->height)) { tVM68k_ubyte lterm,rterm,term; tVM68k_ubyte lbranch,rbranch,branch; // the bitmask is denoting (MSB first) if an entry is a terminal symbol (=1) or a branch (=0) lterm=gfxbuf[treestart+0x00 +treeidx/8]&(0x80>>(treeidx%8)); rterm=gfxbuf[treestart+0x120+treeidx/8]&(0x80>>(treeidx%8)); // the entry in the table could either be a branch or a terminal symbol lbranch=gfxbuf[treestart+0x20 +treeidx]; rbranch=gfxbuf[treestart+0x140+treeidx]; if (mask==0) { mask=0x80; byte=gfxbuf[picstart+i+0x2c]; i++; } term =(byte&mask)? rterm:lterm; branch=(byte&mask)?rbranch:lbranch; mask>>=1; if (term) { if (rlestate==0) { if (branch==escapechar) { rlestate=1; } else { repnum=1; } } else if (rlestate==1) { if (branch==0xff) { branch=escapechar; repnum=1; rlestate=0; } else { repnum=branch+4; // this form of RLE makes sense when the same byte was repeated 4 or more times in the source picture rlestate=2; } } else if (rlestate==2) { rlestate=0; // the current entry is a terminal symbol, which is going to be repeated } if (rlestate==0) { while (repnum && j<(pPicture->width*pPicture->height)) { // the lower 4 bits are the LEFT pixel pPicture->pixels[j]=branch&0xf; j++; // one byte holds two pixels. but when the width is not divisible by 2, drop the remaining nibble. if (j%pPicture->width) // the higher 4 bits are the RIGHT pixel; but only if it is not outside the scope of the image. { pPicture->pixels[j]=(branch>>4)&0xf; // the higher 4 bytes are the RIGHT pixel j++; } repnum--; } } treeidx=0; // go back to the start; } else { // not a terminal symbol. keep following the branches treeidx=branch; } } // the finishing touch: XOR each line with the previous one for (i=pPicture->width;iheight*pPicture->width;i++) { pPicture->pixels[i]^=pPicture->pixels[i-pPicture->width]; } } return retval; } int gfxloader_unpackpic(tVM68k_ubyte* gfxbuf,tVM68k_ulong gfxsize,tVM68k_ubyte version,int picnum,tVM68k_ubyte* picname,tPicture* pPicture,int egamode) { int retval; retval=0; if (gfxbuf==NULL || pPicture==NULL) return -1; if (gfxbuf[0]=='M' && gfxbuf[1]=='a' && gfxbuf[2]=='P' && gfxbuf[3]=='i') retval=gfxloader_gfx1(gfxbuf,gfxsize,version,picnum,pPicture); if (gfxbuf[0]=='M' && gfxbuf[1]=='a' && gfxbuf[2]=='P' && gfxbuf[3]=='2') retval=gfxloader_gfx2(gfxbuf,gfxsize,version,picname,pPicture); if (gfxbuf[0]=='M' && gfxbuf[1]=='a' && gfxbuf[2]=='P' && gfxbuf[3]=='3') retval=gfxloader_gfx3(gfxbuf,gfxsize,version,picnum,pPicture); if (gfxbuf[0]=='M' && gfxbuf[1]=='a' && gfxbuf[2]=='P' && gfxbuf[3]=='4') retval=gfxloader_gfx4(gfxbuf,gfxsize,version,picname,pPicture,egamode); return retval; } int gfxloader_picture_calcxpmsize(tPicture* pPicture,int* xpmsize) { int calcsize; if (pPicture==NULL || xpmsize==NULL) return -1; calcsize=345; // header of the xpm file, including the palette. calcsize+=pPicture->height*(pPicture->width+1+1+2)+3; // each line with the pixels starts and ends with "". in all but 1 cases, there is a ,\n at the end. the last line consists of a };\n\0. *xpmsize=calcsize; return 0; } int gfxloader_picture2xpm(tPicture* pPicture,char* xpm,int xpmspace) { int row; int col; int calcsize; int pixelidx; int xpmidx; int i; if (xpm==NULL) return -1; // invalid pointer if (gfxloader_picture_calcxpmsize(pPicture,&calcsize)) return -1; if (xpmspacewidth,pPicture->height); // the parameters xpmidx+=17; for (i=0;i<16;i++) { int red,green,blue; red=(pPicture->palette[i]>>8)&0xf; green=(pPicture->palette[i]>>4)&0xf; blue=(pPicture->palette[i]>>0)&0xf; snprintf(&xpm[xpmidx],19,"\"%c c #%02X%02X%02X\",\n",i+'A',red*0x20,green*0x20,blue*0x20); xpmidx+=15; } snprintf(&xpm[xpmidx],14,"/* pixels */\n"); xpmidx+=13; pixelidx=0; for (row=0;rowheight;row++) { xpm[xpmidx++]='"'; for (col=0;colwidth;col++) { xpm[xpmidx++]='A'+pPicture->pixels[pixelidx++]; } xpm[xpmidx++]='"'; if (row!=pPicture->height-1) xpm[xpmidx++]=','; xpm[xpmidx++]='\n'; } xpm[xpmidx++]='}';xpm[xpmidx++]=';';xpm[xpmidx++]='\n',xpm[xpmidx]=0; if (xpmidx>=xpmspace) { fprintf(stderr,"ERROR! POSSIBLE INTERNAL MEMORY VIOLATION DETECTED in gfxloader_picture2xpm\n"); } return 0; } dmagnetic-0.22/src/engine/linea/gfx1loader.h0000644000175000017500000000367113621220604020326 0ustar dettusdettus/* Copyright 2019, dettus@dettus.net Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef GFXLOADER_H #define GFXLOADER_H #include "vm68k_datatypes.h" #include "picture.h" // for the pPicture data type // this function is extracting the picture from the .gfx file and converts it into something easier to handle. int gfxloader_unpackpic(tVM68k_ubyte* gfxbuf,tVM68k_ulong gfxsize,tVM68k_ubyte version,int picnum,tVM68k_ubyte* picname,tPicture* pPicture,int egamode); // those function can convert the picture into an xpm. // this one calculates the space needed for the final picture int gfxloader_picture_calcxpmsize(tPicture* pPicture,int* xpmsize); // this one converts it. int gfxloader_picture2xpm(tPicture* pPicture,char* xpm,int xpmspace); #endif dmagnetic-0.22/build.sh0000644000175000017500000000247613621220604014432 0ustar dettusdettus#!/bin/sh #Copyright 2019, dettus@dettus.net # #Redistribution and use in source and binary forms, with or without modification, #are permitted provided that the following conditions are met: # #1. Redistributions of source code must retain the above copyright notice, this # list of conditions and the following disclaimer. # #2. Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. # #THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND #ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED #WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE #DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE #FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL #DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR #SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER #CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, #OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE #OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. make clean all