├── .clang-format ├── .clangd ├── .editorconfig ├── .exrc ├── .gitattributes ├── .github └── workflows │ ├── README.md │ ├── build-push.yml │ ├── build-tag.yml │ └── ci-pr.yml ├── .gitignore ├── .gitmodules ├── BOOT.test ├── CHANGELOG.md ├── CMakeLists.txt ├── COPYRIGHT ├── Init.c ├── Makefile ├── QDOS.h ├── QDOS_driver_ip.h ├── QDisk.c ├── QDisk.h ├── QFilesPriv.h ├── QInstAddr.h ├── QL.h ├── QL68000.h ├── QL_basext.c ├── QL_basext.h ├── QL_boot.c ├── QL_cconv.c ├── QL_cconv.h ├── QL_config.c ├── QL_config.h ├── QL_driver.c ├── QL_driver.h ├── QL_files.c ├── QL_files.h ├── QL_hardware.c ├── QL_hardware.h ├── QL_poll.c ├── QL_poll.h ├── QL_screen.c ├── QL_screen.h ├── QL_serial.c ├── QL_sound.c ├── QL_sound.h ├── QLfiles.h ├── QLip.c ├── QLip.h ├── QLserio.c ├── QLserio.h ├── QLtraps.c ├── QLtraps.h ├── QSerial.h ├── QSound.h ├── QVFS.c ├── QVFS.h ├── README.md ├── Toolchain-arm64.cmake ├── Toolchain-armhf.cmake ├── Toolchain-cross-m32.cmake ├── Toolchain-mingw-w64-i686.cmake ├── Toolchain-mingw-w64-x86_64.cmake ├── Xscreen.c ├── Xscreen.h ├── boot.h ├── build-wasm.sh ├── build └── .gitkeep ├── cond.h ├── deploy-wasm.sh ├── docker ├── Docker.md ├── Dockerfile └── build-sqlux-release.sh ├── docs ├── shaders.md ├── socket.md ├── sqlux-patchpoints.md └── sqlux.md ├── driver.h ├── dummies.c ├── dummies.h ├── emudisk.h ├── examples ├── mdv1 │ ├── BOOT │ └── TK232_net.bin ├── mdv2 │ ├── PTY_TEST_BAS │ ├── rotate_asm │ ├── rotate_bas │ └── rotate_code ├── mdv3 │ ├── BOOT │ ├── QLMIRES_Txt │ ├── QLMIRES_bas │ ├── QLMIRES_doc │ └── testcard_bas └── sqlux.ini ├── general.c ├── general.h ├── generate_version.cmake ├── hexdump.c ├── iexl.h ├── iexl_general.c ├── iexl_general.h ├── include ├── GPUshaders.h ├── SDL2screen.h ├── debug.h ├── emulator_init.h ├── emulator_options.h ├── q-emulator.h ├── qdos-file-header.h ├── qlkeys.h ├── sqlux_debug.h ├── sqlux_windows.h ├── version.h └── wasm_support.h ├── instructions.h ├── instructions_ao.c ├── instructions_pz.c ├── iptraps.h ├── memaccess.c ├── memaccess.h ├── mmodes.c ├── mmodes.h ├── pty.c ├── qlmouse.h ├── qmtrap.c ├── qmtrap.h ├── roms ├── Minerva_1.98a1.bin ├── Minerva_1g98a1.bin ├── TK232.rom └── TK236.rom ├── sQLuxLogo.ico ├── sQLuxLogo.png ├── sQLuxLogo.rc ├── shaders └── crt-pi.glsl ├── sqlux_bdi.c ├── sqlux_bdi.h ├── sqlux_wasm.ini ├── sqlux_wrapper_sample.html ├── src ├── GPUshaders.c ├── SDL2main.c ├── SDL2screen.c ├── emulator_init.c ├── emulator_options.c ├── filemap ├── sqlux_hexdump.c ├── sqlux_windows.c └── wasm_support.c ├── trace.c ├── trace.h ├── unix.h ├── unixstuff.c ├── unixstuff.h ├── util.c ├── util.h ├── uxfile.c ├── uxfile.h ├── version.c.in ├── x86_32.cmake ├── xc68.c ├── xc68.h ├── xcodes.c ├── xcodes.h ├── xqlmouse.c └── xqlmouse.h /.clang-format: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0 2 | # 3 | # clang-format configuration file. Intended for clang-format >= 4. 4 | # 5 | # For more information, see: 6 | # 7 | # Documentation/process/clang-format.rst 8 | # https://clang.llvm.org/docs/ClangFormat.html 9 | # https://clang.llvm.org/docs/ClangFormatStyleOptions.html 10 | # 11 | --- 12 | AccessModifierOffset: -4 13 | AlignAfterOpenBracket: Align 14 | AlignConsecutiveAssignments: false 15 | AlignConsecutiveDeclarations: false 16 | #AlignEscapedNewlines: Left # Unknown to clang-format-4.0 17 | AlignOperands: true 18 | AlignTrailingComments: false 19 | AllowAllParametersOfDeclarationOnNextLine: false 20 | AllowShortBlocksOnASingleLine: false 21 | AllowShortCaseLabelsOnASingleLine: false 22 | AllowShortFunctionsOnASingleLine: None 23 | AllowShortIfStatementsOnASingleLine: false 24 | AllowShortLoopsOnASingleLine: false 25 | AlwaysBreakAfterDefinitionReturnType: None 26 | AlwaysBreakAfterReturnType: None 27 | AlwaysBreakBeforeMultilineStrings: false 28 | AlwaysBreakTemplateDeclarations: false 29 | BinPackArguments: true 30 | BinPackParameters: true 31 | BraceWrapping: 32 | AfterClass: false 33 | AfterControlStatement: false 34 | AfterEnum: false 35 | AfterFunction: true 36 | AfterNamespace: true 37 | AfterObjCDeclaration: false 38 | AfterStruct: false 39 | AfterUnion: false 40 | #AfterExternBlock: false # Unknown to clang-format-5.0 41 | BeforeCatch: false 42 | BeforeElse: false 43 | IndentBraces: false 44 | #SplitEmptyFunction: true # Unknown to clang-format-4.0 45 | #SplitEmptyRecord: true # Unknown to clang-format-4.0 46 | #SplitEmptyNamespace: true # Unknown to clang-format-4.0 47 | BreakBeforeBinaryOperators: None 48 | BreakBeforeBraces: Custom 49 | #BreakBeforeInheritanceComma: false # Unknown to clang-format-4.0 50 | BreakBeforeTernaryOperators: false 51 | BreakConstructorInitializersBeforeComma: false 52 | #BreakConstructorInitializers: BeforeComma # Unknown to clang-format-4.0 53 | BreakAfterJavaFieldAnnotations: false 54 | BreakStringLiterals: false 55 | ColumnLimit: 80 56 | CommentPragmas: '^ IWYU pragma:' 57 | #CompactNamespaces: false # Unknown to clang-format-4.0 58 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 59 | ConstructorInitializerIndentWidth: 8 60 | ContinuationIndentWidth: 8 61 | Cpp11BracedListStyle: false 62 | DerivePointerAlignment: false 63 | DisableFormat: false 64 | ExperimentalAutoDetectBinPacking: false 65 | #FixNamespaceComments: false # Unknown to clang-format-4.0 66 | 67 | #IncludeBlocks: Preserve # Unknown to clang-format-5.0 68 | IncludeCategories: 69 | - Regex: '.*' 70 | Priority: 1 71 | IncludeIsMainRegex: '(Test)?$' 72 | IndentCaseLabels: false 73 | #IndentPPDirectives: None # Unknown to clang-format-5.0 74 | IndentWidth: 8 75 | IndentWrappedFunctionNames: false 76 | JavaScriptQuotes: Leave 77 | JavaScriptWrapImports: true 78 | KeepEmptyLinesAtTheStartOfBlocks: false 79 | MacroBlockBegin: '' 80 | MacroBlockEnd: '' 81 | MaxEmptyLinesToKeep: 1 82 | NamespaceIndentation: None 83 | #ObjCBinPackProtocolList: Auto # Unknown to clang-format-5.0 84 | ObjCBlockIndentWidth: 8 85 | ObjCSpaceAfterProperty: true 86 | ObjCSpaceBeforeProtocolList: true 87 | 88 | # Taken from git's rules 89 | #PenaltyBreakAssignment: 10 # Unknown to clang-format-4.0 90 | PenaltyBreakBeforeFirstCallParameter: 30 91 | PenaltyBreakComment: 10 92 | PenaltyBreakFirstLessLess: 0 93 | PenaltyBreakString: 10 94 | PenaltyExcessCharacter: 100 95 | PenaltyReturnTypeOnItsOwnLine: 60 96 | 97 | PointerAlignment: Right 98 | ReflowComments: false 99 | SortIncludes: false 100 | #SortUsingDeclarations: false # Unknown to clang-format-4.0 101 | SpaceAfterCStyleCast: false 102 | SpaceAfterTemplateKeyword: true 103 | SpaceBeforeAssignmentOperators: true 104 | #SpaceBeforeCtorInitializerColon: true # Unknown to clang-format-5.0 105 | #SpaceBeforeInheritanceColon: true # Unknown to clang-format-5.0 106 | SpaceBeforeParens: ControlStatements 107 | #SpaceBeforeRangeBasedForLoopColon: true # Unknown to clang-format-5.0 108 | SpaceInEmptyParentheses: false 109 | SpacesBeforeTrailingComments: 1 110 | SpacesInAngles: false 111 | SpacesInContainerLiterals: false 112 | SpacesInCStyleCastParentheses: false 113 | SpacesInParentheses: false 114 | SpacesInSquareBrackets: false 115 | Standard: Cpp03 116 | TabWidth: 8 117 | UseTab: Always 118 | ... 119 | -------------------------------------------------------------------------------- /.clangd: -------------------------------------------------------------------------------- 1 | CompileFlags: 2 | CompilationDatabase: build/ # Search build/ directory for compile_commands.json 3 | Add: -ferror-limit=0 4 | 5 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # top-most EditorConfig file 2 | root = true 3 | 4 | # Unix-style newlines with a newline ending every file 5 | [*] 6 | end_of_line = lf 7 | insert_final_newline = true 8 | 9 | # Tab indentation (no size specified) 10 | [*.{c,h}] 11 | indent_style = tab 12 | indent_size = 8 13 | 14 | # 4 space indentation 15 | [*.md] 16 | indent_style = space 17 | indent_size = 4 18 | -------------------------------------------------------------------------------- /.exrc: -------------------------------------------------------------------------------- 1 | set expandtab 2 | set shiftwidth=4 3 | set smarttab 4 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto eol=lf 2 | -------------------------------------------------------------------------------- /.github/workflows/README.md: -------------------------------------------------------------------------------- 1 | # Github workflows 2 | 3 | ## Workflow job descriptions 4 | 5 | ### List of jobs: 6 | - Prepare build definitions 7 | - build_x86_64 8 | - build_arm 9 | - build_macos 10 | - build_windows 11 | 12 | ### Description of jobs: 13 | 14 | 1. `build_x86_64` 15 | 16 | - Builds on Ubuntu 22.04 "Jammy" (x86_64) 17 | - Tested on an Intel desktop w/ Ubuntu 22.04.03 LTS 18 | 19 | 2. `build_arm` 20 | 21 | Builds against `arm` architectures, by way of cross-compiling on: 22 | 23 | - aarch64 24 | - Ubuntu 22.04 "Jammy" 25 | - armv7 26 | - Ubuntu 22.04 "Jammy" 27 | - Debian 11 "Bullseye" 28 | - Debian 10 "Buster" 29 | 30 | 31 | 3. `build_macos` 32 | 33 | It's not fully documented which are the available runners archs... 34 | 35 | https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners/about-github-hosted-runners#supported-runners-and-hardware-resources 36 | 37 | - runs on `macos-12`, which is, in today's commit date, an intel machine, as it can be seen in the runner logs: 38 | 39 | ``` 40 | machdep.cpu.brand_string: Intel(R) Core(TM) i7-8700B CPU @ 3.20GHz 41 | ``` 42 | 43 | 4. `build_windows` 44 | 45 | Builds on Windows x86_64 image, with MSYS2 dev tools 46 | 47 | Crossbuilds: 48 | - mingw64 : x86_64 libraries 49 | - mingw32 : i686 libraries 50 | 51 | 52 | 53 | ## Workflow local tests with `act` 54 | 55 | https://github.com/nektos/act 56 | 57 | Local testing saves runner times on Github.com, though builds are working only for some architecture... 58 | 59 | Anyhow `act` can be useful to test parts of the workflow, saving commit/push/wait-for-runners time. 60 | 61 | The workflow is configurable with variables, so the workflow developer can concentrate on particular features. 62 | 63 | ### 1 - configure `act` using local github env 64 | 65 | ```sh 66 | cat > ~/sQLux.events.json < 6 | 7 | #pragma pack(push,1) 8 | 9 | struct ql_sockaddr { 10 | uint16_t sa_family; /* address family */ 11 | uint8_t sa_data[14]; 12 | }; 13 | 14 | struct ql_in_addr { 15 | uint32_t ql_s_addr; 16 | }; 17 | 18 | struct ql_sockaddr_in { 19 | uint16_t sin_family; 20 | uint16_t sin_port; 21 | struct ql_in_addr sin_addr; 22 | uint8_t sin_zero[8]; 23 | }; 24 | 25 | struct ql_sockproto { 26 | uint16_t sp_family; /* address family */ 27 | uint16_t sp_protocol; /* protocol */ 28 | }; 29 | 30 | struct ql_hostent { 31 | uint32_t h_name; /* official name of host */ 32 | uint32_t h_aliases; /* alias list */ 33 | int32_t h_addrtype; /* host address type */ 34 | int32_t h_length; /* length of address */ 35 | uint32_t h_addr_list; /* list of addresses from name server */ 36 | #define ql_h_addr h_addr_list[0] /* address, for backward compatiblity */ 37 | }; 38 | 39 | #pragma pack(pop) 40 | 41 | #endif /* QL_SOCKET_H */ 42 | -------------------------------------------------------------------------------- /QDisk.h: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) UQLX - see COPYRIGHT 3 | */ 4 | 5 | #ifndef QDISK_H 6 | #define QDISK_H 7 | 8 | #define ERR_UNINITIALIZED_DISK -9810 9 | #define ERR_NO_FILE_BLOCK -9811 10 | 11 | #include "QFilesPriv.h" 12 | 13 | OSErr AllocateDisk(int); 14 | void DeallocateDisk(void); 15 | void QDiskFlush(void); 16 | Cond QDiskPresent(void); 17 | OSErr QDiskEject(void); 18 | void TestCloseDevs(); 19 | OSErr KillFileTail(FileNum fileNum, int nBlock); 20 | void RewriteHeader(void); 21 | 22 | #endif /* QDISK_H */ 23 | -------------------------------------------------------------------------------- /QFilesPriv.h: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) UQLX - see COPYRIGHT 3 | */ 4 | 5 | #ifndef QFPH 6 | #define QFPH 7 | 8 | #define rOpenFiles 133 9 | #define SOFT_ERROR -9845 10 | #define DEMO_ERROR -9846 11 | 12 | 13 | /* it would be so easy to use this struct ..*/ 14 | #if 0 15 | #pragma options align=mac68k 16 | struct mdvFile { 17 | w16 fNumber; 18 | w32 pos; 19 | w32 eof; 20 | w32 slave; 21 | char boh[6]; 22 | unsigned char name[38]; 23 | struct mdvFile *next; 24 | short vol; 25 | long dir; 26 | short ref; 27 | short key; 28 | short drive; 29 | Cond isDirectory; /* dirs can't be written !! */ 30 | Cond open; 31 | Cond qlDisk; 32 | long id; /* to detect overwritten file block */ 33 | }; 34 | #else 35 | struct mdvFile{ char dummy[130];}; 36 | #endif 37 | 38 | /* unfortunately it gets packed differently on many systems so we need 39 | assembler style offstes instead */ 40 | 41 | #define PACKED __attribute__ ((packed)) 42 | 43 | typedef struct { 44 | int dir PACKED; /* file number of (parent) direcory */ 45 | int file PACKED; 46 | int entrynum PACKED; /* number of entry in directory */ 47 | 48 | }FileNum; 49 | 50 | struct fileHeader *GetFileHeader(FileNum fileNum); 51 | 52 | #define _QLF_fNumber 0 53 | #define _QLF_pos 2 54 | #define _QLF_eof 6 55 | #define _QLF_slave 10 56 | #define _QLF_name 20 57 | #define _QLF_next (20+38) 58 | #define _QLF_vol (_QLF_next+4) 59 | #define _QLF_dir (_QLF_vol+2) 60 | #define _QLF_ref (_QLF_dir+4) /* abuse this field to hold update status */ 61 | #define _QLF_key (_QLF_ref+4) 62 | #define _QLF_drive (_QLF_key+2) 63 | #define _QLF_isdir (_QLF_drive+2) 64 | #define _QLF_open (_QLF_isdir+2) 65 | #define _QLF_qlDisk (_QLF_open+2) 66 | #define _QLF_id (_QLF_qlDisk+2) 67 | #define _QLF_filesys (_QLF_id+4) 68 | #define _QLF_hfileref (_QLF_filesys+4) 69 | /*#define _nfn (_hfileref+4)*/ 70 | #define _QLF_hf_fcb (_QLF_hfileref+4) /* sizeof == 8 !!*/ 71 | #define _QLF_seekbase (_QLF_hf_fcb+8) 72 | #define mdvFile_len (_QLF_seekbase+2) 73 | 74 | /* Macros needed to avoid alignment errors on certain architectures */ 75 | #if 0 76 | #define SET_FNUMBER(_mdvf_,_num_) (WW((Ptr)((Ptr)(_mdvf_)+_fNumber),(_num_))) 77 | #define GET_FNUMBER(_mdvf_) (RW((Ptr)((Ptr)(_mdvf_)+_fNumber))) 78 | #else 79 | #if 0 80 | #define SET_FNUMBER(_mdvf_,_num_) (*(FileNum*)((Ptr)(_mdvf_)+_nfn)=(_num_)) 81 | #define GET_FNUMBER(_mdvf_) (*(FileNum*)((Ptr)(_mdvf_)+_nfn)) 82 | #endif 83 | #endif 84 | 85 | #define SET_POS(_mdvf_,_pos_) (WL((Ptr)((Ptr)(_mdvf_)+_QLF_pos),(_pos_))) 86 | #define GET_POS(_mdvf_) (RL((Ptr)((Ptr)(_mdvf_)+_QLF_pos))) 87 | #define SET_EOF(_mdvf_,_pos_) (WL((Ptr)((Ptr)(_mdvf_)+_QLF_eof),(_pos_))) 88 | #define GET_EOF(_mdvf_) (RL((Ptr)((Ptr)(_mdvf_)+_QLF_eof))) 89 | #define SET_REF(_mdvf_,_ref_) (WL((Ptr)((Ptr)(_mdvf_)+_QLF_ref),(_ref_))) 90 | #define GET_REF(_mdvf_) (RL((Ptr)((Ptr)(_mdvf_)+_QLF_ref))) 91 | 92 | static inline void SET_NEXT(struct mdvFile *_mdvf_, struct mdvFile *_nxt_) { 93 | if (!_nxt_) { 94 | WL((Ptr)((Ptr)(_mdvf_)+_QLF_next),0); 95 | } else { 96 | WL((Ptr)((Ptr)(_mdvf_)+_QLF_next),(w32)((uintptr_t)_nxt_-(uintptr_t)memBase)); 97 | } 98 | } 99 | static inline struct mdvFile *GET_NEXT(struct mdvFile *_mdvf_) { 100 | uintptr_t val; 101 | 102 | val = RL((Ptr)((Ptr)(_mdvf_)+_QLF_next)); 103 | if(val) 104 | val += (uintptr_t)memBase; 105 | 106 | return (struct mdvFile *)val; 107 | } 108 | 109 | #define SET_ID(_mdvf_,_id_) (WL((Ptr)((Ptr)(_mdvf_)+_QLF_id),(_id_))) 110 | #define GET_ID(_mdvf_) (RL((Ptr)((Ptr)(_mdvf_)+_QLF_id))) 111 | #define GET_OPEN(_mdvf_) (RW((Ptr)((Ptr)(_mdvf_)+_QLF_open))) 112 | #define SET_OPEN(_mdvf_,_val_) (WW((Ptr)((Ptr)(_mdvf_)+_QLF_open),(_val_))) 113 | #define GET_DRIVE(_mdvf_) (RW((Ptr)((Ptr)(_mdvf_)+_QLF_drive))) 114 | #define GET_ISDIR(_mdvf_) (RW((Ptr)((Ptr)(_mdvf_)+_QLF_isdir))) 115 | #define GET_ISDISK(_mdvf_) (RW((Ptr)((Ptr)(_mdvf_)+_QLF_qlDisk))) 116 | #define NAME_REF(_mdvf_) ((char *)(Ptr)(_mdvf_)+_QLF_name) 117 | #define GET_KEY(_mdvf_) ((w16)RW((Ptr)((Ptr)(_mdvf_)+_QLF_key))) 118 | #define SET_DRIVE(_mdvf_,_drv_) (WW((Ptr)((Ptr)(_mdvf_)+_QLF_drive),(_drv_))) 119 | #define SET_ISDIR(_mdvf_,_val_) (WW((Ptr)((Ptr)(_mdvf_)+_QLF_isdir),(_val_))) 120 | #define SET_ISDISK(_mdvf_,_val_) (WW((Ptr)((Ptr)(_mdvf_)+_QLF_qlDisk),(_val_))) 121 | #define SET_KEY(_mdvf_,_val_) (WW((Ptr)((Ptr)(_mdvf_)+_QLF_key),(_val_))) 122 | #define GET_FILESYS(_mdvf_) ((w32)(RL((Ptr)((Ptr)(_mdvf_)+_QLF_filesys)))) 123 | #define SET_FILESYS(_mdvf_,_val_) (WL((Ptr)((Ptr)(_mdvf_)+_QLF_filesys),(_val_))) 124 | #define GET_HFILE(_mdvf_) ((RL((Ptr)((Ptr)(_mdvf_)+_QLF_hfileref)))) 125 | #define SET_HFILE(_mdvf_,_val_) (WL((Ptr)((Ptr)(_mdvf_)+_QLF_hfileref),(_val_))) 126 | #define SET_SEEKBASE(_mdvf_,_val_) (WW((Ptr)((Ptr)(_mdvf_)+_QLF_seekbase),(_val_))) 127 | #define GET_SEEKBASE(_mdvf_) (RW((Ptr)((Ptr)(_mdvf_)+_QLF_seekbase))) 128 | 129 | #define GET_FCB(_mdvf_) ((struct HF_FCB *)(GET_POINTER((Ptr)(_mdvf_) + _QLF_hf_fcb))) 130 | /*(RL((Ptr)((Ptr)(_mdvf_)+_hf_fcb))))*/ 131 | #define SET_FCB(_mdvf_,_val_) SET_POINTER((Ptr)(_mdvf_)+_QLF_hf_fcb,(_val_)) 132 | /*(WL((Ptr)((Ptr)(_mdvf_)+_hf_fcb),(_val_)))*/ 133 | 134 | #define SET_FNUMBER(_mxdvf_,_num_) (GET_FCB(_mxdvf_)->fileNum=_num_) 135 | #define GET_FNUMBER(_mxdvf_) (GET_FCB(_mxdvf_)->fileNum) 136 | 137 | 138 | /* the addr of this struct is accessed by GET_FCB(f) */ 139 | /* most of the attribs now stored in mdvFile should go into it */ 140 | struct HF_FCB 141 | { 142 | struct HF_FCB *next; 143 | int mode; 144 | FileNum fileNum; /* DiskOp only */ 145 | /* %--------------% */ 146 | char uxname[4096]; /* must be last and unpadded in this struct for QVFS */ 147 | }; 148 | 149 | 150 | #if 0 151 | struct fileHeader{ 152 | w32 len; 153 | w8 access; 154 | w8 type; 155 | w32 info1; 156 | w32 info2; 157 | unsigned char name[38]; 158 | w32 date_update; 159 | w32 date_ref; 160 | w32 date_backup; 161 | }; 162 | #else 163 | struct fileHeader { char xx[64];}; 164 | #endif 165 | 166 | #define _flen 0 167 | #define _facc 4 168 | #define _ftyp 5 169 | #define _finf1 6 170 | #define _finf2 10 171 | #define _fname 14 172 | #define _fdupdt (0x34) 173 | /*#define _fdref (_0x3c)*/ 174 | #define _fdtbak (0x3c) 175 | #define _fdvers 0x38 176 | 177 | #define SET_FLEN(_fh_,_len_) (WL((Ptr)_fh_,_len_)) 178 | #define GET_FLEN(_fh_) (RL((Ptr)_fh_)) 179 | #define SET_FACC(_fh_,_len_) (WB((Ptr)_fh_+_facc,_len_)) 180 | #define GET_FACC(_fh_) (RB((Ptr)_fh_+_facc)) 181 | #define SET_FTYP(_fh_,_len_) (WB((Ptr)_fh_+_ftyp,_len_)) 182 | #define GET_FTYP(_fh_) (RB((Ptr)_fh_+_ftyp)) 183 | #define REF_FNAME(_fh_) ((char *)((char *)(_fh_)+_fname)) 184 | #define SET_FDUPDT(_fh_,_tme_) (WL((Ptr)_fh_+_fdupdt,_tme_)) 185 | #define SET_FDTBAC(_fh_,_tme_) (WL((Ptr)_fh_+_fdtbak,_tme_)) 186 | 187 | #define SET_FVER(_fh_,_tme_) (WW((Ptr)_fh_+_fdvers,_tme_)) 188 | #define GET_FVER(_fh_) (RW((Ptr)_fh_+_fdvers)) 189 | 190 | #define GET_FDUPDT(_fh_) (RL((Ptr)_fh_+_fdupdt)) 191 | #define GET_FDTBAC(_fh_) (RL((Ptr)_fh_+_fdtbak)) 192 | 193 | typedef char Str255[256]; 194 | 195 | 196 | extern unsigned char mdvHeaders[]; 197 | extern short mdvOn; 198 | 199 | void CloseAllMdvFiles(short,int); 200 | void StopMotor(void); 201 | Cond FileAlreadyOpen(short,int,FileNum,w16 *); 202 | void FilenameFromQL(unsigned char *); 203 | void GetWDparms(short,short *,long *); 204 | OSErr GetDirName(Str255,short,long); 205 | 206 | OSErr QDiskDelete(struct mdvFile*); 207 | OSErr QDiskOpen(struct mdvFile*,int ,Cond, Cond); 208 | void QDiskClose(struct mdvFile*); 209 | w32 QDiskLen(struct mdvFile*); 210 | OSErr QDiskIO(struct mdvFile*,short); 211 | void QDiskFormat(uw8*,long*,long*); 212 | 213 | void AdjustSetDirMenu(void); 214 | void InitFileDrivers(void); 215 | w32 PhysicalDefBlock(void); 216 | 217 | 218 | void QHDeleteHeader(char *,int , char *, struct mdvFile *, int); 219 | int HDelete(int , int , unsigned char *, struct mdvFile *, int); 220 | int HOpenDF(int , long ,unsigned char *, long, struct mdvFile *, int, int); 221 | int QHOpenDir(struct mdvFile *, int); 222 | int HCreate(struct mdvFile *, unsigned char *, unsigned char *, unsigned char *, int); 223 | int HDfLen(struct mdvFile *, int); 224 | int QHostIO(struct mdvFile *, int, int ); 225 | 226 | #endif 227 | -------------------------------------------------------------------------------- /QInstAddr.h: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) UQLX - see COPYRIGHT 3 | */ 4 | 5 | void UseIPC(void); 6 | void ReadIPC(void); 7 | void WriteIPC(void); 8 | void QL_KeyTrans(void); 9 | 10 | void ReadMdvSector(void); 11 | void WriteMdvSector(void); 12 | void VerifyMdvSector(void); 13 | void ReadMdvHeader(void); 14 | 15 | void FastStartup(void); 16 | void MdvIO(void); 17 | void MdvOpen(void); 18 | void MdvClose(void); 19 | void MdvSlaving(void); 20 | void MdvFormat(void); 21 | void ScrIO(void); 22 | 23 | void SerIO(void); 24 | void SerOpen(void); 25 | void SerClose(void); 26 | -------------------------------------------------------------------------------- /QL.h: -------------------------------------------------------------------------------- 1 | #ifndef QL_H 2 | #define QL_H 3 | /* 4 | * (c) UQLX - see COPYRIGHT 5 | */ 6 | 7 | 8 | 9 | #define rFormat 136 10 | #define rPat 129 11 | #define mRam 140 12 | #define mKey 144 13 | 14 | 15 | #define ERR_MEMORY -9600 16 | #define ERR_ROM -9601 17 | #define ERR_TIME -9602 18 | #define ERR_DISKROM -9603 19 | #define ERR_RESSIZE -9604 20 | #define ERR_OLD_SYSTEM -9606 21 | #define ERR_GENERIC -9608 22 | #define ERR_ROM_UNKNOWN -9611 23 | 24 | extern Ptr theBuffer; 25 | /* extern WindowPtr theScreenWindow; */ 26 | /* extern WindowPtr regWindow; */ 27 | /* extern WindowPtr mdvWindow; */ 28 | extern long nChunk; 29 | extern Cond qlRunning; 30 | 31 | void ExecuteChunk(long); 32 | void RefreshDisplay(void); 33 | //void FlushDisplay(void); /* Now in QL_screen.h */ 34 | /*void UpdateDisplay(Rect*,Boolean); */ 35 | void DisplayIsValid(void); 36 | void DrawRegisters(void); 37 | void DrawMdv(void); 38 | void DoQLkey(char,short,short); 39 | void CheckCapsLock(short); 40 | void CloseAllFiles(void); 41 | /*void InvalWindow(WindowPtr);*/ 42 | void AttachDirectory(short,Cond,short,long); 43 | 44 | #endif -------------------------------------------------------------------------------- /QL_basext.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef QL_BASEXT_H 4 | #define QL_BASEXT_H 5 | 6 | void init_bas_exts(void); 7 | 8 | #endif 9 | 10 | -------------------------------------------------------------------------------- /QL_boot.c: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) UQLX - see COPYRIGHT 3 | */ 4 | 5 | /*#include "QLtypes.h"*/ 6 | #include "QL68000.h" 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include "QL.h" 19 | #include "QLfiles.h" 20 | #include "QFilesPriv.h" 21 | #include "QInstAddr.h" 22 | #include "QDisk.h" 23 | #include "QL_driver.h" 24 | #include "unix.h" 25 | 26 | #include "driver.h" 27 | #include "QDOS.h" 28 | 29 | /* emulate BOOT device */ 30 | /* take input from string, file or stdin */ 31 | /* determined by ux_boot & ux_bname */ 32 | /* 0: no BOOT device */ 33 | /* 1: ux_bfd is file handle */ 34 | /* 2: ux_bname is command string */ 35 | 36 | int boot_init(int, void *); 37 | int boot_open(int, void **); 38 | int boot_test(int, char *); 39 | void boot_close(int, void *); 40 | void boot_io(int, void *); 41 | 42 | extern int ux_boot, ux_bfd; 43 | extern char *ux_bname; 44 | 45 | #define min(_xx_, _yy_) (_xx_ < _yy_ ? _xx_ : _yy_) 46 | 47 | struct BOOT_PRIV { 48 | int fd; 49 | char *str_p; 50 | int (*read)(); 51 | int (*write)(); 52 | int (*pend)(); 53 | 54 | int bfc_valid; 55 | char bfc; 56 | }; 57 | 58 | int boot_write() 59 | { 60 | return QERR_RO; 61 | } 62 | 63 | int u_pend(struct BOOT_PRIV *p) 64 | { 65 | int res; 66 | 67 | if (p->bfc_valid) 68 | return 0; 69 | 70 | res = read(p->fd, &(p->bfc), 1); 71 | if (res == 1) { 72 | p->bfc_valid = 1; 73 | return 0; 74 | } 75 | return QERR_EF; 76 | } 77 | 78 | int str_pend(struct BOOT_PRIV *p) 79 | { 80 | if (*(p->str_p)) 81 | return 0; 82 | else 83 | return QERR_EF; 84 | } 85 | 86 | int str_read(struct BOOT_PRIV *p, void *buf, int pno) 87 | { 88 | long count; 89 | 90 | if (/*pno>0 &&*/ *(p->str_p) == 0 || pno == 0) 91 | return 0; 92 | 93 | count = min(pno, strlen(p->str_p)); 94 | 95 | strncpy(buf, p->str_p, count); 96 | p->str_p += count; 97 | 98 | return count; 99 | } 100 | 101 | int u_read(struct BOOT_PRIV *p, void *buf, int pno) 102 | { 103 | long count, ci, res; 104 | char *c = buf; 105 | 106 | count = pno; 107 | 108 | if (p->bfc_valid) { 109 | *c++ = p->bfc; 110 | p->bfc_valid = 0; 111 | count--; 112 | ci = 1; 113 | } 114 | 115 | res = read(p->fd, c, count); 116 | 117 | if (res >= 0) 118 | return res + ci; 119 | else 120 | return qmaperr(); 121 | } 122 | 123 | int boot_init(int idx, void * ignored) 124 | { 125 | return 0; 126 | } 127 | 128 | open_arg boot_par; /* dummy */ 129 | int boot_test(int id, char *name) 130 | { 131 | if (ux_boot == 1 || ux_boot == 2) 132 | return decode_name(name, Drivers[id].namep, &boot_par); 133 | else 134 | return 0; 135 | } 136 | 137 | int boot_open(int id, void **priv) 138 | { 139 | struct BOOT_PRIV *p; 140 | 141 | *priv = p = malloc(sizeof(struct BOOT_PRIV)); 142 | if (ux_boot == 1) { 143 | p->fd = ux_bfd; 144 | p->pend = u_pend; 145 | p->read = u_read; 146 | p->write = boot_write; 147 | } else { 148 | p->str_p = ux_bname; 149 | p->pend = str_pend; 150 | p->read = str_read; 151 | p->write = boot_write; 152 | } 153 | 154 | return 0; 155 | } 156 | 157 | void boot_close(int id, void *priv) 158 | { 159 | if (priv) 160 | free(priv); 161 | } 162 | 163 | void boot_io(int id, void *priv) 164 | { 165 | struct BOOT_PRIV *p = priv; 166 | 167 | io_handle(p->read, p->write, p->pend, p); 168 | } 169 | -------------------------------------------------------------------------------- /QL_cconv.c: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) UQLX - see COPYRIGHT 3 | */ 4 | 5 | #include "QL68000.h" 6 | 7 | #include 8 | #include 9 | #include "QL_config.h" 10 | #include "QInstAddr.h" 11 | 12 | /* converts buffer using QDOS tra table, dest must have sufficient length! */ 13 | /* TRA table structure, from PiQ: 14 | basis 0000 $4AFB Konventionszahl 15 | 0002 liste1-basis Ofs zu den Einzelzeichen : liste1-* oder 0 ?!! 16 | 0004 liste2-basis Ofs zu den Zeichengruppen : liste2-* !! 17 | liste1 0006 zeichen.00 Code f�r CHR$(0) 18 | 0007 zeichen.01 Code f�r CHR$(1) 19 | ... bis CHR$(255) 20 | liste2 0000 anzahl.gruppen Byte, ggf. Null 21 | 0001 zeichen.x0 erste zu ersetzende Nummer 22 | 0002 ausgabe.x0.1 bis zu drei Zeichen, die 23 | stattdessen gesendet werden; 24 | auf Viererposten mit Null aufgef�llt. 25 | 0005 zeichen.x1 n�chste zu ersetzende Nummer, 26 | wie oben 27 | ... etc. ... 28 | xxxx zeichen.nn bis alle mit Null markierten Zeichen der ersten 29 | Anordnung definiert sind. 30 | */ 31 | 32 | int tra_conv(char *dest, char *src, int len) 33 | { 34 | uw32 tratab; 35 | uw32 tab1, tab2, tab2cnt, tab2data; 36 | char *pd, *ps, c; 37 | 38 | if (len == 0) 39 | return 0; 40 | 41 | tratab = ReadLong(0x28146); 42 | 43 | if (tratab == 0) { 44 | memcpy(dest, src, len); 45 | return len; 46 | } 47 | 48 | if (ReadWord(tratab) != 0x4afb) { 49 | printf("illegal TRA table %x!\n", tratab); 50 | memcpy(dest, src, len); 51 | return len; 52 | } 53 | 54 | if (ReadWord(tratab + 2) == 0) /* minerva specialitaet ? */ 55 | { 56 | memcpy(dest, src, len); 57 | return len; 58 | } 59 | 60 | tab1 = ReadWord(tratab + 2) + tratab + 2; 61 | tab2 = ReadWord(tratab + 4) + tratab + 4; 62 | tab2cnt = ReadByte(tab2); 63 | tab2data = tab2 + 1; 64 | 65 | for (pd = dest, ps = src; len-- > 0; ps++) { 66 | if ((c = ReadByte(tab1 + *ps))) 67 | *pd++ = c; 68 | else /* the complicated case .. */ 69 | { 70 | int i = 0; 71 | while (i++ < tab2cnt) { 72 | if (c == ReadByte(tab2data + 4 * i)) { 73 | *pd++ = ReadByte(tab2data + 4 * i + 1); 74 | if (ReadByte(tab2data + 4 * i + 2)) { 75 | *pd++ = ReadByte(tab2data + 76 | 4 * i + 2); 77 | if (ReadByte(tab2data + 4 * i + 78 | 3)) 79 | *pd++ = ReadByte( 80 | tab2data + 81 | 4 * i + 3); 82 | } 83 | } 84 | } 85 | if (i == tab2cnt) { 86 | printf("no translation for char %d\n", c); 87 | *pd++ = c; 88 | } 89 | } 90 | } 91 | return pd - dest; 92 | } 93 | 94 | /* table of ISO-latin1 -> QL translations*/ 95 | static struct { 96 | int iso; 97 | int ql; 98 | } codetable[] = { { 96, 159 }, 99 | 100 | { 161, 179 }, { 162, 157 }, { 163, 96 }, { 164, 183 }, 101 | { 165, 158 }, { 167, 182 }, { 169, 127 }, { 171, 184 }, 102 | { 176, 186 }, { 180, 159 }, { 181, 176 }, { 187, 185 }, 103 | { 191, 180 }, 104 | 105 | { 197, 162 }, { 196, 160 }, { 195, 161 }, { 198, 170 }, 106 | { 199, 168 }, { 201, 163 }, { 214, 164 }, { 213, 165 }, 107 | { 216, 166 }, { 220, 167 }, { 223, 156 }, { 224, 141 }, 108 | { 233, 131 }, { 227, 129 }, { 228, 128 }, { 229, 130 }, 109 | { 230, 138 }, { 231, 136 }, { 232, 144 }, { 234, 145 }, 110 | { 236, 148 }, { 237, 147 }, { 238, 149 }, { 239, 146 }, 111 | { 240, 173 }, { 241, 137 }, { 242, 151 }, { 243, 150 }, 112 | { 244, 152 }, { 246, 132 }, { 247, 187 }, { 248, 134 }, 113 | { 249, 154 }, { 250, 153 }, { 251, 155 }, { 252, 135 }, 114 | 115 | { 0, 0 } }; 116 | 117 | /* very simple method to convert iso to ql chars*/ 118 | static unsigned char x__iso2ql(unsigned c) 119 | { 120 | int i; 121 | 122 | for (i = 0; codetable[i].iso != 0; i++) 123 | if (codetable[i].iso == c) 124 | return codetable[i].ql; 125 | return c; 126 | } 127 | static unsigned char x__ql2iso(unsigned c) 128 | { 129 | int i; 130 | 131 | for (i = 0; codetable[i].iso != 0; i++) 132 | if (codetable[i].ql == c) 133 | return codetable[i].iso; 134 | return c; 135 | } 136 | 137 | unsigned char i2q[256]; 138 | unsigned char q2i[256]; 139 | 140 | void init_iso() 141 | { 142 | int i; 143 | 144 | for (i = 0; i < 256; i++) 145 | i2q[i] = x__iso2ql(i); 146 | for (i = 0; i < 256; i++) 147 | q2i[i] = x__ql2iso(i); 148 | } 149 | 150 | int iso2ql(int c) 151 | { 152 | return i2q[c]; 153 | } 154 | int ql2iso(int c) 155 | { 156 | return q2i[c]; 157 | } 158 | 159 | void iso2ql_mem(unsigned char *buf, int len) 160 | { 161 | while (len-- > 0) 162 | buf[len] = i2q[buf[len]]; 163 | } 164 | 165 | void ql2iso_mem(unsigned char *buf, int len) 166 | { 167 | while (len-- > 0) 168 | buf[len] = q2i[buf[len]]; 169 | } 170 | -------------------------------------------------------------------------------- /QL_cconv.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef QL_CCONV_H 4 | #define QL_CCONV_H 5 | 6 | void init_iso(void); 7 | void iso2ql_mem(unsigned char *buf, int len); 8 | void ql2iso_mem(unsigned char *buf, int len); 9 | int tra_conv(char *dest, char *src, int len); 10 | 11 | #endif 12 | 13 | -------------------------------------------------------------------------------- /QL_config.h: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) UQLX - see COPYRIGHT 3 | */ 4 | 5 | #pragma once 6 | 7 | #include 8 | #include 9 | 10 | void InitROM(void); 11 | int EmulatorTable(void); 12 | void save_regs(void *p); 13 | void restore_regs(void *p); 14 | bool LookFor(uint32_t *a, uint32_t w, int nMax); 15 | int LoadMainRom(void); 16 | -------------------------------------------------------------------------------- /QL_driver.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef QL_DRIVER_H 3 | #define QL_DRIVER_H 4 | 5 | int qmaperr(void); 6 | void InitDrivers(void); 7 | 8 | #endif /* QL_DRIVER_H */ 9 | 10 | -------------------------------------------------------------------------------- /QL_files.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef QL_FILES_H 4 | #define QL_FILES_H 5 | 6 | void CleanRAMDev(char *dev); 7 | void fork_files(void); 8 | 9 | #endif /* QL_FILES_H */ 10 | 11 | -------------------------------------------------------------------------------- /QL_hardware.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | extern int display_mode; 6 | void queueKey(short m,short code, uint16_t asciiChar); 7 | void MReadKbd(void); 8 | void KbdCmd(void); 9 | 10 | -------------------------------------------------------------------------------- /QL_poll.c: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) UQLX - see COPYRIGHT 3 | */ 4 | 5 | /* hook for QDOS poll routine */ 6 | 7 | 8 | /*#include "QLtypes.h"*/ 9 | #include "instructions.h" 10 | #include "QL68000.h" 11 | #include "xcodes.h" 12 | #include "QL.h" 13 | #include "QDOS.h" 14 | #include "QInstAddr.h" 15 | #include "QL_hardware.h" 16 | #include "unix.h" 17 | 18 | /*extern int schedCount;*/ 19 | extern volatile int poll_req; 20 | 21 | #if 0 22 | extern uw8 IPCR_buff[22]; 23 | extern uw16 IPCR_ascii[22]; 24 | extern short IPCR_n; 25 | extern short IPCR_p; 26 | 27 | extern uw16 asciiChar; 28 | #endif 29 | 30 | void init_poll() 31 | { 32 | reg[1]=0x10; 33 | reg[2]=0; 34 | QLtrap(1,0x18,2000000l); 35 | 36 | if (*reg==0) 37 | { 38 | Ptr p=(Ptr)memBase+aReg[0]; 39 | p = p + 4; 40 | 41 | WL( p, POLL_CMD_ADDR); 42 | WW((Ptr)memBase+POLL_CMD_ADDR, POLL_CMD_CODE); 43 | 44 | QLtrap(1,0x1c,200000l); 45 | } 46 | } 47 | 48 | 49 | void PollCmd() 50 | { 51 | if((Ptr)gPC-(Ptr)memBase-2!=POLL_CMD_ADDR) 52 | { 53 | exception=4; 54 | extraFlag=true; 55 | nInst2=nInst; 56 | nInst=0; 57 | return; 58 | } 59 | 60 | #ifdef VTIME 61 | if (poll_req>1) 62 | printf("poll_req=%d in PollCmd()\n",poll_req); 63 | poll_req=0; 64 | #endif 65 | 66 | if (isMinerva) 67 | MReadKbd(); 68 | 69 | rts(); 70 | } 71 | 72 | 73 | -------------------------------------------------------------------------------- /QL_poll.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef QLPOLL_H 4 | #define QLPOLL_H 5 | 6 | void init_poll(void); 7 | 8 | #endif /* QLPOLL_H */ 9 | -------------------------------------------------------------------------------- /QL_screen.c: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) UQLX - see COPYRIGHT 3 | */ 4 | #include 5 | #include "QL68000.h" 6 | #include "QL_config.h" 7 | #include "QL_screen.h" 8 | 9 | screen_specs qlscreen = 10 | { 11 | 128 * 1024, 12 | 128 * 1024 + 32 * 1024, 13 | 0x8000, 14 | 128, 15 | 256, 16 | 512, 17 | }; 18 | 19 | struct SCREENDEF 20 | { 21 | uw32 scrbase; 22 | uw32 scrlen; 23 | uw16 linel; 24 | uw16 xres; 25 | uw16 yres; 26 | }; 27 | 28 | static int PtrPatchOk=0; 29 | void QLPatchPTRENV(void) 30 | { 31 | uw32 scrdef_search; 32 | //struct SCREENDEF *scrdef; 33 | int flag; 34 | 35 | scrdef_search=((Ptr)pc-8000) - (void *)memBase; 36 | 37 | while ( LookFor(&scrdef_search,0x20000,24000)) { 38 | struct SCREENDEF *scrdef = (void *)memBase + scrdef_search; 39 | 40 | if (RL(&(scrdef->scrlen))==0x8000 && 41 | RW(&(scrdef->linel)) ==0x80 && 42 | RW(&(scrdef->xres)) ==0x200 && 43 | RW(&(scrdef->yres)) ==0x100 ) { 44 | PtrPatchOk=1; 45 | WL(&(scrdef->scrbase),qlscreen.qm_lo); 46 | WL(&(scrdef->scrlen),qlscreen.qm_len); 47 | WW(&(scrdef->linel),qlscreen.linel); 48 | WW(&(scrdef->xres),qlscreen.xres); 49 | WW(&(scrdef->yres),qlscreen.yres); 50 | 51 | return; 52 | } else { 53 | scrdef_search = scrdef_search + 2; 54 | } 55 | } 56 | 57 | if (!PtrPatchOk) 58 | printf("WARNING: could not patch Pointer Environment\n"); 59 | else 60 | printf("Patched Pointer Environment with screen size\n"); 61 | } 62 | -------------------------------------------------------------------------------- /QL_screen.h: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) UQLX - see COPYRIGHT 3 | */ 4 | #pragma once 5 | 6 | #include 7 | 8 | typedef struct _SCREEN_SPECS { 9 | uint32_t qm_lo; 10 | uint32_t qm_hi; 11 | uint32_t qm_len; 12 | 13 | uint32_t linel; 14 | int yres; 15 | int xres; 16 | } screen_specs; 17 | 18 | extern screen_specs qlscreen; 19 | 20 | void QLPatchPTRENV(void); 21 | 22 | -------------------------------------------------------------------------------- /QL_serial.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 1996 jonathan hudson 3 | */ 4 | 5 | /* most of the code has moved to QLserio.c */ 6 | 7 | #ifdef SERIAL 8 | #include "QL68000.h" 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | 18 | #include "QL.h" 19 | #include "QInstAddr.h" 20 | #include "unix.h" 21 | 22 | #include "QSerial.h" 23 | 24 | static short defbaud[1] = {9600}; 25 | 26 | serdev_t *sparams[MAXSERIAL+1]; 27 | 28 | Cond SetBaudRate(short rate) 29 | { 30 | short i; 31 | 32 | for(i = 1; i < MAXSERIAL+1; i++) 33 | { 34 | defbaud[0] = rate; 35 | if (sparams[i]) 36 | { 37 | (sparams[i])->baud = rate; 38 | if((sparams[i])->fd > 0) 39 | { 40 | tty_baud(sparams[i]); 41 | } 42 | } 43 | } 44 | return 1; 45 | } 46 | 47 | #endif /* SERIAL */ 48 | -------------------------------------------------------------------------------- /QL_sound.h: -------------------------------------------------------------------------------- 1 | /* sQLux Sound */ 2 | #ifndef _QL_sound_ 3 | #define _QL_sound_ 4 | 5 | #include 6 | 7 | extern volatile bool soundOn; 8 | 9 | void initSound(int volume); 10 | void BeepSound(unsigned char*); 11 | void KillSound(void); 12 | void closeSound(); 13 | #endif 14 | -------------------------------------------------------------------------------- /QLfiles.h: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) UQLX - see COPYRIGHT 3 | */ 4 | 5 | 6 | 7 | int match(char *,char *, char *, int , int , int, int); 8 | int qopenfile(char *, char *, int , int , int ); 9 | DIR *qopendir(char *, char *, int ); 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /QLip.h: -------------------------------------------------------------------------------- 1 | /********************************************************************* 2 | * QLIP (c) 1998 Jonathan Hudson & Richard Zidlicky 3 | * 4 | * This code is part of the uqlx QDOS emulator for Unix 5 | * 6 | * This file is outside the uqlx copyright and may be freely copied, 7 | * used and modified for any non-commercial purpose. 8 | * 9 | ********************************************************************/ 10 | 11 | #ifdef IPDEV 12 | 13 | #ifdef __WIN32__ 14 | #include 15 | #else 16 | #include 17 | #include 18 | #include 19 | #endif 20 | 21 | typedef struct { 22 | int status; /* 0 OK, -1 check connection(async), -2 error */ 23 | int lerrno; 24 | int sock; 25 | struct sockaddr_in name; 26 | } ipdev_t; 27 | 28 | int ip_init(int, void *); 29 | int ip_test(int, char *); 30 | int ip_open(int, void **); 31 | void ip_close(int, void *); 32 | void ip_io(int, void *); 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /QLserio.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef QLSERIO_H 4 | #define QLSERIO_H 5 | 6 | int ser_write(serdev_t *sd, void *buf, int pno); 7 | 8 | #endif /* QLSERIO_H */ 9 | 10 | -------------------------------------------------------------------------------- /QLtraps.c: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) UQLX - see COPYRIGHT 3 | */ 4 | 5 | #include "QL68000.h" 6 | #include 7 | #include "QL.h" 8 | #include "QDOS.h" 9 | 10 | #include "QSerial.h" 11 | #include "QInstAddr.h" 12 | #include "boot.h" 13 | #include "QDOS.h" 14 | #include "QL_screen.h" 15 | #include "unixstuff.h" 16 | 17 | /*extern int schedCount;*/ 18 | extern int HasPTR; 19 | 20 | /* external debugging aid */ 21 | /* replaced by gdb's "qldbg" command */ 22 | #if 0 23 | void qldbg(void) 24 | { 25 | exception=32+14; 26 | extraFlag=true; 27 | nInst2=nInst; 28 | nInst=0; 29 | } 30 | #endif 31 | 32 | #if 0 33 | void trap0(void) /* go supervisor */ 34 | { if(!supervisor) 35 | { supervisor=true; 36 | gUSP=(*sp); 37 | (*sp)=gSSP; 38 | } 39 | } 40 | #else 41 | void trap0(void) 42 | { 43 | exception = 32 + (code & 15); 44 | extraFlag = true; 45 | nInst2 = nInst; 46 | nInst = 0; 47 | } 48 | #endif 49 | 50 | void trap1(void) 51 | { 52 | short op; 53 | 54 | op = (short)(*reg) & 0x7f; 55 | 56 | /* if ((op>3 && op<6) || (op>7 && op<0xc))*/ 57 | DECR_SC(); /*schedCount--;*/ 58 | 59 | if (op >= 0x11 && op <= 0x15) /* Gestione dell'hardware */ 60 | { 61 | switch (op) { 62 | #if 0 63 | case 0x10: /* Set or read display mode */ 64 | SetDisplayMode(); 65 | break; 66 | #endif 67 | case 0x11: /* IPC command */ 68 | *reg = 0; /**/ /* neu, .hpr 21.5.99 */ 69 | if (!IPC_Command()) 70 | goto doTrap; 71 | /* *reg=0; */ /**/ /* raus, .hpr 21.5.99 */ 72 | break; 73 | case 0x12: /* set baud rate */ 74 | *reg = SetBaudRate((short)reg[1]) ? 0 : -15; 75 | break; 76 | case 0x15: /* adjust clock */ 77 | if (!reg[1]) 78 | break; 79 | qlClock = (uw32)reg[1]; 80 | /*printf("aclk: qlClock set to %ld\n",qlClock);*/ 81 | case 0x13: /* read clock */ 82 | GetDateTime((w32 *)(reg + 1)); 83 | /*reg[1]=(w32)((uw32)reg[1]-qlClock);*/ 84 | *reg = 0; 85 | prep_rtc_emu(); 86 | break; 87 | case 0x14: /* set clock */ 88 | { 89 | w32 i; 90 | 91 | GetDateTime(&i); 92 | qlClock -= i - (uw32)reg[1]; 93 | /*printf("sclk: qlClock set to %ld\n",qlClock);*/ 94 | *reg = 0; 95 | break; 96 | } 97 | } 98 | } else { 99 | #if 0 100 | if (reg[0]==-26) 101 | { 102 | /* =============================== */ 103 | /* TRAP #1 D0.L=-26 (-$1A) */ 104 | /* =============================== */ 105 | reg[0]=0; 106 | 107 | /* IN: */ 108 | /* D1.L opcode */ 109 | 110 | /* OUT: */ 111 | /* D0.L QDOS error code (QDOS systems return -15, as the trap is not defined) */ 112 | 113 | /* D4-D7/A3-A7 preserved */ 114 | 115 | /* All other registers: depends on the opcode in D1.L. */ 116 | 117 | 118 | /* Currently there are three opcodes defined: */ 119 | switch(reg[1]) 120 | { 121 | 122 | /* D1.L=0 Get extended trap info */ 123 | /* ============================== */ 124 | /* IN: no input */ 125 | /* OUT: */ 126 | /* D0.L=0 (-15 in systems without the trap#1 D0=-26) */ 127 | /* D1.L=version of this trap (currently version 0) */ 128 | /* D2.L=0 (reserved) */ 129 | /* All other registers are preserved */ 130 | case 0: 131 | reg[1]=0; 132 | reg[2]=0; 133 | break; 134 | 135 | /* This trap is provided for future compatibility. QL software can test for an */ 136 | /* emulator using the following opcode (D1.L=1). Version 0 (D1=0) means that */ 137 | /* the trap accepts three opcodes in D1.L: 0, 1 and 2. */ 138 | 139 | 140 | /* D1.L=1 Get emulator info */ 141 | /* ========================= */ 142 | /* IN: no input */ 143 | /* OUT: */ 144 | /* D0.L=0 (-15 in systems without the trap#1 D0=-26) */ 145 | /* D1.L=EMULATOR */ 146 | /* D2.L=VERSION */ 147 | /* D3.L=VERSION TYPE */ 148 | /* All other registers are preserved */ 149 | 150 | case 1: 151 | /* EMULATOR long word format: */ 152 | 153 | /* $aabbccdd, where... */ 154 | /* dd=emulator type (0=QDOS system (no one at the moment with this trap defined) */ 155 | /* 1=Q-emuLator */ 156 | /* 2=UQLX */ 157 | /* 3=QLAY) */ 158 | /* cc=reserved (0) */ 159 | /* bb=host platform (0=Win95, 1=DOS, 2=UNIX, 3=Mac) */ 160 | /* aa=sub-platform code (for example the UNIX dialect, to be defined if needed) */ 161 | 162 | /* Example: D1.L=$00030001 means 'Q-emuLator running on Mac' */ 163 | 164 | reg[1]=0x03020002; 165 | 166 | /* VERSION long word format: */ 167 | 168 | /* $aabbccdd, where... */ 169 | /* aa=version major number */ 170 | /* bb=version minor number */ 171 | /* cc=version minor sub-number */ 172 | /* dd=release */ 173 | 174 | /* The release field is a counter to differentiate releases of the same */ 175 | /* version. The release counter is NOT reset when going from alpha to beta or */ 176 | /* from beta to a final version. In this way greater version long words always */ 177 | /* mean more recent versions. The release counter is reset to 1 for each new */ 178 | /* version. */ 179 | 180 | /* Example: D2.L=$01000308 means 'version 1.0.3, eighth release' */ 181 | 182 | reg[2]=0x0; 183 | 184 | /* VERSION TYPE is 0 for ALPHA, 1 for BETA and 2 for FINAL */ 185 | 186 | reg[3]=0; 187 | break; 188 | 189 | 190 | /* D1.L=2 Get emulator name */ 191 | /* ========================= */ 192 | /* In: */ 193 | /* A1=pointer to buffer */ 194 | /* D2.L= buffer len */ 195 | /* Out: */ 196 | /* the buffer pointed by A1 is filled with a short QL string describing the */ 197 | /* emulator type and version (for example 'Q-emuLator 1.0.3'). */ 198 | 199 | /* If the buffer is too small, the string is truncated to the buffer's length */ 200 | /* and the function returns the error BUFFER FULL. */ 201 | 202 | case 2: 203 | strncpy(reg[1]+(Ptr)memBase,release,reg[2]); 204 | if (strlen(release)>reg[2]) 205 | reg[0]=QERR_BF; 206 | break; 207 | default: 208 | reg[0]=QERR_BP; 209 | } 210 | return; 211 | } 212 | else 213 | #endif 214 | { 215 | doTrap: 216 | exception = 33; 217 | extraFlag = true; 218 | nInst2 = nInst; 219 | nInst = 0; 220 | } 221 | } 222 | } 223 | 224 | void trap2(void) 225 | { 226 | DECR_SC(); /*schedCount--;*/ 227 | 228 | // if (reg[0] == 1 ) 229 | // printf("trap2: %s\n",aReg[0]+(char*)memBase+2); 230 | exception = 34; 231 | extraFlag = true; 232 | nInst2 = nInst; 233 | nInst = 0; 234 | } 235 | 236 | void trap3(void) 237 | { 238 | DECR_SC(); /*schedCount--;*/ 239 | 240 | if (!HasPTR && *reg == 0x70) 241 | QLPatchPTRENV(); 242 | 243 | exception = 35; 244 | extraFlag = true; 245 | nInst2 = nInst; 246 | nInst = 0; 247 | } 248 | 249 | void btrap3(void) 250 | { 251 | DECR_SC(); 252 | 253 | if (((w8)reg[0]) == 1) { 254 | /*printf("btrap3: a0=%x\n",aReg[0]);*/ 255 | *((char *)reg + 4 + RBO) = (char)BOOT_SELECT; 256 | reg[0] = 0; 257 | qlux_table[code] = trap3; 258 | } else 259 | trap3(); 260 | } 261 | 262 | #if 0 263 | void trap4(void) 264 | { w32 a; 265 | 266 | a=ReadLong(ReadLong(0x28064))+0x16; 267 | WriteByte(a,ReadByte(a)|0x80); 268 | } 269 | #endif 270 | 271 | #if 1 272 | void FastStartup(void) 273 | { 274 | if ((Ptr)gPC - (Ptr)memBase - 2 != RL(&memBase[1])) { 275 | exception = 4; 276 | extraFlag = true; 277 | nInst2 = nInst; 278 | nInst = 0; 279 | return; 280 | } 281 | 282 | memset((Ptr)memBase + 131072l, 0, RTOP - 131072l); 283 | 284 | while (RL((w32 *)gPC) != 0x28000l) 285 | gPC++; 286 | gPC -= 4; 287 | aReg[5] = RTOP; 288 | } 289 | 290 | #endif 291 | -------------------------------------------------------------------------------- /QLtraps.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void btrap3(void); 4 | 5 | -------------------------------------------------------------------------------- /QSerial.h: -------------------------------------------------------------------------------- 1 | /* UQLX */ 2 | 3 | #ifndef QSERIAL_H 4 | #define QSERIAL_H 5 | 6 | #include 7 | 8 | Cond SetBaudRate(short); 9 | void InstallSerial(void); 10 | 11 | #if defined(SERIAL) || defined(NEWPTY) 12 | 13 | void InitSerial(void); 14 | void CloseSerial(void); 15 | 16 | typedef struct _FakeRec *FakeTerm; 17 | typedef struct _FakeRec 18 | { 19 | char *command; /* command name */ 20 | char **command_args; /* command arguments */ 21 | char *term_type; /* terminal type */ 22 | char utmp_inhibit; /* don't add utmp entries */ 23 | char login_shell; /* invoke shell as login shell */ 24 | char *tname; /* name of allocated PTY */ 25 | pid_t pid; /* process ID of child process */ 26 | uid_t uid; /* uid of invoking user */ 27 | gid_t gid; /* gid of invoking user */ 28 | int master; /* pty master file descriptor */ 29 | int slave; /* pty slave file descriptor */ 30 | struct SERDEV *sd; 31 | FakeTerm next; 32 | int job_control; 33 | } FakeRec; 34 | 35 | typedef struct SERDEV 36 | { 37 | long unit; 38 | long parity; 39 | long hshake; 40 | long xlate; 41 | long baud; 42 | int fd; 43 | #ifdef NO_FIONREAD 44 | int bfc_valid; 45 | char bfc; 46 | #endif 47 | /* some pty special values */ 48 | FakeTerm w; 49 | int killed; 50 | int teof; /* chr$(26) occured and should cause 1 EOF*/ 51 | } serdev_t; 52 | 53 | 54 | void tty_baud(serdev_t *); 55 | int tty_open(const char *, serdev_t *); 56 | void tty_close(int ); 57 | 58 | int pty_open(int, void **); 59 | void pty_close(int, void *); 60 | 61 | int pendingio (int f); 62 | int writeio (serdev_t * sd, char *buf, long *pno); 63 | int readio (serdev_t * sd, char *buf, long *pno, short tc); 64 | 65 | #define MAXSERIAL 4 66 | 67 | #endif /* defined(SERIAL) || defined(NEWPTY) */ 68 | #endif /* QSERIAL_H */ 69 | -------------------------------------------------------------------------------- /QSound.h: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) UQLX - see COPYRIGHT 3 | */ 4 | 5 | /* someday theese might get implemented */ 6 | /* - at the moment I enjoy the silence */ 7 | 8 | extern volatile Cond soundOn; 9 | 10 | short AllocateSound(void); 11 | void DisposeSound(void); 12 | void BeepSound(unsigned char *); 13 | void KillSound(void); 14 | -------------------------------------------------------------------------------- /QVFS.c: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) UQLX - see COPYRIGHT 3 | */ 4 | 5 | 6 | 7 | /* QVFS is (c) by HPR */ 8 | /* this file implements something remotely similar */ 9 | /* .. hoping to become compatible sometimes */ 10 | 11 | /* currently this IS NOT HPR's QVFS*/ 12 | 13 | #ifdef QVFS 14 | 15 | /*#include "QLtypes.h"*/ 16 | #include "QL68000.h" 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #define MDV_ID 0x28b07ae4 30 | 31 | #define min(_a_,_b_) (_a_<_b_ ? _a_ :_b_) 32 | 33 | 34 | #include "QL.h" 35 | #include "xcodes.h" 36 | 37 | #include "driver.h" 38 | #include "QDOS.h" 39 | 40 | #include "QInstAddr.h" 41 | #include "unix.h" 42 | 43 | #include "QLfiles.h" 44 | #include "QFilesPriv.h" 45 | #include "QL_driver.h" 46 | #include "QVFS.h" 47 | #include "util.h" 48 | 49 | 50 | static char qvf_mount[4096]; 51 | static char qvf_mname[4096]; 52 | static char qvf_buff[4096]; 53 | 54 | 55 | int qvf_init(int id,void *p){return 0;} 56 | 57 | int qvf_test(int id, char *name) 58 | { 59 | int strict,creat; 60 | int res,key; 61 | char *cname,*pname,*cmount; 62 | unsigned int i; 63 | 64 | strict=0; 65 | creat=0; 66 | 67 | /* no delete or directory yet */ 68 | key=reg[3]; 69 | 70 | i=RW(name); 71 | if (i>4000) i=4000; 72 | strncpy(qvf_buff,name+2,i); 73 | qvf_buff[i]=0; 74 | 75 | cname=qvf_buff; 76 | 77 | if(RW(name)>3) 78 | if (!strncasecmp(cname,"XVFS_",5)) 79 | { 80 | cname+=5; /* skip optional name heading */ 81 | strict=1; 82 | } 83 | 84 | if (!strict && cname[0]!='/' ) return 0; 85 | 86 | if (key==-1 || key==4) 87 | { 88 | qerrno=QERR_NI; 89 | return -2; 90 | } 91 | 92 | #if 0 93 | if (strlen(cname)>4000) 94 | return strict ? -1 :0; 95 | #endif 96 | 97 | cmount=qvf_mount; 98 | *cmount++='/'; 99 | cmount[0]=0; 100 | pname=cname; 101 | qvf_mname[0]=0; 102 | 103 | 104 | if (*pname=='/') pname++; 105 | 106 | 107 | if (key==4) 108 | res=match(qvf_mount, qvf_mname, pname, 1,0,4000,0); 109 | else 110 | { 111 | creat=0; 112 | if (key==2 && 113 | (res=match(qvf_mount, qvf_mname, pname, 0,creat,4000,0))) 114 | { 115 | qerrno=QERR_EX; 116 | return -2; 117 | } 118 | 119 | 120 | cmount=qvf_mount; 121 | *cmount++='/'; 122 | cmount[0]=0; 123 | pname=cname; 124 | qvf_mname[0]=0; 125 | 126 | if (*pname=='/') pname++; 127 | 128 | if (key >=2 ) creat=1; 129 | res=match(qvf_mount, qvf_mname, pname, 0,creat,4000,0); 130 | } 131 | 132 | /*printf("qvf_mount: %s\nqvf_mname: %s\nres=%d\n",qvf_mount,qvf_mname,res);*/ 133 | 134 | 135 | return res; 136 | } 137 | 138 | int qvf_open(int id, void **priv) 139 | { 140 | qvf_priv *p; 141 | int perm,fd; 142 | struct HF_FCB *fcb; 143 | struct mdvFile *f; 144 | char *cp; 145 | struct stat sbuf; 146 | 147 | if (reg[3]==4) 148 | /*fd = qopendir(qvf_mount,qvf_mname,4000);*/ 149 | return -1; 150 | else 151 | { 152 | perm = O_RDWR | O_CREAT ; 153 | fd = qopenfile(qvf_mount,qvf_mname,perm,0666,4000); 154 | if (fd<0) 155 | { 156 | fd = qopenfile(qvf_mount,qvf_mname,O_RDWR,0666,4000); 157 | if (fd<0) 158 | fd = qopenfile(qvf_mount,qvf_mname,O_RDONLY ,0666,4000); 159 | } 160 | } 161 | 162 | if (fd<0) 163 | return -1; 164 | 165 | fstat(fd,&sbuf); 166 | 167 | p=*priv=malloc(sizeof(qvf_priv)); 168 | 169 | f=&(p->f); 170 | 171 | #ifndef EMX 172 | #define DEVMODE (S_IFREG | S_IFDIR | S_IFCHR | S_IFBLK) 173 | #else 174 | #define DEVMODE (S_IFREG | S_IFDIR | S_IFCHR) 175 | #endif 176 | 177 | if (sbuf.st_mode & DEVMODE) 178 | { 179 | p->isdev=0; 180 | SET_FCB(f,&(p->fcb)); 181 | strcpy(GET_FCB(f)->uxname,"/"); /* HACK !!! hide mount */ 182 | strncat(GET_FCB(f)->uxname,qvf_mname,4094); 183 | 184 | SET_HFILE(f,fd); 185 | /*SET_FNUMBER(f,-1);*/ 186 | SET_OPEN(f,true); 187 | SET_FILESYS(f,-1); 188 | SET_DRIVE(f,-1); 189 | SET_ISDISK(f,0); 190 | SET_KEY(f,reg[3]); 191 | SET_ISDIR(f,4==reg[3]); 192 | SET_EOF(f,HDfLen(f,0)); 193 | SET_NEXT(f,nil); 194 | SET_ID(f,MDV_ID); 195 | 196 | /*cpy name into header!!!*/ 197 | cp=strrchr(qvf_mname,'/'); 198 | if (cp) cp++; 199 | else cp=qvf_mname; 200 | 201 | strncpy(NAME_REF(f)+2,cp,36); 202 | WW(NAME_REF(f),min(36,strlen(cp))); 203 | } 204 | else p->isdev=1; 205 | 206 | p->fd=fd; 207 | 208 | return 0; 209 | } 210 | 211 | void qvf_close(int id, void *priv) 212 | { 213 | qvf_priv *p=priv; 214 | 215 | close(GET_HFILE(&(p->f))); 216 | 217 | } 218 | 219 | int qvf_pend(qvf_priv *p) 220 | { 221 | if (check_pend(p->fd,SLC_READ)) return 0; 222 | else return QERR_NC; 223 | } 224 | 225 | int qvf_read(qvf_priv *p, void *buf, int pno) 226 | { 227 | int res; 228 | 229 | res=read(p->fd,buf,pno); 230 | 231 | if (res<0) res=qmaperr(); 232 | return res; 233 | } 234 | 235 | static int qvf_write(qvf_priv *p, void *buf, int pno) 236 | { 237 | int res; 238 | 239 | res=write(p->fd,buf,pno); 240 | 241 | if (res<0) res=qmaperr(); 242 | return res; 243 | } 244 | 245 | void qvf_io(int id, void *priv) 246 | { 247 | qvf_priv *p=priv; 248 | 249 | if (p->isdev) 250 | io_handle(qvf_read,qvf_write,qvf_pend, p); 251 | else 252 | QHostIO(&(p->f),reg[0],0); 253 | 254 | } 255 | 256 | #endif /* QVFS */ 257 | -------------------------------------------------------------------------------- /QVFS.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * (c) UQLX - see COPYRIGHT 4 | */ 5 | 6 | 7 | 8 | /* QVFS is (c) by HPR */ 9 | /* this file implements something remotely similar */ 10 | 11 | #include "QFilesPriv.h" 12 | 13 | int qvf_init(int,void *); 14 | int qvf_open(int,void **); 15 | int qvf_test(int,char *); 16 | void qvf_close(int, void *); 17 | void qvf_io(int, void *); 18 | 19 | 20 | typedef struct QVF_PRIV 21 | { 22 | int isdev; 23 | int fd; 24 | struct mdvFile f; 25 | struct HF_FCB fcb; 26 | char padd[4000]; /* longer than standard name in FCB !*/ 27 | } qvf_priv; 28 | 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Progress Halted 2 | 3 | In real life I am too busy building bare metal clouds so don't expect to see 4 | any new features for a while. I am still happy to review PRs. Also if you want 5 | to take over that could be arranged! 6 | 7 | # sQLux (or QL Sux according to DaveP) 8 | 9 | sQLux is a [Sinclair QL](https://en.wikipedia.org/wiki/Sinclair_QL) emulator. It runs on Linux (including Rapsberry Pi), Mac and MS Windows. It is based on uQlx but with SDL2 used as its OS layer. 10 | 11 | sQLux adds several features over the uQlx base code. See the [Documentation](docs/sqlux.md) for more details. 12 | 13 | sQLux is in active development, with new functionality added regularly. However, the latest releases and packages are suitable for normal use. 14 | 15 | 16 | 17 | # Releases 18 | 19 | Automatic builds are run and releases are available for the following architectures/O.S.: 20 | 21 | - Linux Ubuntu 22.04 22 | 23 | - `aarch64` [arm v8](https://en.wikipedia.org/wiki/AArch64) 24 | 25 | - `armv7 ` (armhf kernel) 26 | 27 | - Linux Debian 28 | 29 | - Debian 11 Bullseye 30 | 31 | - `armv7 ` (armhf kernel) 32 | 33 | - Debian 10 Buster 34 | 35 | - `armv7 ` (armhf kernel) 36 | 37 | tested on RaspberryPI 400 38 | 39 | - MacOS Intel 40 | 41 | - Windows (built w/ MSYS2) 42 | - 64bit 43 | 44 | Releases are uploaded on Github automatically whenever a new tag, merge or pull request is pushed: 45 | 46 | - `tags` on `master` branch: Stable releases 47 | - The tag string is used as part of the releases description and artifacts names 48 | 49 | - `master` branch: Development Releases 50 | - Every commit or pull into master branch generates a pre-release artifact 51 | - older Development Releases are overwritten each time a new non-tagged build is run 52 | 53 | # Building 54 | 55 | Some Basic TL;DR instructions will follow for some architecture/O.S. 56 | 57 | For more build tips, see Github Actions commands in `.github/workflows/*.yml` definitions. 58 | 59 | ## Dependencies 60 | ### Debian/Ubuntu 61 | 62 | ``` 63 | apt install build-essential cmake git libsdl2-dev 64 | ``` 65 | ### Fedora 66 | 67 | ``` 68 | dnf install cmake gcc gcc-c++ git SDL2-devel 69 | ``` 70 | 71 | ## All Platforms 72 | 73 | sQLux uses git submodules, so either clone with the `--recursive` argument. 74 | 75 | ``` 76 | git clone --recursive https://github.com/SinclairQL/sQLux/ 77 | ``` 78 | 79 | or after cloning 80 | 81 | ``` 82 | git submodule init 83 | git submodule update 84 | ``` 85 | 86 | ## Building Linux 87 | 88 | sQLux has switched to using cmake as its build system 89 | 90 | 1. Install dependencies as per above chapter 91 | 92 | 1. Build and test 93 | ```sh 94 | make 95 | # then test the binary 96 | ./build/sqlux --help 97 | ``` 98 | 99 | ## Building MacOS 100 | 101 | 1. Install dependencies 102 | 103 | Dependencies are available with [Homebrew](https://brew.sh/) 104 | 105 | ```sh 106 | brew install cmake sdl2 107 | ``` 108 | 109 | 2. Build and test 110 | 111 | ```sh 112 | make 113 | # then test the binary 114 | ./build/sqlux --help 115 | ``` 116 | 117 | ## Building MinGW on Linux 118 | 119 | Instructions based on debian/ubuntu distro, for other distros you will have to modify as appropriate 120 | 121 | Download the SDL2 mingw SDK and adapt the following to your environment/version. 122 | The SDL2 development libraries can be found [here](https://github.com/libsdl-org/SDL/releases): 123 | 124 | ```sh 125 | tar xvf SDL2-devel-2.0.18-mingw.tar.gz 126 | cd SDL2-2.0.18/ 127 | sed -i "s|/opt/local/|/usr/local/|" x86_64-w64-mingw32/lib/cmake/SDL2/sdl2-config.cmake 128 | sed -i "s|/opt/local/|/usr/local/|" i686-w64-mingw32/lib/cmake/SDL2/sdl2-config.cmake 129 | sudo mkdir /usr/local/i686-w64-mingw32 130 | sudo mkdir /usr/local/x86_64-w64-mingw32 131 | sudo make cross 132 | ``` 133 | 134 | Now the mingw version of SDL2 is available and we can build sQLux for Win64 135 | 136 | make mingw64 137 | 138 | ## Building MinGW on Windows 139 | 140 | Install MSYS2 from here https://www.msys2.org/ 141 | 142 | Run the mingw64 environment 143 | 144 | Install the toolchain and SDL2 145 | 146 | ```sh 147 | pacman -Sy mingw-w64-x86_64-toolchain 148 | pacman -Sy mingw-w64-x86_64-cmake 149 | pacman -Sy mingw-w64-x86_64-SDL2 150 | ``` 151 | 152 | Create the build directory and compile 153 | 154 | ```sh 155 | make 156 | # then test the binary 157 | ./build/sqlux --help 158 | ``` 159 | 160 | This will generate `sqlux.exe`. Dependencies are statically linked, so `sqlux.exe` will run without the need for additional dlls. 161 | 162 | ## MinGW pthreads/win32 threads 163 | 164 | The 64bit build using mingw requires the winpthread library for the high definition timer 165 | support. 166 | 167 | The 32bit build can be built using win32 threads for XP compatibility and therefore does 168 | not include the high resolution timer support. 169 | 170 | # uqlxrc 171 | 172 | The emulator currently reads an existing uqlxrc file, so it will re-use any uQlx setup already existing. 173 | 174 | NOTE: ROMIM has changed to now only accept 1 rom name 175 | 176 | NOTE: RAMTOP is where in memory the top of the ram is, not the amount of ram. 177 | As ram on QL starts at 128k in memory map then to created a 128k QL you 178 | need to set RAMTOP = 256 179 | 180 | sQLux supports additional parameters over those used for uqlxrc. See the [Documentation](docs/sqlux.md) for more details. 181 | 182 | # Shader support 183 | sQLux has support for GPU shaders, to emulate the effects seen when using a CRT display. See the [Shader documentation](docs/shaders.md) for more details on how to build and run sQLux with GPU shaders. 184 | 185 | ## Developers notes 186 | 187 | ### Automatic build and upload to Github Releases 188 | 189 | 1. update `CHANGELOG.md` using [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) best practices 190 | 191 | Use `[Unreleased]` during normal development phases 192 | - this will trigger a `latest` release build and upload 193 | 194 | When ready, modify the version to something meaninful. 195 | 196 | Any version different from `[vx.x.x]` or `[vx.x.x-some-text]` will result in: 197 | - possibly missing Release Body text 198 | - a `latest` release build and upload. 199 | 200 | 2. commit 201 | 202 | ```sh 203 | $ git commit -m "Releasing v1.0.7-rc1" 204 | [dev-newci-4 51379d4] Releasing v1.0.7-rc1 205 | 2 files changed, 11 insertions(+), 4 deletions(-) 206 | ``` 207 | 208 | 3. create tag 209 | 210 | Optional. 211 | 212 | If no tag is pushed, the workflow will overwrite/create a `latest` release. 213 | ```sh 214 | $ git tag v1.0.7-rc1 215 | ``` 216 | 217 | 218 | 4. push commits && tags at the same time 219 | 220 | ```sh 221 | $ git push origin dev-branch --tags 222 | Enumerating objects: 11, done. 223 | Counting objects: 100% (11/11), done. 224 | Delta compression using up to 8 threads 225 | Compressing objects: 100% (5/5), done. 226 | Writing objects: 100% (6/6), 657 bytes | 657.00 KiB/s, done. 227 | Total 6 (delta 3), reused 0 (delta 0), pack-reused 0 228 | remote: Resolving deltas: 100% (3/3), completed with 3 local objects. 229 | To https://github.com/ 230 | b66ef20..51379d4 dev-branch -> dev-branch 231 | * [new tag] v1.0.7-rc1 -> v1.0.7-rc1 232 | ``` 233 | -------------------------------------------------------------------------------- /Toolchain-arm64.cmake: -------------------------------------------------------------------------------- 1 | 2 | # Toolchain for arm64(aarch64) cross-builds on x86_64(amd64) 3 | 4 | set(CMAKE_SYSTEM_NAME Linux) 5 | set(CMAKE_SYSTEM_PROCESSOR aarch64) 6 | set(CMAKE_CROSSCOMPILING TRUE) 7 | 8 | # Cross-compile tooling 9 | # https://packages.ubuntu.com/jammy/amd64/gcc-aarch64-linux-gnu/filelist 10 | # https://packages.ubuntu.com/jammy/amd64/g++-aarch64-linux-gnu/filelist 11 | set(CMAKE_C_COMPILER "/usr/bin/aarch64-linux-gnu-gcc") 12 | set(CMAKE_CXX_COMPILER "/usr/bin/aarch64-linux-gnu-g++") 13 | 14 | # disabling immintrin_h as per https://clang.llvm.org/doxygen/immintrin_8h_source.html 15 | # #if !defined(__i386__) && !defined(__x86_64__) 16 | # #error "This header is only meant to be used on x86 and x64 architecture" 17 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DSDL_DISABLE_IMMINTRIN_H") 18 | 19 | # aarch64 pkgs hints: https://packages.ubuntu.com/jammy/arm64/libsdl2-dev/filelist 20 | include_directories(APPEND /usr/include/SDL2) 21 | include_directories(APPEND /usr/include/aarch64-linux-gnu) 22 | 23 | # aarch64 pkgs hints: https://packages.ubuntu.com/jammy/arm64/libc6-dev/filelist 24 | include_directories(APPEND /usr/include/aarch64-linux-gnu) 25 | include_directories(APPEND /usr/include/x86_64-linux-gnu) 26 | 27 | list(APPEND CMAKE_PREFIX_PATH /usr/lib/aarch64-linux-gnu) 28 | list(APPEND CMAKE_PREFIX_PATH /usr/lib/x86_64-linux-gnu) 29 | -------------------------------------------------------------------------------- /Toolchain-armhf.cmake: -------------------------------------------------------------------------------- 1 | 2 | # Toolchain for armhf(arm) cross-builds on x86_64(amd64) 3 | 4 | set(CMAKE_SYSTEM_NAME Linux) 5 | set(CMAKE_SYSTEM_PROCESSOR armhf) 6 | set(CMAKE_CROSSCOMPILING TRUE) 7 | 8 | # Cross-compile tooling 9 | # https://packages.ubuntu.com/jammy/amd64/gcc-arm-linux-gnueabihf/filelist 10 | # https://packages.ubuntu.com/jammy/amd64/g++-arm-linux-gnueabihf/filelist 11 | set(CMAKE_C_COMPILER "/usr/bin/arm-linux-gnueabihf-gcc") 12 | set(CMAKE_CXX_COMPILER "/usr/bin/arm-linux-gnueabihf-g++") 13 | 14 | # disabling immintrin_h as per https://clang.llvm.org/doxygen/immintrin_8h_source.html 15 | # #if !defined(__i386__) && !defined(__x86_64__) 16 | # #error "This header is only meant to be used on x86 and x64 architecture" 17 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DSDL_DISABLE_IMMINTRIN_H") 18 | 19 | # armhf pkgs hints: https://packages.ubuntu.com/jammy/armhf/libsdl2-dev/filelist 20 | include_directories(APPEND /usr/include/SDL2) 21 | list(APPEND CMAKE_PREFIX_PATH /usr/lib/arm-linux-gnueabihf/cmake/SDL2) 22 | 23 | # armhf pkgs hints: https://packages.ubuntu.com/jammy/armhf/libc6-dev/filelist 24 | include_directories(APPEND /usr/include/arm-linux-gnueabihf) 25 | include_directories(APPEND /usr/include/x86_64-linux-gnu) 26 | 27 | list(APPEND CMAKE_PREFIX_PATH /usr/lib/arm-linux-gnueabihf) 28 | list(APPEND CMAKE_PREFIX_PATH /usr/lib/x86_64-linux-gnu) 29 | 30 | # see https://github.com/enribus/sQLux-fork/issues/1 31 | #set(CMAKE_C_FLAGS '${CMAKE_C_FLAGS} -D__STRICT_ANSI__ -D"__float128=long double"') 32 | -------------------------------------------------------------------------------- /Toolchain-cross-m32.cmake: -------------------------------------------------------------------------------- 1 | SET(CMAKE_C_FLAGS "-m32" CACHE STRING "C compiler flags" FORCE) 2 | SET(CMAKE_CXX_FLAGS "-m32" CACHE STRING "C++ compiler flags" FORCE) 3 | 4 | SET(LIB32 /usr/lib) # Fedora 5 | 6 | IF(EXISTS /usr/lib32) 7 | SET(LIB32 /usr/lib32) # Arch, Solus 8 | ENDIF() 9 | 10 | SET(CMAKE_SYSTEM_LIBRARY_PATH ${LIB32} CACHE STRING "system library search path" FORCE) 11 | SET(CMAKE_LIBRARY_PATH ${LIB32} CACHE STRING "library search path" FORCE) 12 | 13 | # this is probably unlikely to be needed, but just in case 14 | SET(CMAKE_EXE_LINKER_FLAGS "-m32 -L${LIB32}" CACHE STRING "executable linker flags" FORCE) 15 | SET(CMAKE_SHARED_LINKER_FLAGS "-m32 -L${LIB32}" CACHE STRING "shared library linker flags" FORCE) 16 | SET(CMAKE_MODULE_LINKER_FLAGS "-m32 -L${LIB32}" CACHE STRING "module linker flags" FORCE) 17 | 18 | # find Wx config script on Fedora for the highest version of 32 bit Wx installed 19 | IF(EXISTS ${LIB32}/wx/config) 20 | FILE(GLOB WX_INSTALLS ${LIB32}/wx/config/*) 21 | 22 | SET(MAX_WX_VERSION 0.0) 23 | FOREACH(WX_INSTALL ${WX_INSTALLS}) 24 | STRING(REGEX MATCH "[0-9]+(\\.[0-9]+)+" WX_VERSION ${WX_INSTALL}) 25 | 26 | IF(WX_VERSION VERSION_GREATER MAX_WX_VERSION) 27 | SET(MAX_WX_VERSION ${WX_VERSION}) 28 | ENDIF() 29 | ENDFOREACH() 30 | 31 | FILE(GLOB WX_INSTALL_CONFIGS "${LIB32}/wx/config/*${MAX_WX_VERSION}*") 32 | LIST(GET WX_INSTALL_CONFIGS 0 WX_INSTALL_CONFIG) 33 | 34 | SET(WX_CONFIG_TRANSFORM_SCRIPT_LINES 35 | "" 36 | ) 37 | FILE(WRITE ${CMAKE_BINARY_DIR}/wx-config-wrapper 38 | "#!/bin/sh 39 | ${WX_INSTALL_CONFIG} \"\$@\" | sed 's!/emul32/!/usr/!g' 40 | ") 41 | EXECUTE_PROCESS(COMMAND chmod +x ${CMAKE_BINARY_DIR}/wx-config-wrapper) 42 | 43 | SET(wxWidgets_CONFIG_EXECUTABLE ${CMAKE_BINARY_DIR}/wx-config-wrapper) 44 | ENDIF() 45 | 46 | # on Fedora and Arch and similar, point pkgconfig at 32 bit .pc files. We have 47 | # to include the regular system .pc files as well (at the end), because some 48 | # are not always present in the 32 bit directory 49 | IF(EXISTS ${LIB32}/pkgconfig) 50 | SET(ENV{PKG_CONFIG_LIBDIR} ${LIB32}/pkgconfig:/usr/share/pkgconfig:/usr/lib/pkgconfig:/usr/lib64/pkgconfig) 51 | ENDIF() 52 | -------------------------------------------------------------------------------- /Toolchain-mingw-w64-i686.cmake: -------------------------------------------------------------------------------- 1 | # Sample toolchain file for building for Windows from an Ubuntu Linux system. 2 | # 3 | # Typical usage: 4 | # *) install cross compiler: `sudo apt-get install mingw-w64` 5 | # *) cd build 6 | # *) cmake -DCMAKE_TOOLCHAIN_FILE=~/mingw-w64-x86_64.cmake .. 7 | 8 | set(CMAKE_SYSTEM_NAME Windows) 9 | set(TOOLCHAIN_PREFIX i686-w64-mingw32) 10 | 11 | # cross compilers to use for C, C++ and Fortran 12 | set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}-gcc) 13 | set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}-g++) 14 | set(CMAKE_Fortran_COMPILER ${TOOLCHAIN_PREFIX}-gfortran) 15 | set(CMAKE_RC_COMPILER ${TOOLCHAIN_PREFIX}-windres) 16 | set(CMAKE_AR ${TOOLCHAIN_PREFIX}-ar) 17 | 18 | # target environment on the build host system 19 | set(CMAKE_FIND_ROOT_PATH /usr/${TOOLCHAIN_PREFIX}) 20 | 21 | # modify default behavior of FIND_XXX() commands 22 | set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) 23 | set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) 24 | set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) 25 | 26 | # set a flag so we know we are on i686 and trying for XP compat 27 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DWINXP_COMPAT") 28 | 29 | # set the boost architecture 30 | set(Boost_ARCHITECTURE "-x32") 31 | 32 | # fortify sources 33 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_FORTIFY_SOURCE=2") 34 | set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -D_FORTIFY_SOURCE=2") 35 | set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fstack-protector-strong") 36 | -------------------------------------------------------------------------------- /Toolchain-mingw-w64-x86_64.cmake: -------------------------------------------------------------------------------- 1 | # Sample toolchain file for building for Windows from an Ubuntu Linux system. 2 | # 3 | # Typical usage: 4 | # *) install cross compiler: `sudo apt-get install mingw-w64` 5 | # *) cd build 6 | # *) cmake -DCMAKE_TOOLCHAIN_FILE=~/mingw-w64-x86_64.cmake .. 7 | 8 | set(CMAKE_SYSTEM_NAME Windows) 9 | set(TOOLCHAIN_PREFIX x86_64-w64-mingw32) 10 | 11 | # cross compilers to use for C, C++ and Fortran 12 | set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}-gcc) 13 | set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}-g++) 14 | set(CMAKE_Fortran_COMPILER ${TOOLCHAIN_PREFIX}-gfortran) 15 | set(CMAKE_RC_COMPILER ${TOOLCHAIN_PREFIX}-windres) 16 | set(CMAKE_AR ${TOOLCHAIN_PREFIX}-ar) 17 | 18 | # target environment on the build host system 19 | set(CMAKE_FIND_ROOT_PATH /usr/${TOOLCHAIN_PREFIX}) 20 | 21 | # modify default behavior of FIND_XXX() commands 22 | set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) 23 | set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) 24 | set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) 25 | 26 | # set the boost architecture 27 | set(Boost_ARCHITECTURE "-x64") 28 | 29 | # fortify sources 30 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_FORTIFY_SOURCE=2") 31 | set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -D_FORTIFY_SOURCE=2") 32 | set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fstack-protector-strong") 33 | -------------------------------------------------------------------------------- /Xscreen.c: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) UQLX - see COPYRIGHT 3 | */ 4 | 5 | /* fancy code to implement bigger screen */ 6 | 7 | #ifdef XSCREEN 8 | #include "QL68000.h" 9 | #include "QL.h" 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include "xcodes.h" 16 | 17 | #include "driver.h" 18 | #include "QDOS.h" 19 | 20 | #include "instructions.h" 21 | #include "QInstAddr.h" 22 | #include "qmtrap.h" 23 | #include "unix.h" 24 | #include "QL_screen.h" 25 | 26 | #define min(_a_, _b_) (_a_ < _b_ ? _a_ : _b_) 27 | #define max(_a_, _b_) (_a_ > _b_ ? _a_ : _b_) 28 | 29 | struct SCREENDEF { 30 | uw32 scrbase; 31 | uw32 scrlen; 32 | uw16 linel; 33 | uw16 xres; 34 | uw16 yres; 35 | }; 36 | 37 | Cond XLookFor(uintptr_t *a, uw32 w, long nMax) 38 | { 39 | while (nMax-- > 0 && RL((*a)) != w) 40 | (*a) += 2; 41 | return nMax > 0; 42 | } 43 | 44 | static int PtrPatchOk = 0; 45 | void XPatchPTRENV() 46 | { 47 | struct SCREENDEF *scrdef; 48 | int flag; 49 | 50 | scrdef = (Ptr)pc - 8000; 51 | while (XLookFor((uintptr_t *)&scrdef, 0x20000, 24000)) { 52 | if (RL(&(scrdef->scrlen)) == 0x8000 && 53 | RW(&(scrdef->linel)) == 0x80 && 54 | RW(&(scrdef->xres)) == 0x200 && 55 | RW(&(scrdef->yres)) == 0x100) { 56 | PtrPatchOk = 1; 57 | WL(&(scrdef->scrbase), qlscreen.qm_lo); 58 | WL(&(scrdef->scrlen), qlscreen.qm_len); 59 | WW(&(scrdef->linel), qlscreen.linel); 60 | WW(&(scrdef->xres), qlscreen.xres); 61 | WW(&(scrdef->yres), qlscreen.yres); 62 | 63 | return; 64 | } else 65 | scrdef = (struct SCREENDEF *)((char *)scrdef + 2); 66 | } 67 | 68 | if (!PtrPatchOk) 69 | printf("WARNING: could not patch Pointer Environment\n"); 70 | } 71 | 72 | /* oadr is QL format, nadr c-pointer ! */ 73 | void scan_patch_chans(w32 oadr) 74 | { 75 | w32 ca; 76 | w32 ce, cc; 77 | 78 | ce = ReadLong(0x2807c); /* table top */ 79 | ca = ReadLong(0x28078); 80 | 81 | for (; ca <= ce; ca += 4) { 82 | cc = ReadLong(ca); 83 | if (ReadLong(cc + 4) == oadr) { 84 | WriteWord(cc + 0x64, qlscreen.linel); 85 | WriteLong(cc + 0x32, qlscreen.qm_lo); 86 | } 87 | } 88 | } 89 | 90 | /* fool ptr_gen */ 91 | static int xic = 0; 92 | static uw32 cdrv = 0; 93 | static uw32 fpdr; 94 | static uw32 orig_open, orig_io, orig_close, orig_cdrv; 95 | 96 | void devpefio_cmd() 97 | { 98 | int xw, yw, xo, yo; 99 | int xm, ym; 100 | uw16 *pbl; 101 | uw32 saved_regs[16]; 102 | int op; 103 | 104 | if ((uw8)reg[0] == 0xd) { 105 | pbl = (Ptr)memBase + aReg[1]; 106 | xw = RW(pbl++); 107 | yw = RW(pbl++); 108 | xo = RW(pbl++); 109 | yo = RW(pbl); 110 | 111 | xm = xw + xo; 112 | ym = yw + yo; 113 | 114 | if (xm > 512 || 115 | ym > 256 && xm <= qlscreen.xres && ym <= qlscreen.yres) { 116 | uint16_t bwidth; 117 | /* get the border width */ 118 | bwidth = ReadWord(aReg[0] + 0x20); 119 | 120 | WriteWord(aReg[0] + 0x18, 121 | xo + (bwidth * 2) /*scr_par[2].i*/); 122 | WriteWord(aReg[0] + 0x1a, yo + bwidth /*scr_par[3].i*/); 123 | WriteWord(aReg[0] + 0x1c, 124 | xw - (bwidth * 4) /*scr_par[0].i*/); 125 | WriteWord(aReg[0] + 0x1e, 126 | yw - (bwidth * 2) /*scr_par[1].i*/); 127 | 128 | reg[0] = 0; 129 | rts(); 130 | return; 131 | } 132 | } 133 | 134 | code = DEVPEFIO_OCODE; 135 | qlux_table[code](); 136 | } 137 | open_arg scr_par[6]; 138 | extern struct NAME_PARS con_name, scr_name; 139 | 140 | #define GXS ((Ptr)memBase + UQLX_STR_SCRATCH) 141 | void mangle_args(char *dev) 142 | { 143 | int xw, yw; 144 | 145 | xw = scr_par[0].i + scr_par[2].i; 146 | yw = scr_par[1].i + scr_par[3].i; 147 | 148 | if (xw <= 512 && yw <= 256) 149 | return; /* no action needed */ 150 | if (xw > qlscreen.xres || yw > qlscreen.yres) 151 | return; /* same, for other reasons */ 152 | 153 | if (scr_par[4].i >= 0) 154 | snprintf(GXS + 2, 0x400, "%s__%ld", dev, scr_par[4].i); 155 | else 156 | snprintf(GXS + 2, 0x400, "%s", dev); 157 | 158 | WW(GXS, strlen(GXS + 2)); 159 | aReg[0] = UQLX_STR_SCRATCH; 160 | } 161 | 162 | void devpefo_cmd() 163 | { 164 | int res; 165 | uw32 sA0; 166 | uint16_t bwidth; 167 | 168 | sA0 = aReg[0]; 169 | 170 | res = decode_name((Ptr)memBase + ((aReg[0]) & ADDR_MASK_E), &scr_name, 171 | (open_arg *)&scr_par); 172 | if (res == 1) 173 | mangle_args("SCR_"); 174 | else { 175 | res = decode_name((Ptr)memBase + ((aReg[0]) & ADDR_MASK_E), 176 | &con_name, (open_arg *)&scr_par); 177 | if (res == 1) 178 | mangle_args("CON_"); 179 | } 180 | 181 | /* we must patch ROM, but that is mprotect'ed !*/ 182 | WW((Ptr)memBase + orig_open, DEVPEFO_OCODE); 183 | QLsubr(orig_open /*XS_GETOPEN((Ptr)memBase+(aReg[3]+0x18))*/, 200000000); 184 | WW((Ptr)memBase + orig_open, DEVPEFO_CMD_CODE); 185 | 186 | if ((w16)reg[0] < 0) { 187 | aReg[0] = sA0; 188 | 189 | rts(); 190 | return; 191 | } 192 | 193 | /* get the border width */ 194 | bwidth = ReadWord(aReg[0] + 0x20); 195 | 196 | /* set real bounds */ 197 | WriteWord(aReg[0] + 0x18, scr_par[2].i + (bwidth * 2)); 198 | WriteWord(aReg[0] + 0x1a, scr_par[3].i + bwidth); 199 | WriteWord(aReg[0] + 0x1c, scr_par[0].i - (bwidth * 4)); 200 | WriteWord(aReg[0] + 0x1e, scr_par[1].i - (bwidth * 2)); 201 | /* set physical screen: */ 202 | 203 | WriteWord(aReg[0] + 0x64, qlscreen.linel); 204 | WriteLong(aReg[0] + 0x32, qlscreen.qm_lo); 205 | rts(); 206 | } 207 | 208 | /* problems that could not be handled by device init */ 209 | void init_xscreen() 210 | { 211 | uw32 ca; 212 | int j; 213 | 214 | /* get ch#0 */ 215 | ca = ReadLong(0x28078); 216 | ca = ReadLong(ca); 217 | /* driver addr */ 218 | ca = ReadLong(ca + 4); 219 | cdrv = ca; 220 | 221 | orig_io = ReadLong(cdrv + 4); 222 | orig_open = ReadLong(cdrv + 8); 223 | orig_close = ReadLong(cdrv + 12); 224 | orig_cdrv = cdrv; 225 | 226 | DEVPEFIO_OCODE = ReadWord(orig_io); 227 | WW((Ptr)memBase + orig_io, DEVPEF_CMD_CODE); 228 | 229 | qlux_table[DEVPEF_CMD_CODE] = devpefio_cmd; 230 | 231 | scan_patch_chans(orig_cdrv); 232 | 233 | DEVPEFO_OCODE = ReadWord(orig_open); 234 | WW((Ptr)memBase + orig_open, DEVPEFO_CMD_CODE); 235 | qlux_table[DEVPEFO_CMD_CODE] = devpefo_cmd; 236 | } 237 | 238 | /***************************************************************/ 239 | /* various related stuff */ 240 | 241 | static void pps_usg(char *m) 242 | { 243 | printf("Bad geometry: %s. Please use 'nXm' where n=x size, m=y size\n", 244 | m); 245 | 246 | qlscreen.xres = 512; 247 | qlscreen.yres = 256; 248 | } 249 | 250 | void parse_screen(char *geometry) 251 | { 252 | char *p, *pp; 253 | long i; 254 | 255 | qlscreen.xres = 512; 256 | qlscreen.yres = 256; 257 | 258 | i = strtol(geometry, &p, 10); 259 | if (p == geometry) { 260 | pps_usg(geometry); 261 | return; 262 | } 263 | qlscreen.xres = max(i, 512); 264 | if (!(*p == 'x' || *p == 'X')) { 265 | pps_usg(geometry); 266 | return; 267 | } else 268 | p++; 269 | i = strtol(p, &pp, 10); 270 | if (p == pp) { 271 | pps_usg(geometry); 272 | return; 273 | } 274 | qlscreen.yres = max(i, 256); 275 | } 276 | 277 | #endif /* XSCREEN */ 278 | -------------------------------------------------------------------------------- /Xscreen.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef XSCREEN_H 4 | #define XSCREEN_H 5 | 6 | void parse_screen(const char * geometry); 7 | void init_xscreen(void); 8 | 9 | #endif /* XSCREEN_H */ 10 | 11 | -------------------------------------------------------------------------------- /boot.h: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) UQLX - see COPYRIGHT 3 | */ 4 | 5 | 6 | #define Q_F1 232 7 | #define Q_F2 236 8 | #define Q_F3 240 9 | #define Q_F4 244 10 | 11 | #define BOOT_SELECT Q_F1 12 | -------------------------------------------------------------------------------- /build-wasm.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | (emcmake cmake -B wasm . && cd wasm && make) 3 | -------------------------------------------------------------------------------- /build/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SinclairQL/sQLux/79aa52decf115d79af328f62ca5563e7f5f916be/build/.gitkeep -------------------------------------------------------------------------------- /cond.h: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) UQLX - see COPYRIGHT 3 | */ 4 | 5 | /* Here are the inline versions of flag-testing functions*/ 6 | 7 | static inline Cond CondT(void) 8 | { 9 | return true; 10 | } 11 | 12 | static inline Cond CondF(void) 13 | { 14 | return false; 15 | } 16 | 17 | static inline Cond CondHI(void) 18 | { 19 | return !(carry||zero); 20 | } 21 | 22 | static inline Cond CondLS(void) 23 | { 24 | return carry||zero; 25 | } 26 | 27 | static inline Cond CondCC(void) 28 | { 29 | return !carry; 30 | } 31 | 32 | static inline Cond CondCS(void) 33 | { 34 | return carry; 35 | } 36 | 37 | static inline Cond CondNE(void) 38 | { 39 | return !zero; 40 | } 41 | 42 | static inline Cond CondEQ(void) 43 | { 44 | return zero; 45 | } 46 | 47 | static inline Cond CondVC(void) 48 | { 49 | return !overflow; 50 | } 51 | 52 | static inline Cond CondVS(void) 53 | { 54 | return overflow; 55 | } 56 | 57 | static inline Cond CondPL(void) 58 | { 59 | return !negative; 60 | } 61 | 62 | static inline Cond CondMI(void) 63 | { 64 | return negative; 65 | } 66 | 67 | static inline Cond CondGE(void) 68 | { 69 | return (negative==overflow);/* return (negative&&overflow)||(!(negative||overflow));*/ 70 | } 71 | 72 | static inline Cond CondLT(void) 73 | { 74 | return (negative!=overflow);/* return (negative&&(!overflow))||((!negative)&&overflow);*/ 75 | } 76 | 77 | static inline Cond CondGT(void) 78 | { 79 | return (!zero)&&(negative==overflow);/* return (!zero)&&((negative&&overflow)||(!(negative||overflow)));*/ 80 | } 81 | 82 | static inline Cond CondLE(void) 83 | { 84 | return zero||(negative!=overflow);/* return zero||(negative&&(!overflow))||((!negative)&&overflow);*/ 85 | } 86 | -------------------------------------------------------------------------------- /deploy-wasm.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | 3 | HOST="$1" 4 | 5 | scp wasm/index.html $HOST/index.html 6 | scp wasm/sqlux.* $HOST/ 7 | -------------------------------------------------------------------------------- /docker/Docker.md: -------------------------------------------------------------------------------- 1 | #Building for Release Using Docker 2 | 3 | ## Prepare buildx 4 | 5 | Buildx is needed so that the container can be built in an insecure env otherwise the chroots will not get 6 | created correctly. So first create a buildx builder with the correct flags. 7 | 8 | ``` 9 | docker buildx create --use --name insecure-builder --buildkitd-flags '--allow-insecure-entitlement security.insecure' 10 | ``` 11 | 12 | # Build the sqlux-build container 13 | 14 | This will build the container and load it into the local docker container stores so it can be used 15 | later. If you want to push to a registry you can also use --push 16 | 17 | ``` 18 | docker buildx build --allow security.insecure --load -t sqlux-build . 19 | ``` 20 | 21 | # Build the sqlux release 22 | 23 | Replace sqlux-dir and sqlux-release in the command with the the checked out sqlux directoy and a 24 | directory where the build artifacts will be place. 25 | 26 | ``` 27 | docker run -v :/build/sqlux -v :/build/release -it sqlux-build 28 | ``` 29 | -------------------------------------------------------------------------------- /docker/Dockerfile: -------------------------------------------------------------------------------- 1 | # syntax=docker/dockerfile:1.3-labs 2 | From ubuntu:22.04 3 | 4 | SHELL ["/bin/bash", "-ce"] 5 | 6 | RUN <msystem.txt 54 | make install _gcc _SDL2 55 | cd / 56 | 57 | ln -nfs "/quasi-msys2-w64/root/mingw64" /mingw64 58 | 59 | git clone https://github.com/HolyBlackCat/quasi-msys2 /quasi-msys2-w32/ 60 | cd /quasi-msys2-w32/ 61 | echo MINGW32 >msystem.txt 62 | make install _gcc _SDL2 63 | cd / 64 | 65 | ln -nfs "/quasi-msys2-w32/root/mingw32" /mingw32 66 | EOF 67 | 68 | RUN --security=insecure < sqlux-$VERSION/sqlux.ini<< EOF 120 | SYSROM = MIN198.rom 121 | ROMIM = TK232.rom 122 | RAMTOP = 4096 123 | FAST_STARTUP = 1 124 | DEVICE = FLP1,198ad.img,qdos-native 125 | BOOT_DEVICE = FLP1 126 | WIN_SIZE = max 127 | FILTER = 1 128 | FIXASPECT = 1 129 | EOF 130 | 131 | # Download vanpeebles game as example program 132 | curl -O https://dilwyn.qlforum.co.uk/games/adventures/198-adventure.zip 133 | unzip 198-adventure.zip "198adDisk ImageFinal.img" 134 | mv "198adDisk ImageFinal.img" sqlux-$VERSION/198ad.img 135 | rm 198-adventure.zip 136 | 137 | # copy the roms and docs into release 138 | cp -r sqlux/roms sqlux-$VERSION/ 139 | cp -r sqlux/docs sqlux-$VERSION/ 140 | 141 | # copy the binaries into release 142 | cp release/sqlux_x86_64 sqlux-$VERSION/sqlux_x86_64 143 | cp release/sqlux_i386 sqlux-$VERSION/sqlux_i386 144 | cp release/sqlux_armv6 sqlux-$VERSION/sqlux_armv6 145 | cp release/sqlux_armv7 sqlux-$VERSION/sqlux_armv7 146 | cp release/sqlux_arm64 sqlux-$VERSION/sqlux_arm64 147 | cp release/sqlux_w64.exe sqlux-$VERSION/sqlux_w64.exe 148 | cp release/sqlux_w32.exe sqlux-$VERSION/sqlux_w32.exe 149 | 150 | # zip the release 151 | zip -r sqlux-$VERSION.zip sqlux-$VERSION/ 152 | 153 | rm -r sqlux-$VERSION/ 154 | 155 | mv sqlux-$VERSION.zip release/ 156 | 157 | -------------------------------------------------------------------------------- /docs/shaders.md: -------------------------------------------------------------------------------- 1 | # sQLux Shader support 2 | 3 | ## Introduction 4 | sQLux optionally supports OpenGL Shader Language (GLSL) shaders. These shaders run on the GPU and introduce display artifacts similar to those seen when using a BBQL with a 1980s CRT monitor. Artifacts that can be emulated include: 5 | + Scan lines 6 | + Shadow mask 7 | + Bloom 8 | + Screen curvature 9 | 10 | Support for shaders has to be enabled at run time. OpenGL or OpenGL ES libraries must to be installed. Shader support is realised through the use of [sdl-gpu](https://github.com/grimfang4/sdl-gpu) which is statically linked into sQLux. The code for sdl-gpu is included in the sQLux repository. 11 | As shaders run on the GPU, the speed of the emulator is not impacted. 12 | 13 | --- 14 | # Building 15 | In all cases, first follow the steps to build sQLux without shader support, as described in the [README](../README.md). Then update submodules 16 | 17 | ``` 18 | git submodule update --init --recursive 19 | ``` 20 | 21 | ## Building linux 22 | ``` 23 | cd build 24 | cmake -DSUPPORT_SHADERS=TRUE .. 25 | make 26 | ``` 27 | ## Building MinGW on Linux 28 | ``` 29 | cd mingw 30 | cmake -DCMAKE_TOOLCHAIN_FILE=../mingw-w64-x86_64.cmake -DCMAKE_PREFIX_PATH=/usr/local/x86_64-w64-mingw32 -DSUPPORT_SHADERS=TRUE .. 31 | make 32 | ``` 33 | ## Building MinGW on Windows 34 | ``` 35 | cd mingw 36 | cmake.exe -G "MinGW Makefiles" -DSUPPORT_SHADERS=TRUE .. 37 | mingw32-make 38 | ``` 39 | # Shader parameters in sqlux.ini 40 | `SHADER` Selects shader support. 0 disables shaders. 1 enables a "flat" shader. 2 enables a shader including emulated barrel distortion. Disabled by default. 41 | 42 | ``` 43 | SHADER = 2 44 | ``` 45 | 46 | `SHADER_FILE` 47 | The path to the GPU shader (written in OpenGL Shading Language) that is loaded when `SHADER` is set to 1 or 2. 48 | 49 | ``` 50 | SHADER_FILE = ../shaders/crt-pi.glsl 51 | ``` 52 | # Configuration 53 | ## The supplied shader 54 | The supplied shader `crt-pi.glsl` works "out of the box". However, optionally, it can be edited to modify the following attributes: 55 | ### `MASK_TYPE` 56 | The type of emulated CRT shadow mask. 57 | 0 = none, 1 = standard mask, 2 = trinitron like. Default = 1 58 | ### `MASK_BRIGHTNESS` 59 | The relative brightness of the emulated shadow mask. Range 0.0 to 1.0. Smaller number = darker. Default = 0.7. 60 | A darker setting, with curvature enabled, may produce Moiré effects. 61 | ### `SCANLINE_WEIGHT` 62 | How wide scanlines are (it is an inverse value, higher number = thinner lines). Default = 5.0 63 | ### `SCANLINE_GAP_BRIGHTNESS` 64 | How dark the gaps between the scan lines are. Range 0.0 to 1.0. Smaller number = darker. Default = 0.6 65 | Darker gaps between scan lines make Moiré effects more likely. 66 | ### `BLOOM_FACTOR` 67 | The increase in width for bright scanlines. Default = 1.5 68 | ### `INPUT_GAMMA` 69 | Input value for gamma correction. Applied prior to calculating other effects. Default = 2.4 70 | ### `OUTPUT_GAMMA` 71 | Output value for gamma correction. Inverse applied after calculating other effects. Default = 2.2 72 | ### `SHARPER` 73 | By default the shader uses linear blending horizontally. If this is too blurry, enable `SHARPER` 74 | ### `CURVATURE_X` 75 | Simulated curvature to be applied in the x dimension, if `SHADER = 2` in `sqlux.ini`. Default = 0.06 76 | ### `CURVATURE_Y` 77 | Simulated curvature to be applied in the y dimension, if `SHADER = 2` in `sqlux.ini`. Default = 0.12 78 | ## Older Raspberry Pis 79 | By default, when using the Raspberry Pi OS Bullseye edition, hardware graphics acceleration may not be enabled for Pi0 to Pi3. This can impact shader performance. 80 | 81 | To enable hardware acceleration, run the configuration tool: 82 | 83 | `sudo raspi-config` 84 | 85 | Select the options to enable glamor (A8) and GL Driver (A2), under the advanced options sub-menu, and reboot. 86 | 87 | **Note:** Hardware graphics acceleration *should* be enabled by default for the Pi4, so this change should *not* be needed for the Pi4. 88 | 89 | # Creating your own shader 90 | Examples of shaders which can be modified to use within sQLux can be found at e.g. [libretro shaders](https://github.com/libretro/glsl-shaders/tree/master/crt/shaders). 91 | A single file is used for both the vertex and fragment shader. It is compiled twice to generate the two shader types, once with `#define VERTEX` prepended to the start of the file, and once with `#define FRAGMENT` 92 | MacOS no longer supports versions of shader files prior to GLSL version 1.5. (OpenGL 3.2). Many Raspberry Pi models do not support versions of shader files later then GLSL version 1.2 (or the equivalent GLSL ES version 1.0). Therefore compatibility `#defines` are needed to ensure one shader file can support multiple targets. See `crt-pi.glsl` for an example. 93 | sQLux prepends the version required to the file before it is compiled. 94 | ## Variables sQLux makes available within a shader 95 | The following variables are used to pass information to the shader. 96 | ### `attribute vec2 VertexCoord` 97 | Vertex coordinate 98 | ### `attribute vec2 TexCoord` 99 | Coordinate of pixel in texture 100 | ### `gl_Color` 101 | See OpenGL description. 102 | ### `uniform mat4 MVPMatrix` 103 | The combined model, view and projection matrix 104 | ### `uniform sampler2D TEX0` 105 | The input texture, i.e. the image of the QL screen to display. 106 | ### `uniform vec2 TextureSize` 107 | The size of the input texture (i.e. the original size in pixels of the QL display) 108 | ### `uniform vec2 u_resolution` 109 | The output size of the image to be displayed 110 | ## Support for curvature 111 | If `SHADER` is set to 2 in `sqlux.ini` then `#define CURVATURE` is prepended to the file prior to compilation. 112 | ### Mouse support 113 | The mouse position has to be adjusted to reflect simulated curvature. Within the shader file it is assumed that the amount of curvature is defined by 114 | ``` 115 | #define CURVATURE_X a.aa 116 | #define CURVATURE_Y b.bb 117 | ``` 118 | where a.aa and b.bb are floats defining the curvature in the x and y direction. sQLux parses these values and uses them to adjust the reported mouse position. 119 | -------------------------------------------------------------------------------- /docs/sqlux-patchpoints.md: -------------------------------------------------------------------------------- 1 | MDV1_BOOT Locations 2 | ------------------- 3 | 4 | MIN189 = 842A 5 | MIN198 = 83CA 6 | MIN198a1 = 83CC 7 | JS = 4BE6 8 | -------------------------------------------------------------------------------- /driver.h: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) UQLX - see COPYRIGHT 3 | */ 4 | 5 | #define DRV_ID 0x4afc3339 6 | 7 | #define DRV_SIZE 0x80 /* leave space for 64 bit alignment */ 8 | #define DRV_OFF 24 /* reserved for QDOS */ 9 | #if 0 10 | #define ALIGNOFFSET(_off_) ((((long long)_off_ + 8 + DRV_OFF) >> 3) << 3) 11 | 12 | #define DGET_PRIV(_f_) (*(void **)ALIGNOFFSET(_f_)) 13 | #define DSET_PRIV(_f_, _p_) (*(void **)ALIGNOFFSET(_f_) = _p_) 14 | #define DGET_ID(_f_) (RL((w32 *)((Ptr)ALIGNOFFSET(_f_) + 8))) 15 | #define DSET_ID(_f_, _p_) (WL((w32 *)((Ptr)ALIGNOFFSET(_f_) + 8), _p_)) 16 | /*#define DGET_DRV(_f_) ( RL((w32 *)((Ptr)ALIGNOFFSET(_f_)+12)) ) */ 17 | /*#define DSET_DRV(_f_,_i_) ( WL((w32 *)((Ptr)ALIGNOFFSET(_f_)+12),_i_) ) */ 18 | #else 19 | #define ALIGNOFFSET(_xx_) ((Ptr)(_xx_) + DRV_OFF) 20 | #define DGET_PRIV(_f_) (GET_POINTER((w32 *)ALIGNOFFSET(_f_))) 21 | /*((void*)RL((w32*)ALIGNOFFSET(_f_)))*/ 22 | #define DSET_PRIV(_f_, _p_) (SET_POINTER((w32 *)ALIGNOFFSET(_f_), (_p_))) 23 | /*(WL((w32*)ALIGNOFFSET(_f_),(w32)(_p_)))*/ 24 | #define DGET_ID(_f_) (RL((w32 *)(ALIGNOFFSET(_f_) + 8))) 25 | #define DSET_ID(_f_, _p_) (WL((w32 *)(ALIGNOFFSET(_f_) + 8), _p_)) 26 | /*#define DGET_DRV(_f_) (RL((w32 *)(ALIGNOFFSET(_f_)+12))) */ 27 | /*#define DSET_DRV(_f_,_i_) (WL((w32 *)(ALIGNOFFSET(_f_)+12),_i_) ) */ 28 | #endif 29 | 30 | /* pointer to free format data */ 31 | /* use with extreme care !! */ 32 | #define DRV_EPRIV(_f_) ((w32 *)(ALIGNOFFSET(_f_) + 20)) 33 | 34 | typedef union { 35 | long i; 36 | char *s; 37 | } open_arg; 38 | 39 | /* Driver name definition, similar to ut.name */ 40 | struct PARENTRY { /* func may be parse_separator, parse_value or parse_option */ 41 | int (*func)(char **, /* rest name */ 42 | int, /* remaining namelen */ 43 | char *, /* option string*/ 44 | open_arg *, /* return values */ 45 | open_arg *); /*store at*/ 46 | char *opt; /* option string, default value or separator */ 47 | open_arg *values; /* default and/or return values for option*/ 48 | }; 49 | 50 | struct NAME_PARS { 51 | char *name; 52 | int pcount; 53 | struct PARENTRY *pars; 54 | }; 55 | 56 | struct DRV { 57 | w32 ref; /* driver addr in QL space, identifier*/ 58 | int (*init)(int, void *); /* called before driver link-in */ 59 | int (*open_test)(int, char *); /* name decoding */ 60 | int (*open)(int, void **); /* dev_open */ 61 | void (*close)(int, void *); /* dev_close */ 62 | void (*io)(int, void *); /* dev_io */ 63 | struct NAME_PARS *namep; /* device name for QPAC2 or intern use */ 64 | int slot; /* other driver specific info */ 65 | }; 66 | 67 | int decode_name(char *, struct NAME_PARS *, open_arg *); 68 | void io_handle(int (*io_read)(void *p, void *buf, int len), 69 | int (*io_write)(void *p, void *buf, int len), 70 | int (*io_pend)(Ptr priv), void *priv); 71 | 72 | int parse_separator(char **, int, char *, open_arg *, open_arg *); 73 | int parse_nseparator(char **, int, char *, open_arg *, open_arg *); 74 | int parse_value(char **, int, char *, open_arg *, open_arg *); 75 | int parse_option(char **, int, char *, open_arg *, open_arg *); 76 | int parse_mseparator(char **, int, char *, open_arg *, open_arg *); 77 | 78 | extern struct DRV Drivers[]; 79 | 80 | /* *************************************************************************** */ 81 | /* add driver local declarations here */ 82 | 83 | extern struct PARENTRY boot_pars[]; 84 | -------------------------------------------------------------------------------- /dummies.c: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) UQLX - see COPYRIGHT 3 | */ 4 | 5 | 6 | 7 | #include "QL68000.h" 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "uxfile.h" 15 | 16 | #define DUMMY(name,par) void name(par){/*printf("warning: calling dummy function: %s \n",__FUNCTION__);*/} 17 | 18 | size_t x_read(int fildes, void *buf, size_t byt) 19 | { 20 | int res; 21 | 22 | do 23 | res=read(fildes,buf,byt); 24 | while(res<=0 && byt>0 && eretry()); 25 | 26 | return res; 27 | } 28 | 29 | void ValidateDispByte(w32 addr){} 30 | 31 | void debug(char *msg) 32 | { 33 | #ifdef DEBUG 34 | printf("%s\n",msg); 35 | #endif 36 | } 37 | void debug2(char *msg, long n) 38 | { 39 | #ifdef DEBUG 40 | printf("%s\t%x\n",msg,n); 41 | #endif 42 | } 43 | 44 | /*#define DEBUG_IPC*/ 45 | void debugIPC(char *msg, long n) 46 | { 47 | #ifdef DEBUG_IPC 48 | printf("%s\t%x\n",msg,n); 49 | /*DbgInfo();*/ 50 | #endif 51 | } 52 | 53 | 54 | 55 | 56 | DUMMY(HFlushFile,void); 57 | DUMMY(HQRead,void) 58 | DUMMY(HRewriteHeader,void) 59 | DUMMY(HKillFileTail,void) 60 | DUMMY(HGetFileHeader,void) 61 | DUMMY(HQWrite,void) 62 | 63 | DUMMY(InstallSerial,void) 64 | DUMMY(NoteAlert,void) 65 | DUMMY(DiskEject,void) 66 | 67 | DUMMY(CautionAlert,void) 68 | DUMMY(MemError,void) 69 | DUMMY(GetEOF,void) 70 | DUMMY(StopAlert,void) 71 | 72 | void ErrorAlert(int x){} 73 | void CustomErrorAlert(char *x){} 74 | 75 | #define min(_a_,_b_) (_a_<_b_ ? _a_ : _b_) 76 | 77 | 78 | #ifdef NEEDS_STRNCPY 79 | char *strncpy(char *dest, const char *src, size_t n) 80 | { 81 | int slen=1+strlen(src); 82 | memcpy(dest,src,min(n,slen)); 83 | } 84 | #endif 85 | 86 | 87 | #ifndef SERIAL 88 | Cond SetBaudRate(short dummy) 89 | { 90 | return 1; 91 | } 92 | #endif 93 | 94 | 95 | void * NewPtr(long need) 96 | { 97 | return (void *)malloc(need); 98 | } 99 | 100 | 101 | int Random() 102 | { 103 | #ifdef __WIN32__ 104 | return rand(); 105 | #else 106 | return random(); 107 | #endif 108 | } 109 | 110 | #ifdef NEED_STRNCASECMP 111 | int strncasecmp(char *s1,char *s2,int len) 112 | { 113 | while (*s1 || *s2 && len--) 114 | { 115 | if (tolower(*s1++)==tolower(*s2++)) continue; 116 | else return 1; /* don't care which is really greater */ 117 | } 118 | if (tolower(*s1)==tolower(*s2)) return 0; /* TRUE */ 119 | } 120 | #endif 121 | 122 | 123 | void BlockMoveData(void *source, void *dest,long len) 124 | { 125 | #ifndef NO_MEMMOVE 126 | memmove(dest,source,len); 127 | #else 128 | bcopy(source,dest,len); 129 | #endif 130 | } 131 | 132 | -------------------------------------------------------------------------------- /dummies.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef DUMMIES_H 3 | #define DUMMIES_H 4 | 5 | size_t x_read(int fildes, void *buf, size_t byt); 6 | void debug(char *msg); 7 | void debug2(char *msg, long n); 8 | void debugIPC(char *msg, long n); 9 | void BlockMoveData(void *source, void *dest,long len); 10 | void ErrorAlert(int x); 11 | void CustomErrorAlert(char *x); 12 | 13 | #ifndef __WIN32__ 14 | #define O_BINARY 0 15 | #endif 16 | 17 | #endif /* DUMMIES_H */ 18 | -------------------------------------------------------------------------------- /emudisk.h: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) UQLX - see COPYRIGHT 3 | */ 4 | 5 | 6 | #ifndef __emudisk_h 7 | #define __emudisk_h 8 | 9 | /* Emulated device structure */ 10 | 11 | /* Where has new meaning : 12 | * 0: unixfilesys 13 | * 1: QL floppy/QXL.WIN 14 | * 2: unixfilesys, case-insensitive 15 | */ 16 | 17 | typedef struct 18 | { 19 | char *qname; 20 | char Where[8]; 21 | char Present[8]; 22 | short OpenFiles[8]; 23 | struct mdvFile *FileList[8]; 24 | struct HF_FCB *fcbList[8]; 25 | const char *mountPoints[8]; 26 | int clean[8]; 27 | struct FLP_FCB *flpp[8]; 28 | int ref; 29 | } EMUDEV_t; 30 | 31 | extern EMUDEV_t qdevs[]; 32 | #define MAXDEV 16 33 | 34 | /* 6/12/97 RZ removed non-essential defaults */ 35 | 36 | #ifdef STATICDEVS 37 | EMUDEV_t qdevs[16] = { 38 | #if 0 39 | {"FLP", {0}, {1,1,0,0,0,0,0,0}, {0}, {NULL}, {NULL}, 40 | {"/ql/qldata/","/ql/qlsoft/"},{0},{0},0}, 41 | {"WIN", {0}, {1,1,1,0,0,0,0,0}, {0}, {NULL}, {NULL}, 42 | {HOME,"/","/ql/"},{0},{0},0}, 43 | #endif 44 | #if 0 45 | {"RAM", {0}, {1,1,1,1,1,1,1,1}, {0}, {NULL}, {NULL}, 46 | { 47 | "/tmp/.ram1/","/tmp/.ram2/", 48 | "/tmp/.ram3/","/tmp/.ram4/", 49 | "/tmp/.ram5/","/tmp/.ram6/", 50 | "/tmp/.ram7/","/tmp/.ram8/",},{0,0,0,0,0,0,0,0},{0},0}, 51 | #endif 52 | #if 0 53 | {"CD", {0}, {1,0,0,0,0,0,0,0}, {0}, {NULL}, {NULL}, 54 | {"/cdrom/"},{0},{0},0}, 55 | {"MS", {0}, {1,0,0,0,0,0,0,0}, {0}, {NULL}, {NULL}, 56 | {"/a/"},{0},{0},0}, 57 | #endif 58 | {0} 59 | }; 60 | 61 | #endif 62 | #endif 63 | -------------------------------------------------------------------------------- /examples/mdv1/BOOT: -------------------------------------------------------------------------------- 1 | 100 REMark sQLux 2 | 110 OPEN #4,con_512x202a0x0 3 | 120 BORDER #4,2,4,2 4 | 130 PAPER #4,2:INK#4,7 5 | 140 CLS #4 6 | 150 AT #4, 1,9 7 | 160 CSIZE #4, 3,1 8 | 170 PRINT #4, "Welcome to sQLux" 9 | 180 CSIZE #4,0,0 10 | 190 PRINT #4 11 | 200 PRINT_RELEASE 12 | 210 PRINT #4 13 | 220 PRINT #4 14 | 230 PRINT #4," Date",DATE$,"QDOS version:",VER$ 15 | 240 PRINT #4 16 | 250 PRINT #4," Ram Size: ";(PEEK_L(163872)/1024 - 128);"k" 17 | 260 PRINT #4 18 | 270 PRINT #4," Start as: '";getXarg$(0);" -h' to get a list of startup options" 19 | 275 PRINT #4 20 | 280 PRINT #4," Quit with: kill_uqlx" 21 | 290 CSIZE #4,0,0 22 | 300 PRINT #4 23 | 310 PRINT #4," .... press any key" 24 | 320 PAUSE 25 | 321 CLS #4 26 | 322 CLOSE #4 27 | 350 WINDOW #1,256,202,256,0 28 | 360 WINDOW #2,256,202,0,0 29 | 361 CLS #1 30 | 362 CLS #2 31 | 372 : 32 | 400 DEFine PROCedure PRINT_RELEASE 33 | 410 STRIP #4,0 34 | 420 AT #4,4,11 35 | 430 PRINT #4,"release"!!UQLX_RELEASE$ 36 | 440 STRIP #4,2 37 | 450 END DEFine 38 | 460 : 39 | 470 DEFine PROCedure sa 40 | 480 DELETE 'mdv1_BOOT' 41 | 490 SAVE 'mdv1_BOOT' 42 | 500 END DEFine 43 | -------------------------------------------------------------------------------- /examples/mdv1/TK232_net.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SinclairQL/sQLux/79aa52decf115d79af328f62ca5563e7f5f916be/examples/mdv1/TK232_net.bin -------------------------------------------------------------------------------- /examples/mdv2/PTY_TEST_BAS: -------------------------------------------------------------------------------- 1 | 10 open#6,pty_csh 2 | 20 print#6,"ls -al" 3 | 30 print#6,"exit" 4 | 40 repeat xx 5 | 50 if eof(#6) :exit xx 6 | 60 input#6,a$:print a$ 7 | 70 end repeat xx 8 | 80 close#6 9 | -------------------------------------------------------------------------------- /examples/mdv2/rotate_asm: -------------------------------------------------------------------------------- 1 | sd_extop EQU $9 2 | mt_inf EQU $0 3 | 4 | start bra plot_init ; Call start to initialise things 5 | 6 | *------------------------------------------------------------------------------- 7 | * Rotate pixels: 8 | * 9 | * Assumes Mode 4 10 | * On Each iteration Black -> Green -> Red -> White -> Black etc 11 | * for a specififed number of display lines at top of screen 12 | * On entry: 13 | * D1 = the number of iterations. If < 1 return immediately 14 | * D2 = Number of display lines to swap. If > 4000 or < 1 return immediately 15 | * D3 = Real writes to screen if != 0 , dummy writes otherwise 16 | * 17 | * Note: This code deliberately writes to screen memory 1 byte at a time to 18 | * maximise the number of individual screen memory writes 19 | *------------------------------------------------------------------------------- 20 | entry subq.w #1,d1 ; Correct for dbra 21 | blt.s finished ; positive number of iterations? 22 | 23 | cmpi.w #4000,d2 ; too large? 24 | bgt.s finished 25 | subq.w #1,d2 ; correct for dbra 26 | blt.s finished ; positive number of lines? 27 | 28 | bsr.s calc ; Get A1 = screen address 29 | lsr.w #1,d6 ; Reading Red and Green bytes each iteration 30 | subq.w #1,d6 ; dbra stops at -1 31 | 32 | tst.w d3 ; real pixel rotate, or dummy? 33 | beq.s dummy_ent 34 | 35 | quick movea.l a1,a2 ; Initialise working screen address 36 | move.w d2,d4 ; num of lines to swap 37 | 38 | row move.w d6,d5 39 | 40 | column move.b (a2),d0 ; Get the green 41 | move.b 1(a2),d3 ; Get the red 42 | 43 | eor.w d0,d3 ; Rotate the colours 44 | not.w d0 45 | 46 | move.b d0,(a2)+ ; Write them back 47 | move.b d3,(a2)+ 48 | 49 | dbra d5,column 50 | dbra d4,row 51 | dbra d1,quick 52 | 53 | finished moveq #0,d0 54 | rts 55 | 56 | * 57 | * Dummy writes. This copies part of the code above, to minimise the 58 | * timing differences between the real screen writes and dummy writes 59 | * 60 | 61 | dummy_ent lea dummy_scr,a0 ; Set the dummy memory for writes 62 | 63 | dummy movea.l a1,a2 ; Initialise working screen address 64 | move.w d2,d4 ; num of lines to swap 65 | 66 | row1 move.w d6,d5 67 | 68 | column1 move.b (a2)+,d0 ; Get the green 69 | move.b (a2)+,d3 ; Get the red 70 | 71 | eor.w d0,d3 ; Rotate the colours 72 | not.w d0 73 | 74 | move.b d0,(a0) ; Dummy Writes 75 | move.b d3,1(a0) 76 | 77 | dbra d5,column1 78 | dbra d4,row1 79 | dbra d1,dummy 80 | 81 | bra.s finished 82 | 83 | dummy_scr ds.w 1 ; address for dummy writes 84 | 85 | *------------------------------------------------------------------------------- 86 | * Returns the start of display memory in a1, and the screen width (in bytes) 87 | * in d6 88 | * The routine plot_init must have been called to initialise the screen addresses 89 | * and scan line widths BEFORE calling this routine. 90 | *------------------------------------------------------------------------------- 91 | calc lea scr_base,a1 ; Where we hold the screen base address 92 | move.l (a1)+,d0 ; Fetch the screen base address 93 | move.w (a1),d6 ; And the scan line size 94 | movea.l d0,a1 ; Get the screen base where we want it 95 | rts 96 | *------------------------------------------------------------------------------- 97 | * This routine must be called once before using the above plot routines. It 98 | * initialises the screen base address and scan line width from the channel 99 | * definition block for SuperBasic channel #0. 100 | *------------------------------------------------------------------------------- 101 | plot_init suba.l a0,a0 ; Channel id for #0 is always 0 102 | lea scr_base,a1 ; Parameter passed to extop routine 103 | lea extop,a2 ; Actual routine to call 104 | moveq #sd_extop,d0 ; Trap code 105 | moveq #-1,d3 ; Timout 106 | trap #3 ; Do it 107 | tst.l d0 ; OK ? 108 | bne.s done ; No, bale out D1 = A1 = garbage 109 | 110 | got_them move.w d1,-(a7) ; Need to check qdos, save scan_line 111 | moveq #mt_inf,d0 ; Trap to get qdos version (preseves A1) 112 | trap #1 ; Get it (no errors) 113 | move.w (a7)+,d1 ; Retrieve scan_line value 114 | andi.l #$ff00ffff,d2 ; D2 = qdos, mask out the dot in "1.03" etc 115 | cmpi.l #$31003034,d2 ; Test for "1?03" where ? = don't care 116 | bcs.s too_old ; Less than 1.03 is too old 117 | 118 | save move.w d1,(a1) ; Store the scan_line size 119 | 120 | done rts ; Finished 121 | 122 | too_old move.w #128,d1 ; Must be 128 bytes 123 | bra.s save ; Save D1 and exit 124 | 125 | extop move.l $32(a0),(a1)+ ; Fetch the scan_line length & store it 126 | move.w $64(a0),d1 ; Fetch the screen base - don't store it 127 | moveq #0,d0 ; No errors 128 | rts ; done 129 | 130 | *------------------------------------------------------------------------------- 131 | * Set aside some storage space to hold the screen base and scan_line width. This 132 | * saves having to calculate it every time we plot a single pixel. 133 | *------------------------------------------------------------------------------- 134 | scr_base ds.l 1 135 | scan_line ds.w 1 136 | 137 | end 138 | 139 | -------------------------------------------------------------------------------- /examples/mdv2/rotate_bas: -------------------------------------------------------------------------------- 1 | 100 REMark Test time to flip pixels on screen 2 | 110 MODE 4 3 | 120 rotate_init = RESPR (256) 4 | 130 rotate_screen = rotate_init + 4 5 | 140 LBYTES mdv2_rotate_code, rotate_init 6 | 150 CALL rotate_init 7 | 160 iterations = 20000 8 | 170 screen_lines = 256 9 | 180 PRINT "Iterations: ";iterations 10 | 190 PRINT "Screen lines: ";screen_lines 11 | 200 PRINT "Rotate: "; 12 | 210 r = DATE 13 | 220 REPeat loop:IF r < DATE THEN EXIT loop 14 | 230 r=DATE 15 | 240 CALL rotate_screen,iterations,screen_lines,1 16 | 250 r = DATE - r 17 | 260 PRINT r;" seconds" 18 | 270 PRINT "Dummy: "; 19 | 280 d = DATE 20 | 290 REPeat loop:IF d < DATE THEN EXIT loop 21 | 300 d = DATE 22 | 310 CALL rotate_screen,iterations,screen_lines,0 23 | 320 d = DATE - d 24 | 330 PRINT d;" seconds" 25 | 340 taken = r - d 26 | 350 IF taken < 0 THEN taken = 0 27 | 360 PRINT "Time for writes: ";taken; " second(s)" 28 | -------------------------------------------------------------------------------- /examples/mdv2/rotate_code: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SinclairQL/sQLux/79aa52decf115d79af328f62ca5563e7f5f916be/examples/mdv2/rotate_code -------------------------------------------------------------------------------- /examples/mdv3/BOOT: -------------------------------------------------------------------------------- 1 | 100 LRUN mdv3_qlmires_bas 2 | -------------------------------------------------------------------------------- /examples/mdv3/QLMIRES_Txt: -------------------------------------------------------------------------------- 1 | PROGRAM: QLMIRES (QLCF software library) 2 | 3 | LANGUAGE: SuperBASIC 4 | 5 | AUTHOR: Alain Piot - QLCF member no. 87105 6 | 7 | As its name indicates, QLMIRES is a testcard-generating program, 8 | intended to control and adjust monochrome or colour monitors (or 9 | possibly televisions.) After beginning with LRUN flp1_qlmires, five 10 | choices are offered: 11 | 12 | F1 : Testcard 1 - bar pattern 13 | F2 : Testcard 2 - circle pattern 14 | F3 : Testcard 3 - colour pattern 15 | F4 : Testcard 4 - composite pattern 16 | F5 : Return to basic 17 | 18 | These options are available from within each pattern. 19 | 20 | All of the patterns are on a plain screen, which is to say using the 21 | total available QL screen area, in order to enable adjustment of the 22 | coverage of a monitor. It's perhaps then possible to recover the three 23 | or four characters missed on the right of the screen. The other 24 | adjustments one can try, such as linearity, colour balance, focussing, 25 | convergence etc. 26 | 27 | WARNING: To everyone not familiar with the working of televisions and 28 | monitors. Certain adjustments necessitate the opening of the cover of 29 | the display unit. This one should not attempt except after noting two 30 | points: - certain adjustments are difficult for beginners to make 31 | without the necessary electronic equipment. - very high voltages (15000 32 | to 25000V) are always present inside this apparatus, and can do much 33 | harm. Most of these voltages persist long after being switched off. 34 | 35 | -------------------------------------------------------------------------------- /examples/mdv3/QLMIRES_bas: -------------------------------------------------------------------------------- 1 | 100 REMark PIOT Alain - N� 87105 2 | 110 REMark Logitheque QLCF. 3 | 120 REMark ----------------------------- 4 | 130 REMark PROGRAMME GENERATEUR DE MIRES 5 | 140 REMark ----------------------------- 6 | 150 MODE 8 7 | 160 OPEN #10,scr_120x50a196x103 8 | 170 PAPER #10,7 : INK #10,0 9 | 180 OPEN #11,scr_512x256a0x0 10 | 190 PAPER #11,0 : INK #11,7 : CLS #11 11 | 200 affich 12 | 210 REPeat saisie 13 | 220 cle=KEYROW(0) 14 | 230 SELect ON cle 15 | 240 =2 : BEEP 500,20 : CLS #11 : mire_bar : affich 16 | 250 =8 : BEEP 500,20 : CLS #11 : mire_bar : mire_cer : affich 17 | 260 =16 : BEEP 500,20 : CLS #11 : mire_cou : affich 18 | 270 =1 : BEEP 500,20 : CLS #11 : mire_bar : mire_cer : mire_cmp : affich 19 | 280 =32 : BEEP 500,20 : retour 20 | 290 END SELect 21 | 300 END REPeat saisie 22 | 310 REMark **** AFFICHAGE DES OPTIONS **** 23 | 320 DEFine PROCedure affich 24 | 330 CLS #10 25 | 340 PRINT #10,"F1: MIRE 1" 26 | 350 PRINT #10,"F2: MIRE 2" 27 | 360 PRINT #10,"F3: MIRE 3" 28 | 370 PRINT #10,"F4: MIRE 4" 29 | 380 PRINT #10,"F5: RETOUR" 30 | 390 END DEFine 31 | 400 REMark **** MIRE DE BARRES (No 1) **** 32 | 410 DEFine PROCedure mire_bar 33 | 420 FOR hori=0 TO 100 STEP 10 : LINE #11,0,hori TO 148,hori 34 | 430 FOR vert=0 TO 148 STEP 10.55 : LINE #11,vert,0 TO vert,100 35 | 440 END DEFine 36 | 450 REMark *** MIRE DE CERCLES (No 2) **** 37 | 460 DEFine PROCedure mire_cer 38 | 470 INK #11,0 : FILL #11,1 : CIRCLE #11,10.55,10,10 : FILL #11,0 : INK #11,7 : CIRCLE #11,10.55,10,10 39 | 480 FILL #11,1 : CIRCLE #11,10.55,10,5 : FILL #11,0 40 | 490 INK #11,0 : FILL #11,1 : CIRCLE #11,137.15,10,10 : FILL #11,0 : INK #11,7 : CIRCLE #11,137.15,10,10 41 | 500 FILL #11,1 : CIRCLE #11,137.15,10,5 : FILL #11,0 42 | 510 INK #11,0 : FILL #11,1 : CIRCLE #11,10.55,90,10 : FILL #11,0 : INK #11,7 : CIRCLE #11,10.55,90,10 43 | 520 FILL #11,1 : CIRCLE #11,10.55,90,5 : FILL #11,0 44 | 530 INK #11,0 : FILL #11,1 : CIRCLE #11,137.15,90,10 : FILL #11,0 : INK #11,7 : CIRCLE #11,137.15,90,10 45 | 540 FILL #11,1 : CIRCLE #11,137.15,90,5 : FILL #11,0 46 | 550 INK #11,0 : FILL #11,1 : CIRCLE #11,73.85,50,47.5 : FILL #11,0 : INK #11,7 : CIRCLE #11,73.85,50,47.5 47 | 560 END DEFine 48 | 570 REMark * MIRE COULEUR he oui! (No 3) * 49 | 580 DEFine PROCedure mire_cou 50 | 590 coul=7 : RESTORE 51 | 600 FOR vert=0 TO 500 STEP 64 52 | 610 BLOCK #11,64,256,vert,0,coul 53 | 620 READ centr : CURSOR #11,vert+centr,10 : READ nom$ : PRINT #11,nom$ 54 | 630 coul=coul-1 55 | 640 END FOR vert 56 | 650 END DEFine 57 | 660 DATA 2,"blanc",2,"jaune",8,"cyan",8,"vert",2,"magen",2,"rouge",8,"bleu",8,"noir" 58 | 670 REMark **** MIRE COMPOSITE (No 4) **** 59 | 680 DEFine PROCedure mire_cmp 60 | 690 BLOCK #11,174,26,168,25,7 61 | 700 CSIZE #11,3,1 : CURSOR #11,216,28 : PRINT #11," Q L " 62 | 710 BLOCK #11,182,26,164,204,7 63 | 720 CURSOR #11,192,207 : PRINT #11,"SINCLAIR" 64 | 730 CSIZE #11,2,0 : coul=6 65 | 740 FOR vert=107 TO 400 STEP 49.6 66 | 750 BLOCK #11,50,38,vert,76,coul 67 | 760 coul=coul-1 68 | 770 END FOR vert 69 | 780 FOR vert=110 TO 168 STEP 12 : BLOCK #11,6,38,vert,141,7 70 | 790 FOR vert=170 TO 226 STEP 8 : BLOCK #11,4,38,vert,141,7 71 | 800 FOR vert=228 TO 284 STEP 4 : BLOCK #11,2,38,vert,141,7 72 | 810 FOR vert=286 TO 342 STEP 8 : BLOCK #11,4,38,vert,141,7 73 | 820 FOR vert=344 TO 400 STEP 12 : BLOCK #11,6,38,vert,141,7 74 | 830 LINE #11,26,50 TO 121,50 75 | 840 FOR vert=31.65 TO 116.05 STEP 10.55 : LINE #11,vert,45 TO vert,55.5 76 | 850 FOR vert=128 TO 380 STEP 34 : BLOCK #11,16,25,vert,51,7 77 | 860 BLOCK #11,50,25,156,179,0,7,0 78 | 870 BLOCK #11,50,25,206,179,0,7,3 79 | 880 BLOCK #11,50,25,256,179,7,0,3 80 | 890 BLOCK #11,50,25,304,179,7,0,0 81 | 900 BLOCK #11,28,25,354,179,7 82 | 910 END DEFine 83 | 920 REMark ******* RETOUR AU BASIC ******* 84 | 930 DEFine PROCedure retour 85 | 940 CLOSE #10 : CLOSE #11 86 | 950 MODE 4 87 | 960 BORDER 1,7,0 : CLS 88 | 970 BORDER #2,1,7,0 : CLS #2 89 | 980 AT #0,0,12 : PRINT #0,"Vous pouvez relancer le programme par RUN, sinon tapez NEW." 90 | 990 STOP 91 | 1000 END DEFine 92 | -------------------------------------------------------------------------------- /examples/mdv3/QLMIRES_doc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SinclairQL/sQLux/79aa52decf115d79af328f62ca5563e7f5f916be/examples/mdv3/QLMIRES_doc -------------------------------------------------------------------------------- /examples/mdv3/testcard_bas: -------------------------------------------------------------------------------- 1 | 100 REMark PIOT Alain - N� 87105 2 | 110 REMark Logitheque QLCF. 3 | 115 REMark Translated 16.04.90 by Phil Barker 4 | 120 REMark ----------------------------- 5 | 130 REMark PROGRAMME GENERATEUR DE MIRES 6 | 140 REMark ----------------------------- 7 | 150 MODE 8 8 | 160 OPEN #10,scr_120x50a196x103 9 | 170 PAPER #10,7 : INK #10,0 10 | 180 OPEN #11,scr_512x256a0x0 11 | 190 PAPER #11,0 : INK #11,7 : CLS #11 12 | 200 affich 13 | 210 REPeat saisie 14 | 220 cle=KEYROW(0) 15 | 230 SELect ON cle 16 | 240 =2 : BEEP 500,20 : CLS #11 : mire_bar : affich 17 | 250 =8 : BEEP 500,20 : CLS #11 : mire_bar : mire_cer : affich 18 | 260 =16 : BEEP 500,20 : CLS #11 : mire_cou : affich 19 | 270 =1 : BEEP 500,20 : CLS #11 : mire_bar : mire_cer : mire_cmp : affich 20 | 280 =32 : BEEP 500,20 : retour 21 | 290 END SELect 22 | 300 END REPeat saisie 23 | 310 REMark **** AFFICHAGE DES OPTIONS **** 24 | 320 DEFine PROCedure affich 25 | 330 CLS #10 26 | 340 PRINT #10,"F1: CARD 1" 27 | 350 PRINT #10,"F2: CARD 2" 28 | 360 PRINT #10,"F3: CARD 3" 29 | 370 PRINT #10,"F4: CARD 4" 30 | 380 PRINT #10,"F5: RETURN" 31 | 390 END DEFine 32 | 400 REMark **** MIRE DE BARRES (No 1) **** 33 | 410 DEFine PROCedure mire_bar 34 | 420 FOR hori=0 TO 100 STEP 10 : LINE #11,0,hori TO 148,hori 35 | 430 FOR vert=0 TO 148 STEP 10.55 : LINE #11,vert,0 TO vert,100 36 | 440 END DEFine 37 | 450 REMark *** MIRE DE CERCLES (No 2) **** 38 | 460 DEFine PROCedure mire_cer 39 | 470 INK #11,0 : FILL #11,1 : CIRCLE #11,10.55,10,10 : FILL #11,0 : INK #11,7 : CIRCLE #11,10.55,10,10 40 | 480 FILL #11,1 : CIRCLE #11,10.55,10,5 : FILL #11,0 41 | 490 INK #11,0 : FILL #11,1 : CIRCLE #11,137.15,10,10 : FILL #11,0 : INK #11,7 : CIRCLE #11,137.15,10,10 42 | 500 FILL #11,1 : CIRCLE #11,137.15,10,5 : FILL #11,0 43 | 510 INK #11,0 : FILL #11,1 : CIRCLE #11,10.55,90,10 : FILL #11,0 : INK #11,7 : CIRCLE #11,10.55,90,10 44 | 520 FILL #11,1 : CIRCLE #11,10.55,90,5 : FILL #11,0 45 | 530 INK #11,0 : FILL #11,1 : CIRCLE #11,137.15,90,10 : FILL #11,0 : INK #11,7 : CIRCLE #11,137.15,90,10 46 | 540 FILL #11,1 : CIRCLE #11,137.15,90,5 : FILL #11,0 47 | 550 INK #11,0 : FILL #11,1 : CIRCLE #11,73.85,50,47.5 : FILL #11,0 : INK #11,7 : CIRCLE #11,73.85,50,47.5 48 | 560 END DEFine 49 | 570 REMark * MIRE COULEUR he oui! (No 3) * 50 | 580 DEFine PROCedure mire_cou 51 | 590 coul=7 : RESTORE 52 | 600 FOR vert=0 TO 500 STEP 64 53 | 610 BLOCK #11,64,256,vert,0,coul 54 | 620 READ centr : CURSOR #11,vert+centr,10 : READ nom$ : PRINT #11,nom$ 55 | 630 coul=coul-1 56 | 640 END FOR vert 57 | 650 END DEFine 58 | 660 DATA 2,"white",2,"yellow",8,"cyan",8,"green",2,"magen",2,"red",8,"blue",8,"black" 59 | 670 REMark **** MIRE COMPOSITE (No 4) **** 60 | 680 DEFine PROCedure mire_cmp 61 | 690 BLOCK #11,174,26,168,25,7 62 | 700 CSIZE #11,3,1 : CURSOR #11,216,28 : PRINT #11," Q L " 63 | 710 BLOCK #11,182,26,164,204,7 64 | 720 CURSOR #11,192,207 : PRINT #11,"SINCLAIR" 65 | 730 CSIZE #11,2,0 : coul=6 66 | 740 FOR vert=107 TO 400 STEP 49.6 67 | 750 BLOCK #11,50,38,vert,76,coul 68 | 760 coul=coul-1 69 | 770 END FOR vert 70 | 780 FOR vert=110 TO 168 STEP 12 : BLOCK #11,6,38,vert,141,7 71 | 790 FOR vert=170 TO 226 STEP 8 : BLOCK #11,4,38,vert,141,7 72 | 800 FOR vert=228 TO 284 STEP 4 : BLOCK #11,2,38,vert,141,7 73 | 810 FOR vert=286 TO 342 STEP 8 : BLOCK #11,4,38,vert,141,7 74 | 820 FOR vert=344 TO 400 STEP 12 : BLOCK #11,6,38,vert,141,7 75 | 830 LINE #11,26,50 TO 121,50 76 | 840 FOR vert=31.65 TO 116.05 STEP 10.55 : LINE #11,vert,45 TO vert,55.5 77 | 850 FOR vert=128 TO 380 STEP 34 : BLOCK #11,16,25,vert,51,7 78 | 860 BLOCK #11,50,25,156,179,0,7,0 79 | 870 BLOCK #11,50,25,206,179,0,7,3 80 | 880 BLOCK #11,50,25,256,179,7,0,3 81 | 890 BLOCK #11,50,25,304,179,7,0,0 82 | 900 BLOCK #11,28,25,354,179,7 83 | 910 END DEFine 84 | 920 REMark ******* RETOUR AU BASIC ******* 85 | 930 DEFine PROCedure retour 86 | 940 CLOSE #10 : CLOSE #11 87 | 950 MODE 4 88 | 960 BORDER 1,7,0 : CLS 89 | 970 BORDER #2,1,7,0 : CLS #2 90 | 980 AT #0,0,12 : PRINT #0,"You can restart the program with RUN, otherwise type NEW." 91 | 990 STOP 92 | 1000 END DEFine 93 | -------------------------------------------------------------------------------- /examples/sqlux.ini: -------------------------------------------------------------------------------- 1 | SYSROM = Minerva_1.98a1.bin 2 | ROMIM = TK236.rom 3 | RAMTOP = 4096 4 | FAST_STARTUP = 1 5 | # DEVICE = FLP1,198ad.img,qdos-native 6 | # DEVICE = WIN1,ql_demo.win,qdos-fs 7 | DEVICE = MDV1,mdv1/,qdos-like 8 | DEVICE = MDV2,mdv2/,qdos-like 9 | DEVICE = MDV3,mdv3/,qdos-like 10 | BOOT_DEVICE = MDV3 11 | WIN_SIZE = 2x 12 | FILTER = 1 13 | FIXASPECT = 1 14 | SPEED = 1 15 | -------------------------------------------------------------------------------- /general.h: -------------------------------------------------------------------------------- 1 | #ifndef _GENERAL_H 2 | #define _GENERAL_H 3 | 4 | void WriteHWByte(aw32 addr, aw8 d); 5 | rw8 ReadHWByte(aw32 addr); 6 | rw16 ReadHWWord(aw32 addr); 7 | void WriteHWWord(aw32 addr, aw16 d); 8 | rw32 ReadHWLong(aw32 addr); 9 | 10 | #endif /* _GENERAL_H */ 11 | -------------------------------------------------------------------------------- /generate_version.cmake: -------------------------------------------------------------------------------- 1 | # Git executable is extracted from parameters. 2 | execute_process(COMMAND ${GIT_EXECUTABLE} describe --tags --always 3 | OUTPUT_VARIABLE GIT_REPO_VERSION 4 | OUTPUT_STRIP_TRAILING_WHITESPACE) 5 | execute_process(COMMAND date +%Y-%m-%d 6 | OUTPUT_VARIABLE BUILD_DATE 7 | OUTPUT_STRIP_TRAILING_WHITESPACE) 8 | 9 | if(GIT_REPO_VERSION STREQUAL "") 10 | execute_process(COMMAND kacl-cli -f ${CHANGELOG_FILE} current 11 | OUTPUT_VARIABLE KACL_VERSION 12 | OUTPUT_STRIP_TRAILING_WHITESPACE 13 | ) 14 | set(GIT_REPO_VERSION v${KACL_VERSION}) 15 | message(WARNING "Setting version from CHANGELOG.md using kacl-cli.") 16 | endif() 17 | 18 | if(GIT_REPO_VERSION STREQUAL "v") 19 | set(GIT_REPO_VERSION v0.0.0-unknown) 20 | message(WARNING "Failed to determine version from Git tags or kacl-cli. Using default version \"${GIT_REPO_VERSION}\".") 21 | endif() 22 | 23 | # Input and output files are extracted from parameters. 24 | configure_file(${INPUT_FILE} ${OUTPUT_FILE}) 25 | 26 | -------------------------------------------------------------------------------- /hexdump.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // Usage: 4 | // hexDump(desc, addr, len, perLine); 5 | // desc: if non-NULL, printed as a description before hex dump. 6 | // addr: the address to start dumping from. 7 | // len: the number of bytes to dump. 8 | // perLine: number of bytes on each output line. 9 | // offset: add this to address 10 | 11 | void hexDump(const char *desc, const void *addr, const int len, 12 | const int perLine, const int offset) 13 | { 14 | int i; 15 | unsigned char buff[perLine + 1]; 16 | const unsigned char *pc = (const unsigned char *)addr; 17 | 18 | // Output description if given. 19 | 20 | if (desc != NULL) 21 | printf("%s:\n", desc); 22 | 23 | // Length checks. 24 | 25 | if (len == 0) { 26 | printf(" ZERO LENGTH\n"); 27 | return; 28 | } 29 | if (len < 0) { 30 | printf(" NEGATIVE LENGTH: %d\n", len); 31 | return; 32 | } 33 | 34 | // Process every byte in the data. 35 | 36 | for (i = 0; i < len; i++) { 37 | // Multiple of perLine means new or first line (with line offset). 38 | 39 | if ((i % perLine) == 0) { 40 | // Only print previous-line ASCII buffer for lines beyond first. 41 | 42 | if (i != 0) 43 | printf(" %s\n", buff); 44 | 45 | // Output the offset of current line. 46 | 47 | printf(" %06x ", i + offset); 48 | } 49 | 50 | // Now the hex code for the specific character. 51 | 52 | printf(" %02x", pc[i]); 53 | 54 | // And buffer a printable ASCII character for later. 55 | 56 | if ((pc[i] < 0x20) || 57 | (pc[i] > 0x7e)) // isprint() may be better. 58 | buff[i % perLine] = '.'; 59 | else 60 | buff[i % perLine] = pc[i]; 61 | buff[(i % perLine) + 1] = '\0'; 62 | } 63 | 64 | // Pad out last line if not exactly perLine characters. 65 | 66 | while ((i % perLine) != 0) { 67 | printf(" "); 68 | i++; 69 | } 70 | 71 | // And print the final ASCII buffer. 72 | 73 | printf(" %s\n", buff); 74 | } 75 | -------------------------------------------------------------------------------- /iexl.h: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) UQLX - see COPYRIGHT 3 | */ 4 | 5 | 6 | #define ENTER_IEXL 7 | #define EXIT_IEXL 8 | #define CALLOUT_IEXL(_call_) _call_; 9 | -------------------------------------------------------------------------------- /iexl_general.h: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) UQLX - see COPYRIGHT 3 | */ 4 | #ifndef IEXL_GENERAL_H 5 | #define IEXL_GENERAL_H 6 | 7 | #include "QL68000.h" 8 | 9 | void ExecuteChunk(long); 10 | void InitialSetup(void); 11 | void ExceptionProcessing(void); 12 | 13 | #define RewriteEA_b(_d_) (*((w8*)dest)=_d_) 14 | 15 | #if 0 16 | static REGP1 inline void RewriteEA_b(aw8 d) 17 | { 18 | *((w8*)dest)=d; 19 | } 20 | #endif 21 | 22 | 23 | #if 1 24 | #ifdef QM_BIG_ENDIAN 25 | #define RewriteEA_w(_d_) (WW((Ptr)dest,_d_)) 26 | #else /* little endian */ 27 | #define RewriteEA_w(_d_) {if (isreg) *((w16*)dest)=_d_; \ 28 | else WW((Ptr)dest,_d_);} 29 | #endif 30 | #else 31 | static inline void RewriteEA_w(aw16 d) 32 | { 33 | #ifndef QM_BIG_ENDIAN 34 | if (isreg) *((w16*)dest)=d; 35 | else 36 | #endif 37 | WW((Ptr)dest,d); 38 | } 39 | #endif 40 | 41 | #if 1 42 | #ifdef QM_BIG_ENDIAN 43 | #define RewriteEA_l(_d_) (WL((Ptr)dest,_d_)) 44 | #else /* little endian */ 45 | #define RewriteEA_l(_d_) {if (isreg) *((w32*)dest)=_d_; \ 46 | else WL((Ptr)dest,_d_);} 47 | #endif 48 | #else 49 | static inline void RewriteEA_l(aw32 d) 50 | { 51 | #ifndef QM_BIG_ENDIAN 52 | if (isreg) *((w32*)dest)=d; 53 | else 54 | #endif 55 | WL((Ptr)dest,d); 56 | 57 | } 58 | #endif 59 | 60 | 61 | /****************************************************/ 62 | 63 | #endif /* IEXL_GENERAL_H */ 64 | 65 | -------------------------------------------------------------------------------- /include/GPUshaders.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020-2022 Graeme Gregory, Ian Jordan 3 | * 4 | */ 5 | 6 | #ifndef _GPUSHADERS_H 7 | #define _GPUSHADERS_H 8 | #include 9 | #include 10 | 11 | bool QLGPUCreateDisplay(int w , int h, int ly, uint32_t* id, 12 | const char* name, uint32_t sdl_window_mode, 13 | int shader_type, const char* shader_path); 14 | void QLGPUUpdateDisplay(void); 15 | void QLGPUSetFullscreen(void); 16 | void QLGPUSetSize(int w, int h); 17 | void QLGPUProcessMouse(int* qlx, int* qly, int x, int y); 18 | void QLGPUClean(void); 19 | 20 | #endif 21 | 22 | -------------------------------------------------------------------------------- /include/SDL2screen.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020-2021 Graeme Gregory 3 | * 4 | * SPDX: Zlib 5 | */ 6 | 7 | #ifndef _SDL2SCREEN_H 8 | #define _SDL2SCREEN_H 9 | 10 | #include 11 | #include 12 | 13 | void QLSDLScreen(void); 14 | void QLSDLRenderScreen(void); 15 | void QLSDLProcessEvents(void); 16 | void QLSDLExit(void); 17 | Uint32 QLSDL50Hz(Uint32 interval, void *param); 18 | void QLSDLUpdateScreenWord(uint32_t, uint16_t); 19 | void QLSDLUpdateScreenLong(uint32_t, uint32_t); 20 | void QLSDLWritePixels(uint32_t *pixelPtr32); 21 | 22 | void QLSDLCreatePalette(const SDL_PixelFormat *format); 23 | void QLSDLCreateIcon(SDL_Window *window); 24 | 25 | extern unsigned int sdl_keyrow[8]; 26 | extern int sdl_shiftstate, sdl_controlstate, sdl_altstate; 27 | 28 | extern SDL_atomic_t doPoll; 29 | extern SDL_sem* sem50Hz; 30 | extern bool shaders_selected; 31 | extern bool ql_fullscreen; 32 | extern double ql_screen_ratio; 33 | 34 | 35 | #define USER_CODE_SCREENREFRESH 0 36 | #define USER_CODE_EMUEXIT 1 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /include/debug.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | extern int verbose; 4 | 5 | #define V1 (verbose>0) 6 | #define V2 (verbose>1) 7 | #define V3 (verbose>2) 8 | 9 | -------------------------------------------------------------------------------- /include/emulator_init.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef EMULATOR_INIT_H 4 | #define EMULATOR_INIT_H 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | void emulatorInit(void); 11 | 12 | #ifdef __cplusplus 13 | }; 14 | #endif 15 | 16 | #endif /* EMULATOR_INIT_H */ -------------------------------------------------------------------------------- /include/emulator_options.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef EMULATOR_OPTIONS_H 4 | #define EMULATOR_OPTIONS_H 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | int emulatorOptionParse(int argc, char **argv); 11 | void emulatorOptionsRemove(void); 12 | const char *emulatorOptionString(const char *name); 13 | int emulatorOptionInt(const char *name); 14 | int emulatorOptionArgc(void); 15 | const char *emulatorOptionArgv(int idx); 16 | 17 | #ifdef __cplusplus 18 | }; 19 | #endif 20 | 21 | #endif /* EMULATOR_OPTIONS_H */ -------------------------------------------------------------------------------- /include/q-emulator.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 Graeme Gregory 3 | * 4 | * SPDX: Zlib 5 | */ 6 | 7 | #pragma once 8 | 9 | #pragma pack(push,1) 10 | typedef struct { 11 | uint8_t h_header[18]; /* "]!QDOS File Header" */ 12 | uint8_t h_res; /* reserved */ 13 | uint8_t h_wordlen; /* header length in words */ 14 | uint8_t f_access; /* file access type */ 15 | uint8_t f_type; /* file type */ 16 | uint32_t f_datalen; /* data length */ 17 | uint32_t f_res; /* reserved */ 18 | uint8_t m_unused[14]; /* extra mdv info */ 19 | } q_emulator_hdr; 20 | #pragma pack(pop) 21 | 22 | #define QEMULATOR_SHORT_HEADER 30 23 | #define QEMULATOR_LONG_HEADER 44 24 | -------------------------------------------------------------------------------- /include/qdos-file-header.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 Graeme Gregory 3 | * 4 | * SPDX: Zlib 5 | */ 6 | 7 | #pragma once 8 | 9 | #pragma pack(push,1) 10 | typedef struct { 11 | int32_t f_length; /* file length */ 12 | uint8_t f_access; /* file access type */ 13 | uint8_t f_type; /* file type */ 14 | int32_t f_datalen; /* data length */ 15 | int32_t f_reserved;/* Unused */ 16 | int16_t f_szname; /* size of name */ 17 | int8_t f_name[36];/* name area */ 18 | int32_t f_update; /* last update */ 19 | int32_t f_refdate; 20 | int32_t f_backup; /* EOD */ 21 | } qdos_file_hdr; 22 | #pragma pack(pop) 23 | -------------------------------------------------------------------------------- /include/qlkeys.h: -------------------------------------------------------------------------------- 1 | /* 2 | QLAY - Sinclair QL emulator 3 | Copyright Jan Venema 1998 4 | QL keys defines 5 | */ 6 | 7 | #define QL_A 0x1c 8 | #define QL_B 0x2c 9 | #define QL_C 0x2b 10 | #define QL_D 0x1e 11 | #define QL_E 0x0c 12 | #define QL_F 0x24 13 | #define QL_G 0x26 14 | #define QL_H 0x1a 15 | #define QL_I 0x12 16 | #define QL_J 0x1f 17 | #define QL_K 0x22 18 | #define QL_L 0x18 19 | #define QL_M 0x2e 20 | #define QL_N 0x06 21 | #define QL_O 0x17 22 | #define QL_P 0x1d 23 | #define QL_Q 0x0b 24 | #define QL_R 0x14 25 | #define QL_S 0x23 26 | #define QL_T 0x0e 27 | #define QL_U 0x0f 28 | #define QL_V 0x04 29 | #define QL_W 0x11 30 | #define QL_X 0x03 31 | #define QL_Y 0x16 32 | #define QL_Z 0x29 33 | 34 | #define QL_0 0x0d 35 | #define QL_1 0x1b 36 | #define QL_2 0x09 37 | #define QL_3 0x19 38 | #define QL_4 0x3e 39 | #define QL_5 0x3a 40 | #define QL_6 0x0a 41 | #define QL_7 0x3f 42 | #define QL_8 0x08 43 | #define QL_9 0x10 44 | 45 | #define QL_F1 0x39 46 | #define QL_F2 0x3b 47 | #define QL_F3 0x3c 48 | #define QL_F4 0x38 49 | #define QL_F5 0x3d 50 | 51 | #define QL_UP 0x32 52 | #define QL_DOWN 0x37 53 | #define QL_LEFT 0x31 54 | #define QL_RIGHT 0x34 55 | 56 | #define QL_SPACE 0x36 57 | #define QL_TAB 0x13 58 | #define QL_ENTER 0x30 59 | #define QL_ESCAPE 0x33 60 | #define QL_CAPSLOCK 0x21 61 | #define QL_LBRACKET 0x20 62 | #define QL_RBRACKET 0x28 63 | #define QL_SEMICOLON 0x27 64 | #define QL_COMMA 0x07 65 | #define QL_PERIOD 0x2a 66 | #define QL_SLASH 0x05 67 | #define QL_BACKSLASH 0x35 68 | #define QL_QUOTE 0x2f 69 | #define QL_POUND 0x2d 70 | #define QL_MINUS 0x15 71 | #define QL_EQUAL 0x25 72 | #define QL_SS 0x45 73 | 74 | #define QL_SHIFT 0x400 75 | #define QL_CTRL 0x200 76 | #define QL_ALT 0x100 77 | 78 | #define QL_KP 0x80 /* keypad key */ 79 | 80 | /* shifted characters */ 81 | #define QLSH_POUND QL_SHIFT|QL_POUND /* backquote US */ 82 | #define QLSH_1 QL_SHIFT|QL_1 83 | #define QLSH_2 QL_SHIFT|QL_2 84 | #define QLSH_3 QL_SHIFT|QL_3 85 | #define QLSH_4 QL_SHIFT|QL_4 86 | #define QLSH_5 QL_SHIFT|QL_5 87 | #define QLSH_6 QL_SHIFT|QL_6 88 | #define QLSH_7 QL_SHIFT|QL_7 89 | #define QLSH_8 QL_SHIFT|QL_8 90 | #define QLSH_9 QL_SHIFT|QL_9 91 | #define QLSH_0 QL_SHIFT|QL_0 92 | #define QLSH_MINUS QL_SHIFT|QL_MINUS 93 | #define QLSH_EQUAL QL_SHIFT|QL_EQUAL 94 | #define QLSH_BACKSLASH QL_SHIFT|QL_BACKSLASH 95 | #define QLSH_LBRACKET QL_SHIFT|QL_LBRACKET 96 | #define QLSH_RBRACKET QL_SHIFT|QL_RBRACKET 97 | #define QLSH_SEMICOLON QL_SHIFT|QL_SEMICOLON 98 | #define QLSH_QUOTE QL_SHIFT|QL_QUOTE 99 | #define QLSH_COMMA QL_SHIFT|QL_COMMA 100 | #define QLSH_PERIOD QL_SHIFT|QL_PERIOD 101 | #define QLSH_SLASH QL_SHIFT|QL_SLASH 102 | 103 | /* special scancode translations */ 104 | #define QL_SC_56 0x40 105 | -------------------------------------------------------------------------------- /include/sqlux_debug.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #if defined(DEBUG) 6 | #define DEBUG_PRINT(fmt, args...) fprintf(stderr, "DEBUG: %d:%s(): " \ 7 | fmt, __LINE__, __func__, ##args) 8 | #else 9 | #define DEBUG_PRINT(fmt, args...) 10 | #endif 11 | -------------------------------------------------------------------------------- /include/sqlux_windows.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021 Graeme Gregory 3 | * 4 | * SPDX: Zlib 5 | */ 6 | 7 | #pragma once 8 | 9 | void sqlux_getemppath(int length, char *buffer); 10 | int sqlux_mkstemp(char *template); 11 | 12 | -------------------------------------------------------------------------------- /include/version.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | extern char *release; 4 | 5 | -------------------------------------------------------------------------------- /include/wasm_support.h: -------------------------------------------------------------------------------- 1 | #ifndef _WASMSUPPORT_H 2 | #define _WASMSUPPORT_H 3 | 4 | void wasm_reload(void); 5 | int wasm_does_boot_file_exist(void); 6 | void wasm_init_storage(void); 7 | 8 | #endif -------------------------------------------------------------------------------- /instructions.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef INSTRUCTIONS_H 3 | #define INSTRUCTIONS_H 4 | 5 | void rts(void); 6 | 7 | #endif /* INSTRUCTIONS_H */ 8 | 9 | -------------------------------------------------------------------------------- /iptraps.h: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) UQLX - see COPYRIGHT 3 | * - unrestricted use - 4 | */ 5 | 6 | 7 | #define IP_LISTEN 0x50 8 | #define IP_SEND 0x51 9 | #define IP_SENDTO 0x52 10 | #define IP_RECV 0x53 11 | #define IP_RECVFM 0x54 12 | #define IP_GETOPT 0x55 13 | #define IP_SETOPT 0x56 14 | #define IP_SHUTDWN 0x57 15 | #define IP_BIND 0x58 16 | #define IP_CONNECT 0x59 17 | #define IP_FCNTL 0x5a 18 | 19 | #define IP_GETHOSTNAME 0x5b 20 | #define IP_GETSOCKNAME 0x5c 21 | #define IP_GETPEERNAME 0x5d 22 | 23 | #define IP_GETHOSTBYNAME 0x5e 24 | #define IP_GETHOSTBYADDR 0x5f 25 | #define IP_SETHOSTENT 0x60 26 | #define IP_ENDHOSTENT 0x61 27 | #define IP_H_ERRNO 0x62 28 | 29 | #define IP_GETSERVENT 0x63 30 | #define IP_GETSERVBYNAME 0x64 31 | #define IP_GETSERVBYPORT 0x65 32 | #define IP_SETSERVENT 0x66 33 | #define IP_ENDSERVENT 0x67 34 | 35 | #define IP_GETNETENT 0x68 36 | #define IP_GETNETBYNAME 0x69 37 | #define IP_GETNETBYADDR 0x6a 38 | #define IP_SETNETENT 0x6b 39 | #define IP_ENDNETENT 0x6c 40 | 41 | #define IP_GETPROTOENT 0x6d 42 | #define IP_GETPROTOBYNAME 0x6e 43 | #define IP_GETPROTOBYNUMBER 0x6f 44 | #define IP_SETPROTOENT 0x70 45 | #define IP_ENDPROTOENT 0x71 46 | 47 | #define IP_INET_ATON 0x72 48 | #define IP_INET_ADDR 0x73 49 | #define IP_INET_NETWORK 0x74 50 | #define IP_INET_NTOA 0x75 51 | #define IP_INET_MAKEADDR 0x76 52 | #define IP_INET_LNAOF 0x77 53 | #define IP_INET_NETOF 0x78 54 | 55 | #define IP_IOCTL 0x79 56 | #define IP_GETDOMAIN 0x7a 57 | #define IP_H_STRERROR 0x7b 58 | #define IP_ERRNO 0x7c 59 | -------------------------------------------------------------------------------- /memaccess.c: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) UQLX - see COPYRIGHT 3 | */ 4 | 5 | 6 | /* define memory access fns */ 7 | #include "QL68000.h" 8 | #include "memaccess.h" 9 | #include "general.h" 10 | #include "QL_screen.h" 11 | #include "SDL2screen.h" 12 | 13 | static int is_hw(uint32_t addr) 14 | { 15 | if ((addr >= QL_INTERNAL_IO_BASE) && 16 | (addr < (QL_INTERNAL_IO_BASE + QL_INTERNAL_IO_SIZE))) { 17 | return 1; 18 | } 19 | 20 | return 0; 21 | } 22 | 23 | rw8 ReadByte(aw32 addr) 24 | { 25 | addr &= ADDR_MASK; 26 | 27 | if ((addr >= RTOP) && (addr >=qlscreen.qm_hi)) 28 | return 0; 29 | 30 | if (is_hw(addr)) { 31 | return ReadHWByte(addr); 32 | } 33 | 34 | return *((w8 *)memBase + addr); 35 | } 36 | 37 | rw16 ReadWord(aw32 addr) 38 | { 39 | addr &= ADDR_MASK; 40 | 41 | if ((addr >= RTOP) && (addr >=qlscreen.qm_hi)) 42 | return 0; 43 | 44 | if (is_hw(addr)) { 45 | return ((w16)ReadHWWord(addr)); 46 | } 47 | 48 | return (w16)RW((w16 *)((Ptr)memBase + addr)); /* make sure it is signed */ 49 | } 50 | 51 | rw32 ReadLong(aw32 addr) 52 | { 53 | addr &= ADDR_MASK; 54 | 55 | if ((addr >= RTOP) && (addr >=qlscreen.qm_hi)) 56 | return 0; 57 | 58 | if (is_hw(addr)) { 59 | return ((w32)ReadHWLong(addr)); 60 | } 61 | 62 | return (w32)RL((Ptr)memBase + addr); /* make sure is is signed */ 63 | } 64 | 65 | void WriteByte(aw32 addr,aw8 d) 66 | { 67 | addr &= ADDR_MASK; 68 | 69 | if ((addr >= RTOP) && (addr >= qlscreen.qm_hi)) 70 | return; 71 | 72 | if (is_hw(addr)) { 73 | WriteHWByte(addr, d); 74 | } else if (addr >= QL_SCREEN_BASE) { 75 | *((w8 *)memBase + addr) = d; 76 | } 77 | } 78 | 79 | void WriteWord(aw32 addr,aw16 d) 80 | { 81 | addr &= ADDR_MASK; 82 | 83 | if ((addr >= RTOP) && (addr >= qlscreen.qm_hi)) 84 | return; 85 | 86 | if (is_hw(addr)) { 87 | WriteHWWord(addr, d); 88 | } else if (addr >= QL_SCREEN_BASE) { 89 | WW((Ptr)memBase + addr, d); 90 | } 91 | } 92 | 93 | void WriteLong(aw32 addr,aw32 d) 94 | { 95 | addr &= ADDR_MASK; 96 | 97 | if ((addr >= RTOP) && (addr >=qlscreen.qm_hi)) 98 | return; 99 | 100 | if (is_hw(addr)) { 101 | WriteHWWord(addr, d >> 16); 102 | WriteHWWord(addr + 2, d); 103 | } else if (addr >= QL_SCREEN_BASE) { 104 | WL((Ptr)memBase + addr, d); 105 | } 106 | } 107 | 108 | /*############################################################*/ 109 | int isreg=0; 110 | 111 | rw8 ModifyAtEA_b(ashort mode,ashort r) 112 | { 113 | shindex displ; 114 | w32 addr; 115 | 116 | isreg = 0; 117 | 118 | switch (mode) 119 | { 120 | case 0: 121 | isreg = 1; 122 | mea_acc = 0; 123 | lastAddr = 0; 124 | dest = (Ptr)(®[r]) + RBO; 125 | return *((w8 *)dest); 126 | case 2: 127 | addr = aReg[r]; 128 | break; 129 | case 3: 130 | addr = aReg[r]++; 131 | if (r == 7) 132 | (*m68k_sp)++; 133 | break; 134 | case 4: 135 | if (r == 7) 136 | (*m68k_sp)--; 137 | addr = --aReg[r]; 138 | break; 139 | case 5: 140 | addr = aReg[r] + (w16)RW(pc++); 141 | break; 142 | case 6: 143 | displ = (w16)RW(pc++); 144 | if ((displ & 2048) != 0) 145 | addr = reg[(displ >> 12) & 15] + 146 | aReg[r] + (w32)((w8)displ); 147 | else 148 | addr = (w32)((w16)(reg[(displ >> 12) & 15])) + 149 | aReg[r] + (w32)((w8)displ); 150 | break; 151 | case 7: 152 | switch (r) 153 | { 154 | case 0: 155 | addr = (w16)RW(pc++); 156 | break; 157 | case 1: 158 | addr = RL((w32 *)pc); 159 | pc += 2; 160 | break; 161 | default: 162 | exception = 4; 163 | extraFlag = true; 164 | nInst2 = nInst; 165 | nInst = 0; 166 | 167 | mea_acc = 0; 168 | lastAddr = 0; 169 | dest = (Ptr)(&dummy); 170 | return 0; 171 | } 172 | break; 173 | default: 174 | exception = 4; 175 | extraFlag = true; 176 | nInst2 = nInst; 177 | nInst = 0; 178 | 179 | mea_acc = 0; 180 | lastAddr = 0; 181 | dest = (Ptr)(&dummy); 182 | return 0; 183 | } 184 | 185 | addr &= ADDR_MASK; 186 | 187 | lastAddr = addr; 188 | dest = (Ptr)memBase + addr; 189 | return ReadByte(addr); 190 | } 191 | 192 | rw16 ModifyAtEA_w(ashort mode,ashort r) 193 | { 194 | /*w16*/ 195 | shindex displ; 196 | w32 addr = 0; 197 | 198 | isreg = 0; 199 | 200 | switch (mode) 201 | { 202 | case 0: 203 | isreg = 1; 204 | dest = (Ptr)(®[r]) + RWO; 205 | return *((w16 *)dest); 206 | case 1: 207 | isreg = 1; 208 | dest = (Ptr)(&aReg[r]) + RWO; 209 | return *((w16 *)dest); 210 | case 2: 211 | addr = aReg[r]; 212 | break; 213 | case 3: 214 | addr = aReg[r]; 215 | aReg[r] += 2; 216 | break; 217 | case 4: 218 | addr = (aReg[r] -= 2); 219 | break; 220 | case 5: 221 | addr = aReg[r] + (w16)RW(pc++); 222 | break; 223 | case 6: 224 | displ = (w16)RW(pc++); 225 | if ((displ & 2048) != 0) 226 | addr = reg[(displ >> 12) & 15] + 227 | aReg[r] + (w32)((w8)displ); 228 | else 229 | addr = (w32)((w16)(reg[(displ >> 12) & 15])) + 230 | aReg[r] + (w32)((w8)displ); 231 | break; 232 | case 7: 233 | switch (r) 234 | { 235 | case 0: 236 | addr = (w16)RW(pc++); 237 | break; 238 | case 1: 239 | addr = RL((w32 *)pc); 240 | pc += 2; 241 | break; 242 | default: 243 | exception = 4; 244 | extraFlag = true; 245 | nInst2 = nInst; 246 | nInst = 0; 247 | mea_acc = 0; 248 | dest = (Ptr)(&dummy); 249 | return 0; 250 | } 251 | break; 252 | } 253 | addr &= ADDR_MASK; 254 | 255 | lastAddr = addr; 256 | dest = (Ptr)memBase + addr; 257 | return ReadWord(addr); 258 | } 259 | 260 | rw32 ModifyAtEA_l(ashort mode, ashort r) 261 | { 262 | /*w16*/ 263 | shindex displ; 264 | w32 addr = 0; 265 | 266 | isreg = 0; 267 | 268 | switch (mode) 269 | { 270 | case 0: 271 | isreg = 1; 272 | dest = (Ptr)(®[r]); 273 | return *((w32 *)dest); 274 | case 1: 275 | isreg = 1; 276 | dest = (Ptr)(&aReg[r]); 277 | return *((w32 *)dest); 278 | case 2: 279 | addr = aReg[r]; 280 | break; 281 | case 3: 282 | addr = aReg[r]; 283 | aReg[r] += 4; 284 | break; 285 | case 4: 286 | addr = (aReg[r] -= 4); 287 | break; 288 | case 5: 289 | addr = aReg[r] + (w16)RW(pc++); 290 | break; 291 | case 6: 292 | displ = (w16)RW(pc++); 293 | if ((displ & 2048) != 0) 294 | addr = reg[(displ >> 12) & 15] + 295 | aReg[r] + (w32)((w8)displ); 296 | else 297 | addr = (w32)((w16)(reg[(displ >> 12) & 15])) + 298 | aReg[r] + (w32)((w8)displ); 299 | break; 300 | case 7: 301 | switch (r) 302 | { 303 | case 0: 304 | addr = (w16)RW(pc++); 305 | break; 306 | case 1: 307 | addr = RL((w32 *)pc); 308 | pc += 2; 309 | break; 310 | default: 311 | exception = 4; 312 | extraFlag = true; 313 | nInst2 = nInst; 314 | nInst = 0; 315 | mea_acc = 0; 316 | 317 | dest = (Ptr)(&dummy); 318 | return 0; 319 | } 320 | break; 321 | } 322 | 323 | addr &= ADDR_MASK; 324 | 325 | lastAddr = addr; 326 | dest = (Ptr)memBase + addr; 327 | return ReadLong(addr); 328 | } 329 | 330 | void RewriteEA_b(aw8 d) 331 | { 332 | if (isreg) 333 | *((w8*)dest)=d; 334 | else { 335 | WriteByte(lastAddr, d); 336 | } 337 | } 338 | 339 | void RewriteEA_w(aw16 d) 340 | { 341 | if (isreg) { 342 | *((w16*)dest)=d; 343 | } else { 344 | WriteWord(lastAddr, d); 345 | } 346 | } 347 | 348 | void RewriteEA_l(aw32 d) 349 | { 350 | if (isreg) { 351 | *((w32*)dest)=d; 352 | } else { 353 | WriteLong(lastAddr, d); 354 | } 355 | } 356 | -------------------------------------------------------------------------------- /memaccess.h: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) UQLX - see COPYRIGHT 3 | */ 4 | 5 | 6 | /* define memory access fns */ 7 | 8 | #pragma once 9 | 10 | #include 11 | 12 | int8_t ReadByte(int32_t addr); 13 | int16_t ReadWord(int32_t addr); 14 | int32_t ReadLong(int32_t addr); 15 | void WriteByte(int32_t addr,int8_t d); 16 | void WriteWord(int32_t addr,int16_t d); 17 | void WriteLong(int32_t addr,int32_t d); 18 | 19 | int8_t ModifyAtEA_b(int16_t mode, int16_t r); 20 | int16_t ModifyAtEA_w(int16_t mode, int16_t r); 21 | int32_t ModifyAtEA_l(int16_t mode, int16_t r); 22 | void RewriteEA_b(int8_t d); 23 | void rwb_acc(int8_t d); 24 | void RewriteEA_w(int16_t d); 25 | void rww_acc(int16_t d); 26 | void RewriteEA_l(int32_t d); 27 | void rwl_acc(int32_t d); 28 | 29 | #define QL_ROM_BASE 0x0000 30 | #define QL_ROM_SIZE 0xC000 31 | #define QL_ROM_PORT_BASE 0xC000 32 | #define QL_ROM_PORT_SIZE 0x4000 33 | #define QL_ROM2_BASE 0x10000 34 | #define QL_ROM2_SIZE 0x4000 35 | #define QL_ROM3_BASE 0x14000 36 | #define QL_ROM3_SIZE 0x4000 37 | #define QL_INTERNAL_IO_BASE 0x18000 38 | #define QL_INTERNAL_IO_SIZE 0x4000 39 | #define QL_EXTERNAL_IO_BASE 0x1C000 40 | #define QL_EXTERNAL_IO_SIZE 0x4000 41 | #define QL_SCREEN_BASE 0x20000 42 | -------------------------------------------------------------------------------- /mmodes.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef MMODES_H 4 | #define MMODES_H 5 | 6 | rw32 GetEA_m2(ashort) AREGP; 7 | rw32 GetEA_m5(ashort) AREGP; 8 | rw32 GetEA_m6(ashort) AREGP; 9 | rw32 GetEA_m7(ashort) AREGP; 10 | rw32 GetEA_mBad(ashort) AREGP; 11 | 12 | rw8 GetFromEA_b_m0(void); 13 | rw8 GetFromEA_b_mBad(void); 14 | rw8 GetFromEA_b_m2(void); 15 | rw8 GetFromEA_b_m3(void); 16 | rw8 GetFromEA_b_m4(void); 17 | rw8 GetFromEA_b_m5(void); 18 | rw8 GetFromEA_b_m6(void); 19 | rw8 GetFromEA_b_m7(void); 20 | 21 | rw16 GetFromEA_w_m0(void); 22 | rw16 GetFromEA_w_m1(void); 23 | rw16 GetFromEA_w_m2(void); 24 | rw16 GetFromEA_w_m3(void); 25 | rw16 GetFromEA_w_m4(void); 26 | rw16 GetFromEA_w_m5(void); 27 | rw16 GetFromEA_w_m6(void); 28 | rw16 GetFromEA_w_m7(void); 29 | 30 | rw32 GetFromEA_l_m0(void); 31 | rw32 GetFromEA_l_m1(void); 32 | rw32 GetFromEA_l_m2(void); 33 | rw32 GetFromEA_l_m3(void); 34 | rw32 GetFromEA_l_m4(void); 35 | rw32 GetFromEA_l_m5(void); 36 | rw32 GetFromEA_l_m6(void); 37 | rw32 GetFromEA_l_m7(void); 38 | 39 | void PutToEA_b_m0(ashort,aw8) AREGP; 40 | void PutToEA_b_mBad(ashort,aw8) AREGP; 41 | void PutToEA_b_m2(ashort,aw8) AREGP; 42 | void PutToEA_b_m3(ashort,aw8) AREGP; 43 | void PutToEA_b_m4(ashort,aw8) AREGP; 44 | void PutToEA_b_m5(ashort,aw8) AREGP; 45 | void PutToEA_b_m6(ashort,aw8) AREGP; 46 | void PutToEA_b_m7(ashort,aw8) AREGP; 47 | 48 | void PutToEA_w_m0(ashort,aw16) AREGP; 49 | void PutToEA_w_m1(ashort,aw16) AREGP; 50 | void PutToEA_w_m2(ashort,aw16) AREGP; 51 | void PutToEA_w_m3(ashort,aw16) AREGP; 52 | void PutToEA_w_m4(ashort,aw16) AREGP; 53 | void PutToEA_w_m5(ashort,aw16) AREGP; 54 | void PutToEA_w_m6(ashort,aw16) AREGP; 55 | void PutToEA_w_m7(ashort,aw16) AREGP; 56 | 57 | void PutToEA_l_m0(ashort,aw32) AREGP; 58 | void PutToEA_l_m1(ashort,aw32) AREGP; 59 | void PutToEA_l_m2(ashort,aw32) AREGP; 60 | void PutToEA_l_m3(ashort,aw32) AREGP; 61 | void PutToEA_l_m4(ashort,aw32) AREGP; 62 | void PutToEA_l_m5(ashort,aw32) AREGP; 63 | void PutToEA_l_m6(ashort,aw32) AREGP; 64 | void PutToEA_l_m7(ashort,aw32) AREGP; 65 | 66 | rw8 GetFromEA_rb_m3(ashort r); 67 | rw32 GetFromEA_rl_m3(ashort r); 68 | rw16 GetFromEA_rw_m3(ashort r); 69 | 70 | Cond CondT(void); 71 | Cond CondF(void); 72 | Cond CondHI(void); 73 | Cond CondLS(void); 74 | Cond CondCC(void); 75 | Cond CondCS(void); 76 | Cond CondNE(void); 77 | Cond CondEQ(void); 78 | Cond CondVC(void); 79 | Cond CondVS(void); 80 | Cond CondPL(void); 81 | Cond CondMI(void); 82 | Cond CondGE(void); 83 | Cond CondLT(void); 84 | Cond CondGT(void); 85 | Cond CondLE(void); 86 | 87 | #endif /* MMODES_H */ 88 | -------------------------------------------------------------------------------- /qlmouse.h: -------------------------------------------------------------------------------- 1 | /* 2 | * qlmouse.h 3 | * 4 | * Created on: Mar 25, 2020 5 | * Author: graeme 6 | */ 7 | 8 | #ifndef QLMOUSE_H_ 9 | #define QLMOUSE_H_ 10 | 11 | void QLButton(int bnr,int press); 12 | void QLMovePointer(int pos_x,int pos_y); 13 | 14 | #endif /* QLMOUSE_H_ */ 15 | -------------------------------------------------------------------------------- /qmtrap.c: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * (c) UQLX - see COPYRIGHT 4 | */ 5 | 6 | 7 | #include "iexl_general.h" 8 | #include "QL68000.h" 9 | #include "QL_config.h" 10 | #include "QInstAddr.h" 11 | 12 | int tracetrap=0; 13 | 14 | void QMExecuteLoop(uw16 *oldPC) /* fetch and dispatch loop */ 15 | { 16 | register void (**tab)(void); 17 | 18 | tab=qlux_table; 19 | 20 | /*printf("enter QME \n");*/ 21 | 22 | rep: 23 | while(likely(--nInst>=0 && oldPC!=pc) /* && oldPC!=pc+1 && oldPC!=pc+2 */) 24 | { 25 | /*printf("PC=%x\n",(Ptr)pc-(Ptr)memBase); */ 26 | tab[code=RW(pc++)&0xffff](); 27 | } 28 | 29 | if(extraFlag) 30 | { 31 | nInst=nInst2; 32 | /* 33 | if (*reg==0x16) 34 | printf("exception processing: exception %d, trap %d, d0=%x\n",exception,exception-32,*reg); 35 | tracetrap=1;*/ 36 | 37 | ExceptionProcessing(); 38 | if(nInst>0) goto rep; 39 | } 40 | 41 | /*printf("QME nInst: %d, oldPC %d, code %x\n",nInst, oldPC,code);*/ 42 | tracetrap=0; 43 | } 44 | 45 | void QLchunk(uw16 *oldPC,long n) /* execute n emulated 68K istructions */ 46 | { 47 | uw16 savePOLLM; 48 | int save_ninst; 49 | 50 | savePOLLM=ReadWord(0x28030); 51 | WriteWord(0x28030,0); 52 | 53 | if((uintptr_t)pc&1) return; 54 | 55 | /*extraFlag=false;*/ 56 | /*ProcessInterrupts();*/ 57 | 58 | if(stopped) return; 59 | if (extraFlag==0) exception=0; 60 | 61 | save_ninst=nInst; 62 | nInst=n; 63 | if(extraFlag) 64 | { 65 | nInst2=nInst; 66 | 67 | nInst=0; 68 | } 69 | 70 | QMExecuteLoop(oldPC); 71 | 72 | nInst=save_ninst; 73 | WriteWord(0x28030,savePOLLM); 74 | } 75 | 76 | void QLtrap(int t,int id,int nMax) 77 | { 78 | /*printf("calling QLtrap #%d, d0=%x d1=%d d2=%d a0=%x a1=%x\n",t,id,reg[1],reg[2],aReg[0],aReg[1]);*/ 79 | 80 | reg[0]=id; 81 | 82 | exception=32+t; 83 | extraFlag=true; 84 | 85 | QLchunk(pc,nMax); 86 | 87 | /*printf("returns : d0=%d d1=%d a0=%x a1=%x\n",reg[0],reg[1],aReg[0],aReg[1]);*/ 88 | } 89 | 90 | void QLvector(int which, int nMax) 91 | { 92 | uw32 ea; 93 | uw16 *savedPC=pc; 94 | /*printf("calling QLvector %x\n",which);*/ 95 | 96 | ea=ReadWord(which); 97 | 98 | WriteLong((*m68k_sp)-=4,(w32)((Ptr)pc-(Ptr)memBase)); 99 | SetPC(ea); 100 | 101 | extraFlag=false; 102 | exception=0; 103 | 104 | QLchunk(savedPC,nMax); 105 | 106 | } 107 | 108 | void QLsubr(uw32 ea, int nMax) 109 | { 110 | uw16 *savedPC=pc; 111 | 112 | WriteLong((*m68k_sp)-=4,(w32)((Ptr)pc-(Ptr)memBase)); 113 | SetPC(ea); 114 | 115 | extraFlag=false; 116 | exception=0; 117 | 118 | QLchunk(savedPC,nMax); 119 | } 120 | -------------------------------------------------------------------------------- /qmtrap.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef QMTRAP_H 4 | #define QMTRAP_H 5 | 6 | void QLsubr(uw32 ea, int nMax); 7 | 8 | #endif /* QMTRAP_H */ 9 | -------------------------------------------------------------------------------- /roms/Minerva_1.98a1.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SinclairQL/sQLux/79aa52decf115d79af328f62ca5563e7f5f916be/roms/Minerva_1.98a1.bin -------------------------------------------------------------------------------- /roms/Minerva_1g98a1.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SinclairQL/sQLux/79aa52decf115d79af328f62ca5563e7f5f916be/roms/Minerva_1g98a1.bin -------------------------------------------------------------------------------- /roms/TK232.rom: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SinclairQL/sQLux/79aa52decf115d79af328f62ca5563e7f5f916be/roms/TK232.rom -------------------------------------------------------------------------------- /roms/TK236.rom: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SinclairQL/sQLux/79aa52decf115d79af328f62ca5563e7f5f916be/roms/TK236.rom -------------------------------------------------------------------------------- /sQLuxLogo.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SinclairQL/sQLux/79aa52decf115d79af328f62ca5563e7f5f916be/sQLuxLogo.ico -------------------------------------------------------------------------------- /sQLuxLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SinclairQL/sQLux/79aa52decf115d79af328f62ca5563e7f5f916be/sQLuxLogo.png -------------------------------------------------------------------------------- /sQLuxLogo.rc: -------------------------------------------------------------------------------- 1 | id ICON "sQLuxLogo.ico" 2 | -------------------------------------------------------------------------------- /shaders/crt-pi.glsl: -------------------------------------------------------------------------------- 1 | /* 2 | crt-pi - A Raspberry Pi friendly CRT shader. 3 | 4 | Copyright (C) 2015-2016 davej 5 | Modified 2022 for sQLux 6 | 7 | This program is free software; you can redistribute it and/or modify it 8 | under the terms of the GNU General Public License as published by the Free 9 | Software Foundation; either version 2 of the License, or (at your option) 10 | any later version. 11 | 12 | 13 | Notes: 14 | 15 | This shader is designed to work well on Raspberry Pi GPUs (i.e. 1080P @ 60Hz on a game with a 4:3 aspect ratio). It pushes the Pi's GPU hard and enabling some features will slow it down so that it is no longer able to match 1080P @ 60Hz. You will need to overclock your Pi to the fastest setting in raspi-config to get the best results from this shader: 'Pi2' for Pi2 and 'Turbo' for original Pi and Pi Zero. Note: Pi2s are slower at running the shader than other Pis, this seems to be down to Pi2s lower maximum memory speed. Pi2s don't quite manage 1080P @ 60Hz - they drop about 1 in 1000 frames. You probably won't notice this, but if you do, try enabling FAKE_GAMMA. 16 | 17 | SCANLINES enables scanlines. You'll almost certainly want to use it with MULTISAMPLE to reduce moire effects. SCANLINE_WEIGHT defines how wide scanlines are (it is an inverse value so a higher number = thinner lines). SCANLINE_GAP_BRIGHTNESS defines how dark the gaps between the scan lines are. Darker gaps between scan lines make moire effects more likely. 18 | 19 | GAMMA enables gamma correction using the values in INPUT_GAMMA and OUTPUT_GAMMA. FAKE_GAMMA causes it to ignore the values in INPUT_GAMMA and OUTPUT_GAMMA and approximate gamma correction in a way which is faster than true gamma whilst still looking better than having none. You must have GAMMA defined to enable FAKE_GAMMA. 20 | 21 | CURVATURE distorts the screen by CURVATURE_X and CURVATURE_Y. Curvature slows things down a lot. 22 | 23 | By default the shader uses linear blending horizontally. If you find this too blury, enable SHARPER. 24 | 25 | BLOOM_FACTOR controls the increase in width for bright scanlines. 26 | 27 | MASK_TYPE defines what, if any, shadow mask to use. MASK_BRIGHTNESS defines how much the mask type darkens the screen. 28 | 29 | */ 30 | 31 | // Haven't put these as parameters as it would slow the code down. 32 | #define SCANLINES 33 | #define MULTISAMPLE 34 | #define GAMMA 35 | //#define FAKE_GAMMA 36 | //#define SHARPER 37 | // MASK_TYPE: 0 = none, 1 = green/magenta, 2 = trinitron(ish) 38 | #define MASK_TYPE 1 39 | 40 | 41 | #ifdef GL_ES 42 | #define COMPAT_PRECISION mediump 43 | precision mediump float; 44 | #else 45 | #define COMPAT_PRECISION 46 | #endif 47 | 48 | #define CURVATURE_X 0.06 49 | #define CURVATURE_Y 0.12 50 | #define MASK_BRIGHTNESS 0.70 51 | #define SCANLINE_WEIGHT 5.0 52 | #define SCANLINE_GAP_BRIGHTNESS 0.60 53 | #define BLOOM_FACTOR 1.5 54 | #define INPUT_GAMMA 2.4 55 | #define OUTPUT_GAMMA 2.2 56 | 57 | uniform vec2 TextureSize; 58 | 59 | // Compatibility 60 | #if __VERSION__ >= 130 61 | #define ATTRIBUTE in 62 | #define SHADER_IN in 63 | #define SHADER_OUT out 64 | #if defined (FRAGMENT) 65 | #define TEXTURE_2D texture 66 | out vec4 fragColor; 67 | #endif 68 | #else 69 | #define ATTRIBUTE attribute 70 | #define SHADER_IN varying 71 | #define SHADER_OUT varying 72 | #if defined (FRAGMENT) 73 | #define TEXTURE_2D texture2D 74 | #define fragColor gl_FragColor 75 | #endif 76 | #endif 77 | 78 | #if defined(VERTEX) 79 | uniform mat4 MVPMatrix; 80 | ATTRIBUTE vec3 VertexCoord; 81 | ATTRIBUTE vec2 TexCoord; 82 | uniform vec2 u_resolution; 83 | SHADER_OUT vec2 TEX0; 84 | SHADER_OUT float filterWidth; 85 | 86 | void main() 87 | { 88 | filterWidth = (TextureSize.y / u_resolution.y) / 3.0; 89 | TEX0 = TexCoord * 1.0001; 90 | gl_Position = MVPMatrix * vec4(VertexCoord, 1.0); 91 | 92 | } 93 | #elif defined(FRAGMENT) 94 | 95 | uniform sampler2D tex; 96 | SHADER_IN vec2 TEX0; 97 | SHADER_IN float filterWidth; 98 | 99 | #if defined(CURVATURE) 100 | vec2 Distort(vec2 coord) 101 | { 102 | vec2 CURVATURE_DISTORTION = vec2(CURVATURE_X, CURVATURE_Y); 103 | // Barrel distortion shrinks the display area a bit, this will allow us to counteract that. 104 | vec2 barrelScale = 1.0 - (0.23 * CURVATURE_DISTORTION); 105 | coord -= vec2(0.5); 106 | float rsq = coord.x * coord.x + coord.y * coord.y; 107 | coord += coord * (CURVATURE_DISTORTION * rsq); 108 | coord *= barrelScale; 109 | if (abs(coord.x) >= 0.5 || abs(coord.y) >= 0.5) 110 | coord = vec2(-1.0); // If out of bounds, return an invalid value. 111 | else 112 | { 113 | coord += vec2(0.5); 114 | } 115 | 116 | return coord; 117 | } 118 | #endif 119 | 120 | float CalcScanLineWeight(float dist) 121 | { 122 | return max(1.0-dist*dist*SCANLINE_WEIGHT, SCANLINE_GAP_BRIGHTNESS); 123 | } 124 | 125 | float CalcScanLine(float dy) 126 | { 127 | float scanLineWeight = CalcScanLineWeight(dy); 128 | #if defined(MULTISAMPLE) 129 | scanLineWeight += CalcScanLineWeight(dy-filterWidth); 130 | scanLineWeight += CalcScanLineWeight(dy+filterWidth); 131 | scanLineWeight *= 0.3333333; 132 | #endif 133 | return scanLineWeight; 134 | } 135 | 136 | void main() 137 | { 138 | #if defined(CURVATURE) 139 | vec2 texcoord = Distort(TEX0); 140 | if (texcoord.x < 0.0) 141 | fragColor = vec4(0.0); 142 | else 143 | #else 144 | vec2 texcoord = TEX0; 145 | #endif 146 | { 147 | vec2 texcoordInPixels = texcoord * TextureSize; 148 | #if defined(SHARPER) 149 | vec2 tempCoord = floor(texcoordInPixels) + 0.5; 150 | vec2 coord = tempCoord / TextureSize; 151 | vec2 deltas = texcoordInPixels - tempCoord; 152 | float scanLineWeight = CalcScanLine(deltas.y); 153 | vec2 signs = sign(deltas); 154 | deltas.x *= 2.0; 155 | deltas = deltas * deltas; 156 | deltas.y = deltas.y * deltas.y; 157 | deltas.x *= 0.5; 158 | deltas.y *= 8.0; 159 | deltas /= TextureSize; 160 | deltas *= signs; 161 | vec2 tc = coord + deltas; 162 | #else 163 | float tempY = floor(texcoordInPixels.y) + 0.5; 164 | float yCoord = tempY / TextureSize.y; 165 | 166 | float dy = texcoordInPixels.y - tempY; 167 | float scanLineWeight = CalcScanLine(dy); 168 | float signY = sign(dy); 169 | dy = dy * dy; 170 | dy = dy * dy; 171 | dy *= 8.0; 172 | dy /= TextureSize.y; 173 | dy *= signY; 174 | vec2 tc = vec2(texcoord.x, yCoord + dy); 175 | #endif 176 | 177 | vec3 colour = TEXTURE_2D(tex, tc).rgb; 178 | 179 | #if defined(SCANLINES) 180 | #if defined(GAMMA) 181 | #if defined(FAKE_GAMMA) 182 | colour = colour * colour; 183 | #else 184 | colour = pow(colour, vec3(INPUT_GAMMA)); 185 | #endif 186 | #endif 187 | scanLineWeight *= BLOOM_FACTOR; 188 | colour *= scanLineWeight; 189 | 190 | #if defined(GAMMA) 191 | #if defined(FAKE_GAMMA) 192 | colour = sqrt(colour); 193 | #else 194 | colour = pow(colour, vec3(1.0/OUTPUT_GAMMA)); 195 | #endif 196 | #endif 197 | #endif 198 | #if MASK_TYPE == 0 199 | fragColor = vec4(colour, 1.0); 200 | #else 201 | #if MASK_TYPE == 1 202 | float whichMask = fract((gl_FragCoord.x*1.0001) * 0.5); 203 | vec3 mask; 204 | if (whichMask < 0.5) 205 | mask = vec3(MASK_BRIGHTNESS, 1.0, MASK_BRIGHTNESS); 206 | else 207 | mask = vec3(1.0, MASK_BRIGHTNESS, 1.0); 208 | #elif MASK_TYPE == 2 209 | float whichMask = fract((gl_FragCoord.x*1.0001) * 0.3333333); 210 | vec3 mask = vec3(MASK_BRIGHTNESS, MASK_BRIGHTNESS, MASK_BRIGHTNESS); 211 | if (whichMask < 0.3333333) 212 | mask.x = 1.0; 213 | else if (whichMask < 0.6666666) 214 | mask.y = 1.0; 215 | else 216 | mask.z = 1.0; 217 | #endif 218 | fragColor = vec4(colour * mask, 1.0); 219 | #endif 220 | } 221 | } 222 | #endif 223 | -------------------------------------------------------------------------------- /sqlux_bdi.c: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) 2021 Graeme Gregory 3 | * 4 | * SPDX-License-Identifier: BSD-3-Clause 5 | * 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "emulator_options.h" 17 | 18 | static int bdi_files[8]; 19 | static uint32_t bdi_address; 20 | static int bdi_ctr; 21 | static int bdi_unit; 22 | uint8_t bdi_buffer[512]; 23 | 24 | #ifdef DEBUG 25 | #define bdi_debug(fmt, a...) printf(fmt, ##a) 26 | #else 27 | #define bdi_debug(fmt, a...) \ 28 | do { \ 29 | } while (0) 30 | #endif 31 | 32 | void SQLUXBDISelect(uint8_t d) 33 | { 34 | int bdi_file; 35 | const char *bdi_file_str = emulatorOptionString("bdi1"); 36 | 37 | /* Currently only supporting 1 unit */ 38 | if ((d == 1) && (!bdi_files[d - 1])) { 39 | bdi_debug("BDI: Opening %s\n", bdi_file_str); 40 | if (strlen(bdi_file_str)) { 41 | bdi_file = open(bdi_file_str, O_RDWR); 42 | if (bdi_file < 0) { 43 | perror("BDI: Select Open File"); 44 | printf("BDI: ERROR Opening %s\n", bdi_file_str); 45 | } else { 46 | bdi_files[d - 1] = bdi_file; 47 | } 48 | } 49 | } 50 | 51 | if (d == 0) { 52 | close(bdi_files[bdi_unit - 1]); 53 | bdi_files[bdi_unit - 1] = 0; 54 | } 55 | 56 | bdi_unit = d; 57 | 58 | return; 59 | } 60 | 61 | void SQLUXBDICommand(uint8_t command) 62 | { 63 | switch (command) { 64 | case 2: 65 | bdi_debug("BDI: Read Command\n"); 66 | bdi_ctr = 0; 67 | break; 68 | case 3: 69 | bdi_debug("BDI: Write Command\n"); 70 | bdi_ctr = 0; 71 | break; 72 | default: 73 | bdi_debug("BDI: Uknown Command 0x%2x\n", command); 74 | } 75 | } 76 | 77 | uint8_t SQLUXBDIStatus() 78 | { 79 | if (!bdi_files[bdi_unit - 1]) { 80 | bdi_debug("BDI: ERROR File Not Open\n"); 81 | return 1; 82 | } 83 | 84 | return 0; 85 | } 86 | 87 | uint8_t SQLUXBDIDataRead() 88 | { 89 | ssize_t res; 90 | 91 | if (!bdi_files[bdi_unit - 1]) { 92 | bdi_debug("BDI: ERROR File Not Open\n"); 93 | return 0; 94 | } 95 | if (bdi_ctr == 0) { 96 | bdi_debug("BDI: seeking to 0x%8x\n", bdi_address * 512); 97 | lseek(bdi_files[bdi_unit - 1], bdi_address * 512, SEEK_SET); 98 | res = read(bdi_files[bdi_unit - 1], bdi_buffer, 512); 99 | if (res < 0) 100 | perror("BDI Read\n"); 101 | } 102 | 103 | bdi_debug("BDI: Read %d\n", bdi_ctr); 104 | 105 | if (bdi_ctr < 512) 106 | return bdi_buffer[bdi_ctr++]; 107 | 108 | return 0; 109 | } 110 | 111 | void SQLUXBDIDataWrite(uint8_t d) 112 | { 113 | ssize_t res; 114 | 115 | if (!bdi_files[bdi_unit - 1]) { 116 | bdi_debug("BDI: ERROR File Not Open\n"); 117 | return; 118 | } 119 | if (bdi_ctr == 0) { 120 | bdi_debug("BDI: seeking to 0x%8x\n", bdi_address * 512); 121 | lseek(bdi_files[bdi_unit - 1], bdi_address * 512, SEEK_SET); 122 | } 123 | 124 | printf("BDI: Write %d\n", bdi_ctr); 125 | 126 | if (bdi_ctr < 512) 127 | bdi_buffer[bdi_ctr++] = d; 128 | 129 | if (bdi_ctr == 512) { 130 | res = write(bdi_files[bdi_unit - 1], bdi_buffer, 512); 131 | if (res < 0 ) 132 | perror("BDI Write\n"); 133 | #ifndef __WIN32__ 134 | fsync(bdi_files[bdi_unit - 1]); 135 | #endif 136 | } 137 | } 138 | 139 | void SQLUXBDIAddressHigh(uint16_t bdi_addr) 140 | { 141 | bdi_debug("BDI: Address 0x%4x\n", bdi_addr); 142 | bdi_address = (bdi_address & 0x0000FFFF) | ((uint32_t)bdi_addr << 16); 143 | } 144 | 145 | void SQLUXBDIAddressLow(uint16_t bdi_addr) 146 | { 147 | bdi_debug("BDI: Address 0x%4x\n", bdi_addr); 148 | bdi_address = (bdi_address & 0xFFFF0000) | ((uint32_t)bdi_addr); 149 | } 150 | 151 | uint16_t SQLUXBDISizeHigh() 152 | { 153 | struct stat bdi_stat; 154 | 155 | if (!bdi_files[bdi_unit - 1]) { 156 | bdi_debug("BDI: ERROR File Not Open\n"); 157 | return 0; 158 | } 159 | 160 | bdi_debug("BDI: SizeHigh\n"); 161 | 162 | fstat(bdi_files[bdi_unit - 1], &bdi_stat); 163 | 164 | return (uint16_t)(bdi_stat.st_size / 512) >> 16; 165 | } 166 | 167 | uint16_t SQLUXBDISizeLow() 168 | { 169 | struct stat bdi_stat; 170 | 171 | if (!bdi_files[bdi_unit - 1]) { 172 | bdi_debug("BDI: ERROR File Not Open\n"); 173 | return 0; 174 | } 175 | 176 | bdi_debug("BDI: SizeLow\n"); 177 | 178 | fstat(bdi_files[bdi_unit - 1], &bdi_stat); 179 | 180 | return (uint16_t)(bdi_stat.st_size / 512) & 0xFFFF; 181 | } 182 | -------------------------------------------------------------------------------- /sqlux_bdi.h: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) 2021 Graeme Gregory 3 | * 4 | * SPDX-License-Identifier: BSD-3-Clause 5 | * 6 | */ 7 | 8 | #ifndef SQLUX_BDI_H 9 | #define SQLUX_BDI_H 10 | 11 | #include 12 | 13 | void SQLUXBDISelect(uint8_t d); 14 | void SQLUXBDICommand(uint8_t command); 15 | uint8_t SQLUXBDIStatus(); 16 | uint8_t SQLUXBDIDataRead(); 17 | void SQLUXBDIDataWrite(uint8_t d); 18 | void SQLUXBDIAddressHigh(uint16_t bdi_addr); 19 | void SQLUXBDIAddressLow(uint16_t bdi_addr); 20 | uint16_t SQLUXBDISizeHigh(); 21 | uint16_t SQLUXBDISizeLow(); 22 | #endif /* SQLUX_BDI_H */ 23 | -------------------------------------------------------------------------------- /sqlux_wasm.ini: -------------------------------------------------------------------------------- 1 | # Example configuration 2 | 3 | SYSROM = MIN198.rom 4 | ROMPORT = TK232.rom 5 | RAMTOP = 4096 6 | PRINT = lpr 7 | CPU_HOG = 0 8 | FAST_STARTUP = 0 9 | #BOOT_DEVICE = WIN1 10 | BOOT_DEVICE = FLP1 11 | DEVICE = WIN1,/local/win1.win,qdos-fs 12 | DEVICE = FLP1,/local/win1.win,qdos-fs 13 | DEVICE = RAM1,/tmp/.ram1-%x,clean,qdos-like 14 | #DEVICE = RAM1,/tmp/.ram1-%x,clean,qdos-like 15 | #DEVICE = RAM2,/tmp/.ram2-%x,clean,qdos-like 16 | #DEVICE = RAM8,/tmp/.ram8-%x,clean,qdos-like 17 | WIN_SIZE = max 18 | FILTER = 1 19 | FIXASPECT = 1 20 | KBD = GB 21 | SOUND = 1 22 | SPEED = 0.0 23 | -------------------------------------------------------------------------------- /sqlux_wrapper_sample.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 33 | 34 | 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /src/SDL2main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "debug.h" 7 | #include "emudisk.h" 8 | #include "emulator_init.h" 9 | #include "emulator_options.h" 10 | #include "QL_sound.h" 11 | #include "SDL2screen.h" 12 | #include "unixstuff.h" 13 | #include "Xscreen.h" 14 | 15 | #if __EMSCRIPTEN__ 16 | #include 17 | #include "wasm_support.h" 18 | #endif 19 | 20 | static SDL_Thread *emuThread = NULL; 21 | 22 | static int unlink_cb(const char *fpath, const struct stat *sb, int typeflag, 23 | struct FTW *ftwbuf) 24 | { 25 | int rv = remove(fpath); 26 | 27 | if (rv) 28 | perror(fpath); 29 | 30 | return rv; 31 | } 32 | 33 | static int rmrf(const char *path) 34 | { 35 | return nftw(path, unlink_cb, 64, FTW_DEPTH | FTW_PHYS); 36 | } 37 | 38 | void CleanRAMDev() 39 | { 40 | int i, j; 41 | 42 | for (i = 0; i < MAXDEV; i++) { 43 | if (qdevs[i].qname && strcmp(qdevs[i].qname, "RAM") == 0) { 44 | for (j = 0; j < 8; j++) { 45 | if ((qdevs[i].mountPoints[j] != NULL) && 46 | qdevs[i].clean[j]) { 47 | if (V2) { 48 | printf("Cleaning: %s\n", qdevs[i].mountPoints[j]); 49 | } 50 | rmrf(qdevs[i].mountPoints[j]); 51 | } 52 | } 53 | break; 54 | } 55 | } 56 | } 57 | 58 | void emu_shutdown() 59 | { 60 | QLdone = 1; 61 | 62 | SDL_WaitThread(emuThread, NULL); 63 | 64 | QLSDLExit(); 65 | 66 | CleanRAMDev(); 67 | } 68 | 69 | void emu_loop() { 70 | static int init_done = 0; 71 | int boot_file_ready = 1; 72 | 73 | #if __EMSCRIPTEN__ 74 | if(!init_done) { 75 | boot_file_ready = wasm_does_boot_file_exist(); 76 | } 77 | #endif 78 | if(boot_file_ready && !init_done) { 79 | emulatorInit(); 80 | QLSDLScreen(); 81 | initSound(emulatorOptionInt("sound")); 82 | emuThread = SDL_CreateThread(QLRun, "sQLux Emulator", NULL); 83 | init_done = 1; 84 | } 85 | if(init_done) { 86 | QLSDLProcessEvents(); 87 | } 88 | } 89 | 90 | #ifdef __WIN32__ 91 | #include 92 | static void reattach_console(void) 93 | { 94 | // Will succeed if launched from console, 95 | // will fail if launched from GUI 96 | if (AttachConsole(ATTACH_PARENT_PROCESS)) 97 | { 98 | freopen("CONIN$", "r", stdin); 99 | freopen("CONOUT$", "w", stdout); 100 | freopen("CONOUT$", "w", stderr); 101 | } 102 | } 103 | #endif 104 | 105 | int main(int argc, char *argv[]) 106 | { 107 | #if __EMSCRIPTEN__ 108 | wasm_init_storage(); 109 | #endif 110 | #ifdef __WIN32__ 111 | // Display output if started from console 112 | if (!getenv("SQLUX_WIN_DISABLE_CONSOLE_OUTPUT")) 113 | { 114 | reattach_console(); 115 | } 116 | #endif 117 | 118 | // set the homedir for the OS first 119 | SetHome(); 120 | 121 | emulatorOptionParse(argc, argv); 122 | 123 | // Set some things that used to be set as side effects 124 | const char *resString = emulatorOptionString("resolution"); 125 | parse_screen(resString); 126 | verbose = emulatorOptionInt("verbose"); 127 | 128 | // setup the boot_cmd if needed 129 | const char *boot_cmd=emulatorOptionString("boot_cmd"); 130 | if (strlen(boot_cmd)) { 131 | ux_boot = 2; 132 | int len = strlen(boot_cmd); 133 | ux_bname = (char *)malloc(len + 2); 134 | strncpy(ux_bname, boot_cmd, len + 2); 135 | ux_bname[len] = 0x0A; 136 | ux_bname[len + 1] = 0; 137 | } 138 | 139 | 140 | #if __EMSCRIPTEN__ 141 | emscripten_set_main_loop(emu_loop, -1, 1); 142 | #else 143 | emu_loop(); 144 | #endif 145 | 146 | emu_shutdown(); 147 | 148 | return 0; 149 | } 150 | -------------------------------------------------------------------------------- /src/emulator_init.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "debug.h" 12 | #include "emulator_options.h" 13 | #include "memaccess.h" 14 | #include "QInstAddr.h" 15 | #include "QL68000.h" 16 | #include "QLtraps.h" 17 | #include "QL_config.h" 18 | #include "QL_cconv.h" 19 | #include "QL_hardware.h" 20 | #include "QL_screen.h" 21 | #include "sds.h" 22 | #include "unixstuff.h" 23 | #include "version.h" 24 | #include "xcodes.h" 25 | #include "xqlmouse.h" 26 | 27 | // TODO: fixup iexl_general.h to not break stuff 28 | void InitialSetup(void); 29 | 30 | int emulatorLoadRom(const char *romDir, const char *romName, uint32_t addr, size_t size) 31 | { 32 | struct stat romStat; 33 | int ret, romFile; 34 | sds romPath; 35 | 36 | if (romDir[0] == '~') { 37 | romPath = sdscatprintf(sdsnew(""), "%s/%s/%s", 38 | homedir, romDir + 1, romName); 39 | } else { 40 | romPath = sdscatprintf(sdsnew(""), "%s/%s", romDir, romName); 41 | } 42 | 43 | ret = stat(romPath, &romStat); 44 | if (ret < 0) { 45 | fprintf(stderr, "FUNC: %s ERR: %s VAL: %s\n", 46 | __func__, strerror(errno), romPath); 47 | return ret; 48 | } 49 | 50 | if (romStat.st_size > size) { 51 | fprintf(stderr, "FUNC: %s ERR: Rom Size Error VAL: %zd != %jd\n", 52 | __func__, size, (intmax_t)romStat.st_size); 53 | return -1; 54 | } 55 | else if (romStat.st_size < size) 56 | puts ("SQLX WARNING: ROM is not 48k"); 57 | 58 | romFile = open(romPath, O_RDONLY); 59 | if (romFile < 0) { 60 | fprintf(stderr, "FUNC: %s ERR: %s VAL: %s\n", 61 | __func__, strerror(errno), romPath); 62 | return -1; 63 | } 64 | ret = read(romFile, (char *)memBase + addr, size); 65 | if (ret < 0) { 66 | fprintf(stderr, "FUNC: %s ERR: %s VAL: %s\n", 67 | __func__, strerror(errno), romPath); 68 | } 69 | close(romFile); 70 | 71 | sdsfree(romPath); 72 | 73 | return ret; 74 | } 75 | 76 | void emulatorInit() 77 | { 78 | char *rf; 79 | int rl = 0; 80 | void *tbuff; 81 | int ret; 82 | 83 | if (V1) 84 | printf("*** sQLux release %s\n\n", release); 85 | 86 | tzset(); 87 | 88 | if (emulatorOptionInt("ramsize")) { 89 | RTOP = (128 + emulatorOptionInt("ramsize")) * 1024; 90 | } else { 91 | RTOP = emulatorOptionInt("ramtop") * 1024; 92 | } 93 | 94 | if (RTOP < (256 * 1024)) { 95 | fprintf(stderr, "Sorry not enough ram defined for QDOS %dK\n", (RTOP / 1024) - 128); 96 | exit(1); 97 | } 98 | 99 | memBase = (int32_t *)malloc(RTOP); 100 | if (memBase == NULL) { 101 | fprintf(stderr, "sorry, not enough memory for a %dK QL\n",RTOP/1024); 102 | exit(1); 103 | } 104 | 105 | if (EmulatorTable()) { 106 | fprintf(stderr, "Failed to allocate instruction table\n"); 107 | free(memBase); 108 | exit(1); 109 | } 110 | 111 | const char *romdir = emulatorOptionString("romdir"); 112 | const char *sysrom = emulatorOptionString("sysrom"); 113 | const char *romport = emulatorOptionString("romport"); 114 | const char *romim = emulatorOptionString("romim"); 115 | const char *iorom1 = emulatorOptionString("iorom1"); 116 | const char *iorom2 = emulatorOptionString("iorom2"); 117 | 118 | ret = emulatorLoadRom(romdir, sysrom, QL_ROM_BASE, QL_ROM_SIZE); 119 | if (ret < 0) { 120 | fprintf(stderr, "Error Loading sysrom %s\n", sysrom); 121 | exit(ret); 122 | } 123 | 124 | if (strlen(romport)) { 125 | ret = emulatorLoadRom(romdir, romport, QL_ROM_PORT_BASE, QL_ROM_PORT_SIZE); 126 | if (ret < 0) { 127 | fprintf(stderr, "Error Loading romport %s\n", romport); 128 | exit(ret); 129 | } 130 | } else if (strlen(romim)) { 131 | ret = emulatorLoadRom(romdir, romim, QL_ROM_PORT_BASE, QL_ROM_PORT_SIZE); 132 | if (ret < 0) { 133 | fprintf(stderr, "Error Loading romim %s\n", romim); 134 | exit(ret); 135 | } 136 | } 137 | 138 | if (strlen(iorom1)) { 139 | ret = emulatorLoadRom(romdir, iorom1, QL_ROM2_BASE, QL_ROM2_SIZE); 140 | if (ret < 0) { 141 | fprintf(stderr, "Error Loading iorom1 %s\n", iorom1); 142 | exit(ret); 143 | } 144 | } 145 | 146 | if (strlen(iorom2)) { 147 | ret = emulatorLoadRom(romdir, iorom2, QL_ROM3_BASE, QL_ROM3_SIZE); 148 | if (ret < 0) { 149 | fprintf(stderr, "Error Loading iorom2 %s\n", iorom2); 150 | exit(ret); 151 | } 152 | } 153 | 154 | init_uqlx_tz(); 155 | 156 | init_iso(); 157 | 158 | LoadMainRom(); /* patch QDOS ROM*/ 159 | 160 | /* Minerva cannot handle more than 16M of memory... */ 161 | if (isMinerva && RTOP > 16384 * 1024) 162 | RTOP = 16384 * 1024; 163 | /* ...everything else not more than 4M */ 164 | if (!isMinerva && RTOP > 4096 * 1024) 165 | RTOP = 4096 * 1024; 166 | 167 | if (isMinerva) { 168 | qlscreen.xres = qlscreen.xres & (~(7)); 169 | qlscreen.linel = qlscreen.xres / 4; 170 | qlscreen.qm_len = qlscreen.linel * qlscreen.yres; 171 | 172 | qlscreen.qm_lo = 128 * 1024; 173 | qlscreen.qm_hi = 128 * 1024 + qlscreen.qm_len; 174 | if (qlscreen.qm_len > 0x8000) { 175 | if (((long)RTOP - qlscreen.qm_len) < 176 | 256 * 1024 + 8192) { 177 | /*RTOP+=qlscreen.qm_len;*/ 178 | printf("sorry, not enough RAM for such a big screen\n"); 179 | goto bsfb; 180 | } 181 | qlscreen.qm_lo = ((RTOP - qlscreen.qm_len) >> 15) 182 | << 15; /* RTOP MUST BE 32K aligned.. */ 183 | qlscreen.qm_hi = qlscreen.qm_lo + qlscreen.qm_len; 184 | RTOP = qlscreen.qm_lo; 185 | } 186 | } else /* JS doesn't handle big screen */ 187 | { 188 | bsfb: 189 | qlscreen.linel = 128; 190 | qlscreen.yres = 256; 191 | qlscreen.xres = 512; 192 | 193 | qlscreen.qm_lo = 128 * 1024; 194 | qlscreen.qm_hi = 128 * 1024 + 32 * 1024; 195 | qlscreen.qm_len = 0x8000; 196 | } 197 | 198 | if (V1 && (atof(emulatorOptionString("speed")) > 0.0)) 199 | printf("Emulation Speed: %s\n", emulatorOptionString("speed")); 200 | else if (V1) 201 | printf("Emulation Speed: FULL\n"); 202 | 203 | if (V1 && (emulatorOptionInt("sound") > 0)) 204 | printf("sound enabled, volume %i.\n", emulatorOptionInt("sound")); 205 | 206 | if (!isMinerva) { 207 | qlux_table[IPC_CMD_CODE] = UseIPC; /* install pseudoops */ 208 | qlux_table[IPCR_CMD_CODE] = ReadIPC; 209 | qlux_table[IPCW_CMD_CODE] = WriteIPC; 210 | qlux_table[KEYTRANS_CMD_CODE] = QL_KeyTrans; 211 | 212 | qlux_table[FSTART_CMD_CODE] = FastStartup; 213 | } 214 | qlux_table[ROMINIT_CMD_CODE] = InitROM; 215 | qlux_table[MDVIO_CMD_CODE] = MdvIO; 216 | qlux_table[MDVO_CMD_CODE] = MdvOpen; 217 | qlux_table[MDVC_CMD_CODE] = MdvClose; 218 | qlux_table[MDVSL_CMD_CODE] = MdvSlaving; 219 | qlux_table[MDVFO_CMD_CODE] = MdvFormat; 220 | qlux_table[POLL_CMD_CODE] = PollCmd; 221 | 222 | #ifdef SERIAL 223 | #ifndef NEWSERIAL 224 | qlux_table[OSERIO_CMD_CODE] = SerIO; 225 | qlux_table[OSERO_CMD_CODE] = SerOpen; 226 | qlux_table[OSERC_CMD_CODE] = SerClose; 227 | #endif 228 | #endif 229 | 230 | qlux_table[SCHEDULER_CMD_CODE] = SchedulerCmd; 231 | if (isMinerva) { 232 | qlux_table[MIPC_CMD_CODE] = KbdCmd; 233 | qlux_table[KBENC_CMD_CODE] = KBencCmd; 234 | } 235 | qlux_table[BASEXT_CMD_CODE] = BASEXTCmd; 236 | 237 | if (emulatorOptionInt("skip_boot")) 238 | qlux_table[0x4e43] = btrap3; 239 | 240 | InitialSetup(); 241 | 242 | if (isMinerva) { 243 | reg[1] = (RTOP & ~16383) | 1; 244 | SetPC(0x186); 245 | } 246 | 247 | QLdone = 0; 248 | } 249 | -------------------------------------------------------------------------------- /src/filemap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SinclairQL/sQLux/79aa52decf115d79af328f62ca5563e7f5f916be/src/filemap -------------------------------------------------------------------------------- /src/sqlux_hexdump.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 Graeme Gregory 3 | * 4 | * SPDX: WTFPL 5 | */ 6 | 7 | #include 8 | 9 | void sqlux_hexdump(const void* data, size_t size) { 10 | char ascii[17]; 11 | size_t i, j; 12 | ascii[16] = '\0'; 13 | for (i = 0; i < size; ++i) { 14 | printf("%02X ", ((unsigned char*)data)[i]); 15 | if (((unsigned char*)data)[i] >= ' ' && ((unsigned char*)data)[i] <= '~') { 16 | ascii[i % 16] = ((unsigned char*)data)[i]; 17 | } else { 18 | ascii[i % 16] = '.'; 19 | } 20 | if ((i+1) % 8 == 0 || i+1 == size) { 21 | printf(" "); 22 | if ((i+1) % 16 == 0) { 23 | printf("| %s \n", ascii); 24 | } else if (i+1 == size) { 25 | ascii[(i+1) % 16] = '\0'; 26 | if ((i+1) % 16 <= 8) { 27 | printf(" "); 28 | } 29 | for (j = (i+1) % 16; j < 16; ++j) { 30 | printf(" "); 31 | } 32 | printf("| %s \n", ascii); 33 | } 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/sqlux_windows.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021 Graeme Gregory 3 | * 4 | * SPDX: Zlib 5 | */ 6 | 7 | #ifdef __WIN32__ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #define POW10_7 10000000 20 | #define DELTA_EPOCH_IN_100NS INT64_C(116444736000000000) 21 | 22 | void sqlux_getemppath(int length, char *buffer) 23 | { 24 | GetTempPath(length, buffer); 25 | } 26 | 27 | char *__randname(char *template) 28 | { 29 | int i; 30 | struct timespec ts; 31 | unsigned long r; 32 | union { 33 | unsigned __int64 u64; 34 | FILETIME ft; 35 | } ct; 36 | 37 | GetSystemTimeAsFileTime(&ct.ft); 38 | 39 | r = (((ct.u64 - DELTA_EPOCH_IN_100NS) % POW10_7) * 100) * 65537 ^ (uintptr_t)&ts / 16 + (uintptr_t)template; 40 | for (i=0; i<6; i++, r>>=5) 41 | template[i] = 'A'+(r&15)+(r&16)*2; 42 | 43 | return template; 44 | } 45 | 46 | int sqlux_mkstemp(char *template) 47 | { 48 | size_t l = strlen(template); 49 | if (l<6 || memcmp(template+l-6, "XXXXXX", 6)) { 50 | errno = EINVAL; 51 | return -1; 52 | } 53 | 54 | int fd, retries = 100; 55 | do { 56 | __randname(template+l-6); 57 | if ((fd = _open(template, 58 | _O_CREAT | _O_TEMPORARY | _O_RDWR | O_EXCL | _O_SHORT_LIVED | _O_BINARY, 59 | _S_IREAD | _S_IWRITE))>=0) 60 | return fd; 61 | } while (--retries && errno == EEXIST); 62 | 63 | memcpy(template+l-6, "XXXXXX", 6); 64 | return -1; 65 | } 66 | 67 | #endif /* __WIN32__ */ 68 | -------------------------------------------------------------------------------- /src/wasm_support.c: -------------------------------------------------------------------------------- 1 | #include "emscripten.h" 2 | #include "wasm_support.h" 3 | 4 | void wasm_reload() { 5 | MAIN_THREAD_ASYNC_EM_ASM("window.location.reload()"); 6 | } 7 | 8 | EM_JS(int, wasm_does_boot_file_exist, (), { 9 | if (!FS.analyzePath(localWinFile).exists) { 10 | return 0; 11 | } 12 | return 1; 13 | }); 14 | 15 | EM_JS(void, wasm_init_storage, (), { 16 | var localStoragePath = '/local'; 17 | var defaultWinFile = 'win1.win'; 18 | localWinFile = localStoragePath + '/' + defaultWinFile; 19 | FS.mkdir(localStoragePath); 20 | FS.mount(IDBFS, {}, localStoragePath); 21 | FS.syncfs( 22 | true, function(err) { 23 | if (!FS.analyzePath(localWinFile).exists) { 24 | console.log('Copy default win1 file.'); 25 | var wincontent = 26 | FS.readFile('/default_win1.win'); 27 | FS.writeFile(localWinFile, wincontent); 28 | FS.syncfs(false, function(err){}); 29 | } 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /trace.c: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) UQLX - see COPYRIGHT 3 | */ 4 | 5 | 6 | #include "QL68000.h" 7 | #include 8 | 9 | #ifdef TRACE 10 | 11 | uw16 *tracelo; 12 | uw16 *tracehi; 13 | 14 | struct TRT 15 | { 16 | uw16 *low; 17 | uw16 *high; 18 | char *comment; 19 | } tracetable[]={ 20 | #if 1 // ROM 21 | {0,16384*3,"ROM"}, 22 | #endif 23 | #if 0 24 | {0xf7938,0xf7a38,"Qsave"}, 25 | #endif 26 | #if 0 27 | {0x1fb800,0x1ff14a,"Ptr_gen"}, 28 | #endif 29 | #if 0 30 | {0x36d4,0x3720,"Verify Name"}, 31 | {0x32a2,0x3378,"trap#2"}, 32 | {0x355a,0x36b6,"dirdev open"}, 33 | #endif 34 | #if 0 35 | {0x3ef6,0x405e,"vect $F0"}, 36 | {0x4a0c,0x4a4a,"RI.NEG"}, 37 | {0x497e,0x4a00,"RI.DIV"}, 38 | {0x48de,0x497e,"RI.MULT"}, 39 | {0x3e54,0x3ea8,"CN.ITOD"}, 40 | #endif 41 | /* the end marker, always should be there */ 42 | {0,0,0}}; 43 | 44 | /* Ptr Backtrace: */ 45 | 46 | struct TRT *curr=NULL; 47 | 48 | struct BTE { 49 | uw16 *where; /* absolute address */ 50 | uw16 *to; /* relative address */ 51 | int what; /* event type */ 52 | } backtrace[100]; 53 | 54 | #define BACKTRSIZE 100 55 | struct BTE *btcurr=backtrace; 56 | int btnochng=1; 57 | 58 | 59 | 60 | void TraceInit() 61 | { 62 | CheckTrace(); 63 | } 64 | 65 | 66 | void AddBackTrace(Ptr p, int type) 67 | { 68 | uw16 *lpc=(uw16*)((Ptr)pc-(Ptr)memBase); 69 | if (btcurr>backtrace+BACKTRSIZE) btcurr=backtrace; 70 | 71 | btcurr->where=p; 72 | btcurr->to=lpc; 73 | btcurr->what=type; 74 | 75 | btcurr++; 76 | btnochng=0; 77 | } 78 | 79 | 80 | void CheckTrace() 81 | { 82 | struct TRT *p; 83 | uw16 *lpc=(uw16*)((Ptr)pc-(Ptr)memBase); 84 | 85 | 86 | p=tracetable; 87 | curr=0; 88 | 89 | while((p->low) || (p->high)) 90 | { 91 | if ( ((p->low <=lpc) && (p->high >=lpc)) || 92 | (p->low >= lpc) && ( curr==NULL || ((p->low) <= (curr->low)))) 93 | curr=p; 94 | p++; 95 | } 96 | if (curr) 97 | { 98 | tracelo=(uw16*)((Ptr)(curr->low)+(long)memBase); 99 | tracehi=(uw16*)((Ptr)(curr->high)+(long)memBase); 100 | } 101 | else tracelo=(uw16*)((Ptr)RTOP+(long)memBase); 102 | } 103 | 104 | void DoTrace() 105 | { 106 | /*printf("entering Dotrace, pcl %x pch %x pc%x\n",tracelo,tracehi,pc);*/ 107 | 108 | if (pc>tracehi) 109 | { 110 | CheckTrace(); 111 | return; 112 | } 113 | 114 | printf("Trace : %s+%x\n",curr->comment,(Ptr)pc-(Ptr)(curr->low)-(long)memBase); 115 | DbgInfo(); 116 | } 117 | 118 | 119 | void BTShowException(int xc) 120 | { 121 | short i; 122 | int p1,p4; 123 | unsigned char *p3; 124 | 125 | long ixc=xc; 126 | 127 | 128 | if(ixc==4) 129 | { 130 | p3="Illegal code"; 131 | } 132 | else 133 | { 134 | p3=""; 135 | if(ixc==2) p3="bus error"; 136 | if(ixc==3) p3="address error"; 137 | if(ixc==5) p3="divide by zero"; 138 | if(ixc==6) p3="CHK instruction"; 139 | if(ixc==7) p3="TRAPV instruction"; 140 | if(ixc==8) p3="privilege violation"; 141 | if(ixc==9) p3="trace xc"; 142 | if(ixc==10) p3="Axxx instruction code"; 143 | if(ixc==11) p3="Fxxx instruction code"; 144 | if(xc>=32 && xc<=32+15) {printf("\tTRAP #%d\t",xc-32);return;} 145 | if(xc>=24 && xc<=24+7){printf("\tInterrupt #%d\t",xc-24);return;} 146 | } 147 | printf("\tException %s \t",p3); 148 | } 149 | 150 | void BackTrace(int depth) 151 | { 152 | struct BTE *p; 153 | char *evname; 154 | int what,x=0; 155 | 156 | 157 | printf("BackTrace:\n"); 158 | if (btnochng) { 159 | printf("\tunchanged\n"); 160 | return; 161 | } 162 | btnochng=1; 163 | p=btcurr; 164 | 165 | if (depth>BACKTRSIZE) depth=BACKTRSIZE; 166 | 167 | for(;depth--;p--) 168 | { 169 | if (pwhat; 172 | if (what>0){ 173 | switch(p->what){ 174 | case RTS : evname="RTS"; 175 | break; 176 | case RTE : evname="RTE"; 177 | break; 178 | case RTR : evname="RTR"; 179 | break; 180 | case JSR : evname="JSR"; 181 | break; 182 | case BSR : evname="BSR"; 183 | break; 184 | default : evname="unknown"; 185 | } 186 | printf("\t %s\t",evname); 187 | } 188 | else BTShowException(-what); 189 | 190 | printf("at PC=%x, new pc=%x\n",(Ptr)(p->where)-(Ptr)memBase,p->to); 191 | } 192 | } 193 | 194 | 195 | 196 | #endif /* TRACE */ 197 | -------------------------------------------------------------------------------- /trace.h: -------------------------------------------------------------------------------- 1 | /* 2 | * UQLX 3 | */ 4 | 5 | /* Backtracking events, negative values are negated exception numbers */ 6 | #define RTS 1 7 | #define RTE 2 8 | #define RTR 3 9 | #define JSR 4 10 | #define BSR 5 11 | -------------------------------------------------------------------------------- /unix.h: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) UQLX - see COPYRIGHT 3 | */ 4 | 5 | 6 | #define BASIC_QL_ROM "jsrom" /* you favourite ROM */ 7 | #define FLP_DISK "DiskImage2" /* name of your flp1_ drive */ 8 | #define USE_COLOR 0 /* set 1 if your XServer is correctly configured */ 9 | 10 | 11 | #define DATAD "mdv1_" 12 | #define PROGD "flp1_" 13 | #define SPOOLD "SER" 14 | #define PRINT_COMMAND "/usr/bin/lpr" /* where PRT sends it data */ 15 | /* experimental raw PAR device (n.i.) */ 16 | #define PAR_OUT_COMMAND "cat >/dev/lp0" /* PAR output */ 17 | #define PAR_IN_COMMAND "cat /dev/lp0" /* PAR input */ 18 | 19 | #ifdef __WIN32__ 20 | #define TEMPDIR "tmp/" 21 | #else 22 | #define TEMPDIR "/tmp" 23 | #endif 24 | 25 | #ifndef PATH_MAX 26 | #define PATH_MAX 400 27 | #endif 28 | 29 | extern char *oldscr; 30 | 31 | -------------------------------------------------------------------------------- /unixstuff.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | extern int QLdone; 5 | extern char *homedir; 6 | extern char *ux_bname; 7 | extern int ux_boot; 8 | extern int speed; 9 | 10 | void cleanup(int err); 11 | void set_rtc_emu(void); 12 | void SetHome(void); 13 | void uqlxInit(void); 14 | int QLRun(void *data); 15 | long ql2uxtime(long t); 16 | long ux2qltime(long t); 17 | int qm_fork(void (*cleanup)(), unsigned long id); 18 | void prep_rtc_emu(void); 19 | void GetDateTime(int32_t *t); 20 | void DbgInfo(void); 21 | void dosignal(void); 22 | int32_t ReadQlClock(void); 23 | uint32_t sysvar_l(uint32_t a); 24 | void init_uqlx_tz(void); 25 | -------------------------------------------------------------------------------- /util.c: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) UQLX - see COPYRIGHT 3 | */ 4 | 5 | 6 | 7 | /* some miscelaneous utility fucntions */ 8 | 9 | #if defined(QVFS) || defined(IPDEV) || defined(QSERIAL) 10 | /*#include "QLtypes.h"*/ 11 | #include "QL68000.h" 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #ifdef IPDEV 24 | #ifdef __WIN32__ 25 | #include 26 | #else 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #endif 33 | #endif 34 | #ifndef __WIN32__ 35 | #include 36 | #endif 37 | 38 | #include "QSerial.h" 39 | #include "QDOS.h" 40 | #include "driver.h" 41 | #include "util.h" 42 | 43 | 44 | int check_pend(int fd,int mode) 45 | { 46 | struct timeval tv; 47 | fd_set wfd,errfd,rfd,*xx; 48 | int res; 49 | 50 | /*printf("calling check_pend\n");*/ 51 | 52 | switch(mode) 53 | { 54 | case SLC_READ: xx=&rfd;; 55 | break; 56 | case SLC_WRITE: xx=&wfd; 57 | break; 58 | case SLC_ERR: xx=&errfd; 59 | break; 60 | default : printf("wrong mode for check_pend: %d\n",mode); 61 | return 0; 62 | } 63 | 64 | tv.tv_sec=0; 65 | tv.tv_usec=0; 66 | 67 | FD_ZERO(&wfd); 68 | FD_ZERO(&errfd); 69 | FD_ZERO(&rfd); 70 | /*FD_ZERO(&xfd);*/ 71 | 72 | FD_SET(fd,xx); 73 | 74 | 75 | res=select(fd+1,&rfd,&wfd,&errfd,&tv); 76 | /*printf("select returns %d, rfds %d wfds %d, errfds %d\n",res,rfd,wfd,errfd);*/ 77 | 78 | if (res<0) return 0; 79 | /*return FD_ISSET(fd,xx);*/ 80 | return (res>0); 81 | } 82 | 83 | #endif /* defined(QVFS) || defined(IPDEV) || defined(QSERIAL) */ 84 | -------------------------------------------------------------------------------- /util.h: -------------------------------------------------------------------------------- 1 | /* UQLX : some usefull functions */ 2 | 3 | /* mode for check_pend :*/ 4 | #define SLC_READ 0 5 | #define SLC_WRITE 1 6 | #define SLC_ERR 2 7 | 8 | int check_pend(int /*fd*/,int /*mode*/) ; 9 | -------------------------------------------------------------------------------- /uxfile.h: -------------------------------------------------------------------------------- 1 | #ifndef __UXFILE_H 2 | #define __UXFILE_H 3 | 4 | void qaddpath(char *mount, char *name, int maxnlen); 5 | int FSClose(int fd); 6 | int eretry(void); 7 | 8 | #endif /* __UXFILE_H */ 9 | 10 | -------------------------------------------------------------------------------- /version.c.in: -------------------------------------------------------------------------------- 1 | char *release = "${GIT_REPO_VERSION}-(${BUILD_DATE})"; 2 | 3 | -------------------------------------------------------------------------------- /x86_32.cmake: -------------------------------------------------------------------------------- 1 | # the name of the target operating system 2 | set(CMAKE_SYSTEM_NAME Linux) 3 | 4 | # which compilers to use for C and C++ 5 | set(CMAKE_C_COMPILER gcc) 6 | set(CMAKE_C_FLAGS -m32) 7 | set(CMAKE_CXX_COMPILER g++) 8 | set(CMAKE_CXX_FLAGS -m32) 9 | 10 | # here is the target environment located 11 | set(CMAKE_FIND_ROOT_PATH /usr/) 12 | 13 | # adjust the default behaviour of the FIND_XXX() commands: 14 | # search headers and libraries in the target environment, search 15 | # programs in the host environment 16 | set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) 17 | set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) 18 | set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) 19 | -------------------------------------------------------------------------------- /xc68.c: -------------------------------------------------------------------------------- 1 | /* UQLX */ 2 | 3 | /* fucntions to translate C68 to/from HOST constants and options */ 4 | 5 | #ifdef IPDEV 6 | 7 | #include "xc68.h" 8 | #include 9 | #include 10 | 11 | int c68err(int err) 12 | { 13 | switch(err) 14 | { 15 | case ENOTSOCK: return C68ERR_ENOTSOCK; 16 | case EDESTADDRREQ: return C68ERR_EDESTADDRREQ; 17 | case EMSGSIZE: return C68ERR_EMSGSIZE; 18 | case EPROTOTYPE: return C68ERR_EPROTOTYPE; 19 | case ENOPROTOOPT: return C68ERR_ENOPROTOOPT; 20 | case EPROTONOSUPPORT: return C68ERR_EPROTONOSUPPORT; 21 | #ifndef __WIN32__ 22 | case ESOCKTNOSUPPORT: return C68ERR_ESOCKTNOSUPPORT; 23 | #endif 24 | case EOPNOTSUPP: return C68ERR_EOPNOTSUPP; 25 | #ifndef __WIN32__ 26 | case EPFNOSUPPORT: return C68ERR_EPFNOSUPPORT; 27 | #endif 28 | case EAFNOSUPPORT: return C68ERR_EAFNOSUPPORT; 29 | case EADDRINUSE: return C68ERR_EADDRINUSE; 30 | case EADDRNOTAVAIL: return C68ERR_EADDRNOTAVAIL; 31 | case ENETDOWN: return C68ERR_ENETDOWN; 32 | case ENETUNREACH: return C68ERR_ENETUNREACH; 33 | case ENETRESET: return C68ERR_ENETRESET; 34 | case ECONNABORTED: return C68ERR_ECONNABORTED; 35 | case ECONNRESET: return C68ERR_ECONNRESET; 36 | case ENOBUFS: return C68ERR_ENOBUFS; 37 | case EISCONN: return C68ERR_EISCONN; 38 | case ENOTCONN: return C68ERR_ENOTCONN; 39 | #ifndef __WIN32__ 40 | case ESHUTDOWN: return C68ERR_ESHUTDOWN; 41 | case ETOOMANYREFS: return C68ERR_ETOOMANYREFS; 42 | #endif 43 | case ETIMEDOUT: return C68ERR_ETIMEDOUT; 44 | case ECONNREFUSED: return C68ERR_ECONNREFUSED; 45 | #ifndef __WIN32__ 46 | case EHOSTDOWN: return C68ERR_EHOSTDOWN; 47 | #endif 48 | case EHOSTUNREACH: return C68ERR_EHOSTUNREACH; 49 | case EALREADY: return C68ERR_EALREADY; 50 | case EINPROGRESS: return C68ERR_EINPROGRESS; 51 | default: return -1; 52 | } 53 | } 54 | 55 | char *protoname(int proto) 56 | { 57 | switch(proto) 58 | { 59 | case C68_IPPROTO_IP : return " dummy for IP "; 60 | case C68_IPPROTO_ICMP : return " control message protocol "; 61 | case C68_IPPROTO_GGP : return " gateway^2 (deprecated) "; 62 | case C68_IPPROTO_TCP : return " tcp "; 63 | case C68_IPPROTO_EGP : return " exterior gateway protocol "; 64 | case C68_IPPROTO_PUP : return " pup "; 65 | case C68_IPPROTO_UDP : return " user datagram protocol "; 66 | case C68_IPPROTO_IDP : return " xns idp "; 67 | case C68_IPPROTO_TP : return " tp-4 w/ class negotiation "; 68 | case C68_IPPROTO_EON : return " ISO cnlp "; 69 | case C68_IPPROTO_RAW : return " raw IP packet "; 70 | default : return "unknown protocol"; 71 | } 72 | 73 | } 74 | 75 | 76 | /* dummy fns, sometimes it should do all translations*/ 77 | void xso_q2x(int level,int optname, void* optval,int len) 78 | { 79 | char *proto; 80 | 81 | proto=protoname(level); 82 | 83 | printf("xso_q2x: proto %d %s, optname %d\n",level,proto,optname); 84 | } 85 | void xso_x2q(int level,int optname, void* optval,int len) 86 | { 87 | char *proto; 88 | 89 | proto=protoname(level); 90 | 91 | printf("xso_q2x: proto %d %s, optname %d\n",level,proto,optname); 92 | } 93 | 94 | #endif /* IPDEV */ 95 | -------------------------------------------------------------------------------- /xcodes.c: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) UQLX - see COPYRIGHT 3 | */ 4 | 5 | 6 | /*#include "QLtypes.h"*/ 7 | #include "QL68000.h" 8 | #include "QL.h" 9 | #include "xcodes.h" 10 | 11 | /* variable addresses */ 12 | 13 | uw32 IPC_CMD_ADDR; /* JS IPC patch*/ 14 | uw32 IPCR_CMD_ADDR; 15 | uw32 IPCW_CMD_ADDR; 16 | uw32 FSTART_CMD_ADDR; /* JS Fast start patch */ 17 | uw32 KEYTRANS_CMD_ADDR; /* JS Keytranslation patch */ 18 | uw16 KEYTRANS_OCODE; 19 | uw32 ROMINIT_CMD_ADDR; /* patch to link in drivers */ 20 | uw16 ROMINIT_OCODE; 21 | uw16 DEVPEFIO_OCODE; 22 | uw16 DEVPEFO_OCODE; 23 | 24 | -------------------------------------------------------------------------------- /xcodes.h: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) UQLX - see COPYRIGHT 3 | */ 4 | 5 | 6 | 7 | /* variable addresses */ 8 | extern uint32_t MIPC_CMD_ADDR; /* Minerva sx_ipcom */ 9 | extern uint32_t IPC_CMD_ADDR; /* JS IPC patch*/ 10 | extern uint32_t IPCR_CMD_ADDR; 11 | extern uint32_t IPCW_CMD_ADDR; 12 | extern uint32_t FSTART_CMD_ADDR; /* JS Fast start patch */ 13 | extern uint32_t KEYTRANS_CMD_ADDR; /* JS Keytranslation patch */ 14 | extern uint16_t KEYTRANS_OCODE; 15 | extern uint32_t ROMINIT_CMD_ADDR; /* patch to link in drivers */ 16 | extern uint16_t ROMINIT_OCODE; 17 | extern uint16_t DEVPEFIO_OCODE; 18 | extern uint16_t DEVPEFO_OCODE; 19 | 20 | 21 | /* hardwired addresses in "QEML ROM" */ 22 | #define MDVIO_CMD_ADDR 0x1C000 23 | #define MDVO_CMD_ADDR 0x1C002 24 | #define MDVC_CMD_ADDR 0x1C004 25 | #define MDVSL_CMD_ADDR 0x1C006 26 | #define MDVFO_CMD_ADDR 0x1C008 27 | 28 | #define DEVIO_CMD_ADDR 0x1C020 29 | #define DEVC_CMD_ADDR 0x1C022 /* DEVO_CMD_ADDR not hardwired */ 30 | 31 | #define SCHEDULER_CMD_ADDR 0x1C030 /* scheduler loop routine */ 32 | #define MIPC_CMD_ADDR 0x1C032 33 | #define POLL_CMD_ADDR 0x1C034 /* gap needed before next address !!!! */ 34 | #define KBENC_CMD_ADDR 0x1C044 /* ... cause they call each other */ 35 | 36 | #if 1 37 | #define DEVPEF_IO_ADDR 0x1C050 /* extended screen fool driver */ 38 | #define DEVPEF_OPEN_ADDR 0x1C054 /* for ptr_gen */ 39 | #define DEVPEF_CLOSE_ADDR 0x1C058 40 | #endif 41 | 42 | #define UQLX_STR_SCRATCH 0x1C400 43 | 44 | 45 | /* instruction opcodes */ 46 | #define IPC_CMD_CODE 0xadc0 47 | #define IPCR_CMD_CODE 0xadc1 48 | #define IPCW_CMD_CODE 0xadc2 49 | #define MDVR_CMD_CODE 0xadc3 /* patch vectored utilities */ 50 | #define MDVW_CMD_CODE 0xadc4 51 | #define MDVV_CMD_CODE 0xadc5 52 | #define MDVH_CMD_CODE 0xadc6 53 | #define FSTART_CMD_CODE 0xadc7 54 | #define KEYTRANS_CMD_CODE 0xadc8 55 | 56 | #define ROMINIT_CMD_CODE 0xaaa0 57 | #define MDVIO_CMD_CODE 0xaaa1 58 | #define MDVO_CMD_CODE 0xaaa2 59 | #define MDVC_CMD_CODE 0xaaa3 60 | #define MDVSL_CMD_CODE 0xaaa4 61 | #define MDVFO_CMD_CODE 0xaaa5 62 | 63 | #define OSERIO_CMD_CODE 0xaaa6 /* old style serial driver*/ 64 | #define OSERO_CMD_CODE 0xaaa7 /* *** OBSOLETE *** */ 65 | #define OSERC_CMD_CODE 0xaaa8 66 | 67 | #define SCHEDULER_CMD_CODE 0xaaa9 68 | 69 | #define DEVIO_CMD_CODE 0xaaaa 70 | #define DEVO_CMD_CODE 0xaaab 71 | #define DEVC_CMD_CODE 0xaaac 72 | 73 | #define MIPC_CMD_CODE 0xaaad 74 | #define POLL_CMD_CODE 0xaaae 75 | #define KBENC_CMD_CODE 0xaaaf 76 | 77 | #define BASEXT_CMD_CODE 0xaab0 78 | 79 | #define DEVPEF_CMD_CODE 0xaab1 80 | #define DEVPEFO_CMD_CODE 0xaab2 81 | 82 | #define REGEMU_CMD_CODE 0xaab3 83 | 84 | extern void PollCmd(void); 85 | extern void KBencCmd(void); 86 | extern void BASEXTCmd(void); 87 | extern void RegEmuCmd(void); 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /xqlmouse.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void SchedInit(void); 4 | void SchedulerCmd(void); 5 | 6 | --------------------------------------------------------------------------------