It is currently Mon Oct 20, 2014 5:41 pm

All times are UTC [ DST ]




Post new topic Reply to topic  [ 39 posts ]  Go to page Previous  1, 2
Author Message
PostPosted: Wed Jul 28, 2010 1:21 pm 
Offline
Site Admin
User avatar
 Profile

Joined: Wed Dec 19, 2007 10:46 pm
Posts: 779
Thanks, Martin.

I'm not sure I know exactly how IRQs and stuff work, so I'll do some reading around tonight and see if I can get a grip on what you're talking about.

Before I bother Tom with another disc image, I'll see if I can convert the pseudocode I wrote above to reset the any of the remaining Plus 1 values that aren't being used for level data, into assembler and append it to Rich's code. It probably won't affect the K glitch, but I think it best to complete the routine as I envisaged before hassling him again.

I did forget to try last night the K-Glitch image with the single-level-relocate routine with the original levelset to see if that makes any difference (the other image without the single-level-relocate routine uses the standard levels). At the moment the K-Glitch image has a line 30 which patches over the original level data with new levels (to test Rich's routine). This means that that part of the Plus 1's workspace does end up looking like (starting at &0D68):

20 13 02 02 12 04 11 17

instead of:

20 12 0c 18 0f 17 0b 01

as it does in the unglitched image without the single-level-relocate routine, as that uses the original level data. It's /possible/ that one of those other values is important and somehow causing the glitch. The extra bit of pseudocode I want to add in should reset as many of them back to their default values as I can manage (including the &BB value at &0D69 you refer to, which is always trampled over atm with different values depending on the level data), so it's possible it might have an effect.

If I get time, I'll also try rewriting the reverse-engineered joystick patch to be more legible as Rich has explained to me some of the wonders of two-pass assembly, that I didn't have a working knowledge of when I did the original disassembly (though I've handed out the original source code to Tom and Rich so that's not too big of an issue).

Sam.


Top
 
PostPosted: Wed Jul 28, 2010 7:03 pm 
Offline
Site Admin
User avatar
 Profile

Joined: Wed Dec 19, 2007 10:46 pm
Posts: 779
Ah-hah!

When I use the original levels, the K glitch disappears!

Overwriting &06D8 - &06DF with the correct Plus 1 values fixes the glitch ... so my hunch paid off. :)

This means I only need to convert the pseudocode I posted above into assembler to complete the routine.

Finally! Something is finally doing what it's supposed to ... !

That still leaves the ADFS issue which I'm stumped on and, Martin, there's now your recent issue running this version on your work beeb. I'll try to finish this version off and send it over so you can try it again ... and maybe also on your unmodified beeb.

Sam.


Top
 
PostPosted: Wed Jul 28, 2010 7:46 pm 
Offline
User avatar
 Profile

Joined: Mon Sep 14, 2009 7:50 pm
Posts: 91
Sorry... Bit late and some of this is way over my head.....

For my level storage which can varry in size I've made a pointer table and just index that to find the correct starting location for the level data.....

The assembler takes care of the rest....

LEVELDHI .byte >Level01,>Level02,>Level03,>Level04, etc etc...
LEVELDLO .byte <Level01,<Level02,<Level03,<Level04, etc etc....

Level01 .byte xx, xx, xx, xx, etc, $FF(end)
Level02 .byte xx, xx, xx, xx, xx, xx, xx, etc, $FF(end)

You could also have a Size table, by doing a bit of subtraction.....

If the data was less than 256 bytes for each you could do..... ( I think)

LevelSize .byte Level02-Level01, Level03-Level02, etc, etc.....

I don't need to worry about sizes of data as I'm only parsing them and use $FF as the Terminator byte, and not copying....

Regards, Colin


Top
 
PostPosted: Wed Jul 28, 2010 9:07 pm 
Offline
Site Admin
User avatar
 Profile

Joined: Wed Dec 19, 2007 10:46 pm
Posts: 779
@ColinD, you and me both. :)

