This is a follow up on the last post Alphatronic P2 memory mapping.

New strategy

Switching the memory while the BASIC interpreter is running obviously didn’t work. So the new strategy is as following: First put the “read_index_duration” program into upper memory. Then create a small program to copy this program from upper memory into lower memory. This includes the memory switch and the switch back. Then provide a caller program that switches the memory bank, calls the program in lower memory, switches the memory back and returns to BASIC.

read_index_duration

This is the same program. I repeat it here so that we can see, which registers it needs. It communicates the result back to BASIC via the memory location provided by the H/L register pair. This register pair points to the location, where the 16-bit BASIC variable is stored.

                                       ORG     1800H
                                       PUBLIC  READ_INDEX_DURATION
1800'  3E D4      READ_INDEX_DURATION: MVI     A,D4H    ;FORCE-INTERRUPT command with IP (index pulse)
1802'  D3 50                           OUT     50H      ;execute command
1804'  06 40                           MVI     B,40H    ;Mask for index detected flag in status register
1806'  11 0000                         LXI     D,0      ;init counter in D
1809'  DB 50                           IN      50H      ;reading the command register?? apparently clearing the IRQ flag
180B'  DB 54                   LOOP1:  IN      54H      ;reading status register into A
180D'  A0                              ANA     B        ;check if index is set
180E'  CA 0B18'                        JZ      LOOP1    ;if no index yet, busy wait...
1811'  DB 50                           IN      50H      ;clearing the INDEX flag for next index detection
1813'  13                      LOOP2:  INX     D        ;counting now...
1814'  DB 54                           IN      54H      ;reading status register into A
1816'  A0                              ANA     B        ;check if index is set
1817'  CA 1318'                        JZ      LOOP2    ;jump back, if no index and keep counting
181A'  73                              MOV     M,E      ;copy counter (low Byte) to memory at [H]
181B'  23                              INX     H        ;
181C'  72                              MOV     M,D      ;copy counter (high Byte) to memory at [H]
181D'  C9                              RET

So, it is supposed to run from 0x1800. It is 0x1E bytes long, so we need to copy this from e.g. 0xFF30 to 0x1800 later on. It ends with RET, so should return to the address that is stored in the stack.

Copy from upper to lower

That’s a simple program. It mostly the adapted example from the Instruction set manual for DCR:

The DCR instruction is frequently used to control multi-byte operations such as moving a number of characters from one area of memory to another.

This is almost what we need. I adjusted it a bit, using INX to copy from begin to end instead of the reverse. And added the memory switch.

                             ORG FF00H
FF00'  3E 60                 MVI A, 60H
FF02'  D3 78                 OUT 78H        ; switch memory
FF04'  06 1E                 MVI B, 1EH     ; number of bytes to copy
FF06'  21 30 FF              LXI H, FF30H   ; load source address into H&L
FF09'  11 00 18              LXI D, 1800H   ; load destination address into D&E
FF0C'  7E              LOOP: MOV A,M        ; load byte to copy
FF0D'  12                    STAX D         ; store byte
FF0E'  13                    INX D          ; increment destination address
FF0F'  23                    INX H          ; increment source address
FF10'  05                    DCR B          ; decrement counter
FF11'  C2 0C FF              JNZ LOOP       ; repeat loop until counter=0
FF14'  3E 20                 MVI A, 20H
FF16'  D3 78                 OUT 78H        ; switch memory back
FF18'  C9                    RET

Call read_index_duration in lower memory

The only task of this program is to call the read_index_duration program, which is stored in lower memory. So the memory switch needs to be done. It uses CALL so that we return into this program and can switch the memory back, before we return to BASIC.

                              ORG FF20H
FF20'  3E 60                  MVI A, 60H
FF22'  D3 78                  OUT 78H    ; switch memory
FF24'  CD 00 18               CALL 1800H ; call read_index_duration
FF27'  3E 20                  MVI A, 20H
FF29'  D3 78                  OUT 78H    ; switch memory back
FF2B'  C9                     RET

We are not dealing with H&L, so we don’t need to safe the register in the stack. The H&L register is set by BASIC to the memory location of the LOOPS% variable. And we write the resulting counter into that memory location.

The complete BASIC program

This combines all the previously described programs and provides the glue code.

