- New strategy
- Copy from upper to lower
- Call read_index_duration in lower memory
- The complete BASIC program
- The result
This is a follow up on the last post Alphatronic P2 memory mapping.
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.
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
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.