Original Progress Thread

Porting Richard Russell's BBC BASIC (Z80) to the TI-83+ and TI-84+ series calculators.

Moderator: benryves

User avatar
benryves
Maxcoderz Staff
Posts: 3087
Joined: Thu 16 Dec, 2004 10:06 pm
Location: Croydon, England
Contact:

Post by benryves »

The easiest way to edit programs is directly on BASIC's command line, though people may wish to edit programs using an editor that's more similar to the TI-OS editor rather than by line.

As BBC BASIC programs are stored in a tokenised format, the files cannot be directly edited. However, if I implement *SPOOL and *EXEC, these could be used to convert BASIC programs to ASCII text and back again.
User avatar
Dwedit
Maxcoderz Staff
Posts: 579
Joined: Wed 15 Dec, 2004 6:06 am
Location: Chicago!
Contact:

Post by Dwedit »

benryves wrote:This screenshot shows a feature borrowed from the BBC Micro: copy key editing. By pressing a cursor key when entering a line of code, the cursor splits into two - a read cursor and a write cursor. The write cursor remains on the end of the line you were editing (a solid block), but the read cursor can be moved to any location on the screen. Pressing the COPY key (in this case, I've commandeered the XTθn key for this purpose) reads the character that is under the read cursor and copies it to the write cursor, then increments both.
Is this like the related feature on the old Apple ][, where you press ESC, then move the text cursor anywhere on the screen, hit ESC to exit that mode, then you hit the right arrow to type in characters under the cursor?
You know your hexadecimal output routine is broken when it displays the character 'G'.
User avatar
benryves
Maxcoderz Staff
Posts: 3087
Joined: Thu 16 Dec, 2004 10:06 pm
Location: Croydon, England
Contact:

Post by benryves »

Sounds like it. :)

EDIT: I'll try to make my post a bit more meaningful; I've started adding support for external devices via ".DEV" files. For example, here's a program that flashes the keyboard LEDs back and forth using AT.DEV to send and receive bytes using the AT protocol.

Code: Select all

   10 keyb%=OPENOUT"AT.DEV"
   20 DATA 2,4,1,4,-1 : REM LED flash pattern (-1 terminated).
   30 REPEAT
   40   READ l%
   50   REPEAT
   60     PROC_setled(l%)
   70     PROC_pause(30)
   80     READ l%
   90   UNTIL l%=-1
  100   RESTORE
  110 UNTIL FALSE
  120 END
  130 :
  140 DEF PROC_flushin
  150 REPEAT
  160   IF EXT#keyb% d%=BGET#keyb%
  170 UNTIL NOT EXT#keyb%
  180 ENDPROC
  190 :
  200 DEF PROC_setled(l%)
  210 BPUT#keyb%,&ED
  220 PROC_flushin
  230 BPUT#keyb%,l%
  240 PROC_flushin
  250 ENDPROC
  260 :
  270 DEF PROC_pause(t%)
  280 start%=TIME
  290 REPEAT UNTIL TIME >= start%+t%
  300 ENDPROC
As there may or may not be data waiting for us from the device, incoming data is buffered and you can check how much stuff is in the buffer by using EXT# (which usually returns the size of the file). In this way, if EXT# returns a positive value, that means there's stuff in the buffer and you can safely call BGET# to retrieve it.

In the above code, PROC_flushin is used to ignore any input from the keyboard. It checks the length of the buffer and tries to read data from it until it's empty.

PROC_setled(l%) sets the keyboard LED state, which is done by sending the control byte &ED followed by the LED state value. After each value is sent to the keyboard, PROC_flushin is called to ignore any response the keyboard tries to send.

PROC_pause(t%) is just a little procedure to pause for a particular number of centiseconds, using the TIME pseudo-variable.