100 '************** DRIVEROT6
110 CLEAR , &HFF00
120 DEFINT D
130 GOSUB 500 ' install copy_to_low into FF00H: COPY
140 GOSUB 600 ' install call read_index_duration into FF20H: RID
150 GOSUB 700 ' install read_index_duration into FF30H
160 CALL COPY ' copy read_index_duration into 1800H
170 PRINT"In the last used drive a floppy has to be inserted!"
180 INPUT"How many measurements should be taken"; COUNT
190 DIM DAT%(COUNT)
200 FOR D=0 TO COUNT-1
210     PRINT"  Start measurement ";D
220     CALL RID(LOOPS%)
230     DAT%(D)=LOOPS%
240     PRINT"    result:";D;"->";DAT%(D)
250 NEXT
260 PRINT"Data ready"
270 MIN=DAT(0) :MAX=MIN :SUM=0
280 FOR D=0 TO COUNT-1
290     IF DAT(D)<MIN THEN MIN=DAT(D)
300     IF DAT(D)>MAX THEN MAX=DAT(D)
310     SUM=SUM+DAT(D)
320 NEXT
330 MEAN=SUM/COUNT
340 LPS=103448! 'loops per second: 3 MHz/29 cycles - dur. of one loop
350 RPM=INT(60*LPS/MEAN+.5)
360 DIF=MAX-MIN
370 PRINT"  Minimum:";MIN/LPS;"s"
380 PRINT"  Maximum:";MAX/LPS;"s"
390 PRINT"     Mean:";MEAN/LPS;"s"
400 PRINT"Rotations:";RPM;"rpm"
410 PRINT" Accuracy:";DIF*1000/LPS;"ms"
420 END
450 ' install loop
460     READ D$
470     D=VAL("&H"+D$)
480     IF D>255 THEN RETURN
490     POKE I,D : I=I+1
495 GOTO 450
500 ' install copy_to_low into FF00H: COPY
510 COPY=&HFF00
520 I=&HFF00
530 GOTO 450
540 DATA 3E,60,D3,78,06,1E,21,30,FF,11,00,18,7E,12,13,23
550 DATA 05,C2,0C,FF,3E,20,D3,78,C9,E0F
600 ' install call read_index_duration into FF20H: RID
610 RID=&HFF20
620 I=&HFF20
630 GOTO 450
640 DATA 3E,60,D3,78,CD,00,18,3E,20,D3,78,C9,E0F
700 ' install read_index_duration into FF30H
710 I=&HFF30
720 GOTO 450
730 DATA 3E,D4,D3,50,06,40,11,00,00,DB,50,DB,54
740 DATA A0,CA,0B,18,DB,50,13,DB,54,A0,CA,13,18
750 DATA 73,23,72,C9,E0F

The result

Now that we switch back the memory before returning to BASIC, it works. That means, you can’t access directly the lower memory from BASIC.

Here you can see the output of the program:

Ok
RUN
In the last used drive a floppy has to be inserted!
How many measurements should be taken? 10
  Start measurement  0 
    result: 0 -> 16218 
  Start measurement  1 
    result: 1 -> 16218 
  Start measurement  2 
    result: 2 -> 16217 
  Start measurement  3 
    result: 3 -> 16217 
  Start measurement  4 
    result: 4 -> 16218 
  Start measurement  5 
    result: 5 -> 16218 
  Start measurement  6 
    result: 6 -> 16217 
  Start measurement  7 
    result: 7 -> 16218 
  Start measurement  8 
    result: 8 -> 16218 
  Start measurement  9 
    result: 9 -> 16218 
Data ready
  Minimum: .156765 s
  Maximum: .156774 s
     Mean: .156772 s
Rotations: 383 rpm
 Accuracy: 9.66669E-03 ms
Ok

So - as expected - it is slow memory like the other upper memory. The only fast memory is the static RAM that is placed directly on the CPU board.

This means, that the memory switch indeed worked. Otherwise, it would have been run on the static RAM and the results would be different.

Note: My Alphatronic P2 has obviously 64k of memory. When upgrading a P2 with 48k to 64k, there seems to be a adapter required. See Alphatronic_P2_memory_option.jpg and AlphatronicP2_RAM_switch_modus.jpg. But my Alphatronic doesn’t have such an adapter. The 48k memory card is plugged directly into the backplane. I assume, that the adapter is only needed when upgrading an existing P2 without replacing the already bought 48k card. And my model is a P2 with directly 64k, which presumably uses a different 48k memory card.