Why was BBC BASIC so fast?

bbc/electron apps, languages, utils, educational progs, demos + more
User avatar
1024MAK
Posts: 10361
Joined: Mon Apr 18, 2011 5:46 pm
Location: Looking forward to summer in Somerset, UK...
Contact:

Re: Why was BBC BASIC so fast?

Post by 1024MAK » Sun Nov 15, 2020 8:00 pm

lurkio wrote:
Sun Nov 15, 2020 7:41 pm

Thanks for that! Of course, I could be a smartarse and point out that that doesn't prove anything because even a Beeb will display ten iterations of the loop, and your photo only shows seven! But I presume you're trying to say that the Model 100 keeps going indefinitely. Nice demo.

:idea:
Err, the FOR loop end value is THREE!

And on this computer, the screen real estate is a bit limited :lol:

Mark

User avatar
1024MAK
Posts: 10361
Joined: Mon Apr 18, 2011 5:46 pm
Location: Looking forward to summer in Somerset, UK...
Contact:

Re: Why was BBC BASIC so fast?

Post by 1024MAK » Sun Nov 15, 2020 10:37 pm

BeebMaster wrote:
Sun Nov 15, 2020 7:47 pm
Can some BASICs not do nested loops at all then? I think I would find that very limiting.
As far as I know, all BASICs can do nested loops (although how deeply nested is another matter).

The Model 100 certainly works okay:
ED82A106-BAE2-4FB0-B547-261E5DE6A6CB.jpeg
Nested FOR - NEXT loops, program listing
4B26E4FF-F871-4E6D-9D68-D9918182A683.jpeg
Program output
Mark

User avatar
scruss
Posts: 295
Joined: Sun Jul 01, 2018 4:12 pm
Location: Toronto
Contact:

Re: Why was BBC BASIC so fast?

Post by scruss » Tue Nov 17, 2020 1:34 am

The Model 100 basic is one of Microsoft's weird diversions into BCD floating point. It's slow, but at least it passes Roger Broucke's test:

Code: Select all

10 S=0
20 X=0
30 FOR N=1 TO 1000
40 S=S+X*X
50 X=X+0.00123
60 NEXT N
70 PRINT S,X
80 PRINT "CORRECT RESULT: 503.54380215, 1.23"

User avatar
scruss
Posts: 295
Joined: Sun Jul 01, 2018 4:12 pm
Location: Toronto
Contact:

Re: Why was BBC BASIC so fast?

Post by scruss » Tue Nov 17, 2020 2:55 am

Richard Russell wrote:
Sun Nov 15, 2020 10:04 am
It's in this very thread! Here's a direct link to the post containing the listing; Coeus used it in his post listing the 'reference' Z80 Second Processor results from B-Em.
Okay, so running this in Arnold (which is fairly accurate to the 3.3 MHz effective clock on an Amstrad CPC) I got this:
Screenshot from 2020-11-16 21-26-17.png
Screenshot from 2020-11-16 21-26-17.png (4.33 KiB) Viewed 665 times
Conclusion: pants, except for the FP.

For consolation, here's the same run in beebjit on a 4 GHz i7, 4th series:

Code: Select all

>CH."CLCKSP3"
BBC BASIC CPU Timing Program
Really real REPEAT loop   8971.55MHz
Integer REPEAT loop       9446.64MHz
Really real FOR loop     12397.09MHz
Integer FOR loop         14710.74MHz
Trig/Log test            12647.05MHz
String manipulation      10467.62MHz
Procedure call           10151.32MHz
GOSUB call                9375.00MHz
Combined Average         10978.20MHz

Compared with a 2.00MHz BBC B
Or in Matrix Brandy on the same hardware:

Code: Select all

sbrandy clcksp3.bbc 
BBC BASIC CPU Timing Program
Really real REPEAT loop 166666.66MHz
Integer REPEAT loop      86909.09MHz
Really real FOR loop    199221.78MHz
Integer FOR loop         82790.69MHz
Trig/Log test           911111.11MHz
String manipulation     177007.29MHz
Procedure call           95379.14MHz
GOSUB call              122615.80MHz
Combined Average        363538.90MHz

Compared with a 2.00MHz BBC B

User avatar
BigEd
Posts: 3562
Joined: Sun Jan 24, 2010 10:24 am
Location: West Country
Contact:

Re: Why was BBC BASIC so fast?

Post by BigEd » Tue Nov 17, 2020 9:53 am

I would say it's not too bad at all for a 3.3MHz Z80 to keep up with a 1MHz 6502. That's about the general equivalence ratio, because they are both accessing memory at about the same rate, with a slight advantage to the Z80 with the larger register pool and richer instruction set.

User avatar
Richard Russell
Posts: 1715
Joined: Sun Feb 27, 2011 10:35 am
Location: Downham Market, Norfolk
Contact:

Re: Why was BBC BASIC so fast?

Post by Richard Russell » Tue Nov 17, 2020 12:37 pm

BigEd wrote:
Tue Nov 17, 2020 9:53 am
I would say it's not too bad at all for a 3.3MHz Z80 to keep up with a 1MHz 6502.
Was it BBC BASIC (Z80) v2 or v3? As noted earlier in the thread, v3 runs a little slower than v2. This is largely because of the modifications I had to make for the Cambridge Computer Z88, principally to separate out the arithmetic and floating-point package (FPP) into a separate self-contained module so that it could be called from other applications, notably Pipedream. It can also be called concurrently from multiple processes.

As a result the v3 interpreter calls the FPP via a common entry-point and a function number, whereas v2 called the appropriate subroutines directly; this unavoidably introduces a run-time overhead every time any numeric calculation is performed. So you can blame Clive Sinclair for BBC BASIC (Z80) slowing down slightly, but I felt it was quite a coup for my FPP to be shared like that.

