REM By WHS, first version 28 november 2002.
REM This version 3 december 2002.
REM 
REM Find out what method a given swr board uses for writing to RAM
REM possibilities:
REM   - 0 none
REM
REM   - 1 single bank, (almost) always selected on write (ROM boards like
REM       watford, ATPL; For the Watford board, this only works when a ROM on
REM       the addon board is selected (cuts power consumption, Watford says),
REM       i.e. ROMSEL must be set to 4-15).
REM
REM   - 2 one or more banks where writing uses the same bank as reading (i.e.
REM       FE30=ROMSEL determines the bank that writes go to)
REM       Used on the solidisk 2MEG 128K board, and some home made boards.
REM       Possibly too for the Acorn User 16K SW RAM.
REM
REM   - 3 multiple banks where writing is separately selected, latch at FE32
REM       (BBC B+ compatible? or does that machine use ROMSEL?)
REM       Note that FE3x is equivalent to FE30 unless there's additional
REM       address decoding logic (as on solidisk 2MEG/4MEG boards, except the
REM       2MEG 128K).
REM
REM   - 4 multiple banks where writing is separately selected with the user
REM       port's output (solidisk), and only 3 bits are really decoded, so
REM       writing to bank 0-7 will in fact write to 8-15... A further
REM       complication is that reads from 0-2 will go to ROMs, 3-7 will go to
REM       RAM banks 11-15...
REM
REM   - 5 multiple banks where writing is separately selected with the user
REM       port's output (solidisk), and all 4 bits bits are properly decoded
REM       (does such a board exist?).
REM
REM   - 6 Watford ROM/RAM card (NOT YET TESTED)
REM
REM What a mess!
REM
REM XXX Should fix the program for use with a 2p
REM
REM version 0.7

  10 MODE 7
  20 DIM code 512
  30 DIM data 64
  40 swr_backup = data
  50 swr_test = data + &10

  60 swr_type = data + &20
  70 swr_banks = data + &21

  80 swr_byte_value1 = data  + &22
  90 swr_byte_value2 = data  + &23

 100 dummy = data  + &24
 110 tmp = data  + &25
 120 
 130 test_location = &8105
 140 
 150 FOR N%=0 TO 2 STEP 2
 160 P%=code
 170 [ OPT N%

 180 .swr_check
 190 SEI
 200 \ save original contents
 210 LDY #0
 220 .lp STY &FE30 \ set rom -> #Y
 230 LDA test_location:STA swr_backup,Y
 240 INY:CPY #16:BCC lp
 250 
 260 LDA #0: STA swr_banks
 270 LDA #255:STA swr_type
 280 
 290 \ now test which type:
 300 LDY #0:LDA #0
 310 .lp0 STA swr_test,Y:INY:CPY #16:BCC lp0
 320 
 330 LDA #&80: STA swr_byte_value1
 340 LDA #&E3: STA swr_byte_value2
 350 
 360 LDY #0
 370.bank_lp_y
 380   JSR set_all
 390   TYA:EOR swr_byte_value1:STA tmp:STA test_location
 400   LDX #15
 410.bank_lp_x
 420     LDA #0:STA dummy
 430     STX &FE30:LDA test_location:CMP tmp:BNE cmp_next_x
 440     \ equality could be accidental (ROM or RAM bank had tested value
 450     \ already), so try a 2nd value.
 460     \ First restore romsel for write
 470     JSR set_romsel
 480     TYA:EOR swr_byte_value2:STA tmp: STA test_location
 490     \ write 0 to a dummy location. Goal is to change the databus value.
 500     \ Otherwise, in a fully decoded bank system, locations that do not
 510     \ have ROM or RAM, will not change the value on the address bus,
 520     \ at least for several cycles, so the old one stays...
 530     \ On my main BBC, this works with at least 2 NOPs
 540     \     LDA #value STA test_location NOP NOP CMP test_location
 550     \ but here we need at least 3
 560     \     LDA #value STA test_location NOP NOP NOP LDA test_location CMP #value
 570     \ Better explicity change the value to something else, as this may
 580     \ vary between CPUs/systems? (e.g. depending on load on the bus).
 590     LDA #0:STA dummy

 600     STX &FE30:LDA test_location:CMP tmp:BNE cmp_next_x
 610     INC swr_banks:INC swr_test,X
 620     \ we don't know which method it is yet...
 630     JMP cmp_next_y
 640.cmp_next_x
 650     \ restore the corrupted byte in swr (from the 2nd write!)
 660     JSR set_romsel
 670     TYA:EOR swr_byte_value1:STA tmp: STA test_location
 680     DEX:BPL bank_lp_x

REM Debug 690 STY &70
REM Debug 700 BRK:BRK:EQUS"We should not arrive here!":BRK

 700.cmp_next_y
 710   INY:CPY #16:BCC bank_lp_y
 720 LDA swr_banks:BNE continue:STA swr_type \ no SWR found
 730 JMP end2

 740.found_type_1
 750 LDA #1:STA swr_type:STA swr_banks
 760 \ restore swr bank byte
 770 LDA swr_backup,Y:STA test_location
 780 JMP end2

 790.continue \ type 1-6
 800 LDY #16
 810.find_type_lp
 820 DEY: \BMI find_type_end \ no need, we only get here if there is RAM.
 830 LDA swr_test,Y:BEQ find_type_lp
 840 CMP #8:BCS found_type_1 \XXX CHANGE THIS
 850 JSR set_only_solidisk
 860 \ N.B. STY &FE30 should take care of the databus problem, as long as the
 870 \ value written to RAM is not in the set {0,...,15}.
 880 TYA:EOR swr_byte_value1:EOR #&22: STA test_location:STY &FE30:CMP test_location:BEQ found_soli
 890 JSR set_only_ramsel
 900 TYA:EOR swr_byte_value2:EOR #&23: STA test_location:STY &FE30:CMP test_location:BEQ found_ram_sel
 910 JSR set_only_romsel
 920 TYA:EOR swr_byte_value2:EOR #&34: STA test_location:STY &FE30:CMP test_location:BEQ found_rom_sel
 930 \ which leaves the watford rom/ram method

 940.found_watford_romram
 950 LDA #6:STA swr_type
 960 JMP end

 970.found_rom_sel
 980 LDA #2:STA swr_type
 990 JMP end

1000.found_ram_sel
1010 LDA #3:STA swr_type
1020 JMP end

1030.found_soli LDA #4:STA swr_type
1040 LDA swr_test,Y:CMP #1:BNE soli_3bits
1050 INC swr_type
1060 JMP end
1070.soli_3bits
1080 \ remove factor 2 from solidisk's incomplete address decoding
1090 LSR swr_banks
1100 JMP end

1110.end
1120 \ restore swr, using method found
1130 LDY #0
1140 \ note that we must write in low to high order for swr_type=4, or only

1150 \   copy for Y=8-15 in that case.
1160 .restore_lp
1170 JSR set_all
1180 LDA swr_backup,Y:STA test_location
1190 INY:CPY #16:BCC restore_lp
1200.end2
1210 LDA &F4:STA &FE30:CLI
1220 RTS

1230 \ Utilities

1240.set_only_solidisk
1250 JSR set_all_to_wrong_bank
1260.set_solidisk \ for old solidisk swr
1270 LDX #&0F:STX &FE62 \ user port -> output
1280 STY &FE60 \ user port output = A
1290 RTS

1300.set_only_romsel
1310 JSR set_all_to_wrong_bank
1320.set_romsel
1330 STY &FE30:RTS

1340 \ RAMSEL may not exist, in which case it is equivalent to ROMSEL
1350 \ (incomplete address decoding), therefore this code:
1360.set_only_ramsel
1370 JSR set_all_to_wrong_bank
1380 JSR set_ramsel
1390 \ now set ROMSEL to the wrong bank, if ROMSEL = RAMSEL, RAMSEL will be deselected too.
1400 TYA:EOR #1:TAY:JSR set_romsel:TYA:EOR #1:TAY
1410 RTS
1420.set_ramsel
1430 STY &FE32:RTS

1440.set_only_watford_romram
1450 JSR set_all_to_wrong_bank
1460.set_watford_romram
1470 STA &FF30,Y:RTS \ write latch set by writing anything to location (FF30+n)

1480.set_all
1490 JSR set_solidisk:JSR set_romsel:JSR set_ramsel:JMP set_watford_romram

1500.set_all_to_wrong_bank
1510 TYA:EOR #1:TAY \ this is fine with solidisks incomplete address decoding (bit 3 not used)
1520 JSR set_all
1530 TYA:EOR #1:TAY
1540 RTS

1550 ]
1560 NEXT
1570 IF P%-code > 512 PRINT"Too much code":END

