Last active
April 18, 2024 15:02
-
-
Save PigDogBay/a2bdfac0181382906e46ea7450d83752 to your computer and use it in GitHub Desktop.
NextBASIC Crib Sheet, Wikitext markup
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
__NOTOC__ | |
Notes on the Sinclair ZX Spectrum Next [[Retro Gaming]], [[ZX Spectrum]], [[Z80 Assembly Language]] | |
==Next BASIC== | |
===Editor=== | |
EXTEND MODE, CAPSLOCK - Start of program<br/> | |
EXTEND MODE, GRAPHICS - End of program | |
<pre> | |
ERASE 100,200 ;Erase lines 100 to 200 | |
LINE 100,2 ;Renumbers lines from 100 in steps of 2, 100, 102, 104, 106... | |
LINE MERGE 20,40 ;Moves lines 20-40 all onto line 20 | |
BANK n LINE first,last ;Copy lines to Bank | |
</pre> | |
To disable the BREAK key (and Scroll? breaking) and prevent the user accessing the editor, set bit 1 of NextBASIC's %CODE variable: | |
<pre> | |
%CODE = %CODE | 2 ;Disables BREAK key, add to the start of your program | |
</pre> | |
===Variables=== | |
Only 26 Integer variables %a to %z | |
<pre> | |
%x,%y = 16,12 ;unsigned 16bit | |
result2 = 1.75 ;40bit (4 bytes mantissa, 1 byte exponent) | |
name$ = "string var" | |
n = 1.75 ;This is not %n | |
bonus = 1000+(%w*50) ;Cast int to float () | |
%s = %INT {bonus} | |
</pre> | |
===Arrays=== | |
<pre> | |
DIM prices(10) | |
prices(1) = 1.42 ;First Index | |
prices(10) = 9.99 ;Last Index | |
DIM names$(20,32) ;20 strings of length 32 chars | |
names$(1) = "Pig Dog Bay" | |
; Integer arrays are already predefined, %a[] to %z[] each with 64 elements | |
; Use () for indices 0-63 | |
%m(63) = 999 | |
;Use [] to extend across multiple sequential integer arrays | |
%d[64] = 42 ;Same as %e(0) = 42 | |
%a[1663] = 88 ;Same as %z(63) = 88, 1663 = 26 * 64 -1 | |
</pre> | |
===Decisions=== | |
<pre> | |
IF answer=42 THEN PRINT "What is the question?" | |
IF %x=10 THEN %x=0: ELSE %x+=1 | |
10 IF a$="spectrum" : PRINT "Good" | |
20 ELSE IF a$="commodore" : PRINT "Bad" | |
25 PRINT "and Ugly!" | |
30 ELSE PRINT "Try again" | |
40 ENDIF | |
;Jump to statement | |
ON x : GO TO 1000 : GO TO 2000 : PRINT "x is 2" : ELSE PRINT "else is optional" | |
;Select expression | |
PRINT n?("n is 0", "n is 1", "n is >1") | |
;Need to use brackets with AND | |
IF %g=19 AND (i>200) THEN SPRITE %g,%i,32,%2,%1 | |
</pre> | |
===Loops=== | |
<pre> | |
FOR %I=0 TO 10 STEP 2 | |
PRINT %I //0,2,4,6,8,10 | |
NEXT %I | |
REPEAT | |
INPUT n | |
IF n=42 THEN EXIT 300 //EXIT will jump to line 300 | |
REPEAT UNITL n<100 | |
REPEAT | |
INPUT n | |
WHILE n>=0. //stay in loop if true | |
WHILE n<100 | |
REPEAT UNTIL 0 //Loop forever as 0 = false | |
</pre> | |
===Structure=== | |
<pre> | |
;Use labels instead of line numbers | |
10 GO TO @setUpGame | |
1000 @setUpGame : PRINT "Setting Up" | |
10 GOSUB 100 | |
90 STOP | |
100 REM Subroutine | |
110 RETURN | |
</pre> | |
Procedure Args are pass by value, unless using REF. Args are also local. | |
<pre> | |
PROC double(42) TO %a | |
DEFPROC double(%x) | |
LOCAL %a | |
%a = %x * 2 | |
ENDPROC = %a | |
</pre> | |
Multiple return values | |
<pre> | |
PROC getTime() TO h,m,s | |
DEFPROC getTime() | |
LOCAL a$ = TIME$ | |
LOCAL h=VAL(a$(12 TO 13)) | |
LOCAL m=VAL(a$(15 TO 16)) | |
LOCAL s=VAL(a$(18 TO )) | |
ENDPROC = h,m,s | |
</pre> | |
<pre> | |
DEF FN sq(x)=x*x | |
</pre> | |
===READ, DATA, RESTORE=== | |
<pre> | |
40 RESTORE 1000 | |
50 READ %i,name$ | |
1000 DATA 42,"ZX Next" | |
;Labels also work | |
RESTORE @WaveData | |
</pre> | |
===PRINT / INPUT=== | |
AT is Y(0-21),X(0-31), POINT is X,Y. For layer 2 you can print at the bottom of the screen normally reserved for INPUT, POINT AT Y(0-23),X(0-31). | |
<pre> | |
PRINT "Col 1","Col 2" | |
PRINT "Toge";"ther" | |
PRINT "New"'"Line" | |
PRINT AT 22,31;"*" ;Prints * bottom right | |
LAYER 1,1: PRINT POINT 248,176;"*" | |
;Fixed width spacing | |
PRINT "Name";TAB 8;"Score";TAB 8;"Rank" | |
INPUT "What is your name? ";name$ | |
INPUT LINE a$ ;Removes quotes | |
5 REM Handling key presses | |
10 IF INKEY$ <> "" GO TO 10 ;Wait for user to release key | |
20 IF INKEY$ = "" GO TO 20 ;Wait for user to press key | |
30 PRINT INKEY$ | |
40 GOTO 10 | |
REM n=0 Keyboard Joystick, n=1 Joystick 1, n=2 Joystick 2 | |
%p = INPUT n ;Bits: 3210udlr (fire buttons bits 4-7) | |
</pre> | |
===Random=== | |
<pre> | |
%r = %RND 100 ;fast random integer 0-99 - no casting | |
%r = INT(RND * 100) ;Casting Float to Int, slow | |
myRand = RND * 100 ;0 to 99.999999 | |
myRand = RND(100) ;0 to 99 real values rounded to nearest whole number | |
RANDOMIZE ;Pick a random seed | |
RANDOMIZE seed ;Seed 1-65535, 0 - random | |
; NextBASIC's %CODE bit 0 can change RND's behaviour: | |
%CODE = 0 ;%RND n and RND(n) return values 0..n-1 | |
%CODE = 1 ;%RND n and RND(n) return values 0..n | |
</pre> | |
===Timing=== | |
<pre> | |
PAUSE n ;n 1/50th second (when in for 50Hz display mode) | |
;TIME reads System var FRAMES which increase every 1/50s | |
start = TIME | |
PRINT "Time taken: ";(TIME-start) | |
TIME$ ;Returns RTC string 2024-01-3 10:55:47 | |
;Update RTC with network time | |
.nxtp time.zx.in.net 12300 -z=UTC | |
</pre> | |
===Expressions=== | |
% at the beginning denotes integer expression | |
<pre> | |
;Modulo | |
%17 MOD 6 ;Returns 5 | |
;Bitwise Operators | |
%!$f ;NOT returns $fff0 | |
%x & $0f ;AND use $ for hexadecimal | |
%x | BIN 01001100 ;OR use @ or BIN for binary notation | |
%x << 2 ;Shift right 2 places (mul by 4) | |
%x >> 4 ;Shift left 4 places (div by 16) | |
%x ^| $y ;XOR (^ is like an up arrow character on the speccy) | |
;Logical | |
x AND y ;Gives 0 if y is zero, x if y non-zero | |
x OR y ;Gives x if y is zero, 1 if y non-zero | |
NOT x ;0->1, non-zero->0 | |
%1 + RND 6 ;Random integer 1-6 | |
%i = -42 ;Integers are unsigned, %i is 65494 (2's complement) | |
PRINT %SGN {i} ;Cast unsigned integer to signed integer | |
</pre> | |
===Strings=== | |
<pre> | |
"abcdefg"(2 To 4) ;Gives "bcd" | |
"abcdefg"( TO 5) ;Gives "abcde" | |
"abcdefg"(3 TO) ;Gives "cdefg" | |
a$(5 TO 8) = "****" | |
"abc"+"def" | |
"abc"*2 | |
"abc"*-1 ;Reverse string | |
"abcdef"*0.5 ;Gives "abc" | |
</pre> | |
====Modifiers==== | |
String$[modifiers] | |
<pre> | |
;+ Lower case, - upper case, < strip leading spaces, > strip trailing spaces | |
" Hello There! "[<+->] | |
Result: "hELLO tHERE!" | |
</pre> | |
====Tokenisation==== | |
<pre> | |
{"sin (pi/4)"} ;Gives "SIN(PI/4)" using BASIC tokens | |
VAL{"sin (pi/4)"} ;Gives 0.7071 | |
i=VAL(a$) ;Convert string to number | |
</pre> | |
==Graphics== | |
===Layers=== | |
Origin - Top Left, except Layer 0 - Origin Bottom Left. Note that layer 3 is not yet supported in BASIC. | |
<pre> | |
Layer Pixels Colours Scheme Name | |
0 256x192 15 32x24 cells Standard Spectrum(ULA) | |
1,0 128x96 256 per pixel LoRes (EnhancedULA) | |
1,1 256x192 256 32x24 cells StandardRes (EnhancedULA) | |
1,2 512x192 256 monochrome Timex HiRes (EnhancedULA) | |
1,3 256x192 256 32x192 cells Timex HiColour (EnhancedULA) | |
2,0 - Disable layer 2 | |
2,1 256x192 256 per pixel RRRGGGBB Colour - | |
2,2 320x256 256 per pixel - PALETTE has no effect - | |
2,3 640x256 16 per pixel - in layer 2 | |
3,0 320x256 256 40x32 cells Text Mode | |
3,1 640x256 256 80x32 cells Text Mode | |
3,2 320x256 256 40x32 cells Graphics Mode - 16 colours per cell | |
3,3 640x256 256 80x32 cells Graphics Mode - 16 colours per cell | |
</pre> | |
====Commands==== | |
<pre> | |
LAYER 0 ;Default layer | |
LAYER 2,0 ;Disable layer 2 | |
LAYER CLEAR | |
LAYER OVER order | |
LAYER ERASE x1,y1,x2,y2,c ;c is optional, default is transparency colour | |
LAYER DIM x1,y1,x2,y2 ;Set clipping window | |
LAYER AT x,y ;Move layer, layer will wrap, good for scrolling background | |
</pre> | |
===Colours=== | |
0-Black, 1-Blue, 2-Red, 3-Magenta, 4-Green, 5-Cyan, 6-Yellow, 7-White | |
<pre> | |
BORDER, PAPER, INK, BRIGHT, FLASH | |
INVERSE 1 ;Swaps INK and PAPER | |
OVER 1 ;XOR mode for text | |
ATTR line,col ;Get attribute value for the cell | |
;Palettes are a table of colour values for EnhancedULA layers | |
;B bit: RRRGGGBB | |
;9 bit: R RRGGGBBB | |
;9 bit palettes require 2 bytes per colour | |
PALETTE DIM bits ;8 or 9 | |
PALETTE FORMAT inkCount ;0,1,3,7,15,31,63,127 or 255 | |
PALETTE FORMAT 0 ;Disable enhanced ULA, normal colour mode | |
PALETTE CLEAR ;Resets all palettes | |
PALETTE OVER value ;Transparency: value - RRRGGGBB (8 bit), index (9 bit) | |
;Select palette 0 or 1 | |
LAYER PALETTE num | |
;Load a bank into the palette | |
LAYER PALETTE num BANK bank,offset ;num = 0,1 select palette table, BANK | |
;Update single palette value | |
LAYER PALETTE num, index, val ;Write a val at index into layer palette num | |
</pre> | |
===Sprites=== | |
====Loading==== | |
<pre> | |
BANK NEW bankId | |
LOAD "spaceship.spr" BANK bankId | |
SPRITE CLEAR ;Clear out any old data | |
SPRITE BANK bankId ;Pass in the sprite patterns | |
</pre> | |
====Display==== | |
<pre> | |
SPRITE PRINT 1 ;1-Enable, 0-Disable sprites | |
SPRITE BORDER 1 ;Display over border, 0 behind | |
SPRITE s,x,y,p,f,rf,mx,my ;Display sprite, s - sprite id, p - pattern, f - flags, rf - relative flags, mx/my scaling 0(1x),1(2x),2(4x),3(8x) | |
;Flags | |
;Bit 0 - 0 invisible, 1 visible | |
;Bit 1 - 1 rotate clockwise by 90 | |
;Bit 2 - Vertical mirror | |
;Bit 3 - Horizontal mirror | |
@1101 - Rotate 180, mirror X+Y | |
@1111 - Rotate 270 clockwise | |
;Relative Flags | |
;Bit 0 - 0 Composite, 1 Relative (Anchor sprite only) | |
;Bit 1 - Pattern is relative to the acnhor | |
;Bit 2 - Palette offset is relative to the acnhor | |
</pre> | |
====Animation==== | |
Smoothly animate and move sprites by batching updates and sync'ing with display redraw | |
<pre> | |
;Animate by changing pattern number | |
;However updating sprites immediately gives flicker and tear | |
SPRITE 0,152,119,0,1 | |
SPRITE 0,152,119,1,1 | |
;Turn off immediately displaying sprite updates from SPRITE cmd | |
;Now in batch mode | |
SPRITE STOP | |
;Update Sprite | |
SPRITE 0,%x,%y,0,1 ;Update x and y | |
;Display sprite updates but wait for 50Hz interrupt | |
;This makes sprite updates smoother | |
SPRITE MOVE INT y ;y optional scanline | |
;To disable batch mode | |
SPRITE RUN | |
</pre> | |
====Automatic Movement==== | |
Instead of updating the sprite position, specify co-ords to move between. Here the sprite will move x 0 to 200, then 200 to 0 forever | |
<pre> | |
;Parameters are optional, can skip ,, | |
SPRITE CONTINUE | |
s, ;must specify sprite ID | |
x1 TO x2 STEP xs RUN, ;x1 min value, x2 max value (x1<x2) | |
y1 TO y2 STEP ys STOP, | |
p1 to p2, ;Pattern animation | |
f, ;Flags see below | |
r, ;Rate: 0 every SPRITE MOVE, 1 every other, 2 skip two ...255 | |
d ;Delay: 0 - none, 1 skip 1 SPRITE MOVE, 2 skip 2 ...255 | |
Flags Bits | |
1:0 00 reflect, 01 stop this direction start other direction,10(2) - Stop this direction, 11(3) stop and invisibile | |
2 Flip Y mirror bit when Y limits reached | |
3 Flip X mirror bit when X limits reached | |
4 Pattern, 0 - wrap to lower limit, 1 - bounce between limits | |
5 1 - disable when reaches limits | |
6 1 - update pattern even when stationary | |
7 1 - Set mirror bits according to direction of travel | |
;Clearer to split the parameters over several calls instead of one huge command | |
SPRITE CONTINUE 0,0 TO 200 STEP 1 RUN. ;Set up X | |
SPRITE CONTINUE 0,,0 TO 192 STEP 1 STOP ;Set up Y | |
SPRITE CONTINUE 0,,,,@0001 ;Set up Flags, follow a rectangular route | |
SPRITE MOVE INT ;Repeatedly call this | |
SPRITE PAUSE s1 [TO s2] | |
SPRITE CONTINUE s1 [TO S2] | |
</pre> | |
====Status==== | |
<pre> | |
%f = SPRITE CONTINUE s ;bit 0: auto enabled, bit 1: moving y axis, bit 2: moving x axis | |
% SPRITE s ;1 sprite is visible, 0 invisible | |
%v = SPRITE AT(s,n) ; n = 0: x co-ord, 1: y co-ord, 2: pattern, 3: x step, 4: y step, 5: delay | |
;If the sprite is smaller than its bounding box 16x16, use overlap, 0-7 | |
;Returns 0 - no collision, or sprite ID if there is a collision | |
SPRITE OVER (s1, s2 [TO s3] [,xOverlap, yOverlap]) | |
</pre> | |
==Files== | |
Drives c: boot, m: ramdisk, t: tape | |
===SAVE & LOAD=== | |
<pre> | |
LOAD"t:" ;Load from tape | |
SAVE "m:" ;Doesn't save anything but selects drive m, RAM disk | |
SAVE "test.scr" SCREEN$ ;Save layer 0 pixels+attr | |
LOAD "test.scr" SCREEN$ | |
SAVE "test.scr" LAYER ;Saves current layer data (but not palette table) | |
SAVE "test.scr" LAYER 0 ;Same as SCREEN$ | |
LOAD "test.scr" LAYER ;Loads data into current layer | |
DIM a(100) | |
SAVE "array.arr" DATA a() ;Save array | |
SAVE "int.arr" INT ;Save all integer array values | |
LOAD "array.arr" DATA x() ;Loads array, no need to DIM beforehand | |
LOAD "int.arr" INT ;Load all integer array values | |
LOAD "test.scr" BANK 5 ;Layer 0 is located bank 5 | |
LOAD "test.scr" BANK 5, 0, 6144 | |
LOAD "test.scr" CODE 16384, 6144 | |
MERGE "utils.bas" ;Will overwrite if same line number | |
VERIFY "program.bas" ;Verify tape program | |
</pre> | |
===Commands=== | |
Recommend use command line with more columns | |
<pre> | |
CAT ;Display contents of directory (also DIR and LS) | |
CAT EXP ;Filename, flags, date (last updated), size | |
CAT "c:/home/*.bas" | |
CAT TAB ;List storage devices | |
CAT ASN ;Show drive assignments | |
.ls ;.ls --help for more options | |
.lstap san*.tap ;Info about a TAP file | |
mkdir "tmp" ;Also .mkdir | |
rmdir "tmp" | |
cd "tmp" | |
.cd .. ;.cd doesn't require quotes | |
pwd ;Print working directory | |
COPY "c:/*.bas" TO "m:" | |
MOVE "screen.sl2" TO "title.sl2" | |
ERASE "tmp.bas" | |
</pre> | |
===Attributes=== | |
<pre> | |
MOVE "nexions.bas" TO "+p" ;Write protect | |
MOVE "nexions.bas" TO "-p" ;Remove write protect | |
MOVE "system.bin" TO "+s" ;Hide file in CAT listing, will show in CAT EXP | |
.chmod --help ;Similar functionality, see help | |
</pre> | |
===Channels and Streams=== | |
0-15 Channels, 0-3 are used by the system, 0,1 Input, 2 screen, 3 printer | |
<pre> | |
;Write a file | |
OPEN #4,"i>/home/tmp.txt" ;u> Appends to the file | |
PRINT #4;"Hello World" | |
CLOSE #4 | |
;Read a file | |
OPEN #4,"o>/home/tmp.txt" | |
DIM #4 TO %s ;Size of file | |
FOR %i=0 TO %s-1 | |
NEXT #4 TO %x ;Read byte, also %x=NEXT #4 | |
PRINT CHR$(x); | |
NEXT %i | |
CLOSE #4 | |
;Quick version of the above | |
COPY "/home/tmp.txt" TO #2 ;Outputs the file to the screen | |
;Change Position | |
GOTO #n, pos | |
</pre> | |
Best practice is to close a stream before opening and use ON ERROR to close as well | |
====Other Streams==== | |
Here we temporarily redirect screen output to a string var | |
<pre> | |
DIM t$(100) | |
OPEN #2,"v>t$" | |
.time | |
CLOSE #2 ;Hand channel back to the system | |
;Send text file to string var | |
COPY "/home/tmp.txt" TO #4 | |
</pre> | |
Memory Streams | |
<pre> | |
CLEAR 29999 | |
OPEN #8,"m>30000,1000" | |
COPY "/home/tmp.txt" TO #8 | |
</pre> | |
==Ports== | |
Display mouse X,Y,Wheel+Buttons | |
<pre> | |
PRINT AT 0,0;IN 64479;",";IN 65503;",";IN 64223;" " | |
</pre> | |
===IN OUT=== | |
<pre> | |
IN 254 ;Read port 254 | |
OUT 254,$d4 ;BEEPER on/off bit | |
</pre> | |
===Next Registers=== | |
<pre> | |
REG 20 ;Returns global transparency colour (default 227) | |
REG 20,42 ;Set GTC | |
;9275 - NextReg Select | |
;9531 - NextReg Value | |
OUT 9275,20: OUT 9531,42 ;Same as REG 20,42 | |
</pre> | |
==Memory== | |
<pre> | |
POKE USR "a",0,1,2,3,4,5,6,7 ;UDG A | |
POKE $4000,"Hello World",13 ;Poke takes multiple params: address, val1...valn | |
a$ = PEEK$($4000,~13) ;Read string until terminator 13 (CR) | |
DPOKE $4000, $FF02 ;Pokes 02 at $4000, then $FF at $4001 | |
;Memory above RAMTOP is protected from being cleared, | |
;eg safely store data/machine code above RAMTOP | |
CLEAR 30000 ;Clear + Sets RAMTOP to 30000 | |
</pre> | |
===Banks=== | |
Next BASIC using 16K banks, whilst NextZXOS uses 8K. | |
<pre> | |
BANK NEW b ;Reserve an available bank, b | |
BANK b CLEAR ;Release bank b | |
BANK 100 COPY TO 90 ;Copy contents of 1 bank to another | |
BANK src_bank COPY [,src_off,len] TO dest_bank[,dest_off] | |
BANK 100 ERASE ;Fill bank 100 with 0's | |
BANK n ERASE [offset,len][,][value] | |
</pre> | |
===Banking Code=== | |
From the prompt/command line (NOT CODE) | |
<pre> | |
BANK n LINE x,y ;Copy lines x to y to bank n | |
BANK n LIST ;List code in bank | |
BANK n LIST PROC name() ;List code in proc | |
SAVE "name.bnk" BANK n ;Save the code in the bank | |
</pre> | |
From code | |
<pre> | |
BANK NEW %b | |
LOAD "utils.bnk" BANK %b ;Load code into bank | |
BANK %b PROC timer() | |
BANK %b GO TO 500 | |
BANK %b RESTORE | |
BANK %b CLEAR ;Release bank when finished | |
</pre> | |
==Links== | |
*[https://www.specnext.com/ Home / Forum]<br/> | |
*[https://zxnext.uk/ GeTiT]</br> | |
*[https://wiki.specnext.dev/ Wiki]<br/> | |
*[https://www.facebook.com/groups/specnext Facebook Group] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment