WIP: Tetris + any GCL tips?

Using, learning, programming and modding the Gigatron and anything related.
Forum rules
Be nice. No drama.
pthomas
Posts: 4
Joined: 15 May 2018, 17:15

Re: WIP: Tetris + any GCL tips?

Post by pthomas »

I generated a trace of vcpu instructions from Gigatris.gt1 using the javascript emulator and saw this (the value after the ... is the virtual link register):

Code: Select all

0200 cd39  DEF 39 ... 02fe
023b 2b3a  STW 3a ... 02fe
023d cd56  DEF 56 ... 02fe
0258 2b3e  STW 3e ... 02fe
025a cda0  DEF a0 ... 02fe
02a2 2b4a  STW 4a ... 02fe
02a4 cdbd  DEF bd ... 02fe
02bf 2b4e  STW 4e ... 02fe
02c1 cded  DEF ed ... 02fe
02ef 2b56  STW 56 ... 02fe
02f1 931b  INC 1b ... 02fe
02f3 ff00  RET 00 ... 03fe
03fe 4846  .cond5 46 ... 03fe
03cf 2b42  STW 42 ... 03fe
It looks like the code assumes the LR will be 0x200, so that it can increment the MSB and RET to 0x300; however, the loader sets the LSB of the LR to 2 less than the start address, so we actually end up executing a vCPU instruction from 0x3fe, which is some random value from oscL[3]. Sometimes this instruction is harmless and the vPC advances, rolling over in the LSB to 0x300, but sometimes it vectors off into the weeds as it did here.
User avatar
marcelk
Posts: 488
Joined: 13 May 2018, 08:26

Re: WIP: Tetris + any GCL tips?

Post by marcelk »

It looks like the code assumes the LR will be 0x200
Ah!!! That is what the Loader is supposed to do... The ROM loader does this and the built-in applications rely on that. But clearly the Loader application doesn't and testing it with "Blinky" didn't reveal this. My mistake :oops: That also explains the reports of problems with reloading native applications over the loader interface. It all makes sense now.

It didn't cross my mind, because at67's life3.gt1 is also multi-segmented and works fine. But his programs don't use this setup mechanism with vLR. A true bug found in ROM v1. I fear it is essentially unfixable because it is in everybody's ROM v1. Shame on me.

A workaround in Chris' game can be to use the explicit sequence to hop over boundaries:

Code: Select all

$300 call
Not as nice byte-wise, but within gcl0x I see no other way yet. We'll, it is a lot clearer what is going on, that is a win...

[Edit: A true hack is to patch this part of the Loader from the gt1 file itself before the execution starts. After all, the Loader itself is in RAM as well. In fact, it is the colourful row of pixels you see on the screen underneath the scanning bar.]
pthomas
Posts: 4
Joined: 15 May 2018, 17:15

Re: WIP: Tetris + any GCL tips?

Post by pthomas »

Doesn't the loader use SYS_LoaderProcessInput_48 which does the subtraction of 2 from the start address and stores it in vPC and vLR? That routine is in ROM, and can't be patched.
User avatar
marcelk
Posts: 488
Joined: 13 May 2018, 08:26

Re: WIP: Tetris + any GCL tips?

Post by marcelk »

I was just going through it and came the same realisation. It is adjusting both vLR and vPC at the same time and from there it is too late because we have already entered the loaded program.

Code: Select all

              d746 0129  ld   [$29]       ;Execute
              d747 a002  suba $02
              d748 c216  st   [$16] ;<-- vPC
              d749 c21a  st   [$1a] ;<-- vLR
It should have done something like this:

Code: Select all

              d746 0129  ld   [$29]       ;Execute
              d747 c21a  st   [$1a] ;<-- vLR (unadjusted because RET subtracts 2)
              d748 a002  suba $02
              d749 c216  st   [$16] ;<-- vPC (adjusted because NEXT adds 2)