I'd include an animated GIF, but my AVI->GIF software isn't working. Oh well. :(
User avatar
benryves
Maxcoderz Staff
Posts: 3087
Joined: Thu 16 Dec, 2004 10:06 pm
Location: Croydon, England
Contact:

Post by benryves »

Regarding the speed issue; no doubt somebody is going to write a 5-line TI-BASIC program that runs at three times the speed and textures the cube at the same time, but here's a very simple 3D demo.

Image Image

On the left is the program running on an 83+ SE at 15MHz, on the right on the regular 83+ at 6MHz. If you really wanted to do 3D in BBC BASIC you could probably get away with writing some of the more expensive operations -- such as transforming/projecting vertices in batches -- in assembly, but that would sort of go against the whole point of trying to write a program to test the speed of BASIC. :)

Here's the rather naïve code:

Code: Select all

   10 *REFRESH OFF
   20 DIM p%(15)
   30 fps%=0
   40 lfps%=0
   50 fpst%=TIME+100
   60 REPEAT
   70   rX=TIME/300
   80   rY=TIME/400
   90   SrX=SIN(rX)
  100   CrX=COS(rX)
  110   SrY=SIN(rY)
  120   CrY=COS(rY)
  130   pt%=0
  140   FOR x=-1TO1STEP2
  150     FOR y=-1TO1STEP2
  160       FOR z=-1TO1STEP2
  170         tX=y*CrX-x*SrX
  180         tY=-x*CrX*SrY-y*SrX*SrY-z*CrY
  190         tZ=3-x*CrX*CrY-y*SrX*CrY+z*SrY
  200         p%(pt%)=tX*40/tZ+48
  210         pt%=pt%+1
  220         p%(pt%)=tY*40/tZ+32
  230         pt%=pt%+1
  240       NEXT
  250     NEXT
  260   NEXT
  270   CLG
  280   PRINTTAB(10,0)lfps%" FPS"
  290   MOVE p%(0),p%(1)
  300   DRAW p%(4),p%(5)
  310   DRAW p%(12),p%(13)
  320   DRAW p%(8),p%(9)
  330   DRAW p%(0),p%(1)
  340   DRAW p%(2),p%(3)
  350   DRAW p%(6),p%(7)
  360   DRAW p%(14),p%(15)
  370   DRAW p%(10),p%(11)
  380   DRAW p%(2),p%(3)
  390   MOVE p%(4),p%(5)
  400   DRAW p%(6),p%(7)
  410   MOVE p%(12),p%(13)
  420   DRAW p%(14),p%(15)
  430   MOVE p%(8),p%(9)
  440   DRAW p%(10),p%(11)
  450   *REFRESH
  460   fps%=fps%+1
  470   IF TIME>fpst% THEN lfps%=fps%:fps%=0:fpst%=TIME+100
  480 UNTIL INKEY(0)<>-1
  490 *REFRESH ON
  500 END
User avatar
benryves
Maxcoderz Staff
Posts: 3087
Joined: Thu 16 Dec, 2004 10:06 pm
Location: Croydon, England
Contact:

Post by benryves »

qarnos has supplied some amazing code to the project. First up is a fast 16-bit line clipping routine.

Image

What isn't shown is that this also uses a new line drawing routine that is a bit faster than the TI-OS ILine (2FPS->3FPS in the above demo on an 83+, no change on an SE) and also supports different colours more easily (black, white, inverse). I need to add support for dotted, dashed and broken lines too.

He's also written an awesome set of ellipse drawing and filling routines which are also nice and fast.

Image Image

GCOL m,c is used to set the graphics colour. m sets the mode; 0 is to "plot" the colour directly, the other settings are used to perform logical operations (OR, AND, EOR -- none of which are fully implemented yet). c sets the colour; 0..127 sets the foreground and 128..255 the background colour. As all we have is a black and white LCD to play with, the colour is mapped to a dither pattern, with 0 being fully black and 127 being fully white.

The code for the screenshot on the left is as follows:

Code: Select all

   10 CLG
   20 REPEAT
   30   GCOL 0,RND(127)
   40   MOVE RND(48),RND(32)
   50   MOVE RND(48),RND(32)
   60   PLOT 205,RND(48),RND(32)
   70 UNTIL INKEY(0)<>-1
