diff --git a/VAX/vax610_defs.h b/VAX/vax610_defs.h index 1c1654f5..990f2a2b 100644 --- a/VAX/vax610_defs.h +++ b/VAX/vax610_defs.h @@ -345,6 +345,13 @@ int32 Map_ReadW (uint32 ba, int32 bc, uint16 *buf); int32 Map_WriteB (uint32 ba, int32 bc, uint8 *buf); int32 Map_WriteW (uint32 ba, int32 bc, uint16 *buf); +/* Function prototypes for system-specific unaligned support */ + +int32 ReadIOU (uint32 pa, int32 lnt); +int32 ReadRegU (uint32 pa, int32 lnt); +void WriteIOU (uint32 pa, int32 val, int32 lnt); +void WriteRegU (uint32 pa, int32 val, int32 lnt); + t_stat cpu_show_leds (FILE *st, UNIT *uptr, int32 val, void *desc); #include "pdp11_io_lib.h" diff --git a/VAX/vax610_io.c b/VAX/vax610_io.c index 306cb700..30122a5e 100644 --- a/VAX/vax610_io.c +++ b/VAX/vax610_io.c @@ -124,7 +124,7 @@ MACH_CHECK (MCHK_WRITE); /* FIXME: is this correc return; } -/* ReadIO - read I/O space +/* ReadIO - read I/O space - aligned access Inputs: pa = physical address @@ -145,7 +145,49 @@ SET_IRQL; return iod; } -/* WriteIO - write I/O space +/* ReadIOU - read I/O space - unaligned access + + Inputs: + pa = physical address + lnt = length (1, 2, 3 bytes) + Output: + data, not shifted + +Note that all of these cases are presented to the existing aligned IO routine: + +bo = 0, byte, word, or longword length +bo = 2, word +bo = 1, 2, 3, byte length + +All the other cases are end up at ReadIOU and WriteIOU, and they must turn +the request into the exactly correct number of Qbus accesses AND NO MORE, +because Qbus reads can have side-effects, and word read-modify-write is NOT +the same as a byte write. + +Note that the sum of the pa offset and the length cannot be greater than 4. +The read cases are: + +bo = 0, byte or word - read one word +bo = 0, tribyte - read two words +bo = 1, byte - read one word +bo = 1, word or tribyte - read two words +bo = 2, byte or word - read one word +bo = 3, byte - read one word +*/ + +int32 ReadIOU (uint32 pa, int32 lnt) +{ +int32 iod; + +iod = ReadQb (pa); /* wd from Qbus */ +if ((lnt + (pa & 1)) <= 2) /* byte or (word & even) */ + iod = iod << ((pa & 2)? 16: 0); /* one op */ +else iod = (ReadQb (pa + 2) << 16) | iod; /* two ops, get 2nd wd */ +SET_IRQL; +return iod; +} + +/* WriteIO - write I/O space - aligned access Inputs: pa = physical address @@ -169,6 +211,54 @@ SET_IRQL; return; } +/* WriteIOU - write I/O space + + Inputs: + pa = physical address + val = data to write, right justified in 32b longword + lnt = length (1, 2, or 3 bytes) + Outputs: + none + +The write cases are: + +bo = x, lnt = byte - write one byte +bo = 0 or 2, lnt = word - write one word +bo = 1, lnt = word - write two bytes +bo = 0, lnt = tribyte - write word, byte +bo = 1, lnt = tribyte - write byte, word +*/ + +void WriteIOU (uint32 pa, int32 val, int32 lnt) +{ +switch (lnt) { +case L_BYTE: /* byte */ + WriteQb (pa, val & BMASK, WRITEB); + break; + +case L_WORD: /* word */ + if (pa & 1) { /* odd addr? */ + WriteQb (pa, val & BMASK, WRITEB); + WriteQb (pa + 1, (val >> 8) & BMASK, WRITEB); + } + else WriteQb (pa, val & WMASK, WRITE); + break; + +case 3: /* tribyte */ + if (pa & 1) { /* odd addr? */ + WriteQb (pa, val & BMASK, WRITEB); /* byte then word */ + WriteQb (pa + 1, (val >> 8) & WMASK, WRITE); + } + else { /* even */ + WriteQb (pa, val & WMASK, WRITE); /* word then byte */ + WriteQb (pa + 2, (val >> 16) & BMASK, WRITEB); + } + break; + } +SET_IRQL; +return; +} + /* Find highest priority outstanding interrupt */ int32 eval_int (void) diff --git a/VAX/vax610_sysdev.c b/VAX/vax610_sysdev.c index de3c9f59..8aa9d7f3 100644 --- a/VAX/vax610_sysdev.c +++ b/VAX/vax610_sysdev.c @@ -60,6 +60,9 @@ extern DEVICE vc_dev, lk_dev, vs_dev; int32 conisp, conpc, conpsl; /* console reg */ int32 sys_model = 0; /* MicroVAX or VAXstation */ char cpu_boot_cmd[CBUFSIZE] = { 0 }; /* boot command */ +static const int32 insert[4] = { + 0x00000000, 0x000000FF, 0x0000FFFF, 0x00FFFFFF + }; static struct boot_dev boot_tab[] = { { "RQ", "DUA", 0x00415544 }, /* DUAn */ @@ -304,6 +307,20 @@ for (p = ®table[0]; p->low != 0; p++) { MACH_CHECK (MCHK_READ); } +/* ReadRegU - read register space, unaligned + + Inputs: + pa = physical address + lnt = length in bytes (1, 2, or 3) + Output: + returned data, not shifted +*/ + +int32 ReadRegU (uint32 pa, int32 lnt) +{ +return ReadReg (pa & ~03, L_LONG); +} + /* WriteReg - write register space Inputs: @@ -328,6 +345,26 @@ mem_err = 1; SET_IRQL; } +/* WriteRegU - write register space, unaligned + + Inputs: + pa = physical address + val = data to write, right justified in 32b longword + lnt = length (1, 2, or 3) + Outputs: + none +*/ + +void WriteRegU (uint32 pa, int32 val, int32 lnt) +{ +int32 sc = (pa & 03) << 3; +int32 dat = ReadReg (pa & ~03, L_LONG); + +dat = (dat & ~(insert[lnt] << sc)) | ((val & insert[lnt]) << sc); +WriteReg (pa & ~03, dat, L_LONG); +return; +} + /* Special boot command - linked into SCP by initial reset Syntax: BOOT {/R5:val} diff --git a/VAX/vax630_defs.h b/VAX/vax630_defs.h index 6c52e0a5..26c05007 100644 --- a/VAX/vax630_defs.h +++ b/VAX/vax630_defs.h @@ -397,7 +397,12 @@ int32 Map_ReadW (uint32 ba, int32 bc, uint16 *buf); int32 Map_WriteB (uint32 ba, int32 bc, uint8 *buf); int32 Map_WriteW (uint32 ba, int32 bc, uint16 *buf); -#include "pdp11_io_lib.h" +/* Function prototypes for system-specific unaligned support */ + +int32 ReadIOU (uint32 pa, int32 lnt); +int32 ReadRegU (uint32 pa, int32 lnt); +void WriteIOU (uint32 pa, int32 val, int32 lnt); +void WriteRegU (uint32 pa, int32 val, int32 lnt); extern t_stat sysd_set_diag (UNIT *uptr, int32 val, char *cptr, void *desc); extern t_stat sysd_show_diag (FILE *st, UNIT *uptr, int32 val, void *desc); @@ -405,5 +410,6 @@ extern t_stat sysd_set_halt (UNIT *uptr, int32 val, char *cptr, void *desc); extern t_stat sysd_show_halt (FILE *st, UNIT *uptr, int32 val, void *desc); extern t_stat sysd_show_leds (FILE *st, UNIT *uptr, int32 val, void *desc); +#include "pdp11_io_lib.h" #endif diff --git a/VAX/vax630_io.c b/VAX/vax630_io.c index 26b2c902..582fe0c1 100644 --- a/VAX/vax630_io.c +++ b/VAX/vax630_io.c @@ -195,7 +195,7 @@ MACH_CHECK (MCHK_WRITE); return; } -/* ReadIO - read I/O space +/* ReadIO - read I/O space - aligned access Inputs: pa = physical address @@ -216,7 +216,49 @@ SET_IRQL; return iod; } -/* WriteIO - write I/O space +/* ReadIOU - read I/O space - unaligned access + + Inputs: + pa = physical address + lnt = length (1, 2, 3 bytes) + Output: + data, not shifted + +Note that all of these cases are presented to the existing aligned IO routine: + +bo = 0, byte, word, or longword length +bo = 2, word +bo = 1, 2, 3, byte length + +All the other cases are end up at ReadIOU and WriteIOU, and they must turn +the request into the exactly correct number of Qbus accesses AND NO MORE, +because Qbus reads can have side-effects, and word read-modify-write is NOT +the same as a byte write. + +Note that the sum of the pa offset and the length cannot be greater than 4. +The read cases are: + +bo = 0, byte or word - read one word +bo = 0, tribyte - read two words +bo = 1, byte - read one word +bo = 1, word or tribyte - read two words +bo = 2, byte or word - read one word +bo = 3, byte - read one word +*/ + +int32 ReadIOU (uint32 pa, int32 lnt) +{ +int32 iod; + +iod = ReadQb (pa); /* wd from Qbus */ +if ((lnt + (pa & 1)) <= 2) /* byte or (word & even) */ + iod = iod << ((pa & 2)? 16: 0); /* one op */ +else iod = (ReadQb (pa + 2) << 16) | iod; /* two ops, get 2nd wd */ +SET_IRQL; +return iod; +} + +/* WriteIO - write I/O space - aligned access Inputs: pa = physical address @@ -240,6 +282,54 @@ SET_IRQL; return; } +/* WriteIOU - write I/O space + + Inputs: + pa = physical address + val = data to write, right justified in 32b longword + lnt = length (1, 2, or 3 bytes) + Outputs: + none + +The write cases are: + +bo = x, lnt = byte - write one byte +bo = 0 or 2, lnt = word - write one word +bo = 1, lnt = word - write two bytes +bo = 0, lnt = tribyte - write word, byte +bo = 1, lnt = tribyte - write byte, word +*/ + +void WriteIOU (uint32 pa, int32 val, int32 lnt) +{ +switch (lnt) { +case L_BYTE: /* byte */ + WriteQb (pa, val & BMASK, WRITEB); + break; + +case L_WORD: /* word */ + if (pa & 1) { /* odd addr? */ + WriteQb (pa, val & BMASK, WRITEB); + WriteQb (pa + 1, (val >> 8) & BMASK, WRITEB); + } + else WriteQb (pa, val & WMASK, WRITE); + break; + +case 3: /* tribyte */ + if (pa & 1) { /* odd addr? */ + WriteQb (pa, val & BMASK, WRITEB); /* byte then word */ + WriteQb (pa + 1, (val >> 8) & WMASK, WRITE); + } + else { /* even */ + WriteQb (pa, val & WMASK, WRITE); /* word then byte */ + WriteQb (pa + 2, (val >> 16) & BMASK, WRITEB); + } + break; + } +SET_IRQL; +return; +} + /* Find highest priority outstanding interrupt */ int32 eval_int (void) diff --git a/VAX/vax630_sysdev.c b/VAX/vax630_sysdev.c index 0ab7e792..9088e559 100644 --- a/VAX/vax630_sysdev.c +++ b/VAX/vax630_sysdev.c @@ -149,6 +149,9 @@ int32 ka_mser = 0; /* KA630 mem sys err */ int32 ka_cear = 0; /* KA630 cpu err */ int32 ka_dear = 0; /* KA630 dma err */ static uint32 rom_delay = 0; +static const int32 insert[4] = { + 0x00000000, 0x000000FF, 0x0000FFFF, 0x00FFFFFF + }; t_bool ka_diag_full = FALSE; t_bool ka_hltenab = TRUE; /* Halt Enable / Autoboot flag */ @@ -778,6 +781,20 @@ for (p = ®table[0]; p->low != 0; p++) { MACH_CHECK (MCHK_READ); } +/* ReadRegU - read register space, unaligned + + Inputs: + pa = physical address + lnt = length in bytes (1, 2, or 3) + Output: + returned data, not shifted +*/ + +int32 ReadRegU (uint32 pa, int32 lnt) +{ +return ReadReg (pa & ~03, L_LONG); +} + /* WriteReg - write register space Inputs: @@ -802,6 +819,26 @@ for (p = ®table[0]; p->low != 0; p++) { MACH_CHECK (MCHK_WRITE); } +/* WriteRegU - write register space, unaligned + + Inputs: + pa = physical address + val = data to write, right justified in 32b longword + lnt = length (1, 2, or 3) + Outputs: + none +*/ + +void WriteRegU (uint32 pa, int32 val, int32 lnt) +{ +int32 sc = (pa & 03) << 3; +int32 dat = ReadReg (pa & ~03, L_LONG); + +dat = (dat & ~(insert[lnt] << sc)) | ((val & insert[lnt]) << sc); +WriteReg (pa & ~03, dat, L_LONG); +return; +} + /* KA630 registers */ int32 ka_rd (int32 pa) diff --git a/VAX/vax730_defs.h b/VAX/vax730_defs.h index 728eff0e..1134aabd 100644 --- a/VAX/vax730_defs.h +++ b/VAX/vax730_defs.h @@ -369,6 +369,14 @@ t_stat show_nexus (FILE *st, UNIT *uptr, int32 val, void *desc); void sbi_set_errcnf (void); +/* Function prototypes for system-specific unaligned support + 11/730 treats unaligned like aligned */ + +#define ReadIOU(p,l) ReadIO (p,l) +#define ReadRegU(p,l) ReadReg (p,l) +#define WriteIOU(p,v,l) WriteIO (p, v, l) +#define WriteRegU(p,v,l) WriteReg (p, v, l) + #include "pdp11_io_lib.h" #endif diff --git a/VAX/vax750_defs.h b/VAX/vax750_defs.h index efcc96a4..48119703 100644 --- a/VAX/vax750_defs.h +++ b/VAX/vax750_defs.h @@ -425,6 +425,14 @@ t_stat show_nexus (FILE *st, UNIT *uptr, int32 val, void *desc); void sbi_set_errcnf (void); +/* Function prototypes for system-specific unaligned support + 11/750 treats unaligned like aligned */ + +#define ReadIOU(p,l) ReadIO (p,l) +#define ReadRegU(p,l) ReadReg (p,l) +#define WriteIOU(p,v,l) WriteIO (p, v, l) +#define WriteRegU(p,v,l) WriteReg (p, v, l) + #include "pdp11_io_lib.h" #endif diff --git a/VAX/vax780_defs.h b/VAX/vax780_defs.h index a16901ab..5210f357 100644 --- a/VAX/vax780_defs.h +++ b/VAX/vax780_defs.h @@ -1,6 +1,6 @@ /* vax780_defs.h: VAX 780 model-specific definitions file - Copyright (c) 2004-2011, Robert M Supnik + Copyright (c) 2004-2013, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,7 +23,9 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. - 05-Nov-11 RMS Added VEC_QBUS definition + 29-Nov-13 RMS Added system-specific unaligned routines + 12-Dec-12 RMS Fixed IO base address for RQB, RQC, RQD + 05-Nov-11 RMS Added VEC_QMODE definition 19-Nov-08 RMS Moved I/O support routines to I/O library 29-Apr-07 RMS Modified model-specific reserved operand check macros to reflect 780 microcode patches (found by Naoki Hamada) @@ -436,6 +438,14 @@ t_stat show_nexus (FILE *st, UNIT *uptr, int32 val, void *desc); void sbi_set_errcnf (void); +/* Function prototypes for system-specific unaligned support + 11/780 treats unaligned like aligned */ + +#define ReadIOU(p,l) ReadIO (p,l) +#define ReadRegU(p,l) ReadReg (p,l) +#define WriteIOU(p,v,l) WriteIO (p, v, l) +#define WriteRegU(p,v,l) WriteReg (p, v, l) + #include "pdp11_io_lib.h" #endif diff --git a/VAX/vax860_defs.h b/VAX/vax860_defs.h index af78c992..0dd97149 100644 --- a/VAX/vax860_defs.h +++ b/VAX/vax860_defs.h @@ -471,6 +471,14 @@ t_stat show_nexus (FILE *st, UNIT *uptr, int32 val, void *desc); void sbi_set_errcnf (void); +/* Function prototypes for system-specific unaligned support + 8600 treats unaligned like aligned */ + +#define ReadIOU(p,l) ReadIO (p,l) +#define ReadRegU(p,l) ReadReg (p,l) +#define WriteIOU(p,v,l) WriteIO (p, v, l) +#define WriteRegU(p,v,l) WriteReg (p, v, l) + #include "pdp11_io_lib.h" #endif diff --git a/VAX/vax_io.c b/VAX/vax_io.c index 58a761a6..fce19eb4 100644 --- a/VAX/vax_io.c +++ b/VAX/vax_io.c @@ -1,6 +1,6 @@ /* vax_io.c: VAX 3900 Qbus IO simulator - Copyright (c) 1998-2012, Robert M Supnik + Copyright (c) 1998-2013, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,7 @@ qba Qbus adapter + 20-Dec-13 RMS Added unaligned access routines 25-Mar-12 RMS Added parameter to int_ack prototype (Mark Pizzolata) 28-May-08 RMS Inlined physical memory routines 25-Jan-08 RMS Fixed declarations (Mark Pizzolato) @@ -231,7 +232,7 @@ mem_err = 1; return; } -/* ReadIO - read I/O space +/* ReadIO - read I/O space - aligned access Inputs: pa = physical address @@ -252,7 +253,49 @@ SET_IRQL; return iod; } -/* WriteIO - write I/O space +/* ReadIOU - read I/O space - unaligned access + + Inputs: + pa = physical address + lnt = length (1, 2, 3 bytes) + Output: + data, not shifted + +Note that all of these cases are presented to the existing aligned IO routine: + +bo = 0, byte, word, or longword length +bo = 2, word +bo = 1, 2, 3, byte length + +All the other cases are end up at ReadIOU and WriteIOU, and they must turn +the request into the exactly correct number of Qbus accesses AND NO MORE, +because Qbus reads can have side-effects, and word read-modify-write is NOT +the same as a byte write. + +Note that the sum of the pa offset and the length cannot be greater than 4. +The read cases are: + +bo = 0, byte or word - read one word +bo = 0, tribyte - read two words +bo = 1, byte - read one word +bo = 1, word or tribyte - read two words +bo = 2, byte or word - read one word +bo = 3, byte - read one word +*/ + +int32 ReadIOU (uint32 pa, int32 lnt) +{ +int32 iod; + +iod = ReadQb (pa); /* wd from Qbus */ +if ((lnt + (pa & 1)) <= 2) /* byte or (word & even) */ + iod = iod << ((pa & 2)? 16: 0); /* one op */ +else iod = (ReadQb (pa + 2) << 16) | iod; /* two ops, get 2nd wd */ +SET_IRQL; +return iod; +} + +/* WriteIO - write I/O space - aligned access Inputs: pa = physical address @@ -276,6 +319,54 @@ SET_IRQL; return; } +/* WriteIOU - write I/O space + + Inputs: + pa = physical address + val = data to write, right justified in 32b longword + lnt = length (1, 2, or 3 bytes) + Outputs: + none + +The write cases are: + +bo = x, lnt = byte - write one byte +bo = 0 or 2, lnt = word - write one word +bo = 1, lnt = word - write two bytes +bo = 0, lnt = tribyte - write word, byte +bo = 1, lnt = tribyte - write byte, word +*/ + +void WriteIOU (uint32 pa, int32 val, int32 lnt) +{ +switch (lnt) { +case L_BYTE: /* byte */ + WriteQb (pa, val & BMASK, WRITEB); + break; + +case L_WORD: /* word */ + if (pa & 1) { /* odd addr? */ + WriteQb (pa, val & BMASK, WRITEB); + WriteQb (pa + 1, (val >> 8) & BMASK, WRITEB); + } + else WriteQb (pa, val & WMASK, WRITE); + break; + +case 3: /* tribyte */ + if (pa & 1) { /* odd addr? */ + WriteQb (pa, val & BMASK, WRITEB); /* byte then word */ + WriteQb (pa + 1, (val >> 8) & WMASK, WRITE); + } + else { /* even */ + WriteQb (pa, val & WMASK, WRITE); /* word then byte */ + WriteQb (pa + 2, (val >> 16) & BMASK, WRITEB); + } + break; + } +SET_IRQL; +return; +} + /* Find highest priority outstanding interrupt */ int32 eval_int (void) diff --git a/VAX/vax_mmu.c b/VAX/vax_mmu.c index e98eacf0..d9550335 100644 --- a/VAX/vax_mmu.c +++ b/VAX/vax_mmu.c @@ -1,6 +1,6 @@ /* vax_mmu.c - VAX memory management - Copyright (c) 1998-2008, Robert M Supnik + Copyright (c) 1998-2013, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,7 +23,7 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. - 09-Nov-13 MB Fixed reading/writing of unaligned data + 29-Nov-13 RMS Reworked unaligned flows 24-Oct-12 MB Added support for KA620 virtual addressing 21-Jul-08 RMS Removed inlining support 28-May-08 RMS Inlined physical memory routines @@ -58,7 +58,6 @@ typedef struct { } TLBENT; extern uint32 *M; -extern const uint32 align[4]; extern int32 PSL; extern int32 mapen; extern int32 p1, p2; @@ -110,6 +109,8 @@ extern int32 ReadIO (uint32 pa, int32 lnt); extern void WriteIO (uint32 pa, int32 val, int32 lnt); extern int32 ReadReg (uint32 pa, int32 lnt); extern void WriteReg (uint32 pa, int32 val, int32 lnt); +int32 ReadU (uint32 pa, int32 lnt); +void WriteU (uint32 pa, int32 val, int32 lnt); /* TLB data structures @@ -199,24 +200,22 @@ if (mapen && ((uint32)(off + lnt) > VA_PAGSIZE)) { /* cross page? */ if (((xpte.pte & acc) == 0) || (xpte.tag != vpn) || ((acc & TLB_WACC) && ((xpte.pte & TLB_M) == 0))) xpte = fill (va + lnt, lnt, acc, NULL); /* fill if needed */ - pa1 = (xpte.pte & TLB_PFN) | VA_GETOFF (va + 4); + pa1 = ((xpte.pte & TLB_PFN) | VA_GETOFF (va + 4)) & ~03; } -else pa1 = (pa + 4) & PAMASK; /* not cross page */ +else pa1 = ((pa + 4) & PAMASK) & ~03; /* not cross page */ bo = pa & 3; -pa = pa & ~3; /* convert to aligned */ -pa1 = pa1 & ~3; if (lnt >= L_LONG) { /* lw unaligned? */ sc = bo << 3; - wl = ReadL (pa); /* read both lw */ - wh = ReadL (pa1); /* extract */ - return ((((wl >> sc) & align[bo]) | (wh << (32 - sc))) & LMASK); + wl = ReadU (pa, L_LONG - bo); /* read both fragments */ + wh = ReadU (pa1, bo); /* extract */ + return ((wl | (wh << (32 - sc))) & LMASK); } -else if (bo == 1) - return ((ReadL (pa) >> 8) & WMASK); +else if (bo == 1) /* read within lw */ + return ReadU (pa, L_WORD); else { - wl = ReadL (pa); /* word cross lw */ - wh = ReadL (pa1); /* read, extract */ - return (((wl >> 24) & 0xFF) | ((wh & 0xFF) << 8)); + wl = ReadU (pa, L_BYTE); /* word cross lw */ + wh = ReadU (pa1, L_BYTE); /* read, extract */ + return (wl | (wh << 8)); } } @@ -234,7 +233,7 @@ else { void Write (uint32 va, int32 val, int32 lnt, int32 acc) { int32 vpn, off, tbi, pa; -int32 pa1, bo, sc, wl, wh; +int32 pa1, bo, sc; TLBENT xpte; mchk_va = va; @@ -267,31 +266,20 @@ if (mapen && ((uint32)(off + lnt) > VA_PAGSIZE)) { if (((xpte.pte & acc) == 0) || (xpte.tag != vpn) || ((xpte.pte & TLB_M) == 0)) xpte = fill (va + lnt, lnt, acc, NULL); - pa1 = (xpte.pte & TLB_PFN) | VA_GETOFF (va + 4); + pa1 = ((xpte.pte & TLB_PFN) | VA_GETOFF (va + 4)) & ~03; } -else pa1 = (pa + 4) & PAMASK; +else pa1 = ((pa + 4) & PAMASK) & ~03; bo = pa & 3; -pa = pa & ~3; /* convert to aligned */ -pa1 = pa1 & ~3; -wl = ReadL (pa); if (lnt >= L_LONG) { sc = bo << 3; - wh = ReadL (pa1); - wl = (wl & insert[bo]) | ((val << sc) & LMASK); - wh = (wh & ~insert[bo]) | ((val >> (32 - sc)) & insert[bo]); - WriteL (pa, wl); - WriteL (pa1, wh); + WriteU (pa, val & insert[L_LONG - bo], L_LONG - bo); + WriteU (pa1, (val >> (32 - sc)) & insert[bo], bo); } -else if (bo == 1) { - wl = (wl & 0xFF0000FF) | (val << 8); - WriteL (pa, wl); - } -else { - wh = ReadL (pa1); - wl = (wl & 0x00FFFFFF) | ((val & 0xFF) << 24); - wh = (wh & 0xFFFFFF00) | ((val >> 8) & 0xFF); - WriteL (pa, wl); - WriteL (pa1, wh); +else if (bo == 1) /* read within lw */ + WriteU (pa, val & WMASK, L_WORD); +else { /* word cross lw */ + WriteU (pa, val & BMASK, L_BYTE); + WriteU (pa1, (val >> 8) & BMASK, L_BYTE); } return; } @@ -362,7 +350,8 @@ SIM_INLINE int32 ReadL (uint32 pa) if (ADDR_IS_MEM (pa)) return M[pa >> 2]; mchk_ref = REF_V; -if (ADDR_IS_IO (pa)) return ReadIO (pa, L_LONG); +if (ADDR_IS_IO (pa)) + return ReadIO (pa, L_LONG); return ReadReg (pa, L_LONG); } @@ -377,6 +366,30 @@ if (ADDR_IS_IO (pa)) return ReadReg (pa, L_LONG); } +/* Read unaligned physical (in virtual context) + + Inputs: + pa = physical address + lnt = length in bytes (1, 2, or 3) + Output: + returned data +*/ + +int32 ReadU (uint32 pa, int32 lnt) +{ +int32 dat; +int32 sc = (pa & 3) << 3; +if (ADDR_IS_MEM (pa)) + dat = M[pa >> 2]; +else { + mchk_ref = REF_V; + if (ADDR_IS_IO (pa)) + dat = ReadIOU (pa, lnt); + else dat = ReadRegU (pa, lnt); + } +return ((dat >> sc) & insert[lnt]); +} + /* Write aligned physical (in virtual context, unless indicated) Inputs: @@ -446,6 +459,33 @@ else { return; } +/* Write unaligned physical (in virtual context) + + Inputs: + pa = physical address + val = data to be written, right justified in 32b longword + lnt = length (1, 2, or 3 bytes) + Output: + none +*/ + +void WriteU (uint32 pa, int32 val, int32 lnt) +{ +if (ADDR_IS_MEM (pa)) { + int32 bo = pa & 3; + int32 sc = bo << 3; + M[pa >> 2] = (M[pa >> 2] & ~(insert[lnt] << sc)) | ((val & insert[lnt]) << sc); + } +else { + mchk_ref = REF_V; + if ADDR_IS_IO (pa) + WriteIOU (pa, val, lnt); + else WriteRegU (pa, val, lnt); + } +return; +} + + /* TLB fill This routine fills the TLB after a tag or access mismatch, or diff --git a/VAX/vax_sysdev.c b/VAX/vax_sysdev.c index 98dbdbef..fc685aa0 100644 --- a/VAX/vax_sysdev.c +++ b/VAX/vax_sysdev.c @@ -1,6 +1,6 @@ /* vax_sysdev.c: VAX 3900 system-specific logic - Copyright (c) 1998-2011, Robert M Supnik + Copyright (c) 1998-2013, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -33,6 +33,7 @@ cmctl memory controller sysd system devices (SSC miscellany) + 20-Dec-13 RMS Added unaligned register space access routines 23-Dec-10 RMS Added power clear call to boot routine (Mark Pizzolato) 25-Oct-05 RMS Automated CMCTL extended memory 16-Aug-05 RMS Fixed C++ declaration and cast problems @@ -232,6 +233,9 @@ int32 ssc_adsm[2] = { 0 }; /* addr strobes */ int32 ssc_adsk[2] = { 0 }; int32 cdg_dat[CDASIZE >> 2]; /* cache data */ static uint32 rom_delay = 0; +static const int32 insert[4] = { + 0x00000000, 0x000000FF, 0x0000FFFF, 0x00FFFFFF + }; t_stat rom_ex (t_value *vptr, t_addr exta, UNIT *uptr, int32 sw); t_stat rom_dep (t_value val, t_addr exta, UNIT *uptr, int32 sw); @@ -1045,6 +1049,20 @@ MACH_CHECK (MCHK_READ); return 0; } +/* ReadRegU - read register space, unaligned + + Inputs: + pa = physical address + lnt = length in bytes (1, 2, or 3) + Output: + returned data, not shifted +*/ + +int32 ReadRegU (uint32 pa, int32 lnt) +{ +return ReadReg (pa & ~03, L_LONG); +} + /* WriteReg - write register space Inputs: @@ -1070,6 +1088,26 @@ MACH_CHECK (MCHK_WRITE); return; } +/* WriteRegU - write register space, unaligned + + Inputs: + pa = physical address + val = data to write, right justified in 32b longword + lnt = length (1, 2, or 3) + Outputs: + none +*/ + +void WriteRegU (uint32 pa, int32 val, int32 lnt) +{ +int32 sc = (pa & 03) << 3; +int32 dat = ReadReg (pa & ~03, L_LONG); + +dat = (dat & ~(insert[lnt] << sc)) | ((val & insert[lnt]) << sc); +WriteReg (pa & ~03, dat, L_LONG); +return; +} + /* CMCTL registers CMCTL00 - 15 configure memory banks 00 - 15. Note that they are diff --git a/VAX/vaxmod_defs.h b/VAX/vaxmod_defs.h index cd53dff7..d06a4341 100644 --- a/VAX/vaxmod_defs.h +++ b/VAX/vaxmod_defs.h @@ -1,6 +1,6 @@ /* vaxmod_defs.h: VAX model-specific definitions file - Copyright (c) 1998-2011, Robert M Supnik + Copyright (c) 1998-2013, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,6 +23,7 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 20-Dec-13 RMS Added prototypes for unaligned IO and register handling 11-Dec-11 RMS Moved all Qbus devices to BR4; deleted RP definitions 25-Nov-11 RMS Added VEC_QBUS definition 29-Apr-07 RMS Separated checks for PxBR and SBR @@ -437,4 +438,11 @@ int32 Map_WriteW (uint32 ba, int32 bc, uint16 *buf); extern t_stat sysd_set_halt (UNIT *uptr, int32 val, char *cptr, void *desc); extern t_stat sysd_show_halt (FILE *st, UNIT *uptr, int32 val, void *desc); +/* Function prototypes for system-specific unaligned support */ + +int32 ReadIOU (uint32 pa, int32 lnt); +int32 ReadRegU (uint32 pa, int32 lnt); +void WriteIOU (uint32 pa, int32 val, int32 lnt); +void WriteRegU (uint32 pa, int32 val, int32 lnt); + #endif