<2kbyte 6502 Tiny Basic?

Topics related to older 6502-based hardware and systems including (but not limited to) the MOS Technology KIM-1, Synertek SYM-1, and Rockwell AIM-65.
Chromatix
Posts: 1462
Joined: 21 May 2018

Re: <2kbyte 6502 Tiny Basic?

Post by Chromatix »

It might, if I need it - but there are more important things to deal with first.
User avatar
drogon
Posts: 1671
Joined: 14 Feb 2018
Location: Scotland
Contact:

Re: <2kbyte 6502 Tiny Basic?

Post by drogon »

One thing I have considered (still am, somewhat) is an optional "library" of code with the intention of it being called by poking input values into a fixed location, calling the routine then peeking the result - rather than extend the interpreter (which is costly in terms of time in TinyBasic) so e.g.

Code: Select all

10 !&500 = A : !&502=B : !&504 = C : CALL &9000 : M = !&500 : REM MulDiv:- M=A*B/C
Same for maybe some scaled trig, etc. Feels a bit cheaty, but stranger things have been done in the past...

-Gordon
--
Gordon Henderson.
See my Ruby 6502 and 65816 SBC projects here: https://projects.drogon.net/ruby/
Chromatix
Posts: 1462
Joined: 21 May 2018

Re: <2kbyte 6502 Tiny Basic?

Post by Chromatix »

Good news: while implementing an absolutely minimalist PRINT statement and working through the resultantly exposed bugs, the code actually got slightly smaller. Most of this was from finding some code I'd prepared for implementing PRINT later, which performed a conditional negate without using the more recent DoNegate subroutine. Cutting out the duplicate code and using the subroutine as intended saved more space than adding the partial PRINT statement used up.

The interpreter is now able to run simple programs involving variables, expressions, comparisons, and printing out single integers. Not everything has been thoroughly tested yet, but I did check most of the basic functionality and some important corner cases.