The code for the screenshot on the right is as follows:

Code: Select all

   10 CLG
   20 FOR i=120 TO 0 STEP -8
   30   GCOL 0,i
   40   MOVE 48,32
   50   MOVE 48+i*0.4,32
   60   PLOT 205,48,2
   70 NEXT i
For an explanation of PLOT as it relates to ellipses, see Draw solid ellipse - PLOT 200 to 207.

All of the above screenshots are running at 15MHz (SE).
User avatar
qarnos
Maxcoderz Staff
Posts: 227
Joined: Thu 01 Dec, 2005 9:04 am
Location: Melbourne, Australia

Post by qarnos »

It's looking good :)

So I assume you are generating the dither patterns dynamically? 128 would seem like too much to store statically.
"I don't know why a refrigerator is now involved, but put that aside for now". - Jim e on unitedti.org

avatar courtesy of driesguldolf.
User avatar
tr1p1ea
Maxcoderz Staff
Posts: 4141
Joined: Thu 16 Dec, 2004 10:06 pm
Location: I cant seem to get out of this cryogenic chamber!
Contact:

Post by tr1p1ea »

Wow those are some great routines! Fast and the dithering is perfect. Good stuff qarnos/ben :).
"My world is Black & White. But if I blink fast enough, I see it in Grayscale."
Image
Image
User avatar
Dwedit
Maxcoderz Staff
Posts: 579
Joined: Wed 15 Dec, 2004 6:06 am
Location: Chicago!
Contact:

Post by Dwedit »

A "PLOT 205" command sounds really obscure. Like the kind of thing you'd need a manual right in front of you to program with. Maybe add extra commands, like "ELIPSE"?
You know your hexadecimal output routine is broken when it displays the character 'G'.
User avatar
benryves
Maxcoderz Staff
Posts: 3087
Joined: Thu 16 Dec, 2004 10:06 pm
Location: Croydon, England
Contact:

Post by benryves »

qarnos wrote:So I assume you are generating the dither patterns dynamically? 128 would seem like too much to store statically.
Image

There are only 16 discrete dither patterns, so I'm just using the static image above (generated by Photoshop's pattern dithering tool).
Dwedit wrote:A "PLOT 205" command sounds really obscure. Like the kind of thing you'd need a manual right in front of you to program with. Maybe add extra commands, like "ELIPSE"?
This one bothers me too, but as far as I'm aware the current BASIC helper libraries also rely on memorising numeric codes for each command (through necessity, not design). However, I cannot modify the BBC BASIC language (and add new keyword). I can add new star commands (*ELLIPSE) as these are intended to be executed by the OS, but no numeric parsing is available for these.

Fortunately, there is a pattern to the numbers used; the two least significant bits define the colour (0=none, 1=foreground, 2=inverse, 3=background), bit 2 specifies whether the passed coordinates are absolute (1) or relative to the last point (0) and the remaining five bits define the type of shape.

There's nothing to stop you from doing this, either:

Code: Select all

DEF PROC_ellipse(cx,cy,rx,ry)
    MOVE cx,cy
    PLOT 0,rx,0
    PLOT 201,0,ry
ENDPROC
On the keyword list ("CATALOG" replacement) I was intending on adding help for the PLOT statement that would let you select the mode you wished (type of shape, coordinate system, colour) and it would generate the code for you.

I've done some work on improving the console (it stores a bitmap of the area under the cursor so moving the cursor around no longer destroys graphics or inverted text - before it was just storing the character under each cell and repainting) and graphics code in general. I've added some code to emulate some of the useful features of the BBC Micro VDU, such as the ability to define the graphics viewport.

Image

"VDU" sends data directly to the output device; an argument that is followed by a comma is sent as a byte and one that is followed by a semicolon is sent as a word. VDU 24,<left>;<top>;<right>;<bottom>; is used in the above example to define a graphics "window" with a 10 pixel border around it. (VDU 26 resets it). The background colour is set to 32 (25%) to make the effect of this statement more obvious.

