Tiny Basic Compiler

You need an actual VIC.

Moderator: Moderators

CurtisP
Vic 20 Dabbler
Posts: 99
Joined: Tue Mar 08, 2005 8:24 pm

Post by CurtisP »

darkatx wrote:This looks just perfect for my needs!
Thanks for the effort put into this! :D
I just uploaded version 0.21 and updated the link in the OP accordingly. So download it and give it a try.

BTW, what is your favorite assembler?
User avatar
darkatx
Vic 20 Afficionado
Posts: 470
Joined: Wed Feb 04, 2009 2:17 pm
Location: Canada

Post by darkatx »

Right now, I'm using CC65 for what I'm trying to tackle in ML here.

I'm pretty excited about trying it out after I download it tonight! :D
Learning all the time... :)
User avatar
Mike
Herr VC
Posts: 4816
Joined: Wed Dec 01, 2004 1:57 pm
Location: Munich, Germany
Occupation: electrical engineer

Post by Mike »

Mike wrote:Presumably it is the hires toolkit written by Thomas Magnusson you are using. That one was featured in the OP of the thread 'Hires Graphics' (download) and it includes a line routine and an interface that fits your description, but it is not related to MINIGRAFIK.
CurtisP wrote:Yes, that is the one I am using. Sorry for the confusion.
O.K., that being cleared up, here's one question: How would you implement an ellipse drawing routine in TCB? A version which only uses MINIGRAFIK commands could be written as follows (all variables and expressions contain integer values):

Code: Select all

10 @ON:@CLR
11 CX=80:CY=96:A=57:B=95:GOSUB15
12 GETA$:IFA$=""THEN12
13 @RETURN:END
14 :
15 X=0:Y=B:S=B*B:T=A*A*(2*Y-1):U=2*B*B:V=2*A*A:E=0
16 X1=CX+X:Y1=CY+Y:P1=X1>=0ANDX1<160:P2=Y1>=0ANDY1<192
17 X2=CX-X:Y2=CY-Y:P3=X2>=0ANDX2<160:P4=Y2>=0ANDY2<192
18 IFP1ANDP2THEN:@1,X1,Y1
19 IFP1ANDP4THEN:@1,X1,Y2
20 IFP3ANDP4THEN:@1,X2,Y2
21 IFP3ANDP2THEN:@1,X2,Y1
22 IFX=AANDY=0THENRETURN
23 F=E+S:D=0
24 G=F-T:IFABS(F)>ABS(G)THENF=G:D=1
25 G=E-T:IFABS(F)>ABS(G)THENF=G:D=2
26 E=F
27 IFD<2THENX=X+1:S=S+U
28 IFD>0THENY=Y-1:T=T-V
29 GOTO16
CX and CY are the centre co-ordinates, and A and B are horizontal and vertical radii of the ellipse. This way, the non-square aspect ratio of the pixels can be taken account for. The example is assumed to plot a centered circle on a PAL VIC-20 (on an NTSC VIC-20 it will appear vertically lengthened, use A=71 instead in line 11).
CurtisP
Vic 20 Dabbler
Posts: 99
Joined: Tue Mar 08, 2005 8:24 pm

Post by CurtisP »

Mike wrote:O.K., that being cleared up, here's one question: How would you implement an ellipse drawing routine in TCB? A version which only uses MINIGRAFIK commands could be written as follows (all variables and expressions contain integer values):
I will need to implement 16-bit (word) variables. My main stumbling block was that the 6502 only has an 8 bit accumulator, so I would need to use memory locations as an accumulator, and that would require making the code machine specific. But I recently realized I can temporarily store the high and low byte in Y and X.

I should have an update later tonight.
CurtisP
Vic 20 Dabbler
Posts: 99
Joined: Tue Mar 08, 2005 8:24 pm

Post by CurtisP »

16 bit variables weren't quite as hard as I thought they would be.

I've got them working in expressions and functions and in the INCR, DECR, SHIFTL, and SHIFTR commands.

I just need to add some extra parameter checking to function calls and upgrade conditionals to 16 bits.