One idea is then to load a tiny patch anywhere in unused RAM that sets up vLR correctly before jumping to the intended execution address. That idea is half-broken because jumping, with CALL, changes vLR and that defeats the purpose. And jumping by performing a STW into vPC doesn't work either, because NEXT doesn't reload the Y register. (The vCPU tries to keep the code page in Y when not leaving its primary page.) We need to pass REENTER to reload the vPC high byte into Y. Only instructions that escape from the primary page will do that. Looking for such vCPU instructions to abuse, I think we can do our jump with ... DOKE!

Replace the last 3 bytes in the GT1 file

Code: Select all

0x00, 0x02, 0x00
with

Code: Select all

0x5b, 0x7e, 0x0e, // Patch segment, 14 bytes at $5b7e (looks nicely aligned with Loader)
0x11, 0x00, 0x02, // LDWI $0200
0x2b, 0x1a,       // STW  vLR
0x59, 0x16,       // LDI  vPC
0x2b, 0x24,       // STW  sysArgs0
0x11, 0xfe, 0x02, // LDWI $02fe
0xf3, 0x24,       // DOKE sysArgs0
0x00, 0x5b, 0x7e, // Execute: run patch first
I quickly tested this, any now the program starts reliably on my board. \o/

Although in principle the GT1 file doesn't have to change for this (the external device can inject the patch in the last frame transmitted), it is much better to carry such patch around in the GT1 files that need it for their setup phase. Otherwise also emulators need adjustment and spreading complexity to innocent bystanders is a sign of a wrong idea.

Follow-up: The dilemma is, are we going to fix the ROM routine bug at some point in time? I tend to say "better not!", because it invites incompatibility down the road. Here we see the birth of legacy... At least what happens to vLR is well-defined, albeit a bit useless. And oh well, ROM v1 already has legacy in it: it still has a debounce delay loop for the reset button that only exists on my breadboard prototype...
Last edited by marcelk on 16 May 2018, 00:05, edited 5 times in total.
User avatar
marcelk
Posts: 488
Joined: 13 May 2018, 08:26

Re: WIP: Tetris + any GCL tips?

Post by marcelk »

Having played the game now (it looks FANTASTIC), some thoughts. Perhaps not immediately applicable for this program, but it can give ideas on using the limited resources of the system in other projects:

1. The tetrominoes keep flickering when they aren't falling to the next position. You can reduce a lot of flicker by changing the order/frequency of actions: not redrawing them when the game state doesn't change.

2. The blocks are 4 pixels in height, and the first line looks the same as the fourth. You can reorganise the video indirection table such that every fourth line is a copy of the the 1st. With that you need to address fewer bytes. Judging by the fast scrolling of the title image, you have already mastered the use of the even addresses in the video indirection table.

3. The odd addresses work slightly different. They are X offsets, but they also accumulate from top to bottom. You can make horizontal scrolling very easily with that. But you can also implement double buffering if the playing field is not too wide. And that is exactly what you have here. (Barring the image data that you have in the off-screen area.)

The double-buffering idea is that you toggle bit 7 of one of the odd-indexed bytes in the video indirection table. That will shift the corresponding scanline by 128 pixels in X direction, and every scanline following, in one go. With that you can bring a second playfield into view. The visible area is 160 pixels, so 160-128 = 32 pixels will be shared between both views. Just leave them blue. You do your drawing in the off-screen area, and then toggle. This will work for playfields up to 96 pixels wide, with 32 opaque pixels left and right. (I was thinking this might help with a smooth 1st-person view maze game. For Gigatris, it would be overkill.)
Cwiiis
Posts: 27
Joined: 14 May 2018, 09:04

Re: WIP: Tetris + any GCL tips?

Post by Cwiiis »

Aah, this is interesting and explains what I was seeing before I think? (it's late, so I've not thought through this properly...) I worked around this by padding all pages out with zeros, so I guess it would consistently execute harmless code - for me, this gives consistent behaviour on hardware and emulators, but could issues still arise doing this? I've not seen any bad loads doing this yet. The patching method is a bit of a shame as memory is already very limited, but I guess it's just a few bytes :)

