         page
; File: P.PROM.SP.TEXT
; Date: 26-Oct-83

BusErrV  equ    $8              ;addr of bus error exception vector

MMUexcp  equ    $280001         ;MMU exception register on board 0
MMUcntxt equ    $280201         ;MMU context register on board 0

SegRegLo equ    $280601         ;first seg register
SegRegHi equ    $3ffe01         ;last seg register
SegRegIn equ    $008000         ;seg register address increment
SegCntIn equ    $000800         ;seg reg inc between contexts
SegStart equ    $80             ;start value of seg register 16
SegPEnd  equ    $8F             ;end value for seg register 31

PagRegLo equ    $200401         ;first page register
PagRegHi equ    $3ffc01         ;last page register
PagRegIn equ    $000800         ;page register address increment

NumCntxt equ    02              ;number of contexts

; setup bus error interrupt vector in static RAM
;
        lea     SPbusEr,a1      ;get bus error processing address
        move.l  a1, BusErrV.W   ;set bus error interrupt vector
SPbusRS move.b  #$0,MMUexcp.l   ;zero exception register to prevent
                                ;   parity error causing Bus Errors
        move.b  #1,CPextcrt.w   ;use external CRT for messages

    page
; Setup MMU so that logical addresses $80000 to $FFFFF access
; physical addresses $00000 to $7FFFF.  The Concept address space
; is mapped into the physical memory address space.
;
; The Concept memory map is selected on the processor board when the
; ALTMAP bit is 0.  Unfortunately, only 48 of the segment registers
; are accessible.  This is because the start of the segment registers is
; is at $280601 instead of $200601 but still must stop at $3FFE01.
;
; The MMU maintains 16 different contexts each with 64 segment registers
; representing the full logical address space (0 ... $1FFFFF).  Context 0
; is used by the Omninet Transporter for DMA in to/out of host memory.
; Context 1 is used when the processor is in supervisor (or privileged)
; state.  Contexts 2 to 15 are user contexts selectable via the context
; register and are active when the processor is in the user state.  Since
; CCOS runs only in supervisor state contexts 0 and 1 are only necessary
; to initialize.  For use by CCOS ALL the contexts are initialized to the
; same memory map.
;
; Setup the segment registers 16 to 31, inclusive.  These seg regs
; correspond to the logical addresses $80000 to $FFFFF.   We will
; use to first 16 page segments to refer to the physical memory.
; Therefore, put the page segment adresses 0 to 15, inclusive, into
; the segment registers 16 to 31, inclusive. (see ahead for page registers).
;
; Have BUG: try setting all 48 seg regs to 0 to F cyclically.
;
; Segment register form :
;
;   Bits 0 through 5 :  page segment number for this segment.
;   Bits 6 through 7 :  protection bits
;         00 :  no access
;         01 :  read only access
;         10 :  full access, read/write/execute  <== use this for CCOS
;         11 :  execute only access
;
        lea     SegRegLo+(00*SegRegIn).L,a0 ;get first seg register address
        movea.l a0, a1          ;save start address
        clr.l   d3              ;context increment (loop counter)
        move.w  #SegStart,d1    ;read/write in bits 6-7 and page segment 0
        move.l  #SegRegIn,d2    ;get address increment
        moveq   #NumCntxt-1,d4  ;number of contexts(loop counter)
        moveq   #47, d5         ;do all 48 seg regs

; for i := 0 to NumCntxt-1 do
;   repeat  set seg regs 00 to 47 for this context
;
SPseg01 move.b  d1, (a0)        ;set segment register
        adda.l  d2, a0          ;update seg register address
        addq.w  #1, d1          ;bump page segment number
        cmpi.w  #SegPEnd, d1    ;at end of seg registers?
        bls.s   SPseg1a         ;no, write next seg reg
        move.w  #SegStart,d1    ;reset page selector every 16 seg regs
SPseg1a dbra    d5,SPseg01      ;do for each 48 regs
        add.l   #SegCntIn, d3   ;do next context
        lea     0(a1,d3), a0    ;get start of seg regs for this context
        move.w  #SegStart,d1    ;read/write in bits 6-7 and page segment 0
        moveq   #47, d5         ;do all 48 seg regs
        dbra    d4,SPseg01      ;do next context

; Verify segment registers set.  Check for errors.
; note: this does not do thorough test
;
        lea     SegRegLo+(00*SegRegIn).L,a0 ;get first seg register address
        movea.l a0, a1          ;save start address
        clr.l   d3              ;context increment (loop counter)
        move.w  #SegStart,d1    ;read/write in bits 6-7 and page segment 0
        move.l  #SegRegIn,d2    ;get address increment
        moveq   #NumCntxt-1,d4  ;number of contexts(loop counter)
        moveq   #47, d5         ;do all 48 seg regs