1580 CALL swr_check
1590 PRINT
1600 IF ?swr_banks = 0 PRINT "No sideway RAM found (if there is RAM, it's write protected or uses an unknown write select method)":END

1610 IF ?swr_banks = 1 PRINT "1 RAM bank";
1620 IF ?swr_banks > 1 PRINT "";?swr_banks;" RAM banks";

1630 IF ?swr_type = 1 AND ?swr_banks < 16 PRINT ", almost always selected for writing"
1640 IF ?swr_type = 1 AND ?swr_banks = 16 PRINT ", always selected for writing"

1650 IF ?swr_type > 1 PRINT ", write bank is selected with ";
1660 IF ?swr_type = 2 PRINT "FE30 (ROMSEL)"
1670 IF ?swr_type = 3 PRINT "FE32 (RAMSEL)"
1680 IF ?swr_type = 4 PRINT "FE62/FE60 (Solidisk, user port), only 3 bits decoded (0=8)"
1690 IF ?swr_type = 5 PRINT "FE62/FE60 (Solidisk, user port), all 4 bits properly decoded"
1700 IF ?swr_type = 6 PRINT " a write to {FF30+bank_no} (Watford ROM/RAM board)"
1710 
1720 FOR R%=0 TO 15
1730  U%=?(swr_test+R%)
1740  IF U%>0 PRINT"RAM: ";R%;" used ";U%;" time";
1750  IF U%>1 PRINT ;"s" ELSE IF U%=1 PRINT
1760 NEXT
1770 END