Hopefully I will have something new to post tomorrow.
CurtisP
Vic 20 Dabbler
Posts: 99
Joined: Tue Mar 08, 2005 8:24 pm

Post by CurtisP »

I just finished coding 16 bit comparisons. I still have to test them, but here is the code that I am currently generating:

Code: Select all

;IF FOO! = BAR! THEN GOSUB YES
  LDY wrdFOO+1
  LDA wrdFOO
  CPY wrdBAR+1
  BNE clb00001
  CMP wrdBAR
  BNE clb00001
  JSR lblYES
clb00001
;IF FOO! <> BAR! THEN GOSUB YES
  LDY wrdFOO+1
  LDA wrdFOO
  CPY wrdBAR+1
  BEQ clb00002
  CMP wrdBAR
  BEQ clb00002
  JSR lblYES
clb00002
;IF FOO! > BAR! THEN GOSUB YES
  LDY wrdFOO+1
  LDA wrdFOO
  CPY wrdBAR+1
  BMI clb00003
  BNE clb00004
  CMP wrdBAR
  BMI clb00003
  BEQ clb00003
clb00004
  JSR lblYES
clb00003
;IF FOO! >= BAR! THEN GOSUB YES
  LDY wrdFOO+1
  LDA wrdFOO
  CPY wrdBAR+1
  BMI clb00005
  BNE clb00005
  CMP wrdBAR
  BMI clb00005
  JSR lblYES
clb00005
;IF FOO! < BAR! THEN GOSUB YES
  LDY wrdFOO+1
  LDA wrdFOO
  CPY wrdBAR+1
  BPL clb00006
  BNE clb00007
  CMP wrdBAR
  BPL clb00006
clb00007
  JSR lblYES
clb00006
;IF FOO! <= BAR! THEN GOSUB YES
  LDY wrdFOO+1
  LDA wrdFOO
  CPY wrdBAR+1
  BEQ clb00009
  BCS clb00008
  BNE clb00010
clb00009
  CMP wrdBAR
  BEQ clb00011
  BCS clb00008
clb00011
clb00010
  JSR lblYES
clb00008
User avatar
Mike
Herr VC
Posts: 4816
Joined: Wed Dec 01, 2004 1:57 pm
Location: Munich, Germany
Occupation: electrical engineer

Post by Mike »

Mike wrote:[...](all variables and expressions contain integer values):
CurtisP wrote:I will need to implement 16-bit (word) variables. [...]
Actually, I meant values without fractional digits. I did not make a statement about the value range, though: CX and CY should be 16-bit signed integer (so the centre of the ellipse may be placed outside the screen in all directions), A and B may sensibly be restricted to unsigned byte, i.e. 0 .. 255. Even with that last restriction, the values in E, F, G, S, T, U, and V require 32 bits to be represented.
My main stumbling block was that the 6502 only has an 8 bit accumulator, so I would need to use memory locations as an accumulator, and that would require making the code machine specific.
What is the problem setting aside a data area to handle 2- or 4-byte values? Then you add two 32-bit values like this:

Code: Select all

CLC
LDA A
ADC B
STA C
LDA A+1
ADC B+1
STA C+1
LDA A+2
ADC B+2
STA C+2
LDA A+3
ADC B+3
STA C+3 ; C = A + B: A, B, C either all signed or all unsigned, 32-bit values
I just finished coding 16 bit comparisons. I still have to test them, but here is the code that I am currently generating:
You should try this one:

Code: Select all

 LDA A
 CMP B
 LDA A+1
 SBC B+1
 BCC skip
 JSR A_gteq_B ; A >= B: A, B unsigned 16-bit values
.skip
 [...]
Actually, these two example code snippets above only cover basic knowledge about 6502 machine language. The carry flag is there to support multi-byte operations.
CurtisP
Vic 20 Dabbler
Posts: 99
Joined: Tue Mar 08, 2005 8:24 pm

Post by CurtisP »

What my example code didn't show was the ability to include mathmatical expressions within the comparison.

Code: Select all