Rich is a long-suffering code guru, who has put up with my feeble CE hacking attempts many times over the years. It's his own fault for writing such a cracking extra colours patch five years ago ... which I've been building on like a house of cards ever since!

Your method looks good, but I have to resort to hacking on what's there. As Rich says, ideally one day someone will take the disassemblies we have of the game and take the next step to create a modern assembler source file which can be modified at will. Until then, my mission is to hack away on the original and bring it as many new features as possible. Unfortunately, the game was never designed with joystick support in mind, so inadvertantly causes problems on the Electron by overwriting the workspace used by the Plus 1 to provide joystick functionality. Hence, my attempts to move things out of the way.

OK,

So here's what I've come up with. Hopefully Rich and/or Martin can sanity check this for me.

This is my pseudocode ...

Code:
IF !(pointerstable[X+1]) > &D69 THEN &D69=&BB
IF !(pointerstable[X+1]) > &D6A THEN &D6A=&80
IF !(pointerstable[X+1]) > &D6B THEN &D6B=&00
IF !(pointerstable[X+1]) > &D6C THEN &D6C=&90
IF !(pointerstable[X+1]) > &D6D THEN &D6D=&01
IF !(pointerstable[X+1]) > &D6E THEN &D6E=&D6
IF !(pointerstable[X+1]) > &D6F THEN &D6F=&F1


Which is meant to say: if the start address of the level /above/ the one we've moved out of the way, is above each value of the rest of the plus 1's workspace that I'm interested in (&0D68-&0D6F), then reset that value. If the next level starts on top of one of those values, then leave them as they are.

So I've come up with the following assembler. Does it look anywhere close?

And, judging from the size of this routine, is there any neater way of doing it that I'm missing?

Hmmm ... hang on ... I've just compared this routine with the test in Rich's original routine, and it seems identical ... so maybe mine isn't doing greater than (>) like it should. Maybe it's doing <= like Rich's ... errr ...

Sam.

Code:
LDA #&69
CMP pointerstable+2,X MOD 256
LDA #&0D
SBC pointerstable+3,X DIV 256
BCC resetnine

.checka
LDA #&6A
CMP pointerstable+2,X MOD 256
LDA #&0D
SBC pointerstable+3,X DIV 256
BCC reseta

.checkb
LDA #&6B
CMP pointerstable+2,X MOD 256
LDA #&0D
SBC pointerstable+3,X DIV 256
BCC resetb

.checkc
LDA #&6C
CMP pointerstable+2,X MOD 256
LDA #&0D
SBC pointerstable+3,X DIV 256
BCC resetc

.checkd
LDA #&6D
CMP pointerstable+2,X MOD 256
LDA #&0D
SBC pointerstable+3,X DIV 256
BCC resetd

.checke
LDA #&6E
CMP pointerstable+2,X MOD 256
LDA #&0D
SBC pointerstable+3,X DIV 256
BCC resete

.checkf
LDA #&6F
CMP pointerstable+2,X MOD 256
LDA #&0D
SBC pointerstable+3,X DIV 256
BCC resetf

.finish
JMP <backtoCE>

.resetnine
LDA #&BB
STA &0D69
JMP checka
.reseta
LDA #&80
STA &0D6A
JMP checkb
.resetb
LDA #&00
STA &0D6B
JMP checkc
.resetc
LDA #&90
STA &0D6C
JMP checkd
.resetd
LDA #&01
STA &0D6D
JMP checke
.resete
LDA #&D6
STA &0D6E
JMP checkf
.resetf
LDA #&F1
STA &0D6F
JMP finish


Top
 
PostPosted: Wed Jul 28, 2010 9:27 pm 
Offline
Site Admin
User avatar
 Profile

Joined: Wed Dec 19, 2007 10:46 pm
Posts: 779
Hmm ..

Should it look like:

Code:
LDA #&69
CMP pointerstable+2,X MOD 256
LDA #&0D
ADC pointerstable+3,X DIV 256
BCC resetnine


?

Specifically, I'm not sure if that's correctly doing a greater than (> &0D69) comparison ...

Sam.


Top
 
PostPosted: Thu Jul 29, 2010 12:28 am 
Offline
User avatar
 Profile

Joined: Fri Apr 25, 2008 7:55 pm
Posts: 147
No, using ADC isn't what you want to do. I won't create confusion by sticking my oar into the actual code since Rich will probably add/alter what's needed but just to help you understand a little better...

In the first code, Rich was effectively performing a 16 bit comparison of the pointer addresses and the target address to determine a less than or equal to condition. I say 'effectively' because he uses CMP for the ls bytes and SBC for the ms bytes. CMP is actually an odd instruction in that it does internally do an [A-data] instruction but non-destructively such that only the flags are set as a result. Here, he uses CMP to set/reset the Carry flag for subsequent use in the following SBC. The advantage of using CMP for comparisons is that the initial state of the Carry flag doesn't matter because it will be explicitly set to a 1 or a 0 depending on the result of the CMP and will not be influenced by the entry state of Carry. He then uses SBC which performs a destructive [A-data] and this is affected by the entry state of the carry flag brought forward from the CMP. (The code actually looks odd at first sight becasue a CMP is almost always followed by a branch instruction.)

Therefore (easy for me to say), a test for 'greater than' as opposed to 'less than' or 'equal to' is defined by approriate branching on the state of the C & Z (zero) flags following CMP and/or SBC. Simplistically then, you might use the same sequence to perform the comparison but replacing BCC with BCS can invert the logical outcome. (Simplistically because you may also need to invoke an additional branch condition or conditions such as BEQ, BPL or BMI to cater for the specific outcome requirement.)

Thus, your changing the SBC to ADC (add with carry) wouldn't achieve what you're after.


Top
 
PostPosted: Thu Jul 29, 2010 10:25 am 
Offline
Site Admin
User avatar
 Profile

Joined: Wed Dec 19, 2007 10:46 pm
Posts: 779
Thanks, Martin.

Shortly after posting that, I did some more googling around and found this article, 6502.org Tutorials: Compare Instructions - Beyond 8-bit Unsigned Comparisons by Bruce Clark, which showed me that ADC isn't at all what I wanted. Duh. I also took a look through some of the books on assembly language linked from the assembly language section of the RS Useful Docs page. Problem was, I couldn't get my head around exactly what I did need for a greater than comparison, so didn't post a follow-up.

From what you've just said, and a helpful note I've had from Rich, does this line of pseudocode:

Code:
IF the value at pointerstable[X+1] > &D69 THEN JMP resetnine

where pointerstable looks like:

Code:
0CC0 D0 0C
0CC2 00 31
0CC4 FF 0C
... etc.

look like it translates into this:

Code:
LDA pointerstable+2,X      ; LSB of the 16-bit value
CMP #&69 MOD 256
LDA pointerstable+3,X      ; MSB of the 16-bit value
SBC #&0D DIV 256
BCS resetnine

And does it work without modifying X (which will be needed again for the next comparisons in the chain)?

Sam.

P.S. I'm aware that this falls over if X is 8, i.e. the last level, but that's so unlikely to happen in the real world that I'm burying my head in the sand and ignoring that case to save bothering anyone else with it. :)


Top
 
PostPosted: Thu Jul 29, 2010 9:53 pm 
Offline
Site Admin
User avatar
 Profile

Joined: Wed Dec 19, 2007 10:46 pm
Posts: 779
OK, so who spotted the deliberate errors? :)

Code:
LDA pointerstable+2,X      ; LSB of the 16-bit value
CMP #&0D6A MOD 256
LDA pointerstable+3,X      ; MSB of the 16-bit value
SBC #&0D6A DIV 256
BCS resetnine

