-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathi80386.vhd
1219 lines (1170 loc) · 56.8 KB
/
i80386.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
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
------------------------------------------------------------------------------
-- --
-- Intel 80386 VHDL model --
-- Copyright (C) Convergent, Inc. 1988 --
-- --
-- File: i80386.vhd --
-- Revision: E0.1 --
-- Date Created: 6-12-1988 --
-- Author: Mark Dakur --
-- Function: This VHDL model emulates the Intel 80386 32-bit CPU --
-- to the instruction and bus timing level. --
-- Generics: Debug 1=Enable Reporting of Model Status. --
-- 0=None (Default) --
-- Inst --
-- Performance --
-- Speed --
-- Target Simulator: ViewSim --
-- --
-- Reference Material: Intel Data Book, 80386-20, Oct., 1987 --
-- Intel 80386 Programmers Reference, 1986 --
-- 80386 Technical Reference, Edmund Strauss, 1987 --
-- --
-- Verification: No --
-- Validation: No --
-- Certification: No --
-- --
-- Behavioral models have two main parts: a package declaration and its --
-- corresponding package body, and an entity declaration and its --
-- corresponding architecture body. The package declaration and --
-- package body define subprograms used by the behavioral model; --
-- the entity declaration and architecture body define the behavior --
-- of the model. --
-- This file contains the entity declaration and architecture. --
------------------------------------------------------------------------------
------------------------------------------------------------------------------
-- Specification --
-- --
-- 1.0 Introduction --
-- 2.0 Description --
-- --
-- The i80386 consists of 6 functional units defined as follows: --
-- --
-- 1) Bus Interface Unit {BIunit} --
-- Accepts internal requests for code fetches from the CPunit and --
-- data transfers from the Eunit and prioritizes the requests. --
-- It is the interface to the external pins (ports) of the package. --
-- --
-- 2) Code Prefetch Unit {CPunit} --
-- Performs the program look ahead function. When the BIunit is not --
-- performing bus cycles to execute an instruction, it uses the BIunit --
-- to to fetch sequentially along the instruction byte stream. These --
-- prefetched instructions are stored in the 16-byte Code Queue to --
-- await processing by the IDunit. --
-- --
-- 3) Instruction Decode Unit {IDunit} --
-- a) Instructions Supported: --
-- 1) nop --
-- 2) mov eax,"immediate 32 bit data" --
-- 3) mov ebx,"immediate 32 bit data" --
-- 4) mov eax,[ebx] --
-- 5) mov [ebx],eax --
-- 6) in al,"byte address" --
-- 7) out "byte address",al --
-- 8) inc eax --
-- 9) inc ebx --
-- 10) jmp "label" (relative nears and shorts) --
-- --
-- 4) Execution Unit {Eunit} --
-- a) Control Unit {Cunit} --
-- b) Data Unit {Dunit} --
-- c) Protection Test Unit {PTunit} --
-- --
-- 5) Segmentation Unit {Sunit} --
-- --
-- 6) Paging Unit {Punit} --
-- a) Page Translator Unit {PTunit} --
-- i) Translation Lookaside Buffer {TLB} --
-- a) Page Directory --
-- b) Page Table --
------------------------------------------------------------------------------
------------------------------------------------------------------------------
-- Revision History --
-- --
-- Revision --
-- Level Date Engineer Description --
-- -------- ------- --------------- --------------------------------------- --
-- E0.1 6-12-88 Dakur First Release --
------------------------------------------------------------------------------
------------------------------------------------------------------------------
--
-- Entity declaration for i80386:
--
-- The following entity declaration begins the definition of the
-- behavioral model of the i80386. It declares the model's name
-- and its IO signals, or ports. This declaration defines the
-- model's interface with enclosing designs; it defines the part
-- of the model that is externally visible. Following this
-- entity declaration is its corresponding architecture body;
-- the architecture body defines the behavior of the model.
--
-----------------------------------------------------------------------
PACKAGE i80386 is
FUNCTION tohex (CONSTANT value, Bytes: IN INTEGER) RETURN integer;
END i80386;
PACKAGE BODY i80386 is
FUNCTION tohex (CONSTANT value, Bytes: IN INTEGER) RETURN integer IS
VARIABLE dWord: vlbit_1d(31 downto 0);
VARIABLE Byte: vlbit_1d(31 downto 0);
VARIABLE Count: INTEGER;
BEGIN
Count := 1;
dWord := vlbit_vector(value);
Convert: WHILE Count <= Bytes LOOP
CASE integer(Bytes) is
WHEN 4 =>
CASE Count is
WHEN 1 =>
Byte := X"000000" & dWord(31 downto 24);
WHEN 2 =>
Byte := X"000000" & dWord(23 downto 16);
WHEN 3 =>
Byte := X"000000" & dWord(15 downto 8);
WHEN 4 =>
Byte := X"000000" & dWord(7 downto 0);
WHEN OTHERS => NULL;
END CASE;
WHEN 2 =>
CASE Count is
WHEN 1 =>
Byte := X"000000" & dWord(15 downto 8);
WHEN 2 =>
Byte := X"000000" & dWord(7 downto 0);
WHEN OTHERS => NULL;
END CASE;
WHEN 1 =>
Byte := X"000000" & dWord(7 downto 0);
WHEN OTHERS => NULL;
END CASE;
Count := Count + 1;
CASE integer(Byte(7 downto 4)) is
WHEN 15 =>
put("F");
WHEN 14 =>
put("E");
WHEN 13 =>
put("D");
WHEN 12 =>
put("C");
WHEN 11 =>
put("B");
WHEN 10 =>
put("A");
WHEN 9 =>
put("9");
WHEN 8 =>
put("8");
WHEN 7 =>
put("7");
WHEN 6 =>
put("6");
WHEN 5 =>
put("5");
WHEN 4 =>
put("4");
WHEN 3 =>
put("3");
WHEN 2 =>
put("2");
WHEN 1 =>
put("1");
WHEN 0 =>
put("0");
WHEN OTHERS => put("X");
END CASE;
CASE integer(Byte(3 downto 0)) is
WHEN 15 =>
put("F");
WHEN 14 =>
put("E");
WHEN 13 =>
put("D");
WHEN 12 =>
put("C");
WHEN 11 =>
put("B");
WHEN 10 =>
put("A");
WHEN 9 =>
put("9");
WHEN 8 =>
put("8");
WHEN 7 =>
put("7");
WHEN 6 =>
put("6");
WHEN 5 =>
put("5");
WHEN 4 =>
put("4");
WHEN 3 =>
put("3");
WHEN 2 =>
put("2");
WHEN 1 =>
put("1");
WHEN 0 =>
put("0");
WHEN OTHERS => put("X");
END CASE;
END LOOP Convert;
put("h");
RETURN 1;
END tohex;
END i80386;
USE work.i80386.tohex;
entity i80386 is
GENERIC (CONSTANT Debug: BOOLEAN := FALSE;
CONSTANT Inst: BOOLEAN := FALSE;
CONSTANT Performance: INTEGER := 1;
CONSTANT Speed: INTEGER := 32);
-- USE: Pass a value to the above generics from attributes attached to the 80386 symbol
-- on the schematic.
-- Description: Debug; A value of integer 1 (one) means that the model will output
-- status information as simulation progresses. The default if no attribute exists is
-- FALSE, or no status reported.
-- Inst; A value of interger 1 (one) means that the model will output
-- instructions. The Debug generic overides this one.
-- Performance; 0=min, 1=typ, 2=max
-- Speed; Processor speed choices, values are: 0=16MHz, 1=20MHz, 2=25MHZ, 3=30MHz
port (BE_n: out vlbit_1d(3 downto 0) := B"0000";
Address: out vlbit_1d(31 downto 2) := B"111111111111111111111111111111";
W_R_n: out vlbit := '0';
D_C_n: out vlbit := '1';
M_IO_n: out vlbit := '0';
LOCK_n, ADS_n: out vlbit := '1';
HLDA: out vlbit := '0';
Data: inout vlbit_1d(31 downto 0) := X"ZZZZZZZZ";
CLK2: in vlbit := '0';
NA_n, BS16_n: in vlbit := '1';
READY_n, HOLD, PERQ: in vlbit := '0';
BUSY_n, ERROR_n: in vlbit := '1';
INTR: in vlbit := '0';
NMI, RESET: in vlbit := '0');
-- THE ORDER OF THE PORTS IS IMPORTANT FOR COMPATIBILITY WITH THE "PINORDER"
-- ATTRIBUTE ON THE SYMBOL FOR THIS MODEL.
end i80386;
-----------------------------------------------------------------------
-----------------------------------------------------------------------
--
-- Architecture Body of i80386:
--
-- The following architecture body defines the behavior of the i80386
-- model. It consists of a set of process statements and other
-- concurrent statements. These statements are all invoked when
-- simulation begins, and continue to execute concurrently throughout
-- simulation. The statements communicate via the internal signals
-- declared at the top of the architecture body. Each statement either
-- checks the validity of input signals, or modifies the values of
-- output signals or internal signals in response to changes on input
-- signals or internal signals.
--
-----------------------------------------------------------------------
architecture behavior of i80386 is
-- Internal Signals
-- These information paths allow for communication between Concurent
-- Process Blocks within the model. All signals that are defined here have
-- global visibility. Signals, variables and constants defined within process
-- blocks have local visibility within that process ONLY.
SIGNAL CLK: vlbit := '1'; -- 80386 internal clock=CLK2 / 2
SIGNAL StateNA: vlbit := '1';
SIGNAL StateBS16: vlbit := '1';
SIGNAL RequestPending: vlbit := '1';
CONSTANT Pending: vlbit := '1';
CONSTANT NotPending: vlbit := '0';
SIGNAL NonAligned: vlbit := '0';
SIGNAL ReadRequest: vlbit := '1';
SIGNAL MemoryFetch: vlbit := '1';
SIGNAL CodeFetch: vlbit := '1';
SIGNAL ByteEnable: vlbit_1d(3 downto 0) := X"0";
SIGNAL DataWidth: vlbit_1d(31 downto 0) := X"00000002";
CONSTANT WidthByte: INTEGER := 0; -- Byte
CONSTANT WidthWord: INTEGER := 1; -- Word (2 bytes)
CONSTANT WidthDword: INTEGER := 2; -- Dword (4 bytes)
SIGNAL dWord: vlbit_1d(31 downto 0) := X"00000000";
SIGNAL State: vlbit_1d(31 downto 0) := X"00000000"; -- State Register, Initialized to StateTi
CONSTANT StateTi: INTEGER := 0; -- Reset State
CONSTANT StateT1: INTEGER := 1; -- First state of a non-pipelined bus cycle
CONSTANT StateT2: INTEGER := 2; -- State where NA_n is false (non-pipelined)
CONSTANT StateT1P: INTEGER := 3; -- First state of a pipelined bus cycle
CONSTANT StateTh: INTEGER := 4; -- Hold acknowledge state
CONSTANT StateT2P: INTEGER := 5; -- Subsequent state of a pipelined bus cycle
CONSTANT StateT2I: INTEGER := 6; -- Subsequent state of a potential pipelined
-- bus cycle.
-- The constants are indexes into the vector State where each constant represents 1 bit of the vector.
-- Internal User Registers
--- General Purpose Data and Address
SIGNAL EAX: vlbit_1d(31 DOWNTO 0);
SIGNAL EDX: vlbit_1d(31 DOWNTO 0);
SIGNAL ECX: vlbit_1d(31 DOWNTO 0);
SIGNAL EBX: vlbit_1d(31 DOWNTO 0);
SIGNAL EBP: vlbit_1d(31 DOWNTO 0);
SIGNAL ESI: vlbit_1d(31 DOWNTO 0);
SIGNAL EDI: vlbit_1d(31 DOWNTO 0);
SIGNAL ESP: vlbit_1d(31 DOWNTO 0);
-- NOTE: Create a proceedure that can be called with the appropriate mnemonic
-- to access the appropriate register. Futher work must be done to implement
-- the 16-bit and 8-bit versions of these registers.
--- Segment Selectors
SIGNAL CS: vlbit_1d(15 DOWNTO 0); -- Code Segment
SIGNAL SS: vlbit_1d(15 DOWNTO 0); -- Stack Segment
SIGNAL DS: vlbit_1d(15 DOWNTO 0); -- Data Segment Module A
SIGNAL ES: vlbit_1d(15 DOWNTO 0); -- Data Segment Structure 1
SIGNAL FSS: vlbit_1d(15 DOWNTO 0); -- Data Segment Structure 2
SIGNAL GS: vlbit_1d(15 DOWNTO 0); -- Data Segment Structure 3
--- Segment Descripters
--- These register are associated with each Segment Selector Register and are
--- not visible to the programmer.
--- Instruction Pointer and Flags
SIGNAL rEIP: vlbit_1d(31 downto 0) := X"FFFFFFF0";
-- Must create a proceedure to access by mnemonic the IP within the EIP register.
SIGNAL rEFLAGS: vlbit_1d(31 downto 0) := B"XXXXXXXXXXXXXXXX0XXXXXXXXX0X0X1X";
CONSTANT VM: INTEGER := 0;
CONSTANT RF: INTEGER := 0;
CONSTANT NT: INTEGER := 0;
CONSTANT IOPL: INTEGER := 0;
CONSTANT xOF: INTEGER := 0;
CONSTANT DF: INTEGER := 0;
CONSTANT xIF: INTEGER := 0;
CONSTANT TF: INTEGER := 0;
CONSTANT SF: INTEGER := 0;
CONSTANT ZF: INTEGER := 0;
CONSTANT AF: INTEGER := 4;
CONSTANT PF: INTEGER := 2;
CONSTANT CF: INTEGER := 0;
--- Machine Control
SIGNAL rCR0: vlbit_1d(31 downto 0) := X"00000000";
SIGNAL rCR1: vlbit_1d(31 downto 0) := X"00000000";
SIGNAL rCR2: vlbit_1d(31 downto 0) := X"00000000";
-- Page Directory Base Register
SIGNAL rCR3: vlbit_1d(31 downto 0) := X"00000000";
--- System Address (Memory Mapping Management)
-- Global Descripter Table Pointer
SIGNAL rGDTbase: vlbit_1d(31 downto 0) := X"00000000";
SIGNAL rGDTlimit: vlbit_1d(15 downto 0) := X"0000";
SIGNAL rGDTselector: vlbit_1d(15 downto 0) := X"0000";
-- Local Descripter Table Pointer
SIGNAL rLDTbase: vlbit_1d(31 downto 0) := X"00000000";
SIGNAL rLDTlimit: vlbit_1d(15 downto 0) := X"0000";
SIGNAL rLDTselector: vlbit_1d(15 downto 0) := X"0000";
-- Interrupt Descripter Table Pointer
SIGNAL rIDTbase: vlbit_1d(31 downto 0) := X"00000000";
SIGNAL rIDTlimit: vlbit_1d(15 downto 0) := X"0000";
SIGNAL rIDTselector: vlbit_1d(15 downto 0) := X"0000";
-- Task State Segment Descripter Table Pointer
SIGNAL rTSSbase: vlbit_1d(31 downto 0) := X"00000000";
SIGNAL rTSSlimit: vlbit_1d(15 downto 0) := X"0000";
SIGNAL rTSSselector: vlbit_1d(15 downto 0) := X"0000";
-- Page Table Register Files
-- SIGNAL rfPageDir: vlbit_2d(0 to 1024,31 downto 0);
-- SIGNAL rfPageTable: vlbit_2d(0 to 1024,31 downto 0);
--- Debug
--- Test
-- 80386 Instruction Set (Supported by this model)
--- Instruction Prefixes
CONSTANT REP: INTEGER := 16#F3#;
CONSTANT REPNE: INTEGER := 16#F2#;
CONSTANT LOCK: INTEGER := 16#F0#;
--- Segment Override Prefixes
CONSTANT CSsop: INTEGER := 16#2E#;
CONSTANT SSsop: INTEGER := 16#36#;
CONSTANT DSsop: INTEGER := 16#3E#;
CONSTANT ESsop: INTEGER := 16#26#;
CONSTANT FSsop: INTEGER := 16#64#;
CONSTANT GSsop: INTEGER := 16#65#;
CONSTANT OPsop: INTEGER := 16#66#;
CONSTANT ADsop: INTEGER := 16#67#;
--- Data Transfer
CONSTANT MOV_al_b: INTEGER := 16#B0#;
CONSTANT MOV_eax_dw: INTEGER := 16#B8#; -- mov eax,0000A5A5h
CONSTANT MOV_ebx_dw: INTEGER := 16#BB#; -- mov ebx,0FFFFFFF0h
CONSTANT MOV_ebx_eax: INTEGER := 16#89#; -- mov [ebx],eax {89,03}
CONSTANT MOV_eax_ebx: INTEGER := 16#8B#; -- mov eax,[ebx] {8B,03}
CONSTANT IN_al: INTEGER := 16#E4#;
CONSTANT OUT_al: INTEGER := 16#E6#;
--- Arithmetic
CONSTANT ADD_al_b: INTEGER := 16#04#;
CONSTANT ADD_ax_w: INTEGER := 16#05#;
--- Shift/Rotate
CONSTANT ROL_eax_b: INTEGER := 16#D1#; -- rol eax,1 {D1,C0}
CONSTANT ROL_al_1: INTEGER := 16#D0#;
CONSTANT ROL_al_n: INTEGER := 16#C0#;
--- String Manipulation
CONSTANT INC_eax: INTEGER := 16#40#;
CONSTANT INC_ebx: INTEGER := 16#43#;
--- Bit Manipulation
--- Control Transfer
CONSTANT JMP_rel_short: INTEGER := 16#EB#;
CONSTANT JMP_rel_near: INTEGER := 16#E9#;
CONSTANT JMP_intseg_immed: INTEGER := 16#EA#;
--- High Level Language Support
--- Operating System Support
--- Processor Control
CONSTANT HLT: INTEGER := 16#F4#;
CONSTANT WAITx: INTEGER := 16#9B#;
CONSTANT NOP: INTEGER := 16#90#;
BEGIN
-- Begin Fault Detection Section
Faults: PROCESS
BEGIN
WAIT UNTIL now > 1;
assert not bitunknown(CLK2)
report "Clock {i}: CLK2 (pin F12) is undefined"
severity FAILURE;
assert not bitunknown(READY_n)
report "Control {i}: READY (pin G13) is undefined"
severity FAILURE;
END PROCESS Faults;
-- End Fault Detection Section
-- Begin Behavioral Blocks
-- Port Signals Status Reports Begin
CLK2status: PROCESS -- Function: The first time (after the loading the network)
-- the simulation is run, this process will report
-- status of the 80386's CLK2 input from the network.
VARIABLE StartTime: INTEGER;
VARIABLE Pwidth: INTEGER;
VARIABLE freq: INTEGER;
BEGIN
WAIT UNTIL prising(CLK2);
StartTime := now;
WAIT UNTIL prising(CLK2);
Pwidth := (now - StartTime);
freq := 10000000 / Pwidth;
put("CLK2 Pulse Width is=",Pwidth);
putline(" in 10ths of nS");
put("CLK2 Frequency is=",freq);
putline("kHZ");
WAIT;
end PROCESS CLK2status;
-- Port Signals Status Reports End
-- Internal Control Logic Processes Begin
GenCLK: PROCESS
begin
-- CLK is the 80386's internal clock an is 1/2 of CLK2
wait until prising(CLK2);
CLK <= not CLK;
end PROCESS GenCLK;
Initialize: PROCESS
BEGIN
EAX <= X"00000000";
rEFLAGS <= X"00000002";
rEIP <= X"FFFFFFF0";
rIDTbase <= X"00000000";
rIDTlimit <= X"03FF";
State <= vlbit_vector(StateTi);
IF Debug THEN
putline("DEBUG: State=RESET");
END IF;
WAIT UNTIL pfalling(RESET); -- De-assert the drivers
IF Debug THEN
putline("DEBUG: 80386 was successfully Reset.");
END IF;
EAX <= X"ZZZZZZZZ";
rEFLAGS <= X"ZZZZZZZZ";
rEIP <= X"ZZZZZZZZ";
rIDTbase <= X"ZZZZZZZZ";
rIDTlimit <= X"ZZZZ";
State <= X"ZZZZZZZZ";
RequestPending <= 'Z';
WAIT UNTIL prising(RESET);
end PROCESS Initialize;
TstateMachine: PROCESS
VARIABLE nState: vlbit_1d(31 downto 0) := X"00000000";
BEGIN
WAIT UNTIL pfalling(CLK);
CASE integer(State) is
WHEN StateTi =>
IF Debug THEN
put("DEBUG: 80386 is in State Ti");
END IF;
IF RESET = '0' and RequestPending = Pending THEN
nState := vlbit_vector(StateT1);
IF Debug THEN
putline(", Moving to StateT1");
END IF;
ELSIF RESET = '0' and HOLD = '1' THEN
nState := vlbit_vector(StateTh);
IF Debug THEN
putline(", Moving to StateTh");
END IF;
ELSE
nState := vlbit_vector(StateTi);
IF Debug THEN
IF RESET = '1' THEN
putline(", Due to RESET = Asserted");
ELSE
putline(", Due to NO Requests Pending");
END IF;
END IF;
END IF;
WHEN StateT1 =>
IF Debug THEN
putline("DEBUG: 80386 is in State T1, Moving to StateT2");
END IF;
nState := vlbit_vector(StateT2);
WHEN StateT2 =>
IF Debug THEN
putline("DEBUG: 80386 is in State T2");
END IF;
IF READY_n = '0' and HOLD ='0' and RequestPending = Pending THEN
nState := vlbit_vector(StateT1);
ELSIF READY_N = '1' and NA_n = '1' THEN
NULL;
ELSIF (RequestPending = Pending or HOLD = '1') and (READY_N = '1' and NA_n = '0') THEN
nState := vlbit_vector(StateT2I);
ELSIF RequestPending = Pending and HOLD = '0' and READY_N = '1' and NA_n = '0' THEN
nState := vlbit_vector(StateT2P);
ELSIF RequestPending = NotPending and HOLD = '0' and READY_N = '0' THEN
nState := vlbit_vector(StateTi);
ELSIF HOLD = '1' and READY_N = '1' THEN
nState := vlbit_vector(StateTh);
END IF;
WHEN StateT1P =>
IF Debug THEN
putline("DEBUG: 80386 is in State T1P");
END IF;
IF NA_n = '0' and HOLD = '0' and RequestPending = Pending THEN
nState := vlbit_vector(StateT2P);
ELSIF NA_n = '0' and (HOLD = '1' or RequestPending = NotPending) THEN
nState := vlbit_vector(StateT2I);
ELSIF NA_n = '1' THEN
nState := vlbit_vector(StateT2);
END IF;
WHEN StateTh =>
IF Debug THEN
putline("DEBUG: 80386 is in State Th");
END IF;
IF HOLD = '1' THEN
NULL;
ELSIF HOLD = '0' and RequestPending = Pending THEN
nState := vlbit_vector(StateT1);
ELSIF HOLD = '0' and RequestPending = NotPending THEN
nState := vlbit_vector(StateTi);
END IF;
WHEN StateT2P =>
IF Debug THEN
putline("DEBUG: 80386 is in State T2P");
END IF;
IF READY_n = '0' THEN
nState := vlbit_vector(StateT1P);
END IF;
WHEN StateT2I =>
IF Debug THEN
putline("DEBUG: 80386 is in State T2I");
END IF;
IF READY_n = '1' and (RequestPending = NotPending or HOLD = '1') THEN
NULL;
ELSIF READY_n = '1' and RequestPending = Pending and HOLD = '0' THEN
nState := vlbit_vector(StateT2P);
ELSIF READY_n = '0' and HOLD = '1' THEN
nState := vlbit_vector(StateTh);
ELSIF READY_n = '0' and HOLD = '0' and RequestPending = Pending THEN
nState := vlbit_vector(StateT1);
ELSIF READY_n = '0' and HOLD = '0' and RequestPending = NotPending THEN
nState := vlbit_vector(StateTi);
END IF;
WHEN OTHERS => putline("MODEL ERROR: Invalid State=",State);
END CASE;
State <= nState; -- This is where the next State is actually assigned.
end PROCESS TstateMachine;
-- Internal Control Logic Processes End
-- Instruction Pre-Fetch, Decode and Execution Unit Begin
InstDecode: PROCESS
VARIABLE InstQueue: vlbit_2d(1 to 16,7 downto 0);
VARIABLE InstQueueRd_Addr: INTEGER := 1; -- Address used by the decode unit to read the queue.
VARIABLE InstQueueWr_Addr: INTEGER := 1; -- Address used by the Pre-fetch unit to fill the queue.
VARIABLE InstQueueLimit: INTEGER := 16; -- Maximum length of the Queue.
VARIABLE InstAddrPointer: INTEGER := 0; -- Allways points to the current instruction's Address.
VARIABLE PhyAddrPointer: INTEGER := 0; -- Allways points to the Systems Physical Address.
VARIABLE Extended: BOOLEAN := FALSE; -- True if an extended op-code prefix was detected.
VARIABLE More: BOOLEAN := FALSE; -- True if instruction was decoded correctly and
-- another read is needed for data.
VARIABLE Flush: BOOLEAN := FALSE; -- True if JMP was executed, flush the Queue.
VARIABLE First: BOOLEAN := TRUE; -- First time thru.
VARIABLE Byte: vlbit_1d(7 downto 0);
VARIABLE lWord: vlbit_1d(15 downto 0);
VARIABLE uWord: vlbit_1d(15 downto 0);
VARIABLE fWord: vlbit_1d(31 downto 0);
VARIABLE Dummy: INTEGER;
BEGIN
IF First THEN
PhyAddrPointer := integer(rEIP);
InstAddrPointer := PhyAddrPointer;
First := FALSE;
END IF;
RequestPending <= Pending;
ReadRequest <= Pending;
MemoryFetch <= Pending;
CodeFetch <= Pending;
IF Debug THEN
put("DEBUG: Fetching 1st Word @ Addr=");Dummy := tohex(PhyAddrPointer,4);putline("");
END IF;
WAIT UNTIL pfalling(READY_n);
RequestPending <= NotPending;
WAIT UNTIL pfalling(CLK);
InstQueue(InstQueueWr_Addr) := Data(7 downto 0);
InstQueueWr_Addr := InstQueueWr_Addr + 1;
InstQueue(InstQueueWr_Addr) := Data(15 downto 8);
InstQueueWr_Addr := InstQueueWr_Addr + 1;
IF StateBS16 = '1' THEN -- A dWord code fetch
InstQueue(InstQueueWr_Addr) := Data(23 downto 16);
InstQueueWr_Addr := InstQueueWr_Addr + 1;
InstQueue(InstQueueWr_Addr) := Data(31 downto 24);
InstQueueWr_Addr := InstQueueWr_Addr + 1;
PhyAddrPointer := PhyAddrPointer + 4; -- Point to next dWord since BS16- = 1
ELSE
PhyAddrPointer := PhyAddrPointer + 2; -- Point to next word since BS16- = 0
IF Debug THEN
put("DEBUG: Fetching 2nd Word @ Addr=");Dummy := tohex(PhyAddrPointer,4);putline("");
END IF;
rEIP <= vlbit_vector(PhyAddrPointer);
WAIT UNTIL prising(CLK);
RequestPending <= Pending;
WAIT UNTIL pfalling(READY_n);
RequestPending <= NotPending;
WAIT UNTIL pfalling(CLK);
InstQueue(InstQueueWr_Addr) := Data(7 downto 0);
InstQueueWr_Addr := InstQueueWr_Addr + 1;
InstQueue(InstQueueWr_Addr) := Data(15 downto 8);
InstQueueWr_Addr := InstQueueWr_Addr + 1;
PhyAddrPointer := PhyAddrPointer + 2; -- Point to next word since BS16- = 0
END IF;
Decode: WHILE InstQueueRd_Addr < InstQueueWr_Addr LOOP
IF DEBUG THEN
putline("DEBUG: InstQueueRd_Addr=",InstQueueRd_Addr);
putline("DEBUG: InstQueueWr_Addr=",InstQueueWr_Addr);
putline("DEBUG: InstQueueLimit=",InstQueueLimit);
put("DEBUG: InstAddrPointer=");Dummy := tohex(InstAddrPointer,4);putline("");
put("DEBUG: PhyAddrPointer=");Dummy := tohex(PhyAddrPointer,4);putline("");
putline("DEBUG: Extended=",Extended);
putline("DEBUG: Flush=",Flush);
putline("DEBUG: More=",More);
put("DEBUG: InstQueue( 1)=");Dummy := tohex(integer(InstQueue(1)),1);putline("");
put("DEBUG: InstQueue( 2)=");Dummy := tohex(integer(InstQueue(2)),1);putline("");
put("DEBUG: InstQueue( 3)=");Dummy := tohex(integer(InstQueue(3)),1);putline("");
put("DEBUG: InstQueue( 4)=");Dummy := tohex(integer(InstQueue(4)),1);putline("");
put("DEBUG: InstQueue( 5)=");Dummy := tohex(integer(InstQueue(5)),1);putline("");
put("DEBUG: InstQueue( 6)=");Dummy := tohex(integer(InstQueue(6)),1);putline("");
put("DEBUG: InstQueue( 7)=");Dummy := tohex(integer(InstQueue(7)),1);putline("");
put("DEBUG: InstQueue( 8)=");Dummy := tohex(integer(InstQueue(8)),1);putline("");
put("DEBUG: InstQueue( 9)=");Dummy := tohex(integer(InstQueue(9)),1);putline("");
put("DEBUG: InstQueue(10)=");Dummy := tohex(integer(InstQueue(10)),1);putline("");
put("DEBUG: InstQueue(11)=");Dummy := tohex(integer(InstQueue(11)),1);putline("");
put("DEBUG: InstQueue(12)=");Dummy := tohex(integer(InstQueue(12)),1);putline("");
put("DEBUG: InstQueue(13)=");Dummy := tohex(integer(InstQueue(13)),1);putline("");
put("DEBUG: InstQueue(14)=");Dummy := tohex(integer(InstQueue(14)),1);putline("");
put("DEBUG: InstQueue(15)=");Dummy := tohex(integer(InstQueue(15)),1);putline("");
put("DEBUG: InstQueue(16)=");Dummy := tohex(integer(InstQueue(16)),1);putline("");
END IF;
CASE integer(InstQueue(InstQueueRd_Addr)) is
WHEN NOP =>
InstAddrPointer := InstAddrPointer + 1;
InstQueueRd_Addr := InstQueueRd_Addr + 1;
Flush := FALSE;
More := FALSE;
IF Debug OR Inst THEN
putline("DEBUG: Executing NOP");
END IF;
WHEN OPsop =>
InstAddrPointer := InstAddrPointer + 1;
InstQueueRd_Addr := InstQueueRd_Addr + 1;
Extended := TRUE;
Flush := FALSE;
More := FALSE;
IF Debug OR Inst THEN
put("DEBUG: Extended Op-Code Read:");Dummy := tohex(OPsop,1);putline("");
END IF;
WHEN JMP_rel_short =>
IF (InstQueueWr_Addr - InstQueueRd_Addr) >= 3 THEN
IF Debug OR Inst THEN
put("DEBUG: Executing JMP-Rel-Short from:");Dummy := tohex(InstAddrPointer,4);
END IF;
IF InstQueue(InstQueueRd_Addr+1,7) = '1' THEN -- Negative Offset
PhyAddrPointer := InstAddrPointer + 1 - (16#FF# - integer(extendum(InstQueue(InstQueueRd_Addr+1),32)));
InstAddrPointer := PhyAddrPointer;
IF Debug OR Inst THEN
put(" (-)To:");Dummy := tohex(PhyAddrPointer,4);putline("");
END IF;
ELSE -- Positive Offset
PhyAddrPointer := InstAddrPointer + 2 + integer(extendum(InstQueue(InstQueueRd_Addr+1),32));
InstAddrPointer := PhyAddrPointer;
IF Debug OR Inst THEN
put(" (+)To:");Dummy := tohex(PhyAddrPointer,4);putline("");
END IF;
END IF;
Flush := TRUE;
More := FALSE;
ELSE
Flush := FALSE;
More := TRUE;
END IF;
WHEN JMP_rel_near =>
IF (InstQueueWr_Addr - InstQueueRd_Addr) >= 5 THEN
IF Debug OR Inst THEN
put("DEBUG: Executing JMP-Rel-Near from:");Dummy := tohex(InstAddrPointer,4);
END IF;
PhyAddrPointer := InstAddrPointer + 5 + integer(extendum(InstQueue(InstQueueRd_Addr+1),32));
InstAddrPointer := PhyAddrPointer;
IF Debug OR Inst THEN
put(" To:");Dummy := tohex(PhyAddrPointer,4);putline("");
END IF;
Flush := TRUE;
More := FALSE;
ELSE
Flush := FALSE;
More := TRUE;
END IF;
WHEN JMP_intseg_immed =>
-- To be Implemented (mad/8-23-1988)
IF Debug OR Inst THEN
putline("DEBUG: {TBD} Executing JMP-IntSeg-Immed from:",InstAddrPointer);
END IF;
InstAddrPointer := InstAddrPointer + 1;
InstQueueRd_Addr := InstQueueRd_Addr + 1;
Flush := FALSE;
More := FALSE;
WHEN MOV_al_b =>
-- To be Implemented (mad/8-23-1988)
IF Debug OR Inst THEN
putline("DEBUG: {TBD} Executing MOV-al<-byte");
END IF;
InstAddrPointer := InstAddrPointer + 1;
InstQueueRd_Addr := InstQueueRd_Addr + 1;
Flush := FALSE;
More := FALSE;
WHEN MOV_eax_dw =>
IF (InstQueueWr_Addr - InstQueueRd_Addr) >= 5 THEN
IF Debug OR Inst THEN
put("DEBUG: Executing MOV-eax<-dw");
END IF;
-- Note Word position is swaped
EAX <= InstQueue(InstQueueRd_Addr+4) & InstQueue(InstQueueRd_Addr+3)
& InstQueue(InstQueueRd_Addr+2) & InstQueue(InstQueueRd_Addr+1);
WAIT FOR 1;
IF Debug OR Inst THEN
put(" of:");Dummy := tohex(integer(EAX),4);putline("");
END IF;
More := FALSE;
Flush := FALSE;
InstAddrPointer := InstAddrPointer + 5;
InstQueueRd_Addr := InstQueueRd_Addr + 5;
ELSE
Flush := FALSE;
More := TRUE;
IF Debug THEN
putline("DEBUG: Executing MOV-eax<-dw but ...");
putline("DEBUG: all of the immediate data is not in queue.");
END IF;
END IF;
WHEN MOV_ebx_dw =>
IF (InstQueueWr_Addr - InstQueueRd_Addr) >= 5 THEN
IF Debug OR Inst THEN
put("DEBUG: Executing MOV-ebx<-dw");
END IF;
-- Note Word position is swaped
EBX <= InstQueue(InstQueueRd_Addr+4) & InstQueue(InstQueueRd_Addr+3)
& InstQueue(InstQueueRd_Addr+2) & InstQueue(InstQueueRd_Addr+1);
WAIT FOR 1;
IF Debug OR Inst THEN
put(" of:");Dummy := tohex(integer(EBX),4);putline("");
END IF;
More := FALSE;
Flush := FALSE;
InstAddrPointer := InstAddrPointer + 5;
InstQueueRd_Addr := InstQueueRd_Addr + 5;
ELSE
Flush := FALSE;
More := TRUE;
IF Debug THEN
putline("DEBUG: Executing MOV-ebx<-dw but ...");
putline("DEBUG: all of the immediate data is not in queue.");
END IF;
END IF;
WHEN MOV_eax_ebx => -- Read at [ebx] to eax register
IF (InstQueueWr_Addr - InstQueueRd_Addr) >= 2 THEN
IF Debug OR Inst THEN
put("DEBUG: Executing MOV-eax,[ebx]");
END IF;
IF Debug OR Inst THEN
put(" at address:");Dummy := tohex(integer(EBX),4);putline("");
END IF;
rEIP <= EBX;
RequestPending <= Pending;
ReadRequest <= Pending;
MemoryFetch <= Pending;
CodeFetch <= NotPending;
WAIT UNTIL pfalling(READY_n);
RequestPending <= NotPending;
WAIT UNTIL pfalling(CLK);
uWord := Data(15 downto 0);
IF StateBS16 = '1' THEN
lWord := Data(31 downto 16);
ELSE
rEIP <= vlbit_vector(integer(rEIP) + 2);
WAIT FOR 1;
IF Debug THEN
put("DEBUG: Reading Second Word at Addr=");Dummy := tohex(integer(rEIP),4);putline("");
END IF;
WAIT UNTIL prising(CLK);
RequestPending <= Pending;
WAIT UNTIL pfalling(READY_n);
RequestPending <= NotPending;
WAIT UNTIL pfalling(CLK);
lWord := Data(15 downto 0);
END IF;
EAX <= uWord & lWord;
WAIT FOR 1;
IF Debug OR Inst THEN
put("DEBUG: Data=");Dummy := tohex(integer(EAX),4);putline("");
END IF;
More := FALSE;
Flush := FALSE;
InstAddrPointer := InstAddrPointer + 2;
InstQueueRd_Addr := InstQueueRd_Addr + 2;
ELSE
Flush := FALSE;
More := TRUE;
END IF;
WHEN MOV_ebx_eax => -- Write at [ebx] from eax register
IF (InstQueueWr_Addr - InstQueueRd_Addr) >= 2 THEN
IF Debug OR Inst THEN
put("DEBUG: Executing MOV-[ebx],eax");
END IF;
IF Debug OR Inst THEN
put(" at address:");Dummy := tohex(integer(EBX),4);putline("");
END IF;
rEIP <= EBX;
lWord := EAX(15 downto 0);
uWord := EAX(31 downto 16);
IF Debug OR Inst THEN
put("DEBUG: Data=");Dummy := tohex(integer(EAX),4);putline("");
END IF;
RequestPending <= Pending;
ReadRequest <= NotPending;
MemoryFetch <= Pending;
CodeFetch <= NotPending;
IF Debug THEN
put("DEBUG: Writing First Word at Addr=");Dummy := tohex(integer(EBX),4);putline("");
END IF;
WAIT UNTIL (integer(State) = StateT1 OR integer(State) = StateT1P);
WAIT UNTIL prising(CLK);
Data <= (uWord & lWord) after 480;
WAIT UNTIL pfalling(READY_n);
RequestPending <= NotPending;
WAIT UNTIL prising(CLK);
Data <= X"ZZZZZZZZ" after 480;
WAIT FOR 1;
IF StateBS16 = '0' THEN
IF Debug THEN
put("DEBUG: Writing Second Word at Addr=");Dummy := tohex(integer(EBX),4);putline("");
END IF;
rEIP <= vlbit_vector(integer(rEIP) + 2);
RequestPending <= Pending;
ReadRequest <= NotPending;
MemoryFetch <= Pending;
CodeFetch <= NotPending;
WAIT UNTIL (integer(State) = StateT1 OR integer(State) = StateT1P);
WAIT UNTIL prising(CLK);
Data <= (uWord & lWord) after 480;
WAIT UNTIL pfalling(READY_n);
RequestPending <= NotPending;
WAIT UNTIL prising(CLK);
Data <= X"ZZZZZZZZ" after 480;
WAIT FOR 1;
END IF;
More := FALSE;
Flush := FALSE;
InstAddrPointer := InstAddrPointer + 2;
InstQueueRd_Addr := InstQueueRd_Addr + 2;
ELSE
Flush := FALSE;
More := TRUE;
END IF;
WHEN IN_al =>
IF (InstQueueWr_Addr - InstQueueRd_Addr) >= 2 THEN
IF Debug OR Inst THEN
put("DEBUG: Executing IN-al");
END IF;
rEIP <= extendum(InstQueue(InstQueueRd_Addr+1),32);
WAIT FOR 1;
IF Debug OR Inst THEN
put(" from:");Dummy := tohex(integer(rEIP),4);
END IF;
RequestPending <= Pending;
ReadRequest <= Pending;
MemoryFetch <= NotPending;
CodeFetch <= NotPending;
WAIT UNTIL pfalling(READY_n);
RequestPending <= NotPending;
WAIT UNTIL pfalling(CLK);
EAX(7 downto 0) <= Data(7 downto 0);
WAIT FOR 1;
IF Debug OR Inst THEN
put(" Data=");Dummy := tohex(integer(EAX(7 downto 0)),1);putline("");
END IF;
InstAddrPointer := InstAddrPointer + 2;
InstQueueRd_Addr := InstQueueRd_Addr + 2;
Flush := FALSE;
More := FALSE;
ELSE
Flush := FALSE;
More := TRUE;
IF Debug THEN
putline("DEBUG: Executing IN-al but ...");
putline("DEBUG: the immediate Address is not in queue.");
END IF;
END IF;
WHEN OUT_al =>
IF (InstQueueWr_Addr - InstQueueRd_Addr) >= 2 THEN
IF Debug OR Inst THEN
put("DEBUG: Executing OUT-al");
END IF;
rEIP <= extendum(InstQueue(InstQueueRd_Addr+1),32);
WAIT FOR 1;
IF Debug OR Inst THEN
put(" to:");Dummy := tohex(integer(rEIP),4);
END IF;
RequestPending <= Pending;
ReadRequest <= NotPending;
MemoryFetch <= NotPending;
CodeFetch <= NotPending;
IF Debug OR Inst THEN
put(" Data=");Dummy := tohex(integer(EAX(7 downto 0)),1);putline("");
END IF;
WAIT UNTIL (integer(State) = StateT1 OR integer(State) = StateT1P);
WAIT UNTIL prising(CLK);
fWord := X"ZZZZZZ" & EAX(7 downto 0);
Data <= fWord after 480;
WAIT UNTIL pfalling(READY_n);
RequestPending <= NotPending;
WAIT UNTIL prising(CLK);
Data <= X"ZZZZZZZZ" after 480;
WAIT FOR 1;
InstAddrPointer := InstAddrPointer + 2;
InstQueueRd_Addr := InstQueueRd_Addr + 2;
Flush := FALSE;
More := FALSE;
ELSE
Flush := FALSE;
More := TRUE;
IF Debug THEN
putline("DEBUG: Executing OUT-al but ...");
putline("DEBUG: the immediate Address is not in queue.");
END IF;
END IF;
WHEN ADD_al_b =>
-- To be Implemented (mad/8-23-1988)
IF Debug OR Inst THEN