;IF A!+B!-C! = D! THEN LET E! = G! & H!
  LDY wrdA+1
  LDA wrdA
  CLC
  ADC wrdB
  PHA
  TYA 
  ADC wrdB+1
  TAY 
  PLA
  SEC
  SBC wrdC
  PHA
  TYA 
  SBC wrdC+1
  TAY 
  PLA
  CPY wrdD+1
  BNE clb00012
  CMP wrdD
  BNE clb00012
  LDY wrdG+1
  LDA wrdG
  AND wrdH
  PHA
  TYA 
  AND wrdH+1
  TAY 
  PLA
  STA wrdE
  STY wrdE+1
clb00012
User avatar
Mike
Herr VC
Posts: 4816
Joined: Wed Dec 01, 2004 1:57 pm
Location: Munich, Germany
Occupation: electrical engineer

Post by Mike »

I see you insist on not storing intermediate results in memory.

That gets rather complicated though if you move beyond what could be hold in A, X, Y at once - 24 bits - even more difficult if you (need to) use the stack.

Yet, your example can easily be shortened to:

Code: Select all

 CLC
 LDA wrdA
 ADC wrdB
 TAX
 LDA wrdA+1
 ADC wrdB+1
 TAY
 SEC
 TXA
 SBC wrdC
 TAX
 TYA
 SBC wrdC+1
 CMP wrdD+1     ; instead of TAY:CPY wrdD+1
 BNE skip
 CPX wrdD
 BNE skip
 LDA wrdG
 AND wrdH
 STA wrdE
 LDA wrdG+1
 AND wrdH+1
 STA wrdE+1
.skip
... omitting any stack usage as well.

IMO, it is rather wasteful to commit the X and Y registers as "accumulators" over any extended period of time. They are more useful as counters or index registers.
CurtisP
Vic 20 Dabbler
Posts: 99
Joined: Tue Mar 08, 2005 8:24 pm

Post by CurtisP »

Hand optimized code is almost always going to beat compiler generated code.

I tested all the sixteen-bit compare code I had writtem and surprisingly, it worked perfectly.
CurtisP
Vic 20 Dabbler
Posts: 99
Joined: Tue Mar 08, 2005 8:24 pm

Post by CurtisP »

Mike wrote:O.K., that being cleared up, here's one question: How would you implement an ellipse drawing routine in TCB? A version which only uses MINIGRAFIK commands could be written as follows (all variables and expressions contain integer values):
Well dang. All variations of the mid-point algorithm require not only multiplication, but signed arithmetic as well. I wasn't planning on implementing the latter at all.
CurtisP
Vic 20 Dabbler
Posts: 99
Joined: Tue Mar 08, 2005 8:24 pm

Post by CurtisP »

OK, an elipse drawing program would look something like this (i say something like this, because this code is untested).

Code: Select all

REM Draw Ellipse using Bresenham Algorithm

IMPORT "LIB"
INCLUDE "MACROS"

IMPORT "GFX"
INCLUDE "MACROGFX"

IMPORT "MTH"
INCLUDE "MACROMTH"

DIM rx, ry, cx, cy, z

LET cx=64
LET cy=64
LET rx=20
LET ry=30

GRAPHICS
CLEAR
GOSUB BELLIPSE

INP z

EXIT

