Xemu [doxygen]  hyppo 0a42be3a057156924bc1b626a687bd6e27349c45 @ Sat 19 Mar 02:15:11 CET 2022
z8010.c
Go to the documentation of this file.
1 /* Z8010 MMU emulator
2  * Written from the technical manual of the Z8000/Z8010 released by Zilog by me,
3  * so it can be very ugly, strange and incorrect code, especially, because
4  * Z8000/Z8010 is a new thing me, first try to even get to know it ... */
5 
6 /* What I know currently:
7 
8  MMU contains table for 64 segments
9 
10  A process called (by Zilog) "relocation" never touches the lower 8 bytes of generated address.
11  (I won't name this way, for me, relocation is a software based thing ...)
12 
13  A 24 bit physical addrss is built as output with:
14  * So, lower 8 bits are unaltered
15  THIS ALSO MEANS THAT IT IS NO NEED FOR THE LOW 8 BITS TO GO INTO THE MMU AND SINCE
16  DATA/ADDRESS LINES ARE COMMON ON THE BUS, LOWER 8 BITS ARE NOT USED WHEN PROGRAMMING
17  THE MMU EITHER! Warning, big trap for youngplayers :)
18  * Higher 16 bits are the output of a 16 bit adder which has two inputs:
19  * the higher 8 bits of the CPU offset (the missing upper bits are zero)
20  * the base address from the segment table
21 
22  Z800X uses "special I/O instructions" to program the MMU. I am not sure why not normal ones, the manual
23  says something that special ones provides the bus cycle/state transitions needed by the MMU. OK then ...
24 
25 */
26 
27 #include "xemu/emutools.h"
28 #include "z8010.h"
29 
30 
31 
32 static Uint16 segment_bases[64];
33 static Uint8 segment_limits[64];
34 static Uint8 segment_attributes[64];
35 static Uint8 mode,sar,dsc;
36 
37 
38 void z8010_init ( void )
39 {
40 }
41 
42 void z8010_reset ( void )
43 {
44  for (int a = 0; a < 64; a++) {
45  segment_bases[a] = 0;
46  segment_limits[a] = 0;
47  segment_attributes[a] = 0;
48  }
49 }
50 
51 
53 {
54  return 0xFF;
55 }
56 
57 
58 static void write_descriptor ( int dsc_now, Uint8 data )
59 {
60  switch (dsc_now & 3) {
61  case 0:
62  segment_bases[sar] = (data << 8) | (segment_bases[sar] & 0xFF);
63  DEBUGPRINT("Z8010: segment #$%02X base high is set to $%02X, value is now = %04X" NL, sar, data, segment_bases[sar]);
64  break;
65  case 1:
66  segment_bases[sar] = (segment_bases[sar] & 0xFF00) | data;
67  DEBUGPRINT("Z8010: segment #$%02X base low is set to $%02X, value is now = %04X" NL, sar, data, segment_bases[sar]);
68  break;
69  case 2:
70  segment_limits[sar] = data;
71  DEBUGPRINT("Z8010: segment #$%02X limit is set to $%02X" NL, sar, data);
72  break;
73  case 3:
74  segment_attributes[sar] = data;
75  DEBUGPRINT("Z8010: segment #$%02X attribute is set to $%02X" NL, sar, data);
76  break;
77  }
78 }
79 
80 
81 static Uint8 read_descriptor ( int dsc_now )
82 {
83  switch (dsc_now & 3) {
84  case 0: return segment_bases [sar] >> 8;
85  case 1: return segment_bases [sar] & 0xFF;
86  case 2: return segment_limits [sar];
87  case 3: return segment_attributes[sar];
88  }
89 }
90 
91 
92 
93 
94 
95 
96 // Z8010 has connection for the AD8-AD15 lines only with the CPU. That is,
97 // even writing MMU registers, only the high byte counts on the data and
98 // the MMU register selection as well! However, to simplify things, we assume
99 // here that these fuctions to read/write MMU registers are now called
100 // with "normalized" values, ie port number and data being a byte entity.
101 
102 void z8010_write_register ( int port, Uint8 data )
103 {
104  switch (port) {
105  case 0x00:
106  mode = data;
107  break;
108  case 0x01:
109  sar = data & 63;
110  dsc = 0; // FIXME: do we need this?
111  break;
112  case 0x08: // base field of descriptor
113  write_descriptor(dsc & 1, data);
114  dsc++;
115  break;
116  case 0x09: // limit
117  write_descriptor(2, data);
118  break;
119  case 0x0A: // attribute field
120  write_descriptor(3, data);
121  break;
122  case 0x0B: // descriptor, ALL fields!!!!
123  write_descriptor(dsc, data);
124  dsc++;
125  case 0x0C: // base field, incrementing SAR
126  write_descriptor(dsc & 1, data);
127  sar = (sar + 1) & 63;
128  break;
129  case 0x0D: // limit field, incrementing SAR
130  write_descriptor(2, data);
131  sar = (sar + 1) & 63;
132  break;
133  case 0x0E: // attribute field, incrementing SAR
134  write_descriptor(3, data);
135  sar = (sar + 1) & 63;
136  break;
137  case 0x0F:
138  write_descriptor(dsc, data);
139  dsc = (dsc + 1) & 3;
140  if (!dsc)
141  sar = (sar + 1) & 63;
142  break;
143 
144  case 0x20: // descriptor counter
145  dsc = data & 3;
146  DEBUGPRINT("Z8010: DSC is set to %d" NL, dsc);
147  break;
148 
149  }
150 }
151 
152 
153 // Output: 24 bit linear address, _OR_ negative number, indicating segmenting violation
154 int z8010_translate ( int is_system_mode, int is_execute, int is_write, Uint8 segment, Uint16 offset )
155 {
156  //if ((!!(segment & 64)) != URS) {
157  //}
158  segment &= 63;
159  return ((segment_bases[segment & 63] << 8) + offset) & 0xFFFFFF;
160 }
z8010_reset
void z8010_reset(void)
Definition: z8010.c:42
emutools.h
z8010_init
void z8010_init(void)
Definition: z8010.c:38
z8010_translate
int z8010_translate(int is_system_mode, int is_execute, int is_write, Uint8 segment, Uint16 offset)
Definition: z8010.c:154
z8010.h
m65-memcontent-generator.data
data
Definition: m65-memcontent-generator.py:119
Uint8
uint8_t Uint8
Definition: fat32.c:51
DEBUGPRINT
#define DEBUGPRINT(...)
Definition: emutools_basicdefs.h:171
NL
#define NL
Definition: fat32.c:37
z8010_read_register
Uint8 z8010_read_register(int port)
Definition: z8010.c:52
Uint16
uint16_t Uint16
Definition: fat32.c:50
z8010_write_register
void z8010_write_register(int port, Uint8 data)
Definition: z8010.c:102