The other day i showed you how to get Cspect working from Visual Studio code and how run and debug your code.
If you missed that tutorial it can be found here.
Well during my step into exploring the Spectrum next I came across quite a few sources that had good code, but they were a little difficult to read and it took some time to strip out some of the basics to do what I needed.
And to be fair the book that comes with the Next is awesome at teaching basic programming but for me the print is too small for the IN-OUT and the next registers section, but hey I am now 60 years old so maybe it’s my eyes. ?
Anyhow here is some more code for you to play with which has been added to the last load of code just because its easier.
OCD
Oh before we get to the code, I have an admission to make, I am a bit OCD as far as my code layout is concerned therefore I like everything lined up and I use Tabs rather than spaces,
Therefore if you are like me and want cleaner looking code then maybe you should add these settings to the bottom of your Visual Studio code workspace file.
"settings": { "C_Cpp.formatting": "vcFormat", "editor.tabSize": 10, "editor.insertSpaces": false }
My complete workspace file
{ folders": [ { "name": ".vscode", "path": "Source//.vscode" }, { "name": "Source", "path": "Source" }, { "name": "Assets", "path": "Assets" } ], "settings": { "C_Cpp.formatting": "vcFormat", "editor.tabSize": 10, "editor.insertSpaces": false } }
So what’s the point of this code?
This code does several things, it puts a sprite on the screen, uploads the palette to the sprites bank and is heavily commented so you should be able to read it. As its written in long hand, rather than using faster code and macros its been written to teach rather than impress.
This ports mentioned in the code come from the documentation, which can be found here https://www.specnext.com/tbblue-io-port-system/
Enjoy.
main.asm
// no copyright patricia dot curtis at luckyredfish.com //------------------------------------------------------------------------------------------------------- // // compiler directives so when compiled it saves the executable in borders.nex and runs from StartAddress // //------------------------------------------------------------------------------------------------------- SAVENEX OPEN "..\\Output\\mario.nex", StartAddress SAVENEX CORE 3, 0, 0 // Next core 3.0.0 required as minimum SAVENEX CFG 0 OPT --zxnext // tell the assembler we want the Spectrum Next instructions DEVICE ZXSPECTRUMNEXT // Compile for the Spectrum next device ORG 0x8000 // start address for this block of code //define the space for the stack StackEnd: ds 127 StackStart: db 0 StartAddress ld a,0 // select sprite 0 ld bc, $303b // get the port in the b,c register out (c),a // send the zero to port 0x303b to select the sprite ld bc, $57 // sprite atribute port for the selected sprite // Auto incrementing pointer so we dont have to keep setting $303b // Sprite Attribute 0 // bits 7-0 = LSB of X coordinate ld a,50 // x position out (c),a // send the x position to attribute 0 via port $57 // Sprite Attribute 1 // bits 7-0 = LSB of Y coordinate ld a,100 // y position out (c),a // send the y position to attribute 1 via port $57 // Sprite Attribute 2 // bits 7-4 = Palette offset added to top 4 bits of sprite colour index // bit 3 = X mirror // bit 2 = Y mirror // bit 1 = Rotate // bit 0 = MSB of X coordinate ld a,0 // no rotation and mirroring , no palette offset out (c),a // send the y position to attribute 2 via port $57 // Sprite Attribute 3 // bit 7 = Visible flag (1 = displayed) // bit 6 = Extended attribute (1 = Sprite Attribute 4 is active) // bits 5-0 = Pattern used by sprite (0-63) ld a,192 // sprite pattern zero and visible (128) and activate Attribute 4 (64) out (c),a // attribute 3 via port $57 // Sprite Attribute 4 // bit 7 = H (1 = sprite uses 4-bit patterns) // bit 6 = N6 (0 = use the first 128 bytes of the pattern else use the last 128 bytes) // bit 5 = 1 if relative sprites are composite, 0 if relative sprites are unified // Scaling // bits 4-3 = X scaling (00 = 1x, 01 = 2x, 10 = 4x, 11 = 8x) // bits 2-1 = Y scaling (00 = 1x, 01 = 2x, 10 = 4x, 11 = 8x) // bit 0 = MSB of Y coordinate ld a,0 // sprite pattern zero and visible (0) out (c),a // send the y position to attribute 3 via port $57 // turn on all sprites ld bc, $243b // select register on TBBlue features ld a, $15 // Enables/disables Sprites and low-res Layer, and chooses priority of sprites and Layer 2. out (c), a // using access the port ld bc, $253b // now access the register we set $15 ld a, 1 // all sprites visible out (c), a // and send it //tell the machine we will be sending sprite data ld bc, $303b // get the port in the b,c register ld a,0 // select sprite zero we are writing too out (c),a // send the zero to port 0x303b to select the sprite // copy the sprite data ld hl,mario0 // get the sprite data ld c,$5b // copy sprite data to through register $5B ld b,0 // do a 256 bytes which is 0 this and the prevous like could be bc,$005b otir // send that // tell the machine we will copy the palette one element at a time ld bc,$243b // port to select zx next register ld a,$43 // register number, palette control out (c),a // bit 7 = ‘1’ to disable palette write auto-increment. // bits 6-4 = Select palette for reading or writing: // 000 = ULA first palette // 100 = ULA second palette // 001 = Layer 2 first palette // 101 = Layer 2 second palette // 010 = Sprites first palette // 110 = Sprites second palette // 011 = Tilemap first palette // 111 = Tilemap second palette // bit 3 = Select Sprites palette (0 = first palette, 1 = second palette) // bit 2 = Select Layer 2 palette (0 = first palette, 1 = second palette) // bit 1 = Select ULA palette (0 = first palette, 1 = second palette) // bit 0 = Enabe ULANext mode if 1. (0 after a reset) ld bc,$253b // port to access pallet selection register // 76543210 ld a,%00100000 // Select sprites first palette out (c),a ld bc, $243b // tbblue port again ld a, $40 // Chooses an palette element (index) to manipulate with out (c), a ld bc, $253b // tell it we are going to be starting with ld a, 0 // we are starting with palette element 0 out (c), a // yup send it ld bc, $243b // tbblue port yet again ld a, $41 // next we will be sending the value of the colour out (c), a ld de,marioPalette // get the a pointer to the palette data ld h,marioColours // do the number of colours times Docolours: ld bc,$253b // write to the port ld a,(de) // get the colour from the palette array out (c),a // send the colour to the register inc de // next element in the array dec h // decrement the amount of colours left to do ld a,-1 // last colour check cp h // have we done all the colours? jp nz,Docolours // nope next colour // now set the Transparency index for sprites ld bc, $243b // tbblue port again ld a, $4b // choose the transparency index register for sprites out (c), a ld bc, $253b // tell it the index ld a, 0 // setting the transparency index to palette element 0 out (c), a // yup send it //------------------------------------- // end of sprite and palette test code //------------------------------------- MainLoop: ld a,4 // black border out ($fe),a // set next border colour port $fe with the value of the accumulator which is 0 // Here DE counts down and D and E are OR-ed to check if the loop has completed. ld de,300 // loop for 1000 times just wasting cycles Loop1: dec de // take 1 off the 1000 ld a,d // move it to a register we can or with or e // or with e to set the flags jp nz,Loop1 ld a,2 // change this for different colours out ($fe),a // set next border colour with the value of the accumulator which is 1 ld de,100 // do another loop wasting more cycles , this time larger band Loop2: dec de ld a,d or e jp nz,Loop2 jp MainLoop // do the whole thing black and blue again and again //end start ORG 0x4000 // change agdress to $4000 include "includes\mario.asm" // add my sprites to the new bank SAVENEX AUTO // Save every 16k bank with data in it SAVENEX CLOSE // close the compiled file so we can either run it or debug it
mario.asm below
You will notice that the palette is laid out in binary with comments showing the 24 bit palette colours, I did this so you can maybe understand how it works.
// Created by NextGraphics.exe on Friday, 25 September 2020 @ 14:10:22 marioColours: equ 149 // RRRGGGBB marioPalette: db %11100011 // Colour 00 is $e3 = 255,0,255 db %10000001 // Colour 01 is $81 = 157,13,21 db %01100000 // Colour 02 is $60 = 140,0,0 db %01100000 // Colour 03 is $60 = 143,0,0 db %01100000 // Colour 04 is $60 = 135,0,0 db %10000001 // Colour 05 is $81 = 152,0,8 db %10000101 // Colour 06 is $85 = 150,37,36 db %10000000 // Colour 07 is $80 = 167,5,0 db %10000001 // Colour 08 is $81 = 177,7,6 db %10100001 // Colour 09 is $a1 = 182,7,4 db %10100001 // Colour 0a is $a1 = 182,8,4 db %10100001 // Colour 0b is $a1 = 186,10,3 db %10100001 // Colour 0c is $a1 = 187,21,17 db %10000001 // Colour 0d is $81 = 151,32,42 db %10000101 // Colour 0e is $85 = 152,39,50 db %01101001 // Colour 0f is $69 = 138,106,18 db %01101001 // Colour 10 is $69 = 125,103,3 db %10001101 // Colour 11 is $8d = 156,118,19 db %11001101 // Colour 12 is $cd = 218,123,4 db %11001101 // Colour 13 is $cd = 216,121,4 db %01101001 // Colour 14 is $69 = 136,101,4 db %10101000 // Colour 15 is $a8 = 203,107,0 db %10001101 // Colour 16 is $8d = 159,138,50 db %11010001 // Colour 17 is $d1 = 223,144,4 db %01101101 // Colour 18 is $6d = 138,128,19 db %10110001 // Colour 19 is $b1 = 209,149,8 db %11110000 // Colour 1a is $f0 = 254,166,0 db %11010001 // Colour 1b is $d1 = 242,155,2 db %01101101 // Colour 1c is $6d = 123,108,13 db %11010001 // Colour 1d is $d1 = 228,152,5 db %11110001 // Colour 1e is $f1 = 255,179,35 db %11110101 // Colour 1f is $f5 = 255,181,42 db %01001000 // Colour 20 is $48 = 102,83,0 db %10101000 // Colour 21 is $a8 = 183,98,0 db %01101001 // Colour 22 is $69 = 114,94,16 db %01101001 // Colour 23 is $69 = 116,96,15 db %11110000 // Colour 24 is $f0 = 253,154,0 db %11110000 // Colour 25 is $f0 = 255,159,0 db %10101101 // Colour 26 is $ad = 191,121,8 db %01101101 // Colour 27 is $6d = 133,116,20 db %10101100 // Colour 28 is $ac = 190,114,0 db %10101000 // Colour 29 is $a8 = 207,102,0 db %11001101 // Colour 2a is $cd = 217,139,31 db %01101101 // Colour 2b is $6d = 112,109,58 db %01001001 // Colour 2c is $49 = 107,90,25 db %10101101 // Colour 2d is $ad = 198,120,7 db %10101101 // Colour 2e is $ad = 204,129,5 db %11110000 // Colour 2f is $f0 = 255,154,0 db %11110000 // Colour 30 is $f0 = 255,153,0 db %01101001 // Colour 31 is $69 = 135,102,14 db %01001001 // Colour 32 is $49 = 88,90,18 db %01001000 // Colour 33 is $48 = 93,74,0 db %01101001 // Colour 34 is $69 = 110,94,25 db %11001101 // Colour 35 is $cd = 223,137,22 db %11001100 // Colour 36 is $cc = 224,119,0 db %10101101 // Colour 37 is $ad = 213,135,5 db %11001101 // Colour 38 is $cd = 216,133,5 db %10101101 // Colour 39 is $ad = 198,121,5 db %10101001 // Colour 3a is $a9 = 198,107,1 db %10101101 // Colour 3b is $ad = 205,139,33 db %01101101 // Colour 3c is $6d = 138,134,54 db %01101101 // Colour 3d is $6d = 132,122,32 db %10010001 // Colour 3e is $91 = 148,150,62 db %10001101 // Colour 3f is $8d = 149,115,25 db %10100001 // Colour 40 is $a1 = 205,23,3 db %10001001 // Colour 41 is $89 = 148,98,18 db %01101101 // Colour 42 is $6d = 120,137,25 db %01101101 // Colour 43 is $6d = 130,111,5 db %10000101 // Colour 44 is $85 = 151,39,9 db %11110001 // Colour 45 is $f1 = 255,167,23 db %11010001 // Colour 46 is $d1 = 246,155,20 db %01001000 // Colour 47 is $48 = 100,77,0 db %01001000 // Colour 48 is $48 = 76,72,0 db %01001001 // Colour 49 is $49 = 79,95,3 db %01101101 // Colour 4a is $6d = 116,115,21 db %10100001 // Colour 4b is $a1 = 191,1,5 db %10000001 // Colour 4c is $81 = 178,0,5 db %01001001 // Colour 4d is $49 = 100,84,18 db %01001001 // Colour 4e is $49 = 86,96,17 db %01000101 // Colour 4f is $45 = 102,63,16 db %01100001 // Colour 50 is $61 = 141,29,42 db %01101001 // Colour 51 is $69 = 134,101,23 db %10101101 // Colour 52 is $ad = 193,133,12 db %11001101 // Colour 53 is $cd = 228,137,21 db %11010001 // Colour 54 is $d1 = 250,150,8 db %11001100 // Colour 55 is $cc = 249,133,0 db %10101000 // Colour 56 is $a8 = 213,105,0 db %10101101 // Colour 57 is $ad = 213,139,38 db %01001101 // Colour 58 is $4d = 104,111,52 db %01001001 // Colour 59 is $49 = 91,74,2 db %10100001 // Colour 5a is $a1 = 180,12,5 db %10100001 // Colour 5b is $a1 = 200,2,2 db %10100001 // Colour 5c is $a1 = 180,8,4 db %10100001 // Colour 5d is $a1 = 201,9,3 db %10100001 // Colour 5e is $a1 = 202,12,1 db %01001001 // Colour 5f is $49 = 92,88,18 db %01101001 // Colour 60 is $69 = 112,104,18 db %10101100 // Colour 61 is $ac = 201,113,0 db %11001100 // Colour 62 is $cc = 226,125,0 db %10101101 // Colour 63 is $ad = 215,123,7 db %10101101 // Colour 64 is $ad = 214,132,22 db %10100001 // Colour 65 is $a1 = 185,33,29 db %10000000 // Colour 66 is $80 = 169,2,0 db %10100001 // Colour 67 is $a1 = 190,17,4 db %10101001 // Colour 68 is $a9 = 208,104,4 db %10100001 // Colour 69 is $a1 = 200,17,3 db %10100001 // Colour 6a is $a1 = 200,0,2 db %10100000 // Colour 6b is $a0 = 200,0,0 db %10101001 // Colour 6c is $a9 = 207,107,10 db %10001101 // Colour 6d is $8d = 147,133,45 db %10100101 // Colour 6e is $a5 = 195,44,45 db %10100000 // Colour 6f is $a0 = 192,0,0 db %10100001 // Colour 70 is $a1 = 195,0,3 db %10000000 // Colour 71 is $80 = 175,0,0 db %10000000 // Colour 72 is $80 = 146,4,0 db %10000000 // Colour 73 is $80 = 172,0,0 db %10100000 // Colour 74 is $a0 = 180,0,0 db %10000001 // Colour 75 is $81 = 178,2,2 db %10000001 // Colour 76 is $81 = 164,21,2 db %10100101 // Colour 77 is $a5 = 202,46,48 db %10001101 // Colour 78 is $8d = 159,131,52 db %01101101 // Colour 79 is $6d = 124,134,33 db %10000101 // Colour 7a is $85 = 158,42,38 db %01100000 // Colour 7b is $60 = 138,0,0 db %10000000 // Colour 7c is $80 = 148,0,0 db %01100001 // Colour 7d is $61 = 143,4,5 db %01100001 // Colour 7e is $61 = 139,0,6 db %10000001 // Colour 7f is $81 = 147,4,6 db %10000001 // Colour 80 is $81 = 150,6,6 db %01100000 // Colour 81 is $60 = 137,0,0 db %10000000 // Colour 82 is $80 = 165,0,0 db %01101000 // Colour 83 is $68 = 110,74,0 db %01101101 // Colour 84 is $6d = 114,120,10 db %01101101 // Colour 85 is $6d = 137,133,41 db %01101000 // Colour 86 is $68 = 111,72,0 db %01100001 // Colour 87 is $61 = 141,11,2 db %10000001 // Colour 88 is $81 = 151,14,18 db %10000001 // Colour 89 is $81 = 146,14,15 db %10000001 // Colour 8a is $81 = 149,26,26 db %01100001 // Colour 8b is $61 = 138,4,4 db %10000001 // Colour 8c is $81 = 148,7,6 db %01001001 // Colour 8d is $49 = 98,76,6 db %01001001 // Colour 8e is $49 = 100,103,25 db %01001001 // Colour 8f is $49 = 97,90,13 db %01001000 // Colour 90 is $48 = 79,78,0 db %01101101 // Colour 91 is $6d = 133,111,29 db %01001001 // Colour 92 is $49 = 99,91,28 db %01001001 // Colour 93 is $49 = 78,80,6 db %01101101 // Colour 94 is $6d = 127,132,70 //mario0 is from frame 0 at position x=0 y=0 mario0: .db $00,$00,$00,$00,$00,$01,$02,$03,$04,$05,$00,$00,$00,$00,$00,$00 .db $00,$00,$00,$00,$06,$07,$08,$09,$0a,$0b,$0c,$0d,$0e,$00,$00,$00 .db $00,$00,$00,$00,$0f,$10,$11,$12,$13,$14,$15,$00,$00,$00,$00,$00 .db $00,$00,$00,$16,$17,$18,$19,$1a,$1b,$1c,$1d,$1e,$1f,$00,$00,$00 .db $00,$00,$00,$20,$21,$22,$23,$24,$25,$26,$27,$28,$29,$2a,$00,$00 .db $00,$00,$00,$2b,$2c,$2d,$2e,$2f,$30,$31,$32,$33,$34,$00,$00,$00 .db $00,$00,$00,$00,$00,$35,$36,$37,$38,$39,$3a,$3b,$00,$00,$00,$00 .db $00,$00,$3c,$3d,$3e,$3f,$40,$41,$42,$43,$44,$00,$00,$00,$00,$00 .db $45,$46,$47,$48,$49,$4a,$4b,$4c,$4d,$4e,$4f,$50,$51,$52,$53,$54 .db $55,$56,$57,$00,$58,$59,$5a,$5b,$5c,$5d,$5e,$03,$5f,$60,$61,$62 .db $63,$64,$00,$00,$65,$66,$67,$68,$69,$6a,$6b,$6c,$00,$00,$6d,$00 .db $00,$00,$00,$6e,$6f,$70,$71,$72,$73,$74,$75,$76,$77,$78,$79,$00 .db $00,$00,$7a,$7b,$73,$7c,$7d,$7e,$7f,$80,$81,$04,$82,$83,$84,$00 .db $00,$85,$86,$87,$88,$89,$00,$00,$00,$00,$8a,$8b,$8c,$8d,$8e,$00 .db $00,$8f,$90,$91,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 .db $00,$00,$92,$93,$94,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
Another nice article, keep ’em coming! 🙂
Great article with excellent notes. Really hope you expand on this. There’s very limited info on coding for an absolute newbie in machine code on the next and it has so many fab new features.
Many thanks
I haven’t started in on the speccy (next) yet, but will soon. Thanks for the head start!
Hello, great content. I have kickstarted Next Issue 2 and I am learning to code for the next with emulator. Now I have a question, you are using some ports in your code, like sprite port $303B, is there any refeence manual out there that lists all the existing ports and their addresses and what they do? Or how do you know that sprite 0 uses port address $303B?
BR
Jörgen Jönsson
Thank you for your kind words, all the ports information can be found here, https://www.specnext.com/tbblue-io-port-system/
Hi Patricia. Thanks for putting this together this bare-bones sprite sample – it is just what I was looking for. Great code, but I have spotted a few ways that might make it even simpler:
1. In quite a few places, the NEXTREG opcode coudl be used to set the Next Feature Control Registers without going through ports TBBlue Register Select ($243B / 9275) and then the TBBlue Register Access ($253B / 9531). See https://wiki.specnext.dev/Extended_Z80_instruction_set
2. The second write to Sprite Select port $303b is redundant. The first call sets both the attribute and pattern upload pointers, and they increment independently, so after uploading the attribute data the pattern data pointer is untouched and ready to use. https://wiki.specnext.dev/Sprite_Status/Slot_Select
3. The palette colour loop can be simplified with the djnz instruction using the B register as the implicit loop index.
Thanks for the feedback, Yes I know NEXTREG could be used and the code is not optimal but as I stated in the tutorial “Its written in long hand, rather than using faster code and macros its been written to teach rather than impress.”
Don’t lie….You needed this. Great work.
Thanks for all your work here. Very helpful to us folks wanting to code asm on the Speccy and have a lot to learn yet!
Hi,
I am late to all this but have backed the 2nd kickstarter and waiting for my next like everyone else. These guides are great and have given me a massive boost in setting up my dev environment with some good and well thought out examples to learn assembly which is my end goal.
The Spectrum passed me by back in the day as I had a C64 but am really wanting to get into this. I would just like to say a big thanks for taking time out to produce these guides.
Much appreciated!
You are more than welcome and thankyou for your kind words.