+Vorticon Posted May 14 Share Posted May 14 Where is all the TI-centric p-system software? I checked out the Whtech site and all there is are the system disks. I'm looking for examples of what was achieved using that system aside from @apersson850's own work. Were there any games made for it using the TI libraries included with the system? The documentation for these can be spotty in places or missing important information (such as the sound volume detail discussed above), or advanced usage of sprites. For example, I am a bit unclear on the usage of the SPRITE_CHANGE_LIST. When I create a sprite using the SET_SPR_ATTRIBUTE function which is supposed to automatically create a SPRITE_CHANGE_LIST, how do I subsequently access specific fields for that sprite such as color or position since I don't know the name assigned to that list? So far the only way to do this that I know of is to use the SET_SPR_ATTRIBUTE function each time I want to make a change to the sprite, and that's a slow function. There has to be a better way. 1 Quote Link to comment Share on other sites More sharing options...
Tursi Posted May 14 Share Posted May 14 I don't have a lot to contribute to Pascal discussion, but I do remember that 99er published a Pascal game called Cannibal. I never saw it run 1 1 Quote Link to comment Share on other sites More sharing options...
+Vorticon Posted May 15 Share Posted May 15 4 hours ago, Tursi said: I don't have a lot to contribute to Pascal discussion, but I do remember that 99er published a Pascal game called Cannibal. I never saw it run I'll see if I can find it. Thanks! Quote Link to comment Share on other sites More sharing options...
apersson850 Posted May 15 Author Share Posted May 15 22 hours ago, Vorticon said: ...and that's a slow function. There has to be a better way. The advantages of separately compiled units are many, but speed isn't one of them. An inter-segment external global call is about the slowest thing you can execute as a p-code. If you want to do a graphical game in Pascal for some reason, then you need to do something special with the graphics, I would presume. Quote Link to comment Share on other sites More sharing options...
+Vorticon Posted May 15 Share Posted May 15 I do have a project in mind. We'll see if it comes together. Quote Link to comment Share on other sites More sharing options...
+Vorticon Posted May 16 Share Posted May 16 To answer my own questions about sprite usage, you can either set up a SPRITE_CHANGE_LIST manually or use SET_SPR_ATTRIBUTE, but not both because they will overwrite each other. The former is cumbersome because it's very verbose, but it's much faster than the latter once it is set up and provides you with additional features such as a sprite "lifespan countdown" and automatic linking to other lists, so it's a trade off. Below is an example. Link is already pre-defined by the SPRITE unit. var car0 : link; begin (* define new sprite *) new(car0); car0^.packet := [spr_pattern..spr_x_vel]; with car0^ do begin pattern_number := 136; color := 4; clock := 0; y_pos := 175; x_pos := 0; y_vel := -10; x_vel := 5; countdown := 0; link := nil; end; (* start up the sprite *) set_sprite(0, car0); (* change the sprite's position and velocity *) with car0^ do begin y_pos := 99; x_pos := 127; y_vel := 0; x_vel := 0; end; (* with any change the sprite has to be reassigned to the SPRITE_CHANGE_LIST *) set_sprite(0, car0); (* Now compare this to using just the SET_SPR_ATTRIBUTE function *) (* Define sprite and set it in motion *) SET_SPR_ATTRIBUTE(136, 4, 0, 175, 0, -10, 5); (* change sprite position and velocity *) SET_SPR_ATTRIBUTE(136, 4, 0, 99, 127, 0, 0); 2 Quote Link to comment Share on other sites More sharing options...
+Vorticon Posted May 19 Share Posted May 19 There is actually a way to get a pointer to a sprite's change list after using the SET_SPR_ATTRIBUTE function: simply use the GET_SPRITE function! Not sure how I missed that. In other words, set up a sprite with SET_SPR_ATTRIBUTE, then execute a GET_SPRITE to get a pointer to it. From there on one can access any of the sprite elements in the change list directly. Unfortunately, it turns out that sprite functionality in the p-system is not as flexible as one might think at first glance. For example, you cannot check sprite coincidence between 2 specified sprites. The SPRITE_COINC is a boolean function that returns true when any sprite coincides with any other sprite, plus there is no way to check for coincidence between a sprite and a specific coordinate point, unlike XB. And to make matters worse, the x_pos and y_pos values are not updated automatically as the sprite moves. Not sure if this is a bug or intentional, but it's a major limitation (I think it's a bug). There are workarounds of course, but it makes sprite usage clumsy at best. Feels half baked in some sense. 2 Quote Link to comment Share on other sites More sharing options...
+TheBF Posted May 19 Share Posted May 19 14 minutes ago, Vorticon said: There is actually a way to get a pointer to a sprite's change list after using the SET_SPR_ATTRIBUTE function: simply use the GET_SPRITE function! Not sure how I missed that. In other words, set up a sprite with SET_SPR_ATTRIBUTE, then execute a GET_SPRITE to get a pointer to it. From there on one can access any of the sprite elements in the change list directly. Unfortunately, it turns out that sprite functionality in the p-system is not as flexible as one might think at first glance. For example, you cannot check sprite coincidence between 2 specified sprites. The SPRITE_COINC is a boolean function that returns true when any sprite coincides with any other sprite, plus there is no way to check for coincidence between a sprite and a specific coordinate point, unlike XB. And to make matters worse, the x_pos and y_pos values are not updated automatically as the sprite moves. Not sure if this is a bug or intentional, but it's a major limitation (I think it's a bug). There are workarounds of course, but it makes sprite usage clumsy at best. Feels half baked in some sense. Pure conjecture here, but this sounds like the sprite table has a replica somewhere in RAM which is what you change in your program. That table would be copied out to VDP RAM(maybe on the video interrupt?) to make things happen, but it seems they don't ever copy it back. I played with that idea when I tried to make sprites work. It was simpler to use the VDP memory functions to fetch and store bytes to/from VDP and just manipulate VDP RAM like it was normal memory. It's slower but just as with P-code, you are not running at processor speed anyway so writing to RAM and doing a block copy to VDP didn't seem to by me much. Does Pascal give you functions to peek/poke VDP RAM? @apersson850 can help us understand what is actually happening behind the curtain. 2 Quote Link to comment Share on other sites More sharing options...
apersson850 Posted May 19 Author Share Posted May 19 I've never dechipered the sprite movement code in the p-system, since I've never used it for anything serious. You can write peek and poke yourself in Pascal, thus also access VDP RAM directly. But if you do you have to make sure your program doesn't run from VDP RAM, since then you change the address to the running code. 1 Quote Link to comment Share on other sites More sharing options...
+Vorticon Posted May 19 Share Posted May 19 I dug a little further into this and it turns out the Sprite Attribute List starts at >C00. This is interesting because according to the EA manual sprite auto-motion requires the SAL to be at >300, which tells me that the p-system seems to actively move sprites directly. Second, the table only contains sprites that are on screen, with those defined off-screen not represented. The table appears to be initialized to >C000 >0000 for each sprite otherwise. >C000 is 192,0 which is just off screen. And I can see that the x and y positions for the visible sprites are updated in real time. So @TheBF's hunch is correct in that there must be a master copy of the SAL in RAM somewhere which is likely not a fixed location but depends on available memory for any particular program and the x and y positions in the VDP are not updating the RAM copy. This has got to be a bug. The good news is that I can easily write a small assembly procedure to check a sprite's position now that I know where to look for it. Homework for today 😁 4 Quote Link to comment Share on other sites More sharing options...
Asmusr Posted May 19 Share Posted May 19 35 minutes ago, Vorticon said: I dug a little further into this and it turns out the Sprite Attribute List starts at >C00. This is interesting because according to the EA manual sprite auto-motion requires the SAL to be at >300, which tells me that the p-system seems to actively move sprites directly. Second, the table only contains sprites that are on screen, with those defined off-screen not represented. The table appears to be initialized to >C000 >0000 for each sprite otherwise. >C000 is 192,0 which is just off screen. And I can see that the x and y positions for the visible sprites are updated in real time. So @TheBF's hunch is correct in that there must be a master copy of the SAL in RAM somewhere which is likely not a fixed location but depends on available memory for any particular program and the x and y positions in the VDP are not updating the RAM copy. This has got to be a bug. The good news is that I can easily write a small assembly procedure to check a sprite's position now that I know where to look for it. Homework for today 😁 It sounds like it works the same way as in all my games. Why do you think that's a bug? Quote Link to comment Share on other sites More sharing options...
+Vorticon Posted May 19 Share Posted May 19 46 minutes ago, Asmusr said: It sounds like it works the same way as in all my games. Why do you think that's a bug? The only way to obtain the current sprite position is by looking up the x_pos and y_pos elements of the sprite's change list as there is no function to do that for you in the p-system. These elements are not getting updated as the sprite moves, and retain their original value when the sprite was created. This makes little sense and severely limits the usability of sprites. Yes, you can get around that by using assembly routines, but I'm talking here about what's available to the user within the p-system proper. Quote Link to comment Share on other sites More sharing options...
Asmusr Posted May 19 Share Posted May 19 56 minutes ago, Vorticon said: The only way to obtain the current sprite position is by looking up the x_pos and y_pos elements of the sprite's change list as there is no function to do that for you in the p-system. These elements are not getting updated as the sprite moves, and retain their original value when the sprite was created. This makes little sense and severely limits the usability of sprites. Yes, you can get around that by using assembly routines, but I'm talking here about what's available to the user within the p-system proper. I don't know much about the p-system, but it makes sense to me to keep your master list of sprites in CPU RAM and rebuild the sprite attribute list in VDP RAM on the fly. But if you can't read back the content of the master list, then yes, that's a problem. 3 Quote Link to comment Share on other sites More sharing options...
+Vorticon Posted May 19 Share Posted May 19 Exactly... Quote Link to comment Share on other sites More sharing options...
+TheBF Posted May 19 Share Posted May 19 This may be of some interest @Vorticon I build a thingy I call a table creators. It allows me to point to a base address of any kind of memory and when given a parameter it computes the offset into that "table" using Assembly Language. For the Sprite table I have TABLE4: which assumes records are four bytes. The offset into each sprite record takes only 2 instructions. SLA Rx,2 and A Rx,Ry I create a separate TABLE4 for each field in a SPRITE record by making each TABLE4 start one byte higher. Using this kind of thing means that reading and writing single bytes with a fetch and store operator into VDP RAM is still pretty quick. It ends up looking like this in Forth, using SAT (sprite attribute table) base address in VDP RAM. SAT TABLE4: SP.Y SAT 1+ TABLE4: SP.X SAT 2+ TABLE4: SP.PAT SAT 3 + TABLE4: SP.COLR The usage is like this #1 SP.Y VC@ #1 SP.X VC@ \ "fetch sprite 1 x and y from VDP RAM RED #3 SP.COLR VC! \ set #3 sprite's colour Not sure how that would translate to Pascal but the concept could have the same advantages as in Forth where there is an underlying interpreter slowing things down. 2 Quote Link to comment Share on other sites More sharing options...
apersson850 Posted May 20 Author Share Posted May 20 (edited) Yes, Pascal runs a sprite movement system all by its own. I've never studied it in detail, as I've not used it. The only two things I remember is that it has two bitmaps at 280AH for sprites 0-15 and 16-31 where it indicates which are moving automatically. So when using Pascal, make sure your moving sprites are in one of these groups if you have no more than 16, since it will skip messing with the whole group if no sprite is moving there. The other thing I remember is that the printout of the assembly routine handling the sprites is about two pages (A4). About 140 bytes of memory fit on one page. As you understand I know where it is in memory, so I can easily find it and analyze it. Time permitting... At 2808H there's a sprite coincidence counter, so some sprite related data is in that area. Edited May 20 by apersson850 2 Quote Link to comment Share on other sites More sharing options...
+Vorticon Posted May 20 Share Posted May 20 Here's a real life code snippet on how to check the position of a moving sprite. It uses VSBR (VDP Single Byte Read) from my VDPUTIL library. In testing I had this a repeat/until loop checking for a destination position and it worked really well and was reasonably fast. set_sprite(sprnum, car[sprnum]); (* start sprite moving *) salloc := 3072 + (sprnum * 4); (* find location of sprite entry in the Sprite Attribute List *) vsbr(salloc, y); (* get y position *) vsbr(salloc + 1, x); (* get x position *) Below is the listing of VDPUTIL ready to assemble. Spoiler ;vdp access routines ;by walid maalouli ;march 2024 vdpwa .equ 8c02h ;vdp write address vdprd .equ 8800h ;vdp read data vdpwd .equ 8c00h ;vdp write data vrtab .equ 2810h ;location of vdp registers copies for PME .proc vwtr,2 ;vdp write to register ;usage: vwtr(regnum, byteval) .def vsavtab mov *r10+,r0 ;get the register value li r1,8000h ;bit mask for msb swpb *r10 ;r10 has pointer to register number socb r1,*r10 ;set the most significant bit swpb r0 movb r0,@vdpwa ;write byte value nop movb *r10,@vdpwa ;write the register number nop b *r11 vsavtab .block 8 .proc vsbr,2 ;vdp single byte read ;usage: vsbr(vdpadr, intvar) mov *r10+,r0 ;get the pointer to the variable swpb *r10 ;r10 now has the vdp address movb *r10,@vdpwa ;write the vdp address lsb swpb *r10 movb *r10,@vdpwa ;write the vdp address msb nop clr *r0 movb @vdprd,*r0 ;store vdp byte into variable swpb *r0 b *r11 .proc vmbr,3 ;vdp multiple byte read ;usage: vmbr(vdpadr, bytearray, bytenum) mov *r10+,r0 ;get the number of bytes to read mov *r10+,r1 ;get the pointer to the byte array swpb *r10 ;r10 now has the vdp address movb *r10,@vdpwa ;write the vdp address lsb swpb *r10 movb *r10,@vdpwa ;write the vdp address msb nop readnxt movb @vdprd,*r1+ ;read byte dec r0 jne readnxt ;done reading all bytes? b *r11 .proc vsbw,2 ;vdp single byte write ;usage: vsbw(vdpadr, intval) mov *r10+,r0 ;get the pointer to the variable swpb *r10 ;r10 now has the vdp address movb *r10,@vdpwa ;write the vdp address lsb swpb *r10 li r1,4000h ;bit mask for vdp address msb socb r1,*r10 ;set the 2 most significant bits movb *r10,@vdpwa ;write the vdp address msb swpb r0 movb r0,@vdpwd ;write byte to vdp address b *r11 .proc vmbw,3 ;vdp multiple byte write ;usage: vmbw(vdpadr, bytearray, bytenum) mov *r10+,r0 ;get the number of bytes to write mov *r10+,r1 ;get the pointer to the byte array swpb *r10 ;r10 now has the vdp address movb *r10,@vdpwa ;write the vdp address lsb swpb *r10 li r2,4000h ;bit mask for vdp address msb socb r2,*r10 ;set the 2 most significant bits movb *r10,@vdpwa ;write the vdp address msb wrinxt movb *r1+,@vdpwd ;write byte to vdp dec r0 jne wrinxt ;done writing all the bytes? b *r11 .proc regcopy,2 ;save copy of vdp register in pme table at >2810 ;usage: regcopy(regnum, byteval) mov *r10+,r0 ;get register value mov *r10,r1 ;get register number dec r1 ;calculate vr address in table sla r1,1 ai r1,vrtab movb r0,*r1 ;save vr value in table b *r11 .proc savevr ;save default pme vdp registers ;usage: savevr .ref vsavtab li r1,vrtab ;point to pme vr table li r2,7 ;number of registers to save li r3,vsavtab ;point to register save table savnxt movb *r1+,*r3+ ;save register dec r2 jne savnxt ;are all registers saved? (vr1-vr7) b *r11 .proc restorevr ;restore default pme vdp registers ;usage: restorevr .ref vsavtab li r1,vsavtab ;point to register save table li r2,7 ;number of registers to restore li r3,vrtab ;point to pme vr table resnxt movb *r1+,*r3+ ;restore register dec r2 jne resnxt ;are all registers restored? (vr1-vr7) b *r11 .end 2 Quote Link to comment Share on other sites More sharing options...
+Vorticon Posted May 21 Share Posted May 21 Best I could make it. Still not bad 2 Quote Link to comment Share on other sites More sharing options...
apersson850 Posted May 22 Author Share Posted May 22 The utility modrs232 shows how you can access VDP RAM directly from Pascal, if you want to. Quote Link to comment Share on other sites More sharing options...
+Vorticon Posted May 22 Share Posted May 22 1 hour ago, apersson850 said: The utility modrs232 shows how you can access VDP RAM directly from Pascal, if you want to. Indeed, but it's not complete. I preferred to roll my own to suit my needs better. Quote Link to comment Share on other sites More sharing options...
apersson850 Posted May 23 Author Share Posted May 23 I rather meant that the principle is demonstrated in that program. Of course you can run your own. 2 Quote Link to comment Share on other sites More sharing options...
+Vorticon Posted Monday at 01:05 PM Share Posted Monday at 01:05 PM How does one override the system font again? Quote Link to comment Share on other sites More sharing options...
apersson850 Posted Monday at 05:21 PM Author Share Posted Monday at 05:21 PM (edited) By having a file called SYSTEM.CHARAC on the system disk (#4) at boot time. That is *SYSTEM.CHARAC in p-system lingo. You can use the file OS:SYSTEM.CHARAC as a template, if you like. It's a simple memory image of the character definitions. Edited Monday at 05:22 PM by apersson850 1 1 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.