| www.retrosoftware.co.uk http://www.retrosoftware.co.uk/forum/ |
|
| COTPORS: Help with an assembler routine http://www.retrosoftware.co.uk/forum/viewtopic.php?f=73&t=489 |
Page 2 of 2 |
| Author: | Samwise [ Wed Jul 28, 2010 1:21 pm ] |
| Post subject: | Re: COTPORS: Help with an assembler routine |
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. |
|
| Author: | Samwise [ Wed Jul 28, 2010 7:03 pm ] |
| Post subject: | Re: COTPORS: Help with an assembler routine |
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. |
|
| Author: | ColinD [ Wed Jul 28, 2010 7:46 pm ] |
| Post subject: | Re: COTPORS: Help with an assembler routine |
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 |
|
| Author: | Samwise [ Wed Jul 28, 2010 9:07 pm ] |
| Post subject: | Re: COTPORS: Help with an assembler routine |
@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 |
|
| Author: | Samwise [ Wed Jul 28, 2010 9:27 pm ] |
| Post subject: | Re: COTPORS: Help with an assembler routine |
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. |
|
| Author: | MartinB [ Thu Jul 29, 2010 12:28 am ] |
| Post subject: | Re: COTPORS: Help with an assembler routine |
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. |
|
| Author: | Samwise [ Thu Jul 29, 2010 10:25 am ] |
| Post subject: | Re: COTPORS: Help with an assembler routine |
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. |
|
| Author: | Samwise [ Thu Jul 29, 2010 9:53 pm ] |
| Post subject: | Re: COTPORS: Help with an assembler routine |
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. 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 |
|
| Author: | Samwise [ Thu Jul 29, 2010 11:03 pm ] |
| Post subject: | Re: COTPORS: Help with an assembler routine |
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. |
|
| Author: | MartinB [ Fri Jul 30, 2010 1:40 pm ] |
| Post subject: | Re: COTPORS: Help with an assembler routine |
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... |
|
| Author: | PaulDv [ Fri Jul 30, 2010 2:01 pm ] |
| Post subject: | Re: COTPORS: Help with an assembler routine |
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. |
|
| Author: | RichTW [ Fri Jul 30, 2010 2:13 pm ] |
| Post subject: | Re: COTPORS: Help with an assembler routine |
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. |
|
| Author: | RichTW [ Fri Jul 30, 2010 2:14 pm ] |
| Post subject: | Re: COTPORS: Help with an assembler routine |
BTW Sam - great work! Glad you managed to get it all working well in the end |
|
| Author: | Samwise [ Fri Jul 30, 2010 2:14 pm ] |
| Post subject: | Re: COTPORS: Help with an assembler routine |
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. |
|
| Author: | Samwise [ Fri Jul 30, 2010 2:35 pm ] |
| Post subject: | Re: COTPORS: Help with an assembler routine |
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'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. |
|
| Author: | irrelevant [ Fri Jul 30, 2010 8:41 pm ] |
| Post subject: | Re: COTPORS: Help with an assembler routine |
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" |
|
| Author: | irrelevant [ Sat Jul 31, 2010 6:35 pm ] |
| Post subject: | Re: COTPORS: Help with an assembler routine |
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.. |
|
| Author: | Samwise [ Sun Aug 01, 2010 10:21 am ] |
| Post subject: | Re: COTPORS: Help with an assembler routine |
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. |
|
| Author: | Samwise [ Fri Aug 06, 2010 6:29 pm ] |
| Post subject: | Re: COTPORS: Help with an assembler routine |
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. |
|
| Page 2 of 2 | All times are UTC [ DST ] |
| Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group http://www.phpbb.com/ |
|