I love this forum. A little discussion here about the Model II from you guys spurs me to get off my butt and play with my gear!
...
LS-DOS 6.1.3 shows five 32K banks available. I would expect a few more given the machine has 256K. @lowen, any thoughts?
Nice! Always glad to help people get more interested....
Alright, let's first get a couple of pieces of terminology consistent: in the Model II hardware architecture, a 'page' is 32K and a 'bank' is 64K. The lower four bits of port 0FFH select the page number for all pages except page 0, which is always resident at addresses 0000H - 7FFFH (pages 1 through 15 are switched into addresses 8000H - 0FFFFH, in other words). The 32K/64K memory boards have jumpers for both banks and pages. The LS-DOS 6 term 'bank' is actually the Model II 'page' instead. A bit confusing at first.
I would expect LS-DOS to see seven 'banks' with 256K (the eighth 'page,' 'page' 0, is not counted as an LS-DOS 'bank' since it's always resident). (EDIT: Verified with MAME with -ramsize 256k; memory lists banks available as 07, banks 0 through 6. The Model II 'page' 0 does not count as a 'bank' for LS-DOS). The Model II's architecture is actually a good fit for LS-DOS 6.
Ok, so this post is going to be long, but this needs to be documented in one place, and right now it's scattered all over the place in the LS-DOS sources. Frank was supposed to send me the 6.3.0 Model II code, but never did. My gut feel is that 6.3.0's code was never updated for Model II, and thus there was no 6.3.0 for Model II for Frank to have or to send. Roy did the 6.3.1 for Model II, and that code is probably long gone; I don't know who got Roy's Misosys archives, but I think Bill D. might have gotten some of what Kim Watt had. I was going to attach a ZIP file of the LS-DOS 6.2 sources that I have here that included the BETA version of the Model II (and Model 4, for that matter) code, but the forum's limit is way too small for the zip I have, so here's a
link to download.
Looking through the sources, it appears that the code simply walks the banks (LS-DOS term; Model II 'pages') starting at 1 and goes up until the bank doesn't respond as a full 32K bank. Do you have any 16K cards in the system? (ARCnet, hard disk interface are two possibilities)? I would suspect a 16K card or a hole at page 6 (the first page on the fourth board). EDIT: Yeah, I know that's confusing a bit, but Model II page 5 corresponds to LS-DOS 'bank' 4, and that's the last recognized LS-DOS bank. I had to triple check that myself as it was a bit counter-intuitive, and I kept wanting it to be page 7 and not 6.....
Below are extracts from the LS-DOS 6.2.0 BETA sources to document this. Aaron Brockbank also has all of this information and has probably documented what's actually in 6.3.1 better than this 6.2.0ac BETA code.
First, the bank detection code (in SYSINIT2/ASM):
Code:
;
; determine number of memory banks available
;
LD BC,8<8+0 ;B=bank, C=bit mask
DETMEM CALL TBANK ;test bank D
RL C ;move bit into C
DJNZ DETMEM ;contine for 8 banks
And the routine TBANK (also in SYSINIT2/ASM):
Code:
;
; sel mem bank at B and return Cy if not avail
;
TBANK LD A,(MODOUT$) ;get flag
AND 0F0H ;drop low 4 bits
OR B ;combine with bank
CALL SET_MOD ;update mask/port
LD HL,8000H ;start of bank memory
CALL TMEM ;test memory here
SCF ;carry = not avail
RET NZ ;go if no memory
LD H,0C0H ;next 16k
CALL TMEM ;test memory
SCF ;carry = not avail
RET NZ ;go if no memory
OR A ;else clear carry
RET ;done
;
TMEM LD A,(HL) ;read data
CPL ;reverse bits
LD (HL),A ;load data
CP (HL) ;still there?
CPL ;reverse back
LD (HL),A ;restore data
RET ;Z=yes, NZ=no memory
;
MODOUT$ and the SET_MOD routine do the actual output to port 0FFH (the code has to keep a mirror of this port value, since you cannot read the currently selected page from the hardware, since it is a 'distributed' write-only port). First, MODOUT$ (from SYSRES2/ASM):
Code:
;*=*=*
; MODOUT$ mask assignments:
;
; 0-4 = bank number
; 5 = video blank
; 6 = RTC enable
; 7 = video enable
;*=*=*
IF @INTL
MODOUT$ DB 21H ;MODOUT international
ELSE
MODOUT$ DB 21H ;MODOUT port image (FAST)
ENDIF
;
Note how this is not correct: only data bits 0-3 are 'page' selects (15 pages available; page 0 isn't switchable), as bit 4 is documented as being the 80/40 character mode switch.
and now SET_MOD (from CLOCKS2/ASM)
Code:
SET_MOD LD (MODOUT$),A ;update image
OUT ($BSEL),A ;re-set
RET ;done
$BSEL is (from BOOT2/ASM):
Code:
$BSEL EQU 0FFH ;bank/video select port
Ok, the operating @BANK SVC code (from CLOCKS2/ASM):
Code:
@BANK
PUSH HL ;save HL
LD A,B ;get command
LD HL,BANKTBL ;lookup table
CALL @LOOKUP ;search entry
EX (SP),HL ;get HL, leave vector
RET Z ;go vector if found
POP AF ;remove vector
JP PERR ;go param error!
;
BANKTBL DB 0 ;select bank
DW BANK0
DB 1 ;unmark bank
DW BANK1
DB 2 ;test bank
DW BANK2
DB 3 ;mark bank
DW BANK3
DB 4 ;select bank
DW BANK4
DB -1 ;terminator
;
BANK4 LD A,(LBANK$) ;P/u current bank
CP A
RET
;
; set bank in use
;
BANK3 CALL BANK2 ;valid and available?
RET NZ ;nope, go!
JR BMARK ;mark and return
;
; reset bank
;
BANK1 CALL VALBANK ;valid bank#?
RET NZ ;nope, go!
JR UMARK ;unmark and return
;
; test bank in use
;
BANK2 CALL VALBANK ;valid bank#?
RET NZ ;nope, go!
JR MTEST ;test bank marked
;
; select bank
;
BANK0 PUSH HL ;Ck if stack is in upper
LD HL,8005H ; bank area
ADD HL,SP
POP HL
JP C,PERR ;Error if > X'7FFE'
CALL VALBANK ;valid bank?
RET NZ ;go if not
LD A,(MODOUT$) ;P/u current memory
AND 0F0H ;remove bank address
LD B,A ;save temp
LD A,C ;get bank # needed
AND 7FH ;remove jump bit
INC A ;bump to correct bank
OR B ;combine
CALL SET_MOD ;set new memory image
LD A,(LBANK$) ;Get old bank #
LD B,A ; & save it
LD A,C ;P/u new bank #
AND 7FH ;Strip any bit-7
LD (LBANK$),A ; & save new bank #
XOR C ;keep bit 7
OR B ;merge in new bank
LD C,A ;replace for return
BIT 7,C ;Transfer to new bank?
LD B,0 ;Init for invoke later
RET Z ;No if bit-7 = 0
EX (SP),HL ;Exchange RET with new
CP A ; transfer & go to it
RET
;
VALBANK LD A,C ;get bank #
AND 7FH ;remove jump bit
CP 8 ;0-7?
JR C,ATEST ;yes, check if exists
INVBANK JP PERR ;param error
;
; test if bank exists
;
ATEST PUSH HL ;save
LD HL,BAR$ ;bank avail ram
JR AMTEST ;continue
;
; test if bank is marked
;
MTEST PUSH HL ;save
LD HL,BUR$ ;bank used ram
;
AMTEST PUSH BC ;save
CALL BSETUP ;setup for test
LD A,(HL) ;get data
AND C ;marked?
POP BC ;restore
POP HL
JR NZ,INVBANK ;go if not
RET ;else return Z
;
; set bank # as marked
;
BMARK CALL BUSET ;setup
OR C ;mark bank
JR MUCOMM ;continue
;
; unmark bank #
;
UMARK CALL BUSET ;setup
AND B ;unmark!
;
MUCOMM LD (HL),A ;update data
POP BC ;restore
POP HL
XOR A ;set NO error
RET ;done
;
; setup for bank activity
;
BUSET POP AF ;get caller
PUSH HL ;save registers
PUSH BC
PUSH AF ;return back
LD HL,BUR$ ;bank used ram
CALL BSETUP ;setup
LD A,(HL) ;get data
RET ;return with data
;
; setup for bank activity
;
BSETUP RES 7,C ;force in range
INC C ;init for test
LD B,1 ;init bit 0
BSETUP1 DEC C ;found?
JR Z,BSETUP2 ;go if yes
SLA B ;shift test bit
JR BSETUP1 ;continue
BSETUP2 LD A,B ;get test bit
LD C,A ;C=set bit
CPL ;reverse bits
LD B,A ;B=reset bits
RET ;done