run copyright.sh for 2011.
[external/binutils.git] / sim / ppc / vm.c
1 /*  This file is part of the program psim.
2
3     Copyright (C) 1994-1997, Andrew Cagney <cagney@highland.com.au>
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14  
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  
19     */
20
21
22 #ifndef _VM_C_
23 #define _VM_C_
24
25 #if 0
26 #include "basics.h"
27 #include "registers.h"
28 #include "device.h"
29 #include "corefile.h"
30 #include "vm.h"
31 #include "interrupts.h"
32 #include "mon.h"
33 #endif
34
35 #include "cpu.h"
36
37 /* OEA vs VEA
38
39    For the VEA model, the VM layer is almost transparent.  It's only
40    purpose is to maintain separate core_map's for the instruction
41    and data address spaces.  This being so that writes to instruction
42    space or execution of a data space is prevented.
43
44    For the OEA model things are more complex.  The reason for separate
45    instruction and data models becomes crucial.  The OEA model is
46    built out of three parts.  An instruction map, a data map and an
47    underlying structure that provides access to the VM data kept in
48    main memory. */
49
50
51 /* OEA data structures:
52
53    The OEA model maintains internal data structures that shadow the
54    semantics of the various OEA VM registers (BAT, SR, etc).  This
55    allows a simple efficient model of the VM to be implemented.
56
57    Consistency between OEA registers and this model's internal data
58    structures is maintained by updating the structures at
59    `synchronization' points.  Of particular note is that (at the time
60    of writing) the memory data types for BAT registers are rebuilt
61    when ever the processor moves between problem and system states.
62
63    Unpacked values are stored in the OEA so that they correctly align
64    to where they will be needed by the PTE address. */
65
66
67 /* Protection table:
68
69    Matrix of processor state, type of access and validity */
70
71 typedef enum {
72   om_supervisor_state,
73   om_problem_state,
74   nr_om_modes
75 } om_processor_modes;
76
77 typedef enum {
78   om_data_read, om_data_write,
79   om_instruction_read, om_access_any,
80   nr_om_access_types
81 } om_access_types;
82
83 static int om_valid_access[2][4][nr_om_access_types] = {
84   /* read, write, instruction, any */
85   /* K bit == 0 */
86   { /*r  w  i  a       pp */
87     { 1, 1, 1, 1 }, /* 00 */
88     { 1, 1, 1, 1 }, /* 01 */
89     { 1, 1, 1, 1 }, /* 10 */
90     { 1, 0, 1, 1 }, /* 11 */
91   },
92   /* K bit == 1  or P bit valid */
93   { /*r  w  i  a       pp */
94     { 0, 0, 0, 0 }, /* 00 */
95     { 1, 0, 1, 1 }, /* 01 */
96     { 1, 1, 1, 1 }, /* 10 */
97     { 1, 0, 1, 1 }, /* 11 */
98   }
99 };
100
101
102 /* Bat translation:
103
104    The bat data structure only contains information on valid BAT
105    translations for the current processor mode and type of access. */
106
107 typedef struct _om_bat {
108   unsigned_word block_effective_page_index;
109   unsigned_word block_effective_page_index_mask;
110   unsigned_word block_length_mask;
111   unsigned_word block_real_page_number;
112   int protection_bits;
113 } om_bat;
114
115 enum _nr_om_bat_registers {
116   nr_om_bat_registers = 4
117 };
118
119 typedef struct _om_bats {
120   int nr_valid_bat_registers;
121   om_bat bat[nr_om_bat_registers];
122 } om_bats;
123
124
125 /* Segment TLB:
126
127    In this model the 32 and 64 bit segment tables are treated in very
128    similar ways.  The 32bit segment registers are treated as a
129    simplification of the 64bit segment tlb */
130
131 enum _om_segment_tlb_constants {
132 #if (WITH_TARGET_WORD_BITSIZE == 64)
133   sizeof_segment_table_entry_group = 128,
134   sizeof_segment_table_entry = 16,
135 #endif
136   om_segment_tlb_index_start_bit = 32,
137   om_segment_tlb_index_stop_bit = 35,
138   nr_om_segment_tlb_entries = 16,
139   nr_om_segment_tlb_constants
140 };
141
142 typedef struct _om_segment_tlb_entry {
143   int key[nr_om_modes];
144   om_access_types invalid_access; /* set to instruction if no_execute bit */
145   unsigned_word masked_virtual_segment_id; /* aligned ready for pte group addr */
146 #if (WITH_TARGET_WORD_BITSIZE == 64)
147   int is_valid;
148   unsigned_word masked_effective_segment_id;
149 #endif
150 } om_segment_tlb_entry;
151
152 typedef struct _om_segment_tlb {
153   om_segment_tlb_entry entry[nr_om_segment_tlb_entries];
154 } om_segment_tlb;
155
156
157 /* Page TLB:
158
159    This OEA model includes a small direct map Page TLB.  The tlb is to
160    cut down on the need for the OEA to perform walks of the page hash
161    table. */
162
163 enum _om_page_tlb_constants {
164   om_page_tlb_index_start_bit = 46,
165   om_page_tlb_index_stop_bit = 51,
166   nr_om_page_tlb_entries = 64,
167 #if (WITH_TARGET_WORD_BITSIZE == 64)
168   sizeof_pte_group = 128,
169   sizeof_pte = 16,
170 #endif
171 #if (WITH_TARGET_WORD_BITSIZE == 32)
172   sizeof_pte_group = 64,
173   sizeof_pte = 8,
174 #endif
175   nr_om_page_tlb_constants
176 };
177
178 typedef struct _om_page_tlb_entry {
179   int protection;
180   int changed;
181   unsigned_word real_address_of_pte_1;
182   unsigned_word masked_virtual_segment_id;
183   unsigned_word masked_page;
184   unsigned_word masked_real_page_number;
185 } om_page_tlb_entry;
186
187 typedef struct _om_page_tlb {
188   om_page_tlb_entry entry[nr_om_page_tlb_entries];
189 } om_page_tlb;
190
191
192 /* memory translation:
193
194    OEA memory translation possibly involves BAT, SR, TLB and HTAB
195    information*/
196
197 typedef struct _om_map {
198
199   /* local cache of register values */
200   int is_relocate;
201   int is_problem_state;
202
203   /* block address translation */
204   om_bats *bat_registers;
205
206   /* failing that, translate ea to va using segment tlb */
207 #if (WITH_TARGET_WORD_BITSIZE == 64)
208   unsigned_word real_address_of_segment_table;
209 #endif
210   om_segment_tlb *segment_tlb;
211
212   /* then va to ra using hashed page table and tlb */
213   unsigned_word real_address_of_page_table;
214   unsigned_word page_table_hash_mask;
215   om_page_tlb *page_tlb;
216
217   /* physical memory for fetching page table entries */
218   core_map *physical;
219
220   /* address xor for PPC endian */
221   unsigned xor[WITH_XOR_ENDIAN];
222
223 } om_map;
224
225
226 /* VM objects:
227
228    External objects defined by vm.h */
229
230 struct _vm_instruction_map {
231   /* real memory for last part */
232   core_map *code;
233   /* translate effective to real */
234   om_map translation;
235 };
236
237 struct _vm_data_map {
238   /* translate effective to real */
239   om_map translation;
240   /* real memory for translated address */
241   core_map *read;
242   core_map *write;
243 };
244
245
246 /* VM:
247
248    Underlying memory object.  For the VEA this is just the
249    core_map. For OEA it is the instruction and data memory
250    translation's */
251
252 struct _vm {
253
254   /* OEA: base address registers */
255   om_bats ibats;
256   om_bats dbats;
257
258   /* OEA: segment registers */
259   om_segment_tlb segment_tlb;
260
261   /* OEA: translation lookaside buffers */
262   om_page_tlb instruction_tlb;
263   om_page_tlb data_tlb;
264
265   /* real memory */
266   core *physical;
267
268   /* memory maps */
269   vm_instruction_map instruction_map;
270   vm_data_map data_map;
271
272 };
273
274
275 /* OEA Support procedures */
276
277
278 STATIC_INLINE_VM\
279 (unsigned_word)
280 om_segment_tlb_index(unsigned_word ea)
281 {
282   unsigned_word index = EXTRACTED(ea,
283                                   om_segment_tlb_index_start_bit,
284                                   om_segment_tlb_index_stop_bit);
285   return index;
286 }
287
288 STATIC_INLINE_VM\
289 (unsigned_word)
290 om_page_tlb_index(unsigned_word ea)
291 {
292   unsigned_word index = EXTRACTED(ea,
293                                   om_page_tlb_index_start_bit,
294                                   om_page_tlb_index_stop_bit);
295   return index;
296 }
297
298 STATIC_INLINE_VM\
299 (unsigned_word)
300 om_hash_page(unsigned_word masked_vsid,
301              unsigned_word ea)
302 {
303   unsigned_word extracted_ea = EXTRACTED(ea, 36, 51);
304 #if (WITH_TARGET_WORD_BITSIZE == 32)
305   unsigned_word masked_ea = INSERTED32(extracted_ea, 7, 31-6);
306   unsigned_word hash = masked_vsid ^ masked_ea;
307 #endif
308 #if (WITH_TARGET_WORD_BITSIZE == 64)
309   unsigned_word masked_ea = INSERTED64(extracted_ea, 18, 63-7);
310   unsigned_word hash = masked_vsid ^ masked_ea;
311 #endif
312   TRACE(trace_vm, ("ea=0x%lx - masked-vsid=0x%lx masked-ea=0x%lx hash=0x%lx\n",
313                    (unsigned long)ea,
314                    (unsigned long)masked_vsid,
315                    (unsigned long)masked_ea,
316                    (unsigned long)hash));
317   return hash;
318 }
319
320 STATIC_INLINE_VM\
321 (unsigned_word)
322 om_pte_0_api(unsigned_word pte_0)
323 {
324 #if (WITH_TARGET_WORD_BITSIZE == 32)
325   return EXTRACTED32(pte_0, 26, 31);
326 #endif
327 #if (WITH_TARGET_WORD_BITSIZE == 64)
328   return EXTRACTED64(pte_0, 52, 56);
329 #endif
330 }
331
332 STATIC_INLINE_VM\
333 (unsigned_word)
334 om_pte_0_hash(unsigned_word pte_0)
335 {
336 #if (WITH_TARGET_WORD_BITSIZE == 32)
337   return EXTRACTED32(pte_0, 25, 25);
338 #endif
339 #if (WITH_TARGET_WORD_BITSIZE == 64)
340   return EXTRACTED64(pte_0, 62, 62);
341 #endif
342 }
343
344 STATIC_INLINE_VM\
345 (int)
346 om_pte_0_valid(unsigned_word pte_0)
347 {
348 #if (WITH_TARGET_WORD_BITSIZE == 32)
349   return MASKED32(pte_0, 0, 0) != 0;
350 #endif
351 #if (WITH_TARGET_WORD_BITSIZE == 64)
352   return MASKED64(pte_0, 63, 63) != 0;
353 #endif
354 }
355
356 STATIC_INLINE_VM\
357 (unsigned_word)
358 om_ea_masked_page(unsigned_word ea)
359 {
360   return MASKED(ea, 36, 51);
361 }
362
363 STATIC_INLINE_VM\
364 (unsigned_word)
365 om_ea_masked_byte(unsigned_word ea)
366 {
367   return MASKED(ea, 52, 63);
368 }
369
370 /* return the VSID aligned for pte group addr */
371 STATIC_INLINE_VM\
372 (unsigned_word)
373 om_pte_0_masked_vsid(unsigned_word pte_0)
374 {
375 #if (WITH_TARGET_WORD_BITSIZE == 32)
376   return INSERTED32(EXTRACTED32(pte_0, 1, 24), 31-6-24+1, 31-6);
377 #endif
378 #if (WITH_TARGET_WORD_BITSIZE == 64)
379   return INSERTED64(EXTRACTED64(pte_0, 0, 51), 63-7-52+1, 63-7);
380 #endif
381 }
382
383 STATIC_INLINE_VM\
384 (unsigned_word)
385 om_pte_1_pp(unsigned_word pte_1)
386 {
387   return MASKED(pte_1, 62, 63); /*PP*/
388 }
389
390 STATIC_INLINE_VM\
391 (int)
392 om_pte_1_referenced(unsigned_word pte_1)
393 {
394   return EXTRACTED(pte_1, 55, 55);
395 }
396
397 STATIC_INLINE_VM\
398 (int)
399 om_pte_1_changed(unsigned_word pte_1)
400 {
401   return EXTRACTED(pte_1, 56, 56);
402 }
403
404 STATIC_INLINE_VM\
405 (int)
406 om_pte_1_masked_rpn(unsigned_word pte_1)
407 {
408   return MASKED(pte_1, 0, 51); /*RPN*/
409 }
410
411 STATIC_INLINE_VM\
412 (unsigned_word)
413 om_ea_api(unsigned_word ea)
414 {
415   return EXTRACTED(ea, 36, 41);
416 }
417
418
419 /* Page and Segment table read/write operators, these need to still
420    account for the PPC's XOR operation */
421
422 STATIC_INLINE_VM\
423 (unsigned_word)
424 om_read_word(om_map *map,
425              unsigned_word ra,
426              cpu *processor,
427              unsigned_word cia)
428 {
429   if (WITH_XOR_ENDIAN)
430     ra ^= map->xor[sizeof(instruction_word) - 1];
431   return core_map_read_word(map->physical, ra, processor, cia);
432 }
433
434 STATIC_INLINE_VM\
435 (void)
436 om_write_word(om_map *map,
437               unsigned_word ra,
438               unsigned_word val,
439               cpu *processor,
440               unsigned_word cia)
441 {
442   if (WITH_XOR_ENDIAN)
443     ra ^= map->xor[sizeof(instruction_word) - 1];
444   core_map_write_word(map->physical, ra, val, processor, cia);
445 }
446
447
448 /* Bring things into existance */
449
450 INLINE_VM\
451 (vm *)
452 vm_create(core *physical)
453 {
454   vm *virtual;
455
456   /* internal checks */
457   if (nr_om_segment_tlb_entries
458       != (1 << (om_segment_tlb_index_stop_bit
459                 - om_segment_tlb_index_start_bit + 1)))
460     error("internal error - vm_create - problem with om_segment constants\n");
461   if (nr_om_page_tlb_entries
462       != (1 << (om_page_tlb_index_stop_bit
463                 - om_page_tlb_index_start_bit + 1)))
464     error("internal error - vm_create - problem with om_page constants\n");
465
466   /* create the new vm register file */
467   virtual = ZALLOC(vm);
468
469   /* set up core */
470   virtual->physical = physical;
471
472   /* set up the address decoders */
473   virtual->instruction_map.translation.bat_registers = &virtual->ibats;
474   virtual->instruction_map.translation.segment_tlb = &virtual->segment_tlb;
475   virtual->instruction_map.translation.page_tlb = &virtual->instruction_tlb;
476   virtual->instruction_map.translation.is_relocate = 0;
477   virtual->instruction_map.translation.is_problem_state = 0;
478   virtual->instruction_map.translation.physical = core_readable(physical);
479   virtual->instruction_map.code = core_readable(physical);
480
481   virtual->data_map.translation.bat_registers = &virtual->dbats;
482   virtual->data_map.translation.segment_tlb = &virtual->segment_tlb;
483   virtual->data_map.translation.page_tlb = &virtual->data_tlb;
484   virtual->data_map.translation.is_relocate = 0;
485   virtual->data_map.translation.is_problem_state = 0;
486   virtual->data_map.translation.physical = core_readable(physical);
487   virtual->data_map.read = core_readable(physical);
488   virtual->data_map.write = core_writeable(physical);
489
490   return virtual;
491 }
492
493
494 STATIC_INLINE_VM\
495 (om_bat *)
496 om_effective_to_bat(om_map *map,
497                     unsigned_word ea)
498 {
499   int curr_bat = 0;
500   om_bats *bats = map->bat_registers;
501   int nr_bats = bats->nr_valid_bat_registers;
502
503   for (curr_bat = 0; curr_bat < nr_bats; curr_bat++) {
504     om_bat *bat = bats->bat + curr_bat;
505     if ((ea & bat->block_effective_page_index_mask)
506         != bat->block_effective_page_index)
507       continue;
508     return bat;
509   }
510
511   return NULL;
512 }
513
514
515 STATIC_INLINE_VM\
516 (om_segment_tlb_entry *)
517 om_effective_to_virtual(om_map *map, 
518                         unsigned_word ea,
519                         cpu *processor,
520                         unsigned_word cia)
521 {
522   /* first try the segment tlb */
523   om_segment_tlb_entry *segment_tlb_entry = (map->segment_tlb->entry
524                                              + om_segment_tlb_index(ea));
525
526 #if (WITH_TARGET_WORD_BITSIZE == 32)
527   TRACE(trace_vm, ("ea=0x%lx - sr[%ld] - masked-vsid=0x%lx va=0x%lx%07lx\n",
528                    (unsigned long)ea,
529                    (long)om_segment_tlb_index(ea),
530                    (unsigned long)segment_tlb_entry->masked_virtual_segment_id, 
531                    (unsigned long)EXTRACTED32(segment_tlb_entry->masked_virtual_segment_id, 31-6-24+1, 31-6),
532                    (unsigned long)EXTRACTED32(ea, 4, 31)));
533   return segment_tlb_entry;
534 #endif
535
536 #if (WITH_TARGET_WORD_BITSIZE == 64)
537   if (segment_tlb_entry->is_valid
538       && (segment_tlb_entry->masked_effective_segment_id == MASKED(ea, 0, 35))) {
539     error("fixme - is there a need to update any bits\n");
540     return segment_tlb_entry;
541   }
542
543   /* drats, segment tlb missed */
544   {
545     unsigned_word segment_id_hash = ea;
546     int current_hash = 0;
547     for (current_hash = 0; current_hash < 2; current_hash += 1) {
548       unsigned_word segment_table_entry_group =
549         (map->real_address_of_segment_table
550          | (MASKED64(segment_id_hash, 31, 35) >> (56-35)));
551       unsigned_word segment_table_entry;
552       for (segment_table_entry = segment_table_entry_group;
553            segment_table_entry < (segment_table_entry_group
554                                   + sizeof_segment_table_entry_group);
555            segment_table_entry += sizeof_segment_table_entry) {
556         /* byte order? */
557         unsigned_word segment_table_entry_dword_0 =
558           om_read_word(map->physical, segment_table_entry, processor, cia);
559         unsigned_word segment_table_entry_dword_1 =
560           om_read_word(map->physical, segment_table_entry + 8,
561                        processor, cia);
562         int is_valid = MASKED64(segment_table_entry_dword_0, 56, 56) != 0;
563         unsigned_word masked_effective_segment_id =
564           MASKED64(segment_table_entry_dword_0, 0, 35);
565         if (is_valid && masked_effective_segment_id == MASKED64(ea, 0, 35)) {
566           /* don't permit some things */
567           if (MASKED64(segment_table_entry_dword_0, 57, 57))
568             error("om_effective_to_virtual() - T=1 in STE not supported\n");
569           /* update segment tlb */
570           segment_tlb_entry->is_valid = is_valid;
571           segment_tlb_entry->masked_effective_segment_id =
572             masked_effective_segment_id;
573           segment_tlb_entry->key[om_supervisor_state] =
574             EXTRACTED64(segment_table_entry_dword_0, 58, 58);
575           segment_tlb_entry->key[om_problem_state] =
576             EXTRACTED64(segment_table_entry_dword_0, 59, 59);
577           segment_tlb_entry->invalid_access =
578             (MASKED64(segment_table_entry_dword_0, 60, 60)
579              ? om_instruction_read
580              : om_access_any);
581           segment_tlb_entry->masked_virtual_segment_id =
582             INSERTED64(EXTRACTED64(segment_table_entry_dword_1, 0, 51),
583                        18-13, 63-7); /* aligned ready for pte group addr */
584           return segment_tlb_entry;
585         }
586       }
587       segment_id_hash = ~segment_id_hash;
588     }
589   }
590   return NULL;
591 #endif
592 }
593
594
595
596 STATIC_INLINE_VM\
597 (om_page_tlb_entry *)
598 om_virtual_to_real(om_map *map, 
599                    unsigned_word ea,
600                    om_segment_tlb_entry *segment_tlb_entry,
601                    om_access_types access,
602                    cpu *processor,
603                    unsigned_word cia)
604 {
605   om_page_tlb_entry *page_tlb_entry = (map->page_tlb->entry
606                                        + om_page_tlb_index(ea));
607
608   /* is it a tlb hit? */
609   if ((page_tlb_entry->masked_virtual_segment_id
610        == segment_tlb_entry->masked_virtual_segment_id)
611       && (page_tlb_entry->masked_page
612           == om_ea_masked_page(ea))) {
613     TRACE(trace_vm, ("ea=0x%lx - tlb hit - tlb=0x%lx\n",
614                (long)ea, (long)page_tlb_entry));
615     return page_tlb_entry;
616   }
617       
618   /* drats, it is a tlb miss */
619   {
620     unsigned_word page_hash =
621       om_hash_page(segment_tlb_entry->masked_virtual_segment_id, ea);
622     int current_hash;
623     for (current_hash = 0; current_hash < 2; current_hash += 1) {
624       unsigned_word real_address_of_pte_group =
625         (map->real_address_of_page_table
626          | (page_hash & map->page_table_hash_mask));
627       unsigned_word real_address_of_pte_0;
628       TRACE(trace_vm,
629             ("ea=0x%lx - htab search %d - htab=0x%lx hash=0x%lx mask=0x%lx pteg=0x%lx\n",
630              (long)ea, current_hash,
631              map->real_address_of_page_table,
632              page_hash,
633              map->page_table_hash_mask,
634              (long)real_address_of_pte_group));
635       for (real_address_of_pte_0 = real_address_of_pte_group;
636            real_address_of_pte_0 < (real_address_of_pte_group
637                                     + sizeof_pte_group);
638            real_address_of_pte_0 += sizeof_pte) {
639         unsigned_word pte_0 = om_read_word(map,
640                                            real_address_of_pte_0,
641                                            processor, cia);
642         /* did we hit? */
643         if (om_pte_0_valid(pte_0)
644             && (current_hash == om_pte_0_hash(pte_0))
645             && (segment_tlb_entry->masked_virtual_segment_id
646                 == om_pte_0_masked_vsid(pte_0))
647             && (om_ea_api(ea) == om_pte_0_api(pte_0))) {
648           unsigned_word real_address_of_pte_1 = (real_address_of_pte_0
649                                                  + sizeof_pte / 2);
650           unsigned_word pte_1 = om_read_word(map,
651                                              real_address_of_pte_1,
652                                              processor, cia);
653           page_tlb_entry->protection = om_pte_1_pp(pte_1);
654           page_tlb_entry->changed = om_pte_1_changed(pte_1);
655           page_tlb_entry->masked_virtual_segment_id = segment_tlb_entry->masked_virtual_segment_id;
656           page_tlb_entry->masked_page = om_ea_masked_page(ea);
657           page_tlb_entry->masked_real_page_number = om_pte_1_masked_rpn(pte_1);
658           page_tlb_entry->real_address_of_pte_1 = real_address_of_pte_1;
659           if (!om_pte_1_referenced(pte_1)) {
660             om_write_word(map,
661                           real_address_of_pte_1,
662                           pte_1 | BIT(55),
663                           processor, cia);
664             TRACE(trace_vm,
665                   ("ea=0x%lx - htab hit - set ref - tlb=0x%lx &pte1=0x%lx\n",
666                    (long)ea, (long)page_tlb_entry, (long)real_address_of_pte_1));
667           }
668           else {
669             TRACE(trace_vm,
670                   ("ea=0x%lx - htab hit - tlb=0x%lx &pte1=0x%lx\n",
671                    (long)ea, (long)page_tlb_entry, (long)real_address_of_pte_1));
672           }
673           return page_tlb_entry;
674         }
675       }
676       page_hash = ~page_hash; /*???*/
677     }
678   }
679   return NULL;
680 }
681
682
683 STATIC_INLINE_VM\
684 (void)
685 om_interrupt(cpu *processor,
686              unsigned_word cia,
687              unsigned_word ea,
688              om_access_types access,
689              storage_interrupt_reasons reason)
690 {
691   switch (access) {
692   case om_data_read:
693     data_storage_interrupt(processor, cia, ea, reason, 0/*!is_store*/);
694     break;
695   case om_data_write:
696     data_storage_interrupt(processor, cia, ea, reason, 1/*is_store*/);
697     break;
698   case om_instruction_read:
699     instruction_storage_interrupt(processor, cia, reason);
700     break;
701   default:
702     error("internal error - om_interrupt - unexpected access type %d", access);
703   }
704 }
705
706
707 STATIC_INLINE_VM\
708 (unsigned_word)
709 om_translate_effective_to_real(om_map *map,
710                                unsigned_word ea,
711                                om_access_types access,
712                                cpu *processor,
713                                unsigned_word cia,
714                                int abort)
715 {
716   om_bat *bat = NULL;
717   om_segment_tlb_entry *segment_tlb_entry = NULL;
718   om_page_tlb_entry *page_tlb_entry = NULL;
719   unsigned_word ra;
720
721   if (!map->is_relocate) {
722     ra = ea;
723     TRACE(trace_vm, ("ea=0x%lx - direct map - ra=0x%lx\n",
724                      (long)ea, (long)ra));
725     return ra;
726   }
727
728   /* match with BAT? */
729   bat = om_effective_to_bat(map, ea);
730   if (bat != NULL) {
731     if (!om_valid_access[1][bat->protection_bits][access]) {
732       TRACE(trace_vm, ("ea=0x%lx - bat access violation\n", (long)ea));
733       if (abort)
734         om_interrupt(processor, cia, ea, access,
735                      protection_violation_storage_interrupt);
736       else
737         return MASK(0, 63);
738     }
739
740     ra = ((ea & bat->block_length_mask) | bat->block_real_page_number);
741     TRACE(trace_vm, ("ea=0x%lx - bat translation - ra=0x%lx\n",
742                      (long)ea, (long)ra));
743     return ra;
744   }
745
746   /* translate ea to va using segment map */
747   segment_tlb_entry = om_effective_to_virtual(map, ea, processor, cia);
748 #if (WITH_TARGET_WORD_BITSIZE == 64)
749   if (segment_tlb_entry == NULL) {
750     TRACE(trace_vm, ("ea=0x%lx - segment tlb miss\n", (long)ea));
751     if (abort)
752       om_interrupt(processor, cia, ea, access,
753                    segment_table_miss_storage_interrupt);
754     else
755       return MASK(0, 63);
756   }
757 #endif
758   /* check for invalid segment access type */
759   if (segment_tlb_entry->invalid_access == access) {
760     TRACE(trace_vm, ("ea=0x%lx - segment access invalid\n", (long)ea));
761     if (abort)
762       om_interrupt(processor, cia, ea, access,
763                    protection_violation_storage_interrupt);
764     else
765       return MASK(0, 63);
766   }
767
768   /* lookup in PTE */
769   page_tlb_entry = om_virtual_to_real(map, ea, segment_tlb_entry,
770                                       access,
771                                       processor, cia);
772   if (page_tlb_entry == NULL) {
773     TRACE(trace_vm, ("ea=0x%lx - page tlb miss\n", (long)ea));
774     if (abort)
775       om_interrupt(processor, cia, ea, access,
776                    hash_table_miss_storage_interrupt);
777     else
778       return MASK(0, 63);
779   }
780   if (!(om_valid_access
781         [segment_tlb_entry->key[map->is_problem_state]]
782         [page_tlb_entry->protection]
783         [access])) {
784     TRACE(trace_vm, ("ea=0x%lx - page tlb access violation\n", (long)ea));
785     if (abort)
786       om_interrupt(processor, cia, ea, access,
787                    protection_violation_storage_interrupt);
788     else
789       return MASK(0, 63);
790   }
791
792   /* update change bit as needed */
793   if (access == om_data_write &&!page_tlb_entry->changed) {
794     unsigned_word pte_1 = om_read_word(map,
795                                        page_tlb_entry->real_address_of_pte_1,
796                                        processor, cia);
797     om_write_word(map,
798                   page_tlb_entry->real_address_of_pte_1,
799                   pte_1 | BIT(56),
800                   processor, cia);
801     TRACE(trace_vm, ("ea=0x%lx - set change bit - tlb=0x%lx &pte1=0x%lx\n",
802                      (long)ea, (long)page_tlb_entry,
803                      (long)page_tlb_entry->real_address_of_pte_1));
804   }
805
806   ra = (page_tlb_entry->masked_real_page_number | om_ea_masked_byte(ea));
807   TRACE(trace_vm, ("ea=0x%lx - page translation - ra=0x%lx\n",
808                    (long)ea, (long)ra));
809   return ra;
810 }
811
812
813 /*
814  * Definition of operations for memory management
815  */
816
817
818 /* rebuild all the relevant bat information */
819 STATIC_INLINE_VM\
820 (void)
821 om_unpack_bat(om_bat *bat,
822               spreg ubat,
823               spreg lbat)
824 {
825   /* for extracting out the offset within a page */
826   bat->block_length_mask = ((MASKED(ubat, 51, 61) << (17-2))
827                             | MASK(63-17+1, 63));
828
829   /* for checking the effective page index */
830   bat->block_effective_page_index = MASKED(ubat, 0, 46);
831   bat->block_effective_page_index_mask = ~bat->block_length_mask;
832
833   /* protection information */
834   bat->protection_bits = EXTRACTED(lbat, 62, 63);
835   bat->block_real_page_number = MASKED(lbat, 0, 46);
836 }
837
838
839 /* rebuild the given bat table */
840 STATIC_INLINE_VM\
841 (void)
842 om_unpack_bats(om_bats *bats,
843                spreg *raw_bats,
844                msreg msr)
845 {
846   int i;
847   bats->nr_valid_bat_registers = 0;
848   for (i = 0; i < nr_om_bat_registers*2; i += 2) {
849     spreg ubat = raw_bats[i];
850     spreg lbat = raw_bats[i+1];
851     if ((msr & msr_problem_state)
852         ? EXTRACTED(ubat, 63, 63)
853         : EXTRACTED(ubat, 62, 62)) {
854       om_unpack_bat(&bats->bat[bats->nr_valid_bat_registers],
855                     ubat, lbat);
856       bats->nr_valid_bat_registers += 1;
857     }
858   }
859 }
860
861
862 #if (WITH_TARGET_WORD_BITSIZE == 32)
863 STATIC_INLINE_VM\
864 (void)
865 om_unpack_sr(vm *virtual,
866              sreg *srs,
867              int which_sr,
868              cpu *processor,
869              unsigned_word cia)
870 {
871   om_segment_tlb_entry *segment_tlb_entry = 0;
872   sreg new_sr_value = 0;
873
874   /* check register in range */
875   ASSERT(which_sr >= 0 && which_sr < nr_om_segment_tlb_entries);
876
877   /* get the working values */
878   segment_tlb_entry = &virtual->segment_tlb.entry[which_sr];  
879   new_sr_value = srs[which_sr];
880   
881   /* do we support this */
882   if (MASKED32(new_sr_value, 0, 0))
883     cpu_error(processor, cia, "unsupported value of T in segment register %d",
884               which_sr);
885
886   /* update info */
887   segment_tlb_entry->key[om_supervisor_state] = EXTRACTED32(new_sr_value, 1, 1);
888   segment_tlb_entry->key[om_problem_state] = EXTRACTED32(new_sr_value, 2, 2);
889   segment_tlb_entry->invalid_access = (MASKED32(new_sr_value, 3, 3)
890                                        ? om_instruction_read
891                                        : om_access_any);
892   segment_tlb_entry->masked_virtual_segment_id =
893     INSERTED32(EXTRACTED32(new_sr_value, 8, 31),
894                31-6-24+1, 31-6); /* aligned ready for pte group addr */
895 }
896 #endif
897
898
899 #if (WITH_TARGET_WORD_BITSIZE == 32)
900 STATIC_INLINE_VM\
901 (void)
902 om_unpack_srs(vm *virtual,
903               sreg *srs,
904               cpu *processor,
905               unsigned_word cia)
906 {
907   int which_sr;
908   for (which_sr = 0; which_sr < nr_om_segment_tlb_entries; which_sr++) {
909     om_unpack_sr(virtual, srs, which_sr,
910                  processor, cia);
911   }
912 }
913 #endif
914
915
916 /* Rebuild all the data structures for the new context as specifed by
917    the passed registers */
918 INLINE_VM\
919 (void)
920 vm_synchronize_context(vm *virtual,
921                        spreg *sprs,
922                        sreg *srs,
923                        msreg msr,
924                        /**/
925                        cpu *processor,
926                        unsigned_word cia)
927 {
928
929   /* enable/disable translation */
930   int problem_state = (msr & msr_problem_state) != 0;
931   int data_relocate = (msr & msr_data_relocate) != 0;
932   int instruction_relocate = (msr & msr_instruction_relocate) != 0;
933   int little_endian = (msr & msr_little_endian_mode) != 0;
934
935   unsigned_word page_table_hash_mask;
936   unsigned_word real_address_of_page_table;
937  
938   /* update current processor mode */
939   virtual->instruction_map.translation.is_relocate = instruction_relocate;
940   virtual->instruction_map.translation.is_problem_state = problem_state;
941   virtual->data_map.translation.is_relocate = data_relocate;
942   virtual->data_map.translation.is_problem_state = problem_state;
943
944   /* update bat registers for the new context */
945   om_unpack_bats(&virtual->ibats, &sprs[spr_ibat0u], msr);
946   om_unpack_bats(&virtual->dbats, &sprs[spr_dbat0u], msr);
947
948   /* unpack SDR1 - the storage description register 1 */
949 #if (WITH_TARGET_WORD_BITSIZE == 64)
950   real_address_of_page_table = MASKED64(sprs[spr_sdr1], 0, 45);
951   page_table_hash_mask = MASK64(18+28-EXTRACTED64(sprs[spr_sdr1], 59, 63),
952                                 63-7);
953 #endif
954 #if (WITH_TARGET_WORD_BITSIZE == 32)
955   real_address_of_page_table = MASKED32(sprs[spr_sdr1], 0, 15);
956   page_table_hash_mask = (INSERTED32(EXTRACTED32(sprs[spr_sdr1], 23, 31),
957                                      7, 7+9-1)
958                           | MASK32(7+9, 31-6));
959 #endif
960   virtual->instruction_map.translation.real_address_of_page_table = real_address_of_page_table;
961   virtual->instruction_map.translation.page_table_hash_mask = page_table_hash_mask;
962   virtual->data_map.translation.real_address_of_page_table = real_address_of_page_table;
963   virtual->data_map.translation.page_table_hash_mask = page_table_hash_mask;
964
965
966   /* unpack the segment tlb registers */
967 #if (WITH_TARGET_WORD_BITSIZE == 32)
968   om_unpack_srs(virtual, srs,
969                 processor, cia);
970 #endif
971  
972   /* set up the XOR registers if the current endian mode conflicts
973      with what is in the MSR */
974   if (WITH_XOR_ENDIAN) {
975     int i = 1;
976     unsigned mask;
977     if ((little_endian && CURRENT_TARGET_BYTE_ORDER == LITTLE_ENDIAN)
978         || (!little_endian && CURRENT_TARGET_BYTE_ORDER == BIG_ENDIAN))
979       mask = 0;
980     else
981       mask = WITH_XOR_ENDIAN - 1;
982     while (i - 1 < WITH_XOR_ENDIAN) {
983       virtual->instruction_map.translation.xor[i-1] = mask;
984       virtual->data_map.translation.xor[i-1] =  mask;
985       mask = (mask << 1) & (WITH_XOR_ENDIAN - 1);
986       i = i * 2;
987     }
988   }
989   else {
990     /* don't allow the processor to change endian modes */
991     if ((little_endian && CURRENT_TARGET_BYTE_ORDER != LITTLE_ENDIAN)
992         || (!little_endian && CURRENT_TARGET_BYTE_ORDER != BIG_ENDIAN))
993       cpu_error(processor, cia, "attempt to change hardwired byte order");
994   }
995 }
996
997 /* update vm data structures due to a TLB operation */
998
999 INLINE_VM\
1000 (void)
1001 vm_page_tlb_invalidate_entry(vm *memory,
1002                              unsigned_word ea)
1003 {
1004   int i = om_page_tlb_index(ea);
1005   memory->instruction_tlb.entry[i].masked_virtual_segment_id = MASK(0, 63);
1006   memory->data_tlb.entry[i].masked_virtual_segment_id = MASK(0, 63);
1007   TRACE(trace_vm, ("ea=0x%lx - tlb invalidate entry\n", (long)ea));
1008 }
1009
1010 INLINE_VM\
1011 (void)
1012 vm_page_tlb_invalidate_all(vm *memory)
1013 {
1014   int i;
1015   for (i = 0; i < nr_om_page_tlb_entries; i++) {
1016     memory->instruction_tlb.entry[i].masked_virtual_segment_id = MASK(0, 63);
1017     memory->data_tlb.entry[i].masked_virtual_segment_id = MASK(0, 63);
1018   }
1019   TRACE(trace_vm, ("tlb invalidate all\n"));
1020 }
1021
1022
1023
1024 INLINE_VM\
1025 (vm_data_map *)
1026 vm_create_data_map(vm *memory)
1027 {
1028   return &memory->data_map;
1029 }
1030
1031
1032 INLINE_VM\
1033 (vm_instruction_map *)
1034 vm_create_instruction_map(vm *memory)
1035 {
1036   return &memory->instruction_map;
1037 }
1038
1039
1040 STATIC_INLINE_VM\
1041 (unsigned_word)
1042 vm_translate(om_map *map,
1043              unsigned_word ea,
1044              om_access_types access,
1045              cpu *processor,
1046              unsigned_word cia,
1047              int abort)
1048 {
1049   switch (CURRENT_ENVIRONMENT) {
1050   case USER_ENVIRONMENT:
1051   case VIRTUAL_ENVIRONMENT:
1052     return ea;
1053   case OPERATING_ENVIRONMENT:
1054     return om_translate_effective_to_real(map, ea, access,
1055                                           processor, cia,
1056                                           abort);
1057   default:
1058     error("internal error - vm_translate - bad switch");
1059     return 0;
1060   }
1061 }
1062
1063
1064 INLINE_VM\
1065 (unsigned_word)
1066 vm_real_data_addr(vm_data_map *map,
1067                   unsigned_word ea,
1068                   int is_read,
1069                   cpu *processor,
1070                   unsigned_word cia)
1071 {
1072   return vm_translate(&map->translation,
1073                       ea,
1074                       is_read ? om_data_read : om_data_write,
1075                       processor,
1076                       cia,
1077                       1); /*abort*/
1078 }
1079
1080
1081 INLINE_VM\
1082 (unsigned_word)
1083 vm_real_instruction_addr(vm_instruction_map *map,
1084                          cpu *processor,
1085                          unsigned_word cia)
1086 {
1087   return vm_translate(&map->translation,
1088                       cia,
1089                       om_instruction_read,
1090                       processor,
1091                       cia,
1092                       1); /*abort*/
1093 }
1094
1095 INLINE_VM\
1096 (instruction_word)
1097 vm_instruction_map_read(vm_instruction_map *map,
1098                         cpu *processor,
1099                         unsigned_word cia)
1100 {
1101   unsigned_word ra = vm_real_instruction_addr(map, processor, cia);
1102   ASSERT((cia & 0x3) == 0); /* always aligned */
1103   if (WITH_XOR_ENDIAN)
1104     ra ^= map->translation.xor[sizeof(instruction_word) - 1];
1105   return core_map_read_4(map->code, ra, processor, cia);
1106 }
1107
1108
1109 INLINE_VM\
1110 (int)
1111 vm_data_map_read_buffer(vm_data_map *map,
1112                         void *target,
1113                         unsigned_word addr,
1114                         unsigned nr_bytes,
1115                         cpu *processor,
1116                         unsigned_word cia)
1117 {
1118   unsigned count;
1119   for (count = 0; count < nr_bytes; count++) {
1120     unsigned_1 byte;
1121     unsigned_word ea = addr + count;
1122     unsigned_word ra = vm_translate(&map->translation,
1123                                     ea, om_data_read,
1124                                     processor, /*processor*/
1125                                     cia, /*cia*/
1126                                     processor != NULL); /*abort?*/
1127     if (ra == MASK(0, 63))
1128       break;
1129     if (WITH_XOR_ENDIAN)
1130       ra ^= map->translation.xor[0];
1131     if (core_map_read_buffer(map->read, &byte, ra, sizeof(byte))
1132         != sizeof(byte))
1133       break;
1134     ((unsigned_1*)target)[count] = T2H_1(byte);
1135   }
1136   return count;
1137 }
1138
1139
1140 INLINE_VM\
1141 (int)
1142 vm_data_map_write_buffer(vm_data_map *map,
1143                          const void *source,
1144                          unsigned_word addr,
1145                          unsigned nr_bytes,
1146                          int violate_read_only_section,
1147                          cpu *processor,
1148                          unsigned_word cia)
1149 {
1150   unsigned count;
1151   unsigned_1 byte;
1152   for (count = 0; count < nr_bytes; count++) {
1153     unsigned_word ea = addr + count;
1154     unsigned_word ra = vm_translate(&map->translation,
1155                                     ea, om_data_write,
1156                                     processor,
1157                                     cia,
1158                                     processor != NULL); /*abort?*/
1159     if (ra == MASK(0, 63))
1160       break;
1161     if (WITH_XOR_ENDIAN)
1162       ra ^= map->translation.xor[0];
1163     byte = T2H_1(((unsigned_1*)source)[count]);
1164     if (core_map_write_buffer((violate_read_only_section
1165                                ? map->read
1166                                : map->write),
1167                               &byte, ra, sizeof(byte)) != sizeof(byte))
1168       break;
1169   }
1170   return count;
1171 }
1172
1173
1174 /* define the read/write 1/2/4/8/word functions */
1175
1176 #define N 1
1177 #include "vm_n.h"
1178 #undef N
1179
1180 #define N 2
1181 #include "vm_n.h"
1182 #undef N
1183
1184 #define N 4
1185 #include "vm_n.h"
1186 #undef N
1187
1188 #define N 8
1189 #include "vm_n.h"
1190 #undef N
1191
1192 #define N word
1193 #include "vm_n.h"
1194 #undef N
1195
1196
1197
1198 #endif /* _VM_C_ */