Yes, that's more arcane number codes to memorise. :P

EDIT: Added a couple of new screenshots to demonstrate bitwise operations when plotting.

Image Image
User avatar
benryves
Maxcoderz Staff
Posts: 3087
Joined: Thu 16 Dec, 2004 10:06 pm
Location: Croydon, England
Contact:

Post by benryves »

After trying to avoid it I finally gave in and added support for text viewports to complement graphics viewports.

Image

The following VDU commands are now supported:
  • VDU 24,<left>;<top>;<right>;<bottom>;
    Define a graphics viewport.
  • VDU 28,<left>,<top>,<right>,<bottom>
    Define a text viewport.
  • VDU 26
    Reset both viewports to their default settings (full screen).
  • VDU 29,<x>;<y>;
    Defines the graphics origin.
The above screenshot is the result of the following:

Code: Select all

VDU 24,0;0;47;63;
VDU 28,12,0,23,9
VDU 29,24;32;
You may be asking why some VDU commands are semicolon delimited whereas others are comma delimited. The semicolon makes BBC BASIC send the previous value as a 16-bit value rather than an 8-bit value (so VDU 24,0;0;47;63; sends 9 bytes to the VDU emulator -- 24,0,0,0,0,47,0,63,0). All graphics commands work in 16-bit coordinates, even though they don't really need to on the TI-83+.

The line at the bottom of the text viewport on the right hand side is the result of some previous graphics tests; as each character is 6 pixels high there's a 4 pixel gap at the bottom of the screen that text (currently) cannot be written to. VDU 5 will let you use the graphics cursor to position text, so pixel-perfect text is only a matter of time (ie, when I get around to adding sprite routines).
User avatar
tr1p1ea
Maxcoderz Staff
Posts: 4141
Joined: Thu 16 Dec, 2004 10:06 pm
Location: I cant seem to get out of this cryogenic chamber!
Contact:

Post by tr1p1ea »

Ahh a very nifty feature that im glad you included. Will prove very handy for certain projects (say an animation with subs) or for performance gains with graphics heavy programs perhaps.
"My world is Black & White. But if I blink fast enough, I see it in Grayscale."
Image
Image
User avatar
benryves
Maxcoderz Staff
Posts: 3087
Joined: Thu 16 Dec, 2004 10:06 pm
Location: Croydon, England
Contact:

Post by benryves »

Well, I'm glad you can think of some uses for this feature (I wasn't too sure of what I'd personally use it for), but having a text viewport complements the graphics viewport nicely. :)

As characters are 6 pixels high, this means that the console only fills the top 60 rows. Maybe I should add a command that lets you specify which line is the top of the display, so the console can be shunted down a few pixel rows if need be.

I've been thinking about the sprite-drawing API, something like this might work well:

Code: Select all

DIM spr% 7 : REM Allocate 8 bytes (0..7) of RAM, pointed to by spr%
spr%?0=&3C : REM Set [spr% + 0] = &3C
spr%?1=&7E : REM Set [spr% + 1] = &7E
spr%?2=&FF : REM Set [spr% + 2] = &FF (and so on)
spr%?3=&FF
spr%?4=&FF
spr%?5=&FF
spr%?6=&7E
spr%?7=&3C
GCOL 3,127 : REM Set plot mode to EOR (3) and foreground colour to black (127)
PLOT 213,10,20,spr% : REM Draw sprite (PLOT code 213) at (10,20)
User avatar
qarnos
Maxcoderz Staff
Posts: 227
Joined: Thu 01 Dec, 2005 9:04 am
Location: Melbourne, Australia

Post by qarnos »

benryves wrote:Well, I'm glad you can think of some uses for this feature (I wasn't too sure of what I'd personally use it for), but having a text viewport complements the graphics viewport nicely. :)

