sometimes99er Posted July 26, 2011 Author Share Posted July 26, 2011 Now Assembly only has 16 Registers and GPL only has 256 bytes of Scratch Pad but the same program in GPL will use less storage and variables then XB or Assembly. Only Forth is more compact, but again much more complicated to learn. You point out that GPL will use less storage and variables than XB and Assembly. Now you know I'm not an expert at GPL, so I'm not going to try and dissect the GPL version of the demo (post #7), but could you explain how GPL will end up using less variables with "the same program" in question ? Quote Link to comment Share on other sites More sharing options...
Willsy Posted July 26, 2011 Share Posted July 26, 2011 Is there any evidence to suggest that the graphics data in GROM has ever changed location? Can I not just assume a hard-coded address? It's in different places in each GROM set. That's why there's a vectored function in GPL to get the data from, and why I wrote this function in the first place. It probably is larger than the GPLLNK, but I never liked the idea of relinquishing control and hoping I get it back. Ah! OK, thanks Tursi! Quote Link to comment Share on other sites More sharing options...
Willsy Posted July 26, 2011 Share Posted July 26, 2011 Now Assembly only has 16 Registers and GPL only has 256 bytes of Scratch Pad but the same program in GPL will use less storage and variables then XB or Assembly. Only Forth is more compact, but again much more complicated to learn. You point out that GPL will use less storage and variables than XB and Assembly. Now you know I'm not an expert at GPL, so I'm not going to try and dissect the GPL version of the demo (post #7), but could you explain how GPL will end up using less variables with "the same program" in question ? I also know nothing about GPL, but I would have thought that the GPL version would use the same number of variables as any other languages. To understand what mean, you have to stop thinking in terms of languages, and think in terms of algorithms. Let's a take a bouncing ball that bounces off the screen edges. The minimum number of variables is 4: Current x coordinate Current y coordinate x direction (1 or -1) y direction (1 or -1) You could *possibly* do it with 3 variables, using a screen address instead of x and y coordiantes, but that just makes screen edge detection more complex. So, GPL, XB, Assembly: The *algorithm* still needs 4 (or 3!) variables. The *language* makes no difference. Therefore I don't really agree that GPL uses less variables for a given job/task. The number of variables is inherent in the algorithm, and once you have broken the algorithm down into its most efficient form, that is how many variables you need, in *any* languge. I do agree that GPL is cool though! I will definatlely try it out! Quote Link to comment Share on other sites More sharing options...
RXB Posted July 26, 2011 Share Posted July 26, 2011 Now Assembly only has 16 Registers and GPL only has 256 bytes of Scratch Pad but the same program in GPL will use less storage and variables then XB or Assembly. Only Forth is more compact, but again much more complicated to learn. You point out that GPL will use less storage and variables than XB and Assembly. Now you know I'm not an expert at GPL, so I'm not going to try and dissect the GPL version of the demo (post #7), but could you explain how GPL will end up using less variables with "the same program" in question ? Sure I have been using GPL for sometime now, more than most others. I convert from Basic, XB and Assembly to GPL. Like Assembly I can use a address instead of a variable for storage. Like this snippet of code I just wrote: CLR @>8374 * KEYBOARD 0 G220 SCAN * GET A KEY CEQ 13,@K * K=13? BR G220 * NO, GOTO G220 G240 ALL 32 CALL TIMSU * SET UP TIMER CLR @B * SPRITE COUNTER ST 32,@NMS * NUMBER OF MOVING SPRITES MOVE 1,G@VR1,#1 * VDP REGISTER 1 MOVE 128,G@SALINT,V@SAT * SPRITE ATTRIBUTE TABLE MOVE 192,G@SHAPE,V@SDB * SPRITE DESCRIPTOR BLOCK MOVE 128,G@SMOTAB,V@SVT * SPRITE VELOCITY TABLE DST S340,@SOND * SOUND LIST ADDRESS I/O 0,@SOND * PLAY IT G350 CALL TIMER * TIMER DCLR V@SVT * STOP PLAYER SPRITE SCAN * GET A KEY CEQ 11,@K * UP? BR G450 * NO, GOTO G450 DST >FB00,V@SVT * LOAD UP MOTION B G530 * GOTO D530 G450 CEQ 10,@K * DOWN? BR G480 * YES, GOTO G480 DST >0500,V@SVT * LOAD DOWN MOTION B G530 * GOTO G530 G480 CEQ 9,@K * RIGHT? BR G510 * NO, GOTO G510 DST >0005,V@SVT * LOAD RIGHT MOTION B G530 * GOTO G530 G510 CEQ 8,@K * LEFT? BR G530 * NO, GOTO G530 DST >00FB,V@SVT * LOAD LEFT MOTION G530 DST SAT+4,@FAC * SPRITE ATTRIBUTE +4 DST SVT+4,@FAC2 * SPRITE MOTION =4 G540 DST V*FAC,@ARG2 * ROW:COL #2 DST V@SAT,@ARG * ROW:COL #1 CALL TIMER * TIMER DADD 4,@FAC2 * SVT+4 DADD 4,@FAC * SAT+4 DCHE >0344,@FAC * LAST ADDRESS? BS G350 * YES, GOTO G350 SUB ARG2,@ARG * ROW#1-ROW#2 CHE 9,@ARG * 9 OR HIGHER? BS G540 * YES, GOTO G540 DST V@SAT,@ARG * ROW:COL #1 SUB @ARG3,@ARG1 * COL#1-COL#2 CHE 9,@ARG1 * 9 OR HIGHER? BS G540 * YES, GOTO G540 G560 DST S560,@SOND * SOUND DATA ADDRESS I/O 0,@SOND * PLAY IT DSUB 4,@FAC * RESET TO ADDRESS DSUB 4,@FAC2 * RESET TO ADDRESS G620 DST >C000,V*FAC * STORE OFF SCREEN DCLR V*FAC2 * ZERO SPRITE VELOCITY INC @B * B+1 CEQ 16,@B * B=32? BR G350 * NO, GOTO G350 ST >D0,V@SAT * OFF SCREEN SPRITE LOCATION This scan keyboard for arrow keys, moves the #1 Sprite accordingly and checks for COINCIDENCE, plays a sound if hit and moves that Sprite off screen and stops velocity, also it has a counter for the number of Spites it has collected. It has 11 variables and looks pretty small for all that. Quote Link to comment Share on other sites More sharing options...
Willsy Posted July 26, 2011 Share Posted July 26, 2011 Sure I have been using GPL for sometime now, more than most others. I convert from Basic, XB and Assembly to GPL. Like Assembly I can use a address instead of a variable for storage. That's just semantics! A variable *is* a memory location! Where do you think TI BASIC or XB (or Forth) programs store their variables? They are stored in memory, of course! Quote Link to comment Share on other sites More sharing options...
RXB Posted July 26, 2011 Share Posted July 26, 2011 Sure I have been using GPL for sometime now, more than most others. I convert from Basic, XB and Assembly to GPL. Like Assembly I can use a address instead of a variable for storage. That's just semantics! A variable *is* a memory location! Where do you think TI BASIC or XB (or Forth) programs store their variables? They are stored in memory, of course! Correct but Basic and XB can not use the same memory to index like ST V*VARIABLE+2,@VARIABLE(@VARIABLE+6), now Forth that is not a problem. I feel like I am in some kind of battle with you. Am I correct? Quote Link to comment Share on other sites More sharing options...
Willsy Posted July 26, 2011 Share Posted July 26, 2011 I feel like I am in some kind of battle with you. Am I correct? Not at all - The TI is my hobby, and I don't spend/waste negative energy on my hobby! Hobbies should be fun! This isn't an argument (at least, not for me) - it's merely a discussion. We might both learn new stuff along the way. That's what it's all about! <-- big smiley! Quote Link to comment Share on other sites More sharing options...
lucien2 Posted July 26, 2011 Share Posted July 26, 2011 (edited) OK, now the C version (compiled with GCC): #define VDP_READ_DATA_REG (*(volatile char*)0x8800) #define VDP_WRITE_DATA_REG (*(volatile char*)0x8C00) #define VDP_ADDRESS_REG (*(volatile char*)0x8C02) #define VDP_READ_FLAG 0x00 #define VDP_WRITE_FLAG 0x40 #define VDP_REG_FLAG 0x80 #define SEED (*(int*)0x83C0) #define TMP (*(volatile char*)0x8300) void vdp_copy_from_sys(int index, char* src, int size) { char* end = src + size; VDP_ADDRESS_REG = index; VDP_ADDRESS_REG = (char)(index >> | VDP_WRITE_FLAG; while(src < end) VDP_WRITE_DATA_REG = *src++; } void vdp_write_reg(int i,char c) { VDP_ADDRESS_REG=c; VDP_ADDRESS_REG=i|VDP_REG_FLAG; } void interrupts() { asm("limi 2"); asm("limi 0"); } /* Does not work, GCC "mpy" bug char random_byte(char c) { SEED=SEED*0x6FE5+0x7AB9; int i=(SEED>>+(SEED<<; return i%c; } */ void random_byte() { asm( "li r7,>6FE5\n\t" "mpy @>83C0,r7\n\t" "ai r8,>7AB9\n\t" "mov r8,@>83C0\n\t" "clr r7\n\t" "swpb r8\n\t" "mov @>8300,r6\n\t" "sra r6,8\n\t" "div r6,r7\n\t" "swpb r8\n\t" "movb r8,@>8300" ); } char vdp_read_byte(int index) { VDP_ADDRESS_REG = index; VDP_ADDRESS_REG = (char)(index >> | VDP_READ_FLAG; asm("nop"); return VDP_READ_DATA_REG; } void shadow(char r,char c,char a) { char g=vdp_read_byte((int)r*32+c); if(g<39) { g=g|a; vdp_copy_from_sys((int)r*32+c,&g,1); } } void main() { char p1[8]={0x00,0x00,0xC0,0xC0,0x3F,0x3F,0xFF,0xFF}; char p2[12]={0x00,0x00,0x00,0x00,0x00,0x00, 0xC0,0xC0,0xC0,0xC0,0xC0,0xC0}; char p3[16]={0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0x7F, 0x01,0x03,0x03,0x03,0x03,0x03,0xFF,0xFF}; char col[8]={0x10,0x23,0x45,0x68,0x89,0xAB,0xC2,0xEF}; int a,b; vdp_write_reg(7,13); for(b=0;b<=1;b++) { for(a=0;a<=3;a++) { vdp_copy_from_sys(0x900+a*8+b*32,p1+a*2,2); vdp_copy_from_sys(0x902+a*8+b*32,p2+b*6,6); } } for(a=0;a<=6;a++)vdp_copy_from_sys(0x940+a*64,p3,16); vdp_copy_from_sys(0x384,col,; char r,c,i,g; while(1) { interrupts(); TMP=23;random_byte();r=TMP; TMP=30;random_byte();c=TMP; g=vdp_read_byte((int)r*32+c); if(g<40) { g=vdp_read_byte((int)r*32+c+1); if(g<40) { TMP=7;random_byte();i=TMP*8+40; vdp_copy_from_sys((int)r*32+c,&i,1); i++; vdp_copy_from_sys((int)r*32+c+1,&i,1); shadow(r,c+2,4); shadow(r+1,c,2); shadow(r+1,c+1,3); shadow(r+1,c+2,1); } } } } Here's the assembly code generated: pseg even def vdp_copy_from_sys vdp_copy_from_sys a r2, r3 mov r1, r4 swpb r4 movb r4, @-29694 ori r1, >4000 movb r1, @-29694 c r2, r3 jhe L4 L5 movb *r2+, @-29696 c r3, r2 jh L5 L4 b *r11 even def vdp_write_reg vdp_write_reg li r3, >8C02 movb r2, *r3 ori r1, >80 swpb r1 movb r1, *r3 b *r11 even def interrupts interrupts * Begin inline assembler code * 23 "main.c" 1 limi 2 * 24 "main.c" 1 limi 0 * End of inline assembler code b *r11 even def random_byte random_byte * Begin inline assembler code * 35 "main.c" 1 li r7,>6FE5 mpy @>83C0,r7 ai r8,>7AB9 mov r8,@>83C0 clr r7 swpb r8 mov @>8300,r6 sra r6,8 div r6,r7 swpb r8 movb r8,@>8300 * End of inline assembler code b *r11 even def vdp_read_byte vdp_read_byte mov r1, r3 swpb r3 li r2, >8C02 movb r3, *r2 movb r1, *r2 * Begin inline assembler code * 53 "main.c" 1 nop * End of inline assembler code movb @-30720, r1 b *r11 even def shadow shadow sra r2, 8 sra r1, 8 sla r1, >5 a r1, r2 mov r2, r1 swpb r1 movb r1, @-29694 movb r2, @-29694 * Begin inline assembler code * 53 "main.c" 1 nop * End of inline assembler code movb @-30720, r4 ci r4, >26FF jgt L18 socb r3, r4 movb r1, @-29694 ori r2, >4000 movb r2, @-29694 movb r4, @-29696 L18 b *r11 even def main main ai r10, >FFC8 mov r10, r0 mov r11, *r0+ mov r9, *r0+ mov r13, *r0+ mov r14, *r0+ mov r15, *r0 mov r10, r8 inct r8 li r9, memcpy mov r8, r1 li r2, C.4.1264 li r3, >8 mov r8, @54(r10) bl *r9 mov r10, r13 ai r13, >12 mov r13, r1 li r2, C.5.1265 li r3, >C bl *r9 mov r10, r15 ai r15, >1E mov r15, r1 li r2, C.6.1266 li r3, >10 bl *r9 mov r10, r14 ai r14, >A mov r14, r1 li r2, C.7.1267 li r3, >8 bl *r9 li r2, >D87 movb r2, @-29694 swpb r2 movb r2, @-29694 mov r13, r6 clr r2 mov @54(r10), r8 L20 mov r8, r3 movb r2, r7 clr r5 movb r2, r0 ai r0, >200 L23 movb r7, @-29694 li r1, >4900 movb r1, @-29694 movb *r3, @-29696 movb @1(r3), @-29696 mov r5, r4 swpb r4 andi r4, >FF00 sla r4, >3 ab r0, r4 movb r4, @-29694 li r1, >4900 movb r1, @-29694 mov r6, r1 clr r4 jmp L21 L22 movb *r1+, @-29696 L21 inc r4 ci r4, >7 jne L22 inc r5 ai r7, >800 inct r3 ci r5, >4 jne L23 ai r6, >6 ai r2, >2000 li r5, >4000 cb r2, r5 jne L20 li r3, >940 mov r10, r1 ai r1, >2E L27 movb r2, @-29694 mov r3, r4 ori r4, >4000 movb r4, @-29694 mov r15, r4 jmp L25 L26 movb *r4+, @-29696 L25 c r4, r1 jne L26 ai r2, >4000 ai r3, >40 ci r3, >B00 jne L27 li r1, >8443 movb r1, @-29694 swpb r1 movb r1, @-29694 mov r14, r2 L28 c r2, r13 jeq L37 movb *r2+, @-29696 jmp L28 L37 li r14, shadow L36 * Begin inline assembler code * 23 "main.c" 1 limi 2 * 24 "main.c" 1 limi 0 * End of inline assembler code li r5, >1700 movb r5, @-32000 * Begin inline assembler code * 35 "main.c" 1 li r7,>6FE5 mpy @>83C0,r7 ai r8,>7AB9 mov r8,@>83C0 clr r7 swpb r8 mov @>8300,r6 sra r6,8 div r6,r7 swpb r8 movb r8,@>8300 * End of inline assembler code movb @-32000, r13 li r6, >1E00 movb r6, @-32000 * Begin inline assembler code * 35 "main.c" 1 li r7,>6FE5 mpy @>83C0,r7 ai r8,>7AB9 mov r8,@>83C0 clr r7 swpb r8 mov @>8300,r6 sra r6,8 div r6,r7 swpb r8 movb r8,@>8300 * End of inline assembler code movb @-32000, r9 movb r13, r3 sra r3, 8 sla r3, >5 movb r9, r1 sra r1, 8 a r1, r3 mov r3, r2 swpb r2 movb r2, @-29694 mov r3, r1 movb r1, @-29694 * Begin inline assembler code * 53 "main.c" 1 nop * End of inline assembler code movb @-30720, r4 ci r4, >27FF jeq JMP_0 jlt JMP_0 b @L36 JMP_0 inc r3 mov r3, r4 swpb r4 movb r4, @-29694 movb r3, @-29694 * Begin inline assembler code * 53 "main.c" 1 nop * End of inline assembler code movb @-30720, r5 ci r5, >27FF jeq JMP_1 jlt JMP_1 b @L36 JMP_1 li r5, >700 movb r5, @-32000 * Begin inline assembler code * 35 "main.c" 1 li r7,>6FE5 mpy @>83C0,r7 ai r8,>7AB9 mov r8,@>83C0 clr r7 swpb r8 mov @>8300,r6 sra r6,8 div r6,r7 swpb r8 movb r8,@>8300 * End of inline assembler code movb @-32000, r5 sra r5, 8 ai r5, >5 swpb r5 andi r5, >FF00 sla r5, >3 movb r2, @-29694 ori r1, >4000 movb r1, @-29694 movb r5, @-29696 ai r5, >100 movb r4, @-29694 ori r3, >4000 movb r3, @-29694 movb r5, @-29696 movb r9, r15 ai r15, >200 movb r13, r1 movb r15, r2 li r3, >400 bl *r14 ai r13, >100 movb r13, r1 movb r9, r2 li r3, >200 bl *r14 movb r13, r1 movb r9, r2 ai r2, >100 li r3, >300 bl *r14 movb r13, r1 movb r15, r2 li r3, >100 bl *r14 b @L36 C.7.1267 byte 16 byte 35 byte 69 byte 104 byte -119 byte -85 byte -62 byte -17 C.6.1266 byte 0 byte 0 byte 0 byte 0 byte 0 byte 0 byte 63 byte 127 byte 1 byte 3 byte 3 byte 3 byte 3 byte 3 byte -1 byte -1 C.5.1265 byte 0 byte 0 byte 0 byte 0 byte 0 byte 0 byte -64 byte -64 byte -64 byte -64 byte -64 byte -64 C.4.1264 byte 0 byte 0 byte -64 byte -64 byte 63 byte 63 byte -1 byte -1 ref memcpy http://www.youtube.com/watch?v=z7lN6QH5m40 Edited July 26, 2011 by lucien2 2 Quote Link to comment Share on other sites More sharing options...
RXB Posted July 26, 2011 Share Posted July 26, 2011 Yep C or Assembly is very fast. Quote Link to comment Share on other sites More sharing options...
sometimes99er Posted July 26, 2011 Author Share Posted July 26, 2011 (edited) Thanks. Excellent video. GPL is apparently not worth it, when C is so much easier. Edited July 26, 2011 by sometimes99er Quote Link to comment Share on other sites More sharing options...
sometimes99er Posted July 26, 2011 Author Share Posted July 26, 2011 If not for Cartidges and that Slot there would be no TurboForth cart. If not Cartidges and that Slot, then it would probably have had some black boxes and a box port holder or something. I'm sure Willsy would have found a way. Quote Link to comment Share on other sites More sharing options...
Willsy Posted July 26, 2011 Share Posted July 26, 2011 Thanks. Excellent video. GPL is apparently not worth it, when C is so much easier. Wow! Yes! Awesome! That beats TF, for sure. However, the development cycle in TF is much nicer Okay, it looks like GCC has set the bar that I have to try to match/beat. This may take some time! Regarding GPL, I think if you can write TMS9900 assembly, you'll have no problems learning GPL. Personally, I'm very interested in learning it - I won't feel like I've fully explored the TI and got the TI coder black belt until I do! Mark 1 Quote Link to comment Share on other sites More sharing options...
sometimes99er Posted July 26, 2011 Author Share Posted July 26, 2011 When the TI99 was introduced it was the GROM slot that sold the machine not the DISK programs or TAPE programs. The TI99 didn't really sell that well when it was introduced. Other home computers was selling with a slot too. That so called GROM slot was a ROM slot too, and thank you Atarisoft for a few decent games for this very closed architecture. I had to buy Mini Memory, just to execute machine code, which most of my friends could do without any expansion. Nice CPU though. Generally a strange architecture. Multiplexer, GROM (slow compared to ROM), and RAM was then actually VRAM. TI Basic was one of the slowest Basics around. A few nice commands, but also many absent. They said it was double interpreted or something. It had to do with GROM and GPL. None of the competitors had that, and I think they did fine without. The TI99 looked cool and nice though, and prices were falling. TI Invaders, Parsec and Speech was hot for a while. But TI was loosing money and shot it down. I don't think it was the GROM slot that sold the machine, I think it was the silver color metal overlay/casing, the cool brand, and Cosby telling us "tons of software". I could also argue that it was the Video Display Processor that sold the machine. Colors and sprites were more convincing than some guy saying, hey you'll get a GROM slot. By the way, nobody in the store told me I was getting a GROM slot, so that was not reason why I bought it. We might as well have to give credit to silicon. Quote Link to comment Share on other sites More sharing options...
Tursi Posted July 26, 2011 Share Posted July 26, 2011 OK, now the C version (compiled with GCC): Thanks for posting that. It's awesome to see the GCC compiler producing programs! And it looks like it runs very well! Quote Link to comment Share on other sites More sharing options...
sometimes99er Posted July 26, 2011 Author Share Posted July 26, 2011 Regarding GPL, I think if you can write TMS9900 assembly, you'll have no problems learning GPL. I think so too. The syntax for GPL is very much like XB. I think the syntax looks more like Assembler. Personally, I'm very interested in learning it - I won't feel like I've fully explored the TI and got the TI coder black belt until I do! I strongly resent that. Meet me outside. I'm really very interested in GPL and plan on having a serious go with it soon. The thing about assembly language on the TI is the TMS9900 instruction set - assembly language on the 99xx is *so easy*, that once you know it well, it really doesn't make sense to 'go backwards' into other languges. Yep. Quote Link to comment Share on other sites More sharing options...
matthew180 Posted July 27, 2011 Share Posted July 27, 2011 Here is a straight assembly version designed to be run as a cartridge. I deviated a little, taking advantage of the fact that I was using assembly, and also a requirement of needing the 32K RAM expansion. I use the lower 8K to buffer the screen in CPU RAM instead of reading / writing the VRAM over and over. The display is pretty much instant, and keep in mind that nothing is drawn to the screen until all the bricks are placed. ** * Bricks with shadows demo * DEF STDHDR * VDP Memory Map * VDPRD EQU >8800 * VDP read data VDPSTA EQU >8802 * VDP status VDPWD EQU >8C00 * VDP write data VDPWA EQU >8C02 * VDP set read/write address * Workspace WRKSP EQU >8300 * Workspace R0LB EQU WRKSP+1 * R0 low byte reqd for VDP routines PGTB EQU >2000 * VRAM Pattern Generator Table Base Address CTBA EQU >0300 * VRAM Color Table Base Address SBUF EQU >2000 * Low 32K RAM expansion for screen buffer ** * Set Up Cartridge * * Always mapped to the cartidge address range AORG >6000 STDHDR BYTE >AA * Indicates a standard header BYTE >01 * Version number BYTE >01 * Number of programs (optional) BYTE >00 * Not used DATA >0000 * Pointer to power-up list (can't use in cartridge ROM) DATA PROG * Pointer to program list DATA >0000 * Pointer to DSR list DATA >0000 * Pointer to subprogram list DATA >0000 * Pointer to ISR list PROG DATA >0000 * No next menu item DATA MAIN * Program start address for this menu item BYTE 10 * Length of text for menu screen TEXT 'BRICK DEMO' EVEN ** * Scratch pad RAM use - Variables * * *THESE MUST BE IN RAM* (since this is a ROM based game... duh) * >8300 * Workspace * >831F * Bottom of workspace STACK EQU >8320 * Subrouting stack, grows down (8 bytes) * >8322 * The stack is maintained in R10 and * >8324 * supports up to 4 BL calls * >8326 NUM38 EQU >8328 * Number 38 in scratchpad NUM39 EQU >8329 * Number 39 in scratchpad NUM4 EQU >832A * Number 4 in scratchpad NUM3 EQU >832B * Number 3 in scratchpad NUM2 EQU >832C * Number 2 in scratchpad NUM1 EQU >832D * Number 1 in scratchpad * Random Number Memory Map - The console seeds >83C0 at startup, see E/A pg. 406 RAND16 EQU >83C0 * 16-BIT random number RANDOM EQU >83C1 * 8-BIT random number * Shadow masks EVEN P1 DATA >0000,>0000,>0000,>0000 DATA >8000,>0000,>0000,>0000 DATA >3F00,>0000,>0000,>0000 DATA >FF00,>0000,>0000,>0000 DATA >0000,>8080,>8080,>8080 DATA >8000,>8080,>8080,>8080 DATA >3F00,>8080,>8080,>8080 DATA >FF00,>8080,>8080,>8080 P1E BRICK DATA >0000,>0000,>0000,>3F7F DATA >0103,>0303,>0303,>FFFF BRICKE COLOR BYTE >23 * Med Grn on Lt Grn BYTE >45 * Drk Blu on Lt Blu BYTE >68 * Drk Red on Med Red BYTE >89 * Med Red on Lt Red BYTE >AB * Drk Yel on Lt Yel BYTE >C2 * Drk Grn on Med Grn BYTE >EF * Gray on White COLORE EVEN RNDCH1 BYTE 40,48,56,64,72,80,88 RNDCH2 BYTE 41,49,57,65,73,81,89 EVEN NUM38B BYTE 38 * Number 38 to load to scratchpad NUM39B BYTE 39 * Number 39 to load to scratchpad NUM4B BYTE 4 * Number 4 to load to scratchpad NUM3B BYTE 3 * Number 3 to load to scratchpad NUM2B BYTE 2 * Number 2 to load to scratchpad NUM1B BYTE 1 * Number 1 to load to scratchpad EVEN ********************************************************************* * * Main Entry Point * * MAIN LIMI 0 * Prevent the console ISR from running LWPI WRKSP LI R10,STACK * Set up the stack pointer MOVB @NUM38B,@NUM38 * Set up constants in scratchpad MOVB @NUM39B,@NUM39 MOVB @NUM4B,@NUM4 MOVB @NUM3B,@NUM3 MOVB @NUM2B,@NUM2 MOVB @NUM1B,@NUM1 BL @GMODE * Set Graphics I * Clear the screen CLR R0 * VRAM address >0000 LI R1,>2000 * Write character 32 (>20) to all locations LI R2,768 * All screen locations BL @VSMW * Clear the CPU RAM screen buffer LI R1,>2020 LI R2,766 LP01 MOV R1,@SBUF(R2) DECT R2 JNE LP01 MOV R1,@SBUF * Define shadow characters LI R0,PGTB+256 * Start at character 32 (32 * 8 bytes per character) LI R1,P1 * Address of source data LI R2,P1E-P1 * Length (in bytes) of data to write BL @VMBW * Define brick characters. The definition * is for the dark color of the brick. LI R3,PGTB+320 * Start bricks at character 40 (40 * LI R4,7 * Write 6 characters sets LP05 MOV R3,R0 * R0 needs to hold the VRAM address maintained by R3 LI R1,BRICK * Address of source data LI R2,BRICKE-BRICK * Length (in bytes) of data to write BL @VMBW AI R3,64 * Next character set DEC R4 * Decrement counter JNE LP05 * Set up brick colors. LI R0,CTBA+5 * Character 40 starts in color set 5 LI R1,COLOR * Address of source data LI R2,COLORE-COLOR * Length (in bytes) of data to write BL @VMBW * After failing to place a brick X times, stop LI R9,1024 FAIL DEC R9 JNE RNDLP B @DUMP * RandomNumber: * R=INT(RND*23)+1 :: C=INT(RND*30)+1 RNDLP BL @RANDNO * Get a random number (in R5) LI R3,736 * Pick a screen buffer location (no bottom row) CLR R4 * Prepare for division DIV R3,R4 * Get a number between 0 and 735 in R5 MOV R5,R6 * Store the random screen location in R6 ANDI R5,>001F * Don't use the column 31 or 32 since bricks are 2 wide CI R5,>001F JEQ FAIL CI R5,>001E JEQ FAIL CB @SBUF(R6),@NUM39 * CALL GCHAR(R, C, G) JH FAIL * IF G>39 THEN RandomNumber CB @SBUF+1(R6),@NUM39 * CALL GCHAR(R, C+1, G) JH FAIL * IF G>39 THEN RandomNumber * I=INT(RND*7)*8+40 LP10 BL @RANDNO * Get a random number (in R5) LI R3,7 * Divide by 7 CLR R4 * Prepare for division DIV R3,R4 * Get a number between 0 and 6 in R5 MOVB @RNDCH1(R5),@SBUF(R6) * CALL HCHAR(R, C, I) MOVB @RNDCH2(R5),@SBUF+1(R6) * CALL HCHAR(R, C+1, I+1) * CheckRight: CB @SBUF+2(R6),@NUM38 * CALL GCHAR(R, C+2, G) JH SKIP05 * IF G>38 THEN CheckDown SOCB @NUM4,@SBUF+2(R6) * CALL HCHAR(R, C+2, G OR 4) * CheckDown: SKIP05 CB @SBUF+32(R6),@NUM38 * CALL GCHAR(R+1, C, G) JH SKIP06 * IF G>38 THEN CheckCorner SOCB @NUM2,@SBUF+32(R6) * CALL HCHAR(R+1, C, G OR 2) * CheckCorner: SKIP06 CB @SBUF+33(R6),@NUM38 * CALL GCHAR(R+1, C+1, G) JH SKIP07 * IF G>38 THEN CheckDiagonal SOCB @NUM3,@SBUF+33(R6) * CALL HCHAR(R+1, C+1, G OR 3) * CheckDiagonal: SKIP07 CB @SBUF+34(R6),@NUM38 * CALL GCHAR(R+1, C+2, G) JH SKIP08 * IF G>38 THEN RandomNumber SOCB @NUM1,@SBUF+34(R6) * CALL HCHAR(R+1, C+2, G OR 1) SKIP08 B @RNDLP * GOTO RandomNumber * Write screen buffer to VRAM DUMP CLR R0 LI R1,SBUF LI R2,768 BL @VMBW ILOOP LIMI 2 LIMI 0 JMP ILOOP ********************************************************************* * * Generates a weak pseudo random number and places it in RAND16 * * R5 - 16-bit random number and stored in RAND16 for next round * RMASK DATA >B400 RANDNO MOV @RAND16,R5 * The seed must not be 0 JNE RND01 INC R5 RND01 SRL R5,1 * Divide by 2 JNC RND02 * Jump if no carry XOR @RMASK,R5 * Apply XOR magic with a special mask RND02 MOV R5,@RAND16 B *R11 *// RANDNO ********************************************************************* * * Sets the graphics mode * * * Bit value 128 64 32 16 8 4 2 1 * * Bit order 0 1 2 3 4 5 6 7 GMODE MOV R11,*R10+ * Push return address onto the stack CLR R0 * M3 is bit 6 and is off for Graphics I BL @VWTR LI R0,>01E0 * 11100000 Graphics I BL @VWTR LI R0,>0200 * Name Base Table to >0000 - >02FF (768 bytes) BL @VWTR LI R0,>030C * Color Table to >0300 - >0320 (32 bytes) BL @VWTR LI R0,>0404 * Pattern Generator Table to >2000 - >2800 (2048 bytes) BL @VWTR LI R0,>0507 * Sprite Attribute Table to >0380 - >03FF (128 bytes) BL @VWTR LI R0,>0605 * Sprite Pattern Table to >2800 - >2C00 (1024 bytes) BL @VWTR LI R0,>0380 * Disable all sprite processing by writing >D0 (208) LI R1,>D000 * to the vertical position of the first sprite entry BL @VSBW * Set colors LI R0,>071D * R7 is the text-mode text color and the border color BL @VWTR LI R0,>0300 * Start of color table LI R1,>1D00 * Black on magenta LI R2,>0020 * All color table entries BL @VSMW DECT R10 * Pop return address off the stack MOV *R10,R11 B *R11 *// GMODE ********************************************************************* * * VDP Single Byte Write * * R0 Write address in VDP RAM * R1 MSB of R1 sent to VDP RAM * * R0 is modified, but can be restored with: ANDI R0,>3FFF * VSBW MOVB @R0LB,@VDPWA * Send low byte of VDP RAM write address ORI R0,>4000 * Set read/write bits 14 and 15 to write (01) MOVB R0,@VDPWA * Send high byte of VDP RAM write address MOVB R1,@VDPWD * Write byte to VDP RAM B *R11 *// VSBW ********************************************************************* * * VDP Single Byte Multiple Write * * R0 Starting write address in VDP RAM * R1 MSB of R1 sent to VDP RAM * R2 Number of times to write the MSB byte of R1 to VDP RAM * * R0 is modified, but can be restored with: ANDI R0,>3FFF * VSMW MOVB @R0LB,@VDPWA * Send low byte of VDP RAM write address ORI R0,>4000 * Set read/write bits 14 and 15 to write (01) MOVB R0,@VDPWA * Send high byte of VDP RAM write address VSMWLP MOVB R1,@VDPWD * Write byte to VDP RAM DEC R2 * Byte counter JNE VSMWLP * Check if done B *R11 *// VSMW ********************************************************************* * * VDP Multiple Byte Write * * R0 Starting write address in VDP RAM * R1 Starting read address in CPU RAM * R2 Number of bytes to send to the VDP RAM * * R0 is modified, but can be restored with: ANDI R0,>3FFF * VMBW MOVB @R0LB,@VDPWA * Send low byte of VDP RAM write address ORI R0,>4000 * Set read/write bits 14 and 15 to write (01) MOVB R0,@VDPWA * Send high byte of VDP RAM write address VMBWLP MOVB *R1+,@VDPWD * Write byte to VDP RAM DEC R2 * Byte counter JNE VMBWLP * Check if done B *R11 *// VMBW ********************************************************************* * * VDP Single Byte Read * * R0 Read address in VDP RAM * R1 MSB of R1 set to byte from VDP RAM * VSBR MOVB @R0LB,@VDPWA * Send low byte of VDP RAM write address MOVB R0,@VDPWA * Send high byte of VDP RAM write address MOVB @VDPRD,R1 * Read byte from VDP RAM B *R11 *// VSBR ********************************************************************* * * VDP Multiple Byte Read * * R0 Starting read address in VDP RAM * R1 Starting write address in CPU RAM * R2 Number of bytes to read from VDP RAM * VMBR MOVB @R0LB,@VDPWA * Send low byte of VDP RAM write address MOVB R0,@VDPWA * Send high byte of VDP RAM write address VMBRLP MOVB @VDPRD,*R1+ * Read byte from VDP RAM DEC R2 * Byte counter JNE VMBRLP * Check if finished B *R11 *// VMBR ********************************************************************* * * VDP Write To Register * * R0 MSB VDP register to write to * R0 LSB Value to write * VWTR MOVB @R0LB,@VDPWA * Send low byte (value) to write to VDP register ORI R0,>8000 * Set up a VDP register write operation (10) MOVB R0,@VDPWA * Send high byte (address) of VDP register B *R11 *// VWTR END 1 Quote Link to comment Share on other sites More sharing options...
sometimes99er Posted July 27, 2011 Author Share Posted July 27, 2011 Thank you Matthew, that is absolutely marvellous. Yes, almost instant. Very nice twist - the approach. Use of white space is of cause important (readability), still the original XB source is pretty compact for what it is. 18 lines which might even be brought down further. Maybe at the expensive of speed, but then XB can't hardly draw two bricks before your version fills the screen. Quote Link to comment Share on other sites More sharing options...
lucien2 Posted July 27, 2011 Share Posted July 27, 2011 /* Does not work, GCC "mpy" bug char random_byte(char c) { SEED=SEED*0x6FE5+0x7AB9; int i=(SEED>>+(SEED<<; return i%c; } */ Thanks to insomnia, it's already corrected. So here's the new version, without this awful inline assembly trick. #define VDP_READ_DATA_REG (*(volatile char*)0x8800) #define VDP_WRITE_DATA_REG (*(volatile char*)0x8C00) #define VDP_ADDRESS_REG (*(volatile char*)0x8C02) #define VDP_READ_FLAG 0x00 #define VDP_WRITE_FLAG 0x40 #define VDP_REG_FLAG 0x80 #define SEED (*(int*)0x83C0) void vdp_copy_from_sys(int index, char* src, int size) { char* end = src + size; VDP_ADDRESS_REG = index; VDP_ADDRESS_REG = (char)(index >> | VDP_WRITE_FLAG; while(src < end) VDP_WRITE_DATA_REG = *src++; } void vdp_write_reg(int i,char c) { VDP_ADDRESS_REG=c; VDP_ADDRESS_REG=i|VDP_REG_FLAG; } void interrupts() { asm("limi 2"); asm("limi 0"); } char random_byte(char c) { SEED=SEED*0x6FE5+0x7AB9; int i=((unsigned)SEED>>+(SEED<<; return (unsigned)i%c; } char vdp_read_byte(int index) { VDP_ADDRESS_REG = index; VDP_ADDRESS_REG = (char)(index >> | VDP_READ_FLAG; asm("nop"); return VDP_READ_DATA_REG; } void shadow(char r,char c,char a) { char g=vdp_read_byte((int)r*32+c); if(g<39) { g=g|a; vdp_copy_from_sys((int)r*32+c,&g,1); } } void main() { char p1[8]={0x00,0x00,0xC0,0xC0,0x3F,0x3F,0xFF,0xFF}; char p2[12]={0x00,0x00,0x00,0x00,0x00,0x00, 0xC0,0xC0,0xC0,0xC0,0xC0,0xC0}; char p3[16]={0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0x7F, 0x01,0x03,0x03,0x03,0x03,0x03,0xFF,0xFF}; char col[8]={0x10,0x23,0x45,0x68,0x89,0xAB,0xC2,0xEF}; int a,b; vdp_write_reg(7,13); for(b=0;b<=1;b++) { for(a=0;a<=3;a++) { vdp_copy_from_sys(0x900+a*8+b*32,p1+a*2,2); vdp_copy_from_sys(0x902+a*8+b*32,p2+b*6,6); } } for(a=0;a<=6;a++)vdp_copy_from_sys(0x940+a*64,p3,16); vdp_copy_from_sys(0x384,col,; char r,c,i,g; while(1) { interrupts(); r=random_byte(23); c=random_byte(30); g=vdp_read_byte((int)r*32+c); if(g<40) { g=vdp_read_byte((int)r*32+c+1); if(g<40) { i=random_byte(7)*8+40; vdp_copy_from_sys((int)r*32+c,&i,1); i++; vdp_copy_from_sys((int)r*32+c+1,&i,1); shadow(r,c+2,4); shadow(r+1,c,2); shadow(r+1,c+1,3); shadow(r+1,c+2,1); } } } } 1 Quote Link to comment Share on other sites More sharing options...
sometimes99er Posted July 27, 2011 Author Share Posted July 27, 2011 You guys are moving fast. I like that. Quote Link to comment Share on other sites More sharing options...
matthew180 Posted July 27, 2011 Share Posted July 27, 2011 Thank you Matthew, that is absolutely marvellous. Yes, almost instant. Very nice twist - the approach. It could be faster if there was an actual "end condition", all of the versions could really. Filling the screen randomly is easy, but inefficient. I think once you get to a certain density, linear scanning to fill in the holes would probably speed things up. I was going to do that, but it was late. In my assembly version, the screen is not drawn until trying to place a brick has failed 1024 times, which is a completely arbitrary number that I chose based on trial and error. If you reduce the number you get results faster, but less dense. However, as the number goes up, you get less and less for a bigger and bigger number as the random number selection tries to fill out those last few spots. still the original XB source is pretty compact for what it is. 18 lines which might even be brought down further. Maybe at the expensive of speed, but then XB can't hardly draw two bricks before your version fills the screen. Absolutely, the XB version is compact! That's the advantage of a higher level language, and that should always be considered. Unfortunately for us, using XB means we greatly sacrifice speed. The TF and C options seem to produce something in the middle are nice alternatives to have. For me though, I'll always be an assembly guy. Also keep in mind though, a good part of the code is support functions, cartridge header setup, and EQUates which don't resolve in to actual code. But, the program listing as a whole is still the largest version I think, and that probably makes it look intimidating. 1 Quote Link to comment Share on other sites More sharing options...
RXB Posted July 27, 2011 Share Posted July 27, 2011 (edited) Matthew I was thinking, about what would the calculation be for filling the screen. There would be a range of like 300 at the least and 320 at the most in the range so you would not have to do any check for being done till that lowest range is reached. Even in XB that would be a section of program that would not slow down the main loop. Like: FOR X=1 TO LOWESTRANGE NEXT X Then start checking if done. Edited July 27, 2011 by RXB Quote Link to comment Share on other sites More sharing options...
sometimes99er Posted July 28, 2011 Author Share Posted July 28, 2011 (edited) There would be a range of like 300 at the least and 320 at the most in the range so you would not have to do any check for being done till that lowest range is reached. Let's number rows, 1 to 24 and columns, 1 to 32 like XB does. When placing bricks, row 24 and column 32 are always reserved for shadows. Shadows anywhere else run the risk of being overwritten by a brick. If we look at the rows only, we can place bricks in any of the first 23 rows - last one is for shadows only. When we look at the columns only, we have 31 columns at our disposal - again last one for shadows only. Bricks are 2 columns wide, so the maximum number of bricks per row is 31/2 = 15.5, that's obviously a maximum 15 bricks (shown below). Now there may be a space between bricks with the width of 1 column (a width of 2 would leave room for a brick). If we place the first brick at column 2, we see that a space and a brick fills 3 columns. We could continue like that to the right of this, putting a space and a brick. The minimum number of bricks per row is 31/3 = 10.333, and that's 10 bricks. Overall we multiply the minimum and maximum numbers, 10 and 15, with the available number of rows, 23. Minimum number of bricks for the screen is 230 (10*23) and maximum is 345 (15*23). Edited April 17, 2015 by sometimes99er Quote Link to comment Share on other sites More sharing options...
RXB Posted July 28, 2011 Share Posted July 28, 2011 That is a much wider spread then I originally thought there would be. Quote Link to comment Share on other sites More sharing options...
lucien2 Posted September 30, 2012 Share Posted September 30, 2012 Now here's the TP99 version. As explained in the doc, you have to run from DSK1 and put RUNLIB in the disk. I didn't find it in the doc, but you also have to run first TP99 or LK99 and do a warm restart... I edited LK99 to just load and restart, and renamed it LD99. Edit: LD99 is not needed with the hardware. PROGRAM BRICKS; CONST PAT=2048; SCR=4096; COL=896; VAR P1:ARRAY[3] OF STRING[4]; P2:ARRAY[1] OF STRING[12]; A,B,R,C,I,G:INTEGER; PROCEDURE PEEKV(ADDR:INTEGER; VAR BYTE: STRING[1]); EXTERNAL; PROCEDURE POKEV(ADDR:INTEGER; BYTE: STRING[1]); EXTERNAL; PROCEDURE BREAK; EXTERNAL; FUNCTION BWOR(I1,I2:INTEGER):INTEGER; EXTERNAL; PROCEDURE CHAR(C:INTEGER; S:STRING[16]); VAR I,I2,I3:INTEGER; B:BOOLEAN; S2:STRING[1]; BEGIN B:=FALSE; FOR I:=1 TO 16 DO BEGIN I2:=ASC(SEG(S,I,1)); IF I2>57 THEN I2:=I2-7; I2:=I2-48; IF B THEN BEGIN B:=FALSE; I3:=I3+I2; S2:=CHR(I3); POKEV(PAT+C*8+I DIV 2-1,S2); END ELSE BEGIN B:=TRUE; I3:=I2*16; END; END; END; PROCEDURE COLOR(I,F,B:INTEGER); BEGIN POKEV(COL+I,CHR((F-1)*16+B-1)); END; FUNCTION GCHAR(R,C:INTEGER):INTEGER; VAR S:STRING[1]; BEGIN PEEKV(SCR+(R-1)*32+(C-1),S); GCHAR:=ASC(S); END; PROCEDURE HCHAR(R,C,I:INTEGER); BEGIN POKEV(SCR+(R-1)*32+(C-1),CHR(I)); END; BEGIN GRAPHICS; SCREEN(2,14); P1[0]:="0000"; P1[1]:="C0C0"; P1[2]:="3F3F"; P1[3]:="FFFF"; P2[0]:="000000000000"; P2[1]:="C0C0C0C0C0C0"; FOR B:=0 TO 1 DO BEGIN FOR A:=0 TO 3 DO BEGIN CHAR(32+A+B*4,P1[A]&P2[b]); END; END; FOR A:=0 TO 6 DO BEGIN CHAR(40+A*8,"0000000000003F7F"); CHAR(41+A*8,"010303030303FFFF"); END; COLOR(5,3,4); COLOR(6,5,6); COLOR(7,7,9); COLOR(8,9,10); COLOR(9,11,12); COLOR(10,13,3); COLOR(11,15,16); RANDOMIZE; WHILE TRUE DO BEGIN R:=RND(22)+1; C:=RND(29)+1; IF GCHAR(R,C)<=39 THEN BEGIN IF GCHAR(R,C+1)<=39 THEN BEGIN I:=RND(6)*8+40; HCHAR(R,C,I); HCHAR(R,C+1,I+1); G:=GCHAR(R,C+2); IF G<=38 THEN HCHAR(R,C+2,BWOR(G,4)); G:=GCHAR(R+1,C); IF G<=38 THEN HCHAR(R+1,C,BWOR(G,2)); G:=GCHAR(R+1,C+1); IF G<=38 THEN HCHAR(R+1,C+1,BWOR(G,3)); G:=GCHAR(R+1,C+2); IF G<=38 THEN HCHAR(R+1,C+2,BWOR(G,1)); END; END; END; END. And the assembly part: DEF POKEV,PEEKV,BREAK,BWOR WP BSS >20 VDPWA EQU >8C02 VDPWD EQU >8C00 VDPRD EQU >8800 VWFLAG BYTE >40 EVEN POKEV LIMI 0 AI R0,-4 LWPI WP MOV @>8300,R3 MOV *R3+,R0 MOV *R3,R1 ANDI R1,>FF SWPB R1 SWPB R0 MOVB R0,@VDPWA SWPB R0 SOCB @VWFLAG,R0 MOVB R0,@VDPWA MOVB R1,@VDPWD LWPI >8300 LIMI 2 RT PEEKV LIMI 0 AI R0,-4 LWPI WP MOV @>8300,R3 MOV *R3+,R0 SWPB R0 MOVB R0,@VDPWA SWPB R0 MOVB R0,@VDPWA LI R1,1 MOVB @VDPRD,R1 SWPB R1 MOV *R3,R3 MOV R1,*R3 LWPI >8300 LIMI 2 RT BREAK LIMI 0 LWPI WP LI R0,>FF00 MOVB R0,@0 LWPI >8300 LIMI 2 RT BWOR LIMI 0 AI R0,-4 LWPI WP MOV @>8300,R0 MOV *R0+,R1 MOV *R0,R0 SOC R1,R0 LWPI >8300 MOV @WP,R14 LIMI 2 RT END BRICKS_TP99.zip 2 Quote Link to comment Share on other sites More sharing options...
lucien2 Posted April 16, 2015 Share Posted April 16, 2015 After 2 1/2 years, here's a new version of my favorite "benchmark" program, this time in Java. Execution speed is just slightly slower than C. You can compare it with my video above. Code size: 870 bytes for the C version, 1222 bytes for the Java version. Java BRICKS.zip The Java part: import net.mikekohn.java_grinder.TI99; public class Bricks { static byte[] p1={0x00,0x00,(byte)0xC0,(byte)0xC0,(byte)0x3F,(byte)0x3F,(byte)0xFF,(byte)0xFF}; static byte[] p2={0x00,0x00,0x00,0x00,0x00,0x00, (byte)0xC0,(byte)0xC0,(byte)0xC0,(byte)0xC0,(byte)0xC0,(byte)0xC0}; static byte[] p3={0x00,0x00,0x00,0x00,0x00,0x00,(byte)0x3F,(byte)0x7F, 0x01,0x03,0x03,0x03,0x03,0x03,(byte)0xFF,(byte)0xFF}; static byte[] col={0x10,0x23,0x45,0x68,(byte)0x89,(byte)0xAB,(byte)0xC2,(byte)0xEF}; static public void shadow(int r,int c,int a) { byte g=TI99.vdp_read_byte(r*32+c); if(g<39) { g=(byte)(g|a); TI99.vdp_write_byte(r*32+c,g); } } static public int random_byte(int c) { int SEED=TI99.seed(); SEED=SEED*0x6FE5+0x7AB9; int i=(SEED>>>+(SEED<<; TI99.setSeed(SEED); return (int)(byte)(i%c); } static public void main(String args[]) { int a,b; TI99.vdp_write_reg(7,13); for(b=0;b<=1;b++) { for(a=0;a<=3;a++) { TI99.vdp_copy_from_indexed_array(0x900+a*8+b*32,p1,a*2,2); TI99.vdp_copy_from_indexed_array(0x902+a*8+b*32,p2,b*6,6); } } for(a=0;a<=6;a++)TI99.vdp_copy_from_sys(0x940+a*64,p3,16); TI99.vdp_copy_from_sys(0x384,col,; int r,c,i,g; while(true) { TI99.interrupts(); r=random_byte(23); c=random_byte(30); g=TI99.vdp_read_byte(r*32+c); if(g<40) { g=TI99.vdp_read_byte(r*32+c+1); if(g<40) { i=random_byte(7)*8+40; TI99.vdp_write_byte(r*32+c,(byte)i); i++; TI99.vdp_write_byte(r*32+c+1,(byte)i); shadow(r,c+2,4); shadow(r+1,c,2); shadow(r+1,c+1,3); shadow(r+1,c+2,1); } } } } } The assembly part: #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdint.h> #include "TI99.h" TI99::TI99() {} TI99::~TI99() { //vdp_copy_from_sys fprintf(out, "_vdp_copy_from_sys:\n"); fprintf(out, " swpb r0\n"); fprintf(out, " movb r0, @VDP_COMMAND\n"); fprintf(out, " swpb r0\n"); fprintf(out, " ori r0, 0x4000\n"); fprintf(out, " movb r0, @VDP_COMMAND\n"); fprintf(out, "_vdp_copy_from_sys_L1:\n"); fprintf(out, " movb *r1+, @VDP_WRITE\n"); fprintf(out, " dec r2\n"); fprintf(out, " jne _vdp_copy_from_sys_L1\n"); fprintf(out, " b *r11\n\n"); } int TI99::open(const char *filename) { if (TMS9900::open(filename) != 0) { return -1; } fprintf(out, "ram_start equ 0xa000\n"); fprintf(out, "heap_ptr equ ram_start\n"); return 0; } int TI99::start_init() { fprintf(out, "\n"); fprintf(out, ".org 0x6000\n"); fprintf(out, " .db 0xaa, 0x01, 0x01, 0x00\n"); fprintf(out, " .dw 0x0000\n"); fprintf(out, " .dw _prog\n"); fprintf(out, " .dw 0x0000\n"); fprintf(out, " .dw 0x0000\n"); fprintf(out, " .dw 0x0000\n"); fprintf(out, " .dw 0x0000\n"); fprintf(out, "_prog:\n"); fprintf(out, " .dw 0x0000\n"); fprintf(out, " .dw start\n"); fprintf(out, " .db 11, \"BRICKS JAVA\"\n"); fprintf(out, ".align 16\n\n"); // Add any set up items (stack, registers, etc). fprintf(out, "start:\n"); fprintf(out, "VDP_COMMAND equ 0x8c02\n"); fprintf(out, "VDP_WRITE equ 0x8c00\n"); fprintf(out, "VDP_READ equ 0x8800\n"); fprintf(out, " lwpi 0x8300\n"); return 0; } int TI99::ti99_vdp_copy_from_sys() { fprintf(out, " mov r%d, r0\n", REG_STACK(reg-3)); fprintf(out, " mov r%d, r1\n", REG_STACK(reg-2)); fprintf(out, " mov r%d, r2\n", REG_STACK(reg-1)); fprintf(out, " mov r11, *r10+\n"); fprintf(out, " bl @_vdp_copy_from_sys\n"); fprintf(out, " ai r10, -2\n"); fprintf(out, " mov *r10, r11\n"); reg -= 3; return 0; } int TI99::ti99_vdp_read_byte() { fprintf(out, " swpb r%d\n", REG_STACK(reg-1)); fprintf(out, " movb r%d, @VDP_COMMAND\n", REG_STACK(reg-1)); fprintf(out, " swpb r%d\n", REG_STACK(reg-1)); fprintf(out, " movb r%d, @VDP_COMMAND\n", REG_STACK(reg-1)); fprintf(out, " jmp $+2\n"); fprintf(out, " clr r%d\n", REG_STACK(reg-1)); fprintf(out, " movb @VDP_READ, r%d\n", REG_STACK(reg-1)); fprintf(out, " swpb r%d\n", REG_STACK(reg-1)); return 0; } int TI99::ti99_vdp_write_reg() { fprintf(out, " swpb r%d\n", REG_STACK(reg-2)); fprintf(out, " swpb r%d\n", REG_STACK(reg-1)); fprintf(out, " movb r%d, @VDP_COMMAND\n", REG_STACK(reg-1)); fprintf(out, " ori r%d, 0x8000\n", REG_STACK(reg-2)); fprintf(out, " movb r%d, @VDP_COMMAND\n", REG_STACK(reg-2)); reg -=2; return 0; } int TI99::ti99_interrupts() { fprintf(out, " limi 2\n"); fprintf(out, " limi 0\n"); return 0; } int TI99::ti99_vdp_write_byte() { fprintf(out, " swpb r%d\n", REG_STACK(reg-2)); fprintf(out, " movb r%d, @VDP_COMMAND\n", REG_STACK(reg-2)); fprintf(out, " swpb r%d\n", REG_STACK(reg-2)); fprintf(out, " ori r%d, 0x4000\n", REG_STACK(reg-2)); fprintf(out, " movb r%d, @VDP_COMMAND\n", REG_STACK(reg-2)); fprintf(out, " swpb r%d\n", REG_STACK(reg-1)); fprintf(out, " movb r%d, @VDP_WRITE\n", REG_STACK(reg-1)); reg -= 2; return 0; } int TI99::ti99_seed() { reg += 1; fprintf(out, " mov @0x83C0, r%d\n", REG_STACK(reg-1)); return 0; } int TI99::ti99_setSeed() { fprintf(out, " mov r%d, @0x83C0\n", REG_STACK(reg-1)); reg -= 1; return 0; } int TI99::ti99_vdp_copy_from_indexed_array() { fprintf(out, " mov r%d, r0\n", REG_STACK(reg-4)); fprintf(out, " mov r%d, r1\n", REG_STACK(reg-3)); fprintf(out, " mov r%d, r3\n", REG_STACK(reg-2)); fprintf(out, " mov r%d, r2\n", REG_STACK(reg-1)); fprintf(out, " a r3, r1\n"); fprintf(out, " mov r11, *r10+\n"); fprintf(out, " bl @_vdp_copy_from_sys\n"); fprintf(out, " ai r10, -2\n"); fprintf(out, " mov *r10, r11\n"); reg -= 4; return 0; } 4 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.