Opry99er Posted November 4, 2010 Share Posted November 4, 2010 This might be a dumb question... more often than not the Lottrup book (while brilliant) confuses the shit out of me unnecessarily. The character table... assuming I want to change the definition of character 128 or character >80, is there a simple way to determine how to address that particular 8 byte chunk? A reference for each location? For instance, according to the Lottrup book, character #35 starts at >0918, increasing by 8 bytes for each character definition. If I wish to redefine character 128, I take >0918 and add 93*8 to it? Is this correct? Or am I totally missing the point..... This is very much an issue of me thinking in dec and not hex Quote Link to comment Share on other sites More sharing options...
+adamantyr Posted November 4, 2010 Share Posted November 4, 2010 (edited) This might be a dumb question... more often than not the Lottrup book (while brilliant) confuses the shit out of me unnecessarily. The character table... assuming I want to change the definition of character 128 or character >80, is there a simple way to determine how to address that particular 8 byte chunk? A reference for each location? For instance, according to the Lottrup book, character #35 starts at >0918, increasing by 8 bytes for each character definition. If I wish to redefine character 128, I take >0918 and add 93*8 to it? Is this correct? Or am I totally missing the point..... This is very much an issue of me thinking in dec and not hex Yes, that is correct. A better way to think of it is like this: Address of character = Starting address + ( character value * 8 ) In assembly, you can do this by having an equated label to the address. A code snippet is below: CHRPAT EQU >0800 . . . * Read a character pattern into BUFFER, @CHAR contains character to read LI R0,CHRPAT MOV @CHAR,R1 SLA R1,3 A R1,R0 LI R1,BUFFER LI R2,8 BLWP @VMBR Does that clear it up? Adamantyr Edited November 4, 2010 by adamantyr Quote Link to comment Share on other sites More sharing options...
Opry99er Posted November 4, 2010 Share Posted November 4, 2010 (edited) Ugh... man, I tell ya... As much as I try--- as many times as I've tried to write in assembly, it still just makes my brain explode. I've been sitting here staring at this book and trying a hundred different things and it's just not happening. I'm trying to work on a little something for Keith and his Dead Station game, but it's frustrating beyond description. It's such a simple thought... redefine ONE character, change ONE character set color, draw the 768 bytes I have already onto the screen. Drawing is easy. DEF START REF VMBW START LI R0,0 LI R1,MD0 LI R2,768 BLWP @VMBW LP LIMI 2 JMP LP Tables just confuse me. I don't know... And my syntax and spacing got screwed up in the above example... I am aware the labels, instructions and operands are not spaced correctly... Edited November 4, 2010 by Opry99er Quote Link to comment Share on other sites More sharing options...
+adamantyr Posted November 4, 2010 Share Posted November 4, 2010 Ugh... man, I tell ya... As much as I try--- as many times as I've tried to write in assembly, it still just makes my brain explode. I've been sitting here staring at this book and trying a hundred different things and it's just not happening. I'm trying to work on a little something for Keith and his Dead Station game, but it's frustrating beyond description. It's such a simple thought... redefine ONE character, change ONE character set color, draw the 768 bytes I have already onto the screen. Drawing is easy. DEF START REF VMBW START LI R0,0 LI R1,MD0 LI R2,768 BLWP @VMBW LP LIMI 2 JMP LP Tables just confuse me. I don't know... Think of it like this... the VDP is just data storage. There's nothing there BUT data. All you need to know is where to find it, and what order it's in. Also, doing BASIC/Assembly cross-over work is seriously brain-hemorrhaging hard stuff. I tried to do it myself back in my teens, and couldn't grok it at all. I wondered how on earth anyone learned assembly programming that way. Adamantyr Quote Link to comment Share on other sites More sharing options...
Opry99er Posted November 4, 2010 Share Posted November 4, 2010 I am writing just an assembly routine. EA3. It's just all the figuring of where the data needs to go, offsets, buffers, bytes words.... It's the whole concept. I understand WHY it all works and even HOW it works.... It's the execution of it that makes my eyes bleed. I've never thought this way... I've only ever coded in BASIC languages, TI and bAtari. I wish it were intuitive to me, as it seems to be for so many of my colleagues here. I'll keep reading and trying. Nothing to it but to do it, right? Quote Link to comment Share on other sites More sharing options...
matthew180 Posted November 4, 2010 Share Posted November 4, 2010 Each tile (character) requires 8 bytes to define the pattern (which I assume you know by now). First find the start of the tile you wish to change. Since there are 256 tiles (numbered 0 to 255), you multiple the tile number you are looking for by 8: Tile Bytes 0 0 - 7 (total of 1 8 - 15 2 16 - 23 . 128 1024 - 1031 . 255 2040 - 2047 The tile bytes are numbered 0 to 2047, for a total of 2048 (2K or >0800) bytes for all 256 tile patterns. That is the first step. Now that you know the starting byte to the tile you want to change, you need to add that to the starting address of the PDT (pattern descriptor table). Thus your "tile number" becomes an "offset" into the PDT, which will be located in VDP RAM at some location determined by VDP Register-4. If the PDT happens to be set to start at VRAM address zero (>0000), then your tile number (index) can be used directly, since 0 + tile_num = tile_num. Since the VDP registers are write-only, you can't find out what address the PDT is set to, so you have to set it to make sure it is at a known location. And, since *you* are setting the PDT start address, you know where it is, and you can use an EQUate in your code to find tile pattern locations at assembly-time or run-time. It does not matter if you do the math in decimal or hex. In assembly, and computers in general, it is typical to represent addresses and memory sizes with hex notation. Let me know if you need some examples. Matthew Quote Link to comment Share on other sites More sharing options...
+adamantyr Posted November 4, 2010 Share Posted November 4, 2010 I am writing just an assembly routine. EA3. It's just all the figuring of where the data needs to go, offsets, buffers, bytes words.... It's the whole concept. I understand WHY it all works and even HOW it works.... It's the execution of it that makes my eyes bleed. I've never thought this way... I've only ever coded in BASIC languages, TI and bAtari. I wish it were intuitive to me, as it seems to be for so many of my colleagues here. I'll keep reading and trying. Nothing to it but to do it, right? It isn't an easy transition from an imperative language like BASIC, I'll agree. I didn't quite grasp it myself as a teen either. I kept thinking "What's the command to do this?" It wasn't until I was back in college years later that I had my "Eureka!" moment. Maybe the best way to try and approach it is to think of the command in BASIC/extended BASIC you want to use, and then ask yourself "Now how would that command actually work? What would it actually do in assembly?" Start with something simple, CALL COLOR. Adamantyr Quote Link to comment Share on other sites More sharing options...
Opry99er Posted November 4, 2010 Share Posted November 4, 2010 Thanks guys... maybe today's not my day. I've been beating my head in for the last 2 hours with absolutely no success whatsoever. All I've done is create Keith's Dead Station graphic on my end. Here's what it looks like on my editor: So, my map data looks like this: MD0 DATA >2020,>2020,>2020,>2020 ; DATA >2020,>2020,>2020,>2020 ; DATA >2020,>2020,>2020,>2020 ; DATA >2020,>2020,>2020,>2020 ; * -- Map Row 1 -- DATA >2020,>2020,>2020,>2020 ; DATA >2020,>2020,>2020,>2020 ; DATA >2020,>2020,>2020,>2020 ; DATA >2020,>2020,>2020,>2020 ; * -- Map Row 2 -- DATA >2020,>2020,>2020,>2020 ; DATA >2020,>2020,>2020,>2020 ; DATA >2020,>2020,>2020,>2020 ; DATA >2020,>2020,>2020,>2020 ; * -- Map Row 3 -- DATA >2020,>2020,>2020,>2020 ; DATA >2020,>2020,>2020,>2020 ; DATA >2020,>2020,>2020,>2020 ; DATA >2020,>2020,>2020,>2020 ; * -- Map Row 4 -- DATA >2020,>2020,>2020,>2020 ; DATA >2020,>2020,>2020,>2020 ; DATA >2020,>2020,>2020,>2020 ; DATA >2020,>2020,>2020,>2020 ; * -- Map Row 5 -- DATA >2020,>2020,>2020,>2020 ; DATA >2020,>2020,>2020,>2020 ; DATA >2020,>2020,>2020,>2020 ; DATA >2020,>2020,>2020,>2020 ; * -- Map Row 6 -- DATA >2020,>2020,>2020,>2020 ; DATA >2020,>2020,>2020,>2020 ; DATA >2020,>2020,>2020,>2020 ; DATA >2020,>2020,>2020,>2020 ; * -- Map Row 7 -- DATA >2020,>2020,>2080,>8080 ; DATA >8080,>8080,>8080,>8080 ; DATA >8080,>8080,>8080,>8080 ; DATA >8080,>8020,>2020,>2020 ; * -- Map Row 8 -- DATA >2020,>2020,>2080,>2020 ; DATA >8020,>2080,>2020,>2020 ; DATA >8020,>2080,>2020,>2020 ; DATA >2020,>8020,>2020,>2020 ; * -- Map Row 9 -- DATA >2020,>2020,>2080,>2020 ; DATA >8020,>2020,>2020,>2020 ; DATA >2020,>2080,>2020,>2020 ; DATA >2020,>8020,>2020,>2020 ; * -- Map Row 10 -- DATA >2020,>2020,>2080,>2020 ; DATA >8020,>2020,>2020,>2020 ; DATA >2020,>2080,>2020,>8080 ; DATA >8020,>8020,>2020,>2020 ; * -- Map Row 11 -- DATA >2020,>2020,>2080,>2020 ; DATA >8080,>2020,>8080,>2020 ; DATA >8080,>8080,>2020,>8080 ; DATA >8020,>8020,>2020,>2020 ; * -- Map Row 12 -- DATA >2020,>2020,>2080,>2020 ; DATA >2020,>2020,>2020,>2020 ; DATA >2020,>2020,>2020,>2020 ; DATA >2020,>8020,>2020,>2020 ; * -- Map Row 13 -- DATA >2020,>2020,>2080,>2080 ; DATA >8020,>2020,>2020,>2020 ; DATA >2020,>2080,>8020,>8080 ; DATA >8080,>8020,>2020,>2020 ; * -- Map Row 14 -- DATA >2020,>2020,>2080,>2080 ; DATA >2020,>8020,>8020,>2020 ; DATA >8020,>2080,>8020,>8080 ; DATA >8080,>8020,>2020,>2020 ; * -- Map Row 15 -- DATA >2020,>2020,>2080,>2080 ; DATA >8020,>2020,>2080,>2080 ; DATA >2020,>2020,>2020,>2020 ; DATA >2020,>8020,>2020,>2020 ; * -- Map Row 16 -- DATA >2020,>2020,>2080,>2080 ; DATA >2020,>8020,>2020,>2020 ; DATA >2020,>2080,>8020,>2020 ; DATA >2020,>8020,>2020,>2020 ; * -- Map Row 17 -- DATA >2020,>2020,>2080,>2080 ; DATA >8020,>2020,>8080,>2080 ; DATA >8020,>2080,>8020,>8020 ; DATA >8020,>8020,>2020,>2020 ; * -- Map Row 18 -- DATA >2020,>2020,>2080,>2080 ; DATA >2020,>8020,>2020,>2020 ; DATA >2020,>2020,>2020,>8020 ; DATA >8020,>8020,>2020,>2020 ; * -- Map Row 19 -- DATA >2020,>2020,>2080,>2080 ; DATA >8020,>2020,>8080,>8080 ; DATA >8080,>2020,>2020,>2020 ; DATA >2020,>8020,>2020,>2020 ; * -- Map Row 20 -- DATA >2020,>2020,>2080,>2020 ; DATA >2020,>2020,>2020,>2020 ; DATA >2020,>2020,>2020,>8080 ; DATA >8020,>8020,>2020,>2020 ; * -- Map Row 21 -- DATA >2020,>2020,>2080,>2020 ; DATA >8020,>8020,>2080,>2020 ; DATA >8020,>2080,>8020,>8080 ; DATA >8020,>8020,>2020,>2020 ; * -- Map Row 22 -- DATA >2020,>2020,>2080,>2020 ; DATA >2020,>2020,>2080,>8080 ; DATA >8020,>2080,>8020,>2020 ; DATA >2020,>8020,>2020,>2020 ; * -- Map Row 23 -- DATA >2020,>2020,>2080,>8080 ; DATA >8080,>8080,>8080,>8080 ; DATA >8080,>8080,>8080,>8080 ; DATA >8080,>8020,>2020,>2020 ; My pattern definition I needed to do is simply >FFFF,>FFFF,>FFFF,>FFFF. Just a block--- solid and white. The color definitions I'm using look like this: CLRSET DATA >1000,>1000,>1000,>1000 ; DATA >1000,>1000,>1000,>1000 ; DATA >1000,>1000,>1000,>1000 ; DATA >1000,>1000,>1000,>1000 ; DATA >F000,>1000,>1000,>1000 ; DATA >1000,>1000,>1000,>1000 ; DATA >1000,>1000,>1000,>1000 ; DATA >1000,>1000,>1000,>1000 ; As you can see, just one color redefine... White for the colorset corresponding with the defined character... I believe it's character set 14. So what I need to do is redefine character 128, color it white, and then display the 768 bytes on the screen. The screen drawing is not hard, it's the rest that confuses me. I hope I'm not annoying you guys with this stuff... I know it's easy, but I'm just not getting it, and its more an indication of mental shortcomings than the complexity of the language. Quote Link to comment Share on other sites More sharing options...
Opry99er Posted November 4, 2010 Share Posted November 4, 2010 (edited) Double post deleted Edited November 4, 2010 by Opry99er Quote Link to comment Share on other sites More sharing options...
Opry99er Posted November 4, 2010 Share Posted November 4, 2010 So if I use an equate.... CHRPT EQU >0800 Then that places my PDT at that specific location... See, another example of this book confusing the hell out of me... All the tables and such are at hard locations in this book.... Quote Link to comment Share on other sites More sharing options...
matthew180 Posted November 4, 2010 Share Posted November 4, 2010 Well, they are probably using a set of default values in the book. Either the values set by XB, or by the console at power-on. Since you are trying to work in a mixed assembly / XB environment, you need to know where XB sets up the tables. Also, XB does not allow full use of the entire tile range, *and* it adds some offset to the tile values themselves. All-in-all a pain in the ass and nothing but added confusion. I'll try to get an example for you. Matthew Quote Link to comment Share on other sites More sharing options...
+adamantyr Posted November 4, 2010 Share Posted November 4, 2010 So if I use an equate.... CHRPT EQU >0800 Then that places my PDT at that specific location... See, another example of this book confusing the hell out of me... All the tables and such are at hard locations in this book.... I think I see part of your problem here... The EQU label is not saying "Put the character pattern table here" or "the character pattern table is here". It is literally just saying "this label points to this address". It is used by the compiler and the programmer to replace something that would ordinarily be a number with a label so that, if you decide you want to move it to another location later, you can just change a single label and have it change everywhere. So what does determine the character pattern table location? The settings in the VDP registers. And they have default settings coming from the E/A cartridge as follows: R1=E0 Standard mode R2=00 Screen image at >0000 R3=0E Color table at >0380 R4=01 Char pattern table at >0800 R5=06 Sprite attribute table at >0300 R6=00 Sprite pattern table at >0000 (not the same as char pats!) R7=F5 White on blue Does that help you grok this a bit better? Adamantyr Quote Link to comment Share on other sites More sharing options...
Opry99er Posted November 4, 2010 Share Posted November 4, 2010 Thanks Matthew... But actually for this particular example, I'm just trying to get a straight assembly EA3 program to work... No XB involved. I wanted to get THAT working before I tried to do anything with BASIC hybridization. I can't even do THAT simple task without this much stress. All I wanted to do was draw the thing in assembly.... Then I was going to try to add some of the other colored tiles Keith had in his example.... Just do a piece by piece assembly version of his screen there.... If I could make all that work, I thought I might try to change it over for XB use. Quote Link to comment Share on other sites More sharing options...
Opry99er Posted November 4, 2010 Share Posted November 4, 2010 Adam, thanks... Yes it does make sense a bit more. I'll update as I make progress. Thanks. Quote Link to comment Share on other sites More sharing options...
jchase1970 Posted November 7, 2010 Author Share Posted November 7, 2010 (edited) Owen here is a small program to computer addresses 5 CALL CLEAR 10 INPUT "ENTER YOUR CHARACTER PATTERNTABLE STARTING ADDRESS >":B 20 PRINT "PRINT YOU ENTER >"&STR$(B) 25 PRINT 30 PRINT "PRESS Y IF THAT IS CORRECT" 40 PRINT "PRESS N IF THAT IS WRONG" 50 CALL KEY(0,K,S) 60 IF S=0 THEN 50 70 IF(K=89)+(K=121)THEN 100 80 IF(K=78)+(K=110)THEN 10 90 GOTO 50 100 INPUT "ENTER CHARACTER NUMBER TO CONVERT TO ADDRESS:":A 110 PRINT "CHARACTER";A;"IS AT >"&STR$(B+(A*) 115 PRINT 120 GOTO 100 Edited November 7, 2010 by jchase1970 Quote Link to comment Share on other sites More sharing options...
jchase1970 Posted November 8, 2010 Author Share Posted November 8, 2010 New question, DIV G,WR* Divides the contents of the words in Workspace Register 3 and Workspace Register 4 by the value of ADR plus Workspace Register 2 and stores the integer result in Workspace Register 3 with the remainder in Workspace Register 4. Ok, I get it that this is a 32bit function and returns a 16bit balue so DIV 2,R3 if R3=0 and R4=10 then the value for the dividend is 10 now 10/2 is 5 so R3=5 and R4=0? if I'm right so far, Div 4,R3 *same values 10/4=2.5 R3=2 and R4=5 One more step and my question if I'm right so far New values R3=0, R4=17 DIV 8,R3 17/8=2.125 R3=2 and R4=? is R4 1 or 125 If it stores the whole decimal remainder whats the cut off 1/1000? John Quote Link to comment Share on other sites More sharing options...
sometimes99er Posted November 8, 2010 Share Posted November 8, 2010 (edited) if I'm right so far, Div 4,R3 *same values 10/4=2.5 R3=2 and R4=5 DIV R2,R3 R2=4 R3=0 R4=10 10/4 = 2.5 = 2 and a remainder of 2 = 2*4+2 = 10 Edited November 8, 2010 by sometimes99er Quote Link to comment Share on other sites More sharing options...
sometimes99er Posted November 8, 2010 Share Posted November 8, 2010 One more step and my question if I'm right so far New values R3=0, R4=17 DIV 8,R3 17/8=2.125 R3=2 and R4=? is R4 1 or 125 If it stores the whole decimal remainder whats the cut off 1/1000? John 17/8 = 2*8+1 R3=2 R4=1 Quote Link to comment Share on other sites More sharing options...
matthew180 Posted November 8, 2010 Share Posted November 8, 2010 DIV can't use immediate values, the destination must be a workspace register and the source can use any of the addressing modes. DIV is "kind of" a 32-bit operation in that the dividend is a 32-bit value, but the divisor is a 16-bit value. The quotient goes into the dividend address, and the remainder goes into the dividend address + 1 (where 1 represents a 16-bit word, not a byte.) LI R2,10 R2 will be the divisor CLR R3 R3+R4 will be the 32-bit dividend LI R4,123 DIV R2,R3 Divide 123 by 10 After the DIV instruction above, R3 will contain 12 and R4 will contain 3, and R2 is unchanged. You don't have to use R2, R3, and R4, but the dividend must be a register and will always be that register combined with the next register to make a 32-bit number. Here is a bigger example with a source value that does not fit in a single 16-bit value. DIVIDE DATA 1234 Divisor must be a 16-bit value . . . LI R8,>000F Load 32-bit dividend with >000FFFFF LI R9,>FFFF DIV @DIVIDE,R8 Divide: 1,048,575 / 1,234 = 849 remainder 909 After the DIV, R8 would contain 849 and R9 would contain 909. Matthew Quote Link to comment Share on other sites More sharing options...
+adamantyr Posted November 8, 2010 Share Posted November 8, 2010 Here is a bigger example with a source value that does not fit in a single 16-bit value. DIVIDE DATA 1234 Divisor must be a 16-bit value . . . LI R8,>000F Load 32-bit dividend with >000FFFFF LI R9,>FFFF DIV @DIVIDE,R8 Divide: 1,048,575 / 1,234 = 849 remainder 909 After the DIV, R8 would contain 849 and R9 would contain 909. One other point, DIV and MPY are both unsigned operations. Signed operations require a bit of extra work; you'll have to store the sign bits for divisor and dividend and restore the true value after completing operations. Curiously, the only two new opcodes added in the TMS9995 processor were signed multiply and divide operators. Adamantyr Quote Link to comment Share on other sites More sharing options...
jchase1970 Posted November 8, 2010 Author Share Posted November 8, 2010 oh hell, now I feel dumb. Remainder not decimal. It's been so long since I have done long hand division with remainders I had forgot what a remainder was. Thanks for pointing out that it can't use immediate values, I was under the impression it could. Quote Link to comment Share on other sites More sharing options...
+adamantyr Posted November 8, 2010 Share Posted November 8, 2010 Thanks for pointing out that it can't use immediate values, I was under the impression it could. You can use memory addresses for the divisor, like follows: W2 DATA 2 . . . LI R0,10 MPY @W2,R0 . * R0 is now 0, R1 is 20 . DIV @W2,R0 . * R0 is now 10, R1 is 0 . Adamantyr Quote Link to comment Share on other sites More sharing options...
jchase1970 Posted November 30, 2010 Author Share Posted November 30, 2010 (edited) Two questions on the fallowing code piece. *VDP MEMORY MAP VDPRD EQU >8800 VDPSTA EQU >8802 VDPWD EQU >8C00 VDPWA EQU >8C02 *WORKSPACE WRKSP EQU >8300 R0LB EQU WRKSP+1 R1LB EQU WRKSP+3 R2LB EQU WRKSP+5 R3LB EQU WRKSP+7 R4LB EQU WRKSP+9 MAIN L10 BL @CLS END MAIN *BASIC COMMANDS CLS LI R0,0 LI R1,>2000 LI R2,768 BL @VMBW B *R11 *ASSEMBLE COMMANDS VMBW MOVB @R0LB,@VDPWA ORI R0,>4000 MOVB R0,@VDPWA VMBWLP MOVB *R1+,@VDPWD DEC R2 JNE VMBWLP B *R11 END this line L10 BL @CLS comes up with a undefined symbol error I don't know why. And 2 I guess this code wont work anyway because I'm BLing in a BLing, L10 BL @CLS <-----HERE END MAIN *BASIC COMMANDS CLS LI R0,0 LI R1,>2000 LI R2,768 BL @VMBW <----HERE B *R11 *ASSEMBLE COMMANDS VMBW MOVB @R0LB,@VDPWA ORI R0,>4000 MOVB R0,@VDPWA VMBWLP MOVB *R1+,@VDPWD DEC R2 JNE VMBWLP B *R11 So am I right now thinking you can't BL in a BL because it will store only 1 return address in R11? Edited November 30, 2010 by jchase1970 Quote Link to comment Share on other sites More sharing options...
Opry99er Posted November 30, 2010 Share Posted November 30, 2010 (edited) Make sure you define all your labels... Is CLS in your REF/DEF table? Edited November 30, 2010 by Opry99er Quote Link to comment Share on other sites More sharing options...
matthew180 Posted November 30, 2010 Share Posted November 30, 2010 What assembler are you using? I'm not sure why it would be complaining about CLS. Also, the assembler does not interpret your code, so the fact that you are executing a BL without saving R11 is inconsequential. As written, the code won't return though. The B *R11 from the VMBW routine will return to the instruction following the BL @VMBW line, which is B *R11, which is now pointing to itself, thus you have an infinite loop. Before you call BL @VMBW from within your CLS function, you have to save R11, and restore it before B *R11 from the CLS function. See my "Assembly My Way" thread, there is a long segment on a doing all of this, including managing a pseudo-stack for just such a thing. Matthew 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.