; for i := 0 to NumCntxt-1 do
;   repeat  set seg regs 00 to 47 for this context
;
SPseg02 cmp.b   (a0), d1        ;is segment register good?
        beq.s   SPseg03         ;yes
        bset    #7, CPsysst.w   ;no, mark error
SPseg03 adda.l  d2, a0          ;update seg register address
        addq.w  #1, d1          ;bump page segment number
        cmpi.w  #SegPEnd, d1    ;at end of seg registers?
        bls.s   SPseg04         ;no, write next seg reg
        move.w  #SegStart,d1    ;reset page selector every 16 seg regs
SPseg04 dbra    d5,SPseg02      ;do for each 48 regs
        add.l   #SegCntIn, d3   ;do next context
        lea     0(a1,d3), a0    ;get start of seg regs for this context
        move.w  #SegStart,d1    ;read/write in bits 6-7 and page segment 0
        moveq   #47, d5         ;do all 48 seg regs
        dbra    d4,SPseg02      ;do next context
     page
; Page registers :
;
; All the page registers in MMU are arranged in 1 page file per memory
; board.  The page file is divided into 64 page segments.  The page
; segments are addressed by the contents of a segment register.  Page
; segments are divided into 16 page registers.  A specific page register
; within a page segment is addressed by bits a11 to a14 of the logical
; address presented to the MMU.  The data in the page register selects
; which physical memory page is accessed.
;
; The last page in the physical memory can never be accessed.  It's page
; address is $FF.  If it is ever accessed a Bus Error occurs.  It is
; reserved as the "invalid page" identifier.
;
; To get segment registers 16 thru 31 which point at page segments 0 thru
; 15 to access the physical memory 0 thru $7F7FF (all except last 2k page)
; contiguously set the page registers 0 thru $FE to 0 thru $FE.  Set page
; register $FF to $FF, to cause a Bus Error if any one tries to read
; or write it.
;
; Logical to physical address conversion :
;
; address lines :   | 2 2 2 | 2 1 1 1 1 1 | 1 1 1 1 | 1 0 0 0 0 0 0 0 0 0 0 |
;                   | 3 2 1 | 0 9 8 7 6 5 | 4 3 2 1 | 0 9 8 7 6 5 4 3 2 1 0 |
; field :           | x MMU |   segment   |  page   |        offset         |
;
; To get a byte accessed the logical address from the processor selects
; which segment register is used.  The data in the segment register selects
; which page segment is selected.  The page field in the logical address
; selects which page register in the page segment is selected.  It page
; field is an index into the page segment.  The data in the page register
; selects which 2k page in the physical address  is selected.  The offset
; in the logical address selects which byte in the 2k page of physical
; memory is accessed.
;
        movea.l #PagRegLo,a0    ;get first page register address
        clr.l   d1              ;get first page register value
        move.l  #PagRegIn,d2    ;get address increment

SPpag01 move.b  d1,(a0)         ;set page register
        adda.l  d2,a0           ;update page register address
        addq.w  #1,d1           ;update page register value
        cmp.w   #$FF,d1
        bls.s   SPpag01         ;for i:=0 to FF do
  page
; check page registers
;                               ;d1 is already zero (0)
        movea.l #PagRegLo,a0    ;get first page register address
        move.w  #PagRegIn,d2    ;get address increment

SPpag02 cmp.b   (a0), d1        ;is page reg set correctly
        beq.s   SPpag03         ;yes
        bset    #7, CPsysst.w   ;no, show error
SPpag03 adda.w  d2,a0           ;update page register address
        addq.w  #1,d1           ;update page register value
        cmp.w   #$FF,d1
        bls.s   SPpag01         ;for i:=0 to FF do

; all done
;
SPdone
         BSR.S     SPSER00             ;{!DB}dump seg and page regs
         BRA       SP1EXIT             ;{!DB}NO, ALL DONE

SPSER00  LEA       SPMGSEG, A0         ;{!DB}MSG ON DISPLAY
         BSR       DSPUTST             ;{!DB} OF SEG REGS
         LEA       SegRegLo.L,a0       ;{!DB}get first seg register address
         MOVEA.L   a0, a1              ;{!DB}save start address
         CLR.L     d3                  ;{!DB}context increment (loop counter)
         CLR.L     D4                  ;{!DB}CONTEXT COUNTER
         CLR.L     D6                  ;{!DB}FORCE BLANK BETWEEN BYTES
         move.L    #SegRegIn,d2        ;{!DB}get address increment
         moveq     #47, d5             ;{!DB}do all 48 seg regs
                                                     ;{!DB}
; for i := 0 to NumCntxt-1 do                        ;{!DB}
;   repeat  set seg regs 00 to 47 for this context   ;{!DB}
;                                                    ;{!DB}
SPSER01  MOVE.L    A0, -(SP)           ;{!DB}SAVE REG ADDR
         LEA       SPMGSCN,A0          ;{!DB} display context
         BSR       DSPUTST             ;{!DB}
         MOVE.L    (SP)+, A0           ;{!DB}RESTORE REG ADDR
         MOVE.B    D4,D0               ;{!DB}DISPLAY WHICH
         BSR.S     SPHEXASC            ;{!DB} CONTEXT'S SEG
         BSR       DSPUTCH   ;{!DB} Display number
         MOVEQ     #DSCCR,D0 ;{!DB} Do CR
         BSR       DSPUTCH   ;{!DB}
SPSER02  move.b    (a0), D1            ;{!DB}Get segment register
         adda.L    d2, a0              ;{!DB}update seg register address
         BSR.S     SPDISPB             ;{!DB}DISPLAY SEG REG
         dbra      d5,SPSER02          ;{!DB}do for each 48 regs
         MOVEQ     #'?', D0            ;{!DB}wait for
         BSR       DSPUTCH             ;{!DB}  user presses
         BSR       KBGETCH             ;{!DB}  any char
         add.l     #SegCntIn, d3       ;{!DB}do next context
         lea       0(a1,d3), a0        ;{!DB}start of seg regs for context
         moveq     #47, d5             ;{!DB}do all 48 seg regs
         ADDQ.W    #1,D4               ;{!DB}INC CONTEXT
         CMP.W     #NumCntxt-1, D4     ;{!DB}ANOTHER CONTEXT LEFT?
         BLS.S     SPSER01             ;{!DB}YES
                                   ;{!DB}
         LEA       SPMGPAG,A0          ;{!DB} display PAGE MESSAGE
         BSR       DSPUTST             ;{!DB}
         lea       PagRegLo.l,a0   ;{!DB}get first page register address
         clr.l     d1              ;{!DB}get first page register value
         move.w    #$FF, d5        ;{!DB}do for 256 regs
         move.l    #PagRegIn,d2    ;{!DB}get address increment
                                   ;{!DB}
SPPER01  move.b    (a0), d1        ;{!DB}set page register
         BSR.S     SPDISPB         ;{!DB}DUMP PAGE REG TO DISPLAY
         adda.l    d2,a0           ;{!DB}update page register address
         addq.b    #1,d1           ;{!DB}update page register value
         dbra      d5,SPPER01      ;{!DB}for i:=FF to 0 do
         MOVEQ     #'?', D0            ;{!DB}wait for
         BSR       DSPUTCH             ;{!DB}  user presses
         BSR       KBGETCH             ;{!DB}  any char
         RTS                           ;{!DB}
                                       ;{!DB}
; SPHEXASC - CONVERT D0.B LOW 4 BITS TO TO ASCII HEX ;{!DB}
;                                                    ;{!DB}
SPHEXASC ANDI.W    #$F,D0              ;{!DB}only low nibble
         MOVE.B    SPTABL(D0.W),D0     ;{!DB}GET TABLE CODE
         RTS                           ;{!DB}
SPTABL   DATA.B    '0123456789ABCDEF'  ;{!DB}
                                       ;{!DB}
; SPDISPB - DISPLAY BYTE IN D1 REGISTER AS ASCII HEX ;{!DB}
;                                                    ;{!DB}
SPDISPB  MOVE.L    A0, -(SP) ;{!DB} save seg reg addr
         MOVE.B    D1,D0     ;{!DB} get hi nibble
         LSR.B     #4,D0     ;{!DB} put hi to low
         BSR.S     SPHEXASC  ;{!DB} convert to ascii
         BSR       DSPUTCH   ;{!DB} display
         MOVE.B    D1,D0     ;{!DB} get low nibble
         BSR.S     SPHEXASC  ;{!DB} convert to ascii
         BSR       DSPUTCH   ;{!DB} display
         TST.B     D6        ;{!DB}DISPLAY BLANKS?
         BNE.S     SPDBCR    ;{!DB}NO
         MOVEQ     #$20,D0   ;{!DB} display a blank
         BSR       DSPUTCH   ;{!DB}
SPDBCR   MOVE.B    D5,D0     ;{!DB} every 16 regs
         ANDI.B    #$F,D0    ;{!DB}   do a CR
         BNE.S     SPDBEXIT  ;{!DB}
         MOVEQ     #DSCCR,D0 ;{!DB}
         BSR       DSPUTCH   ;{!DB}
SPDBEXIT MOVE.L    (SP)+, A0 ;{!DB} restore reg
         RTS                 ;{!DB}
                             ;{!DB}
SPMGSEG  DATA.B    'SEG REGS',DSCCR,0  ;{!DB}
SPMGPAG  DATA.B    'PAGE REGS',DSCCR,0 ;{!DB}
SPMGSCN  DATA.B    'CONTEXT ',0        ;{!DB} debug must end even
                                       ;{!DB}
; SPBUSDATA -DISPLAY BUS ERROR DATA    ;{!DB}
;                                      ;{!DB}
SPBUSDATA                              ;{!DB}
         MOVEQ     #-1,D6          ;{!DB} NO BLANK BETWEEN BYTES
         lea       SPmgER, a0      ;{!DB}mesg -- exception reg
         bsr       DSputSt         ;{!DB}
         moveq     #0,d5           ;{!DB}DO CR AFTER BYTE
         bsr.s     SPDISPB         ;{!DB}D1 is set to exception reg

         lea       SPmgAA, a0      ;{!DB}mesg -- access address
         bsr       DSputSt         ;{!DB}
         moveq     #1,d5           ;{!DB}NO AFTER BYTE
         MOVE.L    4+2(SP), D4     ;{!DB}GET ACCESS ADR OFF STACK
         MOVE.L    D4,D1           ;{!DB}DISPLAY HI BYTE
         SWAP      D1              ;{!DB}
         LSR.W     #8,D1           ;{!DB}
         bsr       SPDISPB         ;{!DB}
         MOVE.L    D4,D1           ;{!DB}DISPLAY HI mid BYTE
         SWAP      D1              ;{!DB}
         bsr       SPDISPB         ;{!DB}
         MOVE.L    D4,D1           ;{!DB}DISPLAY low MID BYTE
         LSR.W     #8,D1           ;{!DB}
         bsr       SPDISPB         ;{!DB}
         moveq     #0,d5           ;{!DB}DO CR AFTER BYTE
         MOVE.L    D4,D1           ;{!DB}DISPLAY LOW BYTE
         bsr       SPDISPB         ;{!DB}

         lea       SPmgPC, a0      ;{!DB}mesg -- PROGRAM COUNTER
         bsr       DSputSt         ;{!DB}
         moveq     #1,d5           ;{!DB}NO CR AFTER BYTE
         MOVE.L    4+$A(SP), D4    ;{!DB}GET PC OFF STACK
         MOVE.L    D4,D1           ;{!DB}DISPLAY HI BYTE
         SWAP      D1              ;{!DB}
         LSR.W     #8,D1           ;{!DB}
         bsr       SPDISPB         ;{!DB}
         MOVE.L    D4,D1           ;{!DB}DISPLAY HI mid BYTE
         SWAP      D1              ;{!DB}
         bsr       SPDISPB         ;{!DB}
         MOVE.L    D4,D1           ;{!DB}DISPLAY low MID BYTE
         LSR.W     #8,D1           ;{!DB}
         bsr       SPDISPB         ;{!DB}
         moveq     #0,d5           ;{!DB}DO CR AFTER BYTE
         MOVE.L    D4,D1           ;{!DB}DISPLAY LOW BYTE
         bsr       SPDISPB         ;{!DB}
         RTS                     ;{!DB}*
SPmgAA  data.b  'AA = ',0        ;{!DB}*
SPmgPC  data.b  'PC = ',0        ;{!DB}*
SPmgER  data.b  'ER = ',0        ;{!DB}*
                                       ;{!DB}
SP1EXIT                                ;{!DB}
        clr.b   CPextcrt.w      ;{!CP};Concept Plus uses display
        bra.s   SetupCk         ;back to normal Concept boot PROM

;
; SPbusEr - Bus error processing
;
SPbusEr
         MOVE.B    MMUexcp.l, D1   ;{!DB} save exception register
        move.b  #$0,MMUexcp.l   ;zero exception register to prevent
                                ;   parity error causing Bus Errors
        lea     SPmgBus,a0      ;mesg -- Bus error
        bsr     DSputSt         ;*
         BSR       SPBUSDATA ;{!DB}DISPLAY WHERE AND WHAT
         BSR       SPSER00   ;{!DB}DISPLAY seg and page regs
        lea     CPistack.w, sp  ;reset stack pointer
        bra     SPbusRS         ;restart from init of MMU

SPmgBus data.b  'Bus error',DSCcr,0
        data.b  0            ;force even boundary
