Programming stuff

Started by Pinacolada, November 05, 2008, 07:08 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Pinacolada

Hey guys,

Maybe some smart folks can help me out. I'm at a loss how to do two things, the first in ML, the second in BASIC 2.0.

1) I'd like to POP GOSUBs off the stack. I know where the stack resides, but how would you do it? I've searched the Internet and c.s.c., and come up empty. Short of using flags that dictate a GOTO vs. RETURN (which is a mess in my code) ...

2) I'm not sure how to phrase this gracefully. How would one address one particular bit in BASIC if I had a region of 30 bytes in a string [chr$(255) equal to all bits set]?

Say I had this group of 4 bytes, showing individual bits:

00000000 00000100 00000000 00000000

and I wanted to toggle bit 14 back to a zero. What is the algorithm used? I suck and AND and OR and Boolean logic.

Something like POKE <varptr>,(byte and 8) or 4...? Seems like I've seen something like this used before if you wanted to flip a pixel on or off in a hi-res screen by hand, but I can't find the algorithm. Of course, the bitmap is not linear, but rather top-to-bottom as if each 8x8 "cell" were a "text mode" reprogrammable character...

It just all makes my head ache. Trying to make progress on my adventure game. :)

By the way, Gene Buckle put up the game "The Land of Spur", running on an Apple //e, available on telnet at:

aor.retroarchive.org

This game is what Totally Awesome Dungeon Adventure is based off of. Contrary to what I may have made it sound like, TADA is not original, I'm just porting TLOS over and adding a few features along the way.

Um... anyway.

Thanks for any help/insight anyone might be able to provide.

~ Pina ~
C128 Programmer's Reference Guide FAIL:

1. Press 40/80 key DOWN.
2. Turn computer OFF, then ON.
3. Remove cartridge if present.

Pinacolada

How easy would it be to adapt a POP routine from the PET?

QuotePET/CBM POP

Michael W.Schaffer

You can avoid stacking up too many subroutines by using POP to cancel a GOSUB (command that sends control to a subroutine at a given line number and then RETURNs to the statement after GOSUB). A programming tool for all PET/CBM computers.

Atari BASIC and the Microsoft BASIC used on the Apple II provide a rather useful command called POP. The POP command removes the last GOSUB from the stack, so that a RETURN will return the program to the second-to-last GOSUB. For example, in this program:

10 GOSUB100
20 PRINT "CONTROL RETURNS HERE."
30 STOP
100 GOSUB200
110 PRINT "NOT HERE."
120 STOP
200 POP
210 PRINT "GOING"
220 RETURN

the RETURN on line 220 returns the program to line 20 (not 110). This utility can be very useful, but it is not available in Commodore BASIC. Well, it wasn't.

Here is a machine language utility that executes a POP on all PET/CBM models. The code is position independent – in other words, it can be moved to any convenient spot in memory without any changes. I prefer to locate the code at the top of memory. A POKE 53,127:POKE 52,0:CLR (for 32K systems) will prevent BASIC from using this space.

Program 1 provides the machine language routine in the form of a BASIC loader. The program will load and protect the POP routine, and then indicate the proper SYS location to call the routine. Programs 2 and 3 provide changes for older ROMs.

A GOSUB in BASIC pushes five bytes onto the system stack. These bytes tell BASIC where to start running when the RETURN statement is executed. These five bytes are the low and high bytes of the CHRGET pointer (locations 119 and 120 for newer ROMs, 221 and 222 for Original ROMs) and the current line number (locations 54 and 55 for newer ROMs, 136 and 137 for Original ROMs), and the token for GOSUB (141). To perform a POP, all we do is remove these five bytes from the stack. The routine uses the same subroutine that BASIC uses (JSR $B322 for BASIC 4.0, JSR $C2AA for Upgrade BASIC, JSR $C2AC for Original BASIC) to search the stack for the GOSUB token. The subroutine loads the accumulator with the token found at the top of the stack. We compare it to 141 to see if we have located a GOSUB. If a GOSUB is not found, then an error is returned. The error message sent is "?without gosub error in xxxx". Notice that the standard BASIC error routine is used, so program and variable integrity are assured. The five PLAs simulate the action of a RETURN without really doing anything.

This utility is especially useful in highly "modular" programs. An error handling subroutine can easily remove "pending" GOSUBs from the stack to prevent them from building up (and resulting in an "?out of memory error").

To use this POP in the preceding program, change the POP in line 200 to a SYS 32512, or whatever SYS location the loader indicates should be used. The program does not change in any other way.

Program 1: BASIC 4.0 Version