I needed to put in the full 16-bit constant value, for the MOD and DIVs to work. Duh! And I also had to add one to that value in order to make it > than and not >=.

For completeness, I figured this out with the help of the program I wrote included below.

Patch as I originally designed, is now complete. I'll bung you a disc image and maybe you can do a little bit of testing with it, Martin. This is a paired down version of what will go in the final product ... from my testing, the only thing that I know it doesn't work with, which I consider an issue (but is probably out of my capabilities to fix) is ADFS on the Electron.

Would be nice if you could test it on a beeb that has DFS and ADFS fitted. I can't imagine why it would conflict with that, but just for completeness.

I also discovered why you had an issue with one of the previous builds on your beeb, Martin ... and it was entirely your own fault. :) Only kidding ... but for some reason, it turns out I can't drop PAGE down to &1100 on a Beeb with DFS. Not even &1200. Based on trial and error, it looks like &1300 is the magic number. Don't know why that is, as I'm not doing anything but reading from disc ... and makes me a bit concerned that not everything is going to fit together in one patch anymore. :(

Got a lot of work ahead of me to find out, tho ...

Sam.

Code:
   10REM Program to compare the values
   20REM at memory loc. &1900 and &1901
   30REM with the constant &1901
   40REM (i.e. &1901+1)
   50REM purpose is to test greater
   60REM than (>) routine
   70?&1908=&00
   80PRINT "STARTING ... &1908 is set to &";~(?&1908)
   90FOR pass=0 TO 3 STEP 3
  100P%=&2000:[OPTpass
  110LDA #&02
  120STA &1900
  130LDA #&19
  140STA &1901
  150LDA &1900
  160CMP #&1902 MOD 256
  170LDA &1901
  180SBC #&1902 DIV 256
  190BCS setflag
  200.finish
  210RTS
  220.setflag
  230LDA #&FF
  240STA &1908
  250JMP finish
  260]
  270NEXT
  280CALL &2000
  290PRINT "FINISHING ... &1908 is set to &";~(?&1908)
  300END


Top
 
PostPosted: Thu Jul 29, 2010 11:03 pm 
Offline
Site Admin
User avatar
 Profile

Joined: Wed Dec 19, 2007 10:46 pm
Posts: 779
Stop the clock! Hey, I just re-tested and it looks like now the ADFS issue is fixed too. :)

Perhaps it was something to do with the Plus 1 being overwritten, but it all seems to work fine now.

Hurrah! God bless us, every one! :)

Do your worst with it, Martin, when the fuss at your end dies down and let me know if you find any incompatibilities with any of the common BBC/Electron hardware ...

Sam.


Top
 
PostPosted: Fri Jul 30, 2010 1:40 pm 
Offline
User avatar
 Profile

Joined: Fri Apr 25, 2008 7:55 pm
Posts: 147
Managed a quick play last night and everything held together ok on an Elk and my development Beeb, both under DFS.

Well done that man... ;)


Top
 
PostPosted: Fri Jul 30, 2010 2:01 pm 
Offline
User avatar
 Profile

Joined: Sun Jun 28, 2009 11:37 pm
Posts: 55
Samwise wrote:
for some reason, it turns out I can't drop PAGE down to &1100 on a Beeb with DFS. Not even &1200. Based on trial and error, it looks like &1300 is the magic number. Don't know why that is, as I'm not doing anything but reading from disc ...

This problem can be caused by a disc that uses an exec !BOOT file (*OPT 4,3). Pages &1100 and &1200 are used as workspace to open and read the contents of the boot file and would get trampled on when a program is loaded at the lower PAGE address.

Say the program you want to run is called CE, your !BOOT file will look something like this:

*BASIC
PAGE=&1100
CHAIN"CE"

This will fail because at the time of loading CE, the !BOOT file is still open so the program will overwrite the DFS workspace.

If !BOOT is changed to the following, it will work:

*BASIC
*KEY 0 PAGE=&1100|MCHAIN"CE"|M
*FX138,0,128

