├── .github └── FUNDING.yml ├── .vscode ├── launch.json └── tasks.json ├── COPYING ├── MANUAL.md ├── README.md ├── TODO.md ├── bbcbasic.txt ├── build.z80 ├── editor.z80 ├── equs.z80 ├── eval.z80 ├── examples ├── ANIMAL.DAT ├── animal.bbc ├── f-index.bbc ├── f-rand0.bbc ├── f-rand1.bbc ├── f-rand2.bbc ├── f-rser1.bbc ├── f-rser2.bbc ├── f-rstd.bbc ├── f-weser1.bbc ├── f-weser2.bbc ├── f-wser1.bbc ├── f-wser2.bbc ├── f-wstd.bbc ├── merge.bbc ├── sort.bbc └── sortreal.bbc ├── exec.z80 ├── fpp.z80 ├── images ├── bbc_basic.png ├── bbc_basic_readme_header.png └── bbc_basic_rtc.png ├── macros.z80 ├── main.z80 ├── misc.z80 ├── next_cursor.z80 ├── next_debug.z80 ├── next_dma.z80 ├── next_dos.z80 ├── next_graphics.z80 ├── next_graphics_L2.z80 ├── next_graphics_ULA.z80 ├── next_init.z80 ├── next_io.z80 ├── next_mouse.z80 ├── next_rtc.z80 ├── next_sound.z80 ├── next_sprites.z80 ├── patch.z80 ├── ram.z80 ├── releases ├── README.md ├── bbcbasic_20210509.nex ├── bbcbasic_20210510.nex ├── bbcbasic_20210513.nex ├── bbcbasic_20210516.nex ├── bbcbasic_20210520.nex ├── bbcbasic_20210523.nex ├── bbcbasic_20210524.nex ├── bbcbasic_20210525.nex ├── bbcbasic_20210603.nex ├── bbcbasic_20210606.nex ├── bbcbasic_20210609.nex ├── bbcbasic_20210613.nex ├── bbcbasic_20210614.nex ├── bbcbasic_20210622.nex ├── bbcbasic_20210706.nex ├── bbcbasic_20210713.nex └── bbcbasic_20210720.nex ├── sorry.z80 └── tests ├── BENCHMARK.md ├── README.md ├── assembler_Z80N.bbc ├── benchm1.bbc ├── benchm2.bbc ├── benchm3.bbc ├── benchm4.bbc ├── benchm5.bbc ├── benchm6.bbc ├── benchm7.bbc ├── benchm8.bbc ├── circle.bbc ├── cube.bbc ├── fireworks.bbc ├── ftest1.bbc ├── ftest2.bbc ├── ftest3.bbc ├── hatgraph.bbc ├── lines.bbc ├── mandlebrot.bbc ├── mouse.bbc ├── on_proc.bbc ├── oscall.bbc ├── shadows.bbc ├── snake.bbc ├── sound.bbc ├── source text ├── assembler_Z80N.txt ├── cube.txt ├── hatgraph.txt ├── mandlebrot.txt ├── mandlebrot_ascii.txt ├── shadows.txt └── stars.txt ├── tornado.bbc ├── triangles.bbc └── udg.bbc /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | ko_fi: breakintoprogram 4 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "dezog", 9 | "request": "launch", 10 | "name": "Z80 Debugger", 11 | "remoteType": "zrcp", 12 | "zrcp": { 13 | "hostname": "localhost", 14 | "port": 10000 15 | // "skipInterrupt": false, 16 | }, 17 | // "topOfStack": "Stack_Top", 18 | "rootFolder": "${fileDirname}", 19 | "sjasmplus": [ 20 | { 21 | "path": "${fileDirname}/${fileBasenameNoExtension}.sld", 22 | "useFiles": true, 23 | "asm": "sjasmplus", 24 | "mainFile": "${fileDirname}/${fileBasenameNoExtension}.z80" 25 | } 26 | ], 27 | "disassemblerArgs": { 28 | "esxdosRst": true 29 | }, 30 | "load": "${fileDirname}/${fileBasenameNoExtension}.nex", 31 | "startAutomatically": false, 32 | "preLaunchTask": "sjasmplus" 33 | } 34 | ], 35 | "compounds": [] 36 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "label": "sjasmplus", 8 | "type": "shell", 9 | "command": "sjasmplus", 10 | "args": [ 11 | "--fullpath", 12 | "--zxnext", 13 | "--sld=${fileDirname}/${fileBasenameNoExtension}.sld", 14 | "${file}" 15 | ], 16 | "group": { 17 | "kind": "build", 18 | "isDefault": true 19 | } 20 | } 21 | ] 22 | } -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | Copyright (c) 1984-2000 R.T. Russell 2 | 3 | This software is provided 'as-is', without any express or implied 4 | warranty. In no event will the authors be held liable for any damages 5 | arising from the use of this software. 6 | 7 | Permission is granted to anyone to use this software for any purpose, 8 | including commercial applications, and to alter it and redistribute it 9 | freely, subject to the following restrictions: 10 | 11 | 1. The origin of this software must not be misrepresented; you must not 12 | claim that you wrote the original software. If you use this software 13 | in a product, an acknowledgment in the product documentation would be 14 | appreciated but is not required. 15 | 2. Altered source versions must be plainly marked as such, and must not be 16 | misrepresented as being the original software. 17 | 3. This notice may not be removed or altered from any source distribution. 18 | -------------------------------------------------------------------------------- /MANUAL.md: -------------------------------------------------------------------------------- 1 | # manual 2 | 3 | In addition to the core BBC Basic for Z80 core language (details of which [can be found here](bbcbasic.txt)), BBC Basic for Next adds the following functionality: 4 | 5 | ## Editor 6 | 7 | A line editor is provided, that allows the user to enter a line of code up to 255 characters long. A cursor can be moved around this line, and text can be deleted or inserted at the current character position. 8 | 9 | A copy mode is provided, by pressing EDIT (Shift+1). When in copy mode, the cursor can be moved around the screen. Pressing Delete (Shift+0) will copy the character under the cursor into the current line. Pressing EDIT or CR will exit copy mode. 10 | 11 | ## Assembler 12 | 13 | The assembler has been extended to handle Z80N instructions. 14 | 15 | See [assembler_Z80N.bbc](tests/source%20text/assembler_Z80N.txt) in the folder [tests/source text](tests/source%20text) for a usage example. 16 | 17 | ## BASIC 18 | 19 | The following statements differ from the BBC Basic standard: 20 | 21 | ### PUT port,value 22 | 23 | Write to a port; add &10000 to port to write to a NEXTREG register 24 | 25 | Examples: 26 | 27 | - `PUT 254,5` Output 5 to Z80 port 254 28 | - `PUT &10007,3` Output 3 to Next register 7 29 | 30 | ### GET(port) 31 | 32 | Read from a port; add &10000 to port to read from a NEXTREG register 33 | 34 | Examples: 35 | 36 | - `A = GET(254)` Read from Z80 port 254 37 | - `A = GET(&10007)` Read from Next register 7 38 | 39 | ### GET(x,y) 40 | 41 | Read a character code from the screen position X, Y. If the character cannot be read, return -1 42 | 43 | Example: 44 | 45 | - `A = GET(0,0)` Read character code from screen position(0,0) 46 | 47 | ### GET$(x,y) 48 | 49 | As GET(x,y), but return a string rather than a character code 50 | 51 | Example: 52 | 53 | - `A$ = GET$(0,0)` Read character code from screen position(0,0) 54 | 55 | ### PLOT type,x,y 56 | 57 | The only plot modes supported currently are: 58 | 59 | - `PLOT 0, X, Y` Draw a line from last plot position to X, Y 60 | - `PLOT 64, X, Y` Plot a point 61 | - `PLOT 80, X, Y` Draw a filled triangle. The other two points are the last two plot positions. 62 | - `PLOT 144, 0, R` Draw a circle of radius R. The center position is the last plot position 63 | 64 | Examples: 65 | 66 | Draw a triangle: 67 | 68 | `MOVE 10,15: MOVE 253,40: PLOT 80,55,181` 69 | 70 | Draw a circle 71 | 72 | `MOVE 128,96: PLOT 144,0,95` 73 | 74 | ### MODE n 75 | 76 | Three modes supported: 77 | 78 | - `MODE 0` ULA mode (Normal Spectrum 256x192 Graphics) 79 | - `MODE 1` Layer 2 mode (256 x 192, 256 colours per pixel) 80 | - `MODE 2` Layer 2 mode (320 x 256, 256 colours per pixel) 81 | - `MODE 3` Layer 2 mode (640 x 256, 16 colours per pixel) 82 | 83 | ### COLOUR n[,type] 84 | 85 | An additional optional parameter, type, has been added. If not specified, will default to 0. 86 | 87 | - 0: Set colour as BBC Standard; add 128 to set paper colour. 88 | - 1: Set foreground (ink) colour 89 | - 2: Set background (paper) colour 90 | - 3: Set border colour 91 | - 4: Set bright (Mode 0 only) 92 | - 5: Set flash (Mode 0 only) 93 | 94 | Mode 1 and 2 are useful in Mode 1, as it allows you to access all 256 Next colours. Mode 0 is maintained as a default, but will only allow you to access the first 128 colours. 95 | 96 | Examples: 97 | 98 | - `COLOUR 2,3` Set the border colour to Red 99 | - `COLOUR 1,255` Set the foreground colour to 255 (Mode 1) 100 | - `COLOUR 5,1` Set to flash (Mode 0) 101 | 102 | ### GCOL mode, colour[, type] 103 | 104 | Sets the graphic colour, as per COLOUR 105 | 106 | Mode values for MODE 0 is currently one of the following: 107 | - 0 and 1 set the pixel 108 | - 2 and 6 clear the pixel 109 | - 3 and 4 invert the pixel 110 | This is an attempt to stick to the BBC BASIC standard with 1-bit graphics 111 | 112 | Mode for MODE 1 should work as per BBC Basic specifications but currently only supports 0 and 6 due to a memory mapping issue I need to resolve. 113 | 114 | All types are valid for Mode 0. Mode 1 only recognises type 0, 1 and 3. 115 | 116 | ### VDU 117 | 118 | The VDU command is a work-in-progress with a handful of mappings implemented: 119 | 120 | - `VDU 8` Backspace 121 | - `VDU 9` Advance one character 122 | - `VDU 10` Line feed 123 | - `VDU 11` Move cursor up one line 124 | - `VDU 12` CLS 125 | - `VDU 13` Carriage return 126 | - `VDU 16` CLG 127 | - `VDU 17,col` COLOUR col 128 | - `VDU 18,mode,col` GCOL mode,col 129 | - `VDU 19,l,r,g,b` COLOUR l,r,g,b 130 | - `VDU 22,n` Mode n 131 | - `VDU 23,c,b1,b2,b3,b4,b5,b6,b7,b8` Define UDG c 132 | - `VDU 25,mode,x;y;` PLOT mode,x,y 133 | - `VDU 29,x;y;` Set graphics origin to x,y 134 | - `VDU 30` Home cursor 135 | - `VDU 31,x,y` TAB(x,y) 136 | 137 | Examples: 138 | 139 | `VDU 25,64,128;88;` Plot point in middle of screen 140 | 141 | `VDU 22,1` Change to Mode 1 142 | 143 | ### SOUND channel,volume,pitch,duration 144 | 145 | Play a sound 146 | 147 | - channel: AY channel between 0 and 2 148 | - volume: 0 (off), -15 (loud) 149 | - pitch: Pitch in quarter-semitones, where 53 is middle C, and 89 is A440 150 | - duration: Duration in 25ths of a second 151 | 152 | Sounds are played asynchronously; up to 5 notes can be queued ahead. If a sixth note is added to the queue, the SOUND command will block until there is space in the queue. 153 | 154 | ### ADVAL(device) 155 | 156 | Read a device. Currently supports the Next Kempston mouse interface. 157 | Implemented as OSBYTE 0x80 158 | 159 | - `PRINT ADVAL(5)` Get X boundary (1280) 160 | - `PRINT ADVAL(6)` Get Y boundary (1024) 161 | - `X% = ADVAL(7)` Get X mouse position (0 <= X < 1280) 162 | - `Y% = ADVAL(8)` Get Y mouse position (0 <= Y < 1024) 163 | - `B% = ADVAL(9)` Get mouse buttons (8 bit value) 164 | 165 | Mouse buttons: 166 | Bits 7-4: Mouse wheel counter 167 | Bit 2: Middle button 168 | Bit 1: Left 169 | Bit 0: Right 170 | 171 | ## STAR commands 172 | 173 | The star commands are all prefixed with an asterisk. These commands do not accept variables or expressions as parameters. Parameters are separated by spaces. Numeric parameters can be specified in hexadecimal by prefixing with an '&' character. Paths are unquoted. 174 | 175 | If you need to pass a parameter to a star command, call it using the OSCLI command, for example: 176 | 177 | - `LET T% = 3: OSCLI("TURBO " + STR$(T%))` 178 | 179 | ### BYE 180 | 181 | Exits BBC Basic by doing a soft reset (does not work on emulators) 182 | 183 | ### CAT (or .) 184 | 185 | List the contents of the current directory 186 | 187 | - `*CAT` 188 | 189 | ### DIR 190 | 191 | Change the current directory; works in much the same way as a PC/Mac command line: 192 | 193 | - `*DIR name` Change to the specified directory by name 194 | - `*DIR ..` Go back up a directory 195 | - `*DIR \` Go to the root directory 196 | 197 | Aliases: CD 198 | 199 | ### ERASE 200 | 201 | Erase a file 202 | 203 | - `*ERASE test.bbc` Erase the file test.bbc 204 | - `*ERASE *.txt` Wildcards are permitted 205 | 206 | Aliases: DELETE 207 | 208 | ### MKDIR 209 | 210 | Make a directory 211 | 212 | - `*MKDIR tests` Make the folder tests 213 | 214 | ### RMDIR 215 | 216 | Remove a directoy 217 | 218 | - `*RMDIR tests` Remove the folder tests 219 | 220 | ### DRIVE 221 | 222 | Select the current working drive 223 | 224 | - `*DRIVE D` Change to drive D 225 | - `*DRIVE $` Change to the default drive 226 | 227 | ### LOAD 228 | 229 | Load a block of memory in 230 | 231 | - `*LOAD SCREEN.SCR 16384` Load file SCREEN.SCR to address 168384 232 | 233 | ### SAVE 234 | 235 | Save a block of memory out 236 | 237 | - `*SAVE SCREEN.SCR 16384 6912` Save the screen out to file SCREEN.SCR 238 | 239 | ### TIME 240 | 241 | Output the current RTC time (if RTC fitted) in BBC Master format. 242 | 243 | The time is also available in the system variable TIME$ 244 | 245 | ### TURBO n 246 | 247 | Will set the Next CPU turbo mode: 248 | 249 | - `*TURBO 0`: 3.5Mhz 250 | - `*TURBO 1`: 7Mhz 251 | - `*TURBO 2`: 14Mhz 252 | - `*TURBO 3`: 28Mhz 253 | 254 | ### MEMDUMP start len 255 | 256 | List contents of memory, hexdump and ASCII. 257 | 258 | - `*MEMDUMP 0 200` Dump the first 200 bytes of ROM 259 | 260 | ### FX n 261 | 262 | Implemented as OSBYTE 263 | 264 | - `*FX 11 n`: Set keyboard auto-repeat delay 265 | - `*FX 12 n`: Set keyboard auto-repeat period 266 | - `*FX 19`: Wait for the horizontal sync 267 | - `*FX 20 n`: Reserve space for UDGs in RAM 268 | 269 | ## OS commands 270 | 271 | The following OS calls are intercepted and pointed to an equivalent routine in the Z80 code: 272 | 273 | - `&FFF4` OSBYTE 274 | - `&FFEE` OSWRCH 275 | - `&FFD7` OSBGET 276 | - `&FFD4` OSBPUT 277 | 278 | Note: `OSBYTE` only supports 0x00, 0x13, 0x14 and 0x80. 279 | 280 | Example: Accessing mouse X coordinate in BASIC 281 | 282 | 10 A%=&80 283 | 20 L%=7 284 | 30 X%=USR &FFF4 285 | 40 PRINT TAB(0,0);X%, 286 | 50 GOTO 30 287 | 288 | ## Other considerations 289 | 290 | I use ULA hardware scrolling, so the top-left screen address is not guaranteed to be 0x4000, likewise the attributes address at 0x5800. 291 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # next-bbc-basic 2 | 3 | A port of BBC Basic for Z80 to the Spectrum Next 4 | 5 | ![BBC Basic for Spectrum Next](images/bbc_basic_readme_header.png) 6 | 7 | ### What is BBC Basic for Z80? 8 | 9 | The original version of BBC Basic was written by Sophie Wilson at Acorn in 1981 for the BBC Micro range of computers, and was designed to support the UK Computer Literacy Project. R.T.Russell was involved in the specification of BBC Basic, and wrote his own Z80 version that was subsequently ported to a number of Z80 based machines. [I highly recommend reading his account of this on his website for more details](http://www.bbcbasic.co.uk/bbcbasic/history.html). 10 | 11 | As an aside, R.T.Russell still supports BBC Basic, and has ported it for a number of modern platforms, including Android, Windows, and SDL, which are [available from his website here](https://www.bbcbasic.co.uk/index.html). 12 | 13 | ### Why am I doing this? 14 | 15 | Whilst I love Sinclair BASIC, I feel that BBC Basic addresses many of its shortcomings, including the clunky editor, variable name length limitations for strings and arrays, and performance. 16 | 17 | “Ah”, I hear you say. “I can load a BBC Micro Core in my Next to run BBC Basic”. Yes of course you can do that, and it is an excellent core. 18 | 19 | The advantage of running BBC Basic native on the Next is that it can potentially take advantage of the Next’s advanced graphics and sound capabilities; hardware sprites, Layer 2 graphics, multiple AY chips, and of course the legendary 28Mhz Turbo mode. 20 | 21 | ### The Challenges 22 | 23 | The foundation of this port is R.T.Russell's original BBC Basic for Z80 code (for CP/M), with the CP/M specific code stripped out. This foundation code is just pure BASIC interpreter with no graphics, sound or file I/O support. 24 | 25 | I will need to add all of that back in, in a manner that befits BBC Basic, whilst including all the features available to the Next in a language that was not designed to handle them, such as hardware sprites. 26 | 27 | ### Next Specific Modifications 28 | 29 | I'm attempting to make this as close to Version 4 of the BBC Basic Standard, resident in the BBC Master series, to the degree that it should be able to load and run BBC Micro code. There are a handful of exceptions, noted in the [manual document](MANUAL.md). 30 | 31 | ### Assembling 32 | 33 | The code is written to be assembled by the SJASMPLUS assembler. Details of the toolchain I use [can be found here on my website](http://www.breakintoprogram.co.uk/computers/zx-spectrum-next/assembly-language/z80-development-toolchain). 34 | 35 | > From version 0.08 this project is no longer compatible with ZEsarUX 9.2. Recommend upgrading to ZEsarUX 9.3 Beta 1 or higher. 36 | 37 | Every endeavour will be made to ensure the code is stable and will assemble, yet as this is a work-in-progress done in my spare time there will be instances where this is not the case. 38 | 39 | > Please avoid raising pull requests: The code will be in a state of flux for at least the next couple of months whilst I jiggle source around to fit the assembled code into 2 x 16K ROMs. I'm not quite geared up for collaboration just yet! 40 | 41 | > Raise an issue if you notice anything amiss; I will endeavour to get back to you. Bear with me if it takes a while to get back to you. 42 | 43 | ### Releases 44 | 45 | I'll dump significant updates as executable nex files in the [releases](releases) folder 46 | 47 | ### License 48 | 49 | This code is distributable under the terms of a zlib license. Read the file [COPYING](COPYING) for more information. 50 | 51 | The code, as originally written by R.T. Russell and [downloaded from David Given's GitHub page](https://github.com/davidgiven/cpmish/tree/master/third_party/bbcbasic), has been modified slightly, either for compatibility reasons when assembling using sjasmplus, or for development reasons for this release: 52 | 53 | The original files are: [eval.z80](eval.z80), [exec.z80](exec.z80), [fpp.z80](fpp.z80), [patch.z80](patch.z80), [ram.z80](ram.z80) and [sorry.z80](sorry.z80). 54 | 55 | - General changes: 56 | - The top-of-file comments have been tweaked to match my style 57 | - GLOBAL and EXPORT directives have been removed and any global labels prefixed with @ 58 | - Source in z80 now enclosed in MODULES to prevent label clash 59 | - A handful of '"' values have been converted to 34, and commented with ASCII '"' 60 | - A [build.z80](build.z80) file has been added; this includes all other files and is the file to build 61 | - All CPMish code has been removed as this version is not going to run on CP/M 62 | - A handful of Z80N optimisations have been made. These are marked with a conditional assembly IF/ELSE/ENDIF block, and the original code can be assembled by setting BUILD_Z80N to 0 in the file [build.z80](build.z80). 63 | - File [main.z80](main.z80) 64 | - Improved readability of KEYWDS table 65 | - File [patch.z80](patch.z80) 66 | - The function PUT has been moved into it from [exec.z80](exec.z80) 67 | - The function GET has been moved into it from [eval.z80](eval.z80) 68 | - File [exec.z80](exec.z80) 69 | - The built-in assembler has been modified to support Z80N instructions 70 | - The assembler opcodes table now uses a macro for sake of clarity 71 | 72 | Other than that, the source code is equivalent to the code originally authored by R.T.Russell, downloaded on David Given's website: 73 | 74 | http://cowlark.com/2019-06-14-bbcbasic-opensource/index.html 75 | 76 | The bulk of the Spectrum Next specific code I've written can be found in the z80 files prefixed with "next_". I've clearly commented any changes made to R.T.Russell's original source files in the source code. In addition to the above, I've added the following files: [editor.z80](editor.z80), [equs.z80](equs.z80), [macros.z80](macros.z80), [misc.z80](misc.z80) and [rom.z80](rom.z80). 77 | 78 | Any additions or modifications I've made to port this to the Next have been released under the same licensing terms as the original code, and code that has been copied or inspired by other sources is clearly marked, with the appropriate accreditations. 79 | 80 | Dean Belfield 81 | 82 | Twitter: [@breakintoprogram](https://twitter.com/BreakIntoProg) 83 | Blog: http://www.breakintoprogram.co.uk 84 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | # TODO 2 | ### Next Jobs 3 | ### Known Bugs / Missing Features 4 | - Cannot set RTC by assigning to TIME$ 5 | - Timestamp not set in saved files 6 | - No attempt to check whether a loaded file will fit in memory 7 | - The DIR outputs file size in bytes; be good to have human readable units (bytes/KB/MB) 8 | - Aspect ratio of circle is stretched vertically in MODE 3 9 | - GCOL modes not working for filled triangles 10 | - Improve the keyscan routine when selecting shifted characters 11 | - Get_Char does not recognise UDG characters 12 | - Get_Char in L2 - perhaps consider using background colour rather than foreground to pick out text 13 | - *FX 11 1 sets a really slow keyboard delay 14 | - *FX 20 should take a copy of the ROM charset into RAM 15 | - File issues 16 | - BASIC does not close all open files on error 17 | ### Fixed Bugs / New Features 18 | #### Version 0.16 19 | - Implement OSCALL function 20 | - Implement ADVAL function 21 | - Add Kempston mouse support (via ADVAL function) 22 | - Add user-definable keyboard auto-repeat delay and period 23 | #### Version 0.15 24 | - Bug in PUTCSR; TAB(X,Y) ignores Y coordinate 25 | - Modifications to GET and PUT 26 | - Add GET(x, y) and GET$(x, y) to read character from screen position (x, y) 27 | - Change GET(n, 1) to GET(n OR &10000) 28 | - Change PUT(n, 1) to PUT(n OR &10000) 29 | #### Version 0.14 30 | - RAM contention is now switched off 31 | - GCOL modes not working for Plot in Mode 3 32 | - File commands 33 | - OPENOUT and OPENUP now working to spec 34 | - INPUT# now more robust when more than one file is open 35 | - PTR# and EXT# now work 36 | #### Version 0.13 37 | - Set all graphics to use common viewport (1280x1024) with origin at bottom left, like BBC Micro 38 | - Added support for VDU 29 (setting the graphics origin) 39 | - CLG now works correctly 40 | - COPY characters now works in Modes 1, 2 and 3 41 | #### Version 0.12 42 | - Mode 3 - horizontal line not quite working (see circles.bbc, gaps in circle at end of draw) 43 | #### Version 0.11 44 | - Mode 3 (640x256) added 45 | - MEMDUMP now displays 16 bytes per line in Mode 3 46 | #### Version 0.10 47 | - ESC handled correctly on interrupt 48 | - ESC now breaks out of GET($) and SOUND command 49 | - Plot modes 1-5 and Point now work in Modes 1 and 2 50 | - Fixed disappearing cursor bug at bottom of screen in Mode 1 and Mode 2 51 | - Fixed default palettes in all modes 52 | - Fixed zero length line bug 53 | #### Version 0.09 54 | - Fixed clipping in line, circle and triangle graphics primitives 55 | - Fixed issue with negative plot coordinates 56 | - Fixed issue with scrolling and graphics primitives in Modes 0, 1 and 2 57 | - Added AY sound support 58 | #### Version 0.08 59 | - Mode 2 (320x256) now implemented 60 | - Cursor is now a sprite and works in all modes 61 | - Editor refactored to fix many bugs, including: 62 | - Editor scrolls incorrectly when editing at bottom of screen 63 | - Unable to type in COPY mode 64 | #### Version 0.07 65 | - Added *DELETE, *MKDIR, *RMDIR and *DRIVE commands 66 | - More specific errors in exsDOS are now displayed 67 | - exsDOS now shifts temporarily to 28Mhz CPU to fix errors running on MiSTer 68 | #### Version 0.06 69 | - Scrolling in Mode 1 now uses the background colour to fill 70 | - SAVE, LOAD and CHAIN commands now implemented 71 | #### Version 0.05 72 | - Rudimentary file system up and running 73 | - Fixed debounce on CAPS LOCK or EDIT 74 | - INKEY$ no longer waits for input 75 | - Added keyboard repeating 76 | - When in COPY mode, the cursor now wraps correctly at end of screen 77 | - COPY mode now stops inserting when buffer is full 78 | - ESC now exits AUTO line numbering 79 | - POINT code moved to next_graphics.z80 80 | #### Version 0.04 81 | - Added line editing functionality 82 | - OLD now restores a program after NEW 83 | - INPUT statement now returns a value 84 | - LD A,(IX) no longer throws a syntax error in the assembler 85 | - GCOL now sets FLASH and BRIGHT 86 | - Line editor now works in MODE 1 87 | - Background colour can now be set in Mode 1 88 | - COPY mode now works after the screen has scrolled 89 | #### Version 0.03 90 | - Z80 assembler output now tabulated correctly 91 | - Spectrum (C) symbol now remapped as ASCII 0xA9 92 | -------------------------------------------------------------------------------- /bbcbasic.txt: -------------------------------------------------------------------------------- 1 | BBC BASIC (Z80) 2 | 3 | Generic CP/M Version 3.00 4 | 5 | (C) Copyright R.T.Russell 1982-1999 6 | 7 | 1. INTRODUCTION 8 | 9 | BBC BASIC (Z80) has been designed to be as compatible as possible with 10 | Version 4 of the 6502 BBC BASIC resident in the BBC Micro Master series. 11 | The language syntax is not always identical to that of the 6502 version, 12 | but in most cases the Z80 version is more tolerant. 13 | 14 | BBC BASIC (Z80) is as machine independent as possible and, as supplied, 15 | it will run on any CP/M 2.2 (or later) system using a Z80 processor 16 | (checks are carried out to ensure that the processor is a Z80 and that 17 | the version of CP/M is at least 2.2). It is minimally configured for an 18 | ADM3a-compatible VDU. 19 | 20 | Few CP/M systems offer colour graphics of the quality provided as 21 | standard on the BBC Microcomputer, and no software can provide colour 22 | high-resolution graphics from a monochrome character-orientated computer. 23 | However, many CP/M system users are interested in the advanced program 24 | structures available from BBC BASIC and, within the limitations of the 25 | host computer, BBC BASIC (Z80) provides the programming structures and 26 | the non-graphic commands and functions specified for BBC BASIC. 27 | 28 | In order to make full use of the facilities available in BBC BASIC (Z80) 29 | it is necessary to install a small patch to adapt it to the capabilities 30 | of the host computer. The source code of the patch present in the 31 | distribution version is supplied as BBCDIST.MAC. 32 | 33 | This documentation should be read in conjunction with a standard BBC 34 | BASIC manual. Only those features which differ from the standard Acorn 35 | versions are documented here. 36 | 37 | 38 | 2. MEMORY UTILISATION 39 | 40 | BBC BASIC (Z80) requires about 16 Kbytes of code space, resulting in a 41 | value of PAGE of about &3E00. The remainder of the user memory is 42 | available for BASIC programs, variables (heap) and stack. Depending on 43 | the system configuration, HIMEM can have a value up to &FE00. 44 | 45 | 46 | 3. COMMANDS, STATEMENTS AND FUNCTIONS 47 | 48 | The syntax of BASIC commands, statements and functions is in most cases 49 | identical to that of the BBC Micro version (BASIC 4). The few 50 | differences are documented here: 51 | 52 | ADVAL 53 | This function is not implemented. 54 | 55 | CALL 56 | CALL sets up a table in RAM containing details of the parameters; the 57 | processor's IX register is set to the address of this parameter table. 58 | The other processor registers are initialised as follows: 59 | 60 | A is initialised to the least significant byte of A% 61 | B is initialised to the least significant byte of B% 62 | C is initialised to the least significant byte of C% 63 | D is initialised to the least significant byte of D% 64 | E is initialised to the least significant byte of E% 65 | F is initialised to the least significant byte of F% 66 | H is initialised to the least significant byte of H% 67 | L is initialised to the least significant byte of L% 68 | 69 | The parameter types are: 70 | 71 | Code No. Parameter Type Example 72 | 0 Byte (8 bits) ?A% 73 | 4 Word (32 bits) !A% or A% 74 | 5 Real (40 bits) A 75 | 128 Fixed string $A% 76 | 129 Movable string A$ 77 | 78 | On entry to the subroutine the parameter table contains the following 79 | values: 80 | 81 | Number of parameters 1 byte (at IX) 82 | 83 | Parameter type 1 byte (at IX+1) 84 | Parameter address 2 bytes (at IX+2, IX+3, LSB first) 85 | 86 | Parameter type ) repeated as often as necessary 87 | Parameter address ) 88 | 89 | Except in the case of a movable string (normal string variable), the 90 | parameter address given is the absolute address at which the item is 91 | stored. In the case of movable strings (type 129) it is the address of a 92 | 4-byte parameter block containing the current length, the maximum length 93 | and the start address of the string (LSB first) in that order. 94 | 95 | Integer variables are stored in twos complement form with their least 96 | significant byte first. 97 | 98 | Fixed strings are stored as the characters of the string followed by a 99 | carriage return (&0D). 100 | 101 | Floating point variables are stored in binary floating point format with 102 | their least significant byte first; the fifth byte is the exponent. The 103 | mantissa is stored as a binary fraction in sign and magnitude format. 104 | Bit 7 of the most significant byte is the sign bit and, for the purposes 105 | of calculating the magnitude of the number, this bit is assumed to be set 106 | to one. The exponent is stored as an integer in excess 127 format (to 107 | find the exponent subtract 127 from the value in the fifth byte). 108 | 109 | If the exponent byte of a floating point number is zero, the number is an 110 | integer stored in integer format in the mantissa bytes. Thus an integer 111 | can be represented in two different ways in a real variable. For example 112 | the value +5 can be stored as: 113 | 114 | 05 00 00 00 00 Integer 5 115 | 00 00 00 20 82 (0.5 + 0.125) * 2^3 116 | 117 | COLOUR (COLOR) 118 | This statement is not implemented. 119 | 120 | DRAW 121 | This statement is not implemented. 122 | 123 | EDIT 124 | A command to edit or concatenate and edit the specified program line(s). 125 | The specified lines (including their line numbers) are listed as a single 126 | line. By changing only the line number you can use EDIT to duplicate a 127 | line. 128 | 129 | EDIT 230 130 | EDIT 200,230 131 | 132 | The following control functions are active both in the EDIT mode and in 133 | the immediate entry mode (i.e. at the BASIC prompt): 134 | 135 | Move the cursor one character position to the left 136 | Move the cursor one character position to the right 137 | Move the cursor to the start of the line 138 | Move the cursor to the end of the line 139 | Insert a space at the current cursor position 140 | Delete the character at the current cursor position 141 | Backspace and delete the character to the left of the cursor 142 | Delete all characters to the left of the cursor 143 | Delete all characters from the cursor to the end of the line 144 | 145 | The choice of which keys activate these functions is made when BBC BASIC 146 | is configured for a particular system. The distribution version uses ^H, 147 | ^I, ^K, ^J, ^A, ^E, DEL (&7F), ^L and ^X. 148 | 149 | To exit EDIT mode and replace the edited line, type RETURN (ENTER). 150 | 151 | To abort the edit and leave the line unchanged, type ESCape. 152 | 153 | ENVELOPE 154 | This statement is not implemented. 155 | 156 | GET 157 | This function waits for a character to be typed at the keyboard, and 158 | returns the ASCII code. 159 | 160 | GET can also be used to read data from a processor I/O port; full 16-bit 161 | port addressing is available: 162 | 163 | N% = GET(X%) : REM input from port X% 164 | 165 | INKEY 166 | This function waits for a specified maximum number of centiseconds for a 167 | character to be typed at the keyboard. If no character is typed in that 168 | time, the value -1 is returned. In the distribution version the delay is 169 | determined by a simple software timing loop, and may be very inaccurate. 170 | The customisation patch allows this to be adjusted to suit the system in 171 | use. 172 | 173 | INPUT# 174 | The format of data files is different from that used by the BBC Micro, in 175 | part to improve compatibility with standard CP/M files. Numeric values 176 | are stored as five bytes in the format documented under CALL; if the 177 | fifth byte is zero the value is an integer. Strings are stored as the 178 | characters of the string (in the correct order!) followed by a carriage 179 | return (&0D). 180 | 181 | MODE 182 | This statement is not implemented. 183 | 184 | MOVE 185 | This statement is not implemented. 186 | 187 | PLOT 188 | This statement is not implemented. 189 | 190 | POINT 191 | This function is not implemented. 192 | 193 | PRINT# 194 | The format of data files is different from that used by the BBC Micro, in 195 | part to improve compatibility with standard CP/M files. Numeric values 196 | are stored as five bytes in the format documented under CALL; if the 197 | fifth byte is zero the value is an integer. Strings are stored as the 198 | characters of the string (in the correct order!) followed by a carriage 199 | return (&0D). 200 | 201 | PUT 202 | A statement to output data to a processor port. Full 16-bit addressing 203 | is available. 204 | 205 | PUT A%,N% : REM Output N% to port A% 206 | 207 | SOUND 208 | This statement is not implemented. 209 | 210 | TIME 211 | This pseudo-variable is not implemented in the distribution version, but 212 | can be supported by means of the customisation patch. See BBCDIST.MAC. 213 | 214 | USR 215 | As with CALL, the processor's registers are initialised as follows: 216 | 217 | A is initialised to the least significant byte of A% 218 | B is initialised to the least significant byte of B% 219 | C is initialised to the least significant byte of C% 220 | D is initialised to the least significant byte of D% 221 | E is initialised to the least significant byte of E% 222 | F is initialised to the least significant byte of F% 223 | H is initialised to the least significant byte of H% 224 | L is initialised to the least significant byte of L% 225 | 226 | USR returns a 32-bit integer result composed of the processor's H, L, H' 227 | and L' registers, with H being the most significant. 228 | 229 | 230 | 4. RESIDENT Z80 ASSEMBLER 231 | 232 | The in-line assembler is accessed in exactly the same way as the 6502 233 | assembler in the BBC Micro version of BBC BASIC. That is, '[' enters 234 | assembler mode and ']' exits assembler mode. 235 | 236 | All standard Zilog mnemonics are accepted: ADD, ADC and SBC must be 237 | followed by A or HL. For example, ADD A,C is accepted but ADD C is not. 238 | However, the brackets around the port number in IN and OUT are optional. 239 | Thus both OUT (5),A and OUT 5,A are accepted. The instruction IN F,(C) 240 | is not accepted, but the equivalent code is produced from IN (HL),C 241 | 242 | The pseudo-ops DEFB, DEFW and DEFM are included. DEFM works like EQUS in 243 | the 6502 version. 244 | 245 | 246 | 5. OPERATING SYSTEM INTERFACE 247 | 248 | The following resident Operating System ("star") commands are 249 | implemented. They may be accessed directly (e.g. *BYE) or via the OSCLI 250 | statement (OSCLI "BYE"). 251 | 252 | Control characters, lower-case characters, DEL and quotation marks may be 253 | incorporated in filenames by using the 'escape' character '|'. However, 254 | there is no equivalent to the BBC Microcomputer's '|!' to set bit 7. 255 | 256 | *BYE 257 | Returns control to the operating system (CP/M). 258 | 259 | *CPM 260 | Same as *BYE. 261 | 262 | *. [filespec] 263 | *DIR [filespec] 264 | List the files which match the (optional) ambiguous filespec. If the 265 | filespec is omitted, all .BBC files are listed: 266 | *DIR List all .BBC files on the disk 267 | *DIR B:*.* List all files on disk B: 268 | *.*.* List all files on the current disk 269 | 270 | *DRIVE d: 271 | Select drive d as the default drive for subsequent disk operations. 272 | 273 | *ERA filespec 274 | Erase (delete) the specified disk file or files. The extension defaults 275 | to .BBC if omitted. 276 | 277 | *ESC [ON|OFF] 278 | *ESC OFF disables the abort action of the ESCape key; after *ESC OFF the 279 | ESCape key simply returns the ASCII code ESC (27). *ESC ON, or *ESC, 280 | restores the normal action of the ESCape key. 281 | 282 | *EXEC filespec 283 | Accept console input from the specified file instead of from the 284 | keyboard. If the extension is omitted, .BBC is assumed. 285 | 286 | *LOAD filespec aaaa 287 | Loads the specified file into memory at address aaaa. The load address 288 | must be specified. If the extension is omitted, .BBC is assumed. 289 | 290 | *OPT [n] 291 | Select the destination for console output characters. The value n is in 292 | the range 0 to 2, as follows: 293 | 294 | 0 Send characters to the console output 295 | 1 Send characters to the auxiliary output 296 | 2 Send characters to the printer (list) output 297 | 298 | *REN newfile=oldfile 299 | *RENAME newfile=oldfile 300 | Renames 'oldfile' as 'newfile'. If the extension is omitted, .BBC is 301 | assumed. 302 | 303 | *RESET 304 | Rest the disk system (CP/M function 13). This command does not close any 305 | files nor does it perform any other housekeeping function. You should 306 | use *RESET after you have changed a disk. 307 | 308 | *SAVE filespec aaaa bbbb 309 | *SAVE filespec aaaa +llll 310 | This command saves a specified range of memory to disk. The address range 311 | is specified either as start (aaaa) and end+1 (bbbb) or as start (aaaa) 312 | and length (llll). If the extension is omitted, .BBC is assumed. 313 | 314 | *SPOOL [filespec] 315 | Copy all subsequent console output to the specified file. If the filename 316 | is omitted, any current spool file is closed and spooling is terminated. 317 | If the extension is omitted, .BBC is assumed. 318 | 319 | *TYPE filespec 320 | Type the specified file to the screen. If the extension is omitted, .BBC 321 | is assumed. 322 | 323 | *| comment 324 | This is a comment line. Anything following the | is ignored. 325 | 326 | 327 | 6. ERROR MESSAGES AND CODES 328 | 329 | Untrappable: 330 | 331 | No room RENUMBER space 332 | Silly LINE space 333 | Sorry Bad program 334 | 335 | Trappable - BASIC: 336 | 337 | 1 Out of range 24 Exp range 338 | 2 25 339 | 3 26 No such variable 340 | 4 Mistake 27 Missing ) 341 | 5 Missing , 28 Bad HEX 342 | 6 Type mismatch 29 No such FN/PROC 343 | 7 No FN 30 Bad call 344 | 8 31 Arguments 345 | 9 Missing " 32 No FOR 346 | 10 Bad DIM 33 Can't match FOR 347 | 11 DIM space 34 FOR variable 348 | 12 Not LOCAL 35 349 | 13 No PROC 36 No TO 350 | 14 Array 37 351 | 15 Subscript 38 No GOSUB 352 | 16 Syntax error 39 ON syntax 353 | 17 Escape 40 ON range 354 | 18 Division by zero 41 No such line 355 | 19 String too long 42 Out of DATA 356 | 20 Too big 43 No REPEAT 357 | 21 -ve root 44 358 | 22 Log range 45 Missing # 359 | 23 Accuracy lost 360 | 361 | Trappable - OS: 362 | 363 | 190 Directory full 214 File not found 364 | 192 Too many open files 222 Channel 365 | 196 File exists 253 Bad string 366 | 198 Disk full 254 Bad command 367 | 200 Close error 255 CP/M error 368 | 204 Bad name 369 |  -------------------------------------------------------------------------------- /build.z80: -------------------------------------------------------------------------------- 1 | ; 2 | ; Title: BBC Basic for Spectrum Next - Main build file 3 | ; Author: Dean Belfield 4 | ; Created: 02/05/2021 5 | ; Last Updated: 15/07/2021 6 | ; 7 | ; Notes: 8 | ; 9 | ; This code is no longer compatible with ZEsarUX (version 9.2) 10 | ; 11 | ; To start in CSpect, I recommend using the following command line (Mac) 12 | ; > mono ECSpect.exe -w4 -basickeys -esc -zxnext -nextrom -tv -16bit -s28 -remote -mmc=cspect-next-2gb.img 13 | ; 14 | ; Modinfo: 15 | ; 10/05/2021: Moved Next specific RAM declarations into ram.z80 and tidied up a bit 16 | ; 13/05/2021: Added BUILD_VERSION define 17 | ; 16/05/2021: USER now aligned to page boundary - fixes bug in OLD 18 | ; 18/05/2021: Moved editor functions to editor.z80 19 | ; 21/05/2021: Addd a configuration section 20 | ; 24/05/2021: Moved Code_Start down to 0x5B00 (after ULA screen RAM) 21 | ; 28/05/2021: Added next_cursor.z80 22 | ; 04/06/2021: Added next_sound.z80 23 | ; 07/06/2021: Added next_sprites.z80 24 | ; 11/06/2021: Added equs.z80 25 | ; 15/07/2021: Added next_mouse.z80, CONF_OSID 26 | 27 | SLDOPT COMMENT WPMEM, LOGPOINT, ASSERTION 28 | 29 | DEVICE ZXSPECTRUMNEXT ; sjasmplus directive for SAVESNA at end 30 | 31 | DEFINE BUILD_VERSION "0.16" ; Build version 32 | ; 33 | ; Assembly flags 34 | ; 35 | BUILD_ROM EQU 0 ; Set to 1 to build a ROM image 36 | BUILD_EMULATOR EQU 0 ; Set to enable any emulator workarounds 37 | BUILD_Z80N EQU 1 ; Set to 1 to use Z80N optimized code in R.T.Russell's code 38 | BUILD_OPT EQU 1 ; Set to 1 to use misc.z80 optimisations in R.T.Russell's code 39 | ; 40 | ; Configuration 41 | ; 42 | CONF_OSID: EQU 27 ; Provisional OS ID for Spectrum Next 43 | CONF_KEYRPT_1: EQU 20 ; Default key delay (50ths of a second) 44 | CONF_KEYRPT_2: EQU 5 ; Default key repeat (50ths of a second) 45 | ; 46 | ; Memory map 47 | ; 48 | IM2_Table: EQU 0xFE00 ; 256 byte page (+ 1 byte) for IM2 49 | IM2_JP: EQU 0xFDFD ; 3 bytes for JP routine under IM2 table 50 | ROM_Charset EQU 0x3D00 ; Address of charset in ROM 51 | RAM_Top: EQU 0xFD00 ; Top of usable RAM; must be on a page boundary 52 | Stack_Top: EQU 0x0000 ; Stack at top 53 | Code_Start EQU 0x5B00 ; Code straight after screen RAM 54 | 55 | ORG Code_Start 56 | 57 | include "macros.z80" ; Useful macros 58 | include "equs.z80" ; Common EQUs 59 | ; 60 | ; Spectrum Next specific code 61 | ; 62 | include "next_init.z80" ; Spectrum Next initialisation 63 | include "next_dos.z80" ; File I/O 64 | include "next_debug.z80" ; Debug routines 65 | include "next_cursor.z80" ; Cursor routines 66 | include "next_io.z80" ; Screen and keyboard I/O 67 | include "next_graphics.z80" ; Bitmap graphics 68 | include "next_dma.z80" ; Spectrum Next DMA routines 69 | include "next_rtc.z80" ; Spectrum Next Real Time Clock routines 70 | include "next_mouse.z80" ; Spectrum Next Kempston Mouse routines 71 | include "next_sound.z80" ; Spectrum Next AY sound chip routines 72 | include "next_sprites.z80" ; Spectrum Next Sprite routines 73 | ; 74 | ; Other generic Z80N helper functions 75 | ; 76 | include "misc.z80" 77 | ; 78 | ; BBC BASIC for Z80 core code 79 | ; 80 | include "main.z80" 81 | include "exec.z80" 82 | include "eval.z80" 83 | include "fpp.z80" 84 | include "sorry.z80" 85 | include "patch.z80" 86 | include "editor.z80" 87 | include "ram.z80" 88 | 89 | ALIGN 256 ; USER needs to be alignd to a page boundary 90 | 91 | @USER:; incbin "tests/on_proc.bbc" ; BASIC program to load into memory 92 | 93 | SAVENEX OPEN "build.nex", Code_Start, Stack_Top 94 | SAVENEX CORE 3, 0, 0 95 | SAVENEX CFG 7, 0, 0 96 | SAVENEX BAR 1, 0xE0, 50, 25 97 | SAVENEX AUTO 98 | SAVENEX CLOSE -------------------------------------------------------------------------------- /editor.z80: -------------------------------------------------------------------------------- 1 | ; 2 | ; Title: BBC Basic for Spectrum Next - Editor 3 | ; Author: Dean Belfield 4 | ; Created: 18/05/2021 5 | ; Last Updated: 15/07/2021 6 | ; 7 | ; Modinfo: 8 | ; 19/05/2021: Added cursor up, cursor down, and copy 9 | ; 20/05/2021: Fixed cursor and copy mode bugs 10 | ; 22/05/2021: Bug fixes - non printable characters, escape handled better 11 | ; 26/05/2021: Added support code for Layer 2 modes 2 and 3 12 | ; 28/05/2021: Now uses hardware (sprite) cursor 13 | ; 31/05/2021: Fixed various editor bugs 14 | ; 08/06/2021: Now uses LTRAP to test for ESC; Renamed module 15 | ; 15/07/2021: Some KEY variables renamed 16 | 17 | MODULE EDITOR 18 | 19 | ; Read/edit a complete line, terminated by CR. 20 | ; HL: Addresses destination buffer. Must be on a page boundary 21 | ; Returns: 22 | ; Buffer filled, terminated by CR. 23 | ; A: 0 24 | ; Destroys: A,BC,DE,HL,IX,F 25 | ; 26 | Edit_Line: LD (HL), CR ; Initialise buffer 27 | LD A, (FLAGS) ; If ESC flag is set, then do nothing 28 | OR A 29 | LD A, 0 30 | RET M 31 | LD DE, (CHARPOS_X) ; Update the cursor position 32 | LD (CURSOR_X), DE 33 | 1: LD A, (KEY_CODE) ; Wait until we've let go of ESC 34 | CP 0x1B 35 | JR Z, 1B 36 | ; 37 | Edit_Line_Loop: LD A, 1 ; Cursor on 38 | CALL NEXT_CURSOR.Display 39 | CALL OSRDCH ; Wait for character input 40 | LD C, A ; Take a copy of the character 41 | XOR A 42 | CALL NEXT_CURSOR.Display ; Cursor off 43 | CALL LTRAP ; Check for escape 44 | ; 45 | LD A, (FLAGS) ; Get the flags in B 46 | LD B, A 47 | LD DE, (CURSOR_X) ; Cursor position 48 | ; 49 | LD A, C ; Check keyboard edit commands 50 | CP 0x7F ; 0x7F: DEL Delete 51 | JP Z, Key_DEL 52 | SUB 0x08 ; 0x08: BS Back one character 53 | JR Z, Key_BS 54 | DEC A ; 0x09: HT Advance one character 55 | JP Z, Key_HT 56 | DEC A ; 0x0A: LF Down one character 57 | JP Z, Key_LF 58 | DEC A ; 0x0B; VT Up one character 59 | JP Z, Key_VT 60 | SUB 0x02 ; 0x0D: CR Enter 61 | JR Z, Key_CR 62 | ; 63 | LD A, C ; Is it a printable character? 64 | CP 32 65 | JR C, Edit_Line_Loop ; No, so skip 66 | ; 67 | LD E, 0 ; Get length of current line 68 | CALL Get_Length 69 | LD A, B 70 | CP 255 71 | JR NC, Edit_Line_Loop ; Skip if line limit (255) exceeded 72 | ; 73 | CALL Insert ; Insert the character into the buffer 74 | LD (HL), C ; Store the character 75 | CALL Update_1 ; Update characters from cursor position 76 | DEC B 77 | CALL NZ, Update_2 78 | INC L ; Move the cursor 79 | LD DE, (CHARPOS_X) ; Update the cursor position 80 | LD (CURSOR_X), DE 81 | JR Edit_Line_Loop 82 | 83 | ; Enter pressed 84 | ; 85 | Key_CR: LD A, (HL) ; Move the cursor to the end of the line 86 | CP CR 87 | JR Z, 1F 88 | INC L 89 | LD A, 0x09: CALL OSWRCH 90 | JR Key_CR 91 | 1: LD A, (FLAGS) 92 | AND %11101111 ; Reset the copy bit 93 | LD (FLAGS), A 94 | CALL CRLF ; Display CRLF 95 | XOR A ; Return A = 0 96 | RET 97 | 98 | ; Cursor Left 99 | ; 100 | Key_BS: BIT 4, B ; Are we in COPY mode? 101 | JR Z, 1F 102 | CALL Move_Cursor_Left 103 | LD (CURSOR_X), DE 104 | JP Edit_Line_Loop 105 | 1: INC L 106 | DEC L ; Check for cursor at beginning of line 107 | JP Z, Edit_Line_Loop ; If we are, then do nothing 108 | DEC L ; Move the cursor back 109 | Key_Out: LD A, C 110 | CALL OSWRCH ; Echo character back to terminal 111 | LD DE, (CHARPOS_X) ; Update the cursor position 112 | LD (CURSOR_X), DE 113 | JP Edit_Line_Loop ; Loop 114 | 115 | ; Cursor Right 116 | ; 117 | Key_HT: BIT 4, B ; Are we in COPY mode? 118 | JR Z, 2F 119 | Key_HT_1: CALL Move_Cursor_Right 120 | LD (CURSOR_X), DE 121 | JP Edit_Line_Loop 122 | 2: LD A, (HL) 123 | CP CR ; Are we at the end of line? (marked with a CR) 124 | JP Z, Edit_Line_Loop ; Yes, so do nothing 125 | INC L ; Advance the cursor 126 | JR Key_Out ; Echo character back to terminal 127 | 128 | ; Cursor Down 129 | ; 130 | Key_LF: BIT 4, B ; Are we in COPY mode? 131 | JR Z, 1F 132 | CALL Move_Cursor_Down 133 | LD (CURSOR_X), DE 134 | JP Edit_Line_Loop 135 | 1: LD E, 0 136 | CALL Get_Length ; Get length of line in B from start of buffer (E=0) 137 | LD A, (CHAR_COLS) 138 | ADD A, L ; Down one line 139 | CP B ; Check with line length 140 | JR C, 2F 141 | JP NZ, Edit_Line_Loop 142 | 2: LD L, A 143 | JR Key_Out ; Echo character back to terminal 144 | 145 | ; Cursor Up 146 | ; 147 | Key_VT: BIT 4, B ; Are we in COPY mode? 148 | JR Z, 1F 149 | CALL Move_Cursor_Up ; Yes, so just move the cursor 150 | LD (CURSOR_X), DE 151 | JP Edit_Line_Loop 152 | 1: LD A, (CHAR_COLS) 153 | NEG 154 | ADD A, L ; Up one line 155 | JP NC, Edit_Line_Loop ; If it takes us past the beginning of the line then do nothing 156 | LD L, A ; Store 157 | JR Key_Out ; Echo character back to terminal 158 | 159 | ; Delete 160 | ; 161 | Key_DEL: BIT 4, B ; Are we in COPY mode? 162 | JR NZ, 2F ; Yes, so do copy 163 | INC L ; Check for input ptr at beginning of line 164 | DEC L 165 | JR Z, 1F 166 | CALL Delete 167 | DEC L 168 | LD A, 0x08: CALL OSWRCH 169 | CALL Update_1 170 | LD A, 0x20: CALL OSWRCH 171 | INC B 172 | CALL Update_2 173 | LD DE, (CHARPOS_X) ; Update the cursor position 174 | LD (CURSOR_X), DE 175 | 1: JP Edit_Line_Loop 176 | ; 177 | 2: PUSH DE 178 | LD E, 0 ; Check whether we can insert 179 | CALL Get_Length ; Get length of current line 180 | POP DE 181 | LD A, B 182 | CP 255 183 | JR NC, 1B ; Skip if line limit (255) exceeded 184 | ; 185 | PUSH DE 186 | PUSH HL 187 | EX DE, HL 188 | CALL NEXT_IO.Get_Charpos_1 189 | CALL NEXT_GRAPHICS.Get_Char 190 | POP HL 191 | POP DE 192 | JR NC, 1B 193 | PUSH DE 194 | CALL Insert ; Insert the character into the buffer 195 | LD (HL), C ; Store the character 196 | CALL Update_1 ; Update characters from cursor position 197 | DEC B 198 | CALL NZ, Update_2 199 | INC L 200 | POP DE 201 | JP Key_HT_1 202 | 203 | ; Get line length 204 | ; E: Start pointer value in buffer 205 | ; Returns 206 | ; B: Number of characters, excluding CR 207 | ; 208 | Get_Length_From_Cursor: LD E, L 209 | Get_Length: LD B, 0 210 | LD D, H 211 | 1: LD A, (DE) 212 | CP CR 213 | RET Z 214 | INC B 215 | INC E 216 | JR 1B 217 | 218 | ; Move cursor 219 | ; DE: Cursor position 220 | ; 221 | Move_Cursor_Left: EQU DEC_E_NZ ; In misc.z80 222 | Move_Cursor_Up: EQU DEC_D_NZ ; In misc.z80 223 | ; 224 | Move_Cursor_Right: LD A, (CHAR_COLS) 225 | DEC A 226 | INC E 227 | CP E 228 | RET NC 229 | LD E, 0 230 | ; 231 | Move_Cursor_Down LD A, (CHAR_ROWS) 232 | DEC A 233 | INC D 234 | CP D 235 | RET NC 236 | DEC D 237 | RET 238 | 239 | ; Update from cursor position 240 | ; L: Cursor position 241 | ; 242 | Update_1: LD D, H ; DE: Current cursor position 243 | LD E, L 244 | LD B, 0 ; B: Number of characters output 245 | 1: LD A, (DE) ; Read buffer 246 | CP CR ; Skip if CR 247 | RET Z 248 | CALL OSWRCH ; Print the character out 249 | INC E 250 | INC B ; Increment # of chars output 251 | JR 1B ; And loop 252 | 253 | ; Backspace a number of characters 254 | ; B: Character count 255 | ; 256 | Update_2: INC B ; Is B=0 (EOL) 257 | DEC B 258 | RET Z 259 | LD A, 0x08 ; Restore cursor position 260 | 3: CALL OSWRCH 261 | DJNZ 3B 262 | RET 263 | 264 | ; Insert character 265 | ; C: Character to insert 266 | ; L: Cursor position 267 | ; 268 | Insert: CALL Get_Length_From_Cursor 269 | INC B ; Need to loop at least once 270 | 1: LD A, (DE) 271 | INC E 272 | LD (DE), A 273 | DEC E 274 | DEC E 275 | DJNZ 1B 276 | RET 277 | 278 | ; Delete character 279 | ; L: Cursor position 280 | Delete: CALL Get_Length_From_Cursor 281 | INC B 282 | LD E, L 283 | 1: LD A, (DE) 284 | DEC E 285 | LD (DE), A 286 | INC E 287 | INC E 288 | DJNZ 1B 289 | RET 290 | 291 | ENDMODULE -------------------------------------------------------------------------------- /equs.z80: -------------------------------------------------------------------------------- 1 | ; 2 | ; Title: BBC Basic Interpreter - Z80 version 3 | ; Useful EQUs 4 | ; Author: Dean Belfield 5 | ; Created: 11/06/2021 6 | ; Last Updated: 13/06/2021 7 | ; 8 | ; Modinfo: 9 | ; 13/06/2021: Added PALETTE control registers 10 | 11 | ; 12 | ; NEXTREG 13 | ; 14 | MODULE NREG 15 | 16 | MACHINE_TYPE EQU 0x03 17 | CONFIG_MAPPING EQU 0x04 18 | PERIPHERAL_1 EQU 0x05 19 | PERIPHERAL_2 EQU 0x06 20 | CPU_SPEED EQU 0x07 21 | PERIPHERAL_3 EQU 0x08 22 | PERIPHERAL_4 EQU 0x09 23 | L2_ACTIVE_RAM EQU 0x12 24 | L2_SHADOW_RAM EQU 0x13 25 | LAYER_CONTROL EQU 0x15 26 | L2_SCROLL_X EQU 0x16 27 | L2_SCROLL_Y EQU 0x17 28 | CLIP_WINDOW_L2 EQU 0x18 29 | CLIP_WINDOW_SPRITES EQU 0x19 30 | ULA_SCROLL_X EQU 0x26 31 | ULA_SCROLL_Y EQU 0x27 32 | PALETTE_INDEX EQU 0x40 33 | PALETTE_VALUE_1 EQU 0x41 34 | ULANEXT_BYTE_FORMAT EQU 0x42 35 | PALETTE_CONTROL EQU 0x43 36 | PALETTE_VALUE_2 EQU 0x44 37 | MMU_SLOT_1 EQU 0x50 38 | MMU_SLOT_2 EQU 0x51 39 | MMU_SLOT_3 EQU 0x52 40 | MMU_SLOT_4 EQU 0x53 41 | MMU_SLOT_5 EQU 0x54 42 | MMU_SLOT_6 EQU 0x55 43 | MMU_SLOT_7 EQU 0x56 44 | MMU_SLOT_8 EQU 0x57 45 | L2_CONTROL EQU 0x70 46 | MEMORY_MAP_MODE EQU 0x8F 47 | 48 | ENDMODULE 49 | -------------------------------------------------------------------------------- /examples/ANIMAL.DAT: -------------------------------------------------------------------------------- 1 | 68 \QDoes it fly\N2\Y3\ \QDoes it live in water\N9\Y8\ \QIs it an insect\Y5\N4\ \QIs it a mammal\Y7\N6\ \QDoes it have black stripes\Y37\N36\ \QIs it yellow\Y19\N18\ \Abat \QIs it a mammal\Y15\N14\ \QIs it an insect\Y11\N10\ \QIs it a mammal\N13\Y12\ \Aant \QDoes it have a long trunk\Y21\N20\ \QDoes it have a pouch\Y27\N26\ \QIs it a fish\N17\Y16\ \QIs it very big\N23\Y22\ \Agoldfish \QDoes it have a hard shell\Y29\N28\ \QDoes it have a red breast\Y25\N24\ \Acanary \QDoes it purr\Y33\N32\ \Aelephant \Awhale \QIs it furry\Y45\N44\ \QDoes it eat fish\Y31\N30\ \Arobin \QDoes it have eight legs\Y39\N38\ \Akangaroo \QDoes it have eight tentacles\N41\Y40\ \QIs its shell almost round\Y35\N34\ \QDoes it quack\Y49\N48\ \Aseagull \QDoes it eat ants\Y47\N46\ \Acat \Alobster \Acrab \QDoes it bite\Y67\N66\ \Awasp \QDoes it have a forked tongue\N43\Y42\ \Aspider \Aoctopus \QDoes it have a nasty smell\Y53\N52\ \Asnake \Aworm \Adolphin \QDoes it build dams\N57\Y56\ \QDoes it bark\N51\Y50\ \Aanteater \Asparrow \Aduck \Adog \QDoes it have a long neck\Y55\N54\ \Afrog \Atoad \QDoes it have antlers\Y59\N58\ \Agiraffe \Abeaver \Aotter \QDoes it like cheese\Y61\N60\ \Adeer \QDoes it like mud\Y63\N62\ \QCan it talk\Y65\N64\ \Arabbit \Ahippopotamus \Amouse \Aman \Abee \Agnat -------------------------------------------------------------------------------- /examples/animal.bbc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/breakintoprogram/next-bbc-basic/506b604533a0bd121df5adc34fd4301b5cbcbba7/examples/animal.bbc -------------------------------------------------------------------------------- /examples/f-index.bbc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/breakintoprogram/next-bbc-basic/506b604533a0bd121df5adc34fd4301b5cbcbba7/examples/f-index.bbc -------------------------------------------------------------------------------- /examples/f-rand0.bbc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/breakintoprogram/next-bbc-basic/506b604533a0bd121df5adc34fd4301b5cbcbba7/examples/f-rand0.bbc -------------------------------------------------------------------------------- /examples/f-rand1.bbc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/breakintoprogram/next-bbc-basic/506b604533a0bd121df5adc34fd4301b5cbcbba7/examples/f-rand1.bbc -------------------------------------------------------------------------------- /examples/f-rand2.bbc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/breakintoprogram/next-bbc-basic/506b604533a0bd121df5adc34fd4301b5cbcbba7/examples/f-rand2.bbc -------------------------------------------------------------------------------- /examples/f-rser1.bbc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/breakintoprogram/next-bbc-basic/506b604533a0bd121df5adc34fd4301b5cbcbba7/examples/f-rser1.bbc -------------------------------------------------------------------------------- /examples/f-rser2.bbc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/breakintoprogram/next-bbc-basic/506b604533a0bd121df5adc34fd4301b5cbcbba7/examples/f-rser2.bbc -------------------------------------------------------------------------------- /examples/f-rstd.bbc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/breakintoprogram/next-bbc-basic/506b604533a0bd121df5adc34fd4301b5cbcbba7/examples/f-rstd.bbc -------------------------------------------------------------------------------- /examples/f-weser1.bbc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/breakintoprogram/next-bbc-basic/506b604533a0bd121df5adc34fd4301b5cbcbba7/examples/f-weser1.bbc -------------------------------------------------------------------------------- /examples/f-weser2.bbc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/breakintoprogram/next-bbc-basic/506b604533a0bd121df5adc34fd4301b5cbcbba7/examples/f-weser2.bbc -------------------------------------------------------------------------------- /examples/f-wser1.bbc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/breakintoprogram/next-bbc-basic/506b604533a0bd121df5adc34fd4301b5cbcbba7/examples/f-wser1.bbc -------------------------------------------------------------------------------- /examples/f-wser2.bbc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/breakintoprogram/next-bbc-basic/506b604533a0bd121df5adc34fd4301b5cbcbba7/examples/f-wser2.bbc -------------------------------------------------------------------------------- /examples/f-wstd.bbc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/breakintoprogram/next-bbc-basic/506b604533a0bd121df5adc34fd4301b5cbcbba7/examples/f-wstd.bbc -------------------------------------------------------------------------------- /examples/merge.bbc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/breakintoprogram/next-bbc-basic/506b604533a0bd121df5adc34fd4301b5cbcbba7/examples/merge.bbc -------------------------------------------------------------------------------- /examples/sort.bbc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/breakintoprogram/next-bbc-basic/506b604533a0bd121df5adc34fd4301b5cbcbba7/examples/sort.bbc -------------------------------------------------------------------------------- /examples/sortreal.bbc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/breakintoprogram/next-bbc-basic/506b604533a0bd121df5adc34fd4301b5cbcbba7/examples/sortreal.bbc -------------------------------------------------------------------------------- /images/bbc_basic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/breakintoprogram/next-bbc-basic/506b604533a0bd121df5adc34fd4301b5cbcbba7/images/bbc_basic.png -------------------------------------------------------------------------------- /images/bbc_basic_readme_header.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/breakintoprogram/next-bbc-basic/506b604533a0bd121df5adc34fd4301b5cbcbba7/images/bbc_basic_readme_header.png -------------------------------------------------------------------------------- /images/bbc_basic_rtc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/breakintoprogram/next-bbc-basic/506b604533a0bd121df5adc34fd4301b5cbcbba7/images/bbc_basic_rtc.png -------------------------------------------------------------------------------- /macros.z80: -------------------------------------------------------------------------------- 1 | ; 2 | ; Title: BBC Basic Interpreter - Z80 version 3 | ; Useful macros 4 | ; Author: Dean Belfield 5 | ; Created: 08/05/2021 6 | ; Last Updated: 30/05/2021 7 | ; 8 | ; Modinfo: 9 | ; 13/05/2021: Added OPCODE macro for assembler (in exec.z80) 10 | ; 18/05/2021: Added CALL_IX and CALL_IY 11 | ; 25/05/2021: Added EXEREG and CALLREG to replace CALL_HL, CALL_IX aned CALL_IY 12 | ; 30/05/2021: Added CP16, NEG16 13 | 14 | MACRO Z80PORT port, value 15 | LD A, value 16 | Z80PRTA port 17 | ENDM 18 | 19 | MACRO Z80PRTA port 20 | IF port > 255 21 | LD BC, port 22 | OUT (C), A 23 | ELSE 24 | OUT (port), A 25 | ENDIF 26 | ENDM 27 | 28 | MACRO CALLREG rp 29 | PUSH .S1 30 | JP (rp) 31 | .S1 ; 32 | ENDM 33 | 34 | MACRO EXREG rp1, rp2 35 | PUSH rp1 36 | POP rp2 37 | ENDM 38 | 39 | MACRO CALLESX hook 40 | RST 0x08 41 | DB hook 42 | ENDM 43 | 44 | MACRO OPCODE byte, op 45 | DC op 46 | DB byte 47 | ENDM 48 | 49 | MACRO CP16 rp1, rp2 50 | OR A 51 | SBC rp1, rp2 52 | ADD rp1, rp2 53 | ENDM 54 | 55 | MACRO NEG16 rp 56 | XOR A 57 | SUB low rp 58 | LD low rp, A 59 | SBC A, A 60 | SUB high rp 61 | LD high rp, a 62 | ENDM 63 | -------------------------------------------------------------------------------- /misc.z80: -------------------------------------------------------------------------------- 1 | ; 2 | ; Title: BBC Basic for Spectrum Next - Miscellaneous helper functions 3 | ; Author: Dean Belfield 4 | ; Created: 10/05/2021 5 | ; Last Updated: 15/07/2021 6 | ; 7 | ; Modinfo: 8 | ; 15/05/2021: Changed ASC_TO_HEX to ASC_TO_NUMBER; now parses decimal or hex 9 | ; 16/05/2021: Added SWITCH_A 10 | ; 23/05/2021: Added HLDE_TO_FPP, PRINT_BCD, NULLTOCR and CRTONULL 11 | ; 24/05/2021: CRTONULL now preserves BC 12 | ; 15/07/2021: Added SKIPNOTSP, NULLTOSP and SPTONULL 13 | 14 | ; Read a number and convert to binary 15 | ; If prefixed with &, will read as hex, otherwise decimal 16 | ; Inputs: HL: Pointer in string buffer 17 | ; Outputs: HL: Updated text pointer 18 | ; DE: Value 19 | ; A: Terminator (spaces skipped) 20 | ; Destroys: A,D,E,H,L,F 21 | ; 22 | ASC_TO_NUMBER: PUSH BC ; Preserve BC 23 | LD DE, 0 ; Initialise DE 24 | CALL SKIPSP ; Skip whitespace 25 | LD A, (HL) ; Read first character 26 | CP "&" ; Is it prefixed with '&' (HEX number)? 27 | JR NZ, 3F ; Jump to decimal parser if not 28 | INC HL ; Otherwise fall through to ASC_TO_HEX 29 | ; 30 | 1: LD A, (HL) ; Fetch the character 31 | CALL UPPRC ; Convert to uppercase 32 | SUB '0' ; Normalise to 0 33 | JR C, 4F ; Return if < ASCII '0' 34 | CP 10 ; Check if >= 10 35 | JR C,2F ; No, so skip next bit 36 | SUB 7 ; Adjust ASCII A-F to nibble 37 | CP 16 ; Check for > F 38 | JR NC, 4F ; Return if out of range 39 | 2: LD B, 4 ; Shift DE left 4 times 40 | BSLA DE, B 41 | OR E ; OR the new digit in to the least significant nibble 42 | LD E, A 43 | INC HL ; Onto the next character 44 | JR 1B ; And loop 45 | ; 46 | 3: LD A, (HL) 47 | SUB '0' ; Normalise to 0 48 | JR C, 4F ; Return if < ASCII '0' 49 | CP 10 ; Check if >= 10 50 | JR NC, 4F ; Return if >= 10 51 | EX DE, HL ; Stick DE in HL 52 | LD B, H ; And copy HL into BC 53 | LD C, L 54 | ADD HL, HL ; x 2 55 | ADD HL, HL ; x 4 56 | ADD HL, BC ; x 5 57 | ADD HL, HL ; x 10 58 | EX DE, HL 59 | ADD DE, A ; Add A to DE 60 | INC HL 61 | JR 3B 62 | 4: POP BC ; Fall through to SKIPSP here 63 | 64 | ; Skip a space 65 | ; HL: Pointer in string buffer 66 | ; 67 | SKIPSP: LD A, (HL) 68 | CP ' ' 69 | RET NZ 70 | INC HL 71 | JR SKIPSP 72 | 73 | ; Skip a string 74 | ; HL: Pointer in string buffer 75 | ; 76 | SKIPNOTSP: LD A, (HL) 77 | CP ' ' 78 | RET Z 79 | INC HL 80 | JR SKIPNOTSP 81 | 82 | ; Convert a character to upper case 83 | ; A: Character to convert 84 | ; 85 | UPPRC: AND 7FH 86 | CP '`' 87 | RET C 88 | AND 5FH ; CONVERT TO UPPER CASE 89 | RET 90 | 91 | ; Convert the buffer to a null terminated string and back 92 | ; 93 | NULLTOSP: PUSH BC 94 | LD B, 0 95 | LD C, ' ' 96 | JR 0F 97 | SPTONULL: PUSH BC 98 | LD B, ' ' 99 | LD C, 0 100 | JR 0F 101 | NULLTOCR: PUSH BC 102 | LD B, 0 103 | LD C, CR 104 | JR 0F 105 | CRTONULL: PUSH BC 106 | LD B, CR 107 | LD C, 0 108 | 0: PUSH HL 109 | 1: LD A, (HL) 110 | CP B 111 | JR Z, 2F 112 | INC HL 113 | JR 1B 114 | 2: LD (HL), C 115 | POP HL 116 | POP BC 117 | RET 118 | 119 | ; Convert BCD to ASCII 120 | ; HL: Pointer in string buffer 121 | ; A: BCD number to convert 122 | ; 123 | BCD_TO_ASC: LD C, A ; Store A 124 | SWAPNIB ; Get high nibble 125 | CALL 1F 126 | LD A, C 127 | 1: AND 0x0F 128 | ADD A, '0' 129 | LD (HL), A 130 | INC HL 131 | RET 132 | 133 | ; Print BCD 134 | ; 135 | PRINT_BCD: ADD A, 0 136 | DAA 137 | PRINT_BCD_1: LD C, A 138 | SWAPNIB 139 | CALL 1F 140 | LD A, C 141 | 1: AND 0x0F 142 | ADD A, '0' 143 | JP OSWRCH 144 | 145 | ; Switch on A - lookup table immediately after call 146 | ; A: Index into lookup table 147 | ; 148 | SWITCH_A: EX (SP), HL ; Swap HL with the contents of the top of the stack 149 | ADD A, A ; Multiply A by two 150 | ADD HL, A ; Index into the lookup table; this should immediately 151 | LD A, (HL) ; follow the call. Fetch an address from the 152 | INC HL ; table. 153 | LD H, (HL) 154 | LD L, A 155 | EX (SP), HL ; Swap this new address back, restores HL 156 | RET ; Return program control to this new address 157 | 158 | ; Decrease if not 0 159 | ; 160 | DEC_D_NZ: INC D 161 | DEC D 162 | RET Z 163 | DEC D 164 | RET 165 | ; 166 | DEC_E_NZ: INC E 167 | DEC E 168 | RET Z 169 | DEC E 170 | RET 171 | 172 | ; Convert LHED to a FPP 173 | ; 174 | HLDE_TO_FPP: PUSH DE 175 | EXX 176 | POP DE 177 | EX DE, HL ; E, D are the least significant bytes 178 | EXX 179 | LD C, 0 ; Exponent 180 | RET -------------------------------------------------------------------------------- /next_cursor.z80: -------------------------------------------------------------------------------- 1 | ; 2 | ; Title: BBC Basic Interpreter - Z80 version 3 | ; Spectrum Next Cursor Routines 4 | ; Author: Dean Belfield 5 | ; Created: 28/05/2021 6 | ; Last Updated: 13/06/2021 7 | ; 8 | ; Modinfo: 9 | ; 07/06/2021: Move and Display no longer do anything if the cursor is disabled 10 | ; 13/06/2021: Cursor X now halved for Mode 3 11 | 12 | MODULE NEXT_CURSOR 13 | 14 | Sprite_Cursor: EQU 127 15 | 16 | ; Initialise the cursor pattern 17 | ; E: Cursor width 18 | ; 19 | Initialise: Z80PORT 0x303B, Sprite_Cursor ; Select the sprite # 20 | LD C, 8 21 | 1: LD B, E 22 | LD A, 255 23 | 2: Z80PRTA 0x5B 24 | DJNZ 2B 25 | LD A, 8 26 | SUB E 27 | LD B, A 28 | LD A, 0x33 ; Transparent colour 29 | 3: Z80PRTA 0x5B 30 | DJNZ 3B 31 | DEC C 32 | JR NZ, 1B 33 | LD B, 64 34 | 4: Z80PRTA 0x5B 35 | DJNZ 4B 36 | RET 37 | 38 | ; Calculate sprite offset 39 | ; A: Cursor X or Y position 40 | ; 41 | Offset_X: LD L, A 42 | LD H, 0 43 | LD A, (CHAR_COLS) 44 | CP 80 45 | JR Z, 2F 46 | JR 1F 47 | Offset_Y: LD L, A ; Multiply by 8 48 | LD H, 0 49 | 1: ADD HL, HL 50 | 2: ADD HL, HL 51 | ADD HL, HL 52 | LD A, (CHAR_ROWS) ; Check for 256 column modes 53 | CP 32 54 | RET Z ; Ret if no border 55 | ADD HL, 32 ; Offset past border area 56 | RET 57 | 58 | Move: LD A, (FLAGS) ; Don't do anything if the cursor is not visible 59 | BIT 3, A 60 | RET Z 61 | NEXTREG 0x34, Sprite_Cursor ; Set the sprite # 62 | LD A, (CHAR_COLS) ; Check for 80 column mode 63 | CP 80 64 | LD A, (CURSOR_X) ; Get cursor positions 65 | CALL Offset_X 66 | LD A, L 67 | LD B, H 68 | NEXTREG 0x35, A ; LSB of X 69 | LD A, (CURSOR_Y) 70 | CALL Offset_Y 71 | LD A, L 72 | NEXTREG 0x36, A ; LSB of Y 73 | LD A, B 74 | AND 1 75 | OR %11110000 76 | NEXTREG 0x37, A ; 7-4: Pallete, 3,2: Mirror, 1: Rotate, 0: MSB of X 77 | LD A, (FLAGS) 78 | SWAPNIB 79 | AND %10000000 80 | LD L, A 81 | LD A, (TIME) 82 | ADD A, A 83 | ADD A, A 84 | AND L 85 | OR %01111111 86 | NEXTREG 0x38, A ; 7: Visible, 6: Extended, 5-0: Pattern 87 | LD A, H ; MSB of Y 88 | AND 1 89 | OR %10000000 90 | NEXTREG 0x39, A ; 7: 4-bit 6: Pattern, 4-1: Scaling, 0: MSB of Y 91 | RET 92 | 93 | ; Set cursor visibility 94 | ; 0: Off 95 | ; 1: On 96 | ; 97 | Display: AND 1 98 | ADD A, A 99 | ADD A, A 100 | ADD A, A 101 | LD B, A 102 | LD A, (FLAGS) 103 | AND %11110111 104 | OR B 105 | LD (FLAGS), A 106 | BIT 3, A 107 | RET NZ 108 | NEXTREG 0x34, Sprite_Cursor 109 | NEXTREG 0x38, 0 110 | RET 111 | 112 | ENDMODULE -------------------------------------------------------------------------------- /next_debug.z80: -------------------------------------------------------------------------------- 1 | ; 2 | ; Title: BBC Basic Interpreter - Z80 version 3 | ; Spectrum Next Debug routines 4 | ; Author: Dean Belfield 5 | ; Created: 07/05/2021 6 | ; Last Updated: 13/06/2021 7 | ; 8 | ; Modinfo: 9 | ; 16/05/2021: Fixed bug exposed by new VDU routines 10 | ; 08/06/2021: ESC now tested using LTRAP in Memory_Dump 11 | ; 13/06/2021: Double-width output for 80 column mode 12 | 13 | MODULE NEXT_DEBUG 14 | 15 | ; Dump memory 16 | ; HL: Start address 17 | ; DE: Length 18 | ; 19 | Memory_Dump: LD A, H 20 | CALL Print_Hex8 21 | LD A, L 22 | CALL Print_Hex8 23 | LD A, ':' : CALL NEXT_IO.Print_Char 24 | LD A, ' ' : CALL NEXT_IO.Print_Char 25 | PUSH HL 26 | PUSH DE 27 | 28 | CALL Get_Columns 29 | 1: LD A, (HL) 30 | CALL Print_Hex8 31 | INC HL 32 | DEC DE 33 | DEC B 34 | JR Z, 3F 35 | LD A, D 36 | OR E 37 | JR NZ, 1B 38 | 39 | 2: LD A, ' ' : CALL NEXT_IO.Print_Char 40 | LD A, ' ' : CALL NEXT_IO.Print_Char 41 | DJNZ 2B 42 | 43 | 3: POP DE 44 | POP HL 45 | LD A, ' ' : CALL NEXT_IO.Print_Char 46 | 47 | CALL Get_Columns 48 | 4: LD A, (HL) 49 | CALL Print_ASCII 50 | INC HL 51 | DEC DE 52 | LD A, D 53 | OR E 54 | JR Z, 5F 55 | DJNZ 4B 56 | CALL 5F ; Print CR/LF 57 | CALL LTRAP ; Check for ESC 58 | JR Memory_Dump 59 | 5: LD A, 0x0D 60 | CALL NEXT_IO.Print_Char 61 | LD A, 0x0A 62 | JP NEXT_IO.Print_Char 63 | 64 | ; Get # columns to dump 65 | ; 66 | Get_Columns: LD B, 8 67 | LD A, (CHAR_COLS) 68 | CP 80 69 | RET NZ 70 | SLA B 71 | RET 72 | 73 | ; A: Ascii char to print 74 | ; 75 | Print_ASCII: CP 127 ; If > 127 76 | JR NC, 2F ; Skip to print '.' 77 | CP 32 ; If >= 32 78 | JR NC, 1F ; Skip to print character 79 | 2: LD A, '.' 80 | 1: JP NEXT_IO.Print_Char 81 | 82 | ; A: Hex digit to print 83 | ; 84 | Print_Hex8: PUSH AF ; Store the value 85 | SWAPNIB ; Move to bottom nibble 86 | CALL 1F ; Print the first nibble 87 | POP AF 88 | 1: AND 0x0F ; Get the bottom nibble 89 | ADD A,0x90 ; Convert to HEX 90 | DAA 91 | ADC A,0x40 92 | DAA 93 | JP NEXT_IO.Print_Char ; Print 94 | 95 | ENDMODULE -------------------------------------------------------------------------------- /next_dma.z80: -------------------------------------------------------------------------------- 1 | ; 2 | ; Title: ZX Spectrum Next DMA Routines 3 | ; Author: Jim Bagley (c) 4 | ; Link: https://www.specnext.com/the-zxndma/ 5 | ; Modified By: Dean Belfield 6 | ; Created: 22/08/2020 7 | ; Last Updated: 10/05/2021 8 | ; 9 | ; Requires: 10 | ; 11 | ; Modinfo: 12 | ; 13 | ; 22/08/2020: Minor formatting changes, renamed some labels 14 | ; 10/05/2021: Added MODULE assembler directives 15 | ; 16 | 17 | MODULE NEXT_DMA 18 | 19 | DMA_RESET EQU 0xc3 20 | DMA_RESET_PORT_A_TIMING EQU 0xc7 21 | DMA_RESET_PORT_B_TIMING EQU 0xcb 22 | DMA_LOAD EQU 0xcf ; %11001111 23 | DMA_CONTINUE EQU 0xd3 24 | DMA_DISABLE_INTERUPTS EQU 0xaf 25 | DMA_ENABLE_INTERUPTS EQU 0xab 26 | DMA_RESET_DISABLE_INTERUPTS EQU 0xa3 27 | DMA_ENABLE_AFTER_RETI EQU 0xb7 28 | DMA_READ_STATUS_BYTE EQU 0xbf 29 | DMA_REINIT_STATUS_BYTE EQU 0x8b 30 | DMA_START_READ_SEQUENCE EQU 0xa7 31 | DMA_FORCE_READY EQU 0xb3 32 | DMA_DISABLE EQU 0x83 33 | DMA_ENABLE EQU 0x87 34 | DMA_WRITE_REGISTER_COMMAND EQU 0xbb 35 | DMA_BURST EQU %11001101 36 | DMA_CONTINUOUS EQU %10101101 37 | ZXN_DMA_PORT EQU 0x6b 38 | 39 | ; Fill a block of memory using the DMA 40 | ; DE: Destination 41 | ; BC: Length 42 | ; A: Fill value 43 | ; 44 | FillDMA: DI 45 | LD (FillDMA_Value), A 46 | LD (FillDMA_Dest), DE 47 | LD (FillDMA_Length), BC 48 | LD HL, FillDMA_Code 49 | LD B, FillDMA_Code_Len 50 | LD C, ZXN_DMA_PORT 51 | OTIR 52 | EI 53 | RET 54 | 55 | FillDMA_Value: DB 0 56 | 57 | FillDMA_Code: DB DMA_DISABLE 58 | DB %01111101 59 | FillDMA_Souce: DW FillDMA_Value 60 | FillDMA_Length: DW 0 61 | DB %00100100 62 | DB %00010000 63 | DB %10101101 64 | FillDMA_Dest: DW 0 65 | DB DMA_LOAD,DMA_ENABLE 66 | 67 | FillDMA_Code_Len: EQU $-FillDMA_Code 68 | 69 | ; Copy a block of memory using the DMA 70 | ; HL: Source 71 | ; DE: Destination 72 | ; BC: Length 73 | ; 74 | TransferDMA: DI 75 | LD (TransferDMA_Source), HL 76 | LD (TransferDMA_Dest), DE 77 | LD (TransferDMA_Length), BC 78 | LD HL, TransferDMA_Code 79 | LD B, TransferDMA_Code_Len 80 | LD C, ZXN_DMA_PORT 81 | OTIR 82 | EI 83 | RET 84 | 85 | TransferDMA_Code: DB DMA_DISABLE 86 | DB %01111101 ; R0-Transfer mode, A -> B, write address + block length 87 | TransferDMA_Source: DW 0 ; R0-Port A, Start address (source address) 88 | TransferDMA_Length: DW 0 ; R0-Block length (length in bytes) 89 | DB %01010100 ; R1-write A time byte, increment, to memory, bitmask 90 | DB %00000010 ; 2t 91 | DB %01010000 ; R2-write B time byte, increment, to memory, bitmask 92 | DB %00000010 ; R2-Cycle length port B 93 | DB DMA_CONTINUOUS ; R4-Continuous mode (use this for block transfer), write dest adress 94 | TransferDMA_Dest: DW 0 ; R4-Dest address (destination address) 95 | DB %10000010 ; R5-Restart on end of block, RDY active LOW 96 | DB DMA_LOAD ; R6-Load 97 | DB DMA_ENABLE ; R6-Enable DMA 98 | 99 | TransferDMA_Code_Len: EQU $-TransferDMA_Code 100 | 101 | ENDMODULE -------------------------------------------------------------------------------- /next_dos.z80: -------------------------------------------------------------------------------- 1 | ; 2 | ; Title: BBC Basic Interpreter - Z80 version 3 | ; Spectrum Next DOS routines 4 | ; Author: Dean Belfield 5 | ; Created: 06/05/2021 6 | ; Last Updated: 05/07/2021 7 | ; 8 | ; Notes: 9 | ; 10 | ; File Attributes 11 | ; 12 | ; 1 byte: file/attributes (MS/DOS format) 13 | ; ? bytes file/directory name (null terminated) 14 | ; 2 bytes: timestamp (MS/DOS format) 15 | ; 2 bytes: datestamp (MS/DOS format) 16 | ; 4 bytes: filesize 17 | ; 18 | ; Attribute Byte: 19 | ; 20 | ; Bit 1: If set, the file/folder is hidden 21 | ; Bit 4: It's a directory 22 | ; 23 | ; Timestamps 24 | ; 25 | ; ╔═══════╦══════╦═════════════════════════════╦══════════════════════════════════╗ 26 | ; ║ Bits ║ Size ║ Description ║ Comments ║ 27 | ; ╠═══════╬══════╬═════════════════════════════╬══════════════════════════════════╣ 28 | ; ║ 0-4 ║ 5 ║ Seconds (2-second interval) ║ 0..29 (29 represents 58 seconds) ║ 29 | ; ║ 5-10 ║ 6 ║ Minutes ║ 0..59 ║ 30 | ; ║ 11-15 ║ 5 ║ Hour ║ 0..23 ║ 31 | ; ╠═══════╬══════╬═════════════════════════════╬══════════════════════════════════╣ 32 | ; ║ 0-4 ║ 5 ║ Day ║ 1..31 ║ 33 | ; ║ 5-9 ║ 4 ║ Month ║ 1..12 ║ 34 | ; ║ 9-15 ║ 7 ║ Year (as offset from 1980) ║ 0 represents 1980 ║ 35 | ; ╚═══════╩══════╩═════════════════════════════╩══════════════════════════════════╝ 36 | ; 37 | ; Modinfo: 38 | ; 13/05/2021: Switched to using EXSDOS calls via RST 08 39 | ; 23/05/2021: Added CD and LS 40 | ; 24/05/2021: Added Load and Save 41 | ; 25/05/2021: Added Delete, MKDIR, RMDIR, DRIVE, Writes done at 28Mhz, error codes 42 | ; 05/07/2021: Added FOPEN, FCLOSE, FREADB, GETPOS, SEEK 43 | 44 | MODULE NEXT_DOS 45 | 46 | m_dosversion EQU 0x88 47 | m_getsetdrv EQU 0x89 48 | m_gethandle EQU 0x8D 49 | m_geterr EQU 0x93 50 | m_p3dos EQU 0x94 51 | 52 | f_open EQU 0x9A 53 | f_close EQU 0x9B 54 | f_read EQU 0x9D 55 | f_write EQU 0x9E 56 | f_seek EQU 0x9F 57 | f_getpos EQU 0xA0 58 | f_fstat EQU 0xA1 59 | f_getdir EQU 0xA8 60 | f_setdir EQU 0xA9 61 | f_opendir EQU 0xA3 62 | f_readdir EQU 0xA4 63 | f_telldir EQU 0xA5 64 | f_seekdir EQU 0xA6 65 | f_rewinddir EQU 0xA7 66 | f_getcwd EQU 0xA8 67 | f_chdir EQU 0xA9 68 | f_mkdir EQU 0xAA 69 | f_rmdir EQU 0xAB 70 | f_stat EQU 0xAC 71 | f_unlink EQU 0xAD 72 | 73 | fa_read EQU 0x01 74 | fa_append EQU 0x06 75 | fa_overwrite EQU 0x0E 76 | 77 | ; Delete a file 78 | ; A: Drive 79 | ; IX: Pointer to path 80 | ; 81 | Delete: NEXTREG 0x07, 3 ; Boost the CPU speed 82 | CALLESX f_unlink 83 | JP C, Error 84 | Restore_CPU: LD A, (CPU_SPEED) ; Restore CPU speed 85 | NEXTREG 0x07, A 86 | RET 87 | 88 | ; Make directory 89 | ; A: Drive 90 | ; IX: Pointer to path 91 | ; 92 | MKDIR: NEXTREG 0x07, 3 ; Boost the CPU speed 93 | CALLESX f_mkdir 94 | JP C, Error 95 | JR Restore_CPU 96 | 97 | ; Remove directory 98 | ; A: Drive 99 | ; IX: Pointer to path 100 | ; 101 | RMDIR: NEXTREG 0x07, 3 ; Boost the CPU speed 102 | CALLESX f_rmdir 103 | JP C, Error 104 | JR Restore_CPU 105 | 106 | ; Change current drive 107 | ; A: Drive letter 108 | ; 109 | DRIVE: CP "$" 110 | JR Z, 1F 111 | SUB 'A' 112 | RET C 113 | ADD A, A 114 | ADD A, A 115 | ADD A, A 116 | INC A 117 | 1: LD (FDRIVE), A 118 | CALLESX m_getsetdrv 119 | JP C, Error 120 | RET 121 | 122 | ; FOPEN 123 | ; IX: Pointer to path 124 | ; A: Drive 125 | ; B: Mode 126 | ; Returns: 127 | ; A: Filehandle, 0 if cannot open 128 | ; 129 | FOPEN: NEXTREG 0x07, 3 130 | CALLESX f_open 131 | JR NC, 1F 132 | XOR A 133 | 1: PUSH AF 134 | LD A, (CPU_SPEED) 135 | NEXTREG 0x07, A 136 | POP AF 137 | RET 138 | 139 | ; FCLOSE 140 | ; E: Filehandle 141 | ; 142 | FCLOSE: NEXTREG 0x07, 3 143 | LD A, E 144 | CALLESX f_close 145 | LD A, (CPU_SPEED) 146 | NEXTREG 0x07, A 147 | RET 148 | 149 | ; FREADB 150 | ; E: Filehandle 151 | ; Returns 152 | ; A: Byte to read 153 | ; 154 | FREADB: NEXTREG 0x07, 3 155 | LD IX, FDATA ; 1 byte buffer for data 156 | 1: LD BC, 1 157 | PUSH DE 158 | LD A, E 159 | CALLESX f_read 160 | POP DE 161 | JR C, 1B ; Loop until we've read a byte 162 | LD A, (CPU_SPEED) 163 | NEXTREG 0x07, A 164 | LD A, (IX) 165 | RET 166 | 167 | ; FWRITEB 168 | ; E: Filehandle 169 | ; A: Byte to write 170 | ; 171 | FWRITEB: NEXTREG 0x07, 3 172 | LD IX, FDATA 173 | LD (IX), A 174 | LD BC, 1 175 | LD A, E 176 | CALLESX f_write 177 | LD A, (CPU_SPEED) 178 | NEXTREG 0x07, A 179 | RET 180 | 181 | ; EOF 182 | ; E: Filehandle 183 | ; Returns 184 | ; F: Z if EOF, otherwise NZ 185 | ; 186 | EOF: CALL FREADB ; Try to read a byte 187 | LD A, B ; If # bytes read is zero 188 | OR C 189 | RET Z ; Then it is probably end of file 190 | PUSH AF ; Stack the flags 191 | NEXTREG 0x07, 3 192 | LD A, E ; File handle 193 | LD BC, 0 ; Seek backwards 1 space 194 | LD DE, 1 195 | LD IXL, 2 196 | CALLESX f_seek 197 | LD A, (CPU_SPEED) 198 | NEXTREG 0x07, A 199 | POP AF ; Restore the flags 200 | RET 201 | 202 | ; GETPOS 203 | ; A: Filehandle 204 | ; Returns 205 | ; BCDE: Current position 206 | ; F: C if there is an error 207 | ; 208 | GETPOS: CALLESX f_getpos 209 | RET 210 | 211 | ; SEEK 212 | ; A: Filehandle 213 | ; BCDE: Current position 214 | ; IXL: Seek mode 215 | ; F: C if there is an error 216 | ; 217 | SEEK: CALLESX f_seek 218 | RET 219 | 220 | ; FSTAT 221 | ; A: Filehandle 222 | ; Returns 223 | ; IX+0: '*' 224 | ; IX+1; 0x81 225 | ; IX+2: File attributes (MS-DOS format) 226 | ; IX+3: Timestamp (2 bytes MS-DOS format) 227 | ; IX+5: Datestamp (2 bytes MS-DOS format) 228 | ; IX+7: Filesize in bytes (4 bytes) 229 | ; 230 | FSTAT: LD IX, FDATA 231 | CALLESX f_fstat 232 | RET 233 | 234 | ; ---------------------------------------------------------------------------- 235 | 236 | ; Load a file 237 | ; A: Drive 238 | ; IX: Pointer to path 239 | ; DE: Load address 240 | ; BC: Maximum number of bytes to load 241 | ; 242 | Load: NEXTREG 0x07, 3 ; Boost the CPU speed 243 | PUSH BC 244 | PUSH DE 245 | LD B, 0x01 ; Open for read 246 | CALLESX f_open 247 | JP NC, 1F 248 | POP DE ; Pop the stack 249 | POP BC ; and 250 | JP Error ; flag the error 251 | ; 252 | 1: LD (FH), A ; Store the file handle 253 | POP IX ; Get the address 254 | POP BC ; And the length 255 | CALLESX f_read ; Read the data in 256 | JP C, Error_Close ; Flag error if carry set 257 | SCF ; Set carry for BASIC (no error) 258 | ; 259 | Close: PUSH AF ; Preserve the carry flag 260 | LD A, (FH) 261 | CALLESX f_close ; Close the file 262 | LD A, (CPU_SPEED) ; Restore the CPU speed 263 | NEXTREG 0x07, A 264 | POP AF 265 | RET 266 | 267 | ; Save a file 268 | ; A: Drive 269 | ; IX: Pointer to path 270 | ; DE: Start address 271 | ; BC: Length of data to save 272 | ; 273 | Save: NEXTREG 0x07, 3 ; Boost the CPU speed 274 | PUSH BC 275 | PUSH DE 276 | LD B, 0x06 ; Open for write, error if exists 277 | CALLESX f_open 278 | JP NC, 1F 279 | POP DE ; Pop the stakc 280 | POP BC ; and 281 | JP Error ; flag the error 282 | ; 283 | 1: LD (FH), A ; Store the file handle 284 | POP IX ; Get the address 285 | POP BC ; And the length 286 | CALLESX f_write ; Write the data 287 | JP C, Error_Close ; Flag error if carry set 288 | JR Close ; Okay at this point, just close 289 | 290 | ; Change directory 291 | ; A: Drive 292 | ; IX: Pointer to path 293 | ; 294 | CD: CALLESX f_chdir 295 | JP C, Error 296 | RET 297 | 298 | ; Read a directory 299 | ; A: Drive 300 | ; 301 | LS: LD IX, DOS_BUFFER 302 | CALLESX f_getcwd 303 | JP C, Error 304 | 305 | LD B, 0x00 ; Access mode 306 | CALLESX f_opendir ; Open the directory 307 | JP C, Error ; Check for error 308 | LD (FH), A ; Store the handle 309 | ; 310 | 1: LD IX, DOS_BUFFER 311 | LD A, (FH) ; Read the next directory entry 312 | CALLESX f_readdir 313 | JP C, Error_Close ; Check for error 314 | OR A 315 | JR NZ, 2F ; If we have a file to read, then do it 316 | ; 317 | LD A, (FH) ; Otherwise, close the file handle 318 | CALLESX f_close ; and exit 319 | JP C, Error 320 | RET 321 | ; 322 | 2: BIT 1, (IX + 0) ; Check if hidden 323 | JR NZ, 1B 324 | ; 325 | LD A, 19: LD (CHARPOS_X), A 326 | PUSH IX 327 | POP HL 328 | INC L 329 | CALL MAIN.TEXT ; Print the filename 330 | PUSH HL 331 | POP IY ; IY now points to the timestamp 332 | XOR A 333 | LD (CHARPOS_X), A 334 | LD H, A 335 | LD A, (IY + 3) ; Get the year byte 336 | RRA 337 | LD L, A 338 | ADD HL, 1980 ; Year offset 339 | CALL MAIN.PBCD 340 | LD A, "-" 341 | CALL OSWRCH 342 | ; 343 | LD A, (IY + 3) ; Get the month 344 | RRA 345 | LD A, (IY + 2) 346 | RRA 347 | SWAPNIB 348 | AND 15 349 | CALL PRINT_BCD 350 | LD A, "-" 351 | CALL OSWRCH 352 | ; 353 | LD A, (IY + 2) ; And the day 354 | AND 31 355 | CALL PRINT_BCD 356 | ; 357 | BIT 4, (IX + 0) ; Is it a folder? 358 | JR NZ, 3F ; Yes, so skip next bit 359 | ; 360 | LD E, (IY + 4) ; Byte 0 of the file length 361 | LD D, (IY + 5) ; Byte 1 362 | LD L, (IY + 6) ; Byte 2 363 | LD H, (IY + 7) ; Byte 3 364 | CALL HLDE_TO_FPP ; Convert to HLH'L' and C 365 | LD DE, ACCS ; Buffer to output the ASCII number to 366 | LD IX, STAVAR ; Used for the @% format variable 367 | CALL FPP.STR ; Output to DE 368 | EX DE, HL 369 | LD (HL), 0 ; Null terminate the string 370 | LD A, 7 ; Right-align it 371 | SUB L 372 | JR C, 3F 373 | ADD A, 11 374 | LD (CHARPOS_X), A 375 | LD L, 0 376 | CALL MAIN.TEXT ; And print it 377 | ; 378 | 3: CALL CRLF 379 | JP 1B 380 | 381 | ; 382 | ; Error handlers 383 | ; 384 | Error_Close: CALL Close 385 | Error: LD E, A ; Store the error 386 | LD A, (CPU_SPEED) ; Restore the CPU speed 387 | NEXTREG 0x07, A 388 | LD HL, Error_Codes ; Find the error 389 | 0: LD A, E 390 | 1: CP (HL) 391 | JR Z, 3F ; Found it! 392 | BIT 7, (HL) ; Is it the last entry? 393 | JR NZ, 3F 394 | 2: INC HL 395 | LD A, (HL) 396 | OR A 397 | JR NZ, 2B 398 | INC HL 399 | JR 0B 400 | 3: INC HL 401 | PUSH HL 402 | XOR A 403 | JP EXTERR 404 | 405 | ; Errors 406 | ; 407 | Error_Codes: DEFB 5, "No such file or directory", 0 408 | DEFB 11, "No such drive", 0 409 | DEFB 16, "Is a directory", 0 410 | DEFB 17, "Not a directory", 0 411 | DEFB 18, "Already exists", 0 412 | DEFB 255, "Error", 0 413 | 414 | ENDMODULE -------------------------------------------------------------------------------- /next_graphics_L2.z80: -------------------------------------------------------------------------------- 1 | ; 2 | ; Title: BBC Basic Interpreter - Z80 version 3 | ; Spectrum Next Layer 2 Graphics Routines 4 | ; Author: Dean Belfield 5 | ; Created: 13/05/2021 6 | ; Last Updated: 12/07/2021 7 | ; 8 | ; Modinfo: 9 | ; 14/05/2021: Added plot modes 10 | ; 15/05/2021: Plot now pulls PLOT_MODE and PLOT_COLOUR direct from RAM; Updates for MODE command 11 | ; 17/05/2021: Tweaks for COLOUR, GCOL 12 | ; 20/05/2021: Added Draw_Horz_Line 13 | ; 22/05/2021: Added Point 14 | ; 24/05/2021: Clear_Line now uses the background colour 15 | ; 26/05/2021: Added support code for Layer 2 modes 2 and 3 16 | ; 04/06/2021: Point and Triangle now work correctly with scroll offset 17 | ; 07/06/2021: Plot modes 1-5 and Point now work correctly; Fixed sprite clipping window & default palette 18 | ; 13/06/2021: Now uses NREG definitions in equs.z80; Added Mode 3 graphics and text code 19 | ; 14/06/2021: Mode 3 screen now cleared correctly; Fixed bug in Clear_Screen; Fixed bug in Draw_Horz_Line_M3 20 | ; 21/06/2021: Added support for Get_Char and CLG 21 | ; 12/07/2021: Added support for UDGs 22 | 23 | 24 | MODULE NEXT_GRAPHICS_L2 25 | 26 | ; Set the video modes up 27 | ; 28 | Set_Video_Mode_M1: LD A, %00000000 ; 256 x 192 x 8 29 | LD E, %00100011 ; Sprites & clipping, SLU priority 30 | LD C, 32 31 | LD B, 24 32 | LD D, 191 + 32 33 | JR Set_Video_Mode 34 | ; 35 | Set_Video_Mode_M2: LD A, %00010000 ; 320 x 256 x 8 36 | LD E, %00100011 ; Sprites & clipping, SLU priority 37 | LD C, 40 38 | LD B, 32 39 | LD D, 255 40 | JR Set_Video_Mode 41 | ; 42 | Set_Video_Mode_M3: LD A, %00100000 ; 640 x 256 x 4 43 | LD E, %00100011 ; Sprites, no clipping, SLU priority 44 | LD C, 80 45 | LD B, 32 46 | LD D, 255 47 | ; 48 | Set_Video_Mode: PUSH AF, BC, DE 49 | XOR A 50 | LD (TEXT_BACKGROUND), A 51 | DEC A 52 | LD (TEXT_FOREGROUND), A 53 | LD (PLOT_COLOUR), A 54 | LD (CHAR_COLS), BC 55 | LD H, 0 56 | LD L, C 57 | ADD HL, HL 58 | ADD HL, HL 59 | ADD HL, HL 60 | LD (PIXEL_WIDTH), HL 61 | LD H, 0 62 | LD L, B 63 | ADD HL, HL 64 | ADD HL, HL 65 | ADD HL, HL 66 | LD (PIXEL_HEIGHT), HL 67 | CALL NEXT_GRAPHICS.CLS 68 | POP DE, BC, AF 69 | NEXTREG NREG.L2_CONTROL, A 70 | LD A, E 71 | NEXTREG NREG.LAYER_CONTROL, A 72 | LD A, D 73 | NEXTREG NREG.CLIP_WINDOW_L2, 0 ; Clip Window 74 | NEXTREG NREG.CLIP_WINDOW_L2, 255 75 | NEXTREG NREG.CLIP_WINDOW_L2, 0 76 | NEXTREG NREG.CLIP_WINDOW_L2, A 77 | NEXTREG NREG.CLIP_WINDOW_SPRITES, 0 ; Clip Window Sprites 78 | NEXTREG NREG.CLIP_WINDOW_SPRITES, 255 79 | NEXTREG NREG.CLIP_WINDOW_SPRITES, 0 80 | NEXTREG NREG.CLIP_WINDOW_SPRITES, A 81 | NEXTREG NREG.PALETTE_CONTROL, %10010000 ; Change L2 first palette 82 | RET 83 | 84 | 85 | ; Clear the screen 86 | ; Used by CLS and CLG 87 | ; C: Colour to clear screen with 88 | ; 89 | Clear_Screen_M1: LD B, 3 90 | LD A, C 91 | JR Clear_Screen 92 | ; 93 | Clear_Screen_M2: LD A, C 94 | JR 1F 95 | 96 | Clear_Screen_M3: LD A, C 97 | AND 0x0F 98 | LD B, A 99 | SWAPNIB 100 | OR B 101 | 1: LD B, 5 102 | ; 103 | Clear_Screen: LD (R00), A ; Store the colour 104 | LD A, (BORDER_COLOUR) ; Set the border colour 105 | OUT (254), A 106 | NEXTREG NREG.L2_SCROLL_Y, 0 ; Scroll register 107 | PUSH BC ; Stack BC, Z80PORT corrupts it! 108 | Z80PORT 0x123B, %00000011 ; Enable for memory writes 109 | POP BC 110 | 1: PUSH BC 111 | LD A, B 112 | DEC A 113 | OR %00010000 ; Set to page relative to current page 114 | Z80PRTA 0x123B 115 | LD A, (R00) ; The fill byte value 116 | LD DE,0x0000 ; Screen RAM is paged into ROM area 117 | LD BC,0x4000 ; 16K in size 118 | CALL NEXT_DMA.FillDMA ; Clear it 119 | POP BC 120 | DJNZ 1B 121 | Z80PORT 0x123B, %00000010 ; Disable memory writes 122 | RET 123 | 124 | ; Scroll 125 | ; H: Line to clear after scroll 126 | ; 127 | Set_Scroll_Reg: LD A, (SCRLPOS_Y) 128 | ADD A, A 129 | ADD A, A 130 | ADD A, A 131 | NEXTREG NREG.L2_SCROLL_Y, A 132 | RET 133 | 134 | ; Adjust HL for scroll position 135 | ; HL: Y 136 | ; Returns: 137 | ; HL: Y adjusted for Y 138 | ; 139 | Adjust_SCRLPOS_P: LD A, (SCRLPOS_Y) ; Get Y scroll position 140 | ADD A, A 141 | ADD A, A 142 | ADD A, A ; Multiply by 8 143 | ADD A, L ; Add to pixel Y position 144 | LD L, A ; Wraps 145 | RET 146 | 147 | ; Print a single character out to an X/Y position 148 | ; E: Character to print 149 | ; L: X Coordinate 150 | ; H: Y Coordinate 151 | ; 152 | Print_Char_M3: CALL Get_Char_Address_M3 153 | CALL Get_Character_Data 154 | LD BC, (TEXT_FOREGROUND) ; C: Foreground, B: Background 155 | CALL Get_Colour_Nibbles 156 | LD IXH, 8 ; Outer loop counter 157 | LD B, high R00 ; Index into nibble table 158 | 1: LD A, (DE) ; First pair of pixels 159 | AND %11000000 160 | RLCA 161 | RLCA 162 | LD C, A 163 | LD A, (BC) 164 | LD (HL), A 165 | INC H 166 | LD A, (DE) ; Second pair of pixels 167 | AND %00110000 168 | SWAPNIB 169 | LD C, A 170 | LD A, (BC) 171 | LD (HL), A 172 | INC H 173 | LD A, (DE) ; Third pair of pixels 174 | AND %00001100 175 | RRCA 176 | RRCA 177 | LD C, A 178 | LD A, (BC) 179 | LD (HL), A 180 | INC H 181 | LD A, (DE) ; Final pair of pixels 182 | AND %00000011 183 | LD C, A 184 | LD A, (BC) 185 | LD (HL), A 186 | DEC H ; Decrement screen position 187 | DEC H 188 | DEC H 189 | INC DE 190 | INC L 191 | DEC IXH 192 | JR NZ, 1B 193 | Z80PORT 0x123B, %00000010 194 | RET 195 | ; 196 | Print_Char_M2: CALL Get_Char_Address_M2 197 | CALL Get_Character_Data 198 | LD BC, (TEXT_FOREGROUND) ; C: Foreground, B: Background 199 | LD IXH, 8 ; Outer Loop counter 200 | 1: PUSH HL 201 | LD A, (DE) ; Get the byte from the ROM into A 202 | LD IXL, 8 ; Inner loop counter 203 | 2: ADD A, A 204 | JR C, 3F 205 | LD (HL), B ; Set background colour 206 | JR 4F 207 | 3: LD (HL), C ; Set foreground colour 208 | 4: INC H 209 | DEC IXL 210 | JR NZ, 2B 211 | INC DE ; Goto next byte of character 212 | POP HL 213 | INC L ; Goto next line on screen 214 | DEC IXH 215 | JR NZ, 1B ; Loop around whilst it is Not Zero (NZ) 216 | Z80PORT 0x123B, %00000010 ; Disable memory writes 217 | RET 218 | ; 219 | Print_Char_M1: CALL Get_Char_Address_M1 220 | CALL Get_Character_Data 221 | LD BC, (TEXT_FOREGROUND) ; C: Foreground, B: Background 222 | LD IXH,8 ; Outer Loop counter 223 | 1: PUSH HL 224 | LD A,(DE) ; Get the byte from the ROM into A 225 | LD IXL, 8 ; Inner loop counter 226 | 2: ADD A, A 227 | JR C, 3F 228 | LD (HL),B ; Set background colour 229 | JR 4F 230 | 3: LD (HL),C ; Set foreground colour 231 | 4: INC L 232 | DEC IXL 233 | JR NZ, 2B 234 | INC DE ; Goto next byte of character 235 | POP HL 236 | INC H ; Goto next line on screen 237 | DEC IXH 238 | JR NZ,1B ; Loop around whilst it is Not Zero (NZ) 239 | Z80PORT 0x123B, %00000010 ; Disable memory writes 240 | RET 241 | 242 | ; Get all possible colour nibble pairs for Layer 2 (640x256) 243 | ; C: Foreground colour 244 | ; B: Background colour 245 | ; Returns: 246 | ; R0-R3: Colour nibble pairs 247 | ; 248 | Get_Colour_Nibbles: LD A, B 249 | AND 0x0F 250 | LD B, A 251 | SWAPNIB 252 | OR B 253 | LD (R00), A ; R0: BB 254 | LD A, C 255 | AND 0x0F 256 | LD C, A 257 | SWAPNIB 258 | OR C 259 | LD (R03), A ; R3: FF 260 | LD A, B 261 | SWAPNIB 262 | OR C 263 | LD (R01), A ; R1: BF 264 | SWAPNIB 265 | LD (R02), A ; R2: FB 266 | RET 267 | 268 | ; Scrape character off screen 269 | ; L: X coordinate 270 | ; H: Y coordinate 271 | ; Returns: 272 | ; R00 to R07: Character data in monochrome bitmap format 273 | ; 274 | Get_Char_M1: CALL Get_Char_Address_M1 ; Screen address in HL 275 | Z80PORT 0x123B, %00000110 ; Enable memory read only (to read screen data) 276 | LD DE, R00 277 | LD B, 8 278 | 1: PUSH BC 279 | PUSH HL 280 | LD B, 8 281 | LD C, 0 282 | 2: LD A, (TEXT_FOREGROUND) 283 | CP (HL) 284 | JR NZ, 3F 285 | SET 7, C 286 | 3: RLC C 287 | INC L 288 | DJNZ 2B 289 | LD A, C 290 | POP HL 291 | POP BC 292 | LD (DE), A 293 | INC E 294 | INC H 295 | DJNZ 1B 296 | Z80PORT 0x123B, %00000010 ; Disable memory read/write (ready to read ROM charset) 297 | RET 298 | ; 299 | Get_Char_M2: CALL Get_Char_Address_M2 ; Screen address in HL 300 | Z80PORT 0x123B, %00000110 ; Enable memory read only (to read screen data) 301 | LD DE, R00 302 | LD B, 8 303 | 1: PUSH BC 304 | PUSH HL 305 | LD B, 8 306 | LD C, 0 307 | 2: LD A, (TEXT_FOREGROUND) 308 | CP (HL) 309 | JR NZ, 3F 310 | SET 7, C 311 | 3: RLC C 312 | INC H 313 | DJNZ 2B 314 | LD A, C 315 | POP HL 316 | POP BC 317 | LD (DE), A 318 | INC E 319 | INC L 320 | DJNZ 1B 321 | Z80PORT 0x123B, %00000010 ; Disable memory read/write (ready to read ROM charset) 322 | RET 323 | ; 324 | Get_Char_M3: CALL Get_Char_Address_M3 325 | Z80PORT 0x123B, %00000110 ; Enable memory read only (to read screen data) 326 | LD DE, R00 327 | LD B, 8 328 | 1: PUSH BC 329 | PUSH DE 330 | PUSH HL 331 | LD B, 4 332 | LD C, 0 333 | LD A, (TEXT_FOREGROUND) 334 | AND 0x0F 335 | LD E, A 336 | SWAPNIB 337 | LD D, A 338 | 2: LD A, (HL) 339 | AND 0xF0 340 | CP D 341 | JR NZ, 3F 342 | SET 7, C 343 | 3: RLC C 344 | LD A, (HL) 345 | AND 0x0F 346 | CP E 347 | JR NZ, 4F 348 | SET 7, C 349 | 4: RLC C 350 | INC H 351 | DJNZ 2B 352 | LD A, C 353 | POP HL 354 | POP DE 355 | POP BC 356 | LD (DE), A 357 | INC E 358 | INC L 359 | DJNZ 1B 360 | Z80PORT 0x123B, %00000010 ; Disable memory read/write (ready to read ROM charset) 361 | RET 362 | 363 | ; Get screen address 364 | ; H = Y character position 365 | ; L = X character position 366 | ; Returns address in HL 367 | ; 368 | Get_Char_Address_M1: SLA L ; Multiply X by 8 369 | SLA L 370 | SLA L 371 | LD A, H ; Multiply Y by 8 372 | RLCA 373 | RLCA 374 | RLCA 375 | LD H, A ; Get the Y coordinate 376 | AND 0xC0 ; Get the bank number 377 | RLCA 378 | RLCA 379 | OR %00010000 380 | Z80PRTA 0x123B 381 | Z80PORT 0x123B, %00000011 ; Enable memory writes 382 | LD A, H 383 | AND 0x3F 384 | LD H, A 385 | RET 386 | ; 387 | Get_Char_Address_M2: LD A, L ; X 388 | AND %00111000 ; Get the bank number 389 | RRCA 390 | RRCA 391 | RRCA 392 | OR %00010000 393 | Z80PRTA 0x123B 394 | Z80PORT 0x123B, %00000011 ; Enable memory writes 395 | LD A, L ; Swap X and Y 396 | LD L, H 397 | SLA L ; Multiply Y by 8 398 | SLA L 399 | SLA L 400 | ADD A, A ; Multiply X by 8 401 | ADD A, A 402 | ADD A, A 403 | AND 0x3F 404 | LD H, A 405 | RET 406 | ; 407 | Get_Char_Address_M3: LD A, L ; X 408 | AND %01110000 ; Get the bank number 409 | SWAPNIB 410 | OR %00010000 411 | Z80PRTA 0x123B 412 | Z80PORT 0x123B, %00000011 ; Enable memory writes 413 | LD A, L ; Swap X and Y 414 | LD L, H 415 | SLA L ; Multiply Y by 8 416 | SLA L 417 | SLA L 418 | ADD A, A ; Multiply X by 4 419 | ADD A, A 420 | AND 0x3F 421 | LD H, A 422 | RET 423 | 424 | ; Get pixel position 425 | ; Pages in the correct 16K Layer 2 screen bank into 0x0000 426 | ; DE: X 427 | ; HL: Y 428 | ; Returns: 429 | ; HL: Address in memory (between 0x0000 and 0x3FFF) 430 | ; 431 | Get_Pixel_Address_M1: LD D, L ; Store the Y coordinate in D 432 | LD L, E ; The low byte is the X coordinate 433 | LD A, D ; Get the Y coordinate 434 | AND 0x3F ; Offset in bank 435 | LD H, A ; Store in high byte 436 | LD A, D ; Get the Y coordinate 437 | AND 0xC0 ; Get the bank number 438 | RLCA 439 | RLCA 440 | OR %00010000 441 | Z80PRTA 0x123B 442 | Z80PORT 0x123B, %00000111 ; Enable memory read/write 443 | RET 444 | ; 445 | Get_Pixel_Address_M2: LD A, E ; Get the X coordinate 446 | AND 0x3F ; Offset in bank 447 | LD H, A ; Store in high byte 448 | LD B, 6 449 | BSRA DE, B 450 | LD A, E ; Get the X coordinate 451 | OR %00010000 452 | LD E, A 453 | Z80PRTA 0x123B 454 | Z80PORT 0x123B, %00000111 ; Enable memory read/write 455 | RET 456 | ; 457 | Get_Pixel_Address_M3: SRL D ; But two pixels per byte 458 | RR E ; So divide X by 2 459 | PUSH AF 460 | CALL Get_Pixel_Address_M2 461 | POP AF 462 | RET 463 | 464 | ; Read a point 465 | ; HL: X 466 | ; DE: Y 467 | ; 468 | Point_M1: CALL Get_Pixel_Address_M1 469 | LD A, (HL) 470 | EX AF, AF 471 | Z80PORT 0x123B, %00000010 ; Disable memory writes 472 | EX AF, AF 473 | RET 474 | ; 475 | Point_M2: CALL Get_Pixel_Address_M2 476 | LD A, (HL) 477 | EX AF, AF 478 | Z80PORT 0x123B, %00000010 ; Disable memory writes 479 | EX AF, AF 480 | RET 481 | ; 482 | Point_M3: CALL Get_Pixel_Address_M3 483 | LD A, (HL) ; Fetch the byte 484 | JR C, 1F ; If right pixel then skip 485 | SWAPNIB ; Swap left pixel so its in right pixels nibble 486 | 1: AND 0x0F ; Mask out the pixel value 487 | EX AF, AF 488 | Z80PORT 0x123B, %00000010 ; Disable memory writes 489 | EX AF, AF 490 | RET 491 | 492 | RET 493 | 494 | ; Plot a point 495 | ; HL: Y 496 | ; DE: X 497 | ; 498 | Plot_M3: CALL Adjust_SCRLPOS_P 499 | CALL Get_Pixel_Address_M3 500 | LD A, (PLOT_COLOUR) 501 | JR C, 1F 502 | AND 0x0F ; Left hand pixel 503 | SWAPNIB 504 | LD E, A 505 | LD D, 0x0F ; Pixel mask 506 | JR 2F 507 | 1: AND 0x0F ; Right hand pixel 508 | LD E, A 509 | LD D, 0xF0 ; Pixel mask 510 | JR 2F 511 | ; 512 | Plot_M2: CALL Adjust_SCRLPOS_P 513 | CALL Get_Pixel_Address_M2 514 | JR 1F 515 | ; 516 | Plot_M1: CALL NEXT_GRAPHICS.NEXT_GRAPHICS_ULA.Adjust_SCRLPOS_P 517 | CALL Get_Pixel_Address_M1 518 | 1: LD A, (PLOT_COLOUR) 519 | LD E, A 520 | LD D, 0 521 | 2: CALL Plot 522 | Z80PORT 0x123B, %00000010 ; Disable memory writes 523 | RET 524 | 525 | ; Write out the pixel data 526 | ; D: Mask 527 | ; E: Pixel data to write 528 | ; 529 | Plot: LD A, (PLOT_MODE) ; Check plot mode is valid 530 | CP 7 531 | RET NC ; Do nothing if plot mode >=7 532 | CALL SWITCH_A 533 | Plot_Table: DEFW Plot_SET 534 | DEFW Plot_OR 535 | DEFW Plot_AND 536 | DEFW Plot_XOR 537 | DEFW Plot_NOT 538 | DEFW Plot_NOP 539 | DEFW Plot_CLR 540 | 541 | Plot_CLR: LD A, (HL) 542 | AND D 543 | LD (HL), A 544 | Plot_NOP: RET 545 | ; 546 | Plot_SET: LD A, (HL) 547 | AND D 548 | OR E 549 | LD (HL), A 550 | RET 551 | ; 552 | Plot_AND: LD A, (HL) 553 | AND E 554 | LD (HL), A 555 | RET 556 | ; 557 | Plot_OR: LD A, (HL) 558 | OR E 559 | LD (HL), A 560 | RET 561 | ; 562 | Plot_XOR: LD A, (HL) 563 | XOR E 564 | LD (HL), A 565 | RET 566 | ; 567 | Plot_NOT: LD A, D 568 | CPL 569 | XOR (HL) 570 | LD (HL), A 571 | RET 572 | 573 | ; Draw Horizontal Line routine 574 | ; HL: Y coordinate 575 | ; BC: X pixel position 1 576 | ; DE: X pixel position 2 577 | ; 578 | Draw_Horz_Line_M1: CALL NEXT_GRAPHICS.NEXT_GRAPHICS_ULA.Adjust_SCRLPOS_P 579 | ; 580 | LD B, C ; B: Low X1, E: Low X2 581 | LD D, L ; D: Low Y 582 | ; 583 | LD A, B ; Check if E (X1) > B (X2) 584 | CP E 585 | JR NC,0F 586 | LD B, E ; Swap B and D 587 | LD E, A 588 | 0: PUSH BC ; Stack colour and X2 589 | CALL Get_Pixel_Address_M1 ; Get pixel address 590 | POP BC 591 | LD A, B ; Calculate line length in bytes 592 | SUB E 593 | LD B, A ; Length in B 594 | INC B 595 | LD A, (PLOT_COLOUR) 596 | 1: LD (HL), A ; Draw the line 597 | INC L 598 | DJNZ 1B 599 | Z80PORT 0x123B, %00000010 ; Disable memory writes 600 | RET 601 | ; 602 | Draw_Horz_Line_M2: CALL Adjust_SCRLPOS_P 603 | PUSH HL ; Stack Y coordinate 604 | LD H, B ; HL: X1 605 | LD L, C 606 | CP16 HL, DE ; DE: X2 607 | JR NC, 1F ; X1 - X2 is > 0 608 | EX DE, HL ; Swap them 609 | 1: SUB HL, DE ; HL: Line length 610 | EX (SP), HL ; Swap with Y coordinate on stack 611 | CALL Get_Pixel_Address_M2 612 | LD A, (PLOT_COLOUR) 613 | LD D, A 614 | POP BC ; Restore loop counter 615 | INC BC 616 | 2: LD (HL), D 617 | INC H 618 | BIT 6, H 619 | CALL NZ, Next_Bank_M2M3 620 | DEC BC 621 | LD A, B 622 | OR C 623 | JR NZ, 2B 624 | Z80PORT 0x123B, %00000010 ; Disable memory writes 625 | RET 626 | ; 627 | Draw_Horz_Line_M3: CALL Adjust_SCRLPOS_P 628 | PUSH HL ; Stack Y coordinate 629 | LD H, B ; HL: X1 630 | LD L, C 631 | CP16 HL, DE ; DE: X2 632 | JR NC, 1F ; X1 - X2 is > 0 633 | EX DE, HL ; Swap them 634 | 1: SUB HL, DE ; HL: Line length 635 | EX (SP), HL ; Swap with Y coordinate on stack 636 | CALL Get_Pixel_Address_M3 637 | POP BC ; Restore the loop counter 638 | INC BC 639 | JR NC, 2F ; If we're on even boundary then fine 640 | ; 641 | LD A, (PLOT_COLOUR) ; Get the plot colour 642 | AND 0x0F 643 | LD D, A 644 | LD A, (HL) ; Write out the odd LSH nibble 645 | AND 0xF0 646 | OR D 647 | LD (HL), A 648 | INC H 649 | BIT 6, H 650 | CALL NZ, Next_Bank_M2M3 651 | DEC BC 652 | ; 653 | 2: LD A, (PLOT_COLOUR) ; Get the plot colour 654 | AND 0x0F 655 | LD D, A 656 | SWAPNIB 657 | OR D 658 | LD D, A ; D: Plot colour 659 | ; 660 | ; POP BC ; Restore the loop counter 661 | SRL B ; Divide by 2 662 | RR C 663 | PUSH AF ; Stack the carry bit 664 | LD A, B ; Check for 0 665 | OR C 666 | JR Z, 4F 667 | ; 668 | 3: LD (HL), D 669 | INC H 670 | BIT 6, H 671 | CALL NZ, Next_Bank_M2M3 672 | DEC BC ; TODO: Needs to do half this 673 | LD A, B 674 | OR C 675 | JR NZ, 3B 676 | ; 677 | 4: POP AF ; Restore the carry bit 678 | JR NC, 5F ; Is there a final pixel to plot? 679 | LD A, D ; Yes, we already have the plot colours in D 680 | AND 0xF0 ; Just want it in top nibble 681 | LD D, A 682 | LD A, (HL) 683 | AND 0x0F 684 | OR D 685 | LD (HL), A 686 | 5: Z80PORT 0x123B, %00000010 ; Disable memory writes 687 | RET 688 | 689 | ; Switch to the next bank 690 | ; HL: Screen addreses 691 | ; E: Curent bank 692 | ; 693 | Next_Bank_M2M3: LD H, 0 ; Reset pixel pointer 694 | INC E ; Increment to next page 695 | PUSH BC 696 | Z80PORT 0x123B, E 697 | Z80PORT 0x123B, %00000111 698 | POP BC 699 | RET 700 | 701 | ; Set the graphics colour 702 | ; C: Colour to set 703 | ; B: Mode 704 | ; 705 | Set_Plot_Colour: LD A, B 706 | CP 3 707 | JP Z, NEXT_GRAPHICS.Set_Border 708 | LD A, C 709 | LD (PLOT_COLOUR), A 710 | RET 711 | 712 | ; Set the text colour 713 | ; C: Colour to set 714 | ; B: Mode (ignored) 715 | ; 716 | Set_Text_Colour: LD A, B 717 | CP 4 718 | RET NC 719 | CALL SWITCH_A 720 | DEFW Set_Text_Colour_All 721 | DEFW Set_Text_Foreground 722 | DEFW Set_Text_Background 723 | DEFW NEXT_GRAPHICS.Set_Border 724 | 725 | Set_Text_Colour_All: BIT 7, C 726 | JR Z, Set_Text_Foreground 727 | RES 7, C 728 | Set_Text_Background: LD A, C 729 | LD (TEXT_BACKGROUND), A 730 | RET 731 | Set_Text_Foreground: LD A, C 732 | LD (TEXT_FOREGROUND), A 733 | RET 734 | 735 | ENDMODULE -------------------------------------------------------------------------------- /next_graphics_ULA.z80: -------------------------------------------------------------------------------- 1 | ; 2 | ; Title: BBC Basic Interpreter - Z80 version 3 | ; Spectrum Next ULA Graphics Routines 4 | ; Author: Dean Belfield 5 | ; Created: 13/05/2021 6 | ; Last Updated: 12/07/2021 7 | ; 8 | ; Modinfo: 9 | ; 15/05/2021: Plot now pulls PLOT_MODE and PLOT_COLOUR direct from RAM; Updates for MODE command 10 | ; 17/05/2021: Tweaks for COLOUR, GCOL 11 | ; 19/05/2021: Fixed bug in Get_Char 12 | ; 20/05/2021: Added Draw_Horz_Line; Fixed bug in Set_Attr 13 | ; 22/05/2021: Added Point; Minor optimisations 14 | ; 26/05/2021: Added support code for Layer 2 modes 2 and 3 15 | ; 28/05/2021: Removed Display_Cursor 16 | ; 04/06/2021: Point and Triangle now work correctly with scroll offset 17 | ; 06/06/2021: CLS now uses DMA 18 | ; 08/06/2021: Fixed default palette and reset sprite clipping 19 | ; 11/06/2021: Now uses NREG definitions in equs.z80 20 | ; 21/06/2021: Added support for CLG; Tweaks to Get_Char 21 | ; 12/07/2021: Added support for UDGs 22 | 23 | MODULE NEXT_GRAPHICS_ULA 24 | 25 | ; Set the video mode up 26 | ; 27 | Set_Video_Mode: LD A, %01000111 28 | LD (TEXT_FOREGROUND), A 29 | LD (PLOT_COLOUR), A 30 | LD A, 32 31 | LD (CHAR_COLS), A 32 | LD A, 24 33 | LD (CHAR_ROWS), A 34 | LD BC, 256 35 | LD (PIXEL_WIDTH), BC 36 | LD BC, 192 37 | LD (PIXEL_HEIGHT), BC 38 | CALL NEXT_GRAPHICS.CLS 39 | NEXTREG NREG.LAYER_CONTROL, %00101001 ; Enable sprites & clipping, SUL priority 40 | NEXTREG NREG.L2_CONTROL, %00000000 ; Reset Layer 2 resolution 41 | NEXTREG NREG.CLIP_WINDOW_L2, 0 42 | NEXTREG NREG.CLIP_WINDOW_L2, 255 43 | NEXTREG NREG.CLIP_WINDOW_L2, 0 44 | NEXTREG NREG.CLIP_WINDOW_L2, 191 ; Resetting Layer 2 clipping 45 | NEXTREG NREG.CLIP_WINDOW_SPRITES, 0 ; Clip Window Sprites 46 | NEXTREG NREG.CLIP_WINDOW_SPRITES, 255 47 | NEXTREG NREG.CLIP_WINDOW_SPRITES, 0 48 | NEXTREG NREG.CLIP_WINDOW_SPRITES, 191 + 32 49 | NEXTREG NREG.PALETTE_CONTROL, %10000000 ; Change ULA first palette 50 | RET 51 | 52 | ; Clear the screen 53 | ; Used by CLS and CLG 54 | ; C: Colour to clear screen with 55 | ; 56 | Clear_Screen: LD A, (BORDER_COLOUR) 57 | OUT (254), A 58 | LD A, C 59 | LD (R00), A 60 | XOR A 61 | LD DE, 16384 62 | LD BC, 6144 63 | CALL NEXT_DMA.FillDMA 64 | LD A, (R00) 65 | LD DE, 22528 66 | LD BC, 768 67 | CALL NEXT_DMA.FillDMA 68 | NEXTREG NREG.ULA_SCROLL_Y, 0 ; Reset scroll 69 | RET 70 | 71 | ; Scroll 72 | ; H: Line to clear after scroll 73 | ; 74 | Set_Scroll_Reg: LD A, (SCRLPOS_Y) 75 | ADD A, A 76 | ADD A, A 77 | ADD A, A 78 | NEXTREG NREG.ULA_SCROLL_Y, A 79 | RET 80 | 81 | ; Adjust HL for scroll position 82 | ; HL: Y 83 | ; Returns: 84 | ; HL: Y adjusted for Y 85 | ; 86 | Adjust_SCRLPOS_P: LD A, (SCRLPOS_Y) ; Get Y scroll position 87 | ADD A, A 88 | ADD A, A 89 | ADD A, A ; Multiply by 8 90 | ADD A, L ; Add to pixel Y position 91 | JR C, 0F ; If we've wrapped, then skip 92 | CP 192 ; Gone off screen? 93 | JR C, 1F 94 | 0: SUB 192 95 | 1: LD L, A 96 | RET 97 | 98 | ; Print a single character out to an X/Y position 99 | ; E: Character to print 100 | ; L: X Coordinate 101 | ; H: Y Coordinate 102 | ; 103 | Print_Char: CALL Get_Char_Address 104 | CALL Get_Character_Data 105 | LD B,8 ; Loop counter 106 | 1: LD A,(DE) ; Get the byte from the character in A 107 | LD (HL),A ; Stick A onto the screen 108 | INC DE ; Goto next byte of character 109 | INC H ; Goto next line on screen 110 | DJNZ 1B ; Loop around whilst it is Not Zero (NZ) 111 | LD A, H ; And set the attribute up too 112 | RRA 113 | RRA 114 | RRA 115 | DEC A 116 | AND 3 117 | OR 88 118 | LD H, A 119 | LD A,(TEXT_FOREGROUND) 120 | LD (HL), A 121 | RET 122 | 123 | ; Scrape character off screen 124 | ; L: X coordinate 125 | ; H: Y coordinate 126 | ; Returns: 127 | ; R00 to R07: Character data in monochrome bitmap format 128 | ; 129 | Get_Char: CALL Get_Char_Address ; Get character address in HL 130 | LD DE, R00 ; Storage for bitmap data 131 | LD B, 8 132 | 1: LD A, (HL) 133 | LD (DE), A 134 | INC H 135 | INC E 136 | DJNZ 1B 137 | RET 138 | 139 | ; Get screen address 140 | ; H: Y character position 141 | ; L: X character position 142 | ; Returns address in HL 143 | ; 144 | Get_Char_Address: LD A,H 145 | AND %00000111 146 | RRCA 147 | RRCA 148 | RRCA 149 | OR L 150 | LD L,A 151 | LD A,H 152 | AND %00011000 153 | OR %01000000 154 | LD H,A 155 | RET ; Returns screen address in HL 156 | 157 | ; Get the attribute address 158 | ; H: Y character position 159 | ; L: X character position 160 | ; Return address in HL 161 | ; 162 | Get_Attr_Address: PUSH DE 163 | LD D, 32 ; Multiply Y by 32 164 | LD E, H 165 | LD A, L ; Get the X offset 166 | MUL D, E ; Multiply Y by 32 167 | ADD DE, A ; Add X 168 | EX DE, HL 169 | LD A, H 170 | ADD A, 0x58 ; Add the attribute 171 | LD H, A 172 | POP DE 173 | RET 174 | 175 | ; Read a point 176 | ; HL: X 177 | ; DE: Y 178 | ; 179 | Point: CALL Adjust_SCRLPOS_P 180 | LD D, L ; D: Y Coordinate 181 | PIXELAD ; Get the pixel address in HL 182 | SETAE ; Get pixel position in A 183 | AND (HL) ; Mask out pixel 184 | RET Z 185 | LD A, 1 186 | RET 187 | 188 | ; Plot a point 189 | ; HL: Y 190 | ; DE: X 191 | ; 192 | Plot: LD A, (PLOT_MODE) ; Check plot mode is valid 193 | CP 7 194 | RET NC ; Do nothing if plot mode >=7 195 | CALL Adjust_SCRLPOS_P 196 | 1: LD D, L ; D = Y, E = X 197 | PIXELAD ; Get the pixel address in HL 198 | SETAE ; Get pixel mask in A 199 | LD E, A ; E: Pixel mask 200 | LD A, (PLOT_MODE) 201 | CALL SWITCH_A 202 | DEFW Plot_OR 203 | DEFW Plot_OR 204 | DEFW Plot_AND 205 | DEFW Plot_XOR 206 | DEFW Plot_XOR 207 | DEFW Plot_NOP 208 | DEFW Plot_AND 209 | 210 | Plot_NOP: RET ; Jump to plot routine (address stacked previous) 211 | 212 | Plot_OR: LD A, (HL) 213 | OR E ; OR with screen 214 | LD (HL), A 215 | JR Plot_Attribute 216 | 217 | Plot_AND: LD A, E ; AND with screen 218 | CPL 219 | AND (HL) 220 | LD (HL), A 221 | JR Plot_Attribute 222 | 223 | Plot_XOR: LD A, (HL) 224 | XOR E ; XOR with screen 225 | LD (HL), A 226 | JR Plot_Attribute 227 | 228 | ; Write colour value out to ULA attribute map 229 | ; HL: Address in ULA pixel map 230 | ; 231 | Plot_Attribute: LD A, H ; Get the attribute address from the screen address 232 | RRA 233 | RRA 234 | RRA 235 | AND 3 236 | OR 88 237 | LD H, A 238 | LD A, (PLOT_COLOUR) 239 | LD (HL), A ; Write the colour out 240 | RET 241 | 242 | ; Draw Horizontal Line routine 243 | ; HL: Y coordinate 244 | ; BC: X pixel position 1 245 | ; DE: X pixel position 2 246 | ; 247 | Draw_Horz_Line: CALL Adjust_SCRLPOS_P 248 | ; 249 | LD B, C ; B: Low X1, E: Low X2 250 | LD D, L ; D: Low Y 251 | ; 252 | LD A, B ; Check if E (X1) > B (X2) 253 | CP E 254 | JR NC,0F 255 | LD B, E ; Swap B and D 256 | LD E, A 257 | 0: PIXELAD ; HL: Screen Address 258 | LD D, B ; D: X2 259 | LD A, E ; Calculate index into table for X1 260 | AND 7 261 | LD BC, Plot_Line_LHS ; Get pixel data table 262 | ADD BC, A 263 | LD A, (BC) ; 264 | LD E, A ; E: X1 pixel mask 265 | ; HL: Screen address 266 | ; E: X1 pixel data 267 | LD A, D ; Calculate index into table for X2 268 | AND 7 269 | LD BC, Plot_Line_RHS 270 | ADD BC, A 271 | LD A, D ; Now the byte address for D 272 | RRCA 273 | RRCA 274 | RRCA 275 | AND 31 276 | LD D, A 277 | LD A, L 278 | AND %11100000 279 | OR D 280 | LD D, A ; D: Screen address (low byte) for X2 281 | LD A, (BC) 282 | LD C, A ; C: X2 pixel mask 283 | LD A, D ; Get number of bytes to write 284 | SUB L 285 | JR NZ, 1F ; If not zero, we're writing more than 1 byte 286 | LD A, E 287 | XOR C ; Otherwise, combine the pixel masks 288 | CPL 289 | OR (HL) ; OR with screen contents 290 | LD (HL), A 291 | JP Plot_Attribute ; Write out the attribute byte 292 | ; 293 | 1: LD B, A ; Loop counter 294 | LD A, (HL) ; Write out the pixel data 295 | OR E ; OR first byte with screen contents 296 | LD (HL), A 297 | LD D, B ; Backup of loop counter 298 | LD E, L ; Backup of low byte 299 | INC L 300 | DEC B 301 | JR Z, 3F 302 | LD A, 255 303 | 2: LD (HL), A ; Write out the main block 304 | INC L 305 | DJNZ 2B 306 | 3: LD A, (HL) ; Write out the last byte 307 | OR C ; OR last byte with screen contents 308 | LD (HL), A 309 | ; 310 | LD L, E ; Restore backup of low byte 311 | LD B, D ; And loop counter 312 | CALL Plot_Attribute ; Write the first attribute byte 313 | INC B 314 | 4: LD (HL), A ; Write out subsequent bytes 315 | INC L 316 | DJNZ 4B 317 | RET 318 | ; 319 | ; End-point masks for the horizontal lines 320 | ; 321 | Plot_Line_LHS: DB %11111111,%01111111,%00111111,%00011111,%00001111,%00000111,%00000011,%00000001 322 | Plot_Line_RHS: DB %10000000,%11000000,%11100000,%11110000,%11111000,%11111100,%11111110,%11111111 323 | 324 | ; Calculate Speccy colour for COLOUR and GCOL 325 | ; C: New Colour 326 | ; A: Existing attribute value 327 | ; Returns: 328 | ; A: New attribute value 329 | ; 330 | Get_Attr_Value: BIT 7, C ; Check bit 7 of the new colour 331 | JR Z, 1F ; for numbers >=128 332 | AND %11000111 ; And out the PAPER colour 333 | LD B, A ; Store in B 334 | LD A, C 335 | AND %00000111 ; Get colour 336 | RLA ; Shift into position 337 | RLA 338 | RLA 339 | OR B ; Or with existing colour 340 | RET 341 | 1: AND %11111000 ; And out the INK colour 342 | LD B, A ; Store in B 343 | LD A, C 344 | AND %00000111 ; Get colour 345 | OR B ; Or with existing colour 346 | RET 347 | 348 | ; Set the graphics colour 349 | ; HL: Value to set 350 | ; C: Colour to set 351 | ; B: Mode 352 | ; 353 | Set_Plot_Colour: LD HL, PLOT_COLOUR 354 | JR Set_Attr 355 | 356 | ; Set the text colour 357 | ; HL: Value to set 358 | ; C: Colour to set 359 | ; B: Mode 360 | ; 361 | Set_Text_Colour: LD HL, TEXT_FOREGROUND 362 | CALL Set_Attr 363 | LD A, (HL) 364 | LD (TEXT_BACKGROUND), A ; For CLS 365 | RET 366 | ; 367 | Set_Attr: LD A, B 368 | CP 6 369 | RET NC 370 | CALL SWITCH_A 371 | DEFW Set_Attr_All 372 | DEFW Set_Attr_Ink 373 | DEFW Set_Attr_Paper 374 | DEFW NEXT_GRAPHICS.Set_Border 375 | DEFW Set_Attr_Bright 376 | DEFW Set_Attr_Flash 377 | ; 378 | Set_Attr_Paper: SET 7, C 379 | JR Set_Attr_All 380 | ; 381 | Set_Attr_Ink: RES 7, C 382 | Set_Attr_All: LD A, (HL) 383 | CALL Get_Attr_Value 384 | LD (HL), A 385 | RET 386 | ; 387 | Set_Attr_Bright: LD A, C 388 | AND 1 389 | RRCA 390 | RRCA 391 | LD B, A 392 | LD A, (HL) 393 | AND %10111111 394 | OR B 395 | LD (HL), A 396 | RET 397 | ; 398 | Set_Attr_Flash: LD A, C 399 | AND 1 400 | RRCA 401 | LD B, A 402 | LD A, (HL) 403 | AND %01111111 404 | OR B 405 | LD (HL), A 406 | RET 407 | 408 | ENDMODULE -------------------------------------------------------------------------------- /next_init.z80: -------------------------------------------------------------------------------- 1 | ; 2 | ; Title: BBC Basic Interpreter - Z80 version 3 | ; Spectrum Next Initialisation 4 | ; Author: Dean Belfield 5 | ; Created: 04/05/2021 6 | ; Last Updated: 15/07/2021 7 | ; 8 | ; Modinfo: 9 | ; 13/05/2021: Added BUILD_VERSION 10 | ; 15/05/2021: Updates for MODE command 11 | ; 17/05/2021: Border colour now set in CLS 12 | ; 21/05/2021: Added Initialise_RAM 13 | ; 23/05/2021: Initialises page registers 14 | ; 25/05/2021: Initialises FDRIVE 15 | ; 26/05/2021: Cursor now on interrupt 16 | ; 04/06/2021: Intitialises NEXT_SOUND 17 | ; 08/06/2021: Test for ESC now done on interrupt 18 | ; 11/06/2021: Now uses NREG definitions in equs.z80 19 | ; 14/06/2021: Setup default (Spectrum) palette for L2 modes 20 | ; 24/06/2021: Disabled RAM contention (Peripheral 3) 21 | ; 12/07/2021: Added Reserve_UDG 22 | ; 15/07/2021: Variables KEY_DELAY and KEY_REPEAT are initialised; Some KEY variables renamed 23 | 24 | MODULE NEXT_INIT 25 | 26 | System: DI 27 | LD SP,Stack_Top ; Stick the stack somewhere safe for now 28 | 29 | NEXTREG NREG.CONFIG_MAPPING, 0x03 30 | NEXTREG NREG.PERIPHERAL_1, %01110001 ; Peripheral 1 settings 31 | NEXTREG NREG.PERIPHERAL_2, %10101000 ; Peripheral 2 settings 32 | NEXTREG NREG.PERIPHERAL_3, %11011110 ; Peripheral 3 settings 33 | ; NEXTREG NREG.PERIPHERAL_4, %00011000 ; Peripheral 4 settings 34 | NEXTREG NREG.MACHINE_TYPE, %10110011 ; Machine type - Native Next/128K+3 35 | 36 | NEXTREG NREG.MMU_SLOT_1, 0xFF ; MMU Slot 1 0x0000 - ROM 37 | NEXTREG NREG.MMU_SLOT_2, 0xFF ; MMU Slot 2 0x2000 - ROM 38 | NEXTREG NREG.MMU_SLOT_3, 0x0A ; MMU Slot 3 0x4000 39 | NEXTREG NREG.MMU_SLOT_4, 0x0B ; MMU Slot 4 0x6000 40 | NEXTREG NREG.MMU_SLOT_5, 0x04 ; MMU Slot 5 0x8000 41 | NEXTREG NREG.MMU_SLOT_6, 0x05 ; MMU Slot 6 0xA000 42 | NEXTREG NREG.MMU_SLOT_7, 0x0E ; MMU Slot 7 0xC000 43 | NEXTREG NREG.MMU_SLOT_8, 0x0F ; MMU Slot 8 0xE000 44 | 45 | NEXTREG NREG.MEMORY_MAP_MODE, 0x00 ; Spectrum Next mapping mode 46 | 47 | NEXTREG NREG.L2_ACTIVE_RAM, 0x09 ; Layer 2 RAM bank 48 | NEXTREG NREG.L2_SHADOW_RAM, 0x09 ; Layer 2 Shadow RAM bank 49 | 50 | NEXTREG NREG.CPU_SPEED, 0x00 ; CPU to 3.5Mhz 51 | 52 | NEXTREG NREG.PALETTE_CONTROL, %00000000 ; Select ULA, first palette, not ULANext 53 | 54 | Z80PORT 0x1FFD, %00000100 ; Page 48K BASIC in 55 | Z80PORT 0x7FFD, %00010000 56 | 57 | CALL Initialise_RAM 58 | CALL Initialise_Interrupt ; Initialise the interrupt handler 59 | CALL Initialise_Palette 60 | 61 | XOR A ; Set the video mode 62 | CALL NEXT_GRAPHICS.Set_Video_Mode 63 | CALL NEXT_SOUND.Initialise 64 | CALL TELL 65 | DEFM "Spectrum Next Version ", BUILD_VERSION, "\n\r" 66 | DEFM "\n\r" 67 | DEFB 0 68 | EI 69 | JP MAIN.COLD 70 | ; 71 | ; Initialise the RAM 72 | ; 73 | Initialise_RAM: LD HL, RAM.Start 74 | LD BC, RAM.Length 75 | LD E, 0 76 | 1: LD (HL), E 77 | DEC BC 78 | LD A, B 79 | OR C 80 | JR NZ, 1B 81 | LD A, %01000111: LD (TEXT_FOREGROUND), A 82 | LD A, %01000111: LD (PLOT_COLOUR), A 83 | LD A, "$": LD (FDRIVE), A 84 | LD A, CONF_KEYRPT_1: LD (KEY_DELAY), A 85 | LD A, CONF_KEYRPT_2: LD (KEY_REPEAT), A 86 | RET 87 | 88 | ; Set HIMEM to reserve some space for UDGS 89 | ; A: Number of banks to reserve (0 to 6) 90 | ; Returns: 91 | ; DE: HIMEM value for OSINIT 92 | ; 93 | Reserve_UDG: PUSH AF 94 | LD D, A ; Calculate HIMEM 95 | LD A, (high @RAM_Top) - 1 96 | SUB D 97 | LD D, A 98 | LD E, 0 99 | POP AF 100 | LD HL, Reserve_UDG_Table ; Get the UDG_MASK 101 | ADD HL, A 102 | LD A, (HL) 103 | LD (UDG_MASK), A 104 | RET 105 | ; 106 | ; The mask is 1 bit per &20 (32) characters and is used to determine whether to read the character data from ROM (0) or RAM (1) 107 | ; The bits are read left to right, so %10000000 is characters 0-31, and %00000001 is characters 224 to 255 108 | ; 109 | Reserve_UDG_Table: DB %00001000 ; Characters &80 to &9F only are redefineable (default) 110 | DB %00001100 ; Characters &80 to &BF are redefineable 111 | DB %00001110 ; Characters &80 to &DF are redefineable 112 | DB %00001111 ; Characters &80 to &FF are redefineable 113 | DB %01001111 ; Characters &20 to &3F, &80 to &FF are redefineable 114 | DB %01101111 ; Characters &20 to &5F, &80 to &FF are redefineable 115 | DB %01111111 ; Characters &20 to &FF are redefineable 116 | 117 | ; 118 | ; Initialise the L2 palette 119 | ; 120 | Initialise_Palette: LD HL, Default_Palette 121 | LD B, 16 122 | NEXTREG NREG.PALETTE_CONTROL, %10010000 ; Change L2 first palette 123 | 1: LD A, 16 124 | SUB B 125 | NEXTREG NREG.PALETTE_INDEX, A 126 | LD A, (HL) 127 | NEXTREG NREG.PALETTE_VALUE_2, A 128 | INC HL 129 | LD A, (HL) 130 | NEXTREG NREG.PALETTE_VALUE_2, A 131 | INC HL 132 | DJNZ 1B 133 | RET 134 | ; 135 | Default_Palette: DW 0x000,0x102,0x0A0,0x1A2,0x014,0x116,0x0B4,0x1B6 136 | DW 0x000,0x103,0x0E0,0x1E7,0x01C,0x11F,0x0FC,0x1FF 137 | 138 | ; 139 | ; Interrupt routine 140 | ; 141 | Interrupt: DI 142 | PUSH AF, BC, DE, HL, IX 143 | EXX 144 | EX AF,AF' 145 | PUSH AF, BC, DE, HL, IY 146 | 147 | CALL NEXT_CURSOR.Move 148 | CALL NEXT_IO.Read_Keyboard 149 | LD (KEY_CODE), A 150 | CP 0x1B 151 | CALL Z, PATCH.ESCSET 152 | LD A, (TIME + 0) 153 | AND 0x02 154 | CALL Z, NEXT_SOUND.Play_Queue 155 | 156 | LD DE, 2 157 | LD HL, (TIME + 0) 158 | ADD HL, DE 159 | LD (TIME + 0), HL 160 | JR NC, 1F 161 | LD HL, (TIME + 2) 162 | INC HL 163 | LD (TIME + 2), HL 164 | 165 | 1: POP IY, HL, DE, BC, AF 166 | EXX 167 | EX AF,AF' 168 | POP IX, HL, DE, BC, AF 169 | EI 170 | RET 171 | ; 172 | ; Interrupt routine 173 | ; 174 | Initialise_Interrupt: LD DE, IM2_Table ; The IM2 vector table (on page boundary) 175 | LD HL, IM2_JP ; Pointer for 3-byte interrupt handler 176 | LD A, D ; Interrupt table page high address 177 | LD I, A ; Set the interrupt register to that page 178 | LD A, L ; Fill page with values 179 | 1: LD (DE), A 180 | INC E 181 | JR NZ, 1B 182 | INC D ; In case data bus bit 0 is not 0, we 183 | LD (DE), A ; put an extra byte in here 184 | LD (HL), 0xC3 ; Write out the interrupt handler, a JP instruction 185 | INC L 186 | LD (HL), low Interrupt ; Store the address of the interrupt routine in 187 | INC L 188 | LD (HL), high Interrupt 189 | IM 2 ; Set the interrupt mode 190 | RET 191 | 192 | ENDMODULE 193 | -------------------------------------------------------------------------------- /next_io.z80: -------------------------------------------------------------------------------- 1 | ; 2 | ; Title: BBC Basic Interpreter - Z80 version 3 | ; Spectrum Next I/O Routines 4 | ; Author: Dean Belfield 5 | ; Created: 03/05/2021 6 | ; Last Updated: 15/07/2021 7 | ; 8 | ; Modinfo: 9 | ; 10/05/2021: Started implementing VDU engine 10 | ; 11/05/2021: Fixed bug in Scroll_Down 11 | ; 13/05/2021: Removed (C) symbol from keytable; 0x7F is now backspace 12 | ; 14/05/2021: Fixed bug in Print_Char - now preserves A 13 | ; 15/05/2021: Restored (C) symbol in keytable as ASCII 0xA9; Updates for MODE command 14 | ; 16/05/2021: VDU system now uses SWITCH_A 15 | ; 17/05/2021: Removed PUSH/POP wrapper around Read_Keyboard and added HT and BS codes; Tweaks for COLOUR, GCOL 16 | ; 19/05/2021: Added LF and VT on Shift 6 and 7 in Read_Keyboard and COPY on Shift 1 17 | ; 20/05/2021: Print_Char now preserves IX 18 | ; 21/05/2021: Fixed debounce for EDIT and CAPS LOCK and added key repeat 19 | ; 26/05/2021: Added support code for Layer 2 modes 2 and 3 20 | ; 16/06/2021: Added VDU_GS (Set graphics origin) 21 | ; 21/06/2021: Added VDU_DLE (CLG) 22 | ; 12/07/2021: Added VDU_ETB (UDG) 23 | ; 15/07/2021: Modified Read_Keyboard to use KEY_DELAY and KEY_REPEAT variables in RAM 24 | 25 | MODULE NEXT_IO 26 | 27 | ; Read the keyboard and return an ASCII character code 28 | ; Returns: 29 | ; A: 0x00 (NUL) if no key pressed 30 | ; 31 | Read_Keyboard: CALL Keyscan ; Scan the keyboard 32 | 33 | LD HL, (KEY_SCAN) ; Are we stil pressing the same key combo 34 | XOR A 35 | SBC HL, DE 36 | LD A, (KEY_DELAY) ; Initial key repeat value 37 | JR NZ, 1F ; No, so move onto next check 38 | LD A,(KEY_COUNT) ; Simple key repeat 39 | DEC A 40 | LD (KEY_COUNT), A 41 | LD A,(KEY_REPEAT) ; Subsequent key repeat value 42 | JR Z, 1F 43 | XOR A 44 | RET 45 | 46 | 1: LD (KEY_COUNT), A 47 | LD (KEY_SCAN), DE ; Store the new keyscan 48 | LD A, E ; Get the keycode 49 | INC A ; Check for 0xFF 50 | RET Z ; Then no key has been pressed 51 | DEC A 52 | LD HL, KeyTable_Main ; Lookup the key value 53 | ADD HL, A 54 | 55 | LD A, (HL) ; Fetch the key value 56 | 57 | CP "A" ; Is it a letter? 58 | JR C, 3F ; No, so skip 59 | 60 | BIT 1, D ; Has symbol shift been pressed? 61 | JR NZ, 2F ; Yes, so get the shifted value 62 | LD E, A ; Store the keycode 63 | LD A, (FLAGS) ; Get caps lock flag 64 | AND %00100000 65 | XOR E 66 | BIT 0, D ; Has caps shift been pressed 67 | RET Z ; No, so just return the letter 68 | XOR %00100000 ; Switch case 69 | RET 70 | ; 71 | ; It's a symbol shifted letter at this point 72 | ; 73 | 2: SUB "A" 74 | LD HL, KeyTable_SS_Alpha ; Get the key value 75 | ADD HL, A 76 | LD A, (HL) ; Get the character code 77 | RET 78 | ; 79 | ; It's not a letter at this point, but could be space or enter 80 | ; 81 | 3: BIT 0, D ; Check for caps 82 | JR NZ, 4F ; If pressed, we'll check for special cases 83 | BIT 1, D ; Has symbol shift been pressed 84 | RET Z ; No, so just return the number 85 | SUB "0" ; Index from ASCII '0' 86 | LD HL, KeyTable_SS_Numeric 87 | ADD HL, A 88 | LD A, (HL) 89 | RET 90 | ; 91 | ; Special cases, like escape, etc. Caps shift is pressed here 92 | ; 93 | 4: CP " " ; Caps Shift + Space 94 | JR NZ, 5F 95 | LD A, 0x1B ; Return ESC 96 | RET 97 | 5: CP "0" ; Caps Shift + 0 98 | JR NZ, 6F 99 | LD A, 0x7F ; Return DEL 100 | RET 101 | 6: CP "5" ; Caps Shift + 5 102 | JR NZ, 7F 103 | LD A, 0x08 ; Return BS 104 | RET 105 | 7: CP "8" ; Caps Shift + 8 106 | JR NZ, 8F 107 | LD A, 0x09 ; Return HT 108 | RET 109 | 8: CP "6" ; Caps Shift + 6 110 | JR NZ, 9F 111 | LD A, 0x0A ; Return LF 112 | RET 113 | 9: CP "7" ; Caps Shift + 7 114 | JR NZ, 10F 115 | LD A, 0x0B ; Return VT 116 | RET 117 | 10: CP "2" ; Caps Shift + 2 118 | LD B, %00100000 119 | JR Z, Toggle_Flags 120 | CP "1" 121 | LD B, %00010000 122 | RET NZ 123 | Toggle_Flags: LD A, (FLAGS) ; Toggle Caps Lock bit in flags 124 | XOR B 125 | LD (FLAGS), A 126 | XOR A ; Clear the keycode 127 | RET 128 | 129 | ; Get adjusted charpos (takes scrollpos into account) 130 | ; 131 | Get_Charpos LD HL, (CHARPOS_X) 132 | Get_Charpos_1: PUSH AF 133 | LD A, (CHAR_ROWS) 134 | LD B, A 135 | LD A, (SCRLPOS_Y) 136 | ADD A, H 137 | CP B 138 | JR C, 1F 139 | SUB B 140 | 1: LD H, A 141 | POP AF 142 | RET 143 | 144 | ; Print a character at the current charpos 145 | ; Destroys nothing 146 | ; 147 | Print_Char: PUSH AF, BC, DE, HL, IX ; Stack all the registers 148 | CALL 1F ; Call the print routine 149 | POP IX, HL, DE, BC, AF 150 | RET 151 | 1: LD C, A ; Temporarily store the character 152 | LD A, (VDU_STATE) ; What's the current VDU state? 153 | OR A ; If not zero... 154 | JR NZ, VDU_READ_BYTES ; Read the data into the VDU buffer and don't output 155 | LD A, C ; Get the character code back 156 | CP 32 ; Is the character a control routine? 157 | JR C, VDU_CTRL_CHAR ; Yes, so just handle that 158 | CP 0x7F ; Is it backspace? 159 | JR Z, VDU_DEL ; Yes, so deal with that 160 | CP 0xA9 ; Bodge for Spectrum (C) symbol 161 | JR NZ, 2F 162 | LD A, 0x7F 163 | 2: CALL Get_Charpos ; Otherwise print it out 164 | CALL NEXT_GRAPHICS.Print_Char 165 | JP VDU_HT 166 | 167 | ; &7F DEL - Delete 168 | ; 169 | VDU_DEL: CALL VDU_BS 170 | LD A, " " 171 | CALL Get_Charpos 172 | JP NEXT_GRAPHICS.Print_Char 173 | 174 | ; Just buffer the characters in the VDU buffer 175 | ; Until we have read enough in, then execute the relevant code 176 | ; 177 | VDU_READ_BYTES: LD IX, VDU_STATE ; Indexes - 0: STATE, 1: PTR, 2: COUNT 178 | LD HL, VDU_BUFFER ; HL: VDU buffer 179 | LD A, (IX + 1) ; A: Current position in buffer 180 | ADD HL, A ; Index in 181 | LD (HL), C ; Store the character 182 | INC (IX + 1) ; Increase the pointer 183 | DEC (IX + 2) ; Decrease the counter 184 | RET NZ ; If not zero, then return 185 | LD A, (IX + 0) ; Get the state 186 | LD (IX + 0), 0 ; Clear it 187 | DEC A ; Index from 1 188 | LD IX, VDU_BUFFER 189 | CALL SWITCH_A 190 | DEFW VDU_EXEC_PLOT 191 | DEFW VDU_EXEC_COLOUR 192 | DEFW VDU_EXEC_GCOL 193 | DEFW VDU_EXEC_TAB 194 | DEFW VDU_EXEC_MODE 195 | DEFW VDU_EXEC_GORIGIN 196 | DEFW VDU_EXEC_UDG 197 | 198 | ; Handle all control characters 199 | ; A: Character code 200 | ; C: Character code (copied in Print_Char) 201 | ; 202 | VDU_CTRL_CHAR: CALL SWITCH_A 203 | DW VDU_NUL ; &00 NUL - Do nothing 204 | DW VDU_NUL ; &01 SOH - Send next character to printer only 205 | DW VDU_NUL ; &02 STX - Start print job 206 | DW VDU_NUL ; &03 ETX - End print job 207 | DW VDU_NUL ; &04 EOT - Write text at text cursor 208 | DW VDU_NUL ; &05 ENQ - Write text at graphics cursor 209 | DW VDU_NUL ; &06 ACK - Enable VDU drivers 210 | DW VDU_NUL ; &07 BEL - Make a short beep 211 | DW VDU_BS ; &08 BS - Backspace 212 | DW VDU_HT ; &09 HT - Advance cursor one character 213 | DW VDU_LF ; &0A LF - Move cursor down one line 214 | DW VDU_VT ; &0B VT - Move cursor up one line 215 | DW VDU_FF ; &0C FF - Clear text area (CLS) 216 | DW VDU_CR ; &0D CR - Move cursor to start of current line 217 | DW VDU_NUL ; &0E SO - Page mode on 218 | DW VDU_NUL ; &0F SI - Page mode off 219 | DW VDU_DLE ; &10 DLE - Clear graphcs area (CLG) 220 | DW VDU_DC1 ; &11 DC1 - Define text colour (COLOUR n) 221 | DW VDU_DC2 ; &12 DC2 - Define graphics colour (GCOL a, n) 222 | DW VDU_DC3 ; &13 DC3 - Define logical colour (COLOUR l, r, g, b) 223 | DW VDU_NUL ; &14 DC4 - Restore logical colours 224 | DW VDU_NUL ; &15 NAK - Disable VDU drivers or delete current line 225 | DW VDU_SYN ; &16 SYN - Select screen mode (MODE n) 226 | DW VDU_ETB ; &17 ETB - Define display character and other commands; used by ON and OFF 227 | DW VDU_NUL ; &18 CAN - Define graphics windows 228 | DW VDU_EM ; &19 EM - PLOT k, x, y (used by MOVE, DRAW, etc) 229 | DW VDU_NUL ; &1A SUB - Restore default windows 230 | DW VDU_NUL ; &1B ESC - Does nothing 231 | DW VDU_NUL ; &1C FS - Define text window 232 | DW VDU_GS ; &1D GS - Define graphics origin (ORIGIN) 233 | DW VDU_RS ; &1E RS - Home 234 | DW VDU_US ; &1F US - Move text cursor to X, Y (PRINT TAB(x,y)); 235 | 236 | ; &00 NUL - Do nothing 237 | ; 238 | VDU_NUL: RET 239 | 240 | ; &08 BS - Backspace 241 | ; 242 | VDU_BS: LD A, (CHARPOS_X) 243 | OR A 244 | JR Z, 1F 245 | DEC A 246 | LD (CHARPOS_X), A 247 | RET 248 | 1: LD A, (CHAR_COLS) 249 | DEC A 250 | LD (CHARPOS_X), A 251 | JR VDU_VT 252 | 253 | 254 | ; &09: HT - Advance to next character 255 | ; 256 | VDU_HT: LD A, (CHAR_COLS) 257 | LD B, A 258 | LD A, (CHARPOS_X) 259 | INC A 260 | LD (CHARPOS_X), A 261 | CP B 262 | RET C 263 | CALL VDU_CR 264 | 265 | ; &0A LF - Linefeed 266 | ; 267 | VDU_LF: LD A, (CHAR_ROWS) 268 | LD B, A 269 | LD A, (CHARPOS_Y) 270 | INC A 271 | LD (CHARPOS_Y), A 272 | CP B 273 | RET C 274 | 1: LD A, B 275 | DEC A 276 | LD (CHARPOS_Y), A 277 | JP NEXT_GRAPHICS.Scroll_Up 278 | 279 | ; &0B VT - Move cursor up one line 280 | ; 281 | VDU_VT: LD A, (CHARPOS_Y) 282 | DEC A 283 | LD (CHARPOS_Y), A 284 | RLCA 285 | RET NC 286 | XOR A 287 | LD (CHARPOS_Y), A 288 | JP NEXT_GRAPHICS.Scroll_Down 289 | 290 | ; &0C FF - CLS 291 | ; 292 | VDU_FF: JP NEXT_GRAPHICS.CLS 293 | 294 | 295 | ; &0D CR - Carriage Return 296 | ; 297 | VDU_CR: XOR A 298 | LD (CHARPOS_X), A 299 | RET 300 | 301 | ; &10 DLE - CLG 302 | ; 303 | VDU_DLE: JP NEXT_GRAPHICS.CLG 304 | 305 | ; &11 DC1 - COLOUR n 306 | ; 307 | VDU_DC1: LD B, 1 ; 1 byte (colour) 308 | LD A, 2 ; State 2: COLOUR 309 | JR VDU_SET_STATE 310 | 311 | ; &12 DC2 - GCOL a, n 312 | ; 313 | VDU_DC2: LD B, 2 ; 2 bytes (mode, colour) 314 | LD A, 3 ; State 3: GCOL 315 | JR VDU_SET_STATE 316 | 317 | ; &12 DC3 - COLOUR a, r, g, b 318 | ; 319 | VDU_DC3: LD B, 4 ; 4 bytes (colour, r, g, b) 320 | LD A, 2 ; State 2: COLOUR 321 | JR VDU_SET_STATE 322 | 323 | ; &16 SYN - MODE n 324 | VDU_SYN: LD B, 1 ; 1 byte (colour) 325 | LD A, 5 ; State 5: MODE 326 | JR VDU_SET_STATE 327 | 328 | ; &17 ETB - Define display character and other commands; used by ON and OFF 329 | ; 330 | VDU_ETB: LD B, 9 ; 9 bytes (char, b0, b1, ..., b7) 331 | LD A, 7 ; State 7: UDG 332 | JR VDU_SET_STATE 333 | 334 | ; &19 EM - PLOT k, x, y 335 | ; 336 | VDU_EM: LD B, 5 ; 5 bytes (mode, xl, xh, yl, yh) 337 | LD A, 1 ; State 1: PLOT 338 | JR VDU_SET_STATE 339 | 340 | ; &1D GS - Graphics Origin 341 | ; 342 | VDU_GS: LD B, 4 ; 4 bytes (OX, OY) 343 | LD A, 6 ; State 6: GORIGIN 344 | JR VDU_SET_STATE 345 | 346 | ; &1E RS - HOME 347 | ; 348 | VDU_RS: XOR A 349 | LD (CHARPOS_X), A 350 | LD (CHARPOS_Y), A 351 | RET 352 | 353 | ; &1F US - PRINT TAB(x,y); 354 | ; 355 | VDU_US: LD B, 2 ; 2 bytes (x, y) 356 | LD A, 4 ; State 4: TAB 357 | JR VDU_SET_STATE 358 | 359 | ; Set up the VDU engine to redirect characters into VDU_BUFFER 360 | ; A: Code for the state (the VDU character that initialised it, i.e. 25 for PLOT 361 | ; B: Number of bytes to read before executing the state, i.e. 5 for PLOT 362 | ; 363 | VDU_SET_STATE: LD (VDU_STATE), A 364 | LD A, B 365 | LD (VDU_COUNT), A 366 | XOR A 367 | LD (VDU_PTR), A 368 | RET 369 | 370 | ; PLOT: VDU 25,mode,x;y; 371 | ; 372 | VDU_EXEC_PLOT: LD HL, (PLOTPOS_X) ; Store the previous plot points 373 | LD (PLOTPRE_X), HL 374 | LD HL, (PLOTPOS_Y) 375 | LD (PLOTPRE_Y), HL 376 | LD A, (VDU_BUFFER + 0) ; Plot style 377 | LD DE, (VDU_BUFFER + 1) ; X 378 | LD HL, (VDU_BUFFER + 3) ; Y 379 | LD (PLOTPOS_X), DE ; Store new plot points 380 | LD (PLOTPOS_Y), HL 381 | JP NEXT_GRAPHICS.Plot 382 | 383 | ; COLOUR: 384 | ; VDU 17,colour 385 | ; VDU 19,colour,r,g,b 386 | ; 387 | VDU_EXEC_COLOUR: LD A, (VDU_PTR) ; Check number of parameters 388 | CP 4 ; If 4, then it is VDU 19,colour,r,g,b 389 | JR Z, 1F 390 | DEC A 391 | RET NZ 392 | LD B, 0 ; If 1, then it is VDU 17,colour 393 | LD C, (IX + 0) 394 | JP NEXT_GRAPHICS.Set_Text_Colour 395 | 1: LD A, (IX + 0) ; Get the palette colour to change 396 | LD B, (IX + 1) ; Get the R component 397 | LD C, (IX + 2) ; Get the G component 398 | LD D, (IX + 3) ; Get the B component 399 | JP NEXT_GRAPHICS.Set_Palette_RGB 400 | 401 | ; GCOL: VDU 18,mode,,colour 402 | ; 403 | VDU_EXEC_GCOL: LD A, (VDU_BUFFER + 0) 404 | LD (PLOT_MODE), A 405 | LD C, (IX + 1) 406 | LD B, 0 407 | JP NEXT_GRAPHICS.Set_Plot_Colour 408 | 409 | ; TAB: VDU 31,x,y 410 | ; 411 | VDU_EXEC_TAB: LD A, (VDU_BUFFER + 0) 412 | LD (CHARPOS_X), A 413 | LD A, (VDU_BUFFER + 1) 414 | LD (CHARPOS_Y), A 415 | RET 416 | 417 | ; MODE: VDU 16,mode 418 | ; 419 | VDU_EXEC_MODE: LD A, (VDU_BUFFER + 0) 420 | JP NEXT_GRAPHICS.Set_Video_Mode 421 | 422 | ; Set graphics origin 423 | ; 424 | VDU_EXEC_GORIGIN: LD HL, (VDU_BUFFER + 0) 425 | LD (PLOTORG_X), HL 426 | LD HL, (VDU_BUFFER + 2) 427 | LD (PLOTORG_Y), HL 428 | RET 429 | 430 | ; Define a UDG 431 | ; 432 | VDU_EXEC_UDG: LD HL, VDU_BUFFER 433 | LD E, (HL) ; Get character code 434 | CALL Get_Character_Data ; Get character data address in DE 435 | CP 0x40 ; Is the character in ROM (A=high byte of address) 436 | RET C ; Yes, so return 437 | INC L ; Copy the 8 bytes of character 438 | LD BC, 8 ; data into RAM 439 | LDIR 440 | RET 441 | 442 | ; Scan the keyboard 443 | ; A modified version of the ZX Spectum 48K rom routine 444 | ; Returns: 445 | ; E: Keycode (in the range 0 to 39), or 0xFF if no key pressed 446 | ; D: Shift code - bit 0: caps, bit 1: symbol 447 | ; 448 | Keyscan: LD L, 0x2F ; The initial key value for each line 449 | LD DE, 0xFFFF ; Initialise DE to no-key 450 | LD BC, 0xFEFE ; C = port address, B = counter 451 | 1: IN A, (C) ; Read bits from keyboard port 452 | CPL 453 | AND 0x1F 454 | JR Z, Keyscan_Done 455 | LD H, A ; Key bits go to the H register 456 | LD A, L ; Fetch initial key value 457 | Keyscan_Multiple: INC D ; If three keys pressed, D will no longer contain FF 458 | RET NZ ; So return at that point 459 | 2: SUB 8 ; Loop until we find a key 460 | SRL H 461 | JR NC, 2B 462 | LD D, E ; Copy any earlier key found to D 463 | LD E, A ; And store the new key value in E 464 | JR NZ, Keyscan_Multiple ; Loop if there are more keys 465 | Keyscan_Done: DEC L ; Line has been scanned, so reduce initial key value for next pass 466 | RLC B ; Shift the counter 467 | JR C, 1B ; And loop if there are still lines to be scanned 468 | INC D ; If D = 0xFF, then single key pressed 469 | RET Z 470 | DEC D 471 | LD A, E ; Symbol shift could be in E as code 0x18 472 | CP 0x18 473 | JR NZ, 3F 474 | LD E, D ; If it is, fetch the keycode from D 475 | LD D, 0x18 ; And set D to symbol shift code 476 | 3: LD A, D ; Get shift key value in D 477 | LD D, 0 ; Reset shift flags 478 | CP 0x27 ; Check for caps shift 479 | JR NZ, 4F ; Skip if not pressed 480 | SET 0, D ; Set caps shift flag 481 | 4: CP 0x18 ; Check for symbol shift 482 | RET NZ ; Skip if not pressed 483 | SET 1, D ; Set symbol shift flag 484 | RET 485 | 486 | KeyTable_Main: DB "B", "H", "Y", "6", "5", "T", "G", "V" 487 | DB "N", "J", "U", "7", "4", "R", "F", "C" 488 | DB "M", "K", "I", "8", "3", "E", "D", "X" 489 | DB $00, "L", "O", "9", "2", "W", "S", "Z" 490 | DB $20, $0D, "P", "0", "1", "Q", "A", $00 491 | 492 | KeyTable_SS_Numeric: DB "_", "!", "@", "#", "$", "%", "&", "'", "(", ")" 493 | KeyTable_SS_Alpha: DB "~", "*", "?", $5C 494 | DB $00, "{", "}", "^" 495 | DB $00, "-", "+", "=" 496 | DB ".", ",", ";", $22 497 | DB $A9, "<", "|", ">" 498 | DB "]", "/", $00, $60 499 | DB "[", ":" 500 | 501 | ENDMODULE 502 | -------------------------------------------------------------------------------- /next_mouse.z80: -------------------------------------------------------------------------------- 1 | ; 2 | ; Title: BBC Basic for Spectrum Next - Kempston Mouse support 3 | ; Authors: Dean Belfield 4 | ; Created: 15/07/2021 5 | ; Last Updated: 15/07/2021 6 | ; 7 | ; Modinfo: 8 | ; 9 | 10 | MODULE NEXT_MOUSE 11 | 12 | Max_X: EQU 1280 13 | Max_Y: EQU 1024 14 | 15 | ; Kempston mouse routine 16 | ; Mouse_Buttons (1 = pressed): 17 | ; Bits 7-4: Mouse wheel counter 18 | ; Bit 2: Middle button 19 | ; Bit 1: Left 20 | ; Bit 0: Right 21 | ; 22 | Read_Buttons: LD BC,0xFADF ; Port for buttons 23 | IN A, (C) 24 | AND %11110111 ; Mask out bit 3 25 | XOR %00000111 ; Invert the mouse buttons for convenience 26 | RET 27 | 28 | Read_X: LD BC, 0xFBDF ; Port for X axis 29 | LD HL, MOUSE_DX 30 | CALL Read_Port 31 | LD HL, (MOUSE_CX) 32 | ADD HL, BC 33 | BIT 7, H 34 | JR Z, 1F 35 | LD HL, 0 36 | JR 2F 37 | 1: LD A, H 38 | SUB high Max_X 39 | JR C, 2F 40 | LD HL, Max_X - 1 41 | 2: LD (MOUSE_CX), HL 42 | RET 43 | 44 | Read_Y: LD BC, 0xFFDF ; Port for Y axis 45 | LD HL, MOUSE_DY 46 | CALL Read_Port 47 | LD HL, (MOUSE_CY) 48 | ADD HL, BC 49 | BIT 7, H 50 | JR Z, 1F 51 | LD HL, 0 52 | JR 2F 53 | 1: LD A, H 54 | SUB high Max_Y 55 | JR C, 2F 56 | LD HL, Max_Y - 1 57 | 2: LD (MOUSE_CY), HL 58 | RET 59 | 60 | ; Read port and get 16-bit signed DX of mouse pointer 61 | ; HL: Pointer to MOUSE_DX or MOUSE_DY 62 | ; BC: Port 63 | ; Returns: 64 | ; BC: Signed mouse velocity 65 | ; 66 | Read_Port: IN A, (C) ; Current mouse X 67 | LD C, (HL) ; Previous mouse X 68 | LD (HL), A ; Store new mouse X 69 | SUB C ; Get difference 70 | LD C, A ; Sign extend to 16 bits 71 | ADD A, A 72 | SBC A 73 | LD B, A 74 | RET 75 | 76 | ENDMODULE -------------------------------------------------------------------------------- /next_rtc.z80: -------------------------------------------------------------------------------- 1 | ; 2 | ; Title: BBC Basic for Spectrum Next - Real Time Clock support 3 | ; Authors: Victor Trucco and Tim Gilberts 4 | ; Link: https://gitlab.com/thesmog358/tbblue/-/blob/master/src/asm/rtc/date.asm 5 | ; Modified By: Dean Belfield 6 | ; Created: 10/05/2021 7 | ; Last Updated: 22/05/2021 8 | ; 9 | ; Notice: Portions of this code to read the RTC module on the Next have 10 | ; been copied from the dot function date.asm with minor changes. 11 | ; Anything above the distribution notice is BBC Basic for 12 | ; Next specific and has been coded by me. 13 | ; 14 | ; Information: The BBC Master TIME$ format is: ddd,dd MMM YYYY.hh:mm:ss 15 | ; For example: Wed,09 Aug 2020.13:51:44 16 | ; 17 | ; Modinfo: 18 | ; 22/05/2021: Minor optimisations 19 | 20 | MODULE NEXT_RTC 21 | 22 | TABLE_DAYS: DB "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" 23 | TABLE_MONTHS: DB "Jan", "Feb", "Mar", "Apr", "May", "Jun" 24 | DB "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" 25 | 26 | ; Read date from RTC 27 | ; Returns: 28 | ; HL: Pointer to end of date string in ACCS, or empty string if no RTC or RTC error 29 | ; L: Implied string length, assuming ACCS is on a page boundary 30 | ; 31 | GET_DATE_STRING: CALL READ_DATE 32 | LD DE, ACCS ; DE = pointer to start of string accumulator 33 | RET C ; There has been an error at this point! 34 | EX DE, HL ; Swap ACCS to HL for convenience 35 | LD DE, TABLE_DAYS 36 | LD A, (RTC_DAY) 37 | CALL LOOKUP_DATE_STR 38 | LD (HL), ',': INC HL 39 | LD A, (RTC_DATE) 40 | CALL BCD_TO_ASC 41 | LD (HL), ' ': INC HL 42 | LD DE, TABLE_MONTHS 43 | LD A, (RTC_MONTH) 44 | CALL LOOKUP_DATE_STR 45 | LD (HL), ' ': INC HL 46 | LD (HL), '2': INC HL 47 | LD (HL), '0': INC HL 48 | LD A, (RTC_YEAR) 49 | CALL BCD_TO_ASC 50 | LD (HL), '.': INC HL 51 | LD A, (RTC_HOUR) 52 | CALL BCD_TO_ASC 53 | LD (HL), ':': INC HL 54 | LD A, (RTC_MIN) 55 | CALL BCD_TO_ASC 56 | LD (HL), ':': INC HL 57 | LD A, (RTC_SEC) 58 | CALL BCD_TO_ASC 59 | EX DE, HL ; Swap ACCS pointer back to DE for output 60 | RET 61 | 62 | ; Copy string from table into ACCS - assumes 3 character lookup for days and months 63 | ; HL: Pointer to ACCS 64 | ; DE: Pointer to table 65 | ; A: Index (from 1) 66 | ; 67 | LOOKUP_DATE_STR: DEC A ; Index from 0 68 | LD C, A 69 | ADD A, A ; * 2 70 | ADD A, C ; * 3 71 | ADD DE, A ; Index into table 72 | LD BC, 3 73 | EX DE, HL 74 | LDIR 75 | EX DE, HL 76 | RET 77 | 78 | ; ---------------------------------------------------------------------------- 79 | ; 80 | ; TBBlue / ZX Spectrum Next project 81 | ; Copyright (c) 2010-2018 82 | ; 83 | ; RTC DATE - Victor Trucco and Tim Gilberts 84 | ; 85 | ; All rights reserved 86 | ; 87 | ; Redistribution and use in source and synthezised forms, with or without 88 | ; modification, are permitted provided that the following conditions are met: 89 | ; 90 | ; Redistributions of source code must retain the above copyright notice, 91 | ; this list of conditions and the following disclaimer. 92 | ; 93 | ; Redistributions in synthesized form must reproduce the above copyright 94 | ; notice, this list of conditions and the following disclaimer in the 95 | ; documentation and/or other materials provided with the distribution. 96 | ; 97 | ; Neither the name of the author nor the names of other contributors may 98 | ; be used to endorse or promote products derived from this software without 99 | ; specific prior written permission. 100 | ; 101 | ; THIS CODE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 102 | ; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 103 | ; THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 104 | ; PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE 105 | ; LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 106 | ; CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 107 | ; SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 108 | ; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 109 | ; CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 110 | ; ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 111 | ; POSSIBILITY OF SUCH DAMAGE. 112 | ; 113 | ; You are responsible for any legal issues arising from your use of this code. 114 | ; 115 | 116 | PORT: EQU 0x3B 117 | PORT_CLOCK: EQU 0x10 ; 0x103B 118 | PORT_DATA: EQU 0x11 ; 0x113B 119 | 120 | ; Read a date into RTC_SIG 121 | ; Returns: 122 | ; F: C set if error, clear if date read okay 123 | ; 124 | READ_DATE: CALL START_SEQUENCE 125 | LD L, 0xD0 126 | CALL SEND_DATA 127 | LD L, 0x3E 128 | CALL SEND_DATA 129 | CALL START_SEQUENCE 130 | LD L, 0xD1 131 | CALL SEND_DATA 132 | LD HL, RTC_SIG 133 | LD E, 9 134 | 1: CALL READ 135 | INC HL 136 | DEC E 137 | JR Z, 2F 138 | CALL SEND_ACK 139 | JR 1B 140 | 2: CALL SEND_NACK 141 | CALL SDA0 142 | CALL SCL1 143 | CALL SDA1 144 | OR A ; Clear Carry 145 | LD HL, (RTC_SIG) 146 | LD DE, 585Ah ; Signature bytes must contain 'ZX' 147 | SBC HL, DE 148 | RET Z ; Carry flag clear if OK 149 | SCF ; Carry flag set if error 150 | RET 151 | 152 | SEND_DATA: LD H, 8 ; # of bits 153 | SEND_DATA_LOOP: RLC L ; Next bit 154 | LD A, L 155 | CALL SDA 156 | CALL PULSE_CLOCK 157 | DEC H 158 | JR NZ, SEND_DATA_LOOP 159 | 160 | WAIT_ACK: CALL SDA1 ; Free the line to wait for the ACK 161 | JR PULSE_CLOCK 162 | 163 | READ: CALL SDA1 ; Free the data line 164 | LD D, 8 ; Let's read 8 bits 165 | READ_LOOP: RLC (HL) ; Next bit 166 | CALL SCL1 ; Clock is high 167 | LD B, PORT_DATA ; Read the bit 168 | IN A, (C) 169 | ; 170 | ; AND 1 ; Is it 1?? 171 | ; JR NZ, SET_BIT 172 | RRCA ; DB: Optimisation 173 | JR C, SET_BIT 174 | ; 175 | RES 0, (HL) 176 | JR END_SET 177 | 178 | SET_BIT: SET 0, (HL) 179 | 180 | END_SET: CALL SCL0 ; Clock is low 181 | DEC D 182 | JR NZ, READ_LOOP ; Go to next bit 183 | RET ; Finish the byte read 184 | 185 | SEND_NACK: LD A, 1 186 | JR SEND_ACK_NACK 187 | 188 | SEND_ACK: XOR A 189 | SEND_ACK_NACK: CALL SDA 190 | call PULSE_CLOCK 191 | JR SDA1 ; Free the data line 192 | 193 | START_SEQUENCE: LD C, PORT 194 | ; 195 | ; LD A, 1 ;High in both i2c pins, before begin 196 | ; CALL SCL 197 | CALL SCL1 ; DB: Optimisation 198 | ; 199 | CALL SDA 200 | CALL SDA0 ; High to low when clock is high 201 | JR SCL ; Low the clock to start sending data 202 | 203 | SDA0: XOR A 204 | JR SDA 205 | 206 | SDA1: LD A, 1 207 | SDA: LD B, PORT_DATA 208 | OUT (C), A 209 | RET 210 | 211 | PULSE_CLOCK: CALL SCL1 212 | SCL0: XOR A 213 | JR SCL 214 | SCL1: LD A, 1 215 | SCL: LD B, PORT_CLOCK 216 | OUT (C), A 217 | RET 218 | 219 | ENDMODULE -------------------------------------------------------------------------------- /next_sound.z80: -------------------------------------------------------------------------------- 1 | ; 2 | ; Title: BBC Basic Interpreter - Z80 version 3 | ; Spectrum Next Sound Routines 4 | ; Author: Dean Belfield 5 | ; Created: 28/05/2021 6 | ; Last Updated: 06/06/2021 7 | ; 8 | ; Notes: 9 | 10 | ; Split over 5 complete octaves, with 53 being middle C 11 | ; * C4: 262hz 12 | ; + A4: 440hz 13 | ; 14 | ; 2 3 4 5 6 7 8 15 | ; 16 | ; B 1 49 97 145 193 241 17 | ; A# 0 45 93 141 189 237 18 | ; A 41 89+ 137 185 233 19 | ; G# 37 85 133 181 229 20 | ; G 33 81 129 177 225 21 | ; F# 29 77 125 173 221 22 | ; F 25 73 121 169 217 23 | ; E 21 69 117 165 213 24 | ; D# 17 65 113 161 209 25 | ; D 13 61 109 157 205 253 26 | ; C# 9 57 105 153 201 249 27 | ; C 5 53* 101 149 197 245 28 | ; 29 | ; Modinfo: 30 | ; 06/06/2021: Added LUA script to create note table 31 | ; 08/06/2021: Queue_Note now uses LTRAP to test for ESC 32 | 33 | MODULE NEXT_SOUND 34 | 35 | Note_Table: LUA ALLPASS 36 | for i = 0, 255 do 37 | f = 440*(2^((i-89)/48)) 38 | v = 1773500 / (16 * f) 39 | sj.add_word(math.floor(v+0.5)) 40 | end 41 | ENDLUA 42 | 43 | Initialise: LD B, 0x07 ; Mixer 44 | LD C, %00111000 45 | CALL Write_AY_Port 46 | LD B, 0x08 ; CH A: Volume 47 | LD C, 0 48 | CALL Write_AY_Port 49 | LD B, 0x09 ; CH B: Volume 50 | LD C, 0 51 | CALL Write_AY_Port 52 | LD B, 0x0A ; CH C: Volume 53 | LD C, 0 54 | CALL Write_AY_Port 55 | RET 56 | 57 | ; Interrupt routine 58 | ; IX: Address of AY block 59 | ; +0: @AY_CNT: 60 | ; +1: @AY_PRD: 61 | ; +2: @AY_PWR: 62 | ; +3: @AY_LEN: 63 | ; 64 | Play_Queue LD IX, AY_CNT_A: LD HL, AY_BUF_A: LD D, 0: CALL Play_Queue_1 65 | LD IX, AY_CNT_B: LD HL, AY_BUF_B: LD D, 1: CALL Play_Queue_1 66 | LD IX, AY_CNT_C: LD HL, AY_BUF_C: LD D, 2 67 | ; 68 | Play_Queue_1: LD A, (IX + 0) ; Is counter 0? 69 | OR A 70 | JR Z, 1F ; Yes, so do nothing 71 | DEC A ; Decrement the counter 72 | LD (IX + 0), A 73 | RET NZ 74 | ; 75 | 1: LD A, (IX + 3) ; Length 76 | OR A 77 | JR NZ, 2F ; Is there something to play? 78 | XOR A ; No, so silence the channel 79 | LD E, A ; by resetting the volume 80 | JR Play_Note 81 | ; 82 | 2: DEC (IX + 3) 83 | LD A, (IX + 1) ; Read pointer 84 | ADD HL, A ; HL: Address to store data in 85 | ADD A, 3 ; Advance the pointer 86 | CP 15 87 | JR C, 3F 88 | SUB 15 89 | 3: LD (IX + 1), A ; And store 90 | ; 91 | LD A, (HL) ; Duration 92 | INC HL 93 | LD E, (HL) ; Volume 94 | INC HL 95 | LD (IX + 0), A ; Set countdown 96 | LD A, (HL) ; Pitch 97 | JR Play_Note ; Trigger note 98 | 99 | ; Queue a sound in the sound buffer 100 | ; HL: Channel / Control 101 | ; D: Pitch 102 | ; E: Duration 103 | ; C: Volume 104 | ; 105 | Queue_Note: LD A, L ; Channel number 106 | ADD A, A ; x2 107 | ADD A, A ; x4 108 | ADD A, low @AY_CNT_A ; Index into channel data 109 | LD IXL, A 110 | LD IXH, high @AY_CNT_A ; IX: Pointer to channel data 111 | ; 112 | 0: LD A, (IX + 3) ; Check length 113 | CP 5 ; Max 5 items in FIFO queue 114 | JR C, 1F 115 | HALT 116 | CALL LTRAP ; Check for ESC 117 | JR 0B ; And loop 118 | ; 119 | 1: INC (IX + 3) ; Increment length 120 | LD A, L ; Channel number 121 | CALL Get_Channel_Buffer ; HL: Channel FIFO buffer 122 | LD A, (IX + 2) ; Write pointer 123 | ADD HL, A ; HL: Address to store data in 124 | ADD A, 3 ; Advance the pointer 125 | CP 15 126 | JR C, 2F 127 | SUB 15 128 | 2: LD (IX + 2), A ; And store 129 | ; 130 | LD (HL), E ; Duration 131 | INC HL 132 | LD (HL), C ; Volume 133 | INC HL 134 | LD (HL), D ; Pitch 135 | RET 136 | 137 | ; Queue Buffers 138 | ; A: Channel 139 | ; Returns; 140 | ; HL: Channel FIFO buffer address 141 | ; 142 | Get_Channel_Buffer: LD HL, Get_Channel_Buffer_LT 143 | ADD A, A 144 | ADD HL, A 145 | LD A, (HL) 146 | INC HL 147 | LD H, (HL) 148 | LD L, A 149 | RET 150 | Get_Channel_Buffer_LT: DEFW AY_BUF_A, AY_BUF_B, AY_BUF_C 151 | 152 | ; Play a note 153 | ; A: Pitch 154 | ; D: Channel 155 | ; E: Volume 156 | ; 157 | Play_Note: LD BC, Note_Table ; Get pitch from Note Table 158 | LD H, 0 159 | LD L, A 160 | ADD HL, HL 161 | ADD HL, BC 162 | LD A, (HL) 163 | INC HL 164 | LD H, (HL) 165 | LD L, A 166 | LD A, D ; Channel 167 | ADD A, A 168 | LD B, A ; Pitch (low byte) 169 | LD C, L 170 | EX AF, AF 171 | CALL Write_AY_Port 172 | EX AF, AF 173 | INC A 174 | LD B, A 175 | LD C, H 176 | CALL Write_AY_Port 177 | LD A, D ; Volume 178 | ADD A, 8 179 | LD B, A 180 | LD C, E 181 | CALL Write_AY_Port 182 | RET 183 | 184 | ; Write to AY port 185 | ; B: Register number 186 | ; C: Value 187 | ; 188 | Write_AY_Port: PUSH BC 189 | Z80PORT 0xFFFD, B 190 | POP BC 191 | Z80PORT 0xBFFD, C 192 | RET 193 | 194 | ENDMODULE -------------------------------------------------------------------------------- /next_sprites.z80: -------------------------------------------------------------------------------- 1 | ; 2 | ; Title: BBC Basic Interpreter - Z80 version 3 | ; Spectrum Next Sprite Routines 4 | ; Author: Dean Belfield 5 | ; Created: 07/06/2021 6 | ; Last Updated: 07/06/2021 7 | ; 8 | ; Modinfo: 9 | 10 | MODULE NEXT_SPRITES 11 | 12 | ; A: Sprite number 13 | ; DE: X coordinate 14 | ; HL: Y coordinate 15 | ; C: Pattern number 16 | ; 17 | Render: NEXTREG 0x34, A ; The sprite number 18 | LD A, E 19 | NEXTREG 0x35, A ; Sprite X coordinate (LSB) 20 | LD A, L 21 | NEXTREG 0x36, A ; Sprite Y coordinate (LSB) 22 | LD A, D 23 | AND 1 24 | NEXTREG 0x37, A ; Sprite X coordinate (MSB) 25 | LD A, C 26 | OR %11000000 27 | NEXTREG 0x38, A ; Visible, Extended, Pattern 28 | LD A, H 29 | AND 1 30 | NEXTREG 0x39, A ; Sprite Y coordinate (MSB) 31 | RET 32 | 33 | ENDMODULE -------------------------------------------------------------------------------- /patch.z80: -------------------------------------------------------------------------------- 1 | ; 2 | ; Title: BBC Basic Interpreter - Z80 version 3 | ; Patch file for Spectrum Next 4 | ; Author: Dean Belfield 5 | ; Created: 02/05/2021 6 | ; Last Updated: 14/07/2021 7 | ; 8 | ; Modinfo: 9 | ; 09/05/2021: Fixed plot mode and bug in COMDS table 10 | ; 10/05/2021: Added RTC TIME$ and *TIME, moved some code into misc.z80, and changes due to VDU support 11 | ; 15/05/2021: References to ASC_TO_HEX changed to ASC_TO_NUMBER in STAR commands; Updates for MODE command 12 | ; 17/05/2021: Fixed bug in OSLINE; now returns 0; Added cursor to OSLINE; Added *EDIT; Tweaks for COLOUR, GCOL 13 | ; 18/05/2021: Moved editor code into editor.z80 14 | ; 20/05/2021: Fixed bugs in MOVE and PLOT 15 | ; 22/05/2021: Fixed bugs in DRAW and OSKEY; Minor optimisations 16 | ; 23/05/2021: Implemented *. and *CD 17 | ; 24/05/2021: Implemented OSLOAD and OSSAVE 18 | ; 25/05/2021: Implemented more file IO commands 19 | ; 29/05/2021: Bug fixes; Implemented *BYE 20 | ; 04/06/2021: Added SOUND 21 | ; 08/06/2021: Tweaked OSLINE EQU to reflect new module name 22 | ; 15/06/2021: Plot, Draw, Move and Line now call Transform_Coords 23 | ; 05/07/2021: Added OPT, OSOPEN, OSSHUT, OSBGET, OSBPUT, OSSTAT, GETPTR and PUTPTR 24 | ; 10/07/2021: Fixed bug in PUTCSR and optimised PUTSCR and GETCSR; Modified GET_PORT and PUT 25 | ; 14/07/2021: Implemented ADVAL, OSCALL and OSBYTE; Some KEY variables renamed 26 | 27 | MODULE PATCH 28 | 29 | @GETIMS: EQU NEXT_RTC.GET_DATE_STRING ; Get the time string from the real-time clock module 30 | @OSWRCH: EQU NEXT_IO.Print_Char ; Write a character out 31 | @OSLINE EQU EDITOR.Edit_Line ; Line editor 32 | 33 | ; MODE n: Set video mode 34 | ; 35 | @MODE: CALL EXPRI 36 | EXX 37 | LD A, L 38 | CALL NEXT_GRAPHICS.Set_Video_Mode 39 | JP XEQ 40 | 41 | ; CLG: clear the graphics screen 42 | ; 43 | @CLG: LD A, 0x10 44 | CALL OSWRCH 45 | JP XEQ 46 | 47 | ; CLRSCN: clears the screen. 48 | ; 49 | @CLRSCN: LD A, 0x0C 50 | JP OSWRCH 51 | 52 | ; PUTIME: set current time to DE:HL, in centiseconds. 53 | ; 54 | @PUTIME: LD (TIME + 2), DE 55 | LD (TIME + 0), HL 56 | RET 57 | 58 | ; GETIME: return current time in DE:HL, in centiseconds. 59 | ; 60 | @GETIME: LD DE, (TIME + 2) 61 | LD HL, (TIME + 0) 62 | RET 63 | 64 | ; PUTCSR: move to cursor to x=DE, y=HL 65 | ; 66 | @PUTCSR: LD D, L ; E: X, D: Y 67 | LD (CHARPOS_X), DE 68 | RET 69 | 70 | ; GETCSR: return cursor position in x=DE, y=HL 71 | ; 72 | @GETCSR: LD DE, (CHARPOS_X) ; E: X, D: Y 73 | LD L, D 74 | LD H, 0 ; HL: Y 75 | LD D, H ; DE: X 76 | RET 77 | 78 | ; Read character from keyboard (blocking) 79 | ; 80 | @OSRDCH: LD A, (KEY_CODE) ; Read keyboard 81 | OR A 82 | JR Z, OSRDCH ; Loop until key is pressed 83 | PUSH AF 84 | 1: LD A, (KEY_CODE) ; And same again 85 | OR A 86 | JR NZ, 1B ; But loop until key is released 87 | POP AF ; Return the keycode 88 | RET 89 | 90 | ; PROMPT: output the input prompt 91 | ; 92 | @PROMPT: LD A,'>' 93 | JP OSWRCH 94 | 95 | ;OSKEY - Read key with time-limit, test for ESCape. 96 | ;Main function is carried out in user patch. 97 | ; Inputs: HL = time limit (centiseconds) 98 | ; Outputs: Carry reset if time-out 99 | ; If carry set A = character 100 | ; Destroys: A,H,L,F 101 | ; 102 | @OSKEY: LD A, (KEY_CODE) ; Read keyboard 103 | OR A ; If we have a character 104 | JR NZ, 1F ; Then process it 105 | LD A,H ; Check if HL is 0 (this is passed by INKEY() function 106 | OR L 107 | RET Z ; If it is then ret 108 | HALT ; Bit of a bodge so this is timed in ms 109 | DEC HL ; Decrement the counter and 110 | JR @OSKEY ; loop 111 | 1: CP 0x1B ; If we are not pressing ESC, 112 | SCF ; then flag we've got a character 113 | RET NZ 114 | ; 115 | ESCSET: PUSH HL 116 | LD HL,FLAGS 117 | BIT 6,(HL) ; ESC DISABLED? 118 | JR NZ,ESCDIS 119 | SET 7,(HL) ; SET ESCAPE FLAG 120 | ESCDIS: POP HL 121 | RET 122 | ; 123 | ESCTEST: LD A, (KEY_CODE) 124 | CP 0x1B ; ESC 125 | JR Z,ESCSET 126 | RET 127 | ; 128 | @TRAP: CALL ESCTEST 129 | @LTRAP: LD A,(FLAGS) 130 | OR A 131 | RET P 132 | LD HL,FLAGS 133 | RES 7,(HL) 134 | JP ESCAPE 135 | 136 | ;OSINIT - Initialise RAM mapping etc. 137 | ;If BASIC is entered by BBCBASIC FILENAME then file 138 | ;FILENAME.BBC is automatically CHAINed. 139 | ; Outputs: DE = initial value of HIMEM (top of RAM) 140 | ; HL = initial value of PAGE (user program) 141 | ; Z-flag reset indicates AUTO-RUN. 142 | ; Destroys: A,D,E,H,L,F 143 | ; 144 | @OSINIT: XOR A 145 | CALL NEXT_INIT.Reserve_UDG ; Reserve RAM for UDG; returns DE = RAMTOP 146 | LD HL, @USER 147 | XOR A 148 | LD (@FLAGS), A ; Clear flags and set F = Z 149 | RET 150 | 151 | ;OSCALL - Intercept page &FF calls and provide an alternative address 152 | ; 153 | ;&FFF7: OSCLI Execute *command. 154 | ;&FFF4: OSBYTE Various byte-wide functions. 155 | ;&FFF1: OSWORD Various control block functions. 156 | ;&FFEE: OSWRCH Write character to output stream. 157 | ;&FFE7: OSNEWL Write NewLine to output stream. 158 | ;&FFE3: OSASCI Write character or NewLine to output stream. 159 | ;&FFE0: OSRDCH Wait for character from input stream. 160 | ;&FFDD: OSFILE Perform actions on whole files or directories. 161 | ;&FFDA: OSARGS Read and write information on open files or filing systems. 162 | ;&FFD7: OSBGET Read a byte from an a channel. 163 | ;&FFD4: OSBPUT Write a byte to a channel. 164 | ;&FFD1: OSGBPB Read and write blocks of data. 165 | ;&FFCE: OSFIND Open or close a file. 166 | ; 167 | @OSCALL: LD HL, OSCALL_TABLE 168 | 1: LD A, (HL) 169 | INC HL 170 | CP 0xFF 171 | RET Z 172 | CP IYL 173 | JR Z, 2F 174 | RET NC 175 | INC HL 176 | INC HL 177 | JR 1B 178 | 2: LD A, (HL) 179 | LD IYL, A 180 | INC HL 181 | LD A, (HL) 182 | LD IYH, A 183 | RET 184 | @OSCALL_TABLE: DB 0xD4: DW OSBPUT 185 | DB 0xD7: DW OSBGET 186 | DB 0xEE: DW OSWRCH 187 | DB 0xF4: DW OSBYTE 188 | DB 0xFF 189 | 190 | ;OSCLI - Process an "operating system" command 191 | ; 192 | @OSCLI: CALL SKIPSP 193 | CP CR 194 | RET Z 195 | CP '|' 196 | RET Z 197 | CP '.' 198 | JP Z,STAR_DOT ; *. 199 | EX DE,HL 200 | LD HL,COMDS 201 | OSCLI0: LD A,(DE) 202 | CALL UPPRC 203 | CP (HL) 204 | JR Z,OSCLI2 205 | JR C,HUH 206 | OSCLI1: BIT 7,(HL) 207 | INC HL 208 | JR Z,OSCLI1 209 | INC HL 210 | INC HL 211 | JR OSCLI0 212 | ; 213 | OSCLI2: PUSH DE 214 | OSCLI3: INC DE 215 | INC HL 216 | LD A,(DE) 217 | CALL UPPRC 218 | CP '.' ; ABBREVIATED? 219 | JR Z,OSCLI4 220 | XOR (HL) 221 | JR Z,OSCLI3 222 | CP 80H 223 | JR Z,OSCLI4 224 | POP DE 225 | JR OSCLI1 226 | ; 227 | OSCLI4: POP AF 228 | INC DE 229 | OSCLI5: BIT 7,(HL) 230 | INC HL 231 | JR Z,OSCLI5 232 | LD A,(HL) 233 | INC HL 234 | LD H,(HL) 235 | LD L,A 236 | PUSH HL 237 | EX DE,HL 238 | JP SKIPSP 239 | 240 | HUH: LD A,254 241 | CALL EXTERR 242 | DEFM 'Bad command' 243 | DEFB 0 244 | 245 | ; ---------------------------------------------------------------------------- 246 | 247 | ; OSCLI STAR commands 248 | 249 | ; Each command has bit 7 of the last character set, and is followed by the address of the handler 250 | ; It looks like these need to be in alphabetical order 251 | ; 252 | COMDS: DC 'BYE': DEFW STAR_BYE ; Soft reset 253 | DC 'CAT': DEFW STAR_DOT ; Catalogue SD Card 254 | DC 'CD': DEFW STAR_CD ; Change directory 255 | DC 'DELETE': DEFW STAR_DELETE ; Delete a file 256 | DC 'DIR': DEFW STAR_CD ; Alias for CD 257 | DC 'DRIVE': DEFW STAR_DRIVE ; Change drive 258 | DC 'ERASE': DEFW STAR_DELETE ; Alias for DELETE 259 | DC 'FX': DEFW STAR_FX ; FX commands 260 | DC 'LOAD': DEFW STAR_LOAD ; Load memory block 261 | DC 'MEMDUMP': DEFW STAR_MEMDUMP ; Memory hex dump 262 | DC 'MKDIR': DEFW STAR_MKDIR ; Make directory 263 | DC 'OPT': DEFW STAR_OPT ; 264 | DC 'RMDIR': DEFW STAR_RMDIR ; Remove directory 265 | DC 'SAVE': DEFW STAR_SAVE ; Save memory block 266 | DC 'TEST': DEFW STAR_TEST ; Test code call for debugging new functions 267 | DC 'TIME': DEFW STAR_TIME ; RTC time 268 | DC 'TURBO': DEFW STAR_TURBO ; CPU speed 269 | DB 0xFF 270 | 271 | ; OSCLI - BYE 272 | ; 273 | STAR_BYE: NEXTREG 0x02, 1 ; Soft reset 274 | JR $ 275 | 276 | 277 | ; OSCLI - CAT / *. 278 | ; 279 | STAR_DOT: PUSH IY 280 | LD A, (FDRIVE) 281 | CALL NEXT_DOS.LS 282 | POP IY 283 | RET 284 | 285 | ; OSCLI - CD path 286 | ; 287 | STAR_CD: LD DE, NEXT_DOS.CD 288 | STAR_CD_1: CALL SKIPSP 289 | PUSH HL 290 | CALL CRTONULL 291 | EXREG HL, IX 292 | LD A, (FDRIVE) 293 | EX DE, HL 294 | CALLREG HL 295 | POP HL 296 | JP NULLTOCR 297 | 298 | ; OSCLI - DELETE path 299 | ; 300 | STAR_DELETE: LD DE, NEXT_DOS.Delete 301 | JR STAR_CD_1 302 | 303 | ; OSCLI - MKDIR path 304 | ; 305 | STAR_MKDIR: LD DE, NEXT_DOS.MKDIR 306 | JR STAR_CD_1 307 | 308 | ; OSCLI - RMDIR path 309 | ; 310 | STAR_RMDIR: LD DE, NEXT_DOS.RMDIR 311 | JR STAR_CD_1 312 | 313 | ; OSCLI - DRIVE d 314 | ; 315 | STAR_DRIVE: CALL SKIPSP 316 | LD A, (HL) 317 | CP CR 318 | RET Z 319 | JP NEXT_DOS.DRIVE 320 | 321 | ; OSCLI FX n 322 | ; 323 | STAR_FX: CALL ASC_TO_NUMBER ; C: FX # 324 | LD C, E 325 | CALL ASC_TO_NUMBER ; B: First parameter 326 | LD B, E 327 | CALL ASC_TO_NUMBER ; E: Second parameter 328 | LD L, B ; L: First parameter 329 | LD H, E ; H: Second parameter 330 | LD A, C ; A: FX #, and fall through to OSBYTE 331 | ; 332 | ; OSBYTE 333 | ; A: FX # 334 | ; L: First parameter 335 | ; H: Second parameter 336 | ; 337 | OSBYTE: CP 0x00 338 | JR Z, OSBYTE_00 339 | CP 0x0B 340 | JR Z, OSBYTE_0B 341 | CP 0x0C 342 | JR Z, OSBYTE_0C 343 | CP 0x13 344 | JR Z, OSBYTE_13 345 | CP 0x14 346 | JR Z, OSBYTE_14 347 | CP 0x80 348 | JR Z, OSBYTE_80 349 | JP HUH 350 | 351 | ; OSBYTE 0x00 (FX 0): Get OS version 352 | ; 353 | OSBYTE_00: LD L, CONF_OSID ; ZX Spectrum Next OS code 354 | JP EVAL.COUNT0 355 | 356 | ; OSBYTE 0x0B (FX 11) Set keyboard auto-repeat delay 357 | ; 358 | OSBYTE_0B: LD DE, KEY_DELAY 359 | JR OSBYTE_0C_1 360 | 361 | ; OSBYTE 0x0C (FX 12) Set keyboard auto-repeat period 362 | ; 363 | OSBYTE_0C: LD DE, KEY_REPEAT 364 | OSBYTE_0C_1: EX DE, HL ; HL: Pointer to KEY_REPEAT or KEY_DELAY; E: New value 365 | LD D, (HL) ; D: Old value 366 | LD (HL), E ; Store new value 367 | LD L, D ; Return old value 368 | JP EVAL.COUNT0 369 | 370 | ; OSBYTE 0x13 (FX 19): Wait 1/50th of a second 371 | ; 372 | OSBYTE_13: HALT 373 | LD L, 0 374 | JP EVAL.COUNT0 375 | 376 | ; OSBYTE 0x14 (FX 20,n): Explode/implode user defined character font RAM 377 | ; L: n 378 | ; 379 | OSBYTE_14: LD A, L 380 | CP 7 381 | JP NC, HUH 382 | CALL NEXT_INIT.Reserve_UDG 383 | LD (HIMEM), DE 384 | LD L, 0xFF 385 | JP EVAL.COUNT0 386 | 387 | ; OSBYTE 0x80 (FX 80, device) 388 | ; ADVAL(device) 389 | ; 390 | @ADVAL: INC IY ; Skip '(' 391 | CALL EXPRI 392 | EXX 393 | CALL BRAKET 394 | ; 395 | OSBYTE_80: LD DE, EVAL.COUNT1 ; Return address 396 | PUSH DE 397 | LD A, L 398 | SUB 5 399 | JR C, 1F 400 | CP 5 401 | JR C, 2F 402 | 1: LD HL, 0 403 | RET 404 | 2: CALL SWITCH_A 405 | DW ADVAL_MOUSE_MAX_X ; ADVAL(5) 406 | DW ADVAL_MOUSE_MAX_Y ; ADVAL(6) 407 | DW ADVAL_MOUSE_X ; ADVAL(7) 408 | DW ADVAL_MOUSE_Y ; ADVAL(8) 409 | DW ADVAL_MOUSE_CLICK ; ADVAL(9) 410 | ; 411 | ADVAL_MOUSE_MAX_X: LD HL, NEXT_MOUSE.Max_X 412 | RET 413 | ; 414 | ADVAL_MOUSE_MAX_Y: LD HL, NEXT_MOUSE.Max_Y 415 | RET 416 | ; 417 | ADVAL_MOUSE_X: EQU NEXT_MOUSE.Read_X 418 | ADVAL_MOUSE_Y: EQU NEXT_MOUSE.Read_Y 419 | ; 420 | ADVAL_MOUSE_CLICK: CALL NEXT_MOUSE.Read_Buttons 421 | LD H, 0 422 | LD L, A 423 | RET 424 | 425 | ; OSCLI MEMDUMP addr, count 426 | ; 427 | STAR_MEMDUMP CALL ASC_TO_NUMBER ; Get start address 428 | PUSH DE 429 | CALL ASC_TO_NUMBER ; Get length in DE 430 | POP HL ; Get start address in HL 431 | JP NEXT_DEBUG.Memory_Dump 432 | 433 | ; OSCLI TEST 434 | ; Stick code to test here 435 | ; 436 | STAR_TEST: JP HUH 437 | 438 | ; OSCLI TIME 439 | ; Output current time 440 | ; 441 | STAR_TIME: CALL GETIMS 442 | EX DE, HL 443 | LD (HL), LF 444 | INC HL 445 | LD (HL), CR 446 | INC HL 447 | LD (HL), 0 448 | LD HL, ACCS 449 | JP MAIN.TEXT 450 | 451 | ; OSCLI TURBO n 452 | ; Set CPU Speed: 0 = 3.5Mhz, 1 = 7Mhz, 2 = 14Mhz, 3 = 28Mhz 453 | ; 454 | STAR_TURBO: CALL ASC_TO_NUMBER 455 | LD A, E 456 | AND 3 457 | LD (CPU_SPEED), A 458 | NEXTREG 0x07, A 459 | RET 460 | 461 | ; OSCLI LOAD file addr 462 | ; 463 | STAR_LOAD: CALL SKIPSP ; First parameter is a string 464 | PUSH HL ; Stack the string pointer 465 | CALL SKIPNOTSP ; Skip to the next parameter 466 | CALL ASC_TO_NUMBER ; DE: Address 467 | POP HL ; HL: Pointer to Filename 468 | CALL SPTONULL ; Convert to null terminated string 469 | PUSH HL 470 | EXREG HL, IX 471 | LD BC, -1 ; Maximum number of bytes 472 | LD A, (FDRIVE) 473 | CALL NEXT_DOS.Load 474 | POP HL 475 | RET 476 | 477 | ; OSCLI SAVE file addr len 478 | ; 479 | STAR_SAVE: CALL SKIPSP ; First parameter is a string 480 | PUSH HL ; Stack the string pointer 481 | CALL SKIPNOTSP ; Skip to the next parameter 482 | CALL ASC_TO_NUMBER ; Read address 483 | PUSH DE 484 | CALL ASC_TO_NUMBER ; Read length 485 | EXREG DE, BC ; BC: Length 486 | POP DE ; DE: Start address 487 | POP HL ; HL: Pointer to Filename 488 | CALL SPTONULL ; Convert to null terminated string 489 | PUSH HL 490 | EXREG HL, IX 491 | LD A, (FDRIVE) 492 | CALL NEXT_DOS.Save 493 | POP HL 494 | RET 495 | 496 | ; OSCLI OPT n 497 | ; 498 | STAR_OPT: CALL ASC_TO_NUMBER 499 | LD A, E 500 | AND 3 501 | SETOPT: LD (OPTVAL), A 502 | RET 503 | ; 504 | @RESET: XOR A 505 | JR SETOPT 506 | 507 | ; ---------------------------------------------------------------------------- 508 | 509 | ; PUT port,data 510 | ; Moved from exec.z80 511 | ; To write Nextreg port, OR port with &10000 512 | ; 513 | @PUT: CALL EXPRI ; Port address 514 | LD A, L ; L is the high word of the port address; check for 1 515 | EXX 516 | PUSH AF 517 | PUSH HL 518 | CALL COMMA 519 | CALL EXPRI ; Data 520 | EXX 521 | POP BC 522 | POP AF 523 | CP 0 524 | JR Z, 1F ; It's a Z80 port 525 | Z80PORT 0x243B, C ; Select Nextreg port 526 | INC B 527 | 1: OUT (C),L ; Output to Z80 port 528 | JP XEQ 529 | 530 | ; GET(port) - Read Z80/Nextreg port 531 | ; GET(x, y) - Read character from screen position (x, y) 532 | ; Called from GET in eval.z80 533 | ; To read Nextreg port, OR port with &10000 534 | ; 535 | @GET_PORT: INC IY ; Skip '(' 536 | CALL EXPRI ; PORT ADDRESS 537 | LD A, L ; L is the high word of the port address; check for 1 538 | EXX 539 | PUSH AF 540 | PUSH HL 541 | CALL NXT 542 | CP "," 543 | JR NZ, 1F 544 | ; 545 | ; Get second parameter 546 | ; 547 | CALL COMMA 548 | CALL EXPRI 549 | EXX 550 | POP DE ; DE: X coordinate 551 | POP AF ; AF: Not used 552 | LD H, L ; H: Y coordinate 553 | LD L, E ; L: X coordinate 554 | CALL NEXT_IO.Get_Charpos_1 555 | CALL NEXT_GRAPHICS.Get_Char 556 | LD L, A ; Character code, or 0xFF if no match 557 | JR C, 3F ; We have a character 558 | CALL BRAKET ; Check for second bracket 559 | JP EVAL.TRUE ; Return -1 560 | ; 561 | ; Read port 562 | ; 563 | 1: POP BC ; Port # in BC 564 | POP AF 565 | CP 0 566 | JR Z, 2F ; It's a Z80 port 567 | Z80PORT 0x243B, C ; Select Nextreg port 568 | INC B 569 | 2: IN L, (C) ; Read the value 570 | 3: CALL BRAKET 571 | JP EVAL.COUNT0 572 | 573 | ; GET$(x, y) - Read character from screen position (x, y) 574 | ; 575 | @GET_CHAR: INC IY 576 | CALL EXPRI ;Get X coordinate 577 | EXX 578 | PUSH HL 579 | CALL COMMA 580 | CALL EXPRI ;Get Y coordinate 581 | EXX 582 | POP DE ;DE: X coordinate 583 | LD H, L ;H: Y coordinate 584 | LD L, E ;L: X coordinate 585 | CALL NEXT_IO.Get_Charpos_1 586 | CALL NEXT_GRAPHICS.Get_Char 587 | EX AF, AF 588 | CALL BRAKET 589 | EX AF, AF 590 | JP EVAL.INKEY1 591 | 592 | ; ---------------------------------------------------------------------------- 593 | 594 | ; COLOUR col[,type] 595 | ; Set the text colour 596 | ; col: 0-127 (foreground), 128-255 (backround) 597 | ; type: 0: BBC spec (default) 598 | ; 1: foreground / ULA ink 599 | ; 2: background / ULA paper 600 | ; 3: border 601 | ; 4: ULA bright 602 | ; 5: ULA flash 603 | ; 604 | @COLOUR: CALL EXPRI 605 | EXX 606 | PUSH HL 607 | CALL NXT 608 | CP "," 609 | LD L, 0 ; Default type 610 | JR NZ,1F 611 | CALL COMMA ; Skip comma 612 | CALL EXPRI ; Type 613 | EXX 614 | 1: POP BC ; C: Colour 615 | LD B, L ; B: Type 616 | CALL NEXT_GRAPHICS.Set_Text_Colour 617 | JP XEQ 618 | 619 | ; GCOL mode,colour[,type] 620 | ; As COLOUR 621 | ; 622 | @GCOL: CALL EXPR_P2 ; DE: mode, HL: colour 623 | LD A, E 624 | LD (PLOT_MODE), A 625 | PUSH HL ; Stack the colour 626 | CALL NXT ; Is there a type parameter? 627 | CP "," 628 | LD L, 0 ; Default type 629 | JR NZ,1F 630 | CALL COMMA ; Skip comma 631 | CALL EXPRI ; Type 632 | EXX 633 | 1: POP BC ; C: Colour 634 | LD B, L ; B: Type 635 | CALL NEXT_GRAPHICS.Set_Plot_Colour 636 | JP XEQ 637 | 638 | ; PLOT mode,x,y 639 | ; 640 | @PLOT: CALL EXPRI ; Get the plot type (line, plot, etc) 641 | EXX 642 | PUSH HL 643 | CALL COMMA 644 | CALL EXPR_P2 ; DE: X, HL: Y 645 | CALL NEXT_GRAPHICS.Transform_Coords 646 | POP BC ; Plot type in C 647 | LD A, C ; Plot type in A 648 | PUSH HL ; Y 649 | PUSH DE ; X 650 | CALL NEXT_GRAPHICS.Plot 651 | @PLOT_1: POP DE 652 | POP HL 653 | CALL MOVE_1 654 | 1: JP XEQ 655 | 656 | ; MOVE x, y 657 | ; 658 | @MOVE: CALL EXPR_P2 ; DE: X, HL: Y 659 | CALL NEXT_GRAPHICS.Transform_Coords 660 | CALL MOVE_1 661 | JP XEQ 662 | ; 663 | @MOVE_1: LD BC, (PLOTPOS_X) ; Store the previous plot points 664 | LD (PLOTPRE_X), BC 665 | LD BC, (PLOTPOS_Y) 666 | LD (PLOTPRE_Y), BC 667 | LD (PLOTPOS_X), DE ; And store the latest plot point 668 | LD (PLOTPOS_Y), HL 669 | RET 670 | 671 | ; DRAW x, y 672 | ; 673 | @DRAW: CALL EXPR_P2 ; DE: X, HL: Y 674 | CALL NEXT_GRAPHICS.Transform_Coords 675 | CALL NXT ; Are there any more paramters? 676 | CP "," 677 | JR NZ, 1F ; No, so just do 'DRAW x, y' 678 | CALL COMMA ; Okay, we're now doing 'DRAW x1,y1,x2,y2 679 | CALL MOVE_1 ; MOVE x1,y1 (DE, HL) 680 | CALL EXPR_P2 ; DE: X2, HL: Y2 681 | CALL NEXT_GRAPHICS.Transform_Coords 682 | 1: PUSH HL ; Stack X2 683 | PUSH DE ; Stack Y2 684 | CALL NEXT_GRAPHICS.Plot_Line 685 | JR PLOT_1 686 | 687 | ; POINT(x,y) 688 | ; 689 | @POINT: CALL EXPR_P2 ; DE: X, HL: Y 690 | CALL NEXT_GRAPHICS.Transform_Coords 691 | CALL NEXT_GRAPHICS.Point 692 | LD L, A 693 | 1: CALL BRAKET 694 | JP EVAL.COUNT0 695 | 696 | ; Get two values from EXPR in DE, HL 697 | ; IY: Pointer to expression string 698 | ; Returns: 699 | ; DE: P1 700 | ; HL: P2 701 | ; 702 | @EXPR_P2: CALL EXPRI ; Get first parameter 703 | EXX 704 | PUSH HL 705 | CALL COMMA 706 | CALL EXPRI ; Get second parameter 707 | EXX 708 | POP DE 709 | RET 710 | 711 | ; ---------------------------------------------------------------------------- 712 | 713 | ;OSLOAD - Load an area of memory from a file. 714 | ; Inputs: HL addresses filename (CR terminated) 715 | ; DE = address at which to load 716 | ; BC = maximum allowed size (bytes) 717 | ; Outputs: Carry reset indicates no room for file. 718 | ; Destroys: A,B,C,D,E,H,L,F 719 | ; 720 | @OSLOAD: CALL CRTONULL 721 | PUSH HL 722 | POP IX 723 | LD A, (FDRIVE) 724 | JP NEXT_DOS.Load 725 | 726 | ;OSSAVE - Save an area of memory to a file. 727 | ; Inputs: HL addresses filename (term CR) 728 | ; DE = start address of data to save 729 | ; BC = length of data to save (bytes) 730 | ; Destroys: A,B,C,D,E,H,L,F 731 | ; 732 | @OSSAVE: CALL CRTONULL 733 | PUSH HL 734 | POP IX 735 | LD A, (FDRIVE) 736 | JP NEXT_DOS.Save 737 | 738 | ; ---------------------------------------------------------------------------- 739 | 740 | ; OSOPEN 741 | ; HL: Pointer to path 742 | ; F: C Z 743 | ; x x OPENIN 744 | ; OPENOUT 745 | ; x OPENUP 746 | ; Returns: 747 | ; A: Filehandle, 0 if cannot open 748 | ; 749 | @OSOPEN: LD B, 0x01 ; Mode: Read+Open 750 | JR Z, 1F 751 | LD B, 0x0A ; Mode: Write+Open/Create 752 | JR C, 1F 753 | LD B, 0x0E ; Mode: Write+Open/Create, Delete if Existing 754 | 1: CALL CRTONULL 755 | PUSH HL 756 | POP IX 757 | LD A, (FDRIVE) 758 | JP NEXT_DOS.FOPEN 759 | 760 | ;OSSHUT - Close disk file(s). 761 | ; E = file channel 762 | ; If E=0 all files are closed (except SPOOL) 763 | ; Destroys: A,B,C,D,E,H,L,F 764 | ; 765 | @OSSHUT: LD A, E ; Will need to store file handles for close all 766 | OR A 767 | RET Z 768 | JP NEXT_DOS.FCLOSE 769 | 770 | ; OSBGET - Read a byte from a random disk file. 771 | ; E = file channel 772 | ; Returns 773 | ; A = byte read 774 | ; Carry set if LAST BYTE of file: TODO 775 | ; Destroys: A,B,C,F 776 | ; 777 | @OSBGET: PUSH HL 778 | CALL NEXT_DOS.FREADB 779 | POP HL 780 | OR A ; Clear carry flag 781 | RET 782 | 783 | ; OSBPUT - Write a byte to a random disk file. 784 | ; E = file channel 785 | ; A = byte to write 786 | ; Destroys: A,B,C,F 787 | ; 788 | @OSBPUT: PUSH DE 789 | PUSH HL 790 | CALL NEXT_DOS.FWRITEB 791 | POP HL 792 | POP DE 793 | RET 794 | 795 | ; OSSTAT - Read file status 796 | ; E = file channel 797 | ; Returns 798 | ; F: Z flag set - EOF 799 | ; A: If Z then A = 0 800 | ; Destroys: A,D,E,H,L,F 801 | ; 802 | @OSSTAT: JP NEXT_DOS.EOF 803 | 804 | ; GETPTR - Return file pointer. 805 | ; E = file channel 806 | ; Returns: 807 | ; DEHL = pointer (0-&7FFFFF) 808 | ; Destroys: A,B,C,D,E,H,L,F 809 | ; 810 | @GETPTR: LD A, E 811 | CALL NEXT_DOS.GETPOS 812 | EX DE, HL ; BCDE -> BCHL 813 | LD D, B 814 | LD E, C ; BCHL -> DEHL 815 | RET 816 | 817 | ; PUTPTR - Update file pointer. 818 | ; A = file channel 819 | ; DEHL = new pointer (0-&7FFFFF) 820 | ; Destroys: A,B,C,D,E,H,L,F 821 | ; 822 | @PUTPTR: LD B, D ; DEHL -> BCHL 823 | LD C, E 824 | EX DE, HL ; BCHL -> BCDE 825 | PUSH IX 826 | LD IXL, 0x00 ; Set 827 | CALL NEXT_DOS.SEEK 828 | POP IX 829 | RET 830 | 831 | ; GETEXT - Find file size. 832 | ; E = file channel 833 | ; Returns: 834 | ; DEHL = file size (0-&800000) 835 | ; Destroys: A,B,C,D,E,H,L,F 836 | ; 837 | @GETEXT: LD A, E 838 | CALL NEXT_DOS.FSTAT 839 | LD L, (IX+7) 840 | LD H, (IX+8) 841 | LD E, (IX+9) 842 | LD D, (IX+10) 843 | RET 844 | 845 | ; ---------------------------------------------------------------------------- 846 | 847 | ; SOUND channel,volume,pitch,duration 848 | ; volume: 0 (off) to -15 (full volume) 849 | ; pitch: 0 - 255 850 | ; duration: -1 to 254 (duration in 20ths of a second, -1 = play forever) 851 | ; 852 | @SOUND: CALL EXPR_P2 ; DE: Channel/Control, HL: Volume 853 | LD A, L ; A: Volume 854 | PUSH AF 855 | PUSH DE 856 | CALL COMMA 857 | CALL EXPR_P2 ; DE: Pitch, HL: Duration 858 | LD D, E ; D: Pitch 859 | LD E, L ; E: Duration 860 | POP HL ; HL: Channel/Control 861 | POP AF 862 | NEG 863 | LD C, A ; C: Volume 864 | CALL NEXT_SOUND.Queue_Note 865 | JP XEQ 866 | 867 | ENDMODULE -------------------------------------------------------------------------------- /ram.z80: -------------------------------------------------------------------------------- 1 | ; 2 | ; Title: BBC Basic Interpreter - Z80 version 3 | ; RAM Module for BBC Basic Interpreter 4 | ; For use with Version 2.0 of BBC BASIC 5 | ; Standard CP/M Distribution Version 6 | ; Author: (C) Copyright R.T.Russell 31-12-1983 7 | ; Modified By: Dean Belfield 8 | ; Created: 02/05/2021 9 | ; Last Updated: 15/07/2021 10 | ; 11 | ; Modinfo: 12 | ; 02/05/2021: Modified by Dean Belfield to assemble with SJASMPLUS 13 | ; 10/05/2021: Moved Next RAM variables from build.z80 into here 14 | ; 15/05/2021: Added PLOTPRE_X and PLOTPRE_Y; VDU_BUFFER now shared with BUFFER 15 | ; 17/05/2021: TEXT_COLOUR now split into TEXT_FOREGROUND and TEXT_BACKGROUND; Added BORDER_COLOUR 16 | ; 19/05/2021: Added CURSOR_X and CURSOR_Y 17 | ; 21/05/2021: Added KEYSCAN and KEYREPEAT 18 | ; 23/05/2021: Added FH and FBUFFER 19 | ; 24/05/2021: FBUFFER reuses ACCS 20 | ; 25/05/2021: Added FDRIVE, CPU_SPEED 21 | ; 26/05/2021: Added CHAR_COLS, CHAR_ROWS 22 | ; 28/05/2021: Added PIXEL_WIDTH, PIXEL_HEIGHT and Rnn variables 23 | ; 04/06/2021: Added AY buffers 24 | ; 15/06/2021: Added PLOTORG_X and PLOTORG_Y 25 | ; 29/06/2021: Added OPTVAL, FDATA 26 | ; 12/07/2021: Added UDG_MASK 27 | ; 15/07/2021: Added MOUSE, modified KEY variables, removed LX1, LX2, LY1, LY2 temporary variables 28 | 29 | MODULE RAM 30 | 31 | ALIGN 256 ; Align to page boundary 32 | 33 | Start: EQU $ 34 | ; 35 | ; ACCS, BUFFER & STAVAR must be on page boundaries. 36 | ; 37 | @ACCS: DEFS 256 ; STRING ACCUMULATOR 38 | @BUFFER: DEFS 256 ; STRING INPUT BUFFER 39 | @STAVAR: DEFS 27*4 ; STATIC VARIABLES 40 | @OC: EQU STAVAR+15*4 ; CODE ORIGIN (O%) 41 | @PC: EQU STAVAR+16*4 ; PROGRAM COUNTER (P%) 42 | @DYNVAR: DEFS 54*2 ; DYN. VARIABLE POINTERS 43 | @FNPTR: DEFS 2 ; DYN. FUNCTION POINTER 44 | @PROPTR: DEFS 2 ; DYN. PROCEDURE POINTER 45 | ; 46 | @PAGE: DEFS 2 ; START OF USER PROGRAM 47 | @TOP: DEFS 2 ; FIRST LOCN AFTER PROG. 48 | @LOMEM: DEFS 2 ; START OF DYN. STORAGE 49 | @FREE: DEFS 2 ; FIRST FREE-SPACE BYTE 50 | @HIMEM: DEFS 2 ; FIRST PROTECTED BYTE 51 | ; 52 | @LINENO: DEFS 2 ; LINE NUMBER 53 | @TRACEN: DEFS 2 ; TRACE FLAG 54 | @AUTONO: DEFS 2 ; AUTO FLAG 55 | @ERRTRP: DEFS 2 ; ERROR TRAP 56 | @ERRTXT: DEFS 2 ; ERROR MESSAGE POINTER 57 | @DATPTR: DEFS 2 ; DATA POINTER 58 | @ERL: DEFS 2 ; ERROR LINE 59 | @ERRLIN: DEFS 2 ; "ON ERROR" LINE 60 | @RANDOM: DEFS 5 ; RANDOM NUMBER 61 | @COUNT: DEFS 1 ; PRINT POSITION 62 | @WIDTH: DEFS 1 ; PRINT WIDTH 63 | @ERR: DEFS 1 ; ERROR NUMBER 64 | @LISTON: DEFS 1 ; LISTO & OPT FLAG 65 | @INCREM: DEFS 1 ; AUTO INCREMENT 66 | ; 67 | ; Extra Next-implementation specific system variables 68 | ; 69 | @VDU_BUFFER: EQU ACCS ; Storage for VDU commands 70 | @DOS_BUFFER: EQU ACCS ; Storage for DOS commands 71 | ; 72 | @R00: DEFS 1 ; General purpose register stores 73 | @R01: DEFS 1 ; Leave here - at top of page boundary 74 | @R02: DEFS 1 75 | @R03: DEFS 1 76 | @R04: DEFS 1 77 | @R05: DEFS 1 78 | @R06: DEFS 1 79 | @R07: DEFS 1 80 | @R08: DEFS 1 81 | @R09: DEFS 1 82 | @R10: DEFS 1 83 | @R11: DEFS 1 84 | @R12: DEFS 1 85 | @R13: DEFS 1 86 | @R14: DEFS 1 87 | @R15: DEFS 1 88 | @R16: DEFS 1 89 | @R17: DEFS 1 90 | @R18: DEFS 1 91 | @R19: DEFS 1 92 | ; 93 | @AY_CNT_A: DEFS 1 ; Duration counter for play routine 94 | @AY_PRD_A: DEFS 1 ; Read pointer 95 | @AY_PWR_A: DEFS 1 ; Write pointer 96 | @AY_LEN_A: DEFS 1 ; Length 97 | ; 98 | @AY_CNT_B: DEFS 1 99 | @AY_PRD_B: DEFS 1 100 | @AY_PWR_B: DEFS 1 101 | @AY_LEN_B: DEFS 1 102 | ; 103 | @AY_CNT_C: DEFS 1 104 | @AY_PRD_C: DEFS 1 105 | @AY_PWR_C: DEFS 1 106 | @AY_LEN_C: DEFS 1 107 | ; 108 | @AY_BUF_A: DEFS 15 ; CH A: Queue 5 x [duration, volume, pitch] 109 | @AY_BUF_B: DEFS 15 ; CH B: Queue 5 x [duration, volume, pitch] 110 | @AY_BUF_C: DEFS 15 ; CH C: Queue 5 x [duration, volume, pitch] 111 | ; 112 | @FLAGS: DEFS 1 ; Flags: B7=ESC PRESSED, B6=ESC DISABLED, B5=CAPS LOCK, B4=COPY PRESSED, B3=SHOW CURSOR 113 | @KEY_SCAN: DEFS 2 ; Results of last keyscan 114 | @KEY_COUNT: DEFS 1 ; Key repeat counter 115 | @KEY_CODE: DEFS 1 ; Keycode updated by keyscan 116 | @KEY_DELAY: DEFS 1 ; Initial key delay 117 | @KEY_REPEAT: DEFS 1 ; Key repeat 118 | @TIME: DEFS 4 119 | @VIDEO_MODE: DEFS 1 ; Video mode 120 | @TEXT_FOREGROUND: DEFS 1 ; Text foreground colour (Layer 2) or attribute (ULA) 121 | @TEXT_BACKGROUND: DEFS 1 ; Text background (Layer 2 only) 122 | @BORDER_COLOUR: DEFS 1 123 | @CURSOR_X: DEFS 1 ; Edit cursor position on screen 124 | @CURSOR_Y: DEFS 1 125 | @CHARPOS_X: DEFS 1 ; Current character position on screen 126 | @CHARPOS_Y: DEFS 1 127 | @PLOTORG_X: DEFS 2 ; Plot origin 128 | @PLOTORG_Y: DEFS 2 129 | @PLOTPRE_X: DEFS 2 ; Previous plot position 130 | @PLOTPRE_Y: DEFS 2 131 | @PLOTPOS_X: DEFS 2 ; Current plot position on screen 132 | @PLOTPOS_Y: DEFS 2 133 | @SCRLPOS_Y: DEFS 1 ; Y scroll offset (in characters) 134 | @VDU_STATE: DEFS 1 ; VDU state 135 | @VDU_PTR: DEFS 1 ; Pointer into VDU buffer 136 | @VDU_COUNT: DEFS 1 ; VDU count of characters left to read 137 | @PLOT_MODE: DEFS 1 ; Plot mode as set by GCOL 138 | @PLOT_COLOUR: DEFS 1 ; Plot colour as set by GCOL 139 | @RTC_SIG: DEFS 2 ; Storage for last-read RTC data 140 | @RTC_SEC: DEFS 1 141 | @RTC_MIN: DEFS 1 142 | @RTC_HOUR: DEFS 1 143 | @RTC_DAY: DEFS 1 144 | @RTC_DATE: DEFS 1 145 | @RTC_MONTH: DEFS 1 146 | @RTC_YEAR: DEFS 1 147 | @FH: DEFS 1 ; File handle store 148 | @FDRIVE: DEFS 1 ; Current drive 149 | @FDATA: DEFS 11 ; Storage for OSBGET, OSBPUT, GETEXT, 150 | @CPU_SPEED: DEFS 1 151 | @CHAR_COLS: DEFS 1 ; Screen dimensions (characters) 152 | @CHAR_ROWS: DEFS 1 153 | @PIXEL_WIDTH: DEFS 2 ; Screen dimensions (pixels) 154 | @PIXEL_HEIGHT: DEFS 2 155 | @OPTVAL: DEFS 1 156 | @UDG_MASK: DEFS 1 ; Exploded UDG mode mask 157 | @MOUSE_DX: DEFS 1 158 | @MOUSE_DY: DEFS 1 159 | @MOUSE_CX: DEFS 2 160 | @MOUSE_CY: DEFS 2 161 | 162 | Length: EQU $ - Start 163 | 164 | ENDMODULE -------------------------------------------------------------------------------- /releases/README.md: -------------------------------------------------------------------------------- 1 | 2 | # releases 3 | 4 | These releases are compiled on an ad-hoc basis and have been tested on the MiSTer Next core, ZEsarUX emulator (9.3 Beta 1) and CSpect (2.14.03) 5 | 6 | #### Using with ZEsarUX 7 | 8 | Please make sure you use the latest version of ZEsarUX (9.3 Beta 1 at time of writing). Earlier versions are missing a couple of features that have been introduced into later cores, ULA scrolling and relative Layer 2 page offset. 9 | 10 | I would also recommend you copy the nex file to the img file and launch from the Next browser. ZEsarUX does not initialise the Next correctly if the nex file is dragged into the emulator or loaded using Smart Load. This is by design, but will prevent the disk commands from working. I would recommend this method anyway. 11 | 12 | ##### 20210720: Version 0.16 13 | - Implemented a handful of page &FF calls 14 | - OSBPUT 15 | - OSBGET 16 | - OSWRCH 17 | - OSBYTE (0x00, 0x13, 0x14, 0x80) 18 | - Added ADVAL function 19 | - Added Kempston mouse support (via ADVAL function) 20 | - Added *FX 11 to set keyboard auto-repeat delay 21 | - Added *FX 12 to set keyboard auto-repeat period 22 | - Refactoring and bug fixes 23 | ##### 20210713: Version 0.15 24 | - Fixed bug in PUTCSR; TAB(X,Y) now sets Y coordinate correctly 25 | - Modifications to GET and PUT 26 | - Added GET(x, y) and GET$(x, y) to read character from screen position (x, y) 27 | - Changed GET(n, 1) to GET(n OR &10000) 28 | - Changed PUT(n, 1) to PUT(n OR &10000) 29 | - Added support for UDGs 30 | - *FX 20: Reserve space for UDGs in RAM 31 | - VDU 23, char, b0, b1, ..., b7: Define a character 32 | ##### 20210706: Version 0.14 33 | - RAM contention is now switched off for 3.5Mhz CPU speed 34 | - GCOL modes for PLOT now work in Mode 3 35 | - Data file I/O now implemented: 36 | - OPENIN, OPENOUT, OPENUP, CLOSE# 37 | - INPUT#, PRINT# 38 | - EOF#, PTR#, EXT# 39 | ##### 20210622: Version 0.13 40 | - COPY characters now works in Modes 1, 2 and 3 41 | - Set all graphics to use common viewport (1280x1024) with origin at bottom left, like BBC Micro 42 | - All BASIC graphics tests updated in tests folder 43 | - Added support for VDU 29 (setting the graphics origin) 44 | - CLG now works 45 | ##### 20210614: Version 0.12 46 | - Fixed bugs in Clear_Screen: 47 | - Background colour now set correctly in Mode 3 48 | - It was clearing 18 16K banks rather than 3 (Mode 1) or 5 (Mode 2 or 3) 49 | - CLG now works 50 | - Fixed bug in Mode 3 horizontal line routine (for filled triangles) 51 | - Modes 1, 2 and 3 now have a Spectrum palette in first 16 colours 52 | ##### 20210613: Version 0.11 53 | - Fixed bug in check for zero-length lines 54 | - Mode 3 implemented (640x256, 80 column text) 55 | ##### 20210609: Version 0.10 56 | - ESC handled correctly on interrupt (can break out of LIST, for example) 57 | - ESC now breaks out of GET($) and SOUND command 58 | - Plot modes 1-5 and Point now work in Modes 1 and 2 59 | - Fixed disappearing cursor bug at bottom of screen in Mode 1 and Mode 2 60 | - Fixed default palettes in all modes 61 | - Fixed zero length line bug 62 | 63 | ##### 20210606: Version 0.09 64 | - Fixed clipping in line, circle and triangle graphics primitives 65 | - Fixed issue with negative plot coordinates 66 | - Fixed issue with scrolling and graphics primitives in Modes 0, 1 and 2 67 | - Added SOUND command 68 | 69 | ##### 20210603: Version 0.08 70 | - Mode 2 (320x240) now implemented 71 | - Cursor is now a sprite and works in all modes 72 | - Editor refactored to fix many bugs, including: 73 | - Editor scrolls incorrectly when editing at bottom of screen 74 | - Unable to type in COPY mode 75 | 76 | ##### 20210525: Version 0.07 77 | - Second drives can now be accessed with *DRIVE command 78 | - Added *MKDIR, *RMDIR, *DELETE 79 | - Added *LOAD, *SAVE for loading and saving memory blocks 80 | - Added the alias *DIR for *CD 81 | - Added the alias *ERASE for *DELETE 82 | - Now shifts automatically to TURBO 3 when doing DOS writes 83 | - Meaningful DOS error messages 84 | 85 | ##### 20210524: Version 0.06 86 | - Added disk operations LOAD, CHAIN and SAVE 87 | 88 | ##### 20210523: Version 0.05 89 | - Added disk operations *CAT and *CD 90 | - Improved editor with key repeat and better debounce 91 | - A handful of Z80N optimisations in the core language routines 92 | - Bug fixes 93 | 94 | ##### 20210520: Version 0.04 95 | - Added filled triangle graphics routine 96 | - Improved line editor 97 | 98 | ##### 20210516: Version 0.03 99 | - Added MODE command 100 | - Added line and circle graphics routines 101 | - Star commands can now take decimal or hex values 102 | - Graphics routines for Layer 2 and ULA now split into separate files 103 | 104 | ##### 20210513: Version 0.02 105 | - Added Z80N instructions to Z80 assembler - see [test_assembler_Z80N.bbc](../tests/test_assembler_Z80N.bbc) for example test code 106 | 107 | ##### 20210510: Version 0.01 108 | - Turbo mode command renamed from *RUN to *TURBO 109 | - Added RTC support - time can be accessed via *TIME or variable TIME$ 110 | - Added VDU command support for cursor control, CLS, COLOUR, CLG, GCOL and PLOT 111 | - General tidy up of the source code 112 | 113 | ##### 20210509: Initial Version 114 | - Implemented key scanning and output routines 115 | - Modified PUT and GET to support writing and reading NEXTREG registers directly 116 | - Implemented COLOUR, GCOL, CLS, GCLS 117 | - Started implementating PLOT and FX commands 118 | - Started implementing MODE 119 | - Added *RUN to set turbo mode 120 | - Added *MEMDUMP to help in debugging 121 | 122 | Dean Belfield 123 | www.breakintoprogram.co.uk 124 | -------------------------------------------------------------------------------- /releases/bbcbasic_20210509.nex: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/breakintoprogram/next-bbc-basic/506b604533a0bd121df5adc34fd4301b5cbcbba7/releases/bbcbasic_20210509.nex -------------------------------------------------------------------------------- /releases/bbcbasic_20210510.nex: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/breakintoprogram/next-bbc-basic/506b604533a0bd121df5adc34fd4301b5cbcbba7/releases/bbcbasic_20210510.nex -------------------------------------------------------------------------------- /releases/bbcbasic_20210513.nex: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/breakintoprogram/next-bbc-basic/506b604533a0bd121df5adc34fd4301b5cbcbba7/releases/bbcbasic_20210513.nex -------------------------------------------------------------------------------- /releases/bbcbasic_20210516.nex: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/breakintoprogram/next-bbc-basic/506b604533a0bd121df5adc34fd4301b5cbcbba7/releases/bbcbasic_20210516.nex -------------------------------------------------------------------------------- /releases/bbcbasic_20210520.nex: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/breakintoprogram/next-bbc-basic/506b604533a0bd121df5adc34fd4301b5cbcbba7/releases/bbcbasic_20210520.nex -------------------------------------------------------------------------------- /releases/bbcbasic_20210523.nex: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/breakintoprogram/next-bbc-basic/506b604533a0bd121df5adc34fd4301b5cbcbba7/releases/bbcbasic_20210523.nex -------------------------------------------------------------------------------- /releases/bbcbasic_20210524.nex: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/breakintoprogram/next-bbc-basic/506b604533a0bd121df5adc34fd4301b5cbcbba7/releases/bbcbasic_20210524.nex -------------------------------------------------------------------------------- /releases/bbcbasic_20210525.nex: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/breakintoprogram/next-bbc-basic/506b604533a0bd121df5adc34fd4301b5cbcbba7/releases/bbcbasic_20210525.nex -------------------------------------------------------------------------------- /releases/bbcbasic_20210603.nex: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/breakintoprogram/next-bbc-basic/506b604533a0bd121df5adc34fd4301b5cbcbba7/releases/bbcbasic_20210603.nex -------------------------------------------------------------------------------- /releases/bbcbasic_20210606.nex: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/breakintoprogram/next-bbc-basic/506b604533a0bd121df5adc34fd4301b5cbcbba7/releases/bbcbasic_20210606.nex -------------------------------------------------------------------------------- /releases/bbcbasic_20210609.nex: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/breakintoprogram/next-bbc-basic/506b604533a0bd121df5adc34fd4301b5cbcbba7/releases/bbcbasic_20210609.nex -------------------------------------------------------------------------------- /releases/bbcbasic_20210613.nex: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/breakintoprogram/next-bbc-basic/506b604533a0bd121df5adc34fd4301b5cbcbba7/releases/bbcbasic_20210613.nex -------------------------------------------------------------------------------- /releases/bbcbasic_20210614.nex: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/breakintoprogram/next-bbc-basic/506b604533a0bd121df5adc34fd4301b5cbcbba7/releases/bbcbasic_20210614.nex -------------------------------------------------------------------------------- /releases/bbcbasic_20210622.nex: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/breakintoprogram/next-bbc-basic/506b604533a0bd121df5adc34fd4301b5cbcbba7/releases/bbcbasic_20210622.nex -------------------------------------------------------------------------------- /releases/bbcbasic_20210706.nex: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/breakintoprogram/next-bbc-basic/506b604533a0bd121df5adc34fd4301b5cbcbba7/releases/bbcbasic_20210706.nex -------------------------------------------------------------------------------- /releases/bbcbasic_20210713.nex: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/breakintoprogram/next-bbc-basic/506b604533a0bd121df5adc34fd4301b5cbcbba7/releases/bbcbasic_20210713.nex -------------------------------------------------------------------------------- /releases/bbcbasic_20210720.nex: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/breakintoprogram/next-bbc-basic/506b604533a0bd121df5adc34fd4301b5cbcbba7/releases/bbcbasic_20210720.nex -------------------------------------------------------------------------------- /sorry.z80: -------------------------------------------------------------------------------- 1 | ; 2 | ; Title: BBC Basic Interpreter - Z80 version 3 | ; Catch-all for unimplemented functionality 4 | ; Author: Dean Belfield 5 | ; Created: 02/05/2021 6 | ; Last Updated: 15/07/2021 7 | ; 8 | ; Modinfo: 9 | ; 10/05/2021 Moved GETIMS to patch.z80 10 | ; 13/05/2021 Moved DRAW to patch.z80 11 | ; 04/06/2021: Moved SOUND to patch.z80 12 | ; 15/07/2021: Moved ADVAL to patch.z80 13 | 14 | MODULE SORRY 15 | 16 | @ENVEL: 17 | @PUTIMS: 18 | XOR A 19 | CALL EXTERR 20 | DEFM 'Sorry' 21 | DEFB 0 22 | 23 | ENDMODULE -------------------------------------------------------------------------------- /tests/BENCHMARK.md: -------------------------------------------------------------------------------- 1 | # benchmarks 2 | 3 | Tested using the [Rugg/Feldman (PCW) benchmarks](https://en.wikipedia.org/wiki/Rugg/Feldman_benchmarks#:~:text=This%20expanded%20set%20became%20known,many%20computer%20magazines%20and%20journals.) 4 | 5 | NB: 6 | 7 | - The BBC Micro CPU is a 6502 8 | - The Spectrum is a Z80 9 | - The Next is a Z80 running on an FPGA core 10 | 11 | | # | Next (3.5Mhz)| Next (28Mhz)| Spectrum (3.5Mhz) | BBC Micro (2Mhz) | 12 | |---|-------------:|-------------:|------------------:|-----------------:| 13 | | 1 | 1.12s | 0.16s | 4.4s | 0.8s | 14 | | 2 | 4.48s | 0.66s | 8.2s | 3.1s | 15 | | 3 | 14.12s | 2.08s | 20.0s | 8.1s | 16 | | 4 | 15.34s | 2.30s | 19.2s | 8.7s | 17 | | 5 | 16.48s | 2.64s | 23.1s | 9.0s | 18 | | 6 | 24.06s | 3.56s | 53.4s | 13.9s | 19 | | 7 | 35.44s | 5.12s | 77.6s | 21.1s | 20 | | 8 | 40.41s | 6.10s | 239.1s | 49.9s | 21 | -------------------------------------------------------------------------------- /tests/README.md: -------------------------------------------------------------------------------- 1 | # tests 2 | 3 | A handful of BBC BASIC programs I use for regression and soak testing: 4 | 5 | - `assembler_Z80N.bbc` Test for Z80N instructions 6 | - `circle.bbc` Draw a filled in circle 7 | - `cube.bbc` Spinning 3D cube 8 | - `fireworks.bbc` Tests colour palette animation in Mode 2 9 | - `ftest1.bbc` Read and output the file ftest.txt 10 | - `ftest2.bbc` Write to file ftest.txt 11 | - `ftest3.bbc` Append to file ftest.txt 12 | - `hatgraph.bbc` A 3D graph 13 | - `lines.bbc` Draw random lines 14 | - `mandlebrot.bbc` Draw a Mandlebrot set 15 | - `mouse.bbc` Next Kempston mouse support via ADVAL, hardware sprite 16 | - `oscall.bbc` Tests intercept of page &FF calls like OSBYTE 17 | - `shadows.bbc` Ray traced spheres 18 | - `snake.bbc` Simple SNAKE game - collect the X, avoid everything else 19 | - `sound.bbc` Tests the SOUND command, should play Amazing Grace 20 | - `tornado.bbc` Tests colour palette animation in Mode 2 21 | - `triangles.bbc` Draw random triangles 22 | - `udg.bbc` Test VDU 23 23 | 24 | And there are also a set of Rugg/Feldman (PCW) benchmark programs; benchm1.bbc to benchm8.bbc -------------------------------------------------------------------------------- /tests/assembler_Z80N.bbc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/breakintoprogram/next-bbc-basic/506b604533a0bd121df5adc34fd4301b5cbcbba7/tests/assembler_Z80N.bbc -------------------------------------------------------------------------------- /tests/benchm1.bbc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/breakintoprogram/next-bbc-basic/506b604533a0bd121df5adc34fd4301b5cbcbba7/tests/benchm1.bbc -------------------------------------------------------------------------------- /tests/benchm2.bbc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/breakintoprogram/next-bbc-basic/506b604533a0bd121df5adc34fd4301b5cbcbba7/tests/benchm2.bbc -------------------------------------------------------------------------------- /tests/benchm3.bbc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/breakintoprogram/next-bbc-basic/506b604533a0bd121df5adc34fd4301b5cbcbba7/tests/benchm3.bbc -------------------------------------------------------------------------------- /tests/benchm4.bbc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/breakintoprogram/next-bbc-basic/506b604533a0bd121df5adc34fd4301b5cbcbba7/tests/benchm4.bbc -------------------------------------------------------------------------------- /tests/benchm5.bbc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/breakintoprogram/next-bbc-basic/506b604533a0bd121df5adc34fd4301b5cbcbba7/tests/benchm5.bbc -------------------------------------------------------------------------------- /tests/benchm6.bbc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/breakintoprogram/next-bbc-basic/506b604533a0bd121df5adc34fd4301b5cbcbba7/tests/benchm6.bbc -------------------------------------------------------------------------------- /tests/benchm7.bbc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/breakintoprogram/next-bbc-basic/506b604533a0bd121df5adc34fd4301b5cbcbba7/tests/benchm7.bbc -------------------------------------------------------------------------------- /tests/benchm8.bbc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/breakintoprogram/next-bbc-basic/506b604533a0bd121df5adc34fd4301b5cbcbba7/tests/benchm8.bbc -------------------------------------------------------------------------------- /tests/circle.bbc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/breakintoprogram/next-bbc-basic/506b604533a0bd121df5adc34fd4301b5cbcbba7/tests/circle.bbc -------------------------------------------------------------------------------- /tests/cube.bbc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/breakintoprogram/next-bbc-basic/506b604533a0bd121df5adc34fd4301b5cbcbba7/tests/cube.bbc -------------------------------------------------------------------------------- /tests/fireworks.bbc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/breakintoprogram/next-bbc-basic/506b604533a0bd121df5adc34fd4301b5cbcbba7/tests/fireworks.bbc -------------------------------------------------------------------------------- /tests/ftest1.bbc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/breakintoprogram/next-bbc-basic/506b604533a0bd121df5adc34fd4301b5cbcbba7/tests/ftest1.bbc -------------------------------------------------------------------------------- /tests/ftest2.bbc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/breakintoprogram/next-bbc-basic/506b604533a0bd121df5adc34fd4301b5cbcbba7/tests/ftest2.bbc -------------------------------------------------------------------------------- /tests/ftest3.bbc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/breakintoprogram/next-bbc-basic/506b604533a0bd121df5adc34fd4301b5cbcbba7/tests/ftest3.bbc -------------------------------------------------------------------------------- /tests/hatgraph.bbc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/breakintoprogram/next-bbc-basic/506b604533a0bd121df5adc34fd4301b5cbcbba7/tests/hatgraph.bbc -------------------------------------------------------------------------------- /tests/lines.bbc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/breakintoprogram/next-bbc-basic/506b604533a0bd121df5adc34fd4301b5cbcbba7/tests/lines.bbc -------------------------------------------------------------------------------- /tests/mandlebrot.bbc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/breakintoprogram/next-bbc-basic/506b604533a0bd121df5adc34fd4301b5cbcbba7/tests/mandlebrot.bbc -------------------------------------------------------------------------------- /tests/mouse.bbc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/breakintoprogram/next-bbc-basic/506b604533a0bd121df5adc34fd4301b5cbcbba7/tests/mouse.bbc -------------------------------------------------------------------------------- /tests/on_proc.bbc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/breakintoprogram/next-bbc-basic/506b604533a0bd121df5adc34fd4301b5cbcbba7/tests/on_proc.bbc -------------------------------------------------------------------------------- /tests/oscall.bbc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/breakintoprogram/next-bbc-basic/506b604533a0bd121df5adc34fd4301b5cbcbba7/tests/oscall.bbc -------------------------------------------------------------------------------- /tests/shadows.bbc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/breakintoprogram/next-bbc-basic/506b604533a0bd121df5adc34fd4301b5cbcbba7/tests/shadows.bbc -------------------------------------------------------------------------------- /tests/snake.bbc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/breakintoprogram/next-bbc-basic/506b604533a0bd121df5adc34fd4301b5cbcbba7/tests/snake.bbc -------------------------------------------------------------------------------- /tests/sound.bbc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/breakintoprogram/next-bbc-basic/506b604533a0bd121df5adc34fd4301b5cbcbba7/tests/sound.bbc -------------------------------------------------------------------------------- /tests/source text/assembler_Z80N.txt: -------------------------------------------------------------------------------- 1 | 1 REM For more information on the extra Z80N instructions on the Spectrum Next core 2 | 2 REM click here: https://wiki.specnext.dev/Extended_Z80_instruction_set and scroll 3 | 3 REM to the bottom 4 | 4 REM 5 | 5 REM Note I am using the 4-letter abbreviated opcodes proposed by Matt Davies 6 | 6 REM 7 | 10 DIM code 256 8 | 20 FOR opt% = 1 TO 3 STEP 2 9 | 30 P% = code 10 | 40 [ OPT opt% 11 | 60 SWAP ; SWAPNIB 12 | 70 MIRR A ; MIRROR 13 | 80 TEST &FF 14 | 90 BSLA DE, B 15 | 100 BSRA DE, B 16 | 110 BSRL DE, B 17 | 120 BSRF DE, B 18 | 130 BRLC DE, B 19 | 140 MUL D, E 20 | 150 OTIB ; OUTINB 21 | 160 NREG &41, &FF ; NEXTREG 22 | 170 NREG &41, A ; NEXTREG 23 | 180 PXDN ; PIXELDN 24 | 190 PXAD ; PIXELAD 25 | 200 STAE ; SETAE 26 | 210 LDIX 27 | 220 LDWS 28 | 230 LDDX 29 | 240 LIRX ; LDIRX 30 | 250 LPRX ; LDPIRX 31 | 260 LDRX ; LDDRX 32 | 270 ADD HL, A 33 | 280 ADD DE, A 34 | 290 ADD BC, A 35 | 300 ADD HL, &1234 36 | 310 ADD DE, &1234 37 | 320 ADD BC, &1234 38 | 330 PUSH &1234 39 | 340 JP (C) 40 | 350 ] 41 | 360 NEXT -------------------------------------------------------------------------------- /tests/source text/cube.txt: -------------------------------------------------------------------------------- 1 | 5 FILLED%=0 2 | 10 REM Initialise the data 3 | 20 READ CN% 4 | 30 DIM X%(CN%),Y%(CN%),Z%(CN%),A%(CN%),B%(CN%) 5 | 40 FOR I%=1 TO CN%: READ X%(I%),Y%(I%),Z%(I%):NEXT 6 | 50 READ TS% 7 | 60 DIM S%(TS%,4) 8 | 70 FOR I%=1 TO TS%: READ S%(I%,1),S%(I%,2),S%(I%,3),S%(I%,4):NEXT 9 | 80 REM Variables 10 | 90 THETA=0:PSI=0:PHI=0 11 | 100 XD=0:YD=0 12 | 110 SD=256:OD=128 13 | 120 REM Transform 14 | 130 FOR I%=1 TO CN% 15 | 140 REM Rotate 16 | 150 XX=X%(I%):YY=Y%(I%):ZZ=Z%(I%) 17 | 160 Y=YY*COS(PHI/180*PI)-ZZ*SIN(PHI/180*PI) 18 | 170 ZZ=YY*SIN(PHI/180*PI)+ZZ*COS(PHI/180*PI) 19 | 180 X=XX*COS(THETA/180*PI)-ZZ*SIN(THETA/180*PI) 20 | 190 ZZ=XX*SIN(THETA/180*PI)+ZZ*COS(THETA/180*PI) 21 | 200 XX=X*COS(PSI/180*PI)-Y*SIN(PSI/180*PI) 22 | 210 YY=X*SIN(PSI/180*PI)+Y*COS(PSI/180*PI) 23 | 220 REM Transform 24 | 230 XX=XX+XD:YY=YY+YD 25 | 240 REM Perspective 26 | 250 A%(I%)=128+XX*SD/(OD-ZZ) 27 | 260 B%(I%)=96+YY*SD/(OD-ZZ) 28 | 270 NEXT 29 | 280 REM Draw 30 | 285 CLS 31 | 290 FOR I%=1 TO TS% 32 | 300 C1%=S%(I%,1):C2%=S%(I%,2):C3%=S%(I%,3):C4%=S%(I%,4) 33 | 310 X1=A%(C1%):X2=A%(C2%):X3=A%(C3%):X4=A%(C4%) 34 | 320 Y1=B%(C1%):Y2=B%(C2%):Y3=B%(C3%):Y4=B%(C4%) 35 | 330 IF X1*(Y2-Y3)+X2*(Y3-Y1)+X3*(Y1-Y2) > 0 THEN GOTO 380 36 | 335 GCOL 0,I%MOD7+1 37 | 336 IF FILLED%=0 THEN GOTO 360 38 | 340 MOVE X1,Y1:MOVE X2,Y2:PLOT 85,X3,Y3 39 | 350 MOVE X3,Y3:MOVE X4,Y4:PLOT 85,X1,Y1 40 | 355 GOTO 380 41 | 360 MOVE X1,Y1:PLOT 5,X2,Y2:PLOT 5,X3,Y3:PLOT 5,X4,Y4:PLOT 5,X1,Y1 42 | 380 NEXT 43 | 390 PHI=PHI+4 44 | 391 THETA=THETA-1 45 | 400 GOTO 130 46 | 1000 REM DATA 47 | 1010 DATA 8 48 | 1020 DATA -20,20,20 49 | 1030 DATA 20,20,20 50 | 1040 DATA -20,-20,20 51 | 1050 DATA 20,-20,20 52 | 1060 DATA -20,20,-20 53 | 1070 DATA 20,20,-20 54 | 1080 DATA -20,-20,-20 55 | 1090 DATA 20,-20,-20 56 | 1100 DATA 6 57 | 1110 DATA 1,2,4,3 58 | 1120 DATA 7,8,6,5 59 | 1130 DATA 2,6,8,4 60 | 1140 DATA 3,7,5,1 61 | 1150 DATA 3,4,8,7 62 | 1160 DATA 1,5,6,2 63 | -------------------------------------------------------------------------------- /tests/source text/hatgraph.txt: -------------------------------------------------------------------------------- 1 | 10 MODE 0 2 | 20 REM VDU 19,1,1,0,0,0 3 | 30 DIM RR(320) 4 | 40 FOR I=0 TO 320:RR(I)=193:NEXT I 5 | 50 XP=144:XR=4.71238905:XF=XR/XP 6 | 60 FOR ZI=64 TO -64 STEP -2 7 | 70 ZT=ZI*2.25:ZS=ZT*ZT 8 | 80 XL=INT(SQR(20736-ZS)+0.5) 9 | 90 FOR XI=0-XL TO XL STEP.5 10 | 100 XT=SQR(XI*XI+ZS)*XF 11 | 110 YY=(SIN(XT)+SIN(XT*3)*0.4)*56 12 | 120 X1=XI+ZI+128:Y1=96-YY+ZI 13 | 125 IF X1<0 THEN GOTO 180 14 | 130 IF RR(X1)<=Y1 THEN 180 15 | 140 RR(X1)=Y1 16 | 170 PLOT 69,X1,Y1 17 | 180 NEXT XI:NEXT -------------------------------------------------------------------------------- /tests/source text/mandlebrot.txt: -------------------------------------------------------------------------------- 1 | 100 REM PROGRAM TO DRAW MANDLEBROT SET 2 | 110 REM P.MAINWARING, MARCH 19TH 1990 3 | 130 ITERS=32 4 | 140 SCALE=1 5 | 150 XRANGE=-2.5 6 | 160 YRANGE=-1.5 7 | 170 DIM A(3),B(3) 8 | 180 FOR I=0 TO 3 9 | 190 READ A(I),B(I) 10 | 200 NEXT I 11 | 210 DATA 0,0,1,1,0,1,1,0 12 | 220 MODE 1 13 | 230 REM XSTP=1 14 | 240 REM YSTP=1 15 | 250 COLS=64 16 | 260 MAXX=256 17 | 270 MAXY=192 18 | 290 FOR I=0 TO 3 19 | 300 FOR J=A(I) TO MAXY/SCALE 20 | 310 FOR K=B(I) TO MAXX/SCALE 21 | 320 CR=XRANGE+K*4/(MAXX/SCALE) 22 | 330 CI=YRANGE+J*3/(MAXX/SCALE) 23 | 340 ZM=0:ZR=0:ZI=0:ZR2=0:ZI2=0 24 | 350 IT=0 25 | 360 REPEAT 26 | 370 Z1=ZR2-ZI2+CR 27 | 380 Z2=2*ZR*ZI+CI 28 | 390 ZR=Z1 29 | 400 ZI=Z2 30 | 410 ZR2=ZR*ZR 31 | 420 ZI2=ZI*ZI 32 | 430 ZM=ZR2+ZI2 33 | 440 IT=IT+1 34 | 450 UNTIL IT=ITERS OR ZM>=4 35 | 490 GCOL 0,COLS-1-INT(IT/(ITERS/(COLS-1))):PLOT 69,K,J 36 | 500 NEXT K 37 | 510 NEXT J 38 | 530 NEXT I 39 | -------------------------------------------------------------------------------- /tests/source text/mandlebrot_ascii.txt: -------------------------------------------------------------------------------- 1 | 1 REM Example Mandlebrot Set 2 | 2 REM This does take quite a while to run! 3 | 3 REM 4 | 10 *TURBO 3 5 | 20 MODE 1 6 | 30 MI% = 255 7 | 40 MX% = 4 8 | 50 LS = -2.0 9 | 60 TP = 1.25 10 | 70 XS = 2.5 11 | 80 YS = -2.5 12 | 90 W% = 255 13 | 100 H% = 191 14 | 110 SX = XS / W% 15 | 120 SY = YS / H% 16 | 130 FOR Y% = 0 TO H% 17 | 140 CY = Y% * SY + TP 18 | 150 FOR X% = 0 TO W% 19 | 160 CX = X% * SX + LS 20 | 170 ZX = 0 21 | 180 ZY = 0 22 | 190 CC% = 0 23 | 200 X2 = ZX * ZX 24 | 210 Y2 = ZY * ZY 25 | 220 IF CC% > MI% THEN GOTO 290 26 | 230 IF (X2 + Y2) > MX THEN GOTO 290 27 | 240 T = X2 - Y2 + CX 28 | 250 ZY = 2 * ZX * ZY + CY 29 | 260 ZX = T 30 | 270 CC% = CC% + 1 31 | 280 GOTO 200 32 | 290 GCOL 0, CC: PLOT 64, X%, Y% 33 | 300 NEXT 34 | 310 NEXT 35 | 320 A%=GET -------------------------------------------------------------------------------- /tests/source text/shadows.txt: -------------------------------------------------------------------------------- 1 | 10 REM Shadows 2 | 20 REM Version B0.25 3 | 30 REM Author: David Williams 4 | 40 REM BEEBUG July 1988 5 | 50 : 6 | 100 MODE 1: ON ERROR GOTO 210 7 | 110 REM VDU 23,1,0;0;0;0; 8 | 120 REM VDU 29,640;512; 9 | 130 REM VDU 19,2,4,0,0,0 10 | 140 DIM d(11) 11 | 150 PROCinitrotate(0,0,-20) 12 | 160 PROCboard 13 | 170 PROCscan(-50,100,50) 14 | 180 REM *BPRINT 15 | 190 END 16 | 200 : 17 | 210 IF ERR=17 END 18 | 220 REPORT:PRINT " at line ";ERL 19 | 230 END 20 | 240 : 21 | 1000 DEF FNBallLineIntersect(a,b,c,ra,p,q,r,s,t,u) 22 | 1010 LOCAL d,e,f,A,B,C,f% 23 | 1020 d=q-a:e=s-b:f=u-c 24 | 1030 A=p*p+r*r+t*t: IF A=0 THEN =TRUE 25 | 1040 B=2*(p*d+r*e+t*f) 26 | 1050 C=(d*d+e*e+f*f)-(ra*ra) 27 | 1060 =B*B-4*A*C>0 28 | 1070 : 29 | 1080 DEF PROCinitrotate(A,B,C) 30 | 1090 LOCAL a,b,c 31 | 1100 a=RAD(A):d(4)=COS(a):d(5)=SIN(a):d(6)=-d(5):d(7)=d(4) 32 | 1110 b=RAD(B):d(8)=COS(b):d(9)=SIN(b):d(10)=-d(9):d(11)=d(8) 33 | 1120 c=RAD(C):d(0)=COS(c):d(1)=SIN(c):d(2)=-d(1):d(3)=d(0) 34 | 1130 ENDPROC 35 | 1140 : 36 | 1150 DEF PROCrotate 37 | 1160 Rx=0:Ry=0:Rz=400 38 | 1170 x=x-Rx:y=y-Ry:z=z-Rz 39 | 1180 LOCAL xs,ys 40 | 1190 xs=x 41 | 1200 x=(xs*d(4))+(y*d(6)):y=(xs*d(5))+(y*d(7)) 42 | 1210 xs=x 43 | 1220 x=(xs*d(8))+(z*d(10)):z=(xs*d(9))+(z*d(11)) 44 | 1230 ys=y 45 | 1240 y=(ys*d(0))+(z*d(2)):z=(ys*d(1))+(z*d(3)) 46 | 1250 x=x+Rx:y=y+Ry:z=z+Rz 47 | 1260 PROCperspective(800) 48 | 1270 ENDPROC 49 | 1280 : 50 | 1290 DEF PROCperspective(F) 51 | 1300 x=(F*x)/(F+z) 52 | 1310 y=(F*y)/(F+z) 53 | 1320 ENDPROC 54 | 1330 : 55 | 1340 DEF PROCmove(x,y,z) 56 | 1350 PROCrotate:MOVE 128+x/5,96+y/5.34 57 | 1360 ENDPROC 58 | 1370 : 59 | 1380 DEF PROCdraw(x,y,z) 60 | 1390 PROCrotate:DRAW 128+x/5,96+y/5.34 61 | 1400 ENDPROC 62 | 1410 : 63 | 1420 DEF PROCplot85(x,y,z) 64 | 1430 PROCrotate:PLOT 85,128+x/5,96+y/5.34 65 | 1440 ENDPROC 66 | 1450 : 67 | 1460 DEF PROCboard 68 | 1470 LOCAL X%,Y%,C% 69 | 1480 FOR X%=-400 TO 350 STEP 100 70 | 1490 FOR Y%=-250 TO 400 STEP 100 71 | 1500 IF C%=3 C%=1 ELSE C%=3 72 | 1510 GCOL 0,C% 73 | 1520 PROCmove(X%,-100,Y%):PROCmove(X%+100,-100,Y%):PROCplot85(X%,-100,Y%+100):PROCplot85(X%+100,-100,Y%+100) 74 | 1530 NEXT:NEXT 75 | 1540 PROCDefinePlane(-400,-100,-250,350,-100,-250,350,-100,400) 76 | 1550 ENDPROC 77 | 1560 : 78 | 1570 DEF PROCDefinePlane(x1,y1,z1,x2,y2,z2,x3,y3,z3) 79 | 1580 LOCAL a,b,c,d,e,f,g,h,i 80 | 1590 x=x1:y=y1:z=z1:PROCrotate 81 | 1600 x1=x:y1=y:z1=z 82 | 1610 x=x2:y=y2:z=z2:PROCrotate 83 | 1620 x2=x:y2=y:z2=z 84 | 1630 x=x3:y=y3:z=z3:PROCrotate 85 | 1640 x3=x:y3=y:z3=z 86 | 1650 a=x2-x1:b=y2-y1:c=z2-z1 87 | 1660 d=x3-x1:e=y3-y1:f=z3-z1 88 | 1670 g=b*f-e*c:h=c*d-a*f:i=a*e-b*d 89 | 1680 A=g:B=h:C=i:D=A*x2+B*y2+C*z2 90 | 1690 ENDPROC 91 | 1700 : 92 | 1710 DEF PROCPlaneLineIntersect(A,B,C,D,p,r,t,q,s,u) 93 | 1720 LOCAL k 94 | 1730 k=(D-(A*q+B*s+C*u))/(A*p+B*r+C*t) 95 | 1740 Vx=p*k+q:Vy=r*k+s:Vz=t*k+u 96 | 1750 ENDPROC 97 | 1760 : 98 | 1770 DEF PROCscan(SLx,SLy,SLz) 99 | 1780 LOCAL x%,y%,col%,test%,Vx,Vy,Vz 100 | 1790 PROCcircle(0,0,100,200) 101 | 1800 PROCcircle(-350,-100,100,100) 102 | 1810 FOR x%=-400 TO 555 STEP 4 103 | 1820 FOR y%=-50 TO -430 STEP -4 104 | 1830 col%=POINT(128+x%/5,96+y%/5.34) 105 | 1840 IF col%=0 OR col%=2 GOTO 1910 106 | 1850 PROCPlaneLineIntersect(A,B,C,D,0,0,-800,x%,y%,0) 107 | 1860 test%=FNBallLineIntersect(0,0,100,200,SLx,Vx,SLy,Vy,SLz,Vz) 108 | 1870 IF test%=FALSE test%=FNBallLineIntersect(-350,-100,100,100,SLx,Vx,SLy,Vy,SLz,Vz) 109 | 1880 IF test%=TRUE AND col%=1 col%=0 110 | 1890 IF test%=TRUE AND col%=3 col%=2 111 | 1900 GCOL 0,col%:PLOT 69,128+x%/5,96+y%/5.34 112 | 1910 NEXT:NEXT 113 | 1920 PROCsphere(0,0,100,200,SLx,SLy,SLz) 114 | 1930 PROCsphere(-350,-100,100,100,SLx,SLy,SLz) 115 | 1940 ENDPROC 116 | 1950 : 117 | 1960 DEF PROCcircle(x,y,z,ra) 118 | 1970 LOCAL a 119 | 1980 PROCmove(x,y,z):GCOL 0,2 120 | 1990 FOR a=0 TO 2*PI+0.1 STEP 0.1 121 | 2000 PROCmove(x,y,z):PROCplot85(x+ra*COS(a),y+ra*SIN(a),z) 122 | 2010 NEXT a 123 | 2020 ENDPROC 124 | 2030 : 125 | 2040 DEF PROCsphere(x,y,z,ra,Lx,Ly,Lz) 126 | 2050 LOCAL a,b,da,db,I,s,c,sd,cd 127 | 2060 da=0.4:db=0.3 128 | 2070 I=0:PROCmove(x+ra*COS(I),y+ra*SIN(I),z) 129 | 2080 FOR b=-0.5*PI TO 0.5*PI STEP db 130 | 2090 s=SIN(b):c=COS(b):sd=SIN(b+db):cd=COS(b+db) 131 | 2100 FOR I=0 TO 2*PI STEP da 132 | 2110 sini=SIN(I):cosi=COS(I):sinida=SIN(I+da):cosida=COS(I+da) 133 | 2120 PROCtriangle(x+(ra*c)*cosi,y+s*ra,z+(ra*c)*sini,x+(ra*cd)*cosi,y+sd*ra,z+(ra*cd)*sini,x+(ra*c)*cosida,y+s*ra,z+(ra*c)*sinida) 134 | 2130 PROCtriangle(x+(ra*cd)*cosi,y+sd*ra,z+(ra*cd)*sini,x+(ra*cd)*cosida,y+sd*ra,z+(ra*cd)*sinida,x+(ra*c)*cosida,y+s*ra,z+(ra*c)*sinida) 135 | 2140 PROCmove(x+(ra*c)*cosi,y+s*ra,z+(ra*c)*sini) 136 | 2150 GCOL 0,3:PROCdraw(x+(ra*c)*cosida,y+s*ra,z+(ra*c)*sinida) 137 | 2160 NEXT 138 | 2170 NEXT 139 | 2180 ENDPROC 140 | 2190 : 141 | 2200 DEF PROCtriangle(x1,y1,z1,x2,y2,z2,x3,y3,z3) 142 | 2210 PROCillumination(x1,y1,z1,x2,y2,z2,x3,y3,z3,Lx,Ly,Lz) 143 | 2220 PROCmove(x1,y1,z1) 144 | 2230 PROCmove(x2,y2,z2) 145 | 2240 PROCplot85(x3,y3,z3) 146 | 2250 ENDPROC 147 | 2260 : 148 | 2270 DEF PROCillumination(x1,y1,z1,x2,y2,z2,x3,y3,z3,Lx,Ly,Lz) 149 | 2280 LOCAL a,b,c,d,e,f,g,h,i,ans 150 | 2290 a=x2-x1:b=y2-y1:c=z2-z1 151 | 2300 d=x3-x1:e=y3-y1:f=z3-z1 152 | 2310 g=b*f-e*c:h=c*d-a*f:i=a*e-b*d 153 | 2320 temp1=(g*g+h*h+i*i):temp2=(Lx*Lx+Ly*Ly+Lz*Lz) 154 | 2330 IF temp1*temp2=0 THEN ans=0 ELSE ans=(g*Lx+h*Ly+i*Lz)/SQR(temp1*temp2) 155 | 2340 IF ans>0 GCOL 0,1 ELSE GCOL 0,2 156 | 2350 ENDPROC 157 | -------------------------------------------------------------------------------- /tests/source text/stars.txt: -------------------------------------------------------------------------------- 1 | 10 REM STARFIELD 2 | 20 LET SPEED=3 3 | 30 LET SC%=25 4 | 40 : 5 | 50 MODE 1 6 | 60 VDU 23,1,0;0;0;0; 7 | 70 DIM SX(SC%),SY(SC%) 8 | 80 FOR S%=1 TO SC% 9 | 90 SX(S%)=RND(256)-128 10 | 100 SY(S%)=RND(192)-96 11 | 110 NEXT 12 | 120 FOR S%=1 TO SC% 13 | 130 PLOT 70,SX(S%)+128,SY(S%)+96 14 | 140 NEXT 15 | 150 REPEAT 16 | 160 FOR S%=1 TO SC% 17 | 170 X1=SX(S%):Y1=SY(S%) 18 | 180 X2=X1+X1/64*SPEED 19 | 190 Y2=Y1+Y1/51.2*SPEED 20 | 200 IF ABS(X2)>128 OR ABS(Y2)>96 THEN X2=RND(128)-64:Y2=RND(96)-48 21 | 210 K$=INKEY$(0) 22 | 220 IF K$="Z" THEN PROCrotate(-20) 23 | 230 IF K$="X" THEN PROCrotate(20) 24 | 240 VDU 25,70,X1+128;Y1+96;25,70,X2+128;Y2+96; 25 | 250 SX(S%)=X2:SY(S%)=Y2 26 | 260 NEXT 27 | 270 UNTIL FALSE 28 | 280 : 29 | 290 DEF PROCrotate(a) 30 | 300 LET SA=SIN(a/180*PI) 31 | 310 LET CA=COS(a/180*PI) 32 | 320 XT=X2*CA-Y2*SA 33 | 330 Y2=X2*SA+Y2*CA 34 | 340 X2=XT 35 | 350 ENDPROC 36 | -------------------------------------------------------------------------------- /tests/tornado.bbc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/breakintoprogram/next-bbc-basic/506b604533a0bd121df5adc34fd4301b5cbcbba7/tests/tornado.bbc -------------------------------------------------------------------------------- /tests/triangles.bbc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/breakintoprogram/next-bbc-basic/506b604533a0bd121df5adc34fd4301b5cbcbba7/tests/triangles.bbc -------------------------------------------------------------------------------- /tests/udg.bbc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/breakintoprogram/next-bbc-basic/506b604533a0bd121df5adc34fd4301b5cbcbba7/tests/udg.bbc --------------------------------------------------------------------------------