10 POKE53, PEEK (53) - 1 : POKE 52, 0: CLR
20 SADR = PEEK (52) + PEEK (53) * 256
30 FOR ADDR = SADR TO SADR + 22
40 READ DTTA : POKE ADDR, DTTA : NEXT ADDR
50 PRINT "USE SYS "; SADR
60 END
70 DATA 169, 255, 133, 71, 32, 34, 179, 201
80 DATA 141, 240, 5, 162, 29, 76, 207, 179
90 DATA 154, 104, 104, 104, 104, 104, 96

Program 2: Make These Changes For Upgrade BASIC

70 DATA 169, 255, 133, 71, 32, 170, 194, 201
80 DATA 141, 240, 5, 162, 29, 76, 87, 195

Program 3: Make These Changes For Original BASIC

70 DATA 169, 255, 133, 71, 32, 172, 194, 201
80 DATA 141, 240, 5, 162, 29, 76, 89, 195
C128 Programmer's Reference Guide FAIL:

1. Press 40/80 key DOWN.
2. Turn computer OFF, then ON.
3. Remove cartridge if present.

xlar54

#2
The gosub issue is a matter of moving the stack pointer, but Id be cautious there for obvious reasons. If it does work, I think reliability would be a concern.  Perhaps a better option would be calculated goto's. (theres code to do that - see April 1988 Gazette : http://www.commodore128.org/gaztype.html)

The other is about knowing what to AND and OR.  I may be speaking the obvious to you, but here's a quick rundown:

      101001 
AND 000001
-----------
      000001

So AND-ing something is used to confirm if a single bit is set.  The test above, I AND it with the bit I want to look for.  If the answer is 1 (or another value depending on the bits you are testing), then it is true.  This translates to alot of  IF PEEK(XXXX) AND 128 (or whatever) THEN...

IF PEEK(XXX) AND 1 = 1 (Test if bit 0 is on - right-most bit)
IF PEEK(XXX) AND 2 = 2 (Test if bit 1 is on)
IF PEEK(XXX) AND 4 = 4 (Test if bit 2 is on)
IF PEEK(XXX) AND 8 = 8 (Test if bit 3 is on)
IF PEEK(XXX) AND 16 = 16 (Test if bit 4 is on)
IF PEEK(XXX) AND 32 = 32 (Test if bit 5 is on)
IF PEEK(XXX) AND 64 = 64 (Test if bit 6 is on)
IF PEEK(XXX) AND 128 = 128 (Test if bit 7 is on - left-most bit)

You can combine tests, by adding their position...

IF PEEK(XXX) AND 3 = 3 (Test if bit 0 and bit 1 is on)

As for OR...

       111110
OR   111111
------------
       111111   ORing a value turns a bit on (here we turned on all bits)

Which is why you see alot of POKE XXXX, PEEK(XXXX) OR 255 (or whatever).  Just an easy way to turn on a single bit, or multiple bits



Pinacolada

#3
Xlar,

Thanks for the quick reply! Yeah, I know that messing with the stack pointer isn't the best thing to do... unfortunately the game I'm trying to port relies on POP (it's a scripted language)... *counts* 91 times. :/

I do know about the TSX and TXS opcodes...

It never was terribly obvious to me when people start throwing around AND and OR logic, so thanks for the table.

Hmm, download to the disk image is broken.

Not that I plan to do any programming with TADA soon, but probably going to do some plotting/code testing.

Once again, thanks!
C128 Programmer's Reference Guide FAIL:

1. Press 40/80 key DOWN.
2. Turn computer OFF, then ON.
3. Remove cartridge if present.

xlar54

Hey man,

I found this from the Ahoy May 87 issue:

1 REM C64 version
2 FOR J = 679 TO 679+22:READA:POKEJ,A:NEXTJ:END
3 DATA 104,104,169,255,133,74,32,138,163,154,201,141
4 DATA 240,3,76,224,168,104,104,104,104,104,96

1 REM C128 version
2 FOR J = 4864 TO 4864+23:READA:POKEJ,A:NEXTJ:END
3 DATA 104,104,104,104,169,141,32,170,79,240,5,162
4 DATA 12,76,60,77,32,80,80,160,5,76,89,80

To demonstrate how to get out of requiring a RETURN statement, after you run one of the above, try this:

10 GOSUB 20
20 A=A+1:PRINT A:SYS 679:GOTO 10

(substitute 4864 if using a 128).  What youll find instead of an out of memory error, is that the need for a RETURN has been removed from the stack.

Pinacolada

Well that works just great! Thanks so much, xlar!

Now to disassemble it and figure out how the magic works. ;P
C128 Programmer's Reference Guide FAIL:

1. Press 40/80 key DOWN.
2. Turn computer OFF, then ON.
3. Remove cartridge if present.

Pinacolada

Bump. :)

