Itchy Scratchy Posted October 29, 2020 Share Posted October 29, 2020 (edited) In order to contribute and help budding Coleco/ADAM programmers I intend to share various code snippets that will help you along. I have found over the years that specific details are hard to come by so I will help where I can but I am not going to teach you Z80 assembly language. It is not as hard as you think and can look intimidating at times but don't give up. If you use assembly language you will gain speed and space over any higher level language. (my opinion you may feel different) That said. Have you ever wanted to know what pattern your sprite is over or just wanted to know what pattern (or color) is at what position on the screen. Maybe you want to build a wall that you do not want to pass through so your wall is pattern 45. Well, you can say if a = 45 then do not pass. In assembly that looks like this LD A, ???? (magic number) CP 45 ; (Compare) or if A = 45 JP Z DO_NOT_PASS ; If yes then jump to Do not pass routine if no then continue on. ; Continue Journey code.... RET ;(Return from where you called from) DO_NOT_PASS: ; Do not continue moving through pattern. RET ;(Return from where you called from) But how do you get that important magic 45 or other value into A Well, in another post I will show you how to set up graphics but for now we will just say it is there. For now it is sitting in GRAM, VRAM....The Ram connected to the TI9928 Graphics Chip. The way Colecovision works is that the Z80 uses Ram and the Graphic Chip uses Ram so in order to get to the 16k Graphics Ram you have to go through a port which kind of sucks because it creates a bottle neck. However the Z80 is mighty fast so we can get away with a few things and scrolling is not one of them. That does not mean you can't have scrolling games, it just means they won't look as smooth as modern systems. Because Coleco Sprite Y and X values range from 0 to 192 Y and 0 to 256 X we have to divide them by 8 to get the proper Rows and Columns In the Coleco world we have 32x24 screen patterns (768) Mathematically it all adds up and divides equally as you would expect in the computer world. The routine is actually 4 parts. 1st is to divide by 8 and get the Rows 2nd is to divide by 8 and get the Columns 3rd is to send (OUT) to PORT 0BFh. 4th is put that returned value (IN) 0BEh into A Port BE VRAM Data (Read/Write) Port BF VDP Status Registers (Read Only) I do not want to get into the AND's and PORTS right now because that is information overload and a distraction so for now I am sticking with minimum code. Copy and paste or use the asm attachment. ; Tile Identify Routine (c) 2020 "From Scratch" Enterprises ; Free to use but please use love for me in the credits. ; To find Pattern under Sprite. (upper left hand corner) ; Sprite Definition (Y, X, Pattern, Color) ; LD Y into (OFFSET_Y) and LD X into (OFFSET_X) then call SPRITE_TO_TILE ; Pattern value will come back in A ; To find the pattern on screen (no sprite) LD HL with tile position 0-767 + VRAM_NAME ($1800) ; To find the pattern color (no sprite) LD HL with tile position 0-767 + VRAM_COLOR ($2000) ; Call QUICK_TILE. Pattern value will return in A VRAM_NAME: EQU $1800 SPRITE_TO_TILE: LD HL, VRAM_NAME LD A, (OFFSET_Y) ; offset Y (ROW) CP 0 ; can't divide by zero skip to find Columns JP Z, FIND_COLUMN SRL A ; divide by 8 (192/8) 24 Rows (actually divide 3 times by 2) SRL A SRL A LD B, A LD DE, 32 XOR A ZERO: ADC HL, DE DJNZ ZERO FIND_COLUMN: LD A, (OFFSET_X) ; offset X (Column) CP 0 ; can't divide by zero skip to QUICK_TILE which calls port to get value JP Z, QUICK_TILE SRL A ; divide by 8 (256/8) 32 Columns (actually divide 3 times by 2) SRL A SRL A LD E, A LD D, 0 XOR A ADC HL, DE QUICK_TILE: DI LD A, L OUT (0BFh), A ; (OUT) Lower Bits LD A, H AND 3Fh OUT (0BFh), A ; (OUT) Higher Bits EI IN A, (0BEh) ; (IN) Return value into A RET If you find errors or inconsistencies please let me know in the comments. Identify Tile.asm Edited October 31, 2020 by Itchy Scratchy clean up code a bit 2 Quote Link to comment Share on other sites More sharing options...
Itchy Scratchy Posted October 29, 2020 Author Share Posted October 29, 2020 (edited) Feel free to comment on how this routine could be better. I highly recommend that in your programing journey to start commenting your code. I am finding that going back to older work is like what the **** did I do here and why does it work. If you find yourself in a full 32k project with over 4000 lines of code then you will wish you commented at least the important stuff. Even in my previous post I have updated, refined, edited you name it at least 20 times to simplify it for you. Edited October 29, 2020 by Itchy Scratchy Quote Link to comment Share on other sites More sharing options...
Tony Cruise Posted October 30, 2020 Share Posted October 30, 2020 Very well explained. Quote Link to comment Share on other sites More sharing options...
Itchy Scratchy Posted October 30, 2020 Author Share Posted October 30, 2020 (edited) 19 hours ago, Tony Cruise said: Very well explained. Thank you. I am sure I missed some important parts but how many times can you go back and edit something. Next time I will write the whole thing out then copy and paste instead of winging most of it from memory. Then again I may end up giving a basic Z80 Assembly language course after all. It seems that all the books on the market are geared toward engineering students. Edited October 30, 2020 by Itchy Scratchy Quote Link to comment Share on other sites More sharing options...
Maltanto Posted November 3, 2020 Share Posted November 3, 2020 (edited) Just a couple of things, if I may.. I think there's a potential bug lurking right here: SRL A ; divide by 8 (192/8) 24 Rows (actually divide 3 times by 2) SRL A SRL A LD B, A .. <enter loop with B> When OFFSET_Y is in the range of (0..7) the result after dividing by 8 will be 0 and that will cause the loop to repeat 256 times. You should check for Z after the last SRL A and skip the loop if needed. Anyway, I think the approach of dividing by 8 and then multiplying that same value by 32 is a bit cumbersome and unnecessary . Here's an easier alternative to calculate the pattern address for a given Y_OFFSET in A. I've put some comments laying out the bit fields to help visualize what's going on: //A=OFFSET_Y // V7 V6 V5 V4 V3 V2 V1 V0 AND #F8 // V7 V6 V5 V4 V3 0 0 0 LD H,0 LD L,A ADD HL,HL // 0 0 0 0 0 0 0 V7 | V6 V5 V4 V3 0 0 0 0 ADD HL,HL // 0 0 0 0 0 0 V7 V6 | V5 V4 V3 0 0 0 0 0 LD DE,VRAM_NAME ADD HL,DE // HL=VRAM_NAME+(Y*32) I'm taking advantage of the fact that we're multiplying an unknown value (OFFSET_Y) by a power of 2. Also that zeroing the lowest 3 bits of something is in fact the same as dividing by 8 and then multiplying the result again by 8, so we just need to multiply by 4 to get the proper offset (Y*32). This way there's no need for expensive loops nor safety checks when B=0. The OFFSET_X part is even easier. We know the lowest 5 bits of the adddress in HL are always 0, so we can just divide X by 8 and add the result to the L register: LD A,(OFFSET_X) // X7 X6 X5 X4 X3 X2 X1 X0 SRL A SRL A SRL A // 0 0 0 X7 X6 X5 X4 X3 OR L LD L,A // V5 V4 V3 X7 X6 X5 X4 X3 Regards Jorge Edited November 3, 2020 by Maltanto Minor corrections 1 Quote Link to comment Share on other sites More sharing options...
Itchy Scratchy Posted November 4, 2020 Author Share Posted November 4, 2020 I get what your attempting to achieve and simplify. I would like to see your entire routine listed and tested. I can always find room for improvement. The way I wrote this out is a universal plugin routine that will cover all bases. Quote Link to comment Share on other sites More sharing options...
Maltanto Posted November 4, 2020 Share Posted November 4, 2020 // IN: (OFFSET_Y, OFFSET_X) // OUT: HL=VRAM_NAME ADDRESS, A=PATTERN LD A,(OFFSET_Y) AND #F8 // V7 V6 V5 V4 V3 0 0 0 LD H,0 LD L,A ADD HL,HL // 0 0 0 0 0 0 0 V7 | V6 V5 V4 V3 0 0 0 0 ADD HL,HL // 0 0 0 0 0 0 V7 V6 | V5 V4 V3 0 0 0 0 0 LD DE,VRAM_NAME ADD HL,DE // HL=VRAM_NAME+(Y*32) LD A,(OFFSET_X) // X7 X6 X5 X4 X3 X2 X1 X0 SRL A SRL A SRL A // 0 0 0 X7 X6 X5 X4 X3 OR L LD L,A // V5 V4 V3 X7 X6 X5 X4 X3 // READ VRAM // THIS IS OK ON EMULATORS, BUT MOST CERTAINLY WON'T WORK ON THE REAL HARDWARE DUE TO TIMING CONSTRAINTS DI LD A,L OUT (#BF),A LD A,H AND #3F OUT (#BF),A IN A,(#BE) EI RET Quote Link to comment Share on other sites More sharing options...
Itchy Scratchy Posted November 4, 2020 Author Share Posted November 4, 2020 I want to try your formula to see if it does actualy work on the real deal. I have physical hardware and a lot of eproms sitting around. Which brings me to an important point. The routine I have given the community I have used in many programs on both emulators for development and real hardware so it has been tested. My goal for teaching and developing is not just to do it but to also have good coding practices. I remember being really upset when I moved from Workbench 1.3 on my Amiga to 2.0 where as a ton of programs did not work because they were created at such a low level and directly used the hardware instead of going through the BIOS. Low level is great for DEMOS, lousy for practical software. Modular, functional and easy to read but at the same time if anyone can introduce better and more efficient code I will turn from teacher to student in a heartbeat, no pride or ego here. Quote Link to comment Share on other sites More sharing options...
Itchy Scratchy Posted November 4, 2020 Author Share Posted November 4, 2020 This brings me to an interesting point. Where are all the Colecovision and ADAM Demos? The Coleco formula is still going strong some 40 years later yet it is still a small community. Youtube is full of TI99/4A fans creating stuff that would knock your socks off yet Coleco has little to nothing. I want to just toy around a bit when Thrippin is completed.. I hope you join in. Working hard on it in between life's activities. That darn NMI is a harsh mistress. Quote Link to comment Share on other sites More sharing options...
Ikrananka Posted November 4, 2020 Share Posted November 4, 2020 CV and ADAM demos certainly are rather scarce. One of the few, and in my opinion the best, is Waterline by krue from way back in 2010. Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.