Code: Select all

                              Specification of
                   Z80 Floating Point Arithmetic Package
                      for Protechnic Computers Limited

This  document  specifies  the  characteristics of the  Z80  Floating  Point 
Package  to be supplied to Protechnic Computers Ltd.  It forms part  of  the 
agreement  between Protechnic Computers Limited and M-Tec Computer  Services 
(UK) for the supply of this product.

General characteristics:

1.  The  FPP  is written in Z80 assembly language.   It uses all  the  Z80's 
    general  purpose  registers,   including  IX,   IY  and  the  "alternate 
    registers",  but  does not use the R register or the I register nor does 
    it  disable or enable interrupts or change the interrupt  mode.   It  is 
    fully interruptible.

2.  The  FPP requires no private or shared workspace,  it uses registers and 
    the stack for all working and temporary storage.  It is fully re-entrant 
    and may be called freely from concurrent processes,  even if  pre-empted 
    by a non-maskable interrupt.

3.  The  code size of the FPP will not exceed three kilobytes (3072  bytes). 
    No  self-modifying  code  is  used  and  it  is  fully  ROMmable.  Stack 
    requirements  have  not  yet been accurately determined but  should  not 
    exceed fifty bytes.

Operations provided:

The  FPP provides sixteen operations which take two numeric  parameters  and 
produce a numeric result (AND, DIV, EOR, MOD, OR, <=, <>, >=, <, =, >, +, -, 
*,  / and ^),  sixteen numeric functions (ABS, ACS, ASN, ATN, COS, DEG, EXP, 
INT,  LN,  LOG, NOT, RAD, SGN, SIN, SQR, TAN), four numeric constants (ZERO, 
FONE,  TRUE,  PI),  two numeric/string conversion routines (VAL,  STR$), two 
format  conversion  routines (FIX,  FLOAT) and  two  miscellaneous  routines 
(TEST, COMPARE).

All   numeric  operations  will  accept  either  integer  or  floating-point 
parameters,  converting where necessary.   Returned values may be in integer 
or floating-point format, as appropriate.

Numeric range and precision:

Integers are stored in 4 bytes, and may represent values from -2147483648 to 
+2147483647.  Floating-point numbers are stored in 5 bytes (4 byte mantissa, 
1  byte exponent) and may represent values from approximately +/- 5.9E-39 to 
+/- 3.4E38, with a resolution of about nine significant figures.

Considerable care has been taken in coding the FPP to preserve the  greatest 
degree  of accuracy consistent with the use of a 32-bit  mantissa.  However, 
complex  operations such as the transcendental functions make use of several 
intermediate  results,  each  of  which  is  stored  only  with  the  normal 
precision.  It  is therefore possible for errors to accumulate and  for  the 
final  result to be less accurate than would be desirable.  This problem  is 
aggravated in certain special cases,  such as the logarithm of numbers close 
to 1. No guarantee can be given that the accuracy will be sufficient for any 
specific application.  As always, in financial applications you are strongly 
advised to use only integer arithmetic.

Numeric Representation

Details  of the formats of integers and floating-point numbers may be  found 
in Appendix E of the BBCBASIC (Z80) manual (section 28 onwards) except that, 
in the case of the FPP, numbers are held in the processor's registers rather 
than in memory.  Two floating-point numbers may be held in the registers  at 
any one time, as follows:

                                       Number 1       Number 2

          Mantissa MS byte:               H              D
                  .                       L              E
                  .                       H'             D'
          Mantissa LS byte:               L'             E'
          Exponent byte:                  C              B
     
As described in Appendix E,  section 34,  integer values are denoted by  the 
"exponent" (C or B register) being zero.

Interface details:

All  FPP  operations are accessed via a common entry  point,  the  operation 
required  being  specified  by  an 8-bit "operation code" passed  in  the  A 
register.  The entry point is the base address of the FPP code:

                         LD   A,opcode
                         CALL fpp

The  intention  is  that two Restart entry points will be  provided  by  the 
machine's  Operating System for accessing the FPP;  these will take care  of 
overheads  such as ensuring that the FPP code is suitably "paged  in".   One 
Restart  will  take  the  "operation code" as  an  in-line  parameter,  thus 
providing  a  convenient  2-byte  mechanism  for  accessing  the  FPP   from 
applications programs:

                         RST  fpprst1
                         DEFB opcode

The other Restart will take the operation code in A, for those circumstances 
when  the required operation has been computed rather than being known as  a 
constant:

                         LD   A,opcode
                         RST  fpprst2

This  latter,  3-byte,  method  is particularly applicable to the BBC  BASIC 
interpreter which often derives the op-code from a keyword token.  It should 
also be slightly faster than the first method.

The  argument  of a numeric function is passed in registers HLH'L'C and  the 
result is returned in registers HLH'L'C. Operators (addition, multiplication 
etc.)  each take two operands and return a single result.  The operands  are 
passed  in HLH'L'C (left) & DED'E'B (right),  and the result is returned  in 
HLH'L'C.  The result of TEST and COMPARE is returned in the A register.

For  information  on  the register usage of  the  numeric/string  conversion 
functions see the detailed descriptions.

Exception handling:

If  an operation completes without error it returns with the zero  flag  set 
and  the  carry flag reset.   If an exception occurs during an operation  it 
returns  with the zero flag reset,  the carry flag set and an error code  in 
the A register.   In this case the returned value in the other registers  is 
meaningless.

The possible error codes (decimal) are as follows:

           1:  "Bad operation code"
          18:  "Division by zero"
          20:  "Too big"
          21:  "-ve root"
          22:  "Log range"
          23:  "Accuracy lost"
          24:  "Exp range"

Note  that  these error codes are defined as manifest constants in  the  FPP 
source  code,  but that it will be inconvenient to the BBC BASIC interpreter 
if they are changed (they correspond to standard BBC BASIC error numbers).

Registers affected:

On return from the FPP,  any or all of the following registers may have been 
altered:

                 A,B,C,D,E,H,L,F,A',B',C',D',E',H',L',F',IX

The IY, SP and I registers are returned unchanged.

Operation codes:

The following (decimal) operation codes cause the specified operations to be 
performed:

           0:  AND       16:  ABS        32:  ZERO
           1:  DIV       17:  ACS        33:  FONE
           2:  EOR       18:  ASN        34:  TRUE
           3:  MOD       19:  ATN        35:  PI   
           4:   OR       20:  COS        36:  VAL  
           5:   <=       21:  DEG        37:  STR$ 
           6:   <>       22:  EXP        38:  FIX  
           7:   >=       23:  INT        39:  FLOAT
           8:   <        24:   LN        40:  TEST
           9:   =        25:  LOG        41:  COMPARE
          10:   *        26:  NOT 
          11:   +        27:  RAD 
          12:   >        28:  SGN 
          13:   -        29:  SIN 
          14:   ^        30:  SQR 
          15:   /        31:  TAN
                                 




Details of FPP operations:

Opcode  0:  AND - Integer bitwise logical AND
Parameters: HLH'L'C & DED'E'B
Results: HLH'L'C (C = 0)

Opcode  1:  DIV - Integer quotient after division
Parameters: HLH'L'C (left) DED'E'B (right)
Results: HLH'L'C (C = 0)

Opcode  2:  EOR - Integer bitwise logical exclusive-OR
Parameters: HLH'L'C & DED'E'B
Results: HLH'L'C (C = 0)

Opcode  3:  MOD - Integer remainder after division
Parameters: HLH'L'C (left) DED'E'B (right)
Results: HLH'L'C (C = 0)

Opcode  4:   OR - Integer bitwise logical OR
Parameters: HLH'L'C & DED'E'B
Results: HLH'L'C (C = 0)

Opcode  5:   <= - Test for less-than or equal-to
Parameters: HLH'L'C (left) DED'E'B (right)
Results: HLH'L'C (C = 0, HLH'L' = 0 [FALSE] or -1 [TRUE])

Opcode  6:   <> - Test for not equal to
Parameters: HLH'L'C & DED'E'B 
Results: HLH'L'C (C = 0, HLH'L' = 0 [FALSE] or -1 [TRUE])

Opcode  7:   >= - Test for greater-than or equal-to
Parameters: HLH'L'C (left) DED'E'B (right)
Results: HLH'L'C (C = 0, HLH'L' = 0 [FALSE] or -1 [TRUE])

Opcode  8:   <  - Test for less than
Parameters: HLH'L'C (left) DED'E'B (right)
Results: HLH'L'C (C = 0, HLH'L' = 0 [FALSE] or -1 [TRUE])

Opcode  9:   =  - Test for equality
Parameters: HLH'L'C & DED'E'B
Results: HLH'L'C (C = 0, HLH'L' = 0 [FALSE] or -1 [TRUE])

Opcode 10:   *  - Integer or floating-point multiplication
Parameters: HLH'L'C & DED'E'B
Results: HLH'L'C

Opcode 11:   +  - Integer or floating-point addition
Parameters: HLH'L'C & DED'E'B
Results: HLH'L'C

Opcode 12:   >  - Test for greater than
Parameters: HLH'L'C (left) DED'E'B (right)
Results: HLH'L'C (C = 0, HLH'L' = 0 [FALSE] or -1 [TRUE])

Opcode 13:   -  - Integer or floating-point subtraction
Parameters: HLH'L'C (left) DED'E'B (right)
Results: HLH'L'C

Opcode 14:   ^  - Integer or floating-point involution (raise to power)
Parameters: HLH'L'C (left) DED'E'B (right)
Results: HLH'L'C

Opcode 15:   /  - Floating-point division
Parameters: HLH'L'C (left) DED'E'B (right)
Results: HLH'L'C

Opcode 16:  ABS - Absolute value
Parameters: HLH'L'C
Results: HLH'L'C

Opcode 17:  ACS - Arc cosine (inverse cosine)
Parameters: HLH'L'C
Results: HLH'L'C (radians)

Opcode 18:  ASN - Arc sine (inverse sine)
Parameters: HLH'L'C
Results: HLH'L'C (radians)

Opcode 19:  ATN - Arc tangent (inverse tangent)
Parameters: HLH'L'C
Results: HLH'L'C (radians)

Opcode 20:  COS - Cosine
Parameters: HLH'L'C (radians)
Results: HLH'L'C

Opcode 21:  DEG - Convert radians to degrees
Parameters: HLH'L'C (radians)
Results: HLH'L'C (degrees)

Opcode 22:  EXP - Exponential (raise e to the power of the argument)
Parameters: HLH'L'C
Results: HLH'L'C

Opcode 23:  INT - Integer part (floor function)
Parameters: HLH'L'C
Results: HLH'L'C (C = 0)

Opcode 24:   LN - Natural (Napierian) logarithm
Parameters: HLH'L'C
Results: HLH'L'C

Opcode 25:  LOG - Base-10 (Common) logarithm
Parameters: HLH'L'C
Results: HLH'L'C

Opcode 26:  NOT - Bitwise logical NOT (one's complement)
Parameters: HLH'L'C
Results: HLH'L'C (C = 0)

Opcode 27:  RAD - Convert degrees to radians
Parameters: HLH'L'C (degrees)
Results: HLH'L'C (radians)



Opcode 28:  SGN - Sign (signum)
Parameters: HLH'L'C
Results: HLH'L'C (=-1 if negative, =0 if zero, =+1 if positive; C = 0)

Opcode 29:  SIN - Sine
Parameters: HLH'L'C (radians)
Results: HLH'L'C

Opcode 30:  SQR - Square root
Parameters: HLH'L'C
Results: HLH'L'C

Opcode 31:  TAN - Tangent
Parameters: HLH'L'C (radians)
Results: HLH'L'C

Opcode 32:  ZERO - Return the floating-point & integer constant zero
Parameters: None
Results: HL=&0000, H'L'=&0000, C=0

Opcode 33:  FONE - Return the floating-point constant one
Parameters: None
Results: HL=&0000, H'L'=&0000, C=&80

Opcode 34:  TRUE - Return the integer constant minus one
Parameters: None
Results: HL=&FFFF, H'L'=&FFFF, C=0

Opcode 35:  PI    - Return the floating-point constant PI
Parameters: None
Results: HLH'L'C (= 3.141592654)

Opcode 36:  VAL   - Return the numeric value of a string
Parameters: IX addresses string in memory, terminated by a NUL
Results: HLH'L'C. If the string does not represent a number, 0 is returned.
         IX addresses the terminating character (not necessarily the NUL).

Opcode 37:  STR$  - Return the string representation of a number
Parameters: HLH'L'C = number to be converted
            DE = destination address in memory for string
            IX addresses format variable (@%), only (IX+1) & (IX+2) used
Results: String stored in memory, DE addresses byte following last character

Opcode 38:  FIX   - Truncate a number to an integer
Parameters: HLH'L'C (if C=0 the number is returned unchanged)
Results: HLH'L'C (C = 0).  The "too big" error may result.

Opcode 39:  FLOAT - Convert an integer to floating-point format
Parameters: HLH'L'C (if C<>0 the number is returned unchanged)
Results: HLH'L'C

Opcode 40:  TEST - Test a number for zero and sign
Parameters: HLH'L'C
Results: If zero, A=0; if positive A=&40; if negative A=&C0

Opcode 41:  COMPARE - Compare two numeric values
Parameters: HLH'L'C (left) DED'E'B (right)
Results: If equal, A=0; If left>right A=&40; If left<right A=&C0
I am suffering from 'cognitive decline' and depression. If you have a comment about the style or tone of this message please report it to the moderators by clicking the exclamation mark icon, rather than complaining on the public forum.

User avatar
BigEd
Posts: 3562
Joined: Sun Jan 24, 2010 10:24 am
Location: West Country
Contact:

Re: Why was BBC BASIC so fast?

Post by BigEd » Tue Nov 17, 2020 1:07 pm

(Very interesting - thanks Richard!)

User avatar
scruss
Posts: 295
Joined: Sun Jul 01, 2018 4:12 pm
Location: Toronto
Contact:

Re: Why was BBC BASIC so fast?

Post by scruss » Tue Nov 17, 2020 1:19 pm

Richard Russell wrote:
Tue Nov 17, 2020 12:37 pm
Was it BBC BASIC (Z80) v2 or v3?
Amstrad BBC BASIC v2.3, run from an image on this rather noisy page: amstrad bbc basic version 2.30 © timatic systems ltd (1986). That boots into CP/M+, so is clearly not from an original disk.
… So you can blame Clive Sinclair for BBC BASIC (Z80) slowing down slightly, but I felt it was quite a coup for my FPP to be shared like that.
I think you should be a bit louder about what you did there - thanks so much for including the spec document. So you wrote a general purpose numerics package:
  • that uses no workspace outside the registers and stack;
  • that was fully re-entrant;
  • that fit into 3K of storage.
That's bloody marvellous, that is. You should be very proud of that.

Unfortunately I can't seem to get the v3 Amstrad interpreter to run on my emulator, for $reasons.

User avatar
Richard Russell
Posts: 1715
Joined: Sun Feb 27, 2011 10:35 am
Location: Downham Market, Norfolk
Contact:

Re: Why was BBC BASIC so fast?

Post by Richard Russell » Tue Nov 17, 2020 2:09 pm

scruss wrote:
Tue Nov 17, 2020 1:19 pm
That's bloody marvellous, that is. You should be very proud of that.
It was an awfully long time ago, and my memory is poor, but I think I was pleased with it. On the other hand it illustrates my obsession at the time, and to an extent since, with minimising code size rather than maximising speed, which may help explain its disappointing performance.

Member Jimmy has been studying the code and is confident that he can make it faster. For example he points out that the IX and IY registers are so slow that using scratch memory locations can actually be faster, but from my perspective sacrificing the re-entrancy would be too high a price to pay.
I am suffering from 'cognitive decline' and depression. If you have a comment about the style or tone of this message please report it to the moderators by clicking the exclamation mark icon, rather than complaining on the public forum.

dominicbeesley
Posts: 1227
Joined: Tue Apr 30, 2013 12:16 pm
Contact:

Re: Why was BBC BASIC so fast?

Post by dominicbeesley » Thu Nov 19, 2020 12:02 pm

Richard Russell wrote:
Tue Nov 17, 2020 12:37 pm

As a result the v3 interpreter calls the FPP via a common entry-point and a function number, whereas v2 called the appropriate subroutines directly; this unavoidably introduces a run-time overhead every time any numeric calculation is performed. So you can blame Clive Sinclair for BBC BASIC (Z80) slowing down slightly, but I felt it was quite a coup for my FPP to be shared like that.
That's interesting - I'm currently working through a disassembly of the Acorn Communicator version of BBC Basic and that too separates much of the higher FP stuff into an "ARITHMETIC" module - did you have anything to do with that? (Any light shed would be useful). I'm close to getting the disassembly to a point where I can start hacking at it with confidence, probably just in time for somebody to come up with the original sourcecode making my efforts moot!

D

User avatar
Richard Russell
Posts: 1715
Joined: Sun Feb 27, 2011 10:35 am
Location: Downham Market, Norfolk
Contact:

Re: Why was BBC BASIC so fast?

Post by Richard Russell » Thu Nov 19, 2020 12:44 pm

dominicbeesley wrote:
Thu Nov 19, 2020 12:02 pm
that too separates much of the higher FP stuff into an "ARITHMETIC" module - did you have anything to do with that?
No, nothing to do with me. But like the Z88 it had, I believe, a built-in spreadsheet application so sharing the FPP is an obvious thing to want to do.
I am suffering from 'cognitive decline' and depression. If you have a comment about the style or tone of this message please report it to the moderators by clicking the exclamation mark icon, rather than complaining on the public forum.

johnha
Posts: 159
Joined: Sat Nov 17, 2012 6:45 pm
Contact:

Re: Why was BBC BASIC so fast?

Post by johnha » Thu Nov 19, 2020 1:09 pm

I'm just coming into this thread, apologies if this has been mentioned before. The Dragon 32 (and presumably the CoCo?) BASIC interpreters (Microsoft BASIC) could be speeded up by POKE &HFFD7,0 - I'm still not sure how it actually worked. Described as either putting the 6809E (E = external clock IIRC) into 'dual clock' mode or clocking it faster (1.8MHz as opposed to 0.9). It was the first line in most BASIC 'type-in' games and memorable for it!

It messed up the cassette baud rates - so if you were impatient in seeing just what your first 50 lines of BASIC might do by running it, you'd lose the ability to record the remaining lines. The Dragon RESET switch only loaded the reset vectors - it didn't clear BASIC programs from memory, I doubt it would have cleared this POKE. Apparently there's a faster POKE which messed up the screen display - I didn't encounter that back in the day.

A further ingrained muscle memory was that pressing SHIFT & DELETE would delete the whole BASIC line you where typing. After years coding the Dragon I found myself checking I didn't have SHIFT pressed when deleting something all the way until I started using PC laptops (the keyboards where sufficiently different to wean me off it).

As to why BBC BASIC Is so fast, it was a well designed machine with a lot of thought going into it. The B was nearly double the price of a Dragon 32 and nearly 4x the price of a Spectrum 16K. The Dragon was developed as a CoCo clone and had some good features - including two analogue joystick ports, a half decent keyboard and remote control of suitably equipped tape recorders. My party trick was to demo its 'superior' sound was to put an audio cassette in the tape recorder and write a program that used MOTOR ON/OFF (start/stop the tape) and AUDIO ON/OFF (pipe the cassette audio straight through to the TV speaker).

dominicbeesley
Posts: 1227
Joined: Tue Apr 30, 2013 12:16 pm
Contact:

Re: Why was BBC BASIC so fast?

Post by dominicbeesley » Thu Nov 19, 2020 2:52 pm

johnha wrote:
Thu Nov 19, 2020 1:09 pm
I'm just coming into this thread, apologies if this has been mentioned before. The Dragon 32 (and presumably the CoCo?) BASIC interpreters (Microsoft BASIC) could be speeded up by POKE &HFFD7,0 - I'm still not sure how it actually worked. Described as either putting the 6809E (E = external clock IIRC) into 'dual clock' mode or clocking it faster (1.8MHz as opposed to 0.9). It was the first line in most BASIC 'type-in' games and memorable for it!
I think it only goes "fast" during the cycles where the 6x09 isn't doing anything with memory or devices (VMA is not asserted)...or maybe that's on the CoCo? It can make a fair difference.

jimmy
Posts: 113
Joined: Tue May 06, 2008 7:37 pm
Contact:

Re: Why was BBC BASIC so fast?

Post by jimmy » Fri Nov 20, 2020 3:54 pm

I've managed to improve the speed a little, but there's still more to go. I'm having to implement some filesystem and VDU support at the same time to allow more BBC BASIC programs to run on the ZX Spectrum. So far I've implemented tape load/save and VDU queues, along with a handful of VDU codes
b07_128_145.png

User avatar
Richard Russell
Posts: 1715
Joined: Sun Feb 27, 2011 10:35 am
Location: Downham Market, Norfolk
Contact:

Re: Why was BBC BASIC so fast?

Post by Richard Russell » Fri Nov 20, 2020 4:54 pm

jimmy wrote:
Fri Nov 20, 2020 3:54 pm
I've managed to improve the speed a little
Can you please make sure that your version prints a message making it obvious that it's been modified by you. The Zlib licence states that "Altered source versions must not be misrepresented as being the original software".
I am suffering from 'cognitive decline' and depression. If you have a comment about the style or tone of this message please report it to the moderators by clicking the exclamation mark icon, rather than complaining on the public forum.

julie_m
Posts: 245
Joined: Wed Jul 24, 2019 9:53 pm
Location: Derby, UK
Contact:

Re: Why was BBC BASIC so fast?

Post by julie_m » Fri Nov 20, 2020 10:26 pm

I noticed while in the course of probing into how BASIC stores its programs and variables that line numbers are stored "backwards" to how the 6502 usually stores multi-byte values. If you are sure you are comparing unsigned numbers, you can CMP the high byte first, but you don't have to store it first in memory; you probably are going to access it with the (zp),Y addressing mode, and LDY#1 and DEY are the same number of bytes as LDY#0 and INY ......

But then it occurred to me that if you can stop as soon as you reach the special value that can't possibly be a real line number because its highest bit is set, then you don't care what the low byte is at all -- meaning you can save one byte of RAM, if you store the line numbers with the high byte first.

Shame they went and ruined it by putting an &00 byte after the end of every variable name, though! % and $ could have been their own delimiters, and the last character of a normal numeric variable name could have had bit 7 set.

User avatar
Richard Russell
Posts: 1715
Joined: Sun Feb 27, 2011 10:35 am
Location: Downham Market, Norfolk
Contact:

Re: Why was BBC BASIC so fast?

Post by Richard Russell » Fri Nov 20, 2020 10:59 pm

julie_m wrote:
Fri Nov 20, 2020 10:26 pm
I noticed while in the course of probing into how BASIC stores its programs and variables that line numbers are stored "backwards" to how the 6502 usually stores multi-byte values.
It's something that I changed right from the start (in my Z80 version and all subsequent ones). The big-endian line numbers probably made little difference on a 6502, which has to access them one byte-at-a-time anyway, but in CPUs with little-endian 16-bit memory accesses it made no sense and would have hit performance of GOTO and GOSUB.
But then it occurred to me that if you can stop as soon as you reach the special value that can't possibly be a real line number because its highest bit is set, then you don't care what the low byte is at all
Only in 6502 BBC BASIC does having the highest bit set mean it can't be a line number. In Sophie's later BASICs the highest line number is 65279 (&FEFF) and in mine it's 65535 (&FFFF).
meaning you can save one byte of RAM, if you store the line numbers with the high byte first.
I can't save a byte that way, but I can (and do) save one by omitting the initial &0D.
% and $ could have been their own delimiters
It's a good thing Sophie didn't do that, because it would have meant that we couldn't now use %% as the suffix for 64-bit integers (which Matrix Brandy and my current BASICs all do).
I am suffering from 'cognitive decline' and depression. If you have a comment about the style or tone of this message please report it to the moderators by clicking the exclamation mark icon, rather than complaining on the public forum.

Soruk
Posts: 802
Joined: Mon Jul 09, 2018 11:31 am
Location: Basingstoke, Hampshire
Contact:

Re: Why was BBC BASIC so fast?

Post by Soruk » Sat Nov 21, 2020 9:25 pm

Richard Russell wrote:
Sun Nov 15, 2020 10:04 am
scruss wrote:
Sun Nov 15, 2020 1:41 am
The really real version isn't anywhere I can find.
It's in this very thread! Here's a direct link to the post containing the listing; Coeus used it in his post listing the 'reference' Z80 Second Processor results from B-Em.

The original version is only suitable for testing emulators running the 6502 (or ARM) BASIC interpreter, it gives misleading results when run with any of my interpreters (Z80, 8086, IA-32 or the cross-platform editions written in C) because they detect that the so-called 'real' loops are actually using integers.
A bit late to the party on this one but I ought to compare both on Matrix Brandy.
Matrix Brandy BASIC VI (work in progress)

dominicbeesley
Posts: 1227
Joined: Tue Apr 30, 2013 12:16 pm
Contact:

Re: Why was BBC BASIC so fast?

Post by dominicbeesley » Sat Nov 21, 2020 10:02 pm

Richard Russell wrote:
Thu Jul 02, 2020 2:01 pm
I don't necessarily think it would have been a drastic change to have, say, an index of line numbers and associated pointers to the program code. Rather than storing three bytes per line (length and number) embedded in the program, a separate table could have stored four bytes per line (two bytes for the line number, two as a pointer) so the overall cost in memory would have been only one byte per line, but with the potential for much faster GOTO, GOSUB and RESTORE.
I think the index idea would be ruled out on space on the smaller memory machines. What I have just "found"* in Communicator's BBC Basic is that there is a facility to do

Code: Select all

...
1000.A_Label%:PRINT "here I am"
1010...
1020GOTOA_Label%
It looks to store the address of the start of the line in the variable OR'd with &FF000000 and use that. It looks on the surface as labels are cached (as normal variables) as they are encountered in GOTO/GOSUB/THEN/ELSE

Is this mechanism available in any other versions of BASIC? It looks useful at least for ON...GOTO etc

D

* this may be old hat?

User avatar
Richard Russell
Posts: 1715
Joined: Sun Feb 27, 2011 10:35 am
Location: Downham Market, Norfolk
Contact:

Re: Why was BBC BASIC so fast?

Post by Richard Russell » Sat Nov 21, 2020 11:58 pm

dominicbeesley wrote:
Sat Nov 21, 2020 10:02 pm
Is this mechanism available in any other versions of BASIC?
All my 'modern' versions of BBC BASIC support labels, but they were added principally to aid machine translation from other BASIC dialects (particularly Liberty BASIC) rather than with the expectation that programs written from scratch in BBC BASIC would use them. Indeed the syntax I use is similar to Liberty BASIC's labels:

Code: Select all

      (A_Label) PRINT "here I am"
      ...
      GOTO A_Label
I am suffering from 'cognitive decline' and depression. If you have a comment about the style or tone of this message please report it to the moderators by clicking the exclamation mark icon, rather than complaining on the public forum.

dominicbeesley
Posts: 1227
Joined: Tue Apr 30, 2013 12:16 pm
Contact:

Re: Why was BBC BASIC so fast?

Post by dominicbeesley » Sun Nov 22, 2020 12:17 am

How do you do the labels. So you scan for them all at program start or cache them as they are used? Do they get stored in normal variables or have their own space.

I've not fully worked out communicator basics implementation yet

D

dominicbeesley
Posts: 1227
Joined: Tue Apr 30, 2013 12:16 pm
Contact:

Re: Why was BBC BASIC so fast?

Post by dominicbeesley » Sun Nov 22, 2020 12:18 am

Thank Richard

How do you do the labels. So you scan for them all at program start or cache them as they are used? Do they get stored in normal variables or have their own space.

I've not fully worked out communicator basics implementation yet

D

User avatar
Richard Russell
Posts: 1715
Joined: Sun Feb 27, 2011 10:35 am
Location: Downham Market, Norfolk
Contact:

Re: Why was BBC BASIC so fast?

Post by Richard Russell » Sun Nov 22, 2020 12:51 am

dominicbeesley wrote:
Sun Nov 22, 2020 12:17 am
Do you scan for them all at program start or cache them as they are used? Do they get stored in normal variables or have their own space.
They share the same namespace as other variables (when machine-translated from Liberty BASIC I use a naming convention which avoids any collisions). I scan for them all in my 'No such variable' handler (rather than at program start), because that works after a CLEAR without any extra effort. The mechanism shares much of the code which scans for DEFs in the 'No such FN/PROC' handler (also to ensure correct operation after CLEAR).
I am suffering from 'cognitive decline' and depression. If you have a comment about the style or tone of this message please report it to the moderators by clicking the exclamation mark icon, rather than complaining on the public forum.

julie_m
Posts: 245
Joined: Wed Jul 24, 2019 9:53 pm
Location: Derby, UK
Contact:

Re: Why was BBC BASIC so fast?

Post by julie_m » Sun Nov 22, 2020 1:59 pm

How did Acorn ATOM BASIC handle its own, simpler "labels"?

jimmy
Posts: 113
Joined: Tue May 06, 2008 7:37 pm
Contact:

Re: Why was BBC BASIC so fast?

Post by jimmy » Sun Nov 22, 2020 3:51 pm

Richard Russell wrote:
Fri Nov 20, 2020 4:54 pm
Can you please make sure that your version prints a message making it obvious that it's been modified by you. The Zlib licence states that "Altered source versions must not be misrepresented as being the original software".
Sure - can you let me know what you'd like it to say and I'll make the changes. I've got 64 bytes (2 rows of 32) due to space constraints (both screen and memory!). The second row is the default string given by REPORT.

I have managed to patch your v3.0 CP/M release so it supports the TIMER. To make sure I'm not breaking any other license conditions, I'll attach the patch code below so anybody can validate the benchmark results:

Code: Select all

;BBCBASIC.COM 3.0 file is 14848 bytes long =3a00
;Patch TIMER access to allow benchmarks to run

;modify jump table
	ORG $010C
	JP PTIME
	JP GTIME

;re-use old code area
;0173 = old gtime
;017a = old ptime
	ORG $0173
SAFETIME:
	DEFS 5		;re-use 5 bytes here

OSWORD	EQU $FFF1

;use up some of blank area in page 01
	ORG $01D1

GTIME:
	LD HL,SAFETIME
	LD A,1
	CALL OSWORD
	LD DE,(SAFETIME+2)
	LD HL,(SAFETIME)
        RET

;overwrite checksum code as we don't need it
	ORG $38A1
	JR $38B7		;skip our code during init
PTIME:
	LD (SAFETIME),HL
	LD (SAFETIME+2),DE
	XOR A
	LD (SAFETIME+4),A	;Can't update 5th byte, so zero it out
	LD A,2
	LD HL,SAFETIME
	CALL OSWORD
        RET
I get the following results when comparing BBC BASIC 2.20 and 3.00 on B-Em running the Z80 2nd processor and CP/M 2.2
bem_220_246.png
bem_300_227.png
I have noticed that the benchmark results are greatly affected by any changes to FOR/NEXT routines. This might seem obvious, but you're sometimes left wondering why you've got a 3% speed increase on Procedure calls even though you haven't touched any of those routines.

dominicbeesley
Posts: 1227
Joined: Tue Apr 30, 2013 12:16 pm
Contact:

Re: Why was BBC BASIC so fast?

Post by dominicbeesley » Sun Nov 22, 2020 4:48 pm

ClockSp is okay as it goes for comparing machines but doesn't really test what it says it is testing. I started thinking about a set of benchmarks for assisting me in porting to different processors but didn't really get anywhere with it. Get in touch if you're interested in working on something more suited to interpreter writers and we could maybe come up with something.

User avatar
Richard Russell
Posts: 1715
Joined: Sun Feb 27, 2011 10:35 am
Location: Downham Market, Norfolk
Contact:

Re: Why was BBC BASIC so fast?

Post by Richard Russell » Sun Nov 22, 2020 5:04 pm

jimmy wrote:
Sun Nov 22, 2020 3:51 pm
can you let me know what you'd like it to say and I'll make the changes. I've got 64 bytes (2 rows of 32) due to space constraints (both screen and memory!).
Why can't you add a third row? Surely an extra 32 bytes isn't going to break anything. :?
I get the following results when comparing BBC BASIC 2.20 and 3.00 on B-Em running the Z80 2nd processor and CP/M 2.2
You are also using the old ClockSp program which gives misleading results with my BASICs (you can see that in the 'real' loops seeming to be much faster than the 'integer' loops, relative to 6502 BASIC, which of course they aren't). Please switch to using the modified 'really real' version of the program, as discussed previously in this thread.
I have noticed that the benchmark results are greatly affected by any changes to FOR/NEXT routines. This might seem obvious, but you're sometimes left wondering why you've got a 3% speed increase on Procedure calls even though you haven't touched any of those routines.
I've not studied ClockSp in any detail, but in any similar programs that I write I time an empty FOR...NEXT loop and subtract that from the measurement of whatever statement is being timed, so that (at least to a first approximation) changes to FOR...NEXT won't affect the results.

I must say I have a pathological hatred of benchmark programs! They can be misleading, especially if used inappropriately (I would say that, since benchmark results have been used to rubbish my BASICs in this thread). In any case I think an emphasis on speed above all else is often inappropriate; in modern implementations of BBC BASIC the speed of the interpreter is often largely irrelevant, because the bottlenecks which dominate execution time are in input/output routines such as graphics.

In my 'modern' BASICs I have added features which undoubtedly slow down execution significantly. For example the line-continuation character \ may be encountered whenever a space is legal, and testing for both space and \ is quite an overhead. Then there's the fact that all internal mathematical calculations use 64-bit integers or 80-bit floats, even when the numbers fit in 32-bits (so A% = B% + C% involves sign-extending both B% and C% to 64-bits, adding them together, then truncating the result to 32-bits again). Somebody obsessed with speed may claim that these features are therefore not beneficial, whereas I am certain they make the language more powerful and useful.
I am suffering from 'cognitive decline' and depression. If you have a comment about the style or tone of this message please report it to the moderators by clicking the exclamation mark icon, rather than complaining on the public forum.

dominicbeesley
Posts: 1227
Joined: Tue Apr 30, 2013 12:16 pm
Contact:

Re: Why was BBC BASIC so fast?

Post by dominicbeesley » Sun Nov 22, 2020 5:51 pm

That is probably all true when running on modern GHz plus hardware but on older processors porting basic speed vs size vs function compromises often need to be quickly tested and compared. A more specific set of benchmarks would help me. I did start something a while back but didn't get it to a releasable state. I'll dig it out soon as I'm going to be optimising for the 65816 soon hopefully.

As you say comparing apples and oranges is not always informative but checking an orange against a hopefully improved orange can be!

User avatar
Richard Russell
Posts: 1715
Joined: Sun Feb 27, 2011 10:35 am
Location: Downham Market, Norfolk
Contact:

Re: Why was BBC BASIC so fast?

Post by Richard Russell » Sun Nov 22, 2020 6:28 pm

dominicbeesley wrote:
Sun Nov 22, 2020 5:51 pm
A more specific set of benchmarks would help me.
I expect you're aware of timing.bbc supplied with all editions of BBC BASIC for SDL 2.0 but that's still heavily weighted towards timing mathematical operations rather than a more typical mix of statements. In fact I doubt that we would get much agreement over what is a typical mix of statements!

It wouldn't be so bad if timings of different aspects of an interpreter were genuinely independent, then one could for example optimise the speed of a FOR...NEXT loop without risking compromising the performance of some seemingly unrelated functionality. Indeed in the old 8-bit days that probably was true, since execution times could simply be determined by adding together the number of cycles needed for each instruction.

But that has long since ceased to be the case. Something which has caused me grief ever since I started writing BBC BASIC for Windows 20 years ago is the impact of code alignment. Although it varies from manufacturer to manufacturer and from CPU to CPU, simply moving a block of code up or down by one byte could have a major impact on execution speed. This is typically because code is fetched from the cache as a block of 16 or 32 bytes at a time, so if an entire loop was contained within one 'fetch unit' it can run significantly faster than if split between two such blocks (AMD having been a particular culprit as I recall).

I have tried to mitigate this by sprinkling 'align' directives throughout my assembly language code (and compilers try to do something similar) but it's unsatisfying to waste all those bytes if in a particular case it doesn't actually help on balance, and that's hard to determine. Then of course there's the potential for the overall code size increases caused by all those aligns to impact on cache performance, if it results in code being evicted that wouldn't otherwise need to be.

It's all a nightmare, and I'd rather not obsess about speed.
I am suffering from 'cognitive decline' and depression. If you have a comment about the style or tone of this message please report it to the moderators by clicking the exclamation mark icon, rather than complaining on the public forum.

jimmy
Posts: 113
Joined: Tue May 06, 2008 7:37 pm
Contact:

Re: Why was BBC BASIC so fast?

Post by jimmy » Tue Nov 24, 2020 9:10 am

Richard Russell wrote:
Sun Nov 22, 2020 5:04 pm
jimmy wrote:
Sun Nov 22, 2020 3:51 pm
can you let me know what you'd like it to say and I'll make the changes. I've got 64 bytes (2 rows of 32) due to space constraints (both screen and memory!).
Why can't you add a third row? Surely an extra 32 bytes isn't going to break anything. :?
Because I've got a fixed limit of 16384 bytes space is very tight! There's no problem with a long message in the CP/M version, but for the Spectrum I'm trying to squeeze as much as I can in 16K. The mini operating system (tape, keyboard, screen, beeper) takes 2K so far and even the character set has to take 0.75K. I haven't implemented the plot and line routines for graphics, nor have I implemented text windows - both are essential for Bat'n'Ball to run.

I'm only trying to make BBC BASIC (Z80) run faster for the technical challenge. I have no intention to sell it, and although I've stated this privately to you, I will repeat publicly - I'm not trying to 'rubbish' what you've done. I have great respect for the achievement of getting a BBC BASIC interpreter working. I was taken by surprise by your statement that I was breaking licensing requirements, as it was certainly not intended. I'm asking what you'd like to see (within the constraints) so I can address your concerns.

The additional challenge of getting it to run on a Spectrum in 16K is a big challenge, but it's one I'm attempting because it gets you thinking - what would've happened if this was released in 1983 to compete with the Electron? JGH's 32K Spectrum BBC BASIC ROM requires a 128K machine because he uses the original Spectrum operating system and must page in/out as required. Mine is a complete replacement, and won't be as feature rich - although an additional module loaded from tape could provide the missing features. The goal I have is to get it running Bat'n'Ball.
dominicbeesley wrote:
Sun Nov 22, 2020 4:48 pm
ClockSp is okay as it goes for comparing machines but doesn't really test what it says it is testing. I started thinking about a set of benchmarks for assisting me in porting to different processors but didn't really get anywhere with it. Get in touch if you're interested in working on something more suited to interpreter writers and we could maybe come up with something.
I think we should be able to re-use some of the old magazine benchmark programs. I'm sure both PCW and Byte published their code. The idea of subtracting the time taken to run an empty FOR/NEXT loop is one I'll look at - especially as I've seen how much this impacts the results.

Post Reply

Return to “8-bit acorn software: other”