Well, done some more programming on TADA lately, mainly reorganizing disk images and such. Trying to get rid of all the duplicated old code and such, too. Fixing a few bugs here and there, also. Yay me. :)
C128 Programmer's Reference Guide FAIL:

1. Press 40/80 key DOWN.
2. Turn computer OFF, then ON.
3. Remove cartridge if present.

Pinacolada

Here is some code I've been trying to figure out why it works (or doesn't work) the way it does.

               ; "wedge.s"
               ; written 12/5/2008
               ; pinacolada's attempt to write a basic
               ; wedge, using & character like image
               ; bbs does.

               chrget   = $73
               chrgot   = chrget+6

               ierror   = $0300
               imain    = $0302
               igone    = $0308

                        *= $c000

c000 ad 08 03  setup    lda igone
c003 18                 clc
c004 69 03              adc #3
c006 8d 2d c0           sta oldigone
c009 ad 09 03           lda igone+1
c00c 69 00              adc #0
c00e 8d 2e c0           sta oldigone+1
c011 a9 1c              lda #<newwedge
c013 8d 08 03           sta igone
c016 a9 c0              lda #>newwedge
c018 8d 09 03           sta igone+1
c01b 60                 rts

c01c 20 73 00  newwedge jsr chrget
c01f c9 26              cmp #"&" ; wedge token
c021 f0 06              beq newbasic
c023 20 79 00           jsr chrgot
c026 6c 2d c0           jmp (oldigone)

c029 ee 20 d0  newbasic inc $d020
c02c 60                 rts

                        ; variables

c02d 00 00     oldigone .byte $00,$00
c02f 00 00     newigone .byte $00,$00


This is copied from Overlord's ML, and I'm just trying to learn stuff about wedges and all sorts of annoying things which are giving me fits.

When I assemble it, it assembles and SYS 49152 works. But the first use of & will lock up the computer. I have to reset it and do another SYS 49152.

Afterwards, & will indeed increment the border color, when used by itself. But put it in a line like this:

0 &:for x=1 to 500:next:goto

it executes what looks like a warm start and sits there at the READY. prompt. :/

So then I thought, maybe inserting SEI before the LDA IGONE and SEI before the RTS (both in the SETUP area) would help. No dice.

Any thoughts?
C128 Programmer's Reference Guide FAIL:

1. Press 40/80 key DOWN.
2. Turn computer OFF, then ON.
3. Remove cartridge if present.

Hydrophilic

Glad to see you're still working on TADA!  I am still overwhelmed by all the stuff in the last download (that I got like a year ago).

To answer your most recent question (about your wedge code), the problem is you should not RTS.  You should either JMP(IGONE) if your custom code is okay or JMP (IERROR) if there is trouble.  Try this:


newbasic:
CLC ;assume okay
INC $D020 ;or whatever you need to do...
BCS myerr ;oh no!
JMP (IGONE) ;okay, continue BASIC program
myerr:
LDX #1 ;error number (TOO MANY FILES, but you can change number for other message)
JMP (IERROR) ;stop program, print error


I tested this quickly in VICE and it works fine:

10 FORX=1TO8:&:NEXT

and

10 OPEN1,3
20 &
30 CLOSE1
40 &:?40
50 END

There might be some more subtle issues I didn't see...
I'm kupo for kupo nuts!

Pinacolada

Wow, thanks! You've taught me even more, now.

Yeah, I'm still working on the project, not much lately. I'm trying to get the inventory and GET and DROP routines working. It's kind of a pain.

I did put some work into the "Wall Bar and Grill" earlier this year, and you can do a few more things there now. Kinda fun. :)
C128 Programmer's Reference Guide FAIL:

1. Press 40/80 key DOWN.
2. Turn computer OFF, then ON.
3. Remove cartridge if present.

Pinacolada

#10
Here's a bit of logic I came up with a while back to print singular/plural words:

10 n=1
20 print"played"n;
30 printleft$("games",4-(n<>1))


Looks a bit neater IMHO than:


20 print"played"n"game";:ifn<>1thenprint"s";
30 print


Yeah, there is a lot of stuff in that archive, isn't there... Working on consolidating stuff a bit. :)

I need to update the web page... I've got my Image BBS stuff there as well, and that could use an update as well.

http://cbbsoutpost.servebbs.com/dragonseye/projects
C128 Programmer's Reference Guide FAIL:

1. Press 40/80 key DOWN.
2. Turn computer OFF, then ON.
3. Remove cartridge if present.

Hydrophilic

Although I agree the old
IF N<>1 THEN ?"S"
routine seems lame compared to your mathmatic approach, there are 3 reasons why the old approach is good.

1. Fewer bytes of code
2. Fewer constants (only 1 in "N<>1", but 2 in "4-(N<>1)")
3. No temporary string (but LEFT$ will create a temp. string)

Each of the points above means your BASIC program will operate a tiny bit faster.  The last point can make a big difference... each time a temporary string is created, it reduces available RAM until, eventually, garbage collection is called.  On a C128 this not so bad, but on a C64, garbage collection can take a very long time... like a minute or more!  And STOP does not work in this time... many users think the computer has crashed when this happens... (STOP + RESTORE will work, but it may corrupt variable memory)

Good luck on your updates!
I'm kupo for kupo nuts!

carlsson

How about an even more obfuscated variant?  ;D

20 PRINT"PLAYED";N;"GAME";CHR$(-83*(N<>1))

Pinacolada

The above points are good ones, Hydrophilic. Maybe I will just stick with the "old" way of doing things.

Not to say my BASIC code is a paradigm of efficient coding, inasmuch BASIC can be.

That line of code is neat, Anders. I had to paste it into VICE (then lowercase it, a quirk I hadn't taken into consideration; my text editor does have a "convert selection to lowercase" function though). I assume it prints a chr$(0) if <>1? There certainly is no CHR$(-1)...

People continue to amaze me with coding feats. :)
C128 Programmer's Reference Guide FAIL:

1. Press 40/80 key DOWN.
2. Turn computer OFF, then ON.
3. Remove cartridge if present.

carlsson

Yup, CHR$(0). I'm not entirely sure what it will do to the computer display, probably nothing. The fact that an evaluated expression returns 0 or -1 is something I use as often as I can in my Basic programs. Perhaps not always it is most efficient way of solving things, but sometimes I can replace up to 4-5 IF statements with one single statement.

Take this rather typical Basic program:

10 x=0:y=0:s=1024
15 get a$:if a$="" then 15
17 poke s+y*40+x,32
20 if a$="w" and y>0 then y=y-1
25 if a$="z" and y<24 then y=y+1
30 if a$="a" and x>0 then x=x-1
35 if a$="s" and x<39 then x=x+1
40 poke s+y*40+x,81:goto 15

Easy to understand and follow, but a whopping four IF statements to move a ball around the screen. Now the rather obfuscated but shorter program:

10 x=0:y=0:s=1024
15 get a$:if a$="" then 15
17 poke s+y*40+x,32
20 x=x+(a$="a" and x>0)-(a$="s" and x<39)
25 y=y+(a$="w" and y>0)-(a$="z" and y<24)
40 poke s+y*40+x,81:goto 15

If required, those two assignments on lines 20-25 can even be put on the same line if space requires, or at least some other code can follow on the same line. Possibly you could even combine variables X and Y into a single one, but it would require some smart boundary checking. If the screen had been exactly 32 columns instead of 40, one could've used boolean AND to split a position index into columns and rows.

Pinacolada

Hey, I saw that on the Denial forums. I saved it in my programming notes, 'cuz I'd never seen anything like that before. Image BBS uses a lot of Boolean logic in the BASIC portions. Things like:

on-(an$="Y")-2*(an$="N")-3*(an$="Q")goto xxx,yyy,zzz:goto aaa

Pretty neat IMHO. Way to go!
C128 Programmer's Reference Guide FAIL:

1. Press 40/80 key DOWN.
2. Turn computer OFF, then ON.
3. Remove cartridge if present.

Pinacolada

Hey, I did it. I wrote a little BASIC ML loader. By myself! No peeking at Google or comp.sys.cbm. Just "Mapping the C64."

Y'know, the type that has one line with

10 sys 2061

in it.

         *= $0801
         ; assemble to disk with <-5
         .word line_link; line link

         .word 10 ; line #
         .byte $9e ; sys token
         .text "2061"
         .byte 0 ; end of line
line_link .word 0
         inc $d021
         rts
;---------------------------------------


Programmed in Style's mighty Turbo Macro Pro assembler. \o/
C128 Programmer's Reference Guide FAIL:

1. Press 40/80 key DOWN.
2. Turn computer OFF, then ON.
3. Remove cartridge if present.

Moloch

Great! Now finish up TADA in assembly! ;)

Pinacolada

C128 Programmer's Reference Guide FAIL:

1. Press 40/80 key DOWN.
2. Turn computer OFF, then ON.
3. Remove cartridge if present.