This commit introduces dozens of changes to make the 3B2-700 simulator fully functional and ready for wider use. In addition to 3B2-700 availability, this commit includes a tremendous amount of refactoring of the 3B2-400 and common code to make the project structure easier to maintain and reason about. One final important change: ROM files are no longer included in the source code. 3B2 ROM images must be obtained separately and loaded into the simulator before boot. Changes: - The 3b2 target has been aliased to 3b2-400 - The formerly named 3b2-600 project has become 3b2-700 - SCSI QIC tape support has been added to sim_scsi.c - Header files have been reworked to reduce complexity of includes - Common code has been consolidated - Timer code has been unified
358 lines
13 KiB
C
358 lines
13 KiB
C
/* 3b2_rev2_mmu.c: WE32101 MMU
|
|
|
|
Copyright (c) 2017-2022, Seth J. Morabito
|
|
|
|
Permission is hereby granted, free of charge, to any person
|
|
obtaining a copy of this software and associated documentation
|
|
files (the "Software"), to deal in the Software without
|
|
restriction, including without limitation the rights to use, copy,
|
|
modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
of the Software, and to permit persons to whom the Software is
|
|
furnished to do so, subject to the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be
|
|
included in all copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
|
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
|
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
SOFTWARE.
|
|
|
|
Except as contained in this notice, the name of the author shall
|
|
not be used in advertising or otherwise to promote the sale, use or
|
|
other dealings in this Software without prior written authorization
|
|
from the author.
|
|
*/
|
|
|
|
#ifndef _3B2_REV2_MMU_H_
|
|
#define _3B2_REV2_MMU_H_
|
|
|
|
#include "sim_defs.h"
|
|
|
|
/************************************************************************
|
|
*
|
|
* Vocabulary
|
|
* ----------
|
|
*
|
|
* PD: Page Descriptor (in main memory)
|
|
* PDT: Page Descriptor Table (in main memory)
|
|
* POT: Page Offset. Bits 0-10 of a Paged virtual address.
|
|
* PSL: Page Select. Bits 11-16 of a Paged virtual address.
|
|
* SD: Segment Descriptor (in main memory)
|
|
* SDT: Segment Descriptor Table (in main memory)
|
|
* SID: Section ID. Bits 30-31 of all virtual addresses
|
|
* SOT: Segment Offset. Bits 0-16 of a Contiguous virtual address.
|
|
* SSL: Segment Select. Bits 17-29 of all virtual addresses.
|
|
*
|
|
*
|
|
* The WE32101 MMU divides the virtual address space into four
|
|
* Sections with 8K Segments per section. Virtual address bits 30 and
|
|
* 31 determine the section, bits 17-29 determine the Segment within
|
|
* the section.
|
|
*
|
|
* There are two kinds of address translation: Contiguous Translation
|
|
* and Paged Translation. Contiguous Translation just uses an offset
|
|
* (bits 0-16 of the virtual address) into each Segment to find an
|
|
* address, allowing for 128K bytes per Segment. Paged translation
|
|
* further break Segments down into 64 Pages of 2K each.
|
|
*
|
|
* Details about how to do translation are held in main memory in
|
|
* Segment Descriptors and Page Descriptors. These are located in
|
|
* Segment Descriptor Tables and Page Descriptor Tables set up by the
|
|
* computer before enabling the MMU.
|
|
*
|
|
* In addition to details in main memory, the MMU has a small cache
|
|
* of both Segment Descriptors and Page Descriptors. This is NOT just
|
|
* used for performance reasons! Various features of the cache,
|
|
* such as updating R and M bits in Segment and Page Descriptors,
|
|
* are used by various operating system features.
|
|
*
|
|
*
|
|
* Virtual Address Fields
|
|
* ----------------------
|
|
*
|
|
* 31 30 29 17 16 0
|
|
* +-----+-------------------+-----------------------------+
|
|
* Contig: | SID | SSL | SOT |
|
|
* +-----+-------------------+-----------------------------+
|
|
*
|
|
* 31 30 29 17 16 11 10 0
|
|
* +-----+-------------------+---------+-------------------+
|
|
* Paged: | SID | SSL | PSL | POT |
|
|
* +-----+-------------------+---------+-------------------+
|
|
*
|
|
*
|
|
* Segment Descriptor Fields
|
|
* -------------------------
|
|
*
|
|
* 31 24 23 10 9 8 7 6 5 4 3 2 1 0
|
|
* +-------+---------+-----+---+---+---+---+---+---+---+---+
|
|
* sd0: | Acc | Max Off | Res | I | V | R | T | $ | C | M | P |
|
|
* +-------+---------+-----+---+---+---+---+---+---+---+---+
|
|
*
|
|
* +-----------------------------------------------+-------+
|
|
* sd1: | Address (high-order 27 or 29 bits) | Soft |
|
|
* +-----------------------------------------------+-------+
|
|
*
|
|
*
|
|
* Segment Descriptor Cache Entry
|
|
* ------------------------------
|
|
*
|
|
* 31 24 23 10 9 0
|
|
* +-------+-------------------------+---------------------+
|
|
* Low: | Acc | Max Off | Tag |
|
|
* +-------+-------------------------+---------------------+
|
|
*
|
|
* 31 5 4 3 2 1 0
|
|
* +-----------------------------------+---+---+---+---+---+
|
|
* High: | Address | T | $ | C | M | G |
|
|
* +-----------------------------------+---+---+---+---+---+
|
|
*
|
|
*
|
|
* Page Descriptor Fields
|
|
* ----------------------
|
|
*
|
|
* 31 11 10 8 7 6 5 4 3 2 1 0
|
|
* +----------------+------+-----+---+---+-----+---+---+---+
|
|
* | Page Address | Soft | Res | R | W | Res | L | M | P |
|
|
* +----------------+------+-----+---+---+-----+---+---+---+
|
|
*
|
|
*
|
|
* Page Descriptor Cache Entry
|
|
* ---------------------------
|
|
*
|
|
* 31 24 23 16 15 0
|
|
* +-----+------------------+------------------------------+
|
|
* Low: | Acc | Res | Tag |
|
|
* +-----+------------------+------------------------------+
|
|
*
|
|
* 31 11 10 7 6 5 4 3 2 1 0
|
|
* +---------------------+-----+---+---+---+---+---+---+---+
|
|
* High: | Address | Res | U | R | W | $ | L | M | G |
|
|
* +---------------------+-----+---+---+---+---+---+---+---+
|
|
*
|
|
* "U" is only set in the left cache entry, and indicates
|
|
* which slot (left or right) was most recently updated.
|
|
*
|
|
***********************************************************************/
|
|
|
|
#define MMUBASE 0x40000
|
|
#define MMUSIZE 0x1000
|
|
|
|
#define MMU_SRS 0x04 /* Section RAM array size (words) */
|
|
#define MMU_SDCS 0x20 /* Segment Descriptor Cache H/L array size
|
|
(words) */
|
|
#define MMU_PDCS 0x20 /* Page Descriptor Cache H/L array size
|
|
(words) */
|
|
|
|
/* Register address offsets */
|
|
#define MMU_SDCL 0
|
|
#define MMU_SDCH 1
|
|
#define MMU_PDCRL 2
|
|
#define MMU_PDCRH 3
|
|
#define MMU_PDCLL 4
|
|
#define MMU_PDCLH 5
|
|
#define MMU_SRAMA 6
|
|
#define MMU_SRAMB 7
|
|
#define MMU_FC 8
|
|
#define MMU_FA 9
|
|
#define MMU_CONF 10
|
|
#define MMU_VAR 11
|
|
|
|
#define MMU_CONF_M (mmu_state.conf & 0x1)
|
|
#define MMU_CONF_R (mmu_state.conf & 0x2)
|
|
|
|
/* Caching */
|
|
#define NUM_SEC 4u /* Number of memory sections */
|
|
#define NUM_SDCE 8 /* SD cache entries per section */
|
|
#define NUM_PDCE 8 /* PD cache entries per section per side (l/r) */
|
|
#define SET_SIZE 2 /* PDs are held in a 2-way associative set */
|
|
|
|
/* Cache Tag for SDs */
|
|
#define SD_TAG(vaddr) ((vaddr >> 20) & 0x3ff)
|
|
|
|
/* Cache Tag for PDs */
|
|
#define PD_TAG(vaddr) (((vaddr >> 13) & 0xf) | ((vaddr >> 14) & 0xfff0))
|
|
|
|
/* Index of entry in the SD cache */
|
|
#define SD_IDX(vaddr) ((vaddr >> 17) & 7)
|
|
|
|
/* Index of entry in the PD cache */
|
|
#define PD_IDX(vaddr) (((vaddr >> 11) & 3) | ((vaddr >> 15) & 4))
|
|
|
|
/* Shift and mask the flag bits for the current CPU mode */
|
|
#define MMU_PERM(f) ((f >> ((3 - CPU_CM) * 2)) & 3)
|
|
|
|
/* Codes set in the MMU Fault register */
|
|
#define MMU_F_SDTLEN 0x03
|
|
#define MMU_F_PW 0x04
|
|
#define MMU_F_PDTLEN 0x05
|
|
#define MMU_F_INV_SD 0x06
|
|
#define MMU_F_SEG_NOT_PRES 0x07
|
|
#define MMU_F_OTRAP 0x08
|
|
#define MMU_F_PDT_NOT_PRES 0x09
|
|
#define MMU_F_PAGE_NOT_PRES 0x0a
|
|
#define MMU_F_ACC 0x0d
|
|
#define MMU_F_SEG_OFFSET 0x0e
|
|
|
|
/* Access Request types */
|
|
#define ACC_MT 0 /* Move Translated */
|
|
#define ACC_SPW 1 /* Support processor write */
|
|
#define ACC_SPF 3 /* Support processor fetch */
|
|
#define ACC_IR 7 /* Interlocked read */
|
|
#define ACC_AF 8 /* Address fetch */
|
|
#define ACC_OF 9 /* Operand fetch */
|
|
#define ACC_W 10 /* Write */
|
|
#define ACC_IFAD 12 /* Instruction fetch after discontinuity */
|
|
#define ACC_IF 13 /* Instruction fetch */
|
|
|
|
/* Pluck out Virtual Address fields */
|
|
#define SID(va) (((va) >> 30) & 3)
|
|
#define SSL(va) (((va) >> 17) & 0x1fff)
|
|
#define SOT(va) (va & 0x1ffff)
|
|
#define PSL(va) (((va) >> 11) & 0x3f)
|
|
#define PSL_C(va) ((va) & 0x1f800)
|
|
#define POT(va) (va & 0x7ff)
|
|
|
|
/* Get the maximum length of an SSL from SRAMB */
|
|
#define SRAMB_LEN(va) (mmu_state.sec[SID(va)].len + 1)
|
|
|
|
/* Pluck out Segment Descriptor fields */
|
|
#define SD_PRESENT(sd0) ((sd0) & 1)
|
|
#define SD_MODIFIED(sd0) (((sd0) >> 1) & 1)
|
|
#define SD_CONTIG(sd0) (((sd0) >> 2) & 1)
|
|
#define SD_PAGED(sd0) ((((sd0) >> 2) & 1) == 0)
|
|
#define SD_CACHE(sd0) (((sd0) >> 3) & 1)
|
|
#define SD_TRAP(sd0) (((sd0) >> 4) & 1)
|
|
#define SD_REF(sd0) (((sd0) >> 5) & 1)
|
|
#define SD_VALID(sd0) (((sd0) >> 6) & 1)
|
|
#define SD_INDIRECT(sd0) (((sd0) >> 7) & 1)
|
|
#define SD_SEG_ADDR(sd1) ((sd1) & 0xffffffe0)
|
|
#define SD_MAX_OFF(sd0) (((sd0) >> 10) & 0x3fff)
|
|
#define SD_ACC(sd0) (((sd0) >> 24) & 0xff)
|
|
#define SD_R_MASK 0x20
|
|
#define SD_M_MASK 0x2
|
|
#define SD_GOOD_MASK 0x1u
|
|
#define SDCE_TAG(sdcl) ((sdcl) & 0x3ff)
|
|
|
|
#define SD_ADDR(va) (mmu_state.sec[SID(va)].addr + (SSL(va) * 8))
|
|
|
|
|
|
/* Convert from sd to sd cache entry */
|
|
#define SD_TO_SDCL(va,sd0) ((sd0 & 0xfffffc00)|SD_TAG(va))
|
|
#define SD_TO_SDCH(sd0,sd1) (SD_SEG_ADDR(sd1)|(sd0 & 0x1e)|1)
|
|
|
|
/* Note that this is a lossy transform. We will lose the state of the
|
|
I and R flags, as well as the software flags. We don't need them.
|
|
The V and P flags can be inferred as set. */
|
|
|
|
#define SDCE_TO_SD0(sdch,sdcl) ((sdcl & 0xfffffc00)|0x40|(sdch & 0x1e)|1)
|
|
#define SDCE_TO_SD1(sdch) (sdch & 0xffffffe0)
|
|
|
|
/* Maximum size (in bytes) of a segment */
|
|
#define MAX_OFFSET(sd0) ((SD_MAX_OFF(sd0) + 1) * 8)
|
|
|
|
#define PD_PRESENT(pd) (pd & 1)
|
|
#define PD_MODIFIED(pd) ((pd >> 1) & 1)
|
|
#define PD_LAST(pd) ((pd >> 2) & 1)
|
|
#define PD_WFAULT(pd) ((pd >> 4) & 1)
|
|
#define PD_REF(pd) ((pd >> 5) & 1)
|
|
#define PD_ADDR(pd) (pd & 0xfffff800) /* Address portion of PD */
|
|
#define PD_R_MASK 0x20
|
|
#define PD_M_MASK 0x2
|
|
#define PD_GOOD_MASK 0x1u
|
|
#define PDCLH_USED_MASK 0x40u
|
|
#define PDCXL_TAG(pdcxl) (pdcxl & 0xffff)
|
|
|
|
#define PD_LOC(sd1,va) SD_SEG_ADDR(sd1) + (PSL(va) * 4)
|
|
|
|
/* Page Descriptor Cache Entry
|
|
*
|
|
*/
|
|
|
|
/* Convert from pd to pd cache entry. Alwasy sets "Good" bit. */
|
|
#define SD_TO_PDCXL(va,sd0) ((sd0 & 0xff000000)|PD_TAG(va))
|
|
#define PD_TO_PDCXH(pd,sd0) ((pd & 0xfffff836)|(sd0 & 0x8)|1)
|
|
|
|
/* Always set 'present' to true on conversion */
|
|
#define PDCXH_TO_PD(pdch) ((pdch & 0xfffff836)|1)
|
|
#define PDCXL_TO_ACC(pdcl) (((pdcl & 0xff000000) >> 24) & 0xff)
|
|
|
|
/* Fault codes */
|
|
#define MMU_FAULT(f) { \
|
|
if (fc) { \
|
|
mmu_state.fcode = ((((uint32)r_acc)<<7)| \
|
|
(((uint32)(CPU_CM))<<5)|f); \
|
|
mmu_state.faddr = va; \
|
|
} \
|
|
}
|
|
|
|
typedef struct _mmu_sec {
|
|
uint32 addr;
|
|
uint32 len;
|
|
} mmu_sec;
|
|
|
|
typedef struct _mmu_state {
|
|
t_bool enabled; /* Global enabled/disabled flag */
|
|
|
|
uint32 sdcl[MMU_SDCS]; /* SDC low bits (0-31) */
|
|
uint32 sdch[MMU_SDCS]; /* SDC high bits (32-63) */
|
|
|
|
uint32 pdcll[MMU_PDCS]; /* PDC low bits (left) (0-31) */
|
|
uint32 pdclh[MMU_PDCS]; /* PDC high bits (left) (32-63) */
|
|
|
|
uint32 pdcrl[MMU_PDCS]; /* PDC low bits (right) (0-31) */
|
|
uint32 pdcrh[MMU_PDCS]; /* PDC high bits (right) (32-63) */
|
|
|
|
uint32 sra[MMU_SRS]; /* Section RAM A */
|
|
uint32 srb[MMU_SRS]; /* Section RAM B */
|
|
|
|
mmu_sec sec[MMU_SRS]; /* Section descriptors decoded from
|
|
Section RAM A and B */
|
|
|
|
uint32 fcode; /* Fault Code Register */
|
|
uint32 faddr; /* Fault Address Register */
|
|
uint32 conf; /* Configuration Register */
|
|
uint32 var; /* Virtual Address Register */
|
|
|
|
} MMU_STATE;
|
|
|
|
t_stat mmu_init(DEVICE *dptr);
|
|
uint32 mmu_read(uint32 pa, size_t size);
|
|
void mmu_write(uint32 pa, uint32 val, size_t size);
|
|
CONST char *mmu_description(DEVICE *dptr);
|
|
|
|
/* Virtual memory translation */
|
|
uint32 mmu_xlate_addr(uint32 va, uint8 r_acc);
|
|
t_stat mmu_decode_vaddr(uint32 vaddr, uint8 r_acc,
|
|
t_bool fc, uint32 *pa);
|
|
|
|
#define SHOULD_CACHE_PD(pd) \
|
|
(fc && PD_PRESENT(pd))
|
|
|
|
#define SHOULD_CACHE_SD(sd) \
|
|
(fc && SD_VALID(sd) && SD_PRESENT(sd))
|
|
|
|
#define SHOULD_UPDATE_SD_R_BIT(sd) \
|
|
(MMU_CONF_R && !((sd) & SD_R_MASK))
|
|
|
|
#define SHOULD_UPDATE_SD_M_BIT(sd) \
|
|
(MMU_CONF_M && r_acc == ACC_W && !((sd) & SD_M_MASK))
|
|
|
|
#define SHOULD_UPDATE_PD_R_BIT(pd) \
|
|
(!((pd) & PD_R_MASK))
|
|
|
|
#define SHOULD_UPDATE_PD_M_BIT(pd) \
|
|
(r_acc == ACC_W && !((pd) & PD_M_MASK))
|
|
|
|
t_stat mmu_decode_va(uint32 va, uint8 r_acc, t_bool fc, uint32 *pa);
|
|
void mmu_enable();
|
|
void mmu_disable();
|
|
|
|
extern MMU_STATE mmu_state;
|
|
|
|
#endif /* _3B2_REV2_MMU_H_ */
|