Jump to content
IGNORED

Need line/dot drawing facilities for ti99 gcc.


tschak909

Recommended Posts

Now that I have working implementations of PLATOTerm for Commodore 64, Apple II, and the Atari, I am doing my planning for other platforms, and TI 99/4A is on that list.

 

I've found tursi's ti99 lib for gcc, which would be very suitable as a low level library, and there are lots of helpers for talking to the VDP, etc... but I am wondering if there are e.g. any line drawing and dot drawing primitives that anyone might have? or am I going to need to roll a pixel plot and bresenham line routine?

 

-Thom

  • Like 1
Link to comment
Share on other sites

Here's an assembly version I wrote a few years ago. It is using R10 as a stack pointer but that can easily be changed. I can't help with the c wrapping.

*********************************************************************
*
* Draw a line from (x1,y1) to (x2,y2)
*
* Adapted from C version at:
* http://rosettacode.org/wiki/Bitmap/Bresenham's_line_algorithm#C
*
* void line(int x1, int y1, int x2, int y2) {
*  int dx = abs(x2-x1), sx = x1<x2 ? 1 : -1;
*  int dy = abs(y2-y1), sy = y1<y2 ? 1 : -1; 
*  int err = (dx>dy ? dx : -dy)/2, e2; 
*  for(; {
*    setPixel(x1,y1);
*    if (x1==x2 && y1==y2) break;
*    e2 = err;
*    if (e2 >-dx) { err -= dy; x1 += sx; }
*    if (e2 < dy) { err += dx; y1 += sy; }
*  }
* }
*
* This version maintains a screen buffer address
* and bit mask instead of coordinates.
*
* R0   x1 value
* R1   y1 value
* R2   x2 value
* R3   y2 value
*
* Modifies all registeres except R10 and R11
*
LFTBIT EQU  >8000                      * Leftmost bit of MSB
RGTBIT EQU  >0100                      * Rightmost bit of MSB
SEVEN  EQU  >0007                      * Three rightmost bits of LSB
*
LINE   MOV  R11,*R10+                  * Push return address onto the stack
*      Setup variables    
       CLR  R6                         * R6 is sx = 0
       MOV  R2,R4                      * R4 is dx = x2
       S    R0,R4                      * dx = x2 - x1 
       JGT  DXPOS3
       DEC  R6                         * sx = -1
       JMP  LINE1
DXPOS3 INC  R6                         * sx = 1
LINE1  ABS  R4                         * dx = abs(dx)b
       CLR  R7                         * R7 is sy = 0
       MOV  R3,R5                      * R5 is dy = y2
       S    R1,R5                      * dy = y2 - y1 
       JGT  DYPOS3
       DEC  R7                         * sy = -1
       JMP  LINE2
DYPOS3 INC  R7                         * sy = 1
LINE2  ABS  R5                         * dy = abs(dy)
       C    R4,R5                      * Compare dx to dy
       JGT  DXGTR3
       MOV  R5,R8                      * R8 is err = dy
       NEG  R8                         * err = -dy
       JMP  LINE3
DXGTR3 MOV  R4,R8                      * R8 is err = dx
LINE3  SRA  R8,1                       * err = err / 2
       MOV  R4,R12                
       NEG  R12                        * R12 = -dx
*      Calculate screen address of first pixel (x1,y1)
       BL   @SCADDR                    * R14 is byte offset 1, R15 is bit mask 1
       MOV  R2,R0                      * Copy x2 to R0
       MOV  R3,R1                      * Copy y2 to R1
       MOV  R14,R2                     * Copy byte offset 1 to R2
       MOV  R15,R3                     * Copy bit mask 1 to R3
*      Calculate screen address of last pixel (x2,y2)
       BL   @SCADDR                    * R14 is byte offset 2, R15 is bit mask 2
       MOV  R2,R0                      * Copy byte offset 1 to R0
       MOV  R3,R1                      * Copy bit mask 1 to R1
       MOV  R14,R2                     * Copy byte offset 2 to R2
       MOV  R15,R3                     * Copy bit mask 2 to R3
*      Add buffer offset to start and end addresses
       AI   R2,SCRBUF
       AI   R0,SCRBUF
*      Reset working bit field in R13 MSB
       ANDI R13,>00FF                  * Clear MSB
*      Main loop
LINEL  SOCB R1,R13                     * OR bit mask onto working bit field
       C    R0,R2                      * Compare byte offset 1 to 2
       JNE  COMPDX                     * Continue if different
       C    R1,R3                      * Compare bit mask 1 to 2
       JNE  COMPDX                     * Continue if different
       JMP  LINEE                      * Break
COMPDX MOV  R8,R9                      * R9 is e2 = err
       C    R9,R12                     * Compare e2 to -dx
       JLT  COMPDY                     * Jump if e2 < -dx
       S    R5,R8                      * err -= dy
       MOV  R6,R6                      * Compare sx to zero
       JLT  PRVCOL                     * Next or previous column?    
NXTCOL COC  @RGTBIT,R1                 * Check if byte should change
       JEQ  NXTBYT
       SRL  R1,1                       * Next screen bit
       JMP  COMPDY                     * Don't write to VDP RAM yet
NXTBYT SOCB R13,*R0                    * Write byte
       CLR  R13                        * Clear bit field       
       AI   R0,8                       * Next screen byte
       MOV  @LFTBIT,R1                 * Set bit mask to leftmost bit
       JMP  COMPDY
PRVCOL COC  @LFTBIT,R1                 * Check if byte should change
       JEQ  PRVBYT
       SLA  R1,1                       * Previous screen bit
       JMP  COMPDY                     * Don't write to VDP RAM yet
PRVBYT SOCB R13,*R0                    * Write byte
       CLR  R13                        * Clear bit field       
       AI   R0,-8                      * Previous screen byte
       MOV  @RGTBIT,R1                 * Set bit mask to rightmost bit
COMPDY C    R9,R5                      * Compare e2 to dy
       JGT  LINEL                      * Loop if e2 > dy
       A    R4,R8                      * err += dx
       SOCB R13,*R0                    * Write byte
       CLR  R13                        * Clear bit field       
       MOV  R7,R7                      * Compare sy to zero
       JLT  PRVROW                     * Next or previous pixel row?    
NXTROW COC  @SEVEN,R0                  * Check if character row should change
       JEQ  NXTCHR
       INC  R0                         * Next pixel row within same character row 
       JMP  LINEL                      * Loop
NXTCHR AI   R0,256-7                   * First pixel row in next character row
       JMP  LINEL                      * Loop
PRVROW CZC  @SEVEN,R0                  * Check if character row should change
       JEQ  PRVCHR
       DEC  R0                         * Previous pixel row within same character row
       JMP  LINEL                      * Loop
PRVCHR AI   R0,7-256                   * Last pixel row in previous character row
       JMP  LINEL                      * Loop
LINEE  SOCB R13,*R0                    * Write byte
       CLR  R13                        * Clear bit field
*      The end
       DECT R10                        * Pop return address off the stack
       MOV  *R10,R11
       B    *R11                       * Return
*// LINE

*********************************************************************
*
* Calculate screen address and bit mask from coordinates
*
* R0   x value
* R1   y value
*
* R14  Set to byte offset
* R15  Set to bit mask
*
SCADDR MOV  R0,*R10+                   * Push R0
*      Calculate screen address from coordinates
*      Based on E/A manual page 336       
       MOV  R1,R14                     * R14 is the byte offset = y
       SLA  R14,5                      * R14 *= 32
       SOC  R1,R14                     * R14 = R14 OR y
       ANDI R14,>FF07                  * R14 = ?
       MOV  R0,R15                     * R15 is bit offset = x
       ANDI R15,7                      * R15 = x mod 8
       A    R0,R14                     * R14 += x 
       S    R15,R14                    * R14 -= bit offset
*      Calculate bit mask        
       MOV  R15,R0                     * Copy bit offset to R0
       LI   R15,>8000                  * Set leftmost pixel
       MOV  R0,R0                      * Compare R0 to zero     
       JEQ  SKIPSR                     * Skip shifting if 0 - this would shift 16 bits!
       SRL  R15,0                      * Shift R15 R0 pixels right
*                                      * R15 is now the bit mask
SKIPSR DECT R10                        * Pop R0
       MOV  *R10,R0
       B    *R11
*// SCADDR
Edited by Asmusr
  • Like 1
Link to comment
Share on other sites

well snek's source isn't released.. soo how about the ti library for gcc-9900

 

https://github.com/tursilion/libti99

 

which sets bitmap mode, you'll have to read the VDP datasheet to do the rest probably

 

also here's the code to the mouse test which uses bitmap mode and uses libti99

 

https://github.com/jedimatt42/tipi/tree/master/examples/mouse

Link to comment
Share on other sites

Drawing lines seems like an application-specific need. A text program might want to reclaim the space that would be taken up by a line-drawing routine. There's not line drawing in hardware, is there? If so, then I suppose it should be accessible from the standard library, but otherwise it's something the application developer should implement. There are lots of documented line-drawing algorithms.

Link to comment
Share on other sites

Ok, this was a fun diversion... pull request has been sent for libti99... in the meantime, my branch is available.

 

I'm not good enough at assembly to tell gcc to inline that and only use all but 2 of the registers. :) I probably could grab a workspace from the stack, and call into an assembly routine... but for now, I just went to wikipedia and implemented the psuedo code as C.

 

https://github.com/tursilion/libti99/pull/5/files

 

There is tile-boundary based puts (put string) so you can still 'draw' text in bitmap mode. Set and clear pixels, and drawline... with some support functions. ( clearing screen, setting 'pen' color' ) -- aiming at high level and generic.

 

Last color attribute for the 1x8 pixel block wins.

 

-M@

  • Like 5
Link to comment
Share on other sites

Now that I have working implementations of PLATOTerm for Commodore 64, Apple II, and the Atari, I am doing my planning for other platforms, and TI 99/4A is on that list.

 

I've found tursi's ti99 lib for gcc, which would be very suitable as a low level library, and there are lots of helpers for talking to the VDP, etc... but I am wondering if there are e.g. any line drawing and dot drawing primitives that anyone might have? or am I going to need to roll a pixel plot and bresenham line routine?

 

-Thom

 

Maybe you already have this... ? from "Rosetta Code.

But it needs the setPixel() function and bitmap config for the VDP.

void line(int x0, int y0, int x1, int y1) {
 
  int dx = abs(x1-x0), sx = x0<x1 ? 1 : -1;
  int dy = abs(y1-y0), sy = y0<y1 ? 1 : -1; 
  int err = (dx>dy ? dx : -dy)/2, e2;
 
  for(;{
    setPixel(x0,y0);
    if (x0==x1 && y0==y1) break;
    e2 = err;
    if (e2 >-dx) { err -= dy; x0 += sx; }
    if (e2 < dy) { err += dx; y0 += sy; }
  }
}
Link to comment
Share on other sites

Maybe you already have this... ? from "Rosetta Code.

But it needs the setPixel() function and bitmap config for the VDP.

void line(int x0, int y0, int x1, int y1) {
 
  int dx = abs(x1-x0), sx = x0<x1 ? 1 : -1;
  int dy = abs(y1-y0), sy = y0<y1 ? 1 : -1; 
  int err = (dx>dy ? dx : -dy)/2, e2;
 
  for(;{
    setPixel(x0,y0);
    if (x0==x1 && y0==y1) break;
    e2 = err;
    if (e2 >-dx) { err -= dy; x0 += sx; }
    if (e2 < dy) { err += dx; y0 += sy; }
  }
}

 

I couldn't get that code to work under gcc, so I went with something else on wikipedia. I think the gcc optimizer was playing games with me... But now we have a set of routines in libti99:

 

// bm_setforeground - specify foreground color to use when drawing
void bm_setforeground(int c);

// bm_setbackground - specify background color to use when drawing
void bm_setbackground(int c);

// bm_clearscreen - clear the screen and sets all regions to the
//                  current colors
void bm_clearscreen();

// bm_setpixel - turn a pixel on
// Inputs: x - 0-255 - horizontal location
//         y - 0-192 - vertial location
void bm_setpixel(unsigned int x, unsigned int y);

// bm_clearpixel - turn a pixel off
// Inputs: x - 0-255 - horizontal location
//         y - 0-192 - vertial location
void bm_clearpixel(unsigned int x, unsigned int y);

// bm_drawline - plot a line between two points
void bm_drawline(int x0, int y0, int x1, int y1);

// bm_consolefont - loads console font to vdp, then copies it up into ram for
// later use in bitmap mode. Use this before switching to bitmap mode if
// you want a TI font.
void bm_consolefont();

// bm_putc - draw a character at a tile location.
// Inputs : c - character column  0:31
//          r - character row  0:23
void bm_putc(int c, int r, unsigned char alphanum);

// bm_puts - draw a 0 terminated string at a tile location.
//    this provides no scrolling, or bounds limiting.
// Inputs : c - character column  0:31
//          r - character row  0:23
void bm_puts(int c, int r, unsigned char* str);

// bm_placetile - draw a 8x8 pattern at the given tile.
// Inputs : c - character column  0:31
//          r - character row  0:23
void bm_placetile(int c, int r, const unsigned char* pattern);

-M@

  • Like 2
Link to comment
Share on other sites

Now that I have working implementations of PLATOTerm for Commodore 64, Apple II, and the Atari, I am doing my planning for other platforms, and TI 99/4A is on that list.

 

I've found tursi's ti99 lib for gcc, which would be very suitable as a low level library, and there are lots of helpers for talking to the VDP, etc... but I am wondering if there are e.g. any line drawing and dot drawing primitives that anyone might have? or am I going to need to roll a pixel plot and bresenham line routine?

 

-Thom

You will find this has recently been done for you and merged into libti99

 

Enjoy.

 

-M@

  • Like 1
Link to comment
Share on other sites

Yup, have managed to build libti99 and the test program. And it runs in Classic99 in the E/A.. This is good. Yay.

 

It looks like there are DSR routines. Are these sufficient to be able to do RS232 I/O? Apologies, this will literally be the first piece of software I've done for the TI-99/4A.

 

-Thom

Edited by tschak909
  • Like 1
Link to comment
Share on other sites

You should probaby fish with another topic (to get the RS232 interested people reading), cause I don't believe in practice anyone ever uses RS232 through the DSR, except maybe to open/configure it...

 

The DSR will read and write records. This will be very inefficient for small protocols... Then your next hurdle, is that everyone who as accessed RS232 for terminal programs has done it in assembly... You'll invariably have to get dirty with inline assembly or some assembly modules in your program anyway... I believe the RS232 byte level access is going to involve a bunch of CRU bit manipulation.. but I've never done it... and I don't know where the reference material for that particular bit is.

 

InsaneMultitasker is an RS232 wizard, as is Stuart

 

Stuart has example assembly of talking to a serial mouse: http://www.stuartconner.me.uk/ti/ti.htm#connecting_serial_mouse

 

-M@

Link to comment
Share on other sites

... Then your next hurdle, is that everyone who as accessed RS232 for terminal programs has done it in assembly... You'll invariably have to get dirty with inline assembly or some assembly modules in your program anyway... I believe the RS232 byte level access is going to involve a bunch of CRU bit manipulation.. but I've never done it... and I don't know where the reference material for that particular bit is. ...

 

-M@

 

FYI, here, on Thierry’s site, is the CRU map of the TMS9902 chips on the RS232 card. [Edit: Per Matt’s suggestion, this post is repeated in post #2 of Accessing-RS232-via-C-in-gcclibti99]

 

...lee

  • Like 1
Link to comment
Share on other sites

If you telnet into 9640news.ddns.net port 9640, look for the MyTerm source code. I think I also uploaded a version on Heatwave last month. In the archive, look for the SUB1 file that has assembly code for accessing the RS232. The snippits of code in that file should work whether you are using a 4A or Geneve.

 

Now, I am not sure, but I do not believe some of the flow control is 100% so that you only pull bytes from the RS232 when you need them. Still a work in progress. On the Geneve though, I can run at 38400. Not sure what the fastest rate you can achieve is on a 4A before dropping characters. If you have flow control correct and with the correct cabling, I think you should be able to have only one routine instead of embedded checks for characters waiting inside other routines like your VDP reads/writes, etc.

 

I can tell you a couple of things I have learned to keep in mind. I poll the RS232 quite frequently and store characters in a buffer. I have only seen this on non TI BBS's under a specific occasion, but with a Telnet connection at 38400 baud, I can get hit with an 8K+ chunk of inbound data pretty quick that is buffered. As it is a circular buffer pulling characters off it as fast as I can, it can still get overrun so things get dropped and never get displayed on the screen. Keep in mind you should anticipate needing a buffer that could be as large as the largest chunk of data you could receive between keypresses if you do not get flow control or handshaking right.

 

Where this happens on my BBS, is if you do a scan for new messages or new files. If there is nothing "new", there can be upwards of 200 areas scanned with each area requiring a screen clear. So, there is a whole lot of VDP writing with it that just takes time.

 

As far as your PlatoTerm software, are you anticipating using it with just RS232 software, or with TIPI? If you are Telnetting into the website, a TIPI interface should be relatively easy as I think Matt has that code available already for the 4A on github. Now, if you are writing for RS232 control and a WIFI modem, that will take some more effort. From what I have learned from Matt, if you have TIPI, your buffer can be relatively small as the TIPI is buffering everything on the PI and you just pull the characters off the port as you need them.

 

Beery

Link to comment
Share on other sites

I will try to support both, especially as there is no TIPI emulation _ANYWHERE_. I do not have TI hardware, and do not have access to any close by, so I am having to do ALL of my work in emulation. ANY help that anyone can give to push this thing along, would be most appreciated. (please?)

 

-Thom

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...