Next step is to complete the feature set of PRINT. My goal here is string literals and more than one integer per statement, divided by semicolons (no space) or commas (one space), with a final semicolon or comma suppressing the newline. How much change will I have from the present 56-byte margin? (NB: this is not a hard limit, as I can go to 3.5KB of code before running into the configured I/O area, but I'll be looking to cut excess beyond 2KB for the sake of bragging rights.)
User avatar
barrym95838
Posts: 2056
Joined: 30 Jun 2013
Location: Sacramento, CA, USA

Re: <2kbyte 6502 Tiny Basic?

Post by barrym95838 »

I don't think that you explicitly stated it, but I saw something a few pages back hinting that you were using the Kowalski simulator for your development. Its I/O is rather simplified and flexible, but it also has some annoying quirks with linefeeds if you want to copy and paste BASIC source into it. Klaus2m5 figured it out for me, but you may already know all of this.
Got a kilobyte lying fallow in your 65xx's memory map? Sprinkle some VTL02C on it and see how it grows on you!

Mike B. (about me) (learning how to github)
Chromatix
Posts: 1462
Joined: 21 May 2018

Re: <2kbyte 6502 Tiny Basic?

Post by Chromatix »

I did notice it went weird when I pasted a program in, yes. I suspect it's pasting LF characters after each CR, whereas pressing Return just sends CR. If that's what it is, I can work around it without too much difficulty.
Chromatix
Posts: 1462
Joined: 21 May 2018

Re: <2kbyte 6502 Tiny Basic?

Post by Chromatix »

As you can see here, the FizzBuzz program I wrote earlier is now running. It takes about 2.5 million cycles, which isn't too bad considering this really isn't a performance-oriented interpreter.
FizzBuzz.png
User avatar
drogon
Posts: 1671
Joined: 14 Feb 2018
Location: Scotland
Contact:

Re: <2kbyte 6502 Tiny Basic?

Post by drogon »

Excellent!

Here it is in my TinyBasic:
Screenshot_2023-10-24_11-13-48.png
With an interesting note... In the old TinyBasic documents I had, the NOT operation was defined as Ones Compliment... So that's what I implemented... And it made my initial version of this fail... Because at (e.g.) X=3 :-

(Y OR Z) returnes (1 OR 0) which is 1 and NOT 1 is -2.

True/False is defined as Non-zero/Zero, so

NOT (1 OR 0) is NOT 1 which is -2 which is TRUE.

Which is correct, but not the expected result...

I changed my implementation of NOT to make 0 -> 1 and anything non-zero return 0 and it worked.

Or did it - which was right? It's an interesting conjecture...

I also fear we're losing the art of translating programs from different dialects - which many of us did back in the 70's/80's when typing into our plethora of little micros, all different at the time...

-Gordon
--
Gordon Henderson.
See my Ruby 6502 and 65816 SBC projects here: https://projects.drogon.net/ruby/
Chromatix
Posts: 1462
Joined: 21 May 2018

Re: <2kbyte 6502 Tiny Basic?

Post by Chromatix »

I adopted the BBC BASIC convention of making "true" results from comparison operators be -1. This means that bitwise operators can also be used for logical operations, including NOT. I don't think it requires significantly more code than producing a 1 result, as for both "false" and "true" a single byte value is replicated to all four result positions.

C doesn't do this - it has separate operators for bitwise and logical operations. So bitwise complement is ~ and logical complement is !.
User avatar
drogon
Posts: 1671
Joined: 14 Feb 2018
Location: Scotland
Contact:

Re: <2kbyte 6502 Tiny Basic?

Post by drogon »

Chromatix wrote:
I adopted the BBC BASIC convention of making "true" results from comparison operators be -1. This means that bitwise operators can also be used for logical operations, including NOT. I don't think it requires significantly more code than producing a 1 result, as for both "false" and "true" a single byte value is replicated to all four result positions.

C doesn't do this - it has separate operators for bitwise and logical operations. So bitwise complement is ~ and logical complement is !.

If only there was a standard... but wait, there is....

https://xkcd.com/927/

-Gordon
--
Gordon Henderson.
See my Ruby 6502 and 65816 SBC projects here: https://projects.drogon.net/ruby/
Chromatix
Posts: 1462
Joined: 21 May 2018

Re: <2kbyte 6502 Tiny Basic?

Post by Chromatix »

Another program showing off interesting features of the interpreter. Note that the code is not presented in execution order, but when pasted in it will effectively be sorted by line number. This takes approximately 1.2 million cycles to complete, and then executing the program takes several million more.

Code: Select all

5000 PRINT D,"|",(18432*100)/(D*16);
5010 F=(18432*10000/(D*16))-(18432*100/(D*16))*100
5011 GOSUB 4000
5020 PRINT " |",(24576*100)/(D*16);
5030 F=(24576*10000/(D*16))-(24576*100/(D*16))*100
5031 GOSUB 4000
5040 PRINT " |",(18432*200)/(D*16);
5050 F=(18432*20000/(D*16))-(18432*200/(D*16))*100
5051 GOSUB 4000
5060 PRINT
5070 RETURN

4000 IF F PRINT ".";F/10;F-(F/10*10);
4010 RETURN

  10 D=1
  20 D=2
  30 D=3
  40 D=4
  50 D=6
  60 D=8
  70 D=12
  80 D=16
  90 D=24
 100 D=32
 110 D=48
 120 D=64
 130 D=96
 140 D=128
 150 D=192
 160 D=256
 170 D=384
 180 D=512
 190 D=576
 200 D=768
 210 D=856
 220 D=1047
 230 D=1142
 240 D=1396
 250 D=1536
 260 D=1713
 270 D=2048
 280 D=2095
 290 D=2304
 300 D=2534
 310 D=3072
 320 D=3379

  15 GOSUB 5000
  25 GOSUB 5000
  35 GOSUB 5000
  45 GOSUB 5000
  55 GOSUB 5000
  65 GOSUB 5000
  75 GOSUB 5000
  85 GOSUB 5000
  95 GOSUB 5000
 105 GOSUB 5000
 115 GOSUB 5000
 125 GOSUB 5000
 135 GOSUB 5000
 145 GOSUB 5000
 155 GOSUB 5000
 165 GOSUB 5000
 175 GOSUB 5000
 185 GOSUB 5000
 195 GOSUB 5000
 205 GOSUB 5000
 215 GOSUB 5000
 225 GOSUB 5000
 235 GOSUB 5000
 245 GOSUB 5000
 255 GOSUB 5000
 265 GOSUB 5000
 275 GOSUB 5000
 285 GOSUB 5000
 295 GOSUB 5000
 305 GOSUB 5000
 315 GOSUB 5000
 325 GOSUB 5000

 330 GOTO 65535
The main features thus demonstrated/exercised are the memory management for program code, the use of 32-bit internal arithmetic to support fixed-point, and nested subroutine calls. In a more complete and conventional BASIC interpreter, this would be a natural place to use DATA and READ, which I don't have - nor is there an END or STOP, but a contrived GOTO past the end of the program also works.

The output is a table of the baud rates for my "improved ACIA" proposal:
BaudRates.png
Chromatix
Posts: 1462
Joined: 21 May 2018

Re: <2kbyte 6502 Tiny Basic?

Post by Chromatix »

And, what I'm sure you've all been waiting for:
Mandelbrot.png

Code: Select all

   0 S=2048
  10 A=S*-21/10
  20 B=S*3/2
  30 C=S*3/2
  40 D=S*-3/2
  50 E=200
  60 F=(B-A)/128
  70 G=(C-D)/48
  80 L=C
  90 REPEAT
 100  K=A
 110  REPEAT
 120   V=0
 130   U=0
 150   O=0
 160   REPEAT
 170    X=U*U/S
 180    Y=V*V/S
 190    V=U*V/(S/2)+L
 200    U=X-Y+K
 210    O=O+1
 220   UNTIL O >= E OR X+Y > 4*S
 230   IF O<E AND O>9 VDU 64
 240   IF O<10 VDU O+48
 250   IF O=E VDU 32
 260   K=K+F
 270  UNTIL K >= B
 280  PRINT
 290  L=L-G
 300 UNTIL L < D
I haven't got a timing for this, but it does run and produce reasonable results. I did have to correct a serious oversight in the division routine, related to the handling of negative arguments…
gfoot
Posts: 871
Joined: 09 Jul 2021

Re: <2kbyte 6502 Tiny Basic?

Post by gfoot »

Hooray! There are some overflows though, I think, e.g. the noise in the top and bottom right corners, and between zones 3 and 4. I'd guess U*U/S or V*V/S is overflowing before the division, so you might need to do range checks on U and V as well, perhaps, and decide how to act if they're already above a threshold.
Chromatix
Posts: 1462
Joined: 21 May 2018

Re: <2kbyte 6502 Tiny Basic?

Post by Chromatix »

I have a suspicion that those aren't really overflows, but might be due to a subtle bug in the interpreter which would only show up with large-magnitude numbers. The near-threshold iterates in those regions should not be overflowing 32 bits with the scale factor I've selected, but might overflow 24 bits. I'll investigate…

EDIT: Well, there's no problem in the intermediate values, but it's more likely that the stored variables are overflowing. With some extra bailout tests on the inner loop, I can successfully hide these, though the shape of the exterior gradient changes.
Chromatix
Posts: 1462
Joined: 21 May 2018

Re: <2kbyte 6502 Tiny Basic?

Post by Chromatix »

This is much better:
Mandelbrot2.png

Code: Select all

   0 S=4096
   5 T=S*4
  10 A=S*-21/10
  20 B=S*3/2
  30 C=S*3/2
  40 D=S*-3/2
  50 E=200
  60 F=(B-A)/128
  70 G=(C-D)/48
  80 L=C
  90 REPEAT
 100  K=A
 110  REPEAT
 120   V=L
 130   U=K
 150   O=-1
 160   REPEAT
 170    Z=(U*U-V*V)/S
 190    V=U*V/(S/2)+L
 200    U=Z+K
 210    O=O+1
 220   UNTIL O >= E OR U*U+V*V > T*S
 230   IF O<E AND O>9 VDU 64
 240   IF O<10 VDU O+48
 250   IF O=E VDU 32
 260   K=K+F
 270  UNTIL K >= B
 280  PRINT
 290  L=L-G
 300 UNTIL L < D
User avatar
barrym95838
Posts: 2056
Joined: 30 Jun 2013
Location: Sacramento, CA, USA

Re: <2kbyte 6502 Tiny Basic?

Post by barrym95838 »

A fellow by the name of Will Stevens has recently implemented a 1012 byte tiny BASIC, with signed 16-bit arithmetic, tokenization, a single numeric array, FOR/NEXT/STEP, ABS(), USR() and RND(). The only trouble (at least for me) is that it's for the 8080, and I quickly developed a headache trying to grok his assembly code. All of those LXI, SHLD, DCX, RST, XTHL, XCHG, SPHL, PCHL instructions certainly pack a punch, but I've never heard of a non-trivial 8080 program being half the size of an equivalent 6502 program, so it's quite possible that some valuable insights could be gained from Will's code related to the subject at hand, for someone brave enough to take the dive. I haven't given up entirely, but I also haven't gathered sufficient courage yet ...
Got a kilobyte lying fallow in your 65xx's memory map? Sprinkle some VTL02C on it and see how it grows on you!

Mike B. (about me) (learning how to github)
Post Reply