This sets up a function key definition and puts the key F0 into the keyboard buffer. The commands won't actually be run until after the !BOOT file has closed and control is returned back to BASIC. At that time it's safe to overwrite the DFS workspace because it's no longer in use.


Top
 
PostPosted: Fri Jul 30, 2010 2:13 pm 
Offline
User avatar
 Profile

Joined: Mon Jan 07, 2008 6:46 pm
Posts: 380
Location: Málaga, Spain
Another alternative is to CHAIN a stub program from your !BOOT file:

!Boot:
Code:
*BASIC
CHAIN "Loader"


Loader:
Code:
10 *FX 119
20 PAGE=&1100
30 CHAIN "Whatever"


The *FX 119 forcibly closes all *EXEC / *SPOOL files in case for some reason there are more characters pending in the !Boot file.


Top
 
PostPosted: Fri Jul 30, 2010 2:14 pm 
Offline
User avatar
 Profile

Joined: Mon Jan 07, 2008 6:46 pm
Posts: 380
Location: Málaga, Spain
BTW Sam - great work! Glad you managed to get it all working well in the end :)


Top
 
PostPosted: Fri Jul 30, 2010 2:14 pm 
Offline
Site Admin
User avatar
 Profile

Joined: Wed Dec 19, 2007 10:46 pm
Posts: 779
MartinB wrote:
Managed a quick play last night and everything held together ok on an Elk and my development Beeb, both under DFS.

Well done that man... ;)

Excellent news. Though Rich of course gets the most credit, as he wrote the most important 90% of the routine. I even managed to screw up compiling it, first time round. :)

PaulDv wrote:
This problem can be caused by a disc that uses an exec !BOOT file (*OPT 4,3). Pages &1100 and &1200 are used as workspace to open and read the contents of the boot file and would get trampled on when a program is loaded at the lower PAGE address.

Paul, that sounds /exactly/ like what's going wrong. I had some vague ideas along those lines, but didn't have time to formulate my thoughts into an actual question worth posting, as I was too busy finishing off the rest of this patch last night. Sounds like you're way ahead of me, tho ... I'll give it a go tonight, and I reckon your suggestion should sort it out - I'm pretty sure everything worked fine, if I just skipped the !BOOT part and ran the code directly. Down the line, those extra &200 bytes will /really/ come in handy too, I suspect.

Many thanks, that was very timely and useful advice!

Sam.


Top
 
PostPosted: Fri Jul 30, 2010 2:35 pm 
Offline
Site Admin
User avatar
 Profile

Joined: Wed Dec 19, 2007 10:46 pm
Posts: 779
haha. I think everyone has got some brief time to spare over their lunch breaks. Replies coming thick and fast, now. :)

RichTW wrote:
Another alternative is to CHAIN a stub program from your !BOOT file:

Good to know, Rich. In my case, I think I will try out Paul's approach first because I have a real problem with the number of files that are on the disc. I'm pretty sure I'm going to hit the 31 limit, and that's even with me combining several menus into one program. Can't afford the luxury of another file, I'm afraid!

RichTW wrote:
BTW Sam - great work! Glad you managed to get it all working well in the end :)

Thanks to all you folk on the good ship, RS. :) I've still got a /lot/ of refactoring work to pull it all together.

I'm sure there's a more efficient way to write the bits of assembler that I wrote, but so long as it works and I can fit it all memory at the same time (which remains to be seen), it's good enough for me. Come to think of it, I'm sure someone with a bit more talent could probably have come up with a more reliable method of getting the joystick on the Electron working with any possible user-defined levels, where my method will fall-over with a small number of possible levelsets under certain conditions. But, then, that might head out of the loader patch territory and into the completely compile a new-enhanced version of the game, which I've been studiously avoiding.

With this patch, I was working on the make-it-good-enough-even-if-its-not-perfect mentality whilst trying-not-to-outstay-my-welcome-with-the-friendly-assembler-gurus who frequent this place, and this routine passes both my criteria ... :)