Anyway, I've improved the game now so that it runs faster and has solid drawing - I'm quite pleased with it :) A new video: https://youtu.be/46E1Pj0BvuQ

Hopefully I can introduce the rest of the features without slowing the game down any, as this point feels about right... There are probably still a few more avenues of optimisation, but things are getting tight.
Cwiiis
Posts: 27
Joined: 14 May 2018, 09:04

Re: WIP: Tetris + any GCL tips?

Post by Cwiiis »

marcelk wrote: 15 May 2018, 23:50 2. The blocks are 4 pixels in height, and the first line looks the same as the fourth. You can reorganise the video indirection table such that every fourth line is a copy of the the 1st. With that you need to address fewer bytes. Judging by the fast scrolling of the title image, you have already mastered the use of the even addresses in the video indirection table.
Ooh, this is a neat idea, I hadn't thought of that! That'll save quite a few cycles :) I had planned on putting some graphics by the side of the field and maybe displaying some stats, so will have to see if it conflicts with that though...
marcelk wrote: 15 May 2018, 23:50 3. The odd addresses work slightly different. They are X offsets, but they also accumulate from top to bottom. You can make horizontal scrolling very easily with that. But you can also implement double buffering if the playing field is not too wide. And that is exactly what you have here. (Barring the image data that you have in the off-screen area.)

The double-buffering idea is that you toggle bit 7 of one of the odd-indexed bytes in the video indirection table. That will shift the corresponding scanline by 128 pixels in X direction, and every scanline following, in one go. With that you can bring a second playfield into view. The visible area is 160 pixels, so 160-128 = 32 pixels will be shared between both views. Just leave them blue. You do your drawing in the off-screen area, and then toggle. This will work for playfields up to 96 pixels wide, with 32 opaque pixels left and right. (I was thinking this might help with a smooth 1st-person view maze game. For Gigatris, it would be overkill.)
Ooh, this is cool too :) Like you say, probably a bit overkill for this, but definitely a useful technique for more action-oriented/less grid-based games.

A quick edit, in case anyone wants to try it out, it's here (this file will probably update as I work on it): https://www.dropbox.com/s/oshibfempa9d3 ... s.gt1?dl=0
pthomas
Posts: 4
Joined: 15 May 2018, 17:15

Re: WIP: Tetris + any GCL tips?

Post by pthomas »

After loading the start address into vLR, can't you just RET?
pthomas
Posts: 4
Joined: 15 May 2018, 17:15

Re: WIP: Tetris + any GCL tips?

Post by pthomas »

Also, the file format doesn't allow a write to page 0 other than the first segment, but a loader can do whatever it wants. What if the loader writes the start address minus 2 and the start address minus nothing to the vPC and vLR in page 0, and not send the start command. Wouldn't the return from the sys call jump to the start address?
at67
Posts: 383
Joined: 14 May 2018, 08:29

Re: WIP: Tetris + any GCL tips?

Post by at67 »

Cwiiis wrote: 16 May 2018, 00:22 A quick edit, in case anyone wants to try it out, it's here (this file will probably update as I work on it): https://www.dropbox.com/s/oshibfempa9d3 ... s.gt1?dl=0
The first external .gt1 file I have tested in my emulator! (apart from blinky :P) Looks and works great, but it only starts maybe 1 in 5 times.

Here's a short unlisted video, the first time I execute it fails, the second time it runs fine, I play until around the 2minute mark and then I try and execute it a few more times where it randomly fails again, (it comes good after a few attempts).

https://youtu.be/YY9jQo8BLF0

I'm wondering if this is how I am executing vCPU code, rather than monitoring the state of the vCPU interpreter before I modify vPC, I just blast an execute address into vPC and hope for the best. Up until now it has yet to fail me...
Post Reply