As characters are 6 pixels high, this means that the console only fills the top 60 rows. Maybe I should add a command that lets you specify which line is the top of the display, so the console can be shunted down a few pixel rows if need be.
Do you text routines handle vertical clipping? If so, why not just allow the top line to scroll half-off screen? Sure, it's unnecessarily complicated and adds no real functionality... but it would look cool :D.

Nice job with the text window, though. I'm sure someone will find it useful. It's one less thing for people to think "why can't I do this...".
"I don't know why a refrigerator is now involved, but put that aside for now". - Jim e on unitedti.org

avatar courtesy of driesguldolf.
DarkAuron
Maxcoderz Staff
Posts: 1349
Joined: Sat 18 Dec, 2004 6:53 pm

Post by DarkAuron »

:o
[Gridwars Score] - E: 1860037 M: 716641 H: 261194
User avatar
benryves
Maxcoderz Staff
Posts: 3087
Joined: Thu 16 Dec, 2004 10:06 pm
Location: Croydon, England
Contact:

Post by benryves »

qarnos wrote:Do you text routines handle vertical clipping? If so, why not just allow the top line to scroll half-off screen? Sure, it's unnecessarily complicated and adds no real functionality... but it would look cool :D.
Aye, it does rather complicate issues. Nice idea, though, but I think I'll keep the console within a rigid grid (as far as it is handled automatically, an explicit command to change its offset from the top of the display might be useful). VDU 5 lets you use the graphics cursor to position text anywhere on screen; this rather nicely brings me onto the next thing I've added, sprites.

Image

Code: Select all

   10 DIM ball 7
   20 ball?0=&3C
   30 ball?1=&5E
   40 ball?2=&8F
   50 ball?3=&DF
   60 ball?4=&FF
   70 ball?5=&FF
   80 ball?6=&7E
   90 ball?7=&3C
  100 *REFRESH OFF
  110 REPEAT
  120   CLG
  130   T=TIME/100
  140   FOR P=0 TO 5
  150     A=P/3*PI+T
  160     X=16*SIN(A)+44
  170     Y=16*COS(A)+28
  180     PLOT 213,X,Y,ball
  190   NEXT
  200   *REFRESH
  210 UNTIL INKEY(0)<>-1
  220 *REFRESH ON
(Again, at 15MHz speeds, though it looks much smoother on hardware or the emulator). As you can see, sprites are clipped to the graphics viewport. Depending on the current graphics plot mode (set with GCOL) and the specific sprite PLOT number you use, sprites can be drawn directly in a particular colour, ORed, ANDed, EORed or inverted.

In reality, it would be more space efficient to store the sprite data in external files, maybe like this (assuming a file named SPRITES that contains the sprite data).

Code: Select all

   10 ball%=FN_loadSprite("SPRITES",0)
   20 face%=FN_loadSprite("SPRITES",1)
   30 *REFRESH OFF
   40 REPEAT
   50   CLG
   60   T=TIME/100
   70   FOR P=0 TO 5
   80     A=P/3*PI+T
   90     X=16*SIN(A)+44
  100     Y=16*COS(A)+28
  110     PLOT 213,X,Y,ball%
  120   NEXT
  130   PLOT 213,44,28,face%
  140   *REFRESH
  150 UNTIL INKEY(0)<>-1
  160 *REFRESH ON
  170 END
  180 DEF FN_loadSprite(f$,i%)
  190 fh%=OPENIN(f$)
  200 PTR#fh%=i%*8
  210 DIM spr 7
  220 FOR j%=0 TO 7
  230   spr?j%=BGET#fh%
  240 NEXT j%
  250 CLOSE#fh%
  260 =spr
  270 ENDPROC
Image
As iterating over an array (for, say, tilemapping) is quite slow in BBC BASIC (BBC BASIC seems faster than TI BASIC but it's no miracle-worker) I'll need to think about how this could be sped up. I'm hesitant to add more PLOT commands (as tilemapping is quite specific), so it may be through an OS command (*TILEMAP?), an entry point (CALL <address>,<args>) or left as an exercise to the reader (custom assembly routines mixed into the BASIC program).
Post Reply