Sam.


Top
 
PostPosted: Fri Jul 30, 2010 8:41 pm 
Offline
 Profile

Joined: Sun Aug 16, 2009 1:49 pm
Posts: 2
Samwise wrote:
RichTW wrote:
Another alternative is to CHAIN a stub program from your !BOOT file:

Good to know, Rich. In my case, I think I will try out Paul's approach first because I have a real problem with the number of files that are on the disc. I'm pretty sure I'm going to hit the 31 limit, and that's even with me combining several menus into one program. Can't afford the luxury of another file, I'm afraid!


No need for a separate program, just add it to the start of an existing menu..

10 IF PAGE>&1100 A%=119:CALL&FFF4:PAGE=&1100:CHAIN"SELF"
20 PRINT"Rest of menu"


Top
 
PostPosted: Sat Jul 31, 2010 6:35 pm 
Offline
 Profile

Joined: Sun Aug 16, 2009 1:49 pm
Posts: 2
And if you need to combine multiple menus, as long as they can all fit into memory at the same time, you can still do it..
Code:
>PA.=&1100                             
>L.                                     
   10 PRINT "MENU 1"                   
   20 INPUT"MENU NUMBER" A%             
   30 IF A%=2 THEN PAGE=&1300           
   40 IF A%=3 THEN PAGE=&1500           
   50 RUN                               
>PA.=&1300                             
>L.                                     
   10 PRINT"MENU 2"                     
   20 INPUT"MENU NUMBER" A%             
   30 IF A%=1 THEN PAGE=&1100           
   40 IF A%=3 THEN PAGE=&1500           
   50 RUN                               
>PA.=&1500                             
>L.                                     
   10 PRINT"MENU 3"                     
   20 INPUT "MENU NUMBER?"A%           
   30 IF A%=1 THEN PAGE=&1100           
   40 IF A%=2 THEN PAGE=&1300           
   50 RUN                               
>P.~TOP                                 
      1557                             
>*SAVE MENUS 1100 1557

Probably the wrong thread for this..


Top
 
PostPosted: Sun Aug 01, 2010 10:21 am 
Offline
Site Admin
User avatar
 Profile

Joined: Wed Dec 19, 2007 10:46 pm
Posts: 779
Thanks, Rob.

As it happens the !BOOT issue is only a problem for the test image I'm working on. The final disc image should work in a slightly different way. Interesting note about the multiple menus - I have seen that before, and looks handy. I've already got that bit written tho. I'll bear it mind, in case it comes up again in future.

Sam.


Top
 
PostPosted: Fri Aug 06, 2010 6:29 pm 
Offline
Site Admin
User avatar
 Profile

Joined: Wed Dec 19, 2007 10:46 pm
Posts: 779
Just for completeness and to finish off this thread, I thought I'd post that I realised the assembler logic I appended to Rich's patch was overusing labels because it was too procedure-y. :)

I've saved some bytes by rewriting the logic so rather than jumping out to a separate routine, it is more linear and the branches simply skip ahead if the inverse condition is true. So the logic line looks like:

Code:
IF the value at pointerstable[X+1] <= &D69 THEN JMP checka

and the resultant code looks like:

Code:
 1610LDA pointerstable+2,X:CMP #&0D6A MOD 256:LDA pointerstable+3,X:SBC #&0D6A DIV 256:BCC checka
 1620LDA #&BB:STA &0D69
 1630.checka:LDA pointerstable+2,X:CMP #&0D6B MOD 256:LDA pointerstable+3,X:SBC #&0D6B DIV 256:BCC checkb
 ... etc.

Which saves me a bunch of extraneous labels and removes a load of JMP instructions too.

Sam.


Top
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 39 posts ]  Go to page Previous  1, 2

All times are UTC [ DST ]


Who is online

Users browsing this forum: No registered users and 0 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
cron