LABEL BELLIPSE
  REM Draw Ellipse
  REM rx = x radius, ry = y radius, cx = center x, cy = center y

  DIM d1!,rxsq!,rysq!,tworxsq!,tworysq!,dx!,dy!,z!
  DIM i,gd,gm,x,y

  LET rxsq!=MULT(rx,rx)
  LET rysq!=MULT(ry,ry)

  REM tworxsq=2*rxsqy
  LET tworxsq!=rxsq!
  SHIFTL tworxsq!

  REM tworysq=2*rysq
  LET tworysq!=rysq!
  SHIFTL tworysq!

  LET x=0
  LET y=ry

  REM d1=rysq-rxsq*ry+(0.25*rxsq)
  LET d1!=MULTW(rxsq!,ry)
  SHIFTR rxsq!
  SHIFTR rxsq!
  LET d1!=rysq!-d1!+rxsq!
  
  LET dx!=MULTW(tworysq,x)
  LET dy!=MULTW(tworxsq,y)

  WHILE Y>0
    LET z=cy+y    
    PLOT cx+x,z
    PLOT cx-x,z
    LET z=cy-y
    PLOT cx-x,z
    PLOT cx+x,z
    LET x=x+1
    LET dx!=dx!+tworysq!
    IF d1! >= $8000 THEN
      LET d1!=d1!+dx!+rysq!
    ELSE
      LET y=y-1
      LET dy!=dy!-tworxsq!
      LET d1!=d1!+dx!-dy!+rysq!
    ENDIF
  WEND
  RETURN
User avatar
Mike
Herr VC
Posts: 4816
Joined: Wed Dec 01, 2004 1:57 pm
Location: Munich, Germany
Occupation: electrical engineer

Post by Mike »

CurtisP wrote:OK, an elipse drawing program would look something like this (i say something like this, because this code is untested).
No need to test it, because the routine won't work anyway, for several reasons.

The code you wrote above was most probably inspired by an implementation of the mid-point algorithm by Gursharan Singh Tatla found on eazynotes, albeit it misses one half of it. As soon as the slope magnitude is greater than one, your version is not able anymore to follow the shape, furthermore the two points intersecting the x-axis are missing:

Image
(green shows the ellipse with rx=100, ry=200; red the overlaid output of your routine)

But you don't even get to this point. As I noted above, some variables require at least 32 bits for storage if you want to draw half-axes up to 255. Integer overflow will make the 16-bit values in 'tworxsq', 'tworysq', 'dx', 'dy', and 'd1' completely meaningless for anything bigger than rx,ry>30.

The unaltered algorithm by Gursharan Singh Tatla is not without problems, either. First, it still requires float variables, second, ellipses with small values of ry and big values of rx are not drawn correctly - they end up too short.
CurtisP
Vic 20 Dabbler
Posts: 99
Joined: Tue Mar 08, 2005 8:24 pm

Post by CurtisP »

Mike wrote:No need to test it, because the routine won't work anyway, for several reasons.
Thanks for the input. I really think that any kind of Bressenham or Mid-Point Algorithm is outside the scope of small or tiny languages.
User avatar
Mike
Herr VC
Posts: 4816
Joined: Wed Dec 01, 2004 1:57 pm
Location: Munich, Germany
Occupation: electrical engineer

Post by Mike »

CurtisP wrote:I really think that any kind of Bressenham or Mid-Point Algorithm is outside the scope of small or tiny languages.
A Bresenham-style line routine for a resolution up to 256x256 pixels implements quite easily with anything that supports 8-bit values. The corresponding code in MINIGRAFIK is roughly 100 bytes in size.

There's already an implementation of the ellipse routine I posted above in 6502 code, it is part of MAXIGRAFIK. This routine is slightly larger, 700 to 900 bytes, that depends on whether the workspace variables are put into zeropage, or not. As you noted, multiplication and signed arithmetic needed to be done, in a way not wasting too much space. The multiplication does 8-bit factor x 24-bit factor -> 32-bit result.

At the time I went to code it, I would have been very thankful for a small language or the like for the 6502 supporting 32-bit values. Maybe even something like SWEET16 for the Apple II, but with 32-bit registers instead. So now, everything is done 'by hand' - 4x LDA,ADC,STA for additions, etc. Judicious use of subroutines for otherwise identical code sections helped (a bit) to keep down the size.
Thanks for the input.
Smoke testing the routine in, say, CBM BASIC + MINIGRAFIK would have revealed immediately, that your implementation was not working. And, unlike logic errors buried deep within some code, the errorneous graphics output is right before your eyes.

I know I was not too subtle about that.

All in all, the usefulness of TCB will be measured against the number of programs which will be written with it. The inclusion of 32-bit arithmetics would help to reach a bigger audience.

Greetings,

Michael
Post Reply