-
Notifications
You must be signed in to change notification settings - Fork 18
/
pdp11_vmbox.vhd
704 lines (608 loc) · 25.2 KB
/
pdp11_vmbox.vhd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
-- $Id: pdp11_vmbox.vhd 1349 2023-01-11 14:52:42Z mueller $
-- SPDX-License-Identifier: GPL-3.0-or-later
-- Copyright 2006-2023 by Walter F.J. Mueller <W.F.J.Mueller@gsi.de>
--
------------------------------------------------------------------------------
-- Module Name: pdp11_vmbox - syn
-- Description: pdp11: virtual memory
--
-- Dependencies: pdp11_mmu
-- pdp11_ubmap
-- ibus/ib_sres_or_4
-- ibus/ib_sres_or_2
-- ibus/ib_sel
--
-- Test bench: tb/tb_pdp11_core (implicit)
-- Target Devices: generic
-- Tool versions: ise 8.2-14.7; viv 2014.4-2022.1; ghdl 0.18-2.0.0
--
-- Revision History:
-- Date Rev Version Comment
-- 2022-01-11 1349 1.6.11 use err_ser to indicate fatal stack error
-- 2022-12-17 1331 1.6.10 BUGFIX: request mmu trap also on ib accesses
-- 2022-11-21 1320 1.6.9 rename some rsv->ser; remove obsolete trap_done;
-- 2022-11-18 1317 1.6.8 BUGFIX: correct red/yellow zone boundary
-- 2019-06-22 1170 1.6.7 support membe for em cacc access
-- 2016-05-22 767 1.6.6 don't init N_REGS (vivado fix for fsm inference)
-- 2015-07-03 697 1.6.5 much wider DM_STAT_VM
-- 2015-04-04 662 1.6.4 atowidth now 6 (was 5) to support ibdr_rprm reset
-- 2011-11-18 427 1.6.3 now numeric_std clean
-- 2010-10-23 335 1.6.2 add r.paddr_iopage, use ib_sel
-- 2010-10-22 334 1.6.1 deassert ibus be's at end-cycle; fix rmw logic
-- 2010-10-17 333 1.6 implement ibus V2 interface
-- 2010-06-27 310 1.5 redo ibus driver logic, now ibus driven from flops
-- 2010-06-20 307 1.4.2 rename cpacc to cacc in vm_cntl_type, mmu_cntl_type
-- 2010-06-18 306 1.4.1 for cpacc: set cacc in ib_mreq, forward racc,be
-- from CP_ADDR; now all ibr handling via vmbox
-- 2010-06-13 305 1.4 rename CPADDR -> CP_ADDR
-- 2009-06-01 221 1.3.8 add dip signal in ib_mreq (set in s_ib)
-- 2009-05-30 220 1.3.7 final removal of snoopers (were already commented)
-- 2009-05-01 211 1.3.6 BUGFIX: add 177776 stack protect (SCCE)
-- 2008-08-22 161 1.3.5 rename pdp11_ibres_ -> ib_sres_, ubf_ -> ibf_
-- 2008-04-25 138 1.3.4 add BRESET port, clear stklim with BRESET
-- 2008-04-20 137 1.3.3 add DM_STAT_VM port
-- 2008-03-19 127 1.3.2 ignore ack state when waiting on a busy IB in s_ib
-- 2008-03-02 121 1.3.1 remove snoopers
-- 2008-02-24 119 1.3 revamp paddr generation; add _ubmap
-- 2008-02-23 118 1.2.1 use sys_conf_mem_losize
-- 2008-02-17 117 1.2 use em_(mreq|sres) interface for external memory
-- 2008-01-26 114 1.1.4 rename 'ubus' to 'ib' (proper name of intbus now)
-- 2008-01-05 110 1.1.3 update snooper.
-- rename IB_MREQ(ena->req) SRES(sel->ack, hold->busy)
-- 2008-01-01 109 1.1.2 Use IB_SRES_(CPU|EXT); use r./n. coding style, move
-- all status into regs_type. add intbus HOLD support.
-- 2007-12-30 108 1.1.1 use ubf_byte[01]
-- 2007-12-30 107 1.1 Use IB_MREQ/IB_SRES interface now; remove DMA port
-- 2007-09-16 83 1.0.2 Use ram_1swsr_wfirst_gen, not ram_2swsr_wfirst_gen
-- 2nd port was unused, connected ADDR caused slow net
-- 2007-06-14 56 1.0.1 Use slvtypes.all
-- 2007-05-12 26 1.0 Initial version
------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.slvtypes.all;
use work.iblib.all;
use work.pdp11.all;
use work.sys_conf.all;
-- ----------------------------------------------------------------------------
entity pdp11_vmbox is -- virtual memory
port (
CLK : in slbit; -- clock
GRESET : in slbit; -- general reset
CRESET : in slbit; -- cpu reset
BRESET : in slbit; -- bus reset
CP_ADDR : in cp_addr_type; -- console port address
VM_CNTL : in vm_cntl_type; -- vm control port
VM_ADDR : in slv16; -- vm address
VM_DIN : in slv16; -- vm data in
VM_STAT : out vm_stat_type; -- vm status port
VM_DOUT : out slv16; -- vm data out
EM_MREQ : out em_mreq_type; -- external memory: request
EM_SRES : in em_sres_type; -- external memory: response
MMU_MONI : in mmu_moni_type; -- mmu monitor port
IB_MREQ_M : out ib_mreq_type; -- ibus request (master)
IB_SRES_CPU : in ib_sres_type; -- ibus response (CPU registers)
IB_SRES_EXT : in ib_sres_type; -- ibus response (external devices)
DM_STAT_VM : out dm_stat_vm_type -- debug and monitor status
);
end pdp11_vmbox;
architecture syn of pdp11_vmbox is
constant ibaddr_slim : slv16 := slv(to_unsigned(8#177774#,16));
constant atowidth : natural := 6; -- size of access timeout counter
-- ! rbus tout must be > ibus tout !
-- ! ensure all BTOWIDTH > atowidth !
type state_type is (
s_idle, -- s_idle: wait for vm_cntl request
s_mem_w, -- s_mem_w: check mmu, wait for memory
s_ib_w, -- s_ib_w: wait for ibus
s_ib_wend, -- s_ib_wend: ibus write completion
s_ib_rend, -- s_ib_rend: ibus read completion
s_idle_mw_ib, -- s_idle_mw_ib: wait macc write (ibus)
s_idle_mw_mem, -- s_idle_mw_mem: wait macc write (mem)
s_mem_mw_w, -- s_mem_mw_w: wait for memory (macc)
s_fail, -- s_fail: vmbox fatal error catcher
s_errrsv, -- s_errrsv: red stack violation
s_errib -- s_errib: ibus error handler
);
type regs_type is record -- state registers
state : state_type; -- state
wacc : slbit; -- write access
macc : slbit; -- modify access (r-m-w sequence)
cacc : slbit; -- console access
bytop : slbit; -- byte operation
kstack : slbit; -- access through kernel stack
ysv : slbit; -- yellow stack violation detected
vaok : slbit; -- virtual address valid (from MMU)
trap_mmu : slbit; -- mmu trap requested
mdin : slv16; -- data input (memory order)
paddr : slv22; -- physical address register
paddr_iopage : slv9; -- iopage base (upper 9 bits of paddr)
atocnt : slv(atowidth-1 downto 0); -- access timeout counter
ibre : slbit; -- ibus re signal
ibwe : slbit; -- ibus we signal
ibbe : slv2; -- ibus be0,be1 signals
ibrmw : slbit; -- ibus rmw signal
ibcacc : slbit; -- ibus cacc signal
ibracc : slbit; -- ibus racc signal
ibdout : slv16; -- ibus dout register
end record regs_type;
constant atocnt_init : slv(atowidth-1 downto 0) := (others=>'1');
constant regs_init : regs_type := (
s_idle, -- state
'0','0','0','0', -- wacc,macc,cacc,bytop
'0','0','0','0', -- kstack,ysv,vaok,trap_mmu
(others=>'0'), -- mdin
(others=>'0'), -- paddr
(others=>'0'), -- paddr_iopage
atocnt_init, -- atocnt
'0','0',"00", -- ibre,ibwe,ibbe
'0','0','0', -- ibrmw,ibcacc,ibracc
(others=>'0') -- ibdout
);
signal R_REGS : regs_type := regs_init;
signal N_REGS : regs_type; -- don't init (vivado fix for fsm infer)
signal R_SLIM : slv8 := (others=>'0'); -- stack limit register
signal MMU_CNTL : mmu_cntl_type := mmu_cntl_init;
signal MMU_STAT : mmu_stat_type := mmu_stat_init;
signal PADDRH : slv16 := (others=>'0');
signal IBSEL_SLIM :slbit := '0'; -- select stack limit reg
signal IB_SRES_SLIM : ib_sres_type := ib_sres_init;
signal IB_SRES_MMU : ib_sres_type := ib_sres_init;
signal IB_SRES_UBMAP : ib_sres_type := ib_sres_init;
signal UBMAP_MREQ : slbit := '0';
signal UBMAP_ADDR_PM : slv22_1 := (others=>'0');
signal VM_STAT_L : vm_stat_type := vm_stat_init; -- vm status (local)
signal VM_DOUT_L : slv16 := (others=>'0'); -- vm data out (local)
signal IB_MREQ : ib_mreq_type := ib_mreq_init; -- ibus request (local)
signal IB_SRES : ib_sres_type := ib_sres_init; -- ibus response (local)
signal IB_SRES_INT : ib_sres_type := ib_sres_init; -- ibus response (cpu)
signal EM_MREQ_L : em_mreq_type := em_mreq_init; -- ext mem: request (local)
begin
MMU : pdp11_mmu
port map (
CLK => CLK,
CRESET => CRESET,
BRESET => BRESET,
CNTL => MMU_CNTL,
VADDR => VM_ADDR,
MONI => MMU_MONI,
STAT => MMU_STAT,
PADDRH => PADDRH,
IB_MREQ => IB_MREQ,
IB_SRES => IB_SRES_MMU
);
UBMAP : pdp11_ubmap
port map (
CLK => CLK,
MREQ => UBMAP_MREQ,
ADDR_UB => CP_ADDR.addr(17 downto 1),
ADDR_PM => UBMAP_ADDR_PM,
IB_MREQ => IB_MREQ,
IB_SRES => IB_SRES_UBMAP
);
SRES_OR_INT : ib_sres_or_4
port map (
IB_SRES_1 => IB_SRES_CPU,
IB_SRES_2 => IB_SRES_SLIM,
IB_SRES_3 => IB_SRES_MMU,
IB_SRES_4 => IB_SRES_UBMAP,
IB_SRES_OR => IB_SRES_INT
);
SRES_OR_ALL : ib_sres_or_2
port map (
IB_SRES_1 => IB_SRES_INT,
IB_SRES_2 => IB_SRES_EXT,
IB_SRES_OR => IB_SRES
);
SEL : ib_sel
generic map (
IB_ADDR => ibaddr_slim)
port map (
CLK => CLK,
IB_MREQ => IB_MREQ,
SEL => IBSEL_SLIM
);
proc_ibres : process (IBSEL_SLIM, IB_MREQ, R_SLIM)
variable idout : slv16 := (others=>'0');
begin
idout := (others=>'0');
if IBSEL_SLIM = '1' then
idout(ibf_byte1) := R_SLIM;
end if;
IB_SRES_SLIM.dout <= idout;
IB_SRES_SLIM.ack <= IBSEL_SLIM and (IB_MREQ.re or IB_MREQ.we); -- ack all
IB_SRES_SLIM.busy <= '0';
end process proc_ibres;
proc_slim: process (CLK)
begin
if rising_edge(CLK) then
if BRESET = '1' then
R_SLIM <= (others=>'0');
elsif IBSEL_SLIM='1' and IB_MREQ.we='1' then
if IB_MREQ.be1 = '1' then
R_SLIM <= IB_MREQ.din(ibf_byte1);
end if;
end if;
end if;
end process proc_slim;
proc_regs: process (CLK)
begin
if rising_edge(CLK) then
if GRESET = '1' then
R_REGS <= regs_init;
else
R_REGS <= N_REGS;
end if;
end if;
end process proc_regs;
proc_next: process (R_REGS, R_SLIM, CP_ADDR, VM_CNTL, VM_DIN, VM_ADDR,
IB_SRES, UBMAP_ADDR_PM,
EM_SRES, MMU_STAT, PADDRH)
variable r : regs_type := regs_init;
variable n : regs_type := regs_init;
variable ivm_stat : vm_stat_type := vm_stat_init;
variable ivm_dout : slv16 := (others=>'0');
variable iem_mreq : em_mreq_type := em_mreq_init;
variable immu_cntl : mmu_cntl_type := mmu_cntl_init;
variable ipaddr : slv22 := (others=>'0');
variable ipaddr_iopage : slv9 := (others=>'0');
variable iib_aval : slbit := '0';
variable ato_go : slbit := '0';
variable ato_end : slbit := '0';
variable is_stackyellow : slbit := '1'; -- VM_ADDR in yellow stack zone
variable is_stackred : slbit := '1'; -- VM_ADDR in red stack zone
variable iubmap_mreq : slbit := '0';
variable paddr_mmu : slbit := '0';
variable paddr_sel : slv2 := "00";
constant c_paddr_sel_vmaddr : slv2 := "00";
constant c_paddr_sel_rpaddr : slv2 := "01";
constant c_paddr_sel_cacc : slv2 := "10";
constant c_paddr_sel_ubmap : slv2 := "11";
begin
r := R_REGS;
n := R_REGS;
n.state := s_fail;
ivm_stat := vm_stat_init;
ivm_dout := EM_SRES.dout;
immu_cntl := mmu_cntl_init;
iib_aval := '0';
iem_mreq := em_mreq_init;
iem_mreq.din := VM_DIN;
if VM_CNTL.cacc = '1' then -- if cacc access
iem_mreq.be := CP_ADDR.be; -- use membe setup
elsif VM_CNTL.bytop = '0' then -- if word access
iem_mreq.be := "11"; -- both be's
else
if VM_ADDR(0) = '0' then -- if low byte
iem_mreq.be := "01";
else -- if high byte
iem_mreq.be := "10";
iem_mreq.din(ibf_byte1) := VM_DIN(ibf_byte0);
end if;
end if;
iubmap_mreq :='0';
paddr_mmu := '1'; -- ipaddr selector, used in s_idle
-- and overwritten in s_idle_mw_mem
paddr_sel := "00";
if MMU_STAT.ena_mmu='0' or VM_CNTL.cacc='1' then
paddr_mmu := '0';
paddr_sel := c_paddr_sel_vmaddr;
if VM_CNTL.cacc = '1' then
if CP_ADDR.ena_ubmap='1' and MMU_STAT.ena_ubmap='1' then
paddr_sel := c_paddr_sel_ubmap;
else
paddr_sel := c_paddr_sel_cacc;
end if;
end if;
end if;
-- the iopage base is determined based on mmu regs and request type
-- r.paddr_iopage is updated during s_idle. This way the iopage base
-- address is determined in parallel to paddr and latched at end of s_idle.
-- Note: is VM_CNTL.cacc here, the status in s_idle is relevant !
ipaddr_iopage := "111111111"; -- iopage match pattern (for 22 bit)
if VM_CNTL.cacc = '1' then
if CP_ADDR.ena_22bit = '0' then
ipaddr_iopage := "000000111"; -- 16 bit cacc
end if;
else
if MMU_STAT.ena_mmu = '0' then
ipaddr_iopage := "000000111"; -- 16 bit mode
else
if MMU_STAT.ena_22bit = '0' then
ipaddr_iopage := "000011111"; -- 18 bit mode
end if;
end if;
end if;
ato_go := '0'; -- default: keep access timeout in reset
ato_end := '0';
if unsigned(r.atocnt) = 0 then -- if access timeout count at zero
ato_end := '1'; -- signal expiration
end if;
is_stackyellow := '0';
is_stackred := '0';
if unsigned(VM_ADDR(15 downto 8)) <= unsigned(R_SLIM) then
if unsigned(VM_ADDR(15 downto 8)) = unsigned(R_SLIM) and
unsigned(VM_ADDR(7 downto 5)) = 7 then
is_stackyellow := '1';
else
is_stackred := '1';
end if;
end if;
if VM_ADDR(15 downto 1) = "111111111111111" then -- PSW protection
is_stackred := '1';
end if;
immu_cntl.wacc := VM_CNTL.wacc;
immu_cntl.macc := VM_CNTL.macc;
immu_cntl.cacc := VM_CNTL.cacc;
immu_cntl.dspace := VM_CNTL.dspace;
immu_cntl.mode := VM_CNTL.mode;
case r.state is
when s_idle => -- s_idle: wait for vm_cntl request --
n.state := s_idle;
iubmap_mreq := '1'; -- activate ubmap always in s_idle
if VM_CNTL.req = '1' then
n.wacc := VM_CNTL.wacc;
n.macc := VM_CNTL.macc;
n.cacc := VM_CNTL.cacc;
n.bytop := VM_CNTL.bytop;
n.kstack := VM_CNTL.kstack;
n.ysv := '0';
n.vaok := MMU_STAT.vaok;
n.trap_mmu := MMU_STAT.trap;
n.mdin := iem_mreq.din;
-- n.paddr assignment handled separately in 'if state=s_idle' at the
-- end.
immu_cntl.req := '1';
if VM_CNTL.wacc='1' and VM_CNTL.macc='1' then
n.state := s_fail;
elsif VM_CNTL.kstack='1' and VM_CNTL.vecser='0' and
is_stackred='1' then
n.state := s_errrsv;
else
iem_mreq.req := '1';
iem_mreq.we := VM_CNTL.wacc;
if VM_CNTL.kstack='1' and VM_CNTL.vecser='0' then
n.ysv := is_stackyellow;
end if;
n.state := s_mem_w;
end if;
end if;
when s_mem_w => -- s_mem_w: check mmu, wait for memory
if r.bytop='0' and r.paddr(0)='1' then -- odd address ?
ivm_stat.err := '1';
ivm_stat.err_odd := '1';
ivm_stat.err_ser := r.kstack; -- escalate to ser if kstack
iem_mreq.cancel := '1'; -- cancel pending mem request
n.state := s_idle;
elsif r.vaok = '0' then -- MMU abort ?
ivm_stat.err := '1';
ivm_stat.err_mmu := '1';
ivm_stat.err_ser := r.kstack; -- escalate to ser if kstack
iem_mreq.cancel := '1'; -- cancel pending mem request
n.state := s_idle;
else
if r.paddr(21 downto 13) = r.paddr_iopage then
-- I/O page decoded
iem_mreq.cancel := '1'; -- cancel pending mem request
iib_aval := '1'; -- declare ibus addr valid
n.ibre := not r.wacc;
n.ibwe := r.wacc;
n.ibcacc := r.cacc;
n.ibracc := r.cacc and CP_ADDR.racc;
n.ibbe := "11";
if r.cacc = '1' then -- console access ?
n.ibbe := CP_ADDR.be;
else -- cpu access ?
if r.bytop = '1' then
if r.paddr(0) = '0' then
n.ibbe(1) := '0';
else
n.ibbe(0) := '0';
end if;
end if;
end if;
n.ibrmw := r.macc;
n.state := s_ib_w;
else
if unsigned(r.paddr(21 downto 6)) > sys_conf_mem_losize then
ivm_stat.err := '1';
ivm_stat.err_nxm := '1';
ivm_stat.err_ser := r.kstack; -- escalate to ser if kstack
iem_mreq.cancel := '1'; -- cancel pending mem request
n.state := s_idle;
else
if EM_SRES.ack_r='1' or EM_SRES.ack_w='1' then
ivm_stat.ack := '1';
if r.macc='1' and r.wacc='0' then
n.state := s_idle_mw_mem;
else
n.state := s_idle;
end if;
else
n.state := s_mem_w; -- keep waiting
end if;
end if;
end if;
end if;
when s_ib_w => -- s_ib_w: wait for ibus -------------
ato_go := '1'; -- activate timeout counter
iib_aval := '1'; -- declare ibus addr valid
n.ibre := '0'; -- end cycle, unless busy seen
n.ibwe := '0';
n.ibrmw := '0';
n.ibbe := "00";
n.ibcacc := '0';
n.ibracc := '0';
if IB_SRES.ack='1' and IB_SRES.busy='0' then -- ibus cycle finished
if r.wacc = '1' then
n.state := s_ib_wend;
else
if r.macc = '1' then -- if first part of rmw
n.ibrmw := r.macc; -- keep rmw
n.ibbe := r.ibbe; -- keep be's
n.ibcacc := r.ibcacc;
n.ibracc := r.ibracc;
end if;
n.ibdout := IB_SRES.dout;
n.state := s_ib_rend;
end if;
elsif IB_SRES.busy='1' and ato_end='0' then
n.ibre := r.ibre; -- continue ibus cycle
n.ibwe := r.ibwe;
n.ibrmw := r.ibrmw;
n.ibbe := r.ibbe;
n.ibcacc := r.ibcacc;
n.ibracc := r.ibracc;
n.state := s_ib_w;
else
n.state := s_errib;
end if;
when s_ib_wend => -- s_ib_wend: ibus write completion --
ivm_stat.ack := '1';
n.state := s_idle;
when s_ib_rend => -- s_ib_rend: ibus read completion ---
ivm_stat.ack := '1';
ivm_dout := r.ibdout;
if r.macc='1' then -- first part of read-mod-write
iib_aval := '1'; -- keep ibus addr valid
n.state := s_idle_mw_ib;
else
n.state := s_idle;
end if;
when s_idle_mw_ib => -- s_idle_mw_ib: wait macc write (ibus)
n.state := s_idle_mw_ib;
iib_aval := '1'; -- keep ibus addr valid
if r.ibbe = "10" then
iem_mreq.din(ibf_byte1) := VM_DIN(ibf_byte0);
end if;
if VM_CNTL.req = '1' then
n.wacc := VM_CNTL.wacc;
n.macc := VM_CNTL.macc;
n.mdin := iem_mreq.din;
if VM_CNTL.wacc='0' or VM_CNTL.macc='0' then
n.state := s_fail;
else
n.ibwe := '1'; -- Note: all other ibus drivers
-- already set in 1st part
n.state := s_ib_w;
end if;
end if;
when s_idle_mw_mem => -- s_idle_mw_mem: wait macc write (mem)
n.state := s_idle_mw_mem;
paddr_mmu := '0';
paddr_sel := c_paddr_sel_rpaddr;
if VM_CNTL.bytop = '0' then -- if word access
iem_mreq.be := "11"; -- both be's
else
if r.paddr(0) = '0' then -- if low byte
iem_mreq.be := "01";
else -- if high byte
iem_mreq.be := "10";
iem_mreq.din(ibf_byte1) := VM_DIN(ibf_byte0);
end if;
end if;
if VM_CNTL.req = '1' then
n.wacc := VM_CNTL.wacc;
n.macc := VM_CNTL.macc;
n.bytop := VM_CNTL.bytop;
n.mdin := iem_mreq.din;
if VM_CNTL.wacc='0' or VM_CNTL.macc='0' then
n.state := s_fail;
else
iem_mreq.req := '1';
iem_mreq.we := '1';
n.state := s_mem_mw_w;
end if;
end if;
when s_mem_mw_w => -- s_mem_mw_w: wait for memory (macc)
if EM_SRES.ack_w = '1' then
ivm_stat.ack := '1';
n.state := s_idle;
else
n.state := s_mem_mw_w; -- keep waiting
end if;
when s_fail => -- s_fail: vmbox fatal error catcher
ivm_stat.fail := '1';
n.state := s_idle;
when s_errrsv => -- s_errrsv: red stack violation -----
ivm_stat.err := '1';
ivm_stat.err_rsv := '1';
ivm_stat.err_ser := '1'; -- an rsv is always a ser
n.state := s_idle;
when s_errib => -- s_errib: ibus error handler -------
ivm_stat.err := '1';
ivm_stat.err_iobto := '1';
ivm_stat.err_ser := r.kstack; -- escalate to ser if kstack
n.state := s_idle;
when others => null;
end case;
if r.bytop='1' and r.paddr(0)='1' then
ivm_dout(ibf_byte0) := ivm_dout(ibf_byte1);
end if;
if ato_go = '0' then -- handle access timeout counter
n.atocnt := atocnt_init; -- if ato_go=0, keep in reset
else
n.atocnt := slv(unsigned(r.atocnt) - 1);-- otherwise count down
end if;
ipaddr := (others=>'0');
if paddr_mmu = '1' then
ipaddr( 5 downto 0) := VM_ADDR(5 downto 0);
ipaddr(21 downto 6) := PADDRH;
if MMU_STAT.ena_22bit = '0' then
ipaddr(21 downto 18) := (others=>'0');
end if;
else
case paddr_sel is
when c_paddr_sel_vmaddr =>
ipaddr(15 downto 0) := VM_ADDR(15 downto 0);
when c_paddr_sel_rpaddr =>
ipaddr := r.paddr;
when c_paddr_sel_cacc =>
ipaddr := CP_ADDR.addr & '0';
if CP_ADDR.ena_22bit = '0' then
ipaddr(21 downto 16) := (others=>'0');
end if;
when c_paddr_sel_ubmap =>
ipaddr := UBMAP_ADDR_PM & '0';
when others => null;
end case;
end if;
if r.state = s_idle then
n.paddr := ipaddr;
n.paddr_iopage := ipaddr_iopage;
end if;
ivm_stat.trap_ysv := r.ysv; -- request ysv trap if condition seen
ivm_stat.trap_mmu := r.trap_mmu; -- forward mmu trap request
iem_mreq.addr := ipaddr(21 downto 1);
N_REGS <= n;
UBMAP_MREQ <= iubmap_mreq;
IB_MREQ.aval <= iib_aval;
IB_MREQ.re <= r.ibre;
IB_MREQ.we <= r.ibwe;
IB_MREQ.be0 <= r.ibbe(0);
IB_MREQ.be1 <= r.ibbe(1);
IB_MREQ.rmw <= r.ibrmw;
IB_MREQ.cacc <= r.ibcacc;
IB_MREQ.racc <= r.ibracc;
IB_MREQ.addr <= r.paddr(12 downto 1);
IB_MREQ.din <= r.mdin;
VM_STAT_L <= ivm_stat;
VM_DOUT_L <= ivm_dout;
MMU_CNTL <= immu_cntl;
EM_MREQ_L <= iem_mreq;
end process proc_next;
VM_STAT <= VM_STAT_L;
VM_DOUT <= VM_DOUT_L;
IB_MREQ_M <= IB_MREQ; -- external drive master port
EM_MREQ <= EM_MREQ_L;
DM_STAT_VM.vmcntl <= VM_CNTL;
DM_STAT_VM.vmaddr <= VM_ADDR;
DM_STAT_VM.vmdin <= VM_DIN;
DM_STAT_VM.vmstat <= VM_STAT_L;
DM_STAT_VM.vmdout <= VM_DOUT_L;
DM_STAT_VM.ibmreq <= IB_MREQ;
DM_STAT_VM.ibsres <= IB_SRES;
DM_STAT_VM.emmreq <= EM_MREQ_L;
DM_STAT_VM.emsres <= EM_SRES;
end syn;