Friday, November 11, 2022

Tandy CoCo ROM to RAM BASIC program, and disassembly

Here is the Tandy CoCo "ROM to RAM" program that was published back in the 1980s.
It copies the contents of the ROMs to the bank of RAM that can replace it.
Executing the address it's POKEd to will start running BASIC out of RAM.
I hand disassembled it, and commented the disassembly by looking up the opcodes in a book.  I tried using the debugger in VCC, but it doesn't have a disassembler, and my internet was down so I couldn't download something else.

The BASIC and disassembly are included below.  The BASIC program should should still work if you leave out lines 50, 60, and 70, but it will run a little slower.

BASIC:

REM MOVE ROM TO RAM ON A COCO 1 & 2
10 READ A$:IF A$="X" THEN END
20 POKE 20000+N,VAL("&H"+A$)
30 N=N+1:GOTO 10
40 DATA 34,01,1A,50,10,8E,80,00

REM LOOP TO COPY 6 BYTES AT A TIME. FASTER BUT NOT REQUIRED TO WORK
50 DATA B7,FF,DE,EC,A4,AE,22,EE
60 DATA 24,B7,FF,DF,ED,A1,AF,A1
70 DATA EF,A1,10,8C,F3,FC,25,E8

REM LOOP TO COPY 2 BYTES AT A TIME.
80 DATA 10,8C,FF,00,24,0C,B7,FF
90 DATA DE,EC,A4,B7,FF,DF,ED,A1
100 DATA 20,EE,35,01,39
110 DATA X


Assembly:

;*************************************************
;* Tandy CoCo 1 & 2 ROM to RAM
;* copies the contents of ROM to RAM and continues running it from there
;*************************************************

; start at location 20000 (code is position independant though)
            org        $4E20

; start    of code
34,01        pshs    $01            ; save cc register
1A,50        orcc    $50            ; disable interrupts

10,8E,80,00    ldy        $8000        ; point to ROM start address

loop1:                            ; copy 6 bytes at a time
B7,FF,DE    sta        $FFDE        ; set ROM mode
EC,A4        ldd        ,y            ; read 6 bytes of ROM data
AE,22        ldx        2,y
EE,24        ldu        4,y
B7,FF,DF    sta        #$FFDF        ; set RAM mode
ED,A1        std        ,y++        ; write 6 bytes and update mem pointer
AF,A1        stx        ,y++
EF,A1        stu        ,y++
10,8C,F3,FC    cmpy    $F3FC        ; are we done with 6 byte copy?
25,E8        blo        loop1        ; go again if not

loop2:                            ; copy 2 bytes at a time
10,8C,FF,00    cmpy    $FF00        ; are we done with 2 byte copy?
24,0C        bhs        exit        ; branch if yes
B7,FF,DE    sta        $FFDE        ; set ROM mode   
EC,A4        ldd        ,y            ; read 2 bytes
B7,FF,DF    sta        $FFDF        ; set RAM mode
ED,A1        std        ,y++        ; write 2 bytes and update mem pointer
20,EE        bra        loop2        ; loop

exit:
35,01        puls    $01            ; restore cc register
39            rts
 

Saturday, November 5, 2022

BASIC ASCII Mandelbrot Benchmark

This is a CoCo 3 version of the ASCII Mandelbrot Benchmark posted here:
https://github.com/scruss/bench64

This just adds the math patch, 6309 control, and CoCo timing code.
Runs in 12.43 minutes.  Takes over 23 minutes on a C64 according to the comment on that site.


 
0 TIMER=0:POKE 65497,0:WIDTH80

REM GET BASIC TOPRAM POINTER, SUBTRACT SIZE OF USER CODE
1 AD=PEEK(116)*256+PEEK(117)-24

REM RESERVE MEMORY FOR USR CODE
2 CLEAR 100,AD

REM VARIABLES ERASED BY CLEAR, SO REDO AD, POKE USR CODE INTO RAM
3 AD=PEEK(116)*256+PEEK(117):FOR I=0 TO 23:READ B$:A=VAL("&H"+B$):POKE AD+I,A:NEXT

REM DEFINE USR ROUTINES
4 DEFUSR0=AD:DEFUSR1=AD+12

REM ENABLE 6309 NATIVE MODE
5 A=USR0(0)

REM INSTALL HARDWARE MULTIPLY PATCH
6 GOSUB 10000



  100 REM A BASIC, ASCII MANDELBROT
  110 REM
  120 REM This implementation copyright (c) 2019, Gordon Henderson
  130 REM
  140 REM Permission to use/abuse anywhere for any purpose granted, but
  150 REM it comes with no warranty whatsoever. Good luck!
  160 REM
  170 C$ = ".,'~=+:;[/<&?oxOX# " : REM 'Pallet' Lightest to darkest...
  180 SO = 1 : REM Set to 0 if your MID$() indexes from 0.
  190 MI = LEN(C$)
  200 MX = 4
  210 LS = -2.0
  220 TP = 1.25
  230 XS = 2.5
  240 YS = -2.5
  250 W = 64
  260 H = 48
  270 SX = XS / W
  280 SY = YS / H
  290 Q = TIME
  300 FOR Y = 0 TO H
  310   CY = Y * SY + TP
  320   FOR X = 0 TO W
  330     CX = X * SX + LS
  340     ZX = 0
  350     ZY = 0
  360     CC = SO
  370     X2 = ZX * ZX
  380     Y2 = ZY * ZY
  390     IF CC > MI THEN GOTO 460
  400     IF (X2 + Y2) > MX THEN GOTO 460
  410     T = X2 - Y2 + CX
  420     ZY = 2 * ZX * ZY + CY
  430     ZX = T
  440     CC = CC + 1
  450     GOTO 370
  460     PRINT MID$(C$, CC - SO, 1);
  470   NEXT
  480   PRINT
  490 NEXT
  500 PRINT

510 PRINT "TIMER=";TIMER/60

REM DISABLE 6309 NATIVE MODE
530 A=USR1(0)
540 END


REM USR functions to enable/disable 6309 native mode
9000 DATA CC,FF,FF,10,4F,5D,26,03,11,3D,01,39,CC,FF,FF,10,4F,5D,26,03,11,3D,00,39

REM COCO3 HARDWARE MULTIPLY PATCH.
REM JUST ADD A GOSUB 10000 AT THE TOP OF YOUR CODE TO ADD IT

REM ADDRESS WE ARE STORING THE MULTIPLY PATCH IN RAM
10000 AD=VAL("&HFA0C")

REM POKE THE MULTIPLY PATCH INTO RAM.
10001 FORI=0 TO 64:READ B$:A=VAL("&H"+B$):POKE AD+I,A:NEXT

REM MAKE BASIC JUMP TO OUR MULTIPY INSTEAD OF USING IT'S CODE. $BB00 JMP $FA0C
10002 POKE VAL("&HBB02"),VAL("&H7E"):POKE VAL("&HBB03"),VAL("&HFA"):POKE VAL("&HBB04"),VAL("&H0C")

10003 RETURN

10005 DATA 32,79,E7,60,96,60,3D,ED,63,E6,60,96,5E,3D,ED,61,E6,60,96,5D
10006 DATA 3D,ED,65,E6,60,96,5F,3D,E3,62,ED,62,EC,65,E9,61,89,00,ED,60
10007 DATA EC,63,D3,15,97,16,D7,63,EC,61,D9,14,99,13,DD,14,A6,60,89,00
10008 DATA 97,13,32,67,39

Friday, November 4, 2022

Ahl's Benchmark Revisited

 Ahl's Benchmark is a short BASIC program written by David H. Ahl, and published in Creative Computing.  It was used to compare the speed of different machines back in the 1980s, and results were published for a lot of machines.  The benchmark, and results for many machines can be found in the March 1984 issue.

With the addition of the hardware multiply patch, and 6309 native mode, the CoCo 3 emulator turns on a time of just under 28.6 seconds, and that includes the time to POKE the code into RAM.
 
The IBM PC turned in a time of 24 seconds, and the Amiga 22 (or 14?) seconds.
I timed the 4 MHz Apple IIc Plus at around 31 seconds.
Considering the difference in clock speeds, these results are pretty respectable.




0 TIMER=0:POKE 65497,0

REM GET BASIC TOPRAM POINTER, SUBTRACT SIZE OF USER CODE
1 AD=PEEK(116)*256+PEEK(117)-24

REM RESERVE MEMORY FOR USR CODE
2 CLEAR 100,AD

REM VARIABLES ERASED BY CLEAR, SO REDO AD, POKE USR CODE INTO RAM
3 AD=PEEK(116)*256+PEEK(117):FOR I=0 TO 23:READ B$:A=VAL("&H"+B$):POKE AD+I,A:NEXT

REM DEFINE USR ROUTINES
4 DEFUSR0=AD:DEFUSR1=AD+12

REM ENABLE 6309 NATIVE MODE
5 A=USR0(0)

REM INSTALL HARDWARE MULTIPLY PATCH
6 GOSUB 10000


10 REM Ahl_s simple benchmark
20 FOR N = 1 TO 100: A = N
30 FOR I = 1 TO 10
40 A = SQR(A): R = R + RND(1)
50 NEXT I
60 FOR I = 1 TO 10
70 A = A^2: R = R + RND(1)
80 NEXT I
90 S = S + A: NEXT N
100 PRINT "Accuracy ";ABS (1010-S/5)
110 PRINT "Random ";ABS (1000-R)
120 PRINT "TIMER=";TIMER/60

REM DISABLE 6309 NATIVE MODE
130 A=USR1(0)
140 END


REM USR functions to enable/disable 6309 native mode
9000 DATA CC,FF,FF,10,4F,5D,26,03,11,3D,01,39,CC,FF,FF,10,4F,5D,26,03,11,3D,00,39

REM COCO3 HARDWARE MULTIPLY PATCH.
REM JUST ADD A GOSUB 10000 AT THE TOP OF YOUR CODE TO ADD IT

REM ADDRESS WE ARE STORING THE MULTIPLY PATCH IN RAM
10000 AD=VAL("&HFA0C")

REM POKE THE MULTIPLY PATCH INTO RAM.
10001 FORI=0 TO 64:READ B$:A=VAL("&H"+B$):POKE AD+I,A:NEXT

REM MAKE BASIC JUMP TO OUR MULTIPY INSTEAD OF USING IT'S CODE. $BB00 JMP $FA0C
10002 POKE VAL("&HBB02"),VAL("&H7E"):POKE VAL("&HBB03"),VAL("&HFA"):POKE VAL("&HBB04"),VAL("&H0C")

10003 RETURN

10005 DATA 32,79,E7,60,96,60,3D,ED,63,E6,60,96,5E,3D,ED,61,E6,60,96,5D
10006 DATA 3D,ED,65,E6,60,96,5F,3D,E3,62,ED,62,EC,65,E9,61,89,00,ED,60
10007 DATA EC,63,D3,15,97,16,D7,63,EC,61,D9,14,99,13,DD,14,A6,60,89,00
10008 DATA 97,13,32,67,39