diff --git a/common/CPU/68K10/license/cern_ohl_v_1_2.odt b/common/CPU/68K10/license/cern_ohl_v_1_2.odt new file mode 100644 index 00000000..0e4038a4 Binary files /dev/null and b/common/CPU/68K10/license/cern_ohl_v_1_2.odt differ diff --git a/common/CPU/68K10/license/cern_ohl_v_1_2.pdf b/common/CPU/68K10/license/cern_ohl_v_1_2.pdf new file mode 100644 index 00000000..99ce718d Binary files /dev/null and b/common/CPU/68K10/license/cern_ohl_v_1_2.pdf differ diff --git a/common/CPU/68K10/license/cern_ohl_v_1_2.txt b/common/CPU/68K10/license/cern_ohl_v_1_2.txt new file mode 100644 index 00000000..62aab65d --- /dev/null +++ b/common/CPU/68K10/license/cern_ohl_v_1_2.txt @@ -0,0 +1,897 @@ + + + + +CERN Open Hardware Licence - cern_ohl_v_1_2.txt - Open Hardware Repository + + + + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + +
+ +

cern_ohl_v_1_2.txt

+ +
+

Licence text in text format. - + Javier Serrano, 2013-09-06 10:05

+

Download (8.9 kB)

+ +
+  +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1
CERN Open Hardware Licence v1.2 
+
2
+
3
Preamble
+
4
+
5
Through this CERN Open Hardware Licence ("CERN OHL") version 1.2, CERN
+
6
wishes to provide a tool to foster collaboration and sharing among
+
7
hardware designers.  The CERN OHL is copyright CERN. Anyone is welcome
+
8
to use the CERN OHL, in unmodified form only, for the distribution of
+
9
their own Open Hardware designs. Any other right is reserved. Release
+
10
of hardware designs under the CERN OHL does not constitute an
+
11
endorsement of the licensor or its designs nor does it imply any
+
12
involvement by CERN in the development of such designs.
+
13
+
14
1. Definitions
+
15
+
16
In this Licence, the following terms have the following meanings:
+
17
 
+
18
“Licence” means this CERN OHL.
+
19
+
20
“Documentation” means schematic diagrams, designs, circuit or circuit
+
21
board layouts, mechanical drawings, flow charts and descriptive text,
+
22
and other explanatory material that is explicitly stated as being made
+
23
available under the conditions of this Licence. The Documentation may
+
24
be in any medium, including but not limited to computer files and
+
25
representations on paper, film, or any other media.
+
26
+
27
“Documentation Location” means a location where the Licensor has
+
28
placed Documentation, and which he believes will be publicly
+
29
accessible for at least three years from the first communication to
+
30
the public or distribution of Documentation.
+
31
+
32
“Product” means either an entire, or any part of a, device built using
+
33
the Documentation or the modified Documentation.
+
34
+
35
“Licensee” means any natural or legal person exercising rights under
+
36
this Licence.
+
37
+
38
“Licensor” means any natural or legal person that creates or modifies
+
39
Documentation and subsequently communicates to the public and/ or
+
40
distributes the resulting Documentation under the terms and conditions
+
41
of this Licence.
+
42
+
43
A Licensee may at the same time be a Licensor, and vice versa. 
+
44
+
45
Use of the masculine gender includes the feminine and neuter genders
+
46
and is employed solely to facilitate reading.
+
47
+
48
2. Applicability
+
49
+
50
2.1. This Licence governs the use, copying, modification,
+
51
communication to the public and distribution of the Documentation, and
+
52
the manufacture and distribution of Products. By exercising any right
+
53
granted under this Licence, the Licensee irrevocably accepts these
+
54
terms and conditions.
+
55
+
56
2.2. This Licence is granted by the Licensor directly to the Licensee,
+
57
and shall apply worldwide and without limitation in time. The Licensee
+
58
may assign his licence rights or grant sub-licences.
+
59
+
60
2.3. This Licence does not extend to software, firmware, or code
+
61
loaded into programmable devices which may be used in conjunction with
+
62
the Documentation, the modified Documentation or with Products, unless
+
63
such software, firmware, or code is explicitly expressed to be subject
+
64
to this Licence. The use of such software, firmware, or code is
+
65
otherwise subject to the applicable licence terms and conditions.
+
66
+
67
3. Copying, modification, communication to the public and distribution
+
68
of the Documentation
+
69
+
70
3.1. The Licensee shall keep intact all copyright and trademarks
+
71
notices, all notices referring to Documentation Location, and all
+
72
notices that refer to this Licence and to the disclaimer of warranties
+
73
that are included in the Documentation. He shall include a copy
+
74
thereof in every copy of the Documentation or, as the case may be,
+
75
modified Documentation, that he communicates to the public or
+
76
distributes.
+
77
+
78
3.2. The Licensee may copy, communicate to the public and distribute
+
79
verbatim copies of the Documentation, in any medium, subject to the
+
80
requirements specified in section 3.1.
+
81
+
82
3.3. The Licensee may modify the Documentation or any portion thereof
+
83
provided that upon modification of the Documentation, the Licensee
+
84
shall make the modified Documentation available from a Documentation
+
85
Location such that it can be easily located by an original Licensor
+
86
once the Licensee communicates to the public or distributes the
+
87
modified Documentation under section 3.4, and, where required by
+
88
section 4.1, by a recipient of a Product. However, the Licensor shall
+
89
not assert his rights under the foregoing proviso unless or until a
+
90
Product is distributed.
+
91
+
92
3.4. The Licensee may communicate to the public and distribute the
+
93
modified Documentation (thereby in addition to being a Licensee also
+
94
becoming a Licensor), always provided that he shall:
+
95
+
96
a) comply with section 3.1;
+
97
+
98
b) cause the modified Documentation to carry prominent notices stating
+
99
that the Licensee has modified the Documentation, with the date and
+
100
description of the modifications;
+
101
+
102
c) cause the modified Documentation to carry a new Documentation
+
103
Location notice if the original Documentation provided for one;
+
104
+
105
d) make available the modified Documentation at the same level of
+
106
abstraction as that of the Documentation, in the preferred format for
+
107
making modifications to it (e.g. the native format of the CAD tool as
+
108
applicable), and in the event that format is proprietary, in a format
+
109
viewable with a tool licensed under an OSI-approved license if the
+
110
proprietary tool can create it; and
+
111
+
112
e) license the modified Documentation under the terms and conditions
+
113
of this Licence or, where applicable, a later version of this Licence
+
114
as may be issued by CERN.
+
115
+
116
3.5. The Licence includes a non-exclusive licence to those patents or
+
117
registered designs that are held by, under the control of, or
+
118
sub-licensable by the Licensor, to the extent necessary to make use of
+
119
the rights granted under this Licence. The scope of this section 3.5
+
120
shall be strictly limited to the parts of the Documentation or
+
121
modified Documentation created by the Licensor.
+
122
+
123
4. Manufacture and distribution of Products
+
124
+
125
4.1. The Licensee may manufacture or distribute Products always
+
126
provided that, where such manufacture or distribution requires a
+
127
licence under this Licence the Licensee provides to each recipient of
+
128
such Products an easy means of accessing a copy of the Documentation
+
129
or modified Documentation, as applicable, as set out in section 3.
+
130
+
131
4.2. The Licensee is invited to inform any Licensor who has indicated
+
132
his wish to receive this information about the type, quantity and
+
133
dates of production of Products the Licensee has (had) manufactured
+
134
+
135
5. Warranty and liability
+
136
+
137
5.1. DISCLAIMER – The Documentation and any modified Documentation are
+
138
provided "as is" and any express or implied warranties, including, but
+
139
not limited to, implied warranties of merchantability, of satisfactory
+
140
quality, non-infringement of third party rights, and fitness for a
+
141
particular purpose or use are disclaimed in respect of the
+
142
Documentation, the modified Documentation or any Product. The Licensor
+
143
makes no representation that the Documentation, modified
+
144
Documentation, or any Product, does or will not infringe any patent,
+
145
copyright, trade secret or other proprietary right. The entire risk as
+
146
to the use, quality, and performance of a Product shall be with the
+
147
Licensee and not the Licensor. This disclaimer of warranty is an
+
148
essential part of this Licence and a condition for the grant of any
+
149
rights granted under this Licence. The Licensee warrants that it does
+
150
not act in a consumer capacity.
+
151
+
152
5.2. LIMITATION OF LIABILITY – The Licensor shall have no liability
+
153
for direct, indirect, special, incidental, consequential, exemplary,
+
154
punitive or other damages of any character including, without
+
155
limitation, procurement of substitute goods or services, loss of use,
+
156
data or profits, or business interruption, however caused and on any
+
157
theory of contract, warranty, tort (including negligence), product
+
158
liability or otherwise, arising in any way in relation to the
+
159
Documentation, modified Documentation and/or the use, manufacture or
+
160
distribution of a Product, even if advised of the possibility of such
+
161
damages, and the Licensee shall hold the Licensor(s) free and harmless
+
162
from any liability, costs, damages, fees and expenses, including
+
163
claims by third parties, in relation to such use.
+
164
+
165
6. General
+
166
+
167
6.1. Except for the rights explicitly granted hereunder, this Licence
+
168
does not imply or represent any transfer or assignment of intellectual
+
169
property rights to the Licensee.
+
170
+
171
6.2. The Licensee shall not use or make reference to any of the names
+
172
(including acronyms and abbreviations), images, or logos under which
+
173
the Licensor is known, save in so far as required to comply with
+
174
section 3. Any such permitted use or reference shall be factual and
+
175
shall in no event suggest any kind of endorsement by the Licensor or
+
176
its personnel of the modified Documentation or any Product, or any
+
177
kind of implication by the Licensor or its personnel in the
+
178
preparation of the modified Documentation or Product.
+
179
+
180
6.3. CERN may publish updated versions of this Licence which retain
+
181
the same general provisions as this version, but differ in detail so
+
182
far this is required and reasonable. New versions will be published
+
183
with a unique version number.
+
184
+
185
6.4. This Licence shall terminate with immediate effect, upon written
+
186
notice and without involvement of a court if the Licensee fails to
+
187
comply with any of its terms and conditions, or if the Licensee
+
188
initiates legal action against Licensor in relation to this
+
189
Licence. Section 5 shall continue to apply.
+
+
+ + + + + + +
+
+
+ + + + +
+
+ + + + + + diff --git a/common/CPU/68K10/license/cern_ohl_v_1_2_howto.odt b/common/CPU/68K10/license/cern_ohl_v_1_2_howto.odt new file mode 100644 index 00000000..0a1ea6ba Binary files /dev/null and b/common/CPU/68K10/license/cern_ohl_v_1_2_howto.odt differ diff --git a/common/CPU/68K10/license/cern_ohl_v_1_2_howto.pdf b/common/CPU/68K10/license/cern_ohl_v_1_2_howto.pdf new file mode 100644 index 00000000..feec8175 Binary files /dev/null and b/common/CPU/68K10/license/cern_ohl_v_1_2_howto.pdf differ diff --git a/common/CPU/68K10/wf68K10.sdc b/common/CPU/68K10/wf68K10.sdc new file mode 100644 index 00000000..024872bf --- /dev/null +++ b/common/CPU/68K10/wf68K10.sdc @@ -0,0 +1,40 @@ +# +# Copyright 2014 Wolfgang Foerster Inventronik GmbH. +# +# This documentation describes Open Hardware and is licensed +# under the CERN OHL v. 1.2. You may redistribute and modify +# this documentation under the terms of the CERN OHL v.1.2. +# (http://ohwr.org/cernohl). This documentation is distributed +# WITHOUT ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING OF +# MERCHANTABILITY, SATISFACTORY QUALITY AND FITNESS FOR A +# PARTICULAR PURPOSE. Please see the CERN OHL v.1.2 for +# applicable conditions + +# Revision History + +# Revision 2K14B 20140922 WF +# Initial Release. + + +#************************************************************** +# Time Information +#************************************************************** + +# set_time_format -unit ns -decimal_places 3 + + + +#************************************************************** +# Create Clock +#************************************************************** + +# create_clock -name CLK -period 100.000 -waveform {0.000 50.000} [get_ports {CLK}] +create_clock -period 20.000 -name CLK [get_ports {CLK}] + +#derive_pll_clocks +#derive_pll_clocks -use_net_name +derive_clock_uncertainty + +#set_clock_groups -exclusive -group {CLK_PLL1} +#set_clock_groups -exclusive -group {CLK_PLL2} +#set_clock_groups -exclusive -group {CODEC_SCLK} diff --git a/common/CPU/68K10/wf68k10_address_registers.vhd b/common/CPU/68K10/wf68k10_address_registers.vhd new file mode 100644 index 00000000..c3d6578f --- /dev/null +++ b/common/CPU/68K10/wf68k10_address_registers.vhd @@ -0,0 +1,512 @@ +------------------------------------------------------------------------ +---- ---- +---- WF68K10 IP Core: Address register logic. ---- +---- ---- +---- Description: ---- +---- This module provides the address registers, stack pointers, ---- +---- the address arithmetics, the program counter logic and the SFC ---- +---- and DFC registers. The address registers are accessible by two ---- +---- read and two write ports simultaneously. For more information ---- +---- refer to the MC68030 User' Manual. ---- +---- ---- +---- Author(s): ---- +---- - Wolfgang Foerster, wf@experiment-s.de; wf@inventronik.de ---- +---- ---- +------------------------------------------------------------------------ +---- ---- +---- Copyright 2014-2019 Wolfgang Foerster Inventronik GmbH. ---- +---- ---- +---- This documentation describes Open Hardware and is licensed ---- +---- under the CERN OHL v. 1.2. You may redistribute and modify ---- +---- this documentation under the terms of the CERN OHL v.1.2. ---- +---- (http://ohwr.org/cernohl). This documentation is distributed ---- +---- WITHOUT ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING OF ---- +---- MERCHANTABILITY, SATISFACTORY QUALITY AND FITNESS FOR A ---- +---- PARTICULAR PURPOSE. Please see the CERN OHL v.1.2 for ---- +---- applicable conditions ---- +---- ---- +------------------------------------------------------------------------ +-- +-- Revision History +-- +-- Revision 2K14B 20141201 WF +-- Initial Release. +-- Revision 2K16A 20160620 WF +-- Minor optimizations. +-- Revision 2K18A 20180620 WF +-- Changed ADR_ATN logic to be valid one clock cycle earlier. +-- Fixed PC restoring during exception processing. +-- Fixed the writing ISP_REG during EXG instruction with two address registers. +-- Fixed writing the stack pointer registers (SBIT_WB is used instead of SBIT). +-- The address registers are always written long. +-- Bugfix: exception handler do not increment and decrement the USP any more. +-- MOVEM-Fix: the effective address in memory to register is stored (STORE_AEFF) not to be overwritten in case the addressing register is also loaded. +-- Revision 2K19A 2019## WF +-- Removed ADR_ATN. We do not need this any more. +-- Fixed the condition if UNMARK and AR_MARK_USED are asserted simultaneously (see process P_IN_USE). +-- + +use work.WF68K10_PKG.all; + +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_unsigned.all; + +entity WF68K10_ADDRESS_REGISTERS is + port ( + CLK : in std_logic; + RESET : in bit; + + -- Address and data: + AR_IN_1 : in std_logic_vector(31 downto 0); + AR_IN_2 : in std_logic_vector(31 downto 0); + AR_OUT_1 : out std_logic_vector(31 downto 0); + AR_OUT_2 : out std_logic_vector(31 downto 0); + INDEX_IN : in std_logic_vector(31 downto 0); + PC : out std_logic_vector(31 downto 0); -- Program counter (or sPC) always word aligned. + PC_EW_OFFSET : in std_logic_vector(3 downto 0); -- Offset to the first address extension word. + STORE_ADR_FORMAT : in bit; + STORE_ABS_HI : in bit; + STORE_ABS_LO : in bit; + STORE_D16 : in bit; + STORE_DISPL : in bit; + STORE_AEFF : in bit; + OP_SIZE : in OP_SIZETYPE; + + ADR_OFFSET : in std_logic_vector(31 downto 0); + ADR_MARK_USED : in bit; + USE_APAIR : in boolean; + ADR_IN_USE : out bit; + + ADR_MODE : in std_logic_vector(2 downto 0); + AMODE_SEL : in std_logic_vector(2 downto 0); + ADR_EFF : out std_logic_vector(31 downto 0); -- This is the effective address. + ADR_EFF_WB : out std_logic_vector(31 downto 0); -- This is the effective address. + + DFC : out std_logic_vector(2 downto 0); + DFC_WR : in bit; + SFC : out std_logic_vector(2 downto 0); + SFC_WR : in bit; + + ISP_DEC : in bit; + ISP_WR : in bit; + USP_RD : in bit; + USP_WR : in bit; + + -- Registers controls: + AR_MARK_USED : in bit; + AR_IN_USE : out bit; + AR_SEL_RD_1 : in std_logic_vector(2 downto 0); + AR_SEL_RD_2 : in std_logic_vector(2 downto 0); + AR_SEL_WR_1 : in std_logic_vector(2 downto 0); + AR_SEL_WR_2 : in std_logic_vector(2 downto 0); + AR_DEC : in bit; -- Address register decrement. + AR_INC : in bit; -- Address register increment. + AR_WR_1 : in bit; -- Address register write. + AR_WR_2 : in bit; -- Address register write. + UNMARK : in bit; + + EXT_WORD : in std_logic_vector(15 downto 0); + + SBIT : in std_logic; + + SP_ADD_DISPL : in bit; + RESTORE_ISP_PC : in bit; + + -- Other controls: + DISPLACEMENT : in std_logic_vector(31 downto 0); + PC_ADD_DISPL : in bit; + PC_INC : in bit; -- Program counter increment. + PC_LOAD : in bit; -- Program counter write. + PC_RESTORE : in bit; + PC_OFFSET : in std_logic_vector(7 downto 0) + ); +end entity WF68K10_ADDRESS_REGISTERS; + +architecture BEHAVIOR of WF68K10_ADDRESS_REGISTERS is +type AR_TYPE is array(0 to 6) of std_logic_vector(31 downto 0); +signal ADR_EFF_I : std_logic_vector(31 downto 0); +signal AR : AR_TYPE; -- Address registers A0 to A6. +signal AR_OUT_1_I : std_logic_vector(31 downto 0); +signal AR_OUT_2_I : std_logic_vector(31 downto 0); +signal ADR_WB : std_logic_vector(32 downto 0); +signal AR_PNTR_1 : integer range 0 to 7; +signal AR_PNTR_2 : integer range 0 to 7; +signal AR_PNTR_WB_1 : integer range 0 to 7; +signal AR_PNTR_WB_2 : integer range 0 to 7; +signal AR_USED_1 : std_logic_vector(3 downto 0); +signal AR_USED_2 : std_logic_vector(3 downto 0); +signal DFC_REG : std_logic_vector(2 downto 0); -- Special function code registers. +signal ISP_REG : std_logic_vector(31 downto 0); -- Interrupt stack pointer (refers to A7'' in the supervisor mode). +signal SBIT_WB : std_logic; +signal PC_I : std_logic_vector(31 downto 0); -- Active program counter. +signal SCALE : std_logic_vector(1 downto 0); -- Scale information for the index. +signal SFC_REG : std_logic_vector(2 downto 0); -- Special function code registers. +signal USP_REG : std_logic_vector(31 downto 0); -- User stack pointer (refers to A7 in the user mode.). +begin + INBUFFER: process + begin + wait until CLK = '1' and CLK' event; + if AR_MARK_USED = '1' then + AR_PNTR_WB_1 <= conv_integer(AR_SEL_WR_1); + AR_PNTR_WB_2 <= conv_integer(AR_SEL_WR_2); + end if; + end process INBUFFER; + + AR_PNTR_1 <= conv_integer(AR_SEL_RD_1); + AR_PNTR_2 <= conv_integer(AR_SEL_RD_2); + + P_IN_USE: process + variable DELAY : boolean; + begin + wait until CLK = '1' and CLK' event; + if RESET = '1' or (UNMARK = '1' and AR_MARK_USED = '0') then + AR_USED_1(3) <= '0'; + AR_USED_2(3) <= '0'; + elsif AR_MARK_USED = '1' then + AR_USED_1 <= '1' & AR_SEL_WR_1; + if USE_APAIR = true then + AR_USED_2 <= '1' & AR_SEL_WR_2; + end if; + SBIT_WB <= SBIT; + end if; + -- + if RESET = '1' or (UNMARK = '1' and AR_MARK_USED = '0') then + ADR_WB(32) <= '0'; + DELAY := false; + elsif ADR_MARK_USED = '1' then + DELAY := true; -- One clock cycle address calculation delay. + elsif DELAY = true then + ADR_WB <= '1' & ADR_EFF_I; + DELAY := false; + end if; + end process P_IN_USE; + + AR_IN_USE <= '1' when AR_USED_1(3) = '1' and AR_USED_1(2 downto 0) = AR_SEL_RD_1 else + '1' when AR_USED_1(3) = '1' and AR_USED_1(2 downto 0) = AR_SEL_RD_2 else + '1' when AR_USED_2(3) = '1' and AR_USED_2(2 downto 0) = AR_SEL_RD_1 else + '1' when AR_USED_2(3) = '1' and AR_USED_2(2 downto 0) = AR_SEL_RD_2 else '0'; + + AR_OUT_1 <= AR_OUT_1_I; + AR_OUT_2 <= AR_OUT_2_I; + + ADR_IN_USE <= '1' when ADR_WB(32) = '1' and ADR_WB(31 downto 2) = ADR_EFF_I(31 downto 2) else -- Actual long word address. + '1' when ADR_WB(32) = '1' and ADR_WB(31 downto 2) - '1' = ADR_EFF_I(31 downto 2) else -- Lock a misaligned access. + '1' when ADR_WB(32) = '1' and ADR_WB(31 downto 2) + '1' = ADR_EFF_I(31 downto 2) else '0'; -- Lock a misaligned access. + + ADR_FORMAT: process + begin + wait until CLK = '1' and CLK' event; + if STORE_ADR_FORMAT = '1' then + SCALE <= EXT_WORD(10 downto 9); + end if; + end process ADR_FORMAT; + + ADDRESS_MODES: process(ADR_MODE, AMODE_SEL, AR, AR_PNTR_1, CLK, + ISP_REG, PC_EW_OFFSET, PC_I, RESTORE_ISP_PC, SBIT, USP_REG) + -- The effective address calculation takes place in this process depending on the + -- selected addressing mode. + -- The PC address (PC_I) used for the address calculation points to the first + -- extension word used. + variable ABS_ADDRESS : std_logic_vector(31 downto 0); + variable ADR_EFF_VAR : std_logic_vector(31 downto 0); + variable ADR_EFF_TMP : std_logic_vector(31 downto 0); + variable ADR_MUX : std_logic_vector(31 downto 0); + variable BASE_DISPL : std_logic_vector(31 downto 0); + variable INDEX : std_logic_vector(31 downto 0) := x"00000000"; + variable INDEX_SCALED : std_logic_vector(31 downto 0); + variable PCVAR : std_logic_vector(31 downto 0); + begin + PCVAR := PC_I + PC_EW_OFFSET; -- This is the address of the extension word. + + if CLK = '1' and CLK' event then + -- This logic selects the INDEX from one of the data registers or from one of + -- the address registers. Furthermore the index needs to be sign extended from + -- 8 bit to 32 bit or from 16 bit to 32 bit dependent on the address mode. + -- In case of a long word operation, no extension is required. The index is + -- multiplied by 1, 2, 4 or 8. + if STORE_ADR_FORMAT = '1' and EXT_WORD(15) = '0' and EXT_WORD(11) = '1' then + INDEX := INDEX_IN; -- Long data register. + elsif STORE_ADR_FORMAT = '1' and EXT_WORD(15) = '0' then + for i in 31 downto 16 loop + INDEX(i) := INDEX_IN(15); + end loop; + INDEX(15 downto 0) := INDEX_IN(15 downto 0); -- Sign extended data register; + elsif STORE_ADR_FORMAT = '1' and EXT_WORD(11) = '1' then -- Long address register. + if EXT_WORD(14 downto 12) = "111" and SBIT = '1' then + INDEX := ISP_REG; + elsif EXT_WORD(14 downto 12) = "111" and SBIT = '0' then + INDEX := USP_REG; + else + INDEX := AR(conv_integer(EXT_WORD(14 downto 12))); + end if; + elsif STORE_ADR_FORMAT = '1' then -- Sign extended address register; + if EXT_WORD(14 downto 12) = "111" and SBIT = '1' then + for i in 31 downto 16 loop + INDEX(i) := ISP_REG(15); + end loop; + INDEX(15 downto 0) := ISP_REG(15 downto 0); + elsif EXT_WORD(14 downto 12) = "111" and SBIT = '0' then + for i in 31 downto 16 loop + INDEX(i) := USP_REG(15); + end loop; + INDEX(15 downto 0) := USP_REG(15 downto 0); + else + for i in 31 downto 16 loop + INDEX(i) := AR(conv_integer(EXT_WORD(14 downto 12)))(15); + end loop; + INDEX(15 downto 0) := AR(conv_integer(EXT_WORD(14 downto 12)))(15 downto 0); + end if; + end if; + -- + case SCALE is + when "00" => INDEX_SCALED := INDEX; -- Multiple by 1. + when "01" => INDEX_SCALED := INDEX(30 downto 0) & '0'; -- Multiple by 2. + when "10" => INDEX_SCALED := INDEX(29 downto 0) & "00"; -- Multiple by 4. + when others => INDEX_SCALED := INDEX(28 downto 0) & "000"; -- Multiple by 8. + end case; + -- + -- The displacement needs to be sign extended from 8 bit to 32, from 16 bit to 32 bit or + -- not extended dependent on the address mode. + if RESET = '1' then + BASE_DISPL := (others => '0'); -- Null base displacement. + elsif STORE_ADR_FORMAT = '1' then + for i in 31 downto 8 loop + BASE_DISPL(i) := EXT_WORD(7); + end loop; + BASE_DISPL(7 downto 0) := EXT_WORD(7 downto 0); + elsif STORE_D16 = '1' then + for i in 31 downto 16 loop + BASE_DISPL(i) := EXT_WORD(15); + end loop; + BASE_DISPL(15 downto 0) := EXT_WORD; + elsif STORE_DISPL = '1' then + BASE_DISPL := DISPLACEMENT; + end if; + -- + if STORE_ABS_LO = '1' then + if AMODE_SEL = "000" then + for i in 31 downto 16 loop + ABS_ADDRESS(i) := EXT_WORD(15); + end loop; + end if; + ABS_ADDRESS(15 downto 0) := EXT_WORD; + elsif STORE_ABS_HI = '1' then + ABS_ADDRESS(31 downto 16) := EXT_WORD; + end if; + end if; + + case AR_PNTR_1 is + when 7 => + if SBIT = '1' then + ADR_MUX := ISP_REG; + else + ADR_MUX := USP_REG; + end if; + when others => ADR_MUX := AR(AR_PNTR_1); + end case; + + case ADR_MODE is + -- when "000" | "001" => Direct address modes: no effective address required. + when "010" | "011" | "100" => + ADR_EFF_VAR := ADR_MUX; -- (An), (An)+, -(An). + when "101" => -- Address register indirect with offset. Assembler syntax: (d16,An). + ADR_EFF_VAR := ADR_MUX + BASE_DISPL; -- (d16,An). + when "110" => + ADR_EFF_VAR := ADR_MUX + BASE_DISPL + INDEX_SCALED; -- (d8, An, Xn, SIZE*SCALE). + when "111" => + case AMODE_SEL is + when "000" | "001" => + ADR_EFF_VAR := ABS_ADDRESS; + when "010" => -- (d16, PC). + ADR_EFF_VAR := PCVAR + BASE_DISPL; + when "011" => + -- Assembler syntax: (d8,PC,Xn.SIZE*SCALE). + ADR_EFF_VAR := PCVAR + BASE_DISPL + INDEX_SCALED; -- (d8, PC, Xn, SIZE*SCALE). + when others => + ADR_EFF_VAR := (others => '-'); -- Don't care, while not used. + end case; + when others => + ADR_EFF_VAR := (others => '-'); -- Result not required. + end case; + -- + if CLK = '1' and CLK' event then + if RESTORE_ISP_PC = '1' then + ADR_EFF_I <= ADR_OFFSET; -- During exception processing. + elsif STORE_AEFF = '1' then -- Used for MOVEM. + ADR_EFF_I <= ADR_EFF_TMP + ADR_OFFSET; -- Keep the effective address. See also CONTROL section. + else -- Normal operation: + ADR_EFF_I <= ADR_EFF_VAR + ADR_OFFSET; + ADR_EFF_TMP := ADR_EFF_VAR; + end if; + end if; + end process ADDRESS_MODES; + + ADR_EFF <= ADR_EFF_I; + ADR_EFF_WB <= ADR_WB(31 downto 0); + + -- Data outputs: + AR_OUT_1_I <= USP_REG when USP_RD = '1' else + AR(AR_PNTR_1) when AR_PNTR_1 < 7 else + ISP_REG when SBIT = '1' else USP_REG; + + AR_OUT_2_I <= AR(AR_PNTR_2) when AR_PNTR_2 < 7 else + ISP_REG when SBIT = '1' else USP_REG; + + PC <= PC_I; + + PROGRAM_COUNTER: process + -- Note: PC_LOAD and PC_ADD_DISPL must be highest + -- prioritized. The reason is that in case of jumps + -- or branches the Ipipe is flushed in connection + -- with PC_INC. In such cases PC_LOAD or PC_ADD_DISPL + -- are asserted simultaneously with PC_INC. + begin + wait until CLK = '1' and CLK' event; + if RESET = '1' then + PC_I <= (others => '0'); + elsif PC_LOAD = '1' then + PC_I <= AR_IN_1; + elsif PC_ADD_DISPL = '1' then + PC_I <= PC_I + DISPLACEMENT; + elsif PC_RESTORE = '1' then + PC_I <= AR_IN_1; -- Keep prioritization! + elsif PC_INC = '1' then + PC_I <= PC_I + PC_OFFSET; + end if; + end process PROGRAM_COUNTER; + + STACK_POINTERS: process + -- The registers are modeled in a way + -- that write and simultaneously increment + -- decrement and others are possible for + -- different registers. + begin + wait until CLK = '1' and CLK' event; + ---------------------------------------- ISP section ---------------------------------------- + if RESET = '1' then + ISP_REG <= (others => '0'); + elsif AR_WR_1 = '1' and AR_PNTR_WB_1 = 7 and SBIT_WB = '1' then + ISP_REG <= AR_IN_1; -- Always written long. + end if; + + if AR_INC = '1' and AR_PNTR_1 = 7 and SBIT = '1' then + case OP_SIZE is + when BYTE => ISP_REG <= ISP_REG + "10"; -- Increment by two! + when WORD => ISP_REG <= ISP_REG + "10"; -- Increment by two. + when others => ISP_REG <= ISP_REG + "100"; -- Increment by four, (LONG). + end case; + end if; + + if ISP_DEC = '1' or (AR_DEC = '1' and AR_PNTR_1 = 7 and SBIT = '1') then + case OP_SIZE is + when BYTE => ISP_REG <= ISP_REG - "10"; -- Decrement by two! + when WORD => ISP_REG <= ISP_REG - "10"; -- Decrement by two. + when others => ISP_REG <= ISP_REG - "100"; -- Decrement by four, (LONG). + end case; + end if; + + if ISP_WR = '1' then + ISP_REG <= AR_IN_1; + elsif SP_ADD_DISPL = '1' and AR_INC = '1' and SBIT = '1' then + ISP_REG <= ISP_REG + DISPLACEMENT + "100"; -- Used for RTD. + elsif SP_ADD_DISPL = '1' and SBIT = '1' then + ISP_REG <= ISP_REG + DISPLACEMENT; + end if; + + ---------------------------------------- USP section ---------------------------------------- + if RESET = '1' then + USP_REG <= (others => '0'); + elsif AR_WR_1 = '1' and AR_PNTR_WB_1 = 7 and SBIT_WB = '0' then + USP_REG <= AR_IN_1; -- Always written long. + end if; + + if AR_INC = '1' and AR_PNTR_1 = 7 and SBIT = '0' then + case OP_SIZE is + when BYTE => USP_REG <= USP_REG + "10"; -- Increment by two! + when WORD => USP_REG <= USP_REG + "10"; -- Increment by two. + when others => USP_REG <= USP_REG + "100"; -- Increment by four, (LONG). + end case; + end if; + + if AR_DEC = '1' and AR_PNTR_1 = 7 and SBIT = '0' then + case OP_SIZE is + when BYTE => USP_REG <= USP_REG - "10"; -- Decrement by two! + when WORD => USP_REG <= USP_REG - "10"; -- Decrement by two. + when others => USP_REG <= USP_REG - "100"; -- Decrement by four, (LONG). + end case; + end if; + + if USP_WR = '1' then + USP_REG <= AR_IN_1; + elsif SP_ADD_DISPL = '1' and AR_INC = '1' and SBIT = '0' then + USP_REG <= USP_REG + DISPLACEMENT + "100"; -- Used for RTD. + elsif SP_ADD_DISPL = '1' and SBIT = '0' then + USP_REG <= USP_REG + DISPLACEMENT; + end if; + + ---------------------------------- ISP / USP section ---------------------------------------- + if AR_WR_2 = '1' and AR_PNTR_WB_2 = 7 and SBIT_WB = '1' then + ISP_REG <= AR_IN_2; -- Used for EXG and UNLK. + elsif AR_WR_2 = '1' and AR_PNTR_WB_2 = 7 then + USP_REG <= AR_IN_2; -- Used for EXG and UNLK. + end if; + end process STACK_POINTERS; + + ADDRESS_REGISTERS: process + -- The registers are modeled in a way + -- that write and simultaneously increment + -- decrement and others are possible for + -- different registers. + begin + -- + wait until CLK = '1' and CLK' event; + + if RESET = '1' then + AR <= (others => (Others => '0')); + end if; + + if AR_WR_1 = '1' and AR_PNTR_WB_1 < 7 then + AR(AR_PNTR_WB_1) <= AR_IN_1; -- Always written long. + end if; + + if AR_INC = '1' and AR_PNTR_1 < 7 then + case OP_SIZE is + when BYTE => AR(AR_PNTR_1) <= AR(AR_PNTR_1) + '1'; + when WORD => AR(AR_PNTR_1) <= AR(AR_PNTR_1) + "10"; + when others => AR(AR_PNTR_1) <= AR(AR_PNTR_1) + "100"; + end case; + end if; + + if AR_DEC = '1' and AR_PNTR_1 < 7 then + case OP_SIZE is + when BYTE => AR(AR_PNTR_1) <= AR(AR_PNTR_1) - '1'; + when WORD => AR(AR_PNTR_1) <= AR(AR_PNTR_1) - "10"; + when others => AR(AR_PNTR_1) <= AR(AR_PNTR_1) - "100"; + end case; + end if; + + if AR_WR_2 = '1' and AR_PNTR_WB_2 < 7 then + AR(AR_PNTR_WB_2) <= AR_IN_2; -- Used for EXG and UNLK. + end if; + end process ADDRESS_REGISTERS; + + FCODES: process + -- These flip flops provide the alternate function + -- code registers. + variable SFC_REG : std_logic_vector(2 downto 0); + variable DFC_REG : std_logic_vector(2 downto 0); + begin + wait until CLK = '1' and CLK' event; + if DFC_WR = '1' then + DFC_REG := AR_IN_1(2 downto 0); + end if; + -- + if SFC_WR = '1' then + SFC_REG := AR_IN_1(2 downto 0); + end if; + -- + DFC <= DFC_REG; + SFC <= SFC_REG; + end process FCODES; +end BEHAVIOR; diff --git a/common/CPU/68K10/wf68k10_alu.vhd b/common/CPU/68K10/wf68k10_alu.vhd new file mode 100644 index 00000000..5c7cdb78 --- /dev/null +++ b/common/CPU/68K10/wf68k10_alu.vhd @@ -0,0 +1,1071 @@ +------------------------------------------------------------------------ +---- ---- +---- WF68K10 IP Core: Address register logic. ---- +---- ---- +---- Description: ---- +---- This arithmetical logical unit handles all integer operations. ---- +---- The shift operations are computed by a standard shifter within ---- +---- up to 32 clock cycles depending on the shift width. The multi- ---- +---- plication is modeled as a hardware multiplier which calculates ---- +---- the result in one clock cycle. The division requires 32 clock ---- +---- cycles for 32 bit wide operands. The date which is required ---- +---- for the respective operation is stored in registers. The ALU ---- +---- works together with the writeback of the operands as third ---- +---- stage in the pipelined architecture. The handshaking is provi- ---- +---- ded by ALU_REQ, ALU_ACK and ALU_BUSY. For more information ---- +---- refer to the MC68010 User' Manual. ---- +---- ---- +---- Author(s): ---- +---- - Wolfgang Foerster, wf@experiment-s.de; wf@inventronik.de ---- +---- ---- +------------------------------------------------------------------------ +---- ---- +---- Copyright 2014-2019 Wolfgang Foerster Inventronik GmbH. ---- +---- ---- +---- This documentation describes Open Hardware and is licensed ---- +---- under the CERN OHL v. 1.2. You may redistribute and modify ---- +---- this documentation under the terms of the CERN OHL v.1.2. ---- +---- (http://ohwr.org/cernohl). This documentation is distributed ---- +---- WITHOUT ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING OF ---- +---- MERCHANTABILITY, SATISFACTORY QUALITY AND FITNESS FOR A ---- +---- PARTICULAR PURPOSE. Please see the CERN OHL v.1.2 for ---- +---- applicable conditions ---- +---- ---- +------------------------------------------------------------------------ +-- +-- Revision History +-- +-- Revision 2K14B 20141201 WF +-- Initial Release. +-- Revision 2K18A 20180620 WF +-- Bug fix: MOVEM sign extension. +-- Fix for restoring correct values during the DIVS and DIVU in word format. +-- Fixed the SUBQ calculation. +-- Rearranged the Offset for the JSR instruction. +-- EXT instruction uses now RESULT(63 downto 0). +-- Shifter signals now ready if shift width is zero. +-- Fixed wrong condition codes for AND_B, ANDI, EOR, EORI, OR_B, ORI and NOT_B. +-- Fixed writeback issues in the status register logic. +-- Fixed the condition code calculation for NEG and NEGX. +-- Revision 2K19A 20190419 WF +-- Fixed a bug in MULU.W (input operands are now 16 bit wide). +-- + +library work; +use work.WF68K10_PKG.all; + +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_unsigned.all; +use ieee.numeric_std.all; + +entity WF68K10_ALU is + port ( + CLK : in std_logic; + RESET : in bit; + + LOAD_OP1 : in bit; + LOAD_OP2 : in bit; + LOAD_OP3 : in bit; + + OP1_IN : in Std_Logic_Vector(31 downto 0); + OP2_IN : in Std_Logic_Vector(31 downto 0); + OP3_IN : in Std_Logic_Vector(31 downto 0); + + BITPOS_IN : in Std_Logic_Vector(4 downto 0); + + RESULT : out Std_Logic_Vector(63 downto 0); + + ADR_MODE_IN : in Std_Logic_Vector(2 downto 0); + OP_SIZE_IN : in OP_SIZETYPE; + OP_IN : in OP_68K; + OP_WB : in OP_68K; + BIW_0_IN : in Std_Logic_Vector(11 downto 0); + BIW_1_IN : in Std_Logic_Vector(15 downto 0); + + -- The Flags: + SR_WR : in bit; + SR_INIT : in bit; + CC_UPDT : in bit; + + STATUS_REG_OUT : out std_logic_vector(15 downto 0); + ALU_COND : out boolean; + + -- Status and Control: + ALU_INIT : in bit; -- Strobe. + ALU_BSY : out bit; + ALU_REQ : buffer bit; + ALU_ACK : in bit; + IRQ_PEND : in std_logic_vector(2 downto 0); + TRAP_CHK : out bit; -- Trap due to the CHK instruction. + TRAP_DIVZERO : out bit -- Trap due to divide by zero. + ); +end entity WF68K10_ALU; + +architecture BEHAVIOUR of WF68K10_ALU is +type DIV_STATES is (IDLE, INIT, CALC); +type SHIFT_STATES is (IDLE, RUN); +signal ALU_COND_I : boolean; +signal ADR_MODE : Std_Logic_Vector(2 downto 0); +signal BITPOS : integer range 0 to 31; +signal BIW_0 : Std_Logic_Vector(11 downto 0); +signal BIW_1 : Std_Logic_Vector(15 downto 0); +signal CB_BCD : std_logic; +signal CHK_CMP_COND : boolean; +signal DIV_RDY : bit; +signal DIV_STATE : DIV_STATES := IDLE; +signal MSB : integer range 0 to 31; +signal OP : OP_68K := UNIMPLEMENTED; +signal OP1 : Std_Logic_Vector(31 downto 0); +signal OP2 : Std_Logic_Vector(31 downto 0); +signal OP3 : Std_Logic_Vector(31 downto 0); +signal OP1_SIGNEXT : Std_Logic_Vector(31 downto 0); +signal OP2_SIGNEXT : Std_Logic_Vector(31 downto 0); +signal OP_SIZE : OP_SIZETYPE := LONG; +signal QUOTIENT : unsigned(31 downto 0); +signal REMAINDER : unsigned(31 downto 0); +signal RESULT_BCDOP : Std_Logic_Vector(7 downto 0); +signal RESULT_BITOP : Std_Logic_Vector(31 downto 0); +signal RESULT_INTOP : Std_Logic_Vector(31 downto 0); +signal RESULT_LOGOP : Std_Logic_Vector(31 downto 0); +signal RESULT_MUL : Std_Logic_Vector(63 downto 0); +signal RESULT_SHIFTOP : Std_Logic_Vector(31 downto 0); +signal RESULT_OTHERS : Std_Logic_Vector(31 downto 0); +signal SHIFT_STATE : SHIFT_STATES; +signal SHIFT_WIDTH : Std_Logic_Vector(5 downto 0); +signal SHIFT_WIDTH_IN : Std_Logic_Vector(5 downto 0); +signal SHFT_LOAD : bit; +signal SHFT_RDY : bit; +signal SHFT_EN : bit; +signal STATUS_REG : Std_Logic_Vector(15 downto 0); +signal VFLAG_DIV : std_logic; +signal XFLAG_SHFT : std_logic; +signal XNZVC : Std_Logic_Vector(4 downto 0); +begin + PARAMETER_BUFFER: process + begin + wait until CLK = '1' and CLK' event; + if ALU_INIT = '1' then + ADR_MODE <= ADR_MODE_IN; + OP_SIZE <= OP_SIZE_IN; + OP <= OP_IN; + BIW_0 <= BIW_0_IN; + BIW_1 <= BIW_1_IN; + BITPOS <= To_Integer(unsigned(BITPOS_IN)); + SHIFT_WIDTH <= SHIFT_WIDTH_IN; + end if; + end process PARAMETER_BUFFER; + + OPERANDS: process + -- During instruction execution, the buffers are written + -- before or during ALU_INIT and copied to the operands + -- during ALU_INIT. + variable OP1_BUFFER : Std_Logic_Vector(31 downto 0); + variable OP2_BUFFER : Std_Logic_Vector(31 downto 0); + variable OP3_BUFFER : Std_Logic_Vector(31 downto 0); + begin + wait until CLK = '1' and CLK' event; + + if LOAD_OP1 = '1' then + OP1_BUFFER := OP1_IN; + end if; + + if LOAD_OP2 = '1' then + OP2_BUFFER := OP2_IN; + end if; + + if LOAD_OP3 = '1' then + OP3_BUFFER := OP3_IN; + end if; + + if ALU_INIT = '1' then + OP1 <= OP1_BUFFER; + OP2 <= OP2_BUFFER; + OP3 <= OP3_BUFFER; + end if; + end process OPERANDS; + + P_BUSY: process + begin + wait until CLK = '1' and CLK' event; + if ALU_INIT = '1' then + ALU_BSY <= '1'; + elsif ALU_ACK = '1' or RESET = '1' then + ALU_BSY <= '0'; + end if; + -- This signal requests the control state machine to proceed when the ALU is ready. + if ALU_ACK = '1' then + ALU_REQ <= '0'; + elsif (OP = ASL or OP = ASR or OP = LSL or OP = LSR or OP = ROTL or OP = ROTR or OP = ROXL or OP = ROXR) and SHFT_RDY = '1' then + ALU_REQ <= '1'; + elsif (OP = DIVS or OP = DIVU) and DIV_RDY = '1' then + ALU_REQ <= '1'; + elsif OP_IN = DIVS or OP_IN = DIVU then + null; + elsif OP_IN = ASL or OP_IN = ASR or OP_IN = LSL or OP_IN = LSR then + null; + elsif OP_IN = ROTL or OP_IN = ROTR or OP_IN = ROXL or OP_IN = ROXR then + null; + elsif ALU_INIT = '1' then + ALU_REQ <= '1'; + end if; + end process P_BUSY; + + with OP_SIZE select + MSB <= 31 when LONG, + 15 when WORD, + 7 when BYTE; + + SIGNEXT: process(OP, OP1, OP2, OP3, OP_SIZE) + -- This module provides the required sign extensions. + begin + case OP_SIZE is + when LONG => + OP1_SIGNEXT <= OP1; + OP2_SIGNEXT <= OP2; + when WORD => + for i in 31 downto 16 loop + OP1_SIGNEXT(i) <= OP1(15); + OP2_SIGNEXT(i) <= OP2(15); + end loop; + OP1_SIGNEXT(15 downto 0) <= OP1(15 downto 0); + OP2_SIGNEXT(15 downto 0) <= OP2(15 downto 0); + when BYTE => + for i in 31 downto 8 loop + OP1_SIGNEXT(i) <= OP1(7); + OP2_SIGNEXT(i) <= OP2(7); + end loop; + OP1_SIGNEXT(7 downto 0) <= OP1(7 downto 0); + OP2_SIGNEXT(7 downto 0) <= OP2(7 downto 0); + end case; + end process SIGNEXT; + + P_BCDOP: process(OP, STATUS_REG, OP1, OP2) + -- The BCD operations are all byte wide and unsigned. + variable X_IN_I : unsigned(0 downto 0); + variable TEMP0 : unsigned(4 downto 0); + variable TEMP1 : unsigned(4 downto 0); + variable Z_0 : unsigned(3 downto 0); + variable C_0 : unsigned(0 downto 0); + variable Z_1 : unsigned(3 downto 0); + variable C_1 : std_logic; + variable S_0 : unsigned(3 downto 0); + variable S_1 : unsigned(3 downto 0); + begin + X_IN_I(0) := STATUS_REG(4); -- Inverted extended Flag. + + case OP is + when ABCD => + TEMP0 := unsigned('0' & OP2(3 downto 0)) + unsigned('0' & OP1(3 downto 0)) + ("0000" & X_IN_I); + when NBCD => + TEMP0 := unsigned(OP1(4 downto 0)) - unsigned('0' & OP2(3 downto 0)) - ("0000" & X_IN_I); + when others => -- Valid for SBCD. + TEMP0 := unsigned('0' & OP2(3 downto 0)) - unsigned('0' & OP1(3 downto 0)) - ("0000" & X_IN_I); + end case; + + if Std_Logic_Vector(TEMP0) > "01001" then + Z_0 := "0110"; + C_0 := "1"; + else + Z_0 := "0000"; + C_0 := "0"; + end if; + + case OP is + when ABCD => + TEMP1 := unsigned('0' & OP2(7 downto 4)) + unsigned('0' & OP1(7 downto 4)) + ("0000" & C_0); + when NBCD => + TEMP1 := unsigned(OP1(4 downto 0)) - unsigned('0' & OP2(7 downto 4)) - ("0000" & X_IN_I); + when others => -- Valid for SBCD. + TEMP1 := unsigned('0' & OP2(7 downto 4)) - unsigned('0' & OP1(7 downto 4)) - ("0000" & C_0); + end case; + + if Std_Logic_Vector(TEMP1) > "01001" then + Z_1 := "0110"; + C_1 := '1'; + else + Z_1 := "0000"; + C_1 := '0'; + end if; + + case OP is + when ABCD => + S_1 := TEMP1(3 downto 0) + Z_1; + S_0 := TEMP0(3 downto 0) + Z_0; + when others => -- Valid for SBCD, NBCD. + S_1 := TEMP1(3 downto 0) - Z_1; + S_0 := TEMP0(3 downto 0) - Z_0; + end case; + -- + CB_BCD <= C_1; + RESULT_BCDOP(7 downto 4) <= Std_Logic_Vector(S_1); + RESULT_BCDOP(3 downto 0) <= Std_Logic_Vector(S_0); + end process P_BCDOP; + + P_BITOP: process(BITPOS, OP, OP2) + -- Bit manipulation operations. + begin + RESULT_BITOP <= OP2; -- The default is the unmanipulated data. + -- + case OP is + when BCHG => + RESULT_BITOP(BITPOS) <= not OP2(BITPOS); + when BCLR => + RESULT_BITOP(BITPOS) <= '0'; + when BSET => + RESULT_BITOP(BITPOS) <= '1'; + when others => + RESULT_BITOP <= OP2; -- Dummy, no result required for BTST. + end case; + end process P_BITOP; + + DIVISION: process + variable BITCNT : integer range 0 to 64; + variable DIVIDEND : unsigned(63 downto 0); + variable DIVISOR : unsigned(31 downto 0); + variable QUOTIENT_REST : unsigned(31 downto 0); + variable QUOTIENT_VAR : unsigned(31 downto 0); + variable REMAINDER_REST : unsigned(31 downto 0); + variable REMAINDER_VAR : unsigned(31 downto 0); + -- Be aware, that the destination and source operands + -- may be reloaded during the division operation. For + -- this, we use the restore values in case of an overflow. + begin + wait until CLK = '1' and CLK' event; + DIV_RDY <= '0'; + case DIV_STATE is + when IDLE => + if ALU_INIT = '1' and (OP_IN = DIVS or OP_IN = DIVU) then + DIV_STATE <= INIT; + end if; + when INIT => + if OP = DIVS and OP_SIZE = LONG and BIW_1(10) = '1' and OP3(31) = '1' then -- 64 bit signed negative dividend. + DIVIDEND := unsigned(not (OP3 & OP2) + '1'); + elsif (OP = DIVS or OP = DIVU) and OP_SIZE = LONG and BIW_1(10) = '1' then -- 64 bit positive or unsigned dividend. + DIVIDEND := unsigned(OP3 & OP2); + elsif OP = DIVS and OP2(31) = '1' then -- 32 bit signed negative dividend. + DIVIDEND := x"00000000" & unsigned(not(OP2) + '1'); + else -- 32 bit positive or unsigned dividend. + DIVIDEND := x"00000000" & unsigned(OP2); + end if; + + if OP = DIVS and OP_SIZE = LONG and OP1(31) = '1' then -- 32 bit signed negative divisor. + DIVISOR := unsigned(not OP1 + '1'); + elsif OP_SIZE = LONG then -- 32 bit positive or unsigned divisor. + DIVISOR := unsigned(OP1); + elsif OP = DIVS and OP_SIZE = WORD and OP1(15) = '1' then -- 16 bit signed negative divisor. + DIVISOR := x"0000" & unsigned(not OP1(15 downto 0) + '1'); + else -- 16 bit posive or unsigned divisor. + DIVISOR := x"0000" & unsigned(OP1(15 downto 0)); + end if; + + VFLAG_DIV <= '0'; + QUOTIENT <= (others => '0'); + QUOTIENT_VAR := (others => '0'); + QUOTIENT_REST := unsigned(OP2); + + REMAINDER <= (others => '0'); + REMAINDER_VAR := (others => '0'); + + case OP_SIZE is + when LONG => REMAINDER_REST := unsigned(OP3); + when others => REMAINDER_REST := unsigned(x"0000" & OP2(31 downto 16)); + end case; + + if OP_SIZE = LONG and BIW_1(10) = '1' then + BITCNT := 64; + else + BITCNT := 32; + end if; + + if DIVISOR = x"00000000" then -- Division by zero. + QUOTIENT <= (others => '1'); + REMAINDER <= (others => '1'); + DIV_STATE <= IDLE; + DIV_RDY <= '1'; + elsif x"00000000" & DIVISOR > DIVIDEND then -- Divisor > dividend. + REMAINDER <= DIVIDEND(31 downto 0); + DIV_STATE <= IDLE; + DIV_RDY <= '1'; + elsif x"00000000" & DIVISOR = DIVIDEND then -- Result is 1. + QUOTIENT <= x"00000001"; + DIV_STATE <= IDLE; + DIV_RDY <= '1'; + else + DIV_STATE <= CALC; + end if; + when CALC => + BITCNT := BITCNT - 1; + -- + if REMAINDER_VAR & DIVIDEND(BITCNT) < DIVISOR then + REMAINDER_VAR := REMAINDER_VAR(30 downto 0) & DIVIDEND(BITCNT); + elsif OP_SIZE = LONG and BITCNT > 31 then -- Division overflow in 64 bit mode. + VFLAG_DIV <= '1'; + DIV_STATE <= IDLE; + DIV_RDY <= '1'; + QUOTIENT <= QUOTIENT_REST; + REMAINDER <= REMAINDER_REST; + elsif OP_SIZE = WORD and BITCNT > 15 then -- Division overflow in 64 bit mode. + VFLAG_DIV <= '1'; + DIV_STATE <= IDLE; + DIV_RDY <= '1'; + QUOTIENT <= QUOTIENT_REST; + REMAINDER <= REMAINDER_REST; + else + REMAINDER_VAR := (REMAINDER_VAR(30 downto 0) & DIVIDEND(BITCNT)) - DIVISOR; + QUOTIENT_VAR(BITCNT) := '1'; + end if; + -- + if BITCNT = 0 then + -- Adjust signs: + if OP = DIVS and OP_SIZE = LONG and BIW_1(10) = '1' and (OP3(31) xor OP1(31)) = '1' then + QUOTIENT <= not QUOTIENT_VAR + 1; -- Negative, change sign. + elsif OP = DIVS and OP_SIZE = LONG and BIW_1(10) = '0' and (OP2(31) xor OP1(31)) = '1' then + QUOTIENT <= not QUOTIENT_VAR + 1; -- Negative, change sign. + elsif OP = DIVS and OP_SIZE = WORD and (OP2(31) xor OP1(15)) = '1' then + QUOTIENT <= not QUOTIENT_VAR + 1; -- Negative, change sign. + else + QUOTIENT <= QUOTIENT_VAR; + end if; + -- + REMAINDER <= REMAINDER_VAR; + DIV_RDY <= '1'; + DIV_STATE <= IDLE; + end if; + end case; + end process DIVISION; + + P_INTOP: process(OP, OP1, OP1_SIGNEXT, OP2, OP2_SIGNEXT, ADR_MODE, STATUS_REG, RESULT_INTOP) + -- The integer arithmetics ADD, SUB, NEG and CMP in their different variations are modelled here. + variable X_IN_I : Std_Logic_Vector(0 downto 0); + variable RESULT : unsigned(31 downto 0); + begin + X_IN_I(0) := STATUS_REG(4); -- Extended Flag. + case OP is + when ADDA => -- No sign extension for the destination. + RESULT := unsigned(OP2) + unsigned(OP1_SIGNEXT); + when ADDQ => + case ADR_MODE is + when "001" => RESULT := unsigned(OP2) + unsigned(OP1); -- No sign extension for address destination. + when others => RESULT := unsigned(OP2_SIGNEXT) + unsigned(OP1); + end case; + when SUBQ => + case ADR_MODE is + when "001" => RESULT := unsigned(OP2) - unsigned(OP1); -- No sign extension for address destination. + when others => RESULT := unsigned(OP2_SIGNEXT) - unsigned(OP1); + end case; + when ADD | ADDI => + RESULT := unsigned(OP2_SIGNEXT) + unsigned(OP1_SIGNEXT); + when ADDX => + RESULT := unsigned(OP2_SIGNEXT) + unsigned(OP1_SIGNEXT) + unsigned(X_IN_I); + when CMPA | DBcc | SUBA => -- No sign extension for the destination. + RESULT := unsigned(OP2) - unsigned(OP1_SIGNEXT); + when CMP | CMPI | CMPM | SUB | SUBI => + RESULT := unsigned(OP2_SIGNEXT) - unsigned(OP1_SIGNEXT); + when SUBX => + RESULT := unsigned(OP2_SIGNEXT) - unsigned(OP1_SIGNEXT) - unsigned(X_IN_I); + when NEG => + RESULT := unsigned(OP1_SIGNEXT) - unsigned(OP2_SIGNEXT); + when NEGX => + RESULT := unsigned(OP1_SIGNEXT) - unsigned(OP2_SIGNEXT) - unsigned(X_IN_I); + when CLR => + RESULT := (others => '0'); + when others => + RESULT := (others => '0'); -- Don't care. + end case; + RESULT_INTOP <= Std_Logic_Vector(RESULT); + end process P_INTOP; + + P_LOGOP: process(OP, OP1, OP2) + -- This process provides the logic operations: + -- AND, OR, XOR and NOT. + -- The logic operations require no signed / unsigned + -- modelling. + begin + case OP is + when AND_B | ANDI | ANDI_TO_CCR | ANDI_TO_SR => + RESULT_LOGOP <= OP1 and OP2; + when OR_B | ORI | ORI_TO_CCR | ORI_TO_SR => + RESULT_LOGOP <= OP1 or OP2; + when EOR | EORI | EORI_TO_CCR | EORI_TO_SR => + RESULT_LOGOP <= OP1 xor OP2; + when others => -- NOT_B. + RESULT_LOGOP <= not OP2; + end case; + end process P_LOGOP; + + RESULT_MUL <= Std_Logic_Vector(signed(OP1_SIGNEXT) * signed(OP2_SIGNEXT)) when OP = MULS else + Std_Logic_Vector(unsigned(OP1) * unsigned(OP2)) when OP_SIZE = LONG else + Std_Logic_Vector(unsigned(x"0000" & OP1(15 downto 0)) * unsigned(x"0000" & OP2(15 downto 0))); + + P_OTHERS: process(ALU_COND_I, BIW_0, OP, OP1, OP2, OP1_SIGNEXT, OP2_SIGNEXT, OP_SIZE) + -- This process provides the calculation for special operations. + variable RESULT : unsigned(31 downto 0); + begin + RESULT := (others => '0'); + case OP is + when EXT => + case BIW_0(8 downto 6) is + when "011" => + for i in 31 downto 16 loop + RESULT(i) := OP2(15); + end loop; + RESULT(15 downto 0) := unsigned(OP2(15 downto 0)); + when others => -- Word. + for i in 15 downto 8 loop + RESULT(i) := OP2(7); + end loop; + RESULT(31 downto 16) := unsigned(OP2(31 downto 16)); + RESULT(7 downto 0) := unsigned(OP2(7 downto 0)); + end case; + when JSR => + RESULT := unsigned(OP1) + "10"; -- Add offset of two to the Pointer of the last extension word. + when MOVEQ => + for i in 31 downto 8 loop + RESULT(i) := OP1(7); + end loop; + RESULT(7 downto 0) := unsigned(OP1(7 downto 0)); + when Scc => + if ALU_COND_I = true then + RESULT := (others => '1'); + else + RESULT := (others => '0'); + end if; + when SWAP => + RESULT := unsigned(OP2(15 downto 0)) & unsigned(OP2(31 downto 16)); + when TAS => + RESULT := x"000000" & '1' & unsigned(OP2(6 downto 0)); -- Set the MSB. + when LINK | TST => + RESULT := unsigned(OP2); + when MOVEA | MOVEM | MOVES => + RESULT := unsigned(OP1_SIGNEXT); + when others => -- MOVE_FROM_CCR, MOVE_TO_CCR, MOVE_FROM_SR, MOVE_TO_SR, MOVE, MOVEC, MOVEP, STOP. + RESULT := unsigned(OP1); + end case; + RESULT_OTHERS <= Std_Logic_Vector(RESULT); + end process P_OTHERS; + + SHFT_LOAD <= '1' when ALU_INIT = '1' and (OP_IN = ASL or OP_IN = ASR) else + '1' when ALU_INIT = '1' and (OP_IN = LSL or OP_IN = LSR) else + '1' when ALU_INIT = '1' and (OP_IN = ROTL or OP_IN = ROTR) else + '1' when ALU_INIT = '1' and (OP_IN = ROXL or OP_IN = ROXR) else '0'; + + SHIFT_WIDTH_IN <= "000001" when BIW_0_IN(7 downto 6) = "11" else -- Memory shifts. + "001000" when BIW_0_IN(5) = '0' and BIW_0_IN(11 downto 9) = "000" else -- Direct. + "000" & BIW_0_IN(11 downto 9) when BIW_0_IN(5) = '0' else -- Direct. + OP1_IN(5 downto 0); + + P_SHFT_CTRL: process + -- The variable shift or rotate length requires a control + -- to achieve the correct OPERAND manipulation. + variable BIT_CNT : std_logic_vector(5 downto 0); + begin + wait until CLK = '1' and CLK' event; + + SHFT_RDY <= '0'; + + if SHIFT_STATE = IDLE then + if SHFT_LOAD = '1' and SHIFT_WIDTH_IN = "000000" then + SHFT_RDY <= '1'; + elsif SHFT_LOAD = '1' then + SHIFT_STATE <= RUN; + BIT_CNT := SHIFT_WIDTH_IN; + SHFT_EN <= '1'; + else + SHIFT_STATE <= IDLE; + BIT_CNT := (others => '0'); + SHFT_EN <= '0'; + end if; + elsif SHIFT_STATE = RUN then + if BIT_CNT = "000001" then + SHIFT_STATE <= IDLE; + SHFT_EN <= '0'; + SHFT_RDY <= '1'; + else + SHIFT_STATE <= RUN; + BIT_CNT := BIT_CNT - '1'; + SHFT_EN <= '1'; + end if; + end if; + end process P_SHFT_CTRL; + + SHIFTER: process + begin + wait until CLK = '1' and CLK' event; + if SHFT_LOAD = '1' then -- Load data in the shifter unit. + RESULT_SHIFTOP <= OP2_IN; -- Load data for the shift or rotate operations. + elsif SHFT_EN = '1' then -- Shift and rotate operations: + case OP is + when ASL => + if OP_SIZE = LONG then + RESULT_SHIFTOP <= RESULT_SHIFTOP(30 downto 0) & '0'; + elsif OP_SIZE = WORD then + RESULT_SHIFTOP <= x"0000" & RESULT_SHIFTOP(14 downto 0) & '0'; + else -- OP_SIZE = BYTE. + RESULT_SHIFTOP <= x"000000" & RESULT_SHIFTOP(6 downto 0) & '0'; + end if; + when ASR => + if OP_SIZE = LONG then + RESULT_SHIFTOP <= RESULT_SHIFTOP(31) & RESULT_SHIFTOP(31 downto 1); + elsif OP_SIZE = WORD then + RESULT_SHIFTOP <= x"0000" & RESULT_SHIFTOP(15) & RESULT_SHIFTOP(15 downto 1); + else -- OP_SIZE = BYTE. + RESULT_SHIFTOP <= x"000000" & RESULT_SHIFTOP(7) & RESULT_SHIFTOP(7 downto 1); + end if; + when LSL => + if OP_SIZE = LONG then + RESULT_SHIFTOP <= RESULT_SHIFTOP(30 downto 0) & '0'; + elsif OP_SIZE = WORD then + RESULT_SHIFTOP <= x"0000" & RESULT_SHIFTOP(14 downto 0) & '0'; + else -- OP_SIZE = BYTE. + RESULT_SHIFTOP <= x"000000" & RESULT_SHIFTOP(6 downto 0) & '0'; + end if; + when LSR => + if OP_SIZE = LONG then + RESULT_SHIFTOP <= '0' & RESULT_SHIFTOP(31 downto 1); + elsif OP_SIZE = WORD then + RESULT_SHIFTOP <= x"0000" & '0' & RESULT_SHIFTOP(15 downto 1); + else -- OP_SIZE = BYTE. + RESULT_SHIFTOP <= x"000000" & '0' & RESULT_SHIFTOP(7 downto 1); + end if; + when ROTL => + if OP_SIZE = LONG then + RESULT_SHIFTOP <= RESULT_SHIFTOP(30 downto 0) & RESULT_SHIFTOP(31); + elsif OP_SIZE = WORD then + RESULT_SHIFTOP <= x"0000" & RESULT_SHIFTOP(14 downto 0) & RESULT_SHIFTOP(15); + else -- OP_SIZE = BYTE. + RESULT_SHIFTOP <= x"000000" & RESULT_SHIFTOP(6 downto 0) & RESULT_SHIFTOP(7); + end if; + -- X not affected; + when ROTR => + if OP_SIZE = LONG then + RESULT_SHIFTOP <= RESULT_SHIFTOP(0) & RESULT_SHIFTOP(31 downto 1); + elsif OP_SIZE = WORD then + RESULT_SHIFTOP <= x"0000" & RESULT_SHIFTOP(0) & RESULT_SHIFTOP(15 downto 1); + else -- OP_SIZE = BYTE. + RESULT_SHIFTOP <= x"000000" & RESULT_SHIFTOP(0) & RESULT_SHIFTOP(7 downto 1); + end if; + -- X not affected; + when ROXL => + if OP_SIZE = LONG then + RESULT_SHIFTOP <= RESULT_SHIFTOP(30 downto 0) & XFLAG_SHFT; + elsif OP_SIZE = WORD then + RESULT_SHIFTOP <= x"0000" & RESULT_SHIFTOP(14 downto 0) & XFLAG_SHFT; + else -- OP_SIZE = BYTE. + RESULT_SHIFTOP <= x"000000" & RESULT_SHIFTOP(6 downto 0) & XFLAG_SHFT; + end if; + when ROXR => + if OP_SIZE = LONG then + RESULT_SHIFTOP <= XFLAG_SHFT & RESULT_SHIFTOP(31 downto 1); + elsif OP_SIZE = WORD then + RESULT_SHIFTOP <= x"0000" & XFLAG_SHFT & RESULT_SHIFTOP(15 downto 1); + else -- OP_SIZE = BYTE. + RESULT_SHIFTOP <= x"000000" & XFLAG_SHFT & RESULT_SHIFTOP(7 downto 1); + end if; + when others => null; -- Unaffected, forbidden. + end case; + end if; + end process SHIFTER; + + P_OUT: process + begin + wait until CLK = '1' and CLK' event; + case OP is + when ABCD | NBCD | SBCD => + RESULT <= x"00000000000000" & RESULT_BCDOP; -- Byte only. + when BCHG | BCLR | BSET | BTST => + RESULT <= x"00000000" & RESULT_BITOP; + when ADD | ADDA | ADDI | ADDQ | ADDX | CLR | CMP | CMPA | CMPI => + RESULT <= x"00000000" & RESULT_INTOP; + when CMPM | DBcc | NEG | NEGX | SUB | SUBA | SUBI | SUBQ | SUBX => + RESULT <= x"00000000" & RESULT_INTOP; + when AND_B | ANDI | EOR | EORI | NOT_B | OR_B | ORI => + RESULT <= x"00000000" & RESULT_LOGOP; + when ANDI_TO_SR | EORI_TO_SR | ORI_TO_SR => -- Used for branch prediction. + RESULT <= x"00000000" & RESULT_LOGOP; + when ASL | ASR | LSL | LSR | ROTL | ROTR | ROXL | ROXR => + RESULT <= x"00000000" & RESULT_SHIFTOP; + when DIVS | DIVU => + case OP_SIZE is + when LONG => RESULT <= Std_Logic_Vector(REMAINDER) & Std_Logic_Vector(QUOTIENT); + when others => RESULT <= x"00000000" & Std_Logic_Vector(REMAINDER(15 downto 0)) & Std_Logic_Vector(QUOTIENT(15 downto 0)); + end case; + when MULS | MULU => + RESULT <= RESULT_MUL; + when others => + RESULT <= OP2 & RESULT_OTHERS; -- OP2 is used for EXG. + end case; + end process P_OUT; + + -- Out of bounds condition: + CHK_CMP_COND <= true when OP = CHK and OP2_SIGNEXT(MSB) = '1' else -- Negative destination. + true when OP = CHK and signed(OP2_SIGNEXT) > signed(OP1_SIGNEXT) else false; + + -- All traps must be modeled as strobes. + TRAP_CHK <= '1' when ALU_ACK = '1' and OP = CHK and CHK_CMP_COND = true else '0'; + TRAP_DIVZERO <= '1' when ALU_INIT = '1' and (OP_IN = DIVS or OP_IN = DIVU) and OP1_IN = x"00000000" else '0'; + + COND_CODES: process(BIW_1, BITPOS, CB_BCD, CHK_CMP_COND, CLK, OP1, OP1_SIGNEXT, OP2, OP2_SIGNEXT, + MSB, OP, OP_SIZE, QUOTIENT, RESULT_BCDOP, RESULT_INTOP, RESULT_LOGOP, RESULT_MUL, RESULT_SHIFTOP, + RESULT_OTHERS, SHIFT_WIDTH, STATUS_REG, VFLAG_DIV, XFLAG_SHFT) + -- In this process all the condition codes X (eXtended), N (Negative) + -- Z (Zero), V (oVerflow) and C (Carry / borrow) are calculated for + -- all integer operations. Except for the MULS, MULU, DIVS, DIVU the + -- new conditions are valid one clock cycle after the operation starts. + -- For the multiplication and the division, the codes are valid after + -- BUSY is released. + variable TMP : std_logic; + variable Z, RM, SM, DM : std_logic; + variable CFLAG_SHFT : std_logic; + variable VFLAG_SHFT : std_logic; + variable NFLAG_DIV : std_logic; + variable NFLAG_MUL : std_logic; + variable VFLAG_MUL : std_logic; + variable RM_SM_DM : bit_vector(2 downto 0); + begin + -- Shifter C, X and V flags: + if CLK = '1' and CLK' event then + if SHFT_LOAD = '1' or SHIFT_WIDTH = "000000" then + XFLAG_SHFT <= STATUS_REG(4); + elsif SHFT_EN = '1' then + case OP is + when ROTL | ROTR => + XFLAG_SHFT <= STATUS_REG(4); -- Unaffected. + when ASL | LSL | ROXL => + case OP_SIZE is + when LONG => + XFLAG_SHFT <= RESULT_SHIFTOP(31); + when WORD => + XFLAG_SHFT <= RESULT_SHIFTOP(15); + when BYTE => + XFLAG_SHFT <= RESULT_SHIFTOP(7); + end case; + when others => -- ASR, LSR, ROXR. + XFLAG_SHFT <= RESULT_SHIFTOP(0); + end case; + end if; + -- + if (OP = ROXL or OP = ROXR) and SHIFT_WIDTH = "000000" then + CFLAG_SHFT := STATUS_REG(4); + elsif SHIFT_WIDTH = "000000" then + CFLAG_SHFT := '0'; + elsif SHFT_EN = '1' then + case OP is + when ASL | LSL | ROTL | ROXL => + case OP_SIZE is + when LONG => + CFLAG_SHFT := RESULT_SHIFTOP(31); + when WORD => + CFLAG_SHFT := RESULT_SHIFTOP(15); + when BYTE => + CFLAG_SHFT := RESULT_SHIFTOP(7); + end case; + when others => -- ASR, LSR, ROTR, ROXR + CFLAG_SHFT := RESULT_SHIFTOP(0); + end case; + end if; + -- + -- This logic provides a detection of any toggling of the most significant + -- bit of the shifter unit during the ASL shift process. For all other shift + -- operations, the V flag is always zero. + if SHFT_LOAD = '1' or SHIFT_WIDTH = "000000" then + VFLAG_SHFT := '0'; + elsif SHFT_EN = '1' then + case OP is + when ASL => -- ASR MSB is always unchanged. + if OP_SIZE = LONG then + VFLAG_SHFT := (RESULT_SHIFTOP(31) xor RESULT_SHIFTOP(30)) or VFLAG_SHFT; + elsif OP_SIZE = WORD then + VFLAG_SHFT := (RESULT_SHIFTOP(15) xor RESULT_SHIFTOP(14)) or VFLAG_SHFT; + else -- OP_SIZE = BYTE. + VFLAG_SHFT := (RESULT_SHIFTOP(7) xor RESULT_SHIFTOP(6)) or VFLAG_SHFT; + end if; + when others => + VFLAG_SHFT := '0'; + end case; + end if; + end if; + + -- DIVISION: + if OP_SIZE = LONG and QUOTIENT(31) = '1' then + NFLAG_DIV := '1'; + elsif OP_SIZE = WORD and QUOTIENT(15) = '1' then + NFLAG_DIV := '1'; + else + NFLAG_DIV := '0'; + end if; + + -- Integer operations: + case OP is + when ADD | ADDI | ADDQ | ADDX | CMP | CMPA | CMPI | CMPM | NEG | NEGX | SUB | SUBI | SUBQ | SUBX => + RM := RESULT_INTOP(MSB); + SM := OP1_SIGNEXT(MSB); + DM := OP2_SIGNEXT(MSB); + when others => + RM := '-'; SM := '-'; DM := '-'; + end case; + + RM_SM_DM := To_Bit(RM) & To_Bit(SM) & To_Bit(DM); + + -- Multiplication: + if OP_SIZE = LONG and BIW_1(10) = '1' and RESULT_MUL(63) = '1' then -- 64 bit result. + NFLAG_MUL := '1'; + elsif RESULT_MUL(31) = '1' then -- 32 bit result. + NFLAG_MUL := '1'; + else + NFLAG_MUL := '0'; + end if; + + if OP_SIZE = LONG and BIW_1(10) = '0' and OP = MULS and RESULT_MUL(31) = '0' and RESULT_MUL(63 downto 32) /= x"00000000" then + VFLAG_MUL := '1'; + elsif OP_SIZE = LONG and BIW_1(10) = '0' and OP = MULS and RESULT_MUL(31) = '1' and RESULT_MUL(63 downto 32) /= x"FFFFFFFF" then + VFLAG_MUL := '1'; + elsif OP_SIZE = LONG and BIW_1(10) = '0' and OP = MULU and RESULT_MUL(63 downto 32) /= x"00000000" then + VFLAG_MUL := '1'; + else + VFLAG_MUL := '0'; + end if; + + -- The Z Flag: + TMP := '0'; + case OP is + when ADD | ADDI | ADDQ | ADDX | CMP | CMPA | CMPI | CMPM | NEG | NEGX | SUB | SUBI | SUBQ | SUBX => + for i in RESULT_INTOP' range loop + if i <= MSB then + TMP:= TMP or RESULT_INTOP(i); -- Detect '1'. + end if; + end loop; + Z := not TMP; -- Invert for Z fLAG . + when AND_B | ANDI | EOR | EORI | OR_B | ORI | NOT_B => + for i in RESULT_LOGOP' range loop + if i <= MSB then + TMP:= TMP or RESULT_LOGOP(i); -- Detect '1'. + end if; + end loop; + Z := not TMP; -- Invert for Z fLAG . + when ASL | ASR | LSL | LSR | ROTL | ROTR | ROXL | ROXR => + for i in RESULT_SHIFTOP' range loop + if i <= MSB then + TMP:= TMP or RESULT_SHIFTOP(i); -- Detect '1'. + end if; + end loop; + Z := not TMP; -- Invert for Z fLAG . + when BCHG | BCLR | BSET | BTST => + Z := not OP2(BITPOS); + when DIVS | DIVU => + if QUOTIENT = x"00000000" then + Z := '1'; + else + Z := '0'; + end if; + when EXT | MOVE | SWAP | TST => + for i in RESULT_OTHERS' range loop + if i <= MSB then + TMP:= TMP or RESULT_OTHERS(i); -- Detect '1'. + end if; + end loop; + Z := not TMP; -- Invert for Z fLAG . + when MULS | MULU => + if OP_SIZE = LONG and BIW_1(10) = '1' and RESULT_MUL = x"0000000000000000" then -- 64 bit result. + Z := '1'; + elsif RESULT_MUL(31 downto 0) = x"00000000" then -- 32 bit result. + Z := '1'; + else + Z := '0'; + end if; + when TAS => + for i in OP2_SIGNEXT' range loop + if i <= MSB then + TMP := TMP or OP2_SIGNEXT(i); -- Detect '1'. + end if; + end loop; + Z := not TMP; -- Invert for Z fLAG . + when others => + Z := '0'; + end case; + + case OP is + when ABCD | NBCD | SBCD => + if RESULT_BCDOP = x"00" then -- N and V are undefined, don't care. + XNZVC <= CB_BCD & '-' & STATUS_REG(2) & '-' & CB_BCD; + else + XNZVC <= CB_BCD & '-' & '0' & '-' & CB_BCD; + end if; + when ADD | ADDI | ADDQ | ADDX => + if (SM = '1' and DM = '1') or (RM = '0' and SM = '1') or (RM = '0' and DM = '1') then + XNZVC(4) <= '1'; + XNZVC(0) <= '1'; + else + XNZVC(4) <= '0'; + XNZVC(0) <= '0'; + end if; + -- + if Z = '1' then + if OP = ADDX then + XNZVC(3 downto 2) <= '0' & STATUS_REG(2); + else + XNZVC(3 downto 2) <= "01"; + end if; + else + XNZVC(3 downto 2) <= RM & '0'; + end if; + -- + case RM_SM_DM is + when "011" => XNZVC(1) <= '1'; + when "100" => XNZVC(1) <= '1'; + when others => XNZVC(1) <= '0'; + end case; + when AND_B | ANDI | EOR | EORI | OR_B | ORI | NOT_B => + XNZVC <= STATUS_REG(4) & RESULT_LOGOP(MSB) & Z & "00"; + when ANDI_TO_CCR | EORI_TO_CCR | ORI_TO_CCR => + XNZVC <= RESULT_LOGOP(4 downto 0); + when ASL | ASR | LSL | LSR | ROTL | ROTR | ROXL | ROXR => + XNZVC <= XFLAG_SHFT & RESULT_SHIFTOP(MSB) & Z & VFLAG_SHFT & CFLAG_SHFT; + when BCHG | BCLR | BSET | BTST => + XNZVC <= STATUS_REG(4 downto 3) & Z & STATUS_REG(1 downto 0); + when CLR => + XNZVC <= STATUS_REG(4) & "0100"; + when SUB | SUBI | SUBQ | SUBX => + if (SM = '1' and DM = '0') or (RM = '1' and SM = '1') or (RM = '1' and DM = '0') then + XNZVC(4) <= '1'; + XNZVC(0) <= '1'; + else + XNZVC(4) <= '0'; + XNZVC(0) <= '0'; + end if; + -- + if Z = '1' then + if OP = SUBX then + XNZVC(3 downto 2) <= '0' & STATUS_REG(2); + else + XNZVC(3 downto 2) <= "01"; + end if; + else + XNZVC(3 downto 2) <= RM & '0'; + end if; + -- + case RM_SM_DM is + when "001" => XNZVC(1) <= '1'; + when "110" => XNZVC(1) <= '1'; + when others => XNZVC(1) <= '0'; + end case; + when CMP | CMPA | CMPI | CMPM => + XNZVC(4) <= STATUS_REG(4); + -- + if Z = '1' then + XNZVC(3 downto 2) <= "01"; + else + XNZVC(3 downto 2) <= RM & '0'; + end if; + -- + case RM_SM_DM is + when "001" => XNZVC(1) <= '1'; + when "110" => XNZVC(1) <= '1'; + when others => XNZVC(1) <= '0'; + end case; + -- + if (SM = '1' and DM = '0') or (RM = '1' and SM = '1') or (RM = '1' and DM = '0') then + XNZVC(0) <= '1'; + else + XNZVC(0) <= '0'; + end if; + when CHK => + if OP2_SIGNEXT(MSB) = '1' then + XNZVC <= STATUS_REG(4) & '1' & "000"; + elsif CHK_CMP_COND = true then + XNZVC <= STATUS_REG(4) & '0' & "000"; + else + XNZVC <= STATUS_REG(4 downto 3) & "000"; + end if; + when DIVS | DIVU => + XNZVC <= STATUS_REG(4) & NFLAG_DIV & Z & VFLAG_DIV & '0'; + when EXT | MOVE | TST => + XNZVC <= STATUS_REG(4) & RESULT_OTHERS(MSB) & Z & "00"; + when MOVEQ => + if OP1_SIGNEXT(7 downto 0) = x"00" then + XNZVC <= STATUS_REG(4) & "0100"; + else + XNZVC <= STATUS_REG(4) & OP1_SIGNEXT(7) & "000"; + end if; + when MULS | MULU => + XNZVC <= STATUS_REG(4) & NFLAG_MUL & Z & VFLAG_MUL & '0'; + when NEG | NEGX => + XNZVC(4) <= DM or RM; + -- + if Z = '1' then + if OP = NEGX then + XNZVC(3 downto 2) <= '0' & STATUS_REG(2); + else + XNZVC(3 downto 2) <= "01"; + end if; + else + XNZVC(3 downto 2) <= RM & '0'; + end if; + -- + XNZVC(1) <= DM and RM; + XNZVC(0) <= DM or RM; + when RTR => + XNZVC <= OP2(4 downto 0); + when SWAP => + XNZVC <= STATUS_REG(4) & RESULT_OTHERS(MSB) & Z & "00"; + when others => -- TAS, Byte only. + XNZVC <= STATUS_REG(4) & OP2_SIGNEXT(MSB) & Z & "00"; + end case; + end process COND_CODES; + + ALU_COND <= ALU_COND_I; -- This signal may not be registerd to meet a correct timing. + -- Status register conditions: (STATUS_REG(4) = X, STATUS_REG(3) = N, STATUS_REG(2) = Z, STATUS_REG(1) = V, STATUS_REG(0) = C.) + ALU_COND_I <= true when OP = TRAPV and STATUS_REG(1) = '1' else + false when OP = TRAPV else + true when BIW_0(11 downto 8) = x"0" else -- True. + true when BIW_0(11 downto 8) = x"2" and (STATUS_REG(2) nor STATUS_REG(0)) = '1' else -- High. + true when BIW_0(11 downto 8) = x"3" and (STATUS_REG(2) or STATUS_REG(0)) = '1' else -- Low or same. + true when BIW_0(11 downto 8) = x"4" and STATUS_REG(0) = '0' else -- Carry clear. + true when BIW_0(11 downto 8) = x"5" and STATUS_REG(0) = '1' else -- Carry set. + true when BIW_0(11 downto 8) = x"6" and STATUS_REG(2) = '0' else -- Not Equal. + true when BIW_0(11 downto 8) = x"7" and STATUS_REG(2) = '1' else -- Equal. + true when BIW_0(11 downto 8) = x"8" and STATUS_REG(1) = '0' else -- Overflow clear. + true when BIW_0(11 downto 8) = x"9" and STATUS_REG(1) = '1' else -- Overflow set. + true when BIW_0(11 downto 8) = x"A" and STATUS_REG(3) = '0' else -- Plus. + true when BIW_0(11 downto 8) = x"B" and STATUS_REG(3) = '1' else -- Minus. + true when BIW_0(11 downto 8) = x"C" and (STATUS_REG(3) xnor STATUS_REG(1)) = '1' else -- Greater or Equal. + true when BIW_0(11 downto 8) = x"D" and (STATUS_REG(3) xor STATUS_REG(1)) = '1' else -- Less than. + true when BIW_0(11 downto 8) = x"E" and STATUS_REG(3 downto 1) = "101" else -- Greater than. + true when BIW_0(11 downto 8) = x"E" and STATUS_REG(3 downto 1) = "000" else -- Greater than. + true when BIW_0(11 downto 8) = x"F" and STATUS_REG(2) = '1' else -- Less or equal. + true when BIW_0(11 downto 8) = x"F" and (STATUS_REG(3) xor STATUS_REG(1)) = '1' else false; -- Less or equal. + + P_STATUS_REG: process + -- This process is the status register with it's related logic. + -- The status register is written 16 bit wide for MOVE_TO_CCR (the ALU result is 16 bit wide). + -- The status register is written entirely for ANDI_TO_SR, EORI_TO_SR, ORI_TO_SR. + -- The status register lower byte is written for ANDI_TO_CCR, EORI_TO_CCR, ORI_TO_CCR. + variable SREG_MEM : std_logic_vector(15 downto 0) := x"0000"; + begin + wait until CLK = '1' and CLK' event; + -- + if CC_UPDT = '1' then + SREG_MEM(4 downto 0) := XNZVC; + end if; + -- + if SR_INIT = '1' then + SREG_MEM(15 downto 13) := "001"; -- Trace cleared, S = '1'. + SREG_MEM(10 downto 8) := IRQ_PEND; -- Update IRQ level. + end if; + -- + if SR_WR = '1' and OP_IN = RTE then -- Written by the exception handler, no ALU required. + SREG_MEM := OP1_IN(15 downto 0); + elsif SR_WR = '1' and (OP_WB = MOVE_TO_CCR or OP_WB = MOVE_TO_SR or OP_WB = STOP) then + SREG_MEM := RESULT_OTHERS(15 downto 0); + elsif SR_WR = '1' and (OP_WB = ANDI_TO_CCR or OP_WB = EORI_TO_CCR or OP_WB = ORI_TO_CCR) then + SREG_MEM(7 downto 5) := RESULT_LOGOP(7 downto 5); -- Bits 4 downto 0 are written via CC_UPDT. + elsif SR_WR = '1' then -- ANDI_TO_SR, EORI_TO_SR, ORI_TO_SR. + SREG_MEM := RESULT_LOGOP(15 downto 0); + end if; + -- + STATUS_REG <= SREG_MEM; -- Fully populated status register. + -- STATUS_REG <= SREG_MEM(15 downto 12) & '0' & SREG_MEM(10 downto 8) & "000" & SREG_MEM(4 downto 0); -- Partially populated. + end process P_STATUS_REG; + -- + STATUS_REG_OUT <= STATUS_REG; +end BEHAVIOUR; diff --git a/common/CPU/68K10/wf68k10_bus_interface.vhd b/common/CPU/68K10/wf68k10_bus_interface.vhd new file mode 100644 index 00000000..fb134a5c --- /dev/null +++ b/common/CPU/68K10/wf68k10_bus_interface.vhd @@ -0,0 +1,767 @@ +------------------------------------------------------------------------ +---- ---- +---- WF68K10 IP Core: this is the bus interface. ---- +---- ---- +---- Description: ---- +---- This module is a 68010 compatible bus controller featuring ---- +---- all of the 68010 bus interface functionality. ---- +---- ---- +---- Bus cycle operation: ---- +---- A bus cycle is invoked by either asserting RD_REQ, WR_REQ or ---- +---- OPCODE_REQ. Data is provided after the respective bus cycle ---- +---- has finished. The RD_REQ, WR_REQ or OPCODE_REQ signals should ---- +---- stay asserted until the respective _RDY signal from the bus ---- +---- controller indicates, that the data is available. These _RDY ---- +---- signals are strobes. If more than one read or write request ---- +---- are asserted the same time, RD_REQ is prioritized over WR_REQ ---- +---- and OPCODE_REQ has lowest priority. For more information of ---- +---- the signal functionality of the bus controller entity see also ---- +---- the comments below. ---- +---- ---- +---- Remarks: ---- +---- ---- +---- Bus arbitration topics: ---- +---- Additionally to the single wire and the three wire bus arbi- ---- +---- tration as described in the 68030 hardware manual, the bus ---- +---- controller also features the two wire arbitration as des- ---- +---- cribed in the documentation of the 68020 processor. ---- +---- ---- +---- Author(s): ---- +---- - Wolfgang Foerster, wf@experiment-s.de; wf@inventronik.de ---- +---- ---- +------------------------------------------------------------------------ +---- ---- +---- Copyright © 2014-2019 Wolfgang Foerster Inventronik GmbH. ---- +---- ---- +---- This documentation describes Open Hardware and is licensed ---- +---- under the CERN OHL v. 1.2. You may redistribute and modify ---- +---- this documentation under the terms of the CERN OHL v.1.2. ---- +---- (http://ohwr.org/cernohl). This documentation is distributed ---- +---- WITHOUT ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING OF ---- +---- MERCHANTABILITY, SATISFACTORY QUALITY AND FITNESS FOR A ---- +---- PARTICULAR PURPOSE. Please see the CERN OHL v.1.2 for ---- +---- applicable conditions ---- +---- ---- +------------------------------------------------------------------------ +-- +-- Revision History +-- +-- Revision 2K14B 20141201 WF +-- Initial Release. +-- Revision 2K18A 20180620 WF +-- Fixed a bug in the DATA_PORT_OUT multiplexer. Thanks to Gary Bingham for the support. +-- Fixed a bug in the DATA_INMUX multiplexer. Thanks to Gary Bingham for the support. +-- Revision 2K18A 20180620 WF +-- RESET is now 124 instead of 512 clock cycles. +-- Adjusted the SSW to 68K10. +-- Removed RERUN_RMC. +-- Suppress bus faults during RESET instruction. +-- Optimized ASn and DSn timing for synchronous RAM. +-- DATA_PORT_EN timing optimization. +-- BUS_EN is now active except during arbitration. +-- Rearanged the DATA_RDY vs. BUS_FLT logic. +-- Opted out START_READ and CHK_RD. +-- UDSn and LDSn are now always enabled for opcode cycles (bugfix). +-- Fixed the faulty bus arbitration logic. +-- Rearranged address error handling. +-- Revision 2K20A 20200620 WF +-- ASn and DSn are not asserted in S0 any more. +-- Some modifications to optimize the RETRY logic. +-- + +library work; +use work.WF68K10_PKG.all; + +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_unsigned.all; +use ieee.numeric_std.all; + +entity WF68K10_BUS_INTERFACE is + port ( + -- System control: + CLK : in std_logic; -- System clock. + + -- Adress bus: + ADR_IN_P : in std_logic_vector(31 downto 0); -- Logical address line inputs. + ADR_OUT_P : out std_logic_vector(31 downto 0); -- Address line outputs. + + -- Function code relevant stuff: + FC_IN : in std_logic_vector(2 downto 0); -- Function codes. + FC_OUT : out std_logic_vector(2 downto 0); -- Physical function codes (top level entity). + + -- Data bus: + DATA_PORT_IN : in std_logic_vector(15 downto 0); -- Data bus input lines (top level entity). + DATA_PORT_OUT : out std_logic_vector(15 downto 0); -- Data bus output lines (top level entity). + DATA_FROM_CORE : in std_logic_vector(31 downto 0); -- Internal bus input lines. + DATA_TO_CORE : out std_logic_vector(31 downto 0); -- Internal data bus output lines. + OPCODE_TO_CORE : out std_logic_vector(15 downto 0); -- Internal instruction bus output lines. + + -- Tri state controls: + DATA_PORT_EN : out std_logic; -- For the data bus. + BUS_EN : out std_logic; -- For all other bus control signals. + + + -- Operation size: + OP_SIZE : in OP_SIZETYPE; -- Used for bus access control. + + -- Control signals: + RD_REQ : in bit; -- Read data. + WR_REQ : in bit; -- Write data. + DATA_RDY : out bit; -- Indicates 'new data available' (this is a strobe). + DATA_VALID : out std_logic; -- The data buffer contains valid data when '1'. + OPCODE_REQ : in bit; -- Read opcode. + OPCODE_RDY : out bit; -- Indicates 'new opcode available' (this is a strobe). + OPCODE_VALID : out std_logic; -- The opcode buffer contains valid data when '1'. + RMC : in bit; -- Indicates a read modify write operation. + BUSY_EXH : in bit; + INBUFFER : out std_logic_vector(31 downto 0); -- Used by the exception handler for stack frame type B. + OUTBUFFER : out std_logic_vector(31 downto 0); -- Used by the exception handler for stack frame types A and B. + SSW : out std_logic_vector(15 downto 0); + + -- Asynchronous bus control signals: + DTACKn : in std_logic; -- Asynchronous bus cycle termination (top level entity). + ASn : out std_logic; -- Adress select (top level entity). + UDSn : out std_logic; -- Data select (top level entity). + LDSn : out std_logic; -- Data select (top level entity). + RWn : out std_logic; -- Hi is read, low = write (top level entity). + RMCn : out std_logic; -- Read modify write indicator (top level entity). + DBENn : out std_logic; -- Data buffer enable (top level entity). + + -- Synchronous peripheral control: + E : out std_logic; + VMAn : out std_logic; + VMA_EN : out std_logic; + VPAn : in std_logic; + + -- Bus arbitration: + BRn : in std_logic; -- Bus request (top level entity). + BGACKn : in std_logic; -- Bus grant acknowledge (top level entity). + BGn : out std_logic; -- Bus grant (top level entity). + + -- Exception signals: + RESET_IN : in std_logic; -- System's reset input (top level entity). + RESET_STRB : in bit; -- From Core: force external reset. + RESET_OUT : out std_logic; -- System's reset output open drain enable. + RESET_CPU : out bit; -- Internal reset used for CPU initialization. + AVECn : in std_logic; -- Auto interrupt vector input (top level entity). + HALTn : in std_logic; -- Halt (top level entity). + BERRn : in std_logic; -- Bus error (top level entity). + AERR : out bit; -- Core internal address error. + + BUS_BSY : out bit -- Bus is busy when '1'. + ); +end entity WF68K10_BUS_INTERFACE; + +architecture BEHAVIOR of WF68K10_BUS_INTERFACE is +type BUS_CTRL_STATES is (IDLE, START_CYCLE, DATA_C1C4); +type ARB_STATES is(IDLE, GRANT, WAIT_RELEASE_3WIRE); +type TIME_SLICES is (IDLE, S0, S1, S2, S3, S4, S5); +signal ADR_OFFSET : std_logic_vector(5 downto 0); +signal ADR_OUT_I : std_logic_vector(31 downto 0); +signal AERR_I : bit; +signal ARB_STATE : ARB_STATES := IDLE; +signal AVEC_In : std_logic; +signal BGACK_In : std_logic; +signal BR_In : std_logic; +signal BUS_CTRL_STATE : BUS_CTRL_STATES; +signal BUS_CYC_RDY : bit; +signal BUS_FLT : std_logic; +signal DATA_INMUX : std_logic_vector(31 downto 0); +signal DATA_RDY_I : bit; +signal DBUFFER : std_logic_vector(31 downto 0); +signal DSn : std_logic; +signal DTACK_In : std_logic; +signal HALT_In : std_logic; +signal HALTED : bit; +signal NEXT_ARB_STATE : ARB_STATES; +signal NEXT_BUS_CTRL_STATE : BUS_CTRL_STATES; +signal OBUFFER : std_logic_vector(15 downto 0); +signal OPCODE_ACCESS : bit; +signal OPCODE_RDY_I : bit; +signal READ_ACCESS : bit; +signal RESET_CPU_I : bit; +signal RESET_OUT_I : std_logic; +signal RETRY : bit; +signal RW_In : std_logic; +signal SIZE_D : std_logic_vector(1 downto 0); +signal SIZE_I : std_logic_vector(1 downto 0); +signal SIZE_N : std_logic_vector(2 downto 0) := "000"; +signal SLICE_CNT_N : std_logic_vector(2 downto 0); +signal SLICE_CNT_P : std_logic_vector(2 downto 0); +signal SYNCn : bit; +signal T_SLICE : TIME_SLICES; +signal VMA_In : std_logic; +signal WAITSTATES : bit; +signal WP_BUFFER : std_logic_vector(31 downto 0); +signal WRITE_ACCESS : bit; +begin + P_SYNC: process(CLK) + -- These flip flops synchronize external signals on the negative clock edge. This + -- meets the requirement of sampling these signals in the end of S2 for asynchronous + -- bus access. Be aware, that we have to buffer the RETRY signal to prevent the bus + -- controller of spurious or timing critical BERRn and/or HALTn signals. The logic + -- for BUS_FLT and RETRY is coded in a way that we have a bus error or a retry + -- condition but not both at the same time. + -- Note: there is no need to synchronize the already synchronous bus control signals + variable BERR_VARn : std_logic; + variable HALT_VARn : std_logic; + begin + if CLK = '0' and CLK' event then + DTACK_In <= DTACKn; + BR_In <= BRn; + BGACK_In <= BGACKn; + AVEC_In <= AVECn; + HALT_VARn := HALTn; + BERR_VARn := BERRn; + end if; + -- + if CLK = '1' and CLK' event then + if BUS_CTRL_STATE = START_CYCLE then + AERR <= AERR_I; -- AERR_I is valid in this state. + else + AERR <= '0'; + end if; + -- + HALT_In <= HALTn or HALT_VARn; + -- + if BUS_CTRL_STATE = DATA_C1C4 then + if (BERRn nand BERR_VARn) = '1' and (HALTn or HALT_VARn) = '0' and SIZE_N /= "000" then + RETRY <= '1'; + elsif T_SLICE = IDLE and (BERRn = '1' and HALTn = '1' and BERR_VARn = '1' and HALT_VARn = '1') then + RETRY <= '0'; + elsif RETRY = '0' then + BUS_FLT <= (BERRn nor BERR_VARn) and HALT_VARn and HALTn; + end if; + else + BUS_FLT <= '0'; + RETRY <= '0'; + end if; + end if; + end process P_SYNC; + + ACCESSTYPE: process + -- This logic stores the execution unit control + -- signals during the current bus access. This is + -- important for the bus control signals to be + -- stable during the complete bus access. + begin + wait until CLK = '1' and CLK' event; + if BUS_CTRL_STATE = START_CYCLE then + if READ_ACCESS = '1' or WRITE_ACCESS = '1' or OPCODE_ACCESS = '1' then + null; -- Do not start either new cycle. + elsif RD_REQ = '1' then + READ_ACCESS <= '1'; + elsif WR_REQ = '1' then + WRITE_ACCESS <= '1'; + elsif OPCODE_REQ = '1' then + OPCODE_ACCESS <= '1'; + end if; + elsif AERR_I = '1' or (BUS_CTRL_STATE = DATA_C1C4 and NEXT_BUS_CTRL_STATE = IDLE) then + READ_ACCESS <= '0'; + WRITE_ACCESS <= '0'; + OPCODE_ACCESS <= '0'; + end if; + end process ACCESSTYPE; + + P_DF: process + -- This is the logic which provides the fault flags for data cycles and + -- input and output buffer information. + variable SIZEVAR : std_logic_vector(1 downto 0) := "00"; + begin + wait until CLK = '1' and CLK' event; + if BUSY_EXH = '0' then -- Do not alter during exception processing. + case OP_SIZE is + when LONG => SIZEVAR := "10"; + when WORD => SIZEVAR := "01"; + when BYTE => SIZEVAR := "00"; + end case; + -- + if BUS_CTRL_STATE = START_CYCLE and NEXT_BUS_CTRL_STATE = DATA_C1C4 then + SSW <= To_StdLogicVector (RMC & '0' & OPCODE_REQ & RD_REQ & RMC) & SIZEVAR & RW_In & "00000" & FC_IN; + end if; + + OUTBUFFER <= WP_BUFFER; -- Used for exception stack frame type A and B. + INBUFFER <= DATA_INMUX; -- Used for exception stack frame type B. + end if; + end process P_DF; + + WRITEBACK_INFO: process + -- This registers stor writeback relevant information. + begin + wait until CLK = '1' and CLK' event; + if BUS_CTRL_STATE = IDLE and NEXT_BUS_CTRL_STATE = START_CYCLE then -- Freeze during a bus cycle. + WP_BUFFER <= DATA_FROM_CORE; + end if; + end process WRITEBACK_INFO; + + BUS_BSY <= '1' when BUS_CTRL_STATE /= IDLE else '0'; + + PARTITIONING: process + -- This logic gives information about the remaining bus cycles The initial + -- size is sampled right before the bus acces. This requires the RD_REQ + -- and WR_REQ signals to work on the positive clock edge. + variable RESTORE_VAR : std_logic_vector(2 downto 0) := "000"; + begin + wait until CLK = '1' and CLK' event; + + if BUS_CTRL_STATE = DATA_C1C4 and T_SLICE = S1 then -- On positive clock edge. + RESTORE_VAR := SIZE_N; -- We need this initial value for early RETRY. + end if; + -- + if RESET_CPU_I = '1' then + SIZE_N <= "000"; + elsif BUS_CTRL_STATE /= DATA_C1C4 and NEXT_BUS_CTRL_STATE = DATA_C1C4 then + if RD_REQ = '1' or WR_REQ = '1' then + case OP_SIZE is + when LONG => SIZE_N <= "100"; + when WORD => SIZE_N <= "010"; + when BYTE => SIZE_N <= "001"; + end case; + else -- OPCODE_ACCESS. + SIZE_N <= "010"; -- WORD. + end if; + end if; + + -- Decrementing the size information: + -- In this logic all permutations are considered. This allows a dynamically changing bus size. + if RETRY = '1' then + SIZE_N <= RESTORE_VAR; + elsif BUS_CTRL_STATE = DATA_C1C4 and T_SLICE = S3 and WAITSTATES = '0' then -- On positive clock edge. + if ADR_OUT_I(1 downto 0) = "11" then + SIZE_N <= SIZE_N - '1'; + elsif ADR_OUT_I(1 downto 0) = "01" then + SIZE_N <= SIZE_N - '1'; + elsif SIZE_N = "001" then + SIZE_N <= SIZE_N - '1'; + else + SIZE_N <= SIZE_N - "10"; + end if; + end if; + -- + if (BUS_FLT = '1' and HALT_In = '1') then -- Abort bus cycle. + SIZE_N <= "000"; + end if; + end process PARTITIONING; + + SIZE_I <= SIZE_N(1 downto 0) when T_SLICE = S0 or T_SLICE = S1 else SIZE_D; + + P_DELAY: process + -- This delay is responsible for a correct SIZE_I information. Use this, if the + -- process PARTITIONING works on the positive clock edge. The SIZE_I information + -- is delayed by half a clock cycle to be valid just in time of sampling the INMUX. + begin + wait until CLK = '1' and CLK' event; + SIZE_D <= SIZE_N(1 downto 0); + end process P_DELAY; + + BUS_STATE_REG: process + -- This is the bus controller's state register. + begin + wait until CLK = '1' and CLK' event; + BUS_CTRL_STATE <= NEXT_BUS_CTRL_STATE; + end process BUS_STATE_REG; + + BUS_CTRL_DEC: process(ADR_IN_P, ADR_OUT_I, AERR_I, ARB_STATE, BGACK_In, BR_In, BUS_CTRL_STATE, BUS_CYC_RDY, + BUS_FLT, HALT_In, OPCODE_REQ, RD_REQ, RESET_CPU_I, RMC, SIZE_N, WR_REQ) + -- This is the bus controller's state machine decoder. A SIZE_N count of "000" means that all bytes + -- to be transfered. After a bus transfer a value of x"0" indicates that no further bytes are required + -- for a bus transfer. + begin + case BUS_CTRL_STATE is + when IDLE => + if RESET_CPU_I = '1' then + NEXT_BUS_CTRL_STATE <= IDLE; -- Reset condition (bus cycle terminated). + elsif HALT_In = '0' then + NEXT_BUS_CTRL_STATE <= IDLE; -- This is the 'HALT' condition. + elsif (BR_In = '0' and RMC = '0') or ARB_STATE /= IDLE or BGACK_In = '0' then + NEXT_BUS_CTRL_STATE <= IDLE; -- Arbitration, wait! + elsif RD_REQ = '1' then + NEXT_BUS_CTRL_STATE <= START_CYCLE; -- Read cycle. + elsif WR_REQ = '1' then + NEXT_BUS_CTRL_STATE <= START_CYCLE; -- Write cycle. + elsif OPCODE_REQ = '1' then + NEXT_BUS_CTRL_STATE <= START_CYCLE; -- Opcode cycle. + else + NEXT_BUS_CTRL_STATE <= IDLE; + end if; + when START_CYCLE => + if (RD_REQ = '1' or WR_REQ = '1') and AERR_I = '1' then + NEXT_BUS_CTRL_STATE <= IDLE; + elsif RD_REQ = '1' then + NEXT_BUS_CTRL_STATE <= DATA_C1C4; + elsif WR_REQ = '1' then + NEXT_BUS_CTRL_STATE <= DATA_C1C4; + elsif OPCODE_REQ = '1' and ADR_IN_P(0) = '1' then + NEXT_BUS_CTRL_STATE <= IDLE; -- Abort due to address error. + elsif OPCODE_REQ = '1' then + NEXT_BUS_CTRL_STATE <= DATA_C1C4; + else + NEXT_BUS_CTRL_STATE <= IDLE; + end if; + when DATA_C1C4 => + if BUS_CYC_RDY = '1' and SIZE_N = "000" then + NEXT_BUS_CTRL_STATE <= IDLE; + else + NEXT_BUS_CTRL_STATE <= DATA_C1C4; + end if; + end case; + end process BUS_CTRL_DEC; + + P_ADR_OFFS: process + -- This process provides a temporary address offset. + variable OFFSET_VAR : std_logic_vector(2 downto 0) := "000"; + begin + wait until CLK = '1' and CLK' event; + if RESET_CPU_I = '1' then + OFFSET_VAR := "000"; + elsif T_SLICE = S3 then + case ADR_OUT_I(1 downto 0) is + when "01" | "11" => OFFSET_VAR := "001"; + when others => OFFSET_VAR := "010"; + end case; + end if; + -- + if RESET_CPU_I = '1' then + ADR_OFFSET <= (others => '0'); + elsif RETRY = '1' then + null; -- Do not update if there is a retry cycle. + elsif BUS_CTRL_STATE /= IDLE and NEXT_BUS_CTRL_STATE = IDLE then + ADR_OFFSET <= (others => '0'); + elsif BUS_CYC_RDY = '1' then + ADR_OFFSET <= ADR_OFFSET + OFFSET_VAR; + end if; + end process P_ADR_OFFS; + + ADR_OUT_I <= ADR_IN_P + ADR_OFFSET; + ADR_OUT_P <= ADR_OUT_I; + + FC_OUT <= FC_IN; + + -- Address and bus errors: + AERR_I <= '1' when BUS_CTRL_STATE = START_CYCLE and OPCODE_REQ = '1' and RD_REQ = '0' and WR_REQ = '0' and ADR_IN_P(0) = '1' else + '1' when BUS_CTRL_STATE = START_CYCLE and OP_SIZE = LONG and ADR_IN_P(0) = '1' else + '1' when BUS_CTRL_STATE = START_CYCLE and OP_SIZE = WORD and ADR_IN_P(0) = '1' else '0'; + + + DATA_PORT_OUT <= WP_BUFFER(31 downto 16) when SIZE_I = "00" else + WP_BUFFER(15 downto 0) when SIZE_I = "10" else + WP_BUFFER(7 downto 0) & WP_BUFFER(7 downto 0); + + IN_MUX: process + -- This is the input multiplexer which can handle up to four bytes. + begin + wait until CLK = '0' and CLK' event; + -- + if T_SLICE = S4 then + case SIZE_I is + when "00" => + DATA_INMUX(31 downto 16) <= DATA_PORT_IN; + when "10" => -- Word. + DATA_INMUX(15 downto 0) <= DATA_PORT_IN; + when others => -- Byte. + case ADR_OUT_I(0) is + when '0' => DATA_INMUX(7 downto 0) <= DATA_PORT_IN(15 downto 8); + when others => DATA_INMUX(7 downto 0) <= DATA_PORT_IN(7 downto 0); + end case; + end case; + end if; + end process IN_MUX; + + VALIDATION: process + -- These flip flops detect a fault during the read operation over one or + -- several bytes or during the write operation. + begin + wait until CLK = '1' and CLK' event; + -- + if RESET_CPU_I = '1' then + OPCODE_VALID <= '1'; + elsif OPCODE_ACCESS = '1' and BUS_CTRL_STATE = DATA_C1C4 and BUS_FLT = '1' then + OPCODE_VALID <= '0'; + elsif OPCODE_RDY_I = '1' then + OPCODE_VALID <= '1'; -- Reset after use, TRAP_BERR is asserted during DATA_RDY. + end if; + -- + if RESET_CPU_I = '1' then + DATA_VALID <= '1'; + elsif BUS_CTRL_STATE = DATA_C1C4 and BUS_FLT = '1' then + DATA_VALID <= '0'; + elsif DATA_RDY_I = '1' then + DATA_VALID <= '1'; -- Reset after use, TRAP_BERR is asserted during DATA_RDY. + end if; + end process VALIDATION; + + PREFETCH_BUFFERS: process + -- These are the data and the operation code input registers. After a last read to the registered + -- input multiplexer, the respective data is copied from the input multiplexer to these buffers. + -- The opcode buffer is always written with 32 bit data. The data buffers may contain invalid bytes + -- in case of word or byte data size. + variable DBUFFER_MEM : std_logic_vector(31 downto 8) := x"000000"; + variable RDY_VAR : bit := '0'; + begin + wait until CLK = '1' and CLK' event; + -- + OPCODE_RDY_I <= '0'; -- This is a strobe. + DATA_RDY_I <= '0'; -- This is a strobe. + -- + -- The following variable is responsible, that the _RDY signals are + -- always strobes. + if DATA_RDY_I = '1' or OPCODE_RDY_I = '1' then + RDY_VAR := '0'; + elsif BUS_CTRL_STATE = START_CYCLE then + RDY_VAR := '1'; + end if; + -- Opcode cycle: + if AERR_I = '1' then + OPCODE_RDY_I <= '1'; + elsif OPCODE_ACCESS = '1' and BUS_CTRL_STATE = DATA_C1C4 and BUS_CYC_RDY = '1' and SIZE_N = "000" then + -- Instruction prefetches are always long and on word boundaries. + -- The word is available after the first word read. + OBUFFER <= DATA_INMUX(15 downto 0); + OPCODE_RDY_I <= RDY_VAR; + end if; + -- Data cycle: + if AERR_I = '1' then + DATA_RDY_I <= '1'; + elsif WRITE_ACCESS = '1' and BUS_CTRL_STATE = DATA_C1C4 and BUS_CYC_RDY = '1' and SIZE_N = "000" then + DATA_RDY_I <= RDY_VAR; + elsif READ_ACCESS = '1' and BUS_CTRL_STATE = DATA_C1C4 and BUS_CYC_RDY = '1' then + case OP_SIZE is + when LONG => + if SIZE_N = "000" then + DBUFFER <= DATA_INMUX; + DATA_RDY_I <= RDY_VAR; + end if; + when WORD => + if SIZE_N = "000" then + DBUFFER <= x"0000" & DATA_INMUX(15 downto 0); + DATA_RDY_I <= RDY_VAR; + end if; + when BYTE => -- Byte always aligned. + DATA_RDY_I <= RDY_VAR; + DBUFFER <= x"000000" & DATA_INMUX(7 downto 0); + end case; + end if; + end process PREFETCH_BUFFERS; + + DATA_RDY <= DATA_RDY_I; + OPCODE_RDY <= OPCODE_RDY_I; + + DATA_TO_CORE <= DBUFFER; + OPCODE_TO_CORE <= OBUFFER; + + WAITSTATES <= '0' when T_SLICE /= S3 else + '1' when RESET_OUT_I = '1' else -- No bus fault during RESET instruction. + '0' when SYNCn = '0' else -- For synchronous bus cycles. + '0' when DTACK_In = '0' else -- For asynchronous bus cycles. + '0' when ADR_IN_P(19 downto 16) = x"F" and AVEC_In = '0' else -- Interrupt acknowledge space cycle. + '0' when BUS_FLT = '1' else -- In case of a bus error; + '0' when RESET_CPU_I = '1' else '1'; -- A CPU reset terminates the current bus cycle. + + SLICES: process(CLK) + -- This process provides the central timing for the read, write and read modify write cycle as also + -- for the bus arbitration procedure. Be aware, that the bus controller state machine changes it's + -- state on the positive clock edge. The BUS_CYC_RDY signal is asserted during S3 or S5. So the + -- slice counter working on the positive clock edge may change it's state. + begin + if CLK = '1' and CLK' event then + if BUS_CTRL_STATE = IDLE then + SLICE_CNT_P <= "111"; -- Init. + elsif RETRY = '1' then + SLICE_CNT_P <= "111"; -- Stay in IDLE, go to IDLE. + elsif BUS_CTRL_STATE /= IDLE and NEXT_BUS_CTRL_STATE = IDLE then + SLICE_CNT_P <= "111"; -- Init. + elsif SLICE_CNT_P = "010" then + if RETRY = '1' then + SLICE_CNT_P <= "111"; -- Go IDLE. + elsif BUS_CTRL_STATE = DATA_C1C4 and NEXT_BUS_CTRL_STATE = IDLE then + SLICE_CNT_P <= "111"; -- Ready. + else + SLICE_CNT_P <= "000"; -- Go on. + end if; + elsif WAITSTATES = '0' then + SLICE_CNT_P <= SLICE_CNT_P + '1'; -- Cycle active. + end if; + end if; + -- + if CLK = '0' and CLK' event then + SLICE_CNT_N <= SLICE_CNT_P; -- Follow the P counter. + end if; + end process SLICES; + + T_SLICE <= S0 when SLICE_CNT_P = "000" and SLICE_CNT_N = "111" else + S1 when SLICE_CNT_P = "000" and SLICE_CNT_N = "000" else + S2 when SLICE_CNT_P = "001" and SLICE_CNT_N = "000" else + S3 when SLICE_CNT_P = "001" and SLICE_CNT_N = "001" else + S4 when SLICE_CNT_P = "010" and SLICE_CNT_N = "001" else + S5 when SLICE_CNT_P = "010" and SLICE_CNT_N = "010" else + S0 when SLICE_CNT_P = "000" and SLICE_CNT_N = "010" else IDLE; -- Rollover from state S5 to S0. + + -- Bus control signals: + RWn <= RW_In; + RW_In <= '0' when WRITE_ACCESS = '1' and BUS_CTRL_STATE = DATA_C1C4 else '1'; + RMCn <= '0' when RMC = '1' else '1'; + ASn <= '0' when T_SLICE = S1 or T_SLICE = S2 or T_SLICE = S3 or T_SLICE = S4 else '1'; + + UDSn <= '1' when OPCODE_ACCESS = '0' and OP_SIZE = BYTE and ADR_OUT_I(0) = '1' else DSn; + LDSn <= '1' when OPCODE_ACCESS = '0' and OP_SIZE = BYTE and ADR_OUT_I(0) = '0' else DSn; + DSn <= '0' when (T_SLICE = S3 or T_SLICE = S4 or T_SLICE = S5) and WRITE_ACCESS = '1' else -- Write. + '0' when T_SLICE = S1 or T_SLICE = S2 or T_SLICE = S3 or T_SLICE = S4 else '1'; -- Read. + + DBENn <= '0' when (T_SLICE = S1 or T_SLICE = S2 or T_SLICE = S3 or T_SLICE = S4 or T_SLICE = S5) and WRITE_ACCESS = '1' else -- Write. + '0' when T_SLICE = S2 or T_SLICE = S3 or T_SLICE = S4 else '1'; -- Read. + + -- Bus tri state controls: + BUS_EN <= '1' when ARB_STATE = IDLE and RESET_CPU_I = '0' else '0'; + DATA_PORT_EN <= '1' when WRITE_ACCESS = '1' and ARB_STATE = IDLE and RESET_CPU_I = '0' else '0'; + + -- Progress controls: + BUS_CYC_RDY <= '0' when RETRY = '1' else + '1' when T_SLICE = S5 else '0'; -- Asynchronous cycles. + + -- Bus arbitration: + ARB_REG: process + -- This is the arbiters state register. + begin + wait until CLK = '1' and CLK' event; + -- + if RESET_CPU_I = '1' then + ARB_STATE <= IDLE; + else + ARB_STATE <= NEXT_ARB_STATE; + end if; + end process ARB_REG; + + ARB_DEC: process(ARB_STATE, BGACK_In, BR_In, BUS_CTRL_STATE, RETRY, RMC) + -- This is the bus arbitration state machine's decoder. It can handle single-, two- + -- or three wire arbitration. The two wire arbitration is done in the GRANT state + -- by negating BRn. + begin + case ARB_STATE is + when IDLE => + if RMC = '1' and RETRY = '0' then + NEXT_ARB_STATE <= IDLE; -- Arbitration in RETRY operation is possible. + elsif BGACK_In = '0' and BUS_CTRL_STATE = IDLE then -- This is the single wire arbitration. + NEXT_ARB_STATE <= WAIT_RELEASE_3WIRE; + elsif BR_In = '0' and BUS_CTRL_STATE = IDLE then -- Wait until the bus is free. + NEXT_ARB_STATE <= GRANT; + else + NEXT_ARB_STATE <= IDLE; + end if; + when GRANT => + if BGACK_In = '0' then + NEXT_ARB_STATE <= WAIT_RELEASE_3WIRE; + elsif BR_In = '1' then + NEXT_ARB_STATE <= IDLE; -- Resume normal operation. + else + NEXT_ARB_STATE <= GRANT; + end if; + when WAIT_RELEASE_3WIRE => + if BGACK_In = '1' and BR_In = '0' then + NEXT_ARB_STATE <= GRANT; -- Re-enter new arbitration. + elsif BGACK_In = '1' then + NEXT_ARB_STATE <= IDLE; + else + NEXT_ARB_STATE <= WAIT_RELEASE_3WIRE; + end if; + end case; + end process ARB_DEC; + + BGn <= '0' when ARB_STATE = GRANT else '1'; + + -- RESET logic: + RESET_FILTER: process + -- This process filters the incoming reset pin. + -- If RESET_IN and HALT_In are asserted together for longer + -- than 10 clock cycles over the execution of a CPU reset + -- command, the CPU reset is released. + variable STARTUP : boolean := false; + variable TMP : std_logic_vector(3 downto 0) := x"0"; + begin + wait until CLK = '1' and CLK' event; + -- + if RESET_IN = '1' and HALT_In = '0' and RESET_OUT_I = '0' and TMP < x"F" then + TMP := TMP + '1'; + elsif RESET_IN = '0' or HALT_In = '1' or RESET_OUT_I = '1' then + TMP := x"0"; + end if; + if TMP > x"A" then + RESET_CPU_I <= '1'; -- Release internal reset. + STARTUP := true; + elsif STARTUP = false then + RESET_CPU_I <= '1'; + else + RESET_CPU_I <= '0'; + end if; + end process RESET_FILTER; + + RESET_TIMER: process + -- This logic is responsible for the assertion of the + -- reset output for 124 clock cycles, during the reset + -- command. The LOCK variable avoids re-initialisation + -- of the counter in the case that the RESET_EN is no + -- strobe. + variable TMP : std_logic_vector(6 downto 0) := "0000000"; + begin + wait until CLK = '1' and CLK' event; + -- + if RESET_STRB = '1' or TMP > "0000000" then + RESET_OUT_I <= '1'; + else + RESET_OUT_I <= '0'; + end if; + -- + if RESET_STRB = '1' then + TMP := "1111011"; -- 124 initial value. + elsif TMP > "0000000" then + TMP := TMP - '1'; + end if; + end process RESET_TIMER; + + RESET_CPU <= RESET_CPU_I; + RESET_OUT <= RESET_OUT_I; + + VMA_EN <= '0' when ARB_STATE /= IDLE or RESET_CPU_I = '1' else '1'; + VMAn <= VMA_In; + + -- Synchronous bus timing: + E_TIMER: process + -- The E clock is a free running clock with a period of 10 times + -- the CLK period. The pulse ratio is 4 CLK high and 6 CLK low. + -- Use a synchronous reset due to FPGA constraints. + variable TMP : std_logic_vector(3 downto 0); + begin + wait until CLK = '1' and CLK' event; + if RESET_CPU_I = '1' then + TMP := x"0"; + VMA_In <= '1'; + SYNCn <= '1'; + E <= '1'; + elsif TMP < x"9" then + TMP := TMP + '1'; + else + TMP := x"0"; + end if; + + -- E logic: + if TMP = x"0" then + E <= '1'; + elsif TMP = x"4" then + E <= '0'; + end if; + + -- VMA logic: + if VPAn = '0' and TMP >= x"4" then -- Switch, when E is low. + VMA_In <= '0'; + elsif VPAn = '1' then + VMA_In <= '1'; + end if; + + -- SYNCn logic (wait states controlling): + if VPAn = '0' and VMA_In = '0' and TMP = x"2" then -- Adjust E to S6.. + SYNCn <= '0'; + elsif VPAn = '1' then + SYNCn <= '1'; + end if; + end process E_TIMER; +end BEHAVIOR; diff --git a/common/CPU/68K10/wf68k10_control.vhd b/common/CPU/68K10/wf68k10_control.vhd new file mode 100644 index 00000000..2d26b4c3 --- /dev/null +++ b/common/CPU/68K10/wf68k10_control.vhd @@ -0,0 +1,2044 @@ +------------------------------------------------------------------------ +---- ---- +---- WF68K10 IP Core: this is the main controller to handle all ---- +---- integer instructions. ---- +---- ---- +---- Description: ---- +---- This controller handles all integer instructions and provides ---- +---- all required system control signals. The instructions are ---- +---- requested from the instruction prefetch unit in the opcode ---- +---- decoder unit. The data is mostly written to the ALU and after- ---- +---- wards from the ALU to the writeback logic. This pipelined ---- +---- structure requires a correct management of data in use. Any ---- +---- address or data registers or memory addresses which are in use ---- +---- are marked by a flag not to be used befor written back. Any ---- +---- time data or address reegisters or the effective address are ---- +---- in the writeback pipe, the respective use flag is evaluated. ---- +---- Instructions like MOVE read unused source and the destination ---- +---- is written, when the ALU and writeback controller 'free'. ---- +---- Instructions like ADD, SUB etc. read unused source and desti- ---- +---- nations and write back the destination, when the operands are ---- +---- not used any more and the ALU and writeback controller are not ---- +---- in use by another operation. ---- +---- The main controller is the second pipeline stage of the CPU. ---- +---- The pipelining structure also requires some special treatment ---- +---- for the system control instructions as described as follows: ---- +------------------------------------------------------------------------ +---- System Control Instructions: ---- +---- There are several instructions which require the instruction ---- +---- pipe to be flushed as described in the following. For further ---- +---- information refer to the 68Kxx data sheets. ---- +---- ---- +---- 1. TRAP generating: ---- +---- The following instructions result in a pipe flush when the ---- +---- exception handler takes control over the system: ---- +---- BKPT, CHK, ILLEGAL, TRAP, TRAPV ---- +---- There are some other indirect conditions flushing the pipe ---- +---- such as the STOP which is invoked by an external interrupt.---- +---- ---- +---- 2. Privilege violations: ---- +---- Some instructions may result in a privilege violation ---- +---- when executed in user space. The result will be a ---- +---- privilege violation trap and the ipipe is flushed when ---- +---- the exception handler takes over. The instructions are: ---- +---- ANDI_TO_SR, EORI_TO_SR, ORI_TO_SR, MOVEC, MOVES, MOVE_USP, ---- +---- MOVE_FROM_SR (68K10), MOVE_TO_SR, RESET, RTE and STOP. ---- +---- ---- +---- 3. Branches and Jumps: ---- +---- In case of branches and jumps and the respective return ---- +---- operations it is required to flush the instruction pipe. ---- +---- If PC value changes due to any branch or jump, it is neces- ---- +---- sary to flush the instruction pipe to invalidate already ---- +---- loaded 'old' instructions. This affects: ---- +---- BRA, BSR, Bcc, DBcc, JMP, JSR and the returns: ---- +---- RTD, RTR, RTS, RTE and also STOP. ---- +---- ---- +------------------------------------------------------------------------ +---- Data hazards: ---- +---- To avoid malfunction by using old data several things have ---- +---- to be taken into account: ---- +---- 1. Operations manipulating the system registers must wait ---- +---- in the end of the operation until the ALU has updated ---- +---- the condition codes. These operations are ANDI_TO_SR, ---- +---- EORI_TO_SR, ORI_TO_SR, MOVE_TO_SR and MOVEC. ---- +---- 2. Operations using the staus register must not start until ---- +---- the ALU has updated the condition codes. These operations ---- +---- are MOVE_FROM_CCR, MOVE_FROM_SR and MOVEC. ---- +---- 3. Operations using the stack pointer must not start until ---- +---- the stack pointer is updated by the previous operation. ---- +---- Operations using the stack pointer are RTD, RTR, RTS, ---- +---- MOVEC, MOVE_USP and UNLK. ---- +---- 4. Operations manipulating the stack pointer without using ---- +---- the ALU must not start until the stack is written by the ---- +---- previous operation. Stack pointer manipulating operations ---- +---- are BSR, JSR, LINK and PEA. ---- +------------------------------------------------------------------------ +---- ---- +---- Remarks: ---- +---- ---- +---- Author(s): ---- +---- - Wolfgang Foerster, wf@experiment-s.de; wf@inventronik.de ---- +---- ---- +------------------------------------------------------------------------ +---- ---- +---- Copyright © 2014-2019 Wolfgang Foerster Inventronik GmbH. ---- +---- ---- +---- This documentation describes Open Hardware and is licensed ---- +---- under the CERN OHL v. 1.2. You may redistribute and modify ---- +---- this documentation under the terms of the CERN OHL v.1.2. ---- +---- (http://ohwr.org/cernohl). This documentation is distributed ---- +---- WITHOUT ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING OF ---- +---- MERCHANTABILITY, SATISFACTORY QUALITY AND FITNESS FOR A ---- +---- PARTICULAR PURPOSE. Please see the CERN OHL v.1.2 for ---- +---- applicable conditions ---- +---- ---- +------------------------------------------------------------------------ +-- +-- Revision History +-- +-- Revision 2K14B 20141201 WF +-- Initial Release. +-- Revision 2K16A 20160620 WF +-- Fixed a bug in the MOVEM operation. +-- Break the DBcc_LOOP when the exception handler is busy. +-- Revision 2K18A (unreleased) WF +-- Fixed a bug in MOVE An,-(Ay). Thanks to Gary Bingham for the support. +-- Removed RERUN_RMC. +-- Fixed wrong PEA behaviour. +-- Fixed the displacement for LINK. +-- Fixed AR_MARK_USED in LINK. +-- Fixed the operation size for MOVEQ. +-- ADDQ, SUBQ Fix: address registers are always written long. +-- ADDI, ANDI, EORI, ORI, SUBI: address is not marked used if destination is Dn. +-- ADDI, ANDI, EORI, ORI, SUBI: data register is marked used if destination is Dn. +-- EXG: rearranged logic to meet the new top level multiplexers. +-- LINK, UNLK: wait in START_OP until the ALU is ready (avoids possible data hazards). +-- LINK, UNLK: fixed the write back operation size. +-- MOVEM: Fixed predecrement mode for consecutive MOVEM -(An). +-- MOVEP: MOVEP_PNTR is now correct for consecutive MOVEP. +-- MOVEP: avoid structural hazard in SWITCH_STATE by waiting for ALU. +-- EOR: fixed a bug in the writeback mechanism. +-- BSR, JSR: EXEC_WB state machine waits now for ALU_INIT. Avoid structural / data hazard. +-- The instruction pipe is not flushed for ANDI_TO_CCR, EORI_TO_CCR, ORI_TO_CCR. +-- The instruction pipe is not flushed for MOVE_FROM_CCR, MOVE_TO_CCR, MOVE_FROM_SR, MOVE_USP, MOVEC. +-- Modifications in the FETCH state machine to avoid several data hazards for MOVEM, MOVE_FROM_CCR, MOVE_FROM_SR. +-- Modifications in the FETCH state machine to avoid several data hazards for ANDI_TO_CCR, ANDI_TO_SR, EORI_TO_CCR, EORI_TO_SR, ORI_TO_CCR, ORI_TO_SR. +-- Bugfix: the condition codes were not updated if there was a pending interrupt. +-- We have to stop a pending operation in case of a pending interrupt. This is done by rejecting OW_RDY. +-- Write the undecremented Register for MOVE Ax, -(Ax). +-- LINK A7 and PEA(A7) stacks the undecremented A7. +-- UNMARK is now asserted in the end of the write cycle. This avoids data hazards. +-- Fixed a MOVEC writeback issue (use BIW_WB... instead of BIW_...). +-- Fixed a USP writeback issue (use BIW_WB... instead of BIW_...). +-- Introduced a switch NO_PIPELINE. +-- MOVEM-Fix: the effective address in memory to register is stored (STORE_AEFF) not to be overwritten in case the addressing register is also loaded. +-- DBcc: fixed a data hazard for DBcc_COND evaluation by waiting on the ALU result. +-- Fixed DR_WR_1 locking against AR_WR_2. +-- IPIPE is flushed, when there is a memory space change in the end of xx_TO_SR operations. +-- To handle correct addressing, ADR_OFFSET is now cleared right in the end of the respective operation. +-- Fixed a bug in EOR writing back in register direct mode. +-- ADDQ and SUBQ: fixed (An)+ mode. An increments now. +-- Fixed DIVS, DIVU in memory address modes (wrong control flow). +-- ADDQ and SUBQ: fixed condition code control UPDT_CC. +-- Fixed a data hazard bug using addressing modes with index register. +-- Rewritten DBcc loop for split loops (see LOOP_SPLIT). +-- BTST: fixed (d16,Ax) addressing mode. +-- Fixed several pipelinig issues (hazards). +-- Revision 2K19A 20190419 WF +-- Introdeced a new state CALC_AEFF which results in no need of ADR_ATN and a twice highre fmax. +-- Revision 2K19B 20191224 WF +-- NOP explicitely synchronizes the instruction pipe now. +-- Control: BUSY is now asserted when an opword is loaded and we have to wait in START_OP (avoids other controllers to reload the opword, see OW_REQ). +-- Removed a data hazard condition (A7) for JSR, PEA, LINK and UNLK in the beginning of the operation. +-- + +use work.WF68K10_PKG.all; + +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_unsigned.all; +use ieee.numeric_std.all; + +entity WF68K10_CONTROL is + generic(NO_PIPELINE : boolean); -- If true the controller work in scalar mode. + port ( + CLK : in std_logic; -- System clock. + RESET_CPU : in bit; -- CPU reset. + + BUSY : out bit; -- Main controller finished an execution. + BUSY_EXH : in bit; + EXH_REQ : in bit; + INT_TRIG : out bit; + + OW_REQ : out bit; -- Operation words request. + OW_VALID : in std_logic; -- Operation words is valid. + EW_REQ : out bit; -- Extension word request. + EW_ACK : in bit; -- Extension word available. + OPD_ACK : in bit; -- Opcode has new data. + + ADR_MARK_USED : out bit; + ADR_IN_USE : in bit; + ADR_OFFSET : out std_logic_vector(5 downto 0); + + DATA_RD : out bit; + DATA_WR : out bit; + DATA_RDY : in bit; + DATA_VALID : in std_logic; + RMC : out bit; + + LOAD_OP1 : out bit; + LOAD_OP2 : out bit; + LOAD_OP3 : out bit; + STORE_ADR_FORMAT : out bit; + STORE_D16 : out bit; + STORE_DISPL : out bit; + STORE_ABS_HI : out bit; + STORE_ABS_LO : out bit; + STORE_AEFF : out bit; + STORE_IDATA_B2 : out bit; + STORE_IDATA_B1 : out bit; + + -- System control signals: + OP : in OP_68K; + OP_SIZE : out OP_SIZETYPE; + BIW_0 : in std_logic_vector(13 downto 0); + BIW_1 : in std_logic_vector(15 downto 0); + EXT_WORD : in std_logic_vector(15 downto 0); + + ADR_MODE : out std_logic_vector(2 downto 0); + AMODE_SEL : out std_logic_vector(2 downto 0); + + OP_WB : out OP_68K; + OP_SIZE_WB : out OP_SIZETYPE; + BIW_0_WB_73 : out std_logic_vector(7 downto 3); -- Used for EXG. + + AR_MARK_USED : out bit; + USE_APAIR : out boolean; + AR_IN_USE : in bit; + AR_SEL_RD_1 : out std_logic_vector(2 downto 0); + AR_SEL_RD_2 : out std_logic_vector(2 downto 0); + AR_SEL_WR_1 : out std_logic_vector(2 downto 0); + AR_SEL_WR_2 : out std_logic_vector(2 downto 0); + AR_INC : out bit; + AR_DEC : out bit; + AR_WR_1 : out bit; + AR_WR_2 : out bit; + + DR_MARK_USED : out bit; + USE_DPAIR : out boolean; + DR_IN_USE : in bit; + DR_SEL_WR_1 : out std_logic_vector(2 downto 0); + DR_SEL_WR_2 : out std_logic_vector(2 downto 0); + DR_SEL_RD_1 : out std_logic_vector(2 downto 0); + DR_SEL_RD_2 : out std_logic_vector(2 downto 0); + DR_WR_1 : out bit; + DR_WR_2 : out bit; + + UNMARK : out bit; + + DISPLACEMENT : out std_logic_vector(31 downto 0); + PC_ADD_DISPL : out bit; + PC_LOAD : out bit; + PC_INC_EXH : in bit; + + SP_ADD_DISPL : out bit; + + DFC_WR : out bit; + DFC_RD : out bit; + SFC_WR : out bit; + SFC_RD : out bit; + + VBR_WR : out bit; + VBR_RD : out bit; + + USP_RD : out bit; + USP_WR : out bit; + + IPIPE_FLUSH : out bit; -- Abandon the instruction pipeline. + + ALU_INIT : out bit; + ALU_BSY : in bit; + ALU_REQ : in bit; + ALU_ACK : out bit; + + BKPT_CYCLE : out bit; + BKPT_INSERT : out bit; + + LOOP_BSY : in bit; + LOOP_SPLIT : out boolean; + LOOP_EXIT : out bit; + + SR_WR : out bit; + MOVEM_ADn : out bit; + MOVEP_PNTR : out integer range 0 to 3; + CC_UPDT : out bit; + TRACE_EN : in std_logic; + ALU_COND : in boolean; + DBcc_COND : in boolean; + BRANCH_ATN : in bit; + RESET_STRB : out bit; + BERR : out bit; + EX_TRACE : out bit; + TRAP_ILLEGAL : out bit; -- Used for BKPT. + TRAP_V : out bit + ); +end entity WF68K10_CONTROL; + +architecture BEHAVIOUR of WF68K10_CONTROL is +type FETCH_STATES is (START_OP, CALC_AEFF, FETCH_DISPL, FETCH_EXWORD_1, FETCH_ABS_HI, FETCH_ABS_LO, + FETCH_IDATA_B2, FETCH_IDATA_B1, FETCH_OPERAND, INIT_EXEC_WB, SLEEP, SWITCH_STATE); +type EXEC_WB_STATES is (IDLE, EXECUTE, WRITEBACK, WRITE_DEST); +signal FETCH_STATE : FETCH_STATES; +signal NEXT_FETCH_STATE : FETCH_STATES; +signal EXEC_WB_STATE : EXEC_WB_STATES; +signal NEXT_EXEC_WB_STATE : EXEC_WB_STATES; +signal ADR_MODE_I : std_logic_vector(2 downto 0); +signal ALU_INIT_I : bit; +signal ALU_TRIG : bit; +signal AR_DEC_I : bit; +signal AR_WR_I : bit; +signal AR_WR_II : bit; +signal BIW_0_WB : std_logic_vector(11 downto 0); +signal BIW_1_WB : std_logic_vector(15 downto 0); +signal DATA_RD_I : bit; +signal DATA_WR_I : bit; +signal EW_RDY : bit; +signal INIT_ENTRY : bit; +signal IPIPE_FLUSH_I : bit; +signal LOOP_EXIT_I : bit; +signal MOVEM_ADn_I : bit; +signal MOVEM_ADn_WB : bit; +signal MOVEM_COND : boolean; +signal MOVEM_FIRST_RD : boolean; +signal MOVEM_INH_WR : boolean; +signal MOVEM_LAST_WR : boolean; +signal MOVEM_PNTR : std_logic_vector(3 downto 0); +signal MOVEP_PNTR_I : integer range 0 to 3; +signal OP_SIZE_I : OP_SIZETYPE; +signal OP_WB_I : OP_68K := UNIMPLEMENTED; +signal OW_RDY : bit; +signal PC_LOAD_I : bit; +signal PHASE2 : boolean; +signal RD_RDY : bit; +signal READ_CYCLE : bit; +signal UPDT_CC : bit; +signal WR_RDY : bit; +signal WRITE_CYCLE : bit; +-- Debugging: +signal OP_TEST : bit; +begin + BUSY <= '1' when OPD_ACK = '1' else -- Early indication. + '1' when OW_RDY = '1' and OP /= ILLEGAL and OP /= RTE and OP /= TRAP and OP /= UNIMPLEMENTED else -- In progress MAIN is now busy. + '1' when LOOP_BSY = '1' else -- Finish the DBcc loop. + '1' when ALU_BSY = '1' else -- Busy, wait. + '1' when FETCH_STATE /= START_OP else '0'; -- Main controller is busy. + + -- The interrupt must not be activated when the controller is in its START_OP + -- state and fetches new OPWORDS. so we define the trigger for the interrupt + -- in the end of the FETCH phase. The SLEEP state is important for STOP. + INT_TRIG <= '1' when FETCH_STATE = INIT_EXEC_WB or FETCH_STATE = SLEEP else '0'; + + OW_REQ <= '0' when BUSY_EXH = '1' else + '0' when EXH_REQ = '1' and LOOP_BSY = '0' else -- Non interrupt exception requests, loop has priority. + '0' when OPD_ACK = '1' or OW_RDY = '1' else + '1' when NO_PIPELINE = true and FETCH_STATE = START_OP and ALU_BSY = '0' else + '1' when NO_PIPELINE = false and FETCH_STATE = START_OP else '0'; + + DATA_AVAILABLE: process + -- These flip flops store the information whether the data required in the different + -- states is available or not. This is necessary in case of delayed cycles for + -- example if the required address register is not ready to be read. + begin + wait until CLK = '1' and CLK' event; + if RESET_CPU = '1' then + OW_RDY <= '0'; + elsif FETCH_STATE = START_OP and NEXT_FETCH_STATE /= START_OP then + OW_RDY <= '0'; -- Reset. + elsif FETCH_STATE = START_OP and (OP = ILLEGAL or OP = RTE or OP = TRAP or OP = UNIMPLEMENTED) and BUSY_EXH = '1' then + OW_RDY <= '0'; -- Done. + elsif OPD_ACK = '1' then + OW_RDY <= '1'; -- Set. + end if; + + if FETCH_STATE = START_OP then + EW_RDY <= '0'; + elsif FETCH_STATE = FETCH_DISPL and NEXT_FETCH_STATE /= FETCH_DISPL then + EW_RDY <= '0'; + elsif FETCH_STATE = FETCH_EXWORD_1 and NEXT_FETCH_STATE /= FETCH_EXWORD_1 then + EW_RDY <= '0'; + elsif FETCH_STATE = FETCH_IDATA_B1 and NEXT_FETCH_STATE /= FETCH_IDATA_B1 then + EW_RDY <= '0'; + elsif (FETCH_STATE = FETCH_DISPL or FETCH_STATE = FETCH_EXWORD_1 or FETCH_STATE = FETCH_IDATA_B1) and EW_ACK = '1' then + EW_RDY <= '1'; + end if; + end process DATA_AVAILABLE; + + EW_REQ <= '0' when EW_ACK = '1' or EW_RDY = '1' else + '1' when FETCH_STATE = FETCH_DISPL or FETCH_STATE = FETCH_EXWORD_1 else + '1' when FETCH_STATE = FETCH_ABS_HI or FETCH_STATE = FETCH_ABS_LO else + '1' when FETCH_STATE = FETCH_IDATA_B2 or FETCH_STATE = FETCH_IDATA_B1 else + '1' when FETCH_STATE /= FETCH_DISPL and NEXT_FETCH_STATE = FETCH_DISPL else + '1' when FETCH_STATE /= FETCH_EXWORD_1 and NEXT_FETCH_STATE = FETCH_EXWORD_1 else + '1' when FETCH_STATE /= FETCH_ABS_HI and NEXT_FETCH_STATE = FETCH_ABS_HI else + '1' when FETCH_STATE /= FETCH_ABS_LO and NEXT_FETCH_STATE = FETCH_ABS_LO else + '1' when FETCH_STATE /= FETCH_IDATA_B2 and NEXT_FETCH_STATE = FETCH_IDATA_B2 else + '1' when FETCH_STATE /= FETCH_IDATA_B1 and NEXT_FETCH_STATE = FETCH_IDATA_B1 else '0'; + + CYCLECONTROL: process + -- This process contros the read and write signals, if + -- asserted simultaneously. In this way, a read cycle is + -- not interrupted by a write cycle and vice versa. + begin + wait until CLK = '1' and CLK' event; + if DATA_RDY = '1' then + WRITE_CYCLE <= '0'; + READ_CYCLE <= '0'; + elsif DATA_WR_I = '1' then + WRITE_CYCLE <= '1'; + READ_CYCLE <= '0'; + elsif DATA_RD_I = '1' then + READ_CYCLE <= '1'; + WRITE_CYCLE <= '0'; + end if; + end process CYCLECONTROL; + + RD_RDY <= DATA_RDY when READ_CYCLE = '1' else '0'; + WR_RDY <= DATA_RDY when WRITE_CYCLE = '1' else '0'; + + INIT_ENTRY <= '1' when FETCH_STATE /= INIT_EXEC_WB and NEXT_FETCH_STATE = INIT_EXEC_WB else '0'; + + DATA_RD <= DATA_RD_I; + DATA_RD_I <= '0' when DATA_WR_I = '1' and READ_CYCLE = '0' and WRITE_CYCLE = '0' else -- Write is prioritized. + '0' when WRITE_CYCLE = '1' else -- Do not read during a write cycle. + '0' when ADR_IN_USE = '1' else -- Avoid data hazards. + '0' when DATA_RDY = '1' else + '1' when FETCH_STATE = FETCH_OPERAND else '0'; + + DATA_WR <= DATA_WR_I; + DATA_WR_I <= '0' when READ_CYCLE = '1' else -- Do not write during a read cycle. + '0' when DATA_RDY = '1' else + '1' when EXEC_WB_STATE = WRITE_DEST else '0'; + + RMC <= '1' when OP = TAS and FETCH_STATE /= START_OP else '0'; + + ALU_ACK <= '1' when EXEC_WB_STATE = EXECUTE and NEXT_EXEC_WB_STATE = IDLE else + '1' when EXEC_WB_STATE = WRITEBACK else + '1' when EXEC_WB_STATE = WRITE_DEST and WR_RDY = '1' else '0'; + + -- Store the extension word right in the end due to used data and/or address registers. + STORE_ADR_FORMAT <= '1' when FETCH_STATE = FETCH_EXWORD_1 and NEXT_FETCH_STATE /= FETCH_EXWORD_1 else '0'; + + STORE_D16 <= '1' when FETCH_STATE = FETCH_DISPL and EW_ACK = '1' else '0'; + + STORE_DISPL <= '1' when OP = MOVEP and FETCH_STATE = START_OP and NEXT_FETCH_STATE /= START_OP and BIW_0(7 downto 6) < "10" else -- Memory to register. + '1' when OP = MOVEP and FETCH_STATE = SWITCH_STATE else '0'; -- Register to memory. + + STORE_ABS_HI <= '1' when FETCH_STATE = FETCH_ABS_HI and EW_ACK = '1' else '0'; + STORE_ABS_LO <= '1' when FETCH_STATE = FETCH_ABS_LO and EW_ACK = '1' else '0'; + + STORE_IDATA_B2 <= '1' when FETCH_STATE = FETCH_IDATA_B2 and EW_ACK = '1' else '0'; + STORE_IDATA_B1 <= '1' when FETCH_STATE = FETCH_IDATA_B1 and EW_ACK = '1' else '0'; + + LOAD_OP1 <= '1' when OP = CMPM and FETCH_STATE = FETCH_OPERAND and RD_RDY = '1' and DATA_VALID = '1' and PHASE2 = true else + '1' when OP = MOVE and BIW_0(8 downto 6) = "100" and BIW_0(5 downto 3) = "001" and BIW_0(11 downto 9) = BIW_0(2 downto 0) and INIT_ENTRY = '1' else -- Load early to write the undecremented Register for Ax, -(Ax). + '1' when OP = MOVES and FETCH_STATE = START_OP and NEXT_FETCH_STATE /= START_OP and ADR_MODE_I = "100" and BIW_1(15) = '1' and BIW_1(11) = '1' and BIW_1(14 downto 12) = BIW_0(2 downto 0) else -- Load the adressing register before decrementing. + '1' when OP = PEA and FETCH_STATE = SWITCH_STATE and PHASE2 = true else -- Load early not to stack the decremented value. + '0' when OP = CMPM or OP = PEA else + '0' when OP = MOVE and BIW_0(8 downto 6) = "100" and BIW_0(5 downto 3) = "001" and BIW_0(11 downto 9) = BIW_0(2 downto 0) else + '0' when OP = MOVES and ADR_MODE_I = "100" and BIW_1(15) = '1' and BIW_1(11) = '1' and BIW_1(14 downto 12) = BIW_0(2 downto 0) else -- Do not load the decremented addressing register. + '1' when ALU_INIT_I = '1' else '0'; + + LOAD_OP2 <= '1' when (OP = ABCD or OP = SBCD) and FETCH_STATE = FETCH_OPERAND and RD_RDY = '1' and DATA_VALID = '1' and PHASE2 = false else + '1' when (OP = ADDX or OP = SUBX) and FETCH_STATE = FETCH_OPERAND and RD_RDY = '1' and DATA_VALID = '1' and PHASE2 = false else + '1' when (OP = ABCD or OP = SBCD) and FETCH_STATE = INIT_EXEC_WB and BIW_0(3) = '0' else -- Register direct. + '1' when (OP = ADDX or OP = SUBX) and FETCH_STATE = INIT_EXEC_WB and BIW_0(3) = '0' else -- Register direct. + '1' when OP = CMPM and FETCH_STATE = FETCH_OPERAND and RD_RDY = '1' and DATA_VALID = '1' and PHASE2 = false else + '0' when OP = ABCD or OP = SBCD or OP = ADDX or OP = SUBX or OP = CMPM else + '1' when OP = LINK and BIW_0(2 downto 0) = "111" and FETCH_STATE = START_OP and NEXT_FETCH_STATE /= START_OP else -- Load early not to stack the decremented address register. + '0' when OP = LINK and BIW_0(2 downto 0) = "111" else + '1' when INIT_ENTRY = '1' else '0'; + + LOAD_OP3 <= '1' when (OP = DIVS or OP = DIVU) and OP_SIZE_I = LONG and BIW_1(10) = '1' and INIT_ENTRY = '1' else '0'; -- 64 bit operand. + + SR_WR <= '1' when (OP_WB_I = ANDI_TO_SR or OP_WB_I = EORI_TO_SR or OP_WB_I = ORI_TO_SR) and EXEC_WB_STATE = WRITEBACK else + '1' when (OP_WB_I = MOVE_TO_CCR or OP_WB_I = MOVE_TO_SR) and EXEC_WB_STATE = WRITEBACK else + '1' when OP_WB_I = STOP and EXEC_WB_STATE = WRITEBACK else '0'; + + -- Addressing mode: + ADR_MODE <= ADR_MODE_I; + ADR_MODE_I <= "010" when OP = BSR or OP = LINK or OP = UNLK else -- (An), (Dn). + "010" when OP = RTD or OP = RTR or OP = RTS else -- (An). + "011" when OP = CMPM else -- (An)+ + "100" when OP = ABCD or OP = SBCD else -- -(An). + "100" when OP = ADDX or OP = SUBX else -- -(An). + "101" when OP = MOVEP else -- (d16, An). + -- The following two conditions change the address mode right in the end of the fetch phase. + "010" when (OP = JSR or OP = PEA) and FETCH_STATE = INIT_EXEC_WB and ALU_BSY = '0' else -- (A7). + BIW_0(8 downto 6) when OP = MOVE and FETCH_STATE = INIT_EXEC_WB and ALU_BSY = '0' else + BIW_0(8 downto 6) when OP = MOVE and PHASE2 = true else + BIW_0(5 downto 3); + + -- This is the selector for the address mode "111". + AMODE_SEL <= BIW_0(11 downto 9) when OP = MOVE and (NEXT_FETCH_STATE = INIT_EXEC_WB or FETCH_STATE = INIT_EXEC_WB) else + BIW_0(11 downto 9) when OP = MOVE and PHASE2 = true else BIW_0(2 downto 0); + + -- Used for the addressing modes and as source selector. + -- In case of the addressing modes, the selector mus be valid one clock cycle before the bus cycle + -- starts due to the pipeline stage for ADR_REG in the address register section. + AR_SEL_RD_1 <= BIW_0(11 downto 9) when (OP = ABCD or OP = SBCD) and FETCH_STATE = START_OP else + BIW_0(11 downto 9) when (OP = ABCD or OP = SBCD) and FETCH_STATE = CALC_AEFF and PHASE2 = false else + BIW_0(11 downto 9) when (OP = ABCD or OP = SBCD) and FETCH_STATE = FETCH_OPERAND and PHASE2 = false and RD_RDY = '0' else -- Destination first. + BIW_0(11 downto 9) when (OP = ABCD or OP = SBCD) and FETCH_STATE = INIT_EXEC_WB else + BIW_0(11 downto 9) when (OP = ADDX or OP = SUBX) and FETCH_STATE = START_OP else + BIW_0(11 downto 9) when (OP = ADDX or OP = SUBX) and FETCH_STATE = CALC_AEFF and PHASE2 = false else + BIW_0(11 downto 9) when (OP = ADDX or OP = SUBX) and FETCH_STATE = FETCH_OPERAND and PHASE2 = false and RD_RDY = '0' else -- Destination first. + BIW_0(11 downto 9) when (OP = ADDX or OP = SUBX) and FETCH_STATE = INIT_EXEC_WB else + BIW_0(11 downto 9) when OP = CMPM and FETCH_STATE = FETCH_OPERAND and PHASE2 = false else -- Fetch destination. + BIW_0(11 downto 9) when OP = MOVE and FETCH_STATE = START_OP and BIW_0(5 downto 3) < "010" and BIW_0(8 downto 6) /= "000" else -- Source is Dn, An. + BIW_0(11 downto 9) when OP = MOVE and FETCH_STATE = CALC_AEFF and PHASE2 = true else + BIW_0(11 downto 9) when OP = MOVE and FETCH_STATE = FETCH_OPERAND and RD_RDY = '1' and BIW_0(8 downto 6) = "100" and BIW_0(5 downto 3) /= "011" else -- All except (An)+,-(An). + BIW_0(11 downto 9) when OP = MOVE and FETCH_STATE = FETCH_IDATA_B1 and BIW_0(8 downto 6) /= "000" else + BIW_0(11 downto 9) when OP = MOVE and FETCH_STATE = FETCH_ABS_LO and BIW_0(8 downto 6) /= "000" and PHASE2 = false else + BIW_0(11 downto 9) when OP = MOVE and FETCH_STATE = SWITCH_STATE and BIW_0(8 downto 6) /= "000" else + BIW_0(11 downto 9) when OP = MOVE and FETCH_STATE = INIT_EXEC_WB and BIW_0(8 downto 6) /= "000" else + BIW_1(14 downto 12) when OP = MOVEC and BIW_0(0) = '1' else -- MOVEC: general register to control register. + "111" when OP = BSR or OP = MOVEC else -- Stack pointers. + "111" when (OP = JSR or OP = LINK) and FETCH_STATE = START_OP else -- Select the SP to decrement. + "111" when OP = PEA and FETCH_STATE = SWITCH_STATE and PHASE2 = true else -- Select the SP to decrement. + "111" when (OP = JSR or OP = LINK or OP = PEA) and FETCH_STATE = INIT_EXEC_WB else -- Writeback address is the SP. + "111" when OP = RTD or OP = RTR or OP = RTS else -- Stack pointer. + "111" when OP = UNLK and (FETCH_STATE = START_OP or FETCH_STATE = CALC_AEFF or FETCH_STATE = FETCH_OPERAND) else -- Check in START_OP to avoid dataz hazards! + BIW_0(2 downto 0) when OP = ABCD or OP = ADD or OP = ADDA or OP = ADDI or OP = ADDQ or OP = ADDX or OP = AND_B or OP = ANDI else + BIW_0(2 downto 0) when OP = ASL or OP = ASR or OP = BCHG or OP = BCLR or OP = BSET or OP = BTST else + BIW_0(2 downto 0) when OP = CHK or OP = CLR or OP = CMP or OP = CMPA or OP = CMPI or OP = CMPM else + BIW_0(2 downto 0) when OP = DIVS or OP = DIVU or OP = EOR or OP = EORI or OP = EXG or OP = JMP or OP = JSR or OP = LEA or OP = LINK or OP = LSL or OP = LSR else + BIW_0(2 downto 0) when OP = MOVE or OP = MOVEA or OP = MOVE_FROM_CCR or OP = MOVE_FROM_SR or OP = MOVE_TO_CCR or OP = MOVE_TO_SR else + BIW_0(2 downto 0) when OP = MOVE_USP or OP = MOVEM or OP = MOVEP or OP = MOVES or OP = MULS or OP = MULU else + BIW_0(2 downto 0) when OP = NBCD or OP = NEG or OP = NEGX or OP = NOT_B or OP = OR_B or OP = ORI or OP = PEA else + BIW_0(2 downto 0) when OP = ROTL or OP = ROTR or OP = ROXL or OP = ROXR or OP = SBCD or OP = Scc or OP = SUB or OP = SUBA else + BIW_0(2 downto 0) when OP = SUBI or OP = SUBQ or OP = SUBX or OP = TAS or OP = TST or OP = UNLK else "000"; + + -- Always the destination. + AR_SEL_WR_1 <= BIW_0(2 downto 0) when OP = ADDQ or OP = SUBQ else + BIW_0(2 downto 0) when OP = EXG and BIW_0(7 downto 3) = "10001" else -- Data and Address register. + BIW_1(14 downto 12) when OP = MOVEC or OP = MOVES else + "111" when OP = UNLK and FETCH_STATE = START_OP else + BIW_0(2 downto 0) when OP = LINK else + MOVEM_PNTR(2 downto 0) when OP = MOVEM else + BIW_0(2 downto 0) when OP = MOVE_USP else + BIW_0(11 downto 9); -- ADDA, EXG, LEA, MOVE, MOVEA, SUBA. + + AR_WR_1 <= AR_WR_I; + AR_WR_I <= '1' when OP = LINK and FETCH_STATE = INIT_EXEC_WB and ALU_BSY = '0' else -- Write SP to An. + '1' when OP = UNLK and FETCH_STATE = SWITCH_STATE and NEXT_FETCH_STATE /= SWITCH_STATE else -- Write An to SP. + '0' when EXEC_WB_STATE /= WRITEBACK else + '1' when OP_WB_I = ADDA or OP_WB_I = SUBA else + '1' when (OP_WB_I = ADDQ or OP_WB_I = SUBQ) and BIW_0_WB(5 downto 3) = "001" else + '1' when OP_WB_I = EXG and BIW_0_WB(7 downto 3) = "01001" else -- Two address registers. + '1' when OP_WB_I = EXG and BIW_0_WB(7 downto 3) = "10001" else -- Data and Address register. + '1' when OP_WB_I = LEA else + '1' when OP_WB_I = MOVE_USP and BIW_0_WB(3) = '1' else + '1' when OP_WB_I = MOVEA else + '1' when OP_WB_I = MOVEC and BIW_1_WB(15) = '1' and BIW_0_WB(0) = '0' else + '1' when OP_WB_I = MOVES and BIW_1_WB(15) = '1' else + '1' when OP_WB_I = MOVEM and MOVEM_ADn_WB = '1' else '0'; + + AR_SEL_RD_2 <= MOVEM_PNTR(2 downto 0) when OP = MOVEM else -- This is the non addressing output. + BIW_1(14 downto 12) when OP = MOVES else + BIW_0(2 downto 0) when OP = ADDQ or OP = MOVE or OP = SUBQ or OP = TST else + BIW_0(2 downto 0) when OP = EXG and BIW_0(7 downto 3) = "10001" else -- Data and address register. + BIW_0(11 downto 9) when OP = ADDA or OP = CMPA or OP = EXG or OP = SUBA else "000"; + + AR_SEL_WR_2 <= BIW_0(2 downto 0); -- Used for EXG, UNLK. + + AR_WR_2 <= AR_WR_II; + AR_WR_II <= '1' when OP_WB_I = UNLK and EXEC_WB_STATE = WRITEBACK else -- Write (SP) to An. + '1' when OP_WB_I = EXG and EXEC_WB_STATE = WRITEBACK and BIW_0_WB(7 downto 3) = "01001" else '0'; -- Two address registers. + + AR_INC <= '1' when (OP = ADD or OP = CMP or OP = SUB) and ADR_MODE_I = "011" and ALU_INIT_I = '1' else + '1' when (OP = ADDA or OP = CMPA or OP = SUBA) and ADR_MODE_I = "011" and FETCH_STATE = FETCH_OPERAND and DATA_RDY = '1' else + '1' when (OP = ADDI or OP = CMPI or OP = SUBI) and ADR_MODE_I = "011" and ALU_INIT_I = '1' else + '1' when (OP = ADDQ or OP = SUBQ) and ADR_MODE_I = "011" and ALU_INIT_I = '1' else + '1' when (OP = AND_B or OP = EOR or OP = OR_B) and ADR_MODE_I = "011" and ALU_INIT_I = '1' else + '1' when (OP = ANDI or OP = EORI or OP = ORI) and ADR_MODE_I = "011" and ALU_INIT_I = '1' else + '1' when (OP = ASL or OP = ASR or OP = LSL or OP = LSR) and BIW_0(7 downto 3) = "11011" and ALU_INIT_I = '1' else + '1' when (OP = ROTL or OP = ROTR or OP = ROXL or OP = ROXR) and BIW_0(7 downto 3) = "11011" and ALU_INIT_I = '1' else + '1' when (OP = BCHG or OP = BCLR or OP = BSET or OP = BTST) and ADR_MODE_I = "011" and ALU_INIT_I = '1' else + '1' when OP = TAS and ADR_MODE_I = "011" and FETCH_STATE = INIT_EXEC_WB and NEXT_FETCH_STATE /= INIT_EXEC_WB else + '1' when (OP = CHK or OP = CLR or OP = TST or OP = Scc) and ADR_MODE_I = "011" and ALU_INIT_I = '1' else + '1' when (OP = NBCD or OP = NEG or OP = NEGX or OP = NOT_B) and ADR_MODE_I = "011" and ALU_INIT_I = '1' else + '1' when OP = CMPM and FETCH_STATE = FETCH_OPERAND and RD_RDY = '1' and DATA_VALID = '1' else + '1' when (OP = MULS or OP = MULU or OP = DIVS or OP = DIVU) and ADR_MODE_I = "011" and ALU_INIT_I = '1' else + '1' when (OP = MOVE_FROM_CCR or OP = MOVE_FROM_SR) and ADR_MODE_I = "011" and FETCH_STATE = INIT_EXEC_WB and NEXT_FETCH_STATE /= INIT_EXEC_WB else + '1' when (OP = MOVE_TO_CCR or OP = MOVE_TO_SR) and ADR_MODE_I = "011" and FETCH_STATE = INIT_EXEC_WB and NEXT_FETCH_STATE /= INIT_EXEC_WB else + '1' when OP = MOVE and ADR_MODE_I = "011" and FETCH_STATE = FETCH_OPERAND and NEXT_FETCH_STATE /= FETCH_OPERAND else + '1' when OP = MOVE and BIW_0(8 downto 6) = "011" and FETCH_STATE = INIT_EXEC_WB and NEXT_FETCH_STATE /= INIT_EXEC_WB else + '1' when OP = MOVEA and ADR_MODE_I = "011" and FETCH_STATE = INIT_EXEC_WB and NEXT_FETCH_STATE /= INIT_EXEC_WB else + '1' when OP = MOVEM and ADR_MODE_I = "011" and ALU_INIT_I = '1' else + '1' when OP = MOVES and ADR_MODE_I = "011" and ALU_INIT_I = '1' else + '1' when (OP = UNLK or OP = RTD or OP = RTR or OP = RTS) and FETCH_STATE = FETCH_OPERAND and RD_RDY = '1' and DATA_VALID = '1' else '0'; + + with OP select + AR_DEC_I <= '1' when ABCD | ADD | ADDA | ADDI | ADDQ | ADDX | AND_B | ANDI | ASL | ASR | BCHG | BCLR | BSET | BTST | CHK | CMP | CMPA | CMPI | + DIVS | DIVU | EOR | EORI | LSL | LSR | MOVE | MOVEA | MOVE_TO_CCR | MOVE_TO_SR | MOVES | MULS | MULU | NBCD | NEG | NEGX | + NOT_B | OR_B | ORI | ROTL | ROTR | ROXL | ROXR | SBCD | SUB | SUBA | SUBI | SUBQ | SUBX | TAS | TST, '0' when others; + + AR_DEC <= AR_DEC_I when ADR_MODE_I = "100" and FETCH_STATE /= CALC_AEFF and NEXT_FETCH_STATE = CALC_AEFF else + '1' when (OP = BSR or OP = JSR or OP = LINK) and FETCH_STATE = START_OP and NEXT_FETCH_STATE /= START_OP else + '1' when (OP = CLR or OP = Scc) and ADR_MODE_I = "100" and INIT_ENTRY = '1' else + '1' when OP = MOVE and BIW_0(8 downto 6) = "100" and BIW_0(5 downto 3) /= "011" and INIT_ENTRY = '1' else -- Not (An)+,-(An). + '1' when OP = MOVE and BIW_0(8 downto 6) = "100" and FETCH_STATE = SWITCH_STATE else -- Needed for source (An)+ mode. + '1' when OP = MOVEM and ADR_MODE_I = "100" and INIT_ENTRY = '1' else -- Decrement before the first bus access. + '1' when OP = MOVEM and ADR_MODE_I = "100" and ALU_INIT_I = '1' and MOVEM_LAST_WR = false else -- After the last bus access the address register is not decremented. + '1' when (OP = MOVE_FROM_CCR or OP = MOVE_FROM_SR) and ADR_MODE_I = "100" and INIT_ENTRY = '1' else + '1' when OP = MOVES and ADR_MODE_I = "100" and BIW_1(11) = '1' and INIT_ENTRY = '1' else + -- PEA: decrement late in SWITCH_STATE not to decremented address register for PEA (xx,A7,yy) address modi. + '1' when OP = PEA and FETCH_STATE = SWITCH_STATE and PHASE2 = true else '0'; + + DR_SEL_RD_1 <= EXT_WORD(14 downto 12) when FETCH_STATE = FETCH_EXWORD_1 else -- Index register + BIW_0(11 downto 9) when (OP = ADD or OP = SUB) and BIW_0(8) = '1' else + BIW_0(11 downto 9) when (OP = AND_B or OP = EOR or OP = OR_B) and BIW_0(8) = '1' else + BIW_0(11 downto 9) when OP = BCHG or OP = BCLR or OP = BSET or OP = BTST else + BIW_0(11 downto 9) when OP = ASL or OP = ASR or OP = LSL or OP = LSR else + BIW_0(11 downto 9) when OP = ROTL or OP = ROTR or OP = ROXL or OP = ROXR else + BIW_1(2 downto 0) when (OP = DIVS or OP = DIVU) and FETCH_STATE /= INIT_EXEC_WB and BIW_0(8 downto 6) = "001" else -- LONG 64. + MOVEM_PNTR(2 downto 0) when OP = MOVEM else + BIW_0(11 downto 9) when OP = MOVEP else + BIW_1(14 downto 12) when OP = MOVEC or OP = MOVES else + BIW_0(2 downto 0) when OP = ADD or OP = AND_B or OP = OR_B or OP = SUB else + BIW_0(2 downto 0) when OP = ABCD or OP = ADDA or OP = ADDX or OP = CHK or OP = CMP or OP = CMPA else + BIW_0(11 downto 9) when OP = EXG and BIW_0(7 downto 3) = "10001" else -- Data and address register. + BIW_0(2 downto 0) when OP = DIVS or OP = DIVU or OP = EXG else + BIW_0(2 downto 0) when OP = MOVE or OP = MOVEA or OP = MOVE_TO_CCR or OP = MOVE_TO_SR or OP = MULS or OP = MULU else + BIW_0(2 downto 0) when OP = SBCD or OP = SUBA or OP = SUBX else "000"; + + DR_SEL_WR_1 <= BIW_1(14 downto 12) when OP = MOVEC or OP = MOVES else + BIW_0(11 downto 9) when OP = ABCD or OP = SBCD else + BIW_0(11 downto 9) when OP = ADDX or OP = SUBX else + BIW_0(11 downto 9) when OP = ADD or OP = SUB else + BIW_0(11 downto 9) when OP = AND_B or OP = OR_B else + BIW_0(11 downto 9) when (OP = DIVS or OP = DIVU) and OP_SIZE_I = WORD else + BIW_1(14 downto 12) when OP = DIVS or OP = DIVU else + BIW_0(11 downto 9) when (OP = MULS or OP = MULU) and OP_SIZE_I = WORD else + BIW_1(14 downto 12) when OP = MULS or OP = MULU else -- Low order result and operand. + BIW_0(11 downto 9) when OP = EXG else + BIW_0(11 downto 9) when OP = MOVE or OP = MOVEP or OP = MOVEQ else + MOVEM_PNTR(2 downto 0) when OP = MOVEM else + BIW_0(2 downto 0); + + DR_WR_1 <= '1' when OP_WB_I = EXG and EXEC_WB_STATE = WRITEBACK and BIW_0_WB(7 downto 3) = "10001" else -- Address- and data register. + '0' when AR_WR_I = '1' else -- This is the locking AR against DR. + '0' when AR_WR_II = '1' else -- This is the locking AR against DR. + '0' when OP_WB_I = ANDI_TO_SR or OP_WB_I = EORI_TO_SR or OP_WB_I = ORI_TO_SR else + '0' when OP_WB_I = MOVE_TO_CCR or OP_WB_I = MOVE_TO_SR else + '0' when OP_WB_I = MOVE_USP else -- USP is written. + '0' when OP_WB_I = MOVEC and BIW_0_WB(0) = '1' else -- To control register. + '0' when OP_WB_I = STOP else -- SR is written but not DR. + '1' when EXEC_WB_STATE = WRITEBACK else '0'; + + DR_SEL_RD_2 <= BIW_0(11 downto 9) when OP = ABCD or OP = SBCD or OP = ADDX or OP = SUBX else + BIW_0(2 downto 0) when (OP = ADD or OP = AND_B or OP = OR_B or OP = SUB) and BIW_0(8) = '1' else + BIW_0(11 downto 9) when OP = ADD or OP = CMP or OP = SUB or OP = AND_B or OP = OR_B else + BIW_0(11 downto 9) when OP = CHK or OP = EXG else + BIW_0(11 downto 9) when (OP = DIVS or OP = DIVU) and BIW_0(7) = '1' else -- WORD size. + BIW_1(14 downto 12) when (OP = DIVS or OP = DIVU) else -- Quotient low portion. + BIW_0(11 downto 9) when (OP = MULS or OP = MULU) and BIW_0(7) = '1' else -- WORD size. + BIW_1(14 downto 12) when (OP = MULS or OP = MULU) else + BIW_0(2 downto 0) when OP = BCHG or OP = BCLR or OP = BSET or OP = BTST else + BIW_0(2 downto 0) when OP = ADDI or OP = ADDQ or OP = ANDI or OP = BCHG or OP = BCLR or OP = BSET or OP = BTST or OP = CMPI else + BIW_0(2 downto 0) when OP = DBcc or OP = EOR or OP = EORI or OP = EXT or OP = NBCD or OP = NEG or OP = NEGX else + BIW_0(2 downto 0) when OP = NOT_B or OP = ORI or OP = SUBI or OP = SUBQ or OP = SWAP or OP = TAS or OP = TST else + BIW_0(2 downto 0) when OP = ASL or OP = ASR or OP = LSL or OP = LSR else + BIW_0(2 downto 0) when OP = ROTL or OP = ROTR or OP = ROXL or OP = ROXR else "000"; + + DR_SEL_WR_2 <= BIW_0(2 downto 0) when OP = EXG else BIW_1(2 downto 0); -- Default is for DIVS and DIVU, MULS, MULU. + + -- Normally source register. Writte in a few exceptions. + DR_WR_2 <= '1' when OP_WB_I = EXG and EXEC_WB_STATE = WRITEBACK and BIW_0_WB(7 downto 3) = "01000" else -- Two data registers. + '1' when OP_WB_I = DIVS and EXEC_WB_STATE = WRITEBACK and BIW_0_WB(8 downto 6) = "001" and BIW_1_WB(14 downto 12) /= BIW_1_WB(2 downto 0) else + '1' when OP_WB_I = DIVU and EXEC_WB_STATE = WRITEBACK and BIW_0_WB(8 downto 6) = "001" and BIW_1_WB(14 downto 12) /= BIW_1_WB(2 downto 0) else + '1' when OP_WB_I = MULS and EXEC_WB_STATE = WRITEBACK and BIW_0_WB(8 downto 6) = "000" and BIW_1_WB(10) = '1' and BIW_1_WB(14 downto 12) /= BIW_1_WB(2 downto 0) else + '1' when OP_WB_I = MULU and EXEC_WB_STATE = WRITEBACK and BIW_0_WB(8 downto 6) = "000" and BIW_1_WB(10) = '1' and BIW_1_WB(14 downto 12) /= BIW_1_WB(2 downto 0) else '0'; + + WB_BUFFER: process + -- This process stores the data for the + -- WRITEBACK or the WRITE_DEST procedure. + -- The MOVEM condition is foreseen to bring + -- the ADn_WB and the PNTR_WB right in time + -- befor the address or data registers are + -- marked used. + begin + wait until CLK = '1' and CLK' event; + if OP = LINK and FETCH_STATE = START_OP and NEXT_FETCH_STATE = SWITCH_STATE then + OP_SIZE_WB <= OP_SIZE_I; -- Bring this information early because the registers are written early. + elsif ALU_INIT_I = '1' then + if OP = DIVS or OP = DIVU or OP = MULS or OP = MULU then + OP_SIZE_WB <= LONG; + elsif OP = MOVEM and BIW_0(10) = '1' then -- Memory to register. + OP_SIZE_WB <= LONG; -- Registers are always written long. + else + OP_SIZE_WB <= OP_SIZE_I; -- Store right in the end before data processing starts. + end if; + + MOVEM_ADn_WB <= MOVEM_ADn_I; + OP_WB_I <= OP; + BIW_0_WB <= BIW_0(11 downto 0); + BIW_1_WB <= BIW_1; + end if; + end process WB_BUFFER; + + OP_WB <= OP_WB_I; + BIW_0_WB_73 <= BIW_0_WB(7 downto 3); + + OP_SIZE <= OP_SIZE_I; + OP_SIZE_I <= LONG when (OP = ADDA or OP = CMPA or OP = SUBA) and BIW_0(8 downto 7) = "11" else + LONG when (OP = BCHG or OP = BCLR or OP = BTST or OP = BSET) and BIW_0(5 downto 3) = "000" else + LONG when OP = EXT and BIW_0(8 downto 6) = "011" else + LONG when OP = BSR or OP = EXG or OP = JSR or OP = LEA or OP = LINK or OP = PEA or OP = SWAP or OP = UNLK else + LONG when OP = CHK and BIW_0(8 downto 7) = "10" else + LONG when (OP = MOVE or OP = MOVEA) and BIW_0(13 downto 12) = "10" else + LONG when OP = MOVEC or OP = MOVEQ or OP = MOVE_USP or OP = RTD or OP = RTS else + LONG when OP = MOVEM and BIW_0(6) = '1' else + LONG when OP = MOVEP and FETCH_STATE = INIT_EXEC_WB and BIW_0(7 downto 6) < "10" else -- Writeback to registers is long (see top level multiplexer). + LONG when (OP = DIVS or OP = DIVU or OP = MULS or OP = MULU) and BIW_0(7) = '0' else + LONG when OP = RTR and PHASE2 = true else -- Read PC. + WORD when (OP = ADDA or OP = CMPA or OP = SUBA) and BIW_0(8 downto 7) = "01" else + WORD when (OP = ASL or OP = ASR) and BIW_0(7 downto 6) = "11" else -- Memory shifts. + WORD when OP = ANDI_TO_SR or OP = EORI_TO_SR or OP = ORI_TO_SR else + WORD when OP = BKPT and FETCH_STATE = FETCH_OPERAND and DATA_RD_I = '1' else + WORD when OP = CHK and BIW_0(8 downto 7) = "11" else + WORD when OP = DBcc or OP = EXT else + WORD when (OP = LSL or OP = LSR) and BIW_0(7 downto 6) = "11" else -- Memory shifts. + WORD when (OP = MOVE or OP = MOVEA) and BIW_0(13 downto 12) = "11" else + WORD when OP = MOVE_FROM_CCR or OP = MOVE_TO_CCR else + WORD when OP = MOVE_FROM_SR or OP = MOVE_TO_SR else + WORD when OP = MOVEM or OP = RTR else + WORD when OP = DIVS or OP = DIVU or OP = MULS or OP = MULU else + WORD when (OP = ROTL or OP = ROTR) and BIW_0(7 downto 6) = "11" else -- Memory shifts. + WORD when (OP = ROXL or OP = ROXR) and BIW_0(7 downto 6) = "11" else -- Memory shifts. + BYTE when OP = ABCD or OP = NBCD or OP = SBCD else + BYTE when OP = ANDI_TO_CCR or OP = EORI_TO_CCR or OP = ORI_TO_CCR else + BYTE when OP = BCHG or OP = BCLR or OP = BTST or OP = BSET else + BYTE when OP = MOVE or OP = MOVEP else + BYTE when OP = Scc or OP = TAS else + -- The following are default settings for all other OP_SIZE relevant operations. + BYTE when BIW_0(7 downto 6) = "00" else + WORD when BIW_0(7 downto 6) = "01" else LONG; + + BKPT_CYCLE <= '1' when OP = BKPT and FETCH_STATE = FETCH_OPERAND and DATA_RD_I = '1' else '0'; + BKPT_INSERT <= '1' when OP = BKPT and FETCH_STATE = FETCH_OPERAND and RD_RDY = '1' and DATA_VALID = '1' else '0'; + + -- All traps must be modeled as strobes. + TRAP_ILLEGAL <= '1' when OP = BKPT and FETCH_STATE = FETCH_OPERAND and RD_RDY = '1' and DATA_VALID = '0' else '0'; + + TRAP_V <= '1' when OP = TRAPV and ALU_COND = true and FETCH_STATE = SLEEP and NEXT_FETCH_STATE = START_OP else '0'; + + BERR <= '0' when FETCH_STATE = START_OP and EXEC_WB_STATE = IDLE else -- Disable when controller is not active. + '0' when OP = BKPT else -- No bus error during breakpoint cycle. + '1' when DATA_RDY = '1' and DATA_VALID = '0' else + '1' when OPD_ACK = '1' and OW_VALID = '0' else + '1' when EW_ACK = '1' and OW_VALID = '0' else '0'; + + SFC_RD <= '1' when OP = MOVEC and BIW_0(0) = '0' and BIW_1(11 downto 0) = x"000" else '0'; + SFC_WR <= '1' when OP_WB_I = MOVEC and BIW_0_WB(0) = '1' and BIW_1_WB(11 downto 0) = x"000" and EXEC_WB_STATE = WRITEBACK else '0'; + + DFC_RD <= '1' when OP = MOVEC and BIW_0(0) = '0' and BIW_1(11 downto 0) = x"001" else '0'; + DFC_WR <= '1' when OP_WB_I = MOVEC and BIW_0_WB(0) = '1' and BIW_1_WB(11 downto 0) = x"001" and EXEC_WB_STATE = WRITEBACK else '0'; + + VBR_RD <= '1' when OP = MOVEC and BIW_0(0) = '0' and BIW_1(11 downto 0) = x"801" else '0'; + VBR_WR <= '1' when OP_WB_I = MOVEC and BIW_0_WB(0) = '1' and BIW_1_WB(11 downto 0) = x"801" and EXEC_WB_STATE = WRITEBACK else '0'; + + USP_RD <= '1' when OP = MOVE_USP and BIW_0(3) = '1' else + '1' when OP = MOVEC and BIW_0(0) = '0' and BIW_1(11 downto 0) = x"800" else '0'; + USP_WR <= '1' when OP_WB_I = MOVE_USP and EXEC_WB_STATE = WRITEBACK and BIW_0_WB(3) = '0' else + '1' when OP_WB_I = MOVEC and BIW_0_WB(0) = '1' and BIW_1_WB(11 downto 0) = x"800" and EXEC_WB_STATE = WRITEBACK else '0'; + + P_DISPLACEMENT: process + variable DISPL_VAR : std_logic_vector(31 downto 0); + -- The displacement is is always word sized and sign + -- extended for the K00/K10. + begin + wait until CLK = '1' and CLK' event; + case OP is + when Bcc | BRA | BSR => + case BIW_0(7 downto 0) is + when x"00" => + for i in 16 to 31 loop + DISPL_VAR(i) := BIW_1(15); + end loop; + DISPL_VAR(15 downto 0) := BIW_1; + when others => + for i in 8 to 31 loop + DISPL_VAR(i) := BIW_0(7); + end loop; + DISPL_VAR(7 downto 0) := BIW_0(7 downto 0); + end case; + when DBcc | MOVEP | RTD => + for i in 16 to 31 loop + DISPL_VAR(i) := BIW_1(15); + end loop; + DISPL_VAR(15 downto 0) := BIW_1; + when others => -- Used for LINK. + for i in 16 to 31 loop + DISPL_VAR(i) := BIW_1(15); + end loop; + DISPL_VAR(15 downto 0) := BIW_1; + end case; + -- + case OP is + when LINK | MOVEP => DISPLACEMENT <= DISPL_VAR; + when others => DISPLACEMENT <= DISPL_VAR + "10"; + end case; + end process P_DISPLACEMENT; + + PC_ADD_DISPL <= '1' when OP = Bcc and FETCH_STATE /= START_OP and NEXT_FETCH_STATE = START_OP and ALU_COND = true else + '1' when (OP = BRA or OP = BSR) and FETCH_STATE /= START_OP and NEXT_FETCH_STATE = START_OP else + '1' when OP = DBcc and FETCH_STATE /= START_OP and NEXT_FETCH_STATE = START_OP and ALU_COND = false and DBcc_COND = false else '0'; + + PC_LOAD <= PC_LOAD_I; + PC_LOAD_I <= '1' when (OP = JMP or OP = JSR) and FETCH_STATE /= START_OP and NEXT_FETCH_STATE = START_OP else + '1' when (OP = RTD or OP = RTR or OP = RTS) and FETCH_STATE /= START_OP and NEXT_FETCH_STATE = START_OP else '0'; + + -- The pipe is flushed for the system control instructions. Be aware, that the operations resulting in an exception + -- like the CHK or TRAP operations flush the pipe via the exception handler. + -- Context switch may occur from: + -- changing the PC value (branches etc.) + -- changing the RAM space (status register MSBs). + -- changing Function codes or the active stack pointer. + IPIPE_FLUSH <= IPIPE_FLUSH_I; + IPIPE_FLUSH_I <= '1' when (OP = BRA or OP = BSR) and FETCH_STATE /= START_OP and NEXT_FETCH_STATE = START_OP else + '1' when OP = Bcc and FETCH_STATE /= START_OP and NEXT_FETCH_STATE = START_OP and ALU_COND = true else + '1' when OP = DBcc and LOOP_BSY = '0' and FETCH_STATE /= START_OP and NEXT_FETCH_STATE = START_OP and ALU_COND = false and DBcc_COND = false else + '1' when OP = DBcc and LOOP_EXIT_I = '1' and (ALU_COND = true or DBcc_COND = true) else -- Flush the pipe after a finished loop. + '1' when (OP = ANDI_TO_SR or OP = EORI_TO_SR or OP = MOVE_TO_SR or OP = ORI_TO_SR) and FETCH_STATE = SLEEP and NEXT_FETCH_STATE = START_OP else + '1' when (OP = JMP or OP = JSR) and FETCH_STATE /= START_OP and NEXT_FETCH_STATE = START_OP else + '1' when OP = MOVEC and BIW_0(0) = '1' and FETCH_STATE /= START_OP and NEXT_FETCH_STATE = START_OP else -- Writing control registers. + '1' when (OP = RTD or OP = RTR or OP = RTS) and FETCH_STATE /= START_OP and NEXT_FETCH_STATE = START_OP else '0'; + + SP_ADD_DISPL <= '1' when OP = LINK and FETCH_STATE = INIT_EXEC_WB and ALU_BSY = '0' else + '1' when OP = RTD and FETCH_STATE = FETCH_OPERAND and RD_RDY = '1' and DATA_VALID = '1' else '0'; + + ALU_TRIG <= '0' when ALU_BSY = '1' or FETCH_STATE /= INIT_EXEC_WB else + '0' when OP = CMPM and PHASE2 = false else + '0' when OP = MOVE and PHASE2 = true else -- No ALU required after second portion of address calculation. + '0' when OP = MOVEM and MOVEM_COND = false else + '0' when OP = MOVEM and BIW_0(10) = '1' and MOVEM_FIRST_RD = false else -- Do not load before the first read access. + '0' when OP = RTR and PHASE2 = true else '1'; -- RTR: not when PC is loaded. + + -- This is the signal loading the operands into the ALU registers: + ALU_INIT <= ALU_INIT_I; + with OP select + ALU_INIT_I <= ALU_TRIG when ABCD | ADD | ADDA | ADDI | ADDQ | ADDX | AND_B | ANDI | ANDI_TO_CCR | ANDI_TO_SR | ASL | ASR | Bcc | BCHG | + BCLR | BSET | BSR | BTST | CHK | CLR | CMP | CMPA | CMPI | CMPM | DBcc | DIVS | DIVU | EOR | EORI | + EORI_TO_CCR | EORI_TO_SR | EXG | EXT | JSR | LEA | LINK | LSL | LSR | MOVE | MOVEA | MOVE_FROM_CCR | + MOVE_TO_CCR | MOVE_FROM_SR | MOVE_TO_SR | MOVE_USP | MOVEC | MOVEM | MOVEQ | MOVEP | MOVES | MULS | + MULU | NBCD | NEG | NEGX | NOT_B | OR_B | ORI | ORI_TO_CCR | ORI_TO_SR | PEA | ROTL | ROTR | ROXL | + ROXR | RTR | SBCD | Scc | SUB | SUBA | SUBI | SUBQ | SUBX | SWAP | STOP | TAS | TRAPV | TST | UNLK, '0' when others; + + UPDT_CC <= '0' when (OP_WB_I = ADDQ or OP_WB_I = SUBQ) and BIW_0_WB(5 downto 3) = "001" else ALU_REQ; -- No update for ADDQ and SUBQ when destination is an address register. + + with OP_WB_I select + CC_UPDT <= UPDT_CC when ABCD | ADD | ADDI | ADDQ | ADDX | AND_B | ANDI | ANDI_TO_CCR | ASL | ASR | BCHG | BCLR | + BSET | BTST | CHK | CLR | CMP | CMPA | CMPI | CMPM | DIVS | DIVU | + EOR | EORI | EORI_TO_CCR | EXT | LSL | LSR | MOVE | MOVEQ | MULS | MULU | NBCD | + NEG | NEGX | NOT_B | OR_B | ORI | ORI_TO_CCR | ROTL | ROTR | ROXL | ROXR | RTR | SBCD | + SUB | SUBI | SUBQ | SUBX | SWAP | TAS | TST, '0' when others; + + ADR_MARK_USED <= '1' when OP = MOVE and FETCH_STATE = INIT_EXEC_WB and PHASE2 = true else -- Destination address calculation done. + '0' when FETCH_STATE /= INIT_EXEC_WB or ALU_BSY = '1' else -- Deactivate except in the end of INIT_EXEC_WB. + '1' when OP = BSR or OP = JSR or OP = LINK or OP = PEA else + '1' when (OP = ADDI or OP = ANDI or OP = EOR or OP = EORI or OP = ORI or OP = SUBI) and BIW_0(5 downto 3) /= "000" else + '1' when (OP = ABCD or OP = SBCD or OP = ADDX or OP = SUBX) and BIW_0(3) = '1' else + '1' when (OP = ADD or OP = AND_B or OP = OR_B or OP = SUB) and BIW_0(8) = '1' else -- Destination is memory. + '1' when (OP = ADDQ or OP = BCHG or OP = BCLR or OP = BSET or OP = CLR or OP = MOVE_FROM_CCR or OP = MOVE_FROM_SR) and BIW_0(5 downto 3) > "001" else + '1' when (OP = NBCD or OP = NEG or OP = NEGX or OP = NOT_B or OP = Scc or OP = SUBQ or OP = TAS) and BIW_0(5 downto 3) > "001" else + '1' when (OP = ASL or OP = ASR or OP = LSL or OP = LSR) and BIW_0(7 downto 6) = "11" else -- Memory shifts. + '1' when (OP = ROTL or OP = ROTR or OP = ROXL or OP = ROXR) and BIW_0(7 downto 6) = "11" else -- Memory shifts. + '1' when OP = MOVE and PHASE2 = false and BIW_0(8 downto 6) /= "000" and BIW_0(8 downto 6) < "101" else -- We do not need destination address calculation access. + '1' when OP = MOVEM and BIW_0(10) = '0' and MOVEM_COND = true else -- Register to memory. + '1' when OP = MOVEP and BIW_0(7 downto 6) > "01" else -- Register to Memory. + '1' when OP = MOVES and BIW_1(11) = '1' else '0'; -- Register to memory. + + AR_MARK_USED <= '1' when OP = UNLK and FETCH_STATE /= SWITCH_STATE and NEXT_FETCH_STATE = SWITCH_STATE else -- This is for An to SP. + '1' when OP = LINK and FETCH_STATE = SWITCH_STATE and NEXT_FETCH_STATE /= SWITCH_STATE else -- This is for SP to An. + '0' when FETCH_STATE /= INIT_EXEC_WB or NEXT_FETCH_STATE = INIT_EXEC_WB else -- Deactivate except in the end of INIT_EXEC_WB. + '1' when OP = ADDA or OP = SUBA else + '1' when (OP = ADDQ or OP = SUBQ) and BIW_0(5 downto 3) = "001" else + '1' when OP = EXG and BIW_0(7 downto 3) /= "01000" else + '1' when OP = LEA else + '1' when OP = MOVE_USP else + '1' when OP = MOVEM and BIW_0(10) = '1' and MOVEM_ADn_I = '1' and MOVEM_COND = true else -- Memory to register. + '1' when OP = MOVEA else + '1' when OP = MOVEC and BIW_0(0) = '0' and BIW_1(15) = '1' else -- Destination is Ax. + '1' when OP = MOVES and BIW_1(15) = '1' and BIW_1(11) = '0' else + '1' when OP = UNLK else '0'; + + DR_MARK_USED <= '0' when FETCH_STATE /= INIT_EXEC_WB or NEXT_FETCH_STATE = INIT_EXEC_WB else -- Deactivate except in the end of INIT_EXEC_WB. + '1' when (OP = ABCD or OP = SBCD) and BIW_0(3) = '0' else + '1' when (OP = ADDX or OP = SUBX) and BIW_0(3) = '0' else + '1' when (OP = ADDQ or OP = SUBQ) and BIW_0(5 downto 3) = "000" else + '1' when (OP = ADD or OP = SUB) and BIW_0(8) = '0' else -- Destination is a register. + '1' when (OP = ADDI or OP = ANDI or OP = EOR or OP = EORI or OP = ORI or OP = SUBI) and BIW_0(5 downto 3) = "000" else + '1' when (OP = AND_B or OP = OR_B) and BIW_0(8) = '0' else -- Destination is a register. + '1' when (OP = ASL or OP = ASR) and BIW_0(7 downto 6) /= "11" else + '1' when (OP = LSL or OP = LSR) and BIW_0(7 downto 6) /= "11" else + '1' when (OP = ROTL or OP = ROTR) and BIW_0(7 downto 6) /= "11" else + '1' when (OP = ROXL or OP = ROXR) and BIW_0(7 downto 6) /= "11" else + '1' when (OP = BCHG or OP = BCLR or OP = BSET) and BIW_0(5 downto 3) = "000" else + '1' when (OP = CLR or OP = TAS or OP = Scc) and BIW_0(5 downto 3) = "000" else + '1' when OP = DBcc or OP = DIVS or OP = DIVU or OP = MULS or OP = MULU else + '1' when OP = EXG and BIW_0(7 downto 3) /= "01001" else + '1' when OP = EXT or OP = SWAP else + '1' when OP = MOVE and BIW_0(8 downto 6) = "000" else + '1' when (OP = MOVE_FROM_CCR or OP = MOVE_FROM_SR) and BIW_0(5 downto 3) = "000" else + '1' when OP = MOVEM and BIW_0(10) = '1' and MOVEM_ADn_I = '0' and MOVEM_COND = true else -- Memory to register. + '1' when OP = MOVEP and BIW_0(7 downto 6) < "10" else -- Memory to register. + '1' when OP = MOVEC and BIW_0(0) = '0' and BIW_1(15) = '0' else -- Destination is Dx. + '1' when OP = MOVEQ else + '1' when OP = MOVES and BIW_1(15) = '0' and BIW_1(11) = '0' else + '1' when (OP = NBCD or OP = NEG or OP = NEGX or OP = NOT_B) and BIW_0(5 downto 3) = "000" else '0'; + + UNMARK <= '1' when EXEC_WB_STATE /= IDLE and NEXT_EXEC_WB_STATE = IDLE else '0'; -- Release a pending write cycle when done. + + -- These signals indicates, that two registers are prepared to be written. In this case, the values + -- in both of these registers are invalidated before the writeback. + USE_APAIR <= true when OP = EXG and BIW_0(7 downto 3) = "01001" else false; + USE_DPAIR <= true when OP = EXG and BIW_0(7 downto 3) = "01000" else + true when (OP = DIVS or OP = DIVU) and OP_SIZE_I = LONG and BIW_1(14 downto 12) /= BIW_1(2 downto 0) else + true when (OP = MULS or OP = MULU) and OP_SIZE_I = LONG and BIW_1(10) = '1' and BIW_1(14 downto 12) /= BIW_1(2 downto 0) else false; + + LOOP_EXIT <= LOOP_EXIT_I; + LOOP_EXIT_I <= '1' when OP /= DBcc and LOOP_BSY = '1' and FETCH_STATE /= START_OP and NEXT_FETCH_STATE = START_OP and EXH_REQ = '1' else -- Exception! break the loop. + '1' when OP = DBcc and LOOP_BSY = '1' and FETCH_STATE = SLEEP and NEXT_FETCH_STATE = START_OP and (ALU_COND = true or DBcc_COND = true) else '0'; -- 68010 loop mechanism. + + LOOP_CTRL: process + -- This flip flop indicates, if a DBcc loop operation has finished if the exception handler indicates an interrupt. + -- If so, no action is required. If the loop is split (when not finished) the exception handler may not increment + -- the PC to hold the value of the loop operation. + -- Split the loop between the loop op and DBcc to handle the PC value at interrupts correctly. + begin + wait until CLK = '1' and CLK' event; + if FETCH_STATE = START_OP and NEXT_FETCH_STATE /= START_OP then + LOOP_SPLIT <= false; + elsif PC_INC_EXH = '1' then + LOOP_SPLIT <= false; + elsif OP /= DBcc and EXH_REQ = '1' and LOOP_BSY = '1' and FETCH_STATE = SLEEP and NEXT_FETCH_STATE = START_OP then + LOOP_SPLIT <= true; + end if; + end process LOOP_CTRL; + + RESET_STRB <= '1' when OP = RESET and INIT_ENTRY = '1' else '0'; + + EX_TRACE <= '0' when OP = ILLEGAL or OP = UNIMPLEMENTED else + '1' when TRACE_EN = '1' and OPD_ACK = '1' and FETCH_STATE = START_OP and OP = TRAP else + '1' when TRACE_EN = '1' and FETCH_STATE /= START_OP and NEXT_FETCH_STATE = START_OP else '0'; + + ADDRESS_OFFSET: process + variable ADR_OFFS_VAR: std_logic_vector(5 downto 0) := "000000"; + begin + wait until CLK = '1' and CLK' event; + if FETCH_STATE = START_OP then + ADR_OFFS_VAR := "000000"; + else + case OP is + when MOVEM => + if ADR_MODE_I = "011" or ADR_MODE_I = "100" then -- (An)+, -(An). + null; -- Offset comes from addressing register in register to memory mode. + elsif BIW_0(10) = '1' and MOVEM_FIRST_RD = false then + null; -- Do not increment before the first bus access. + elsif MOVEM_COND = true and FETCH_STATE = INIT_EXEC_WB and ALU_BSY = '0' and OP_SIZE_I = LONG then + ADR_OFFS_VAR := ADR_OFFS_VAR + "100"; -- Register to memory. + elsif MOVEM_COND = true and FETCH_STATE = INIT_EXEC_WB and ALU_BSY = '0' then + ADR_OFFS_VAR := ADR_OFFS_VAR + "10"; -- Register to memory. + end if; + when MOVEP => + if FETCH_STATE = INIT_EXEC_WB and ALU_BSY = '0' then + ADR_OFFS_VAR := ADR_OFFS_VAR + "10"; + end if; + when others => null; + end case; + end if; + ADR_OFFSET <= ADR_OFFS_VAR; + end process ADDRESS_OFFSET; + + MOVEM_CONTROL: process(ADR_MODE_I, CLK, BIW_0, BIW_1, OP, RESET_CPU, FETCH_STATE, NEXT_FETCH_STATE, ALU_BSY, MOVEM_PNTR) + variable INDEX : integer range 0 to 15 := 0; + variable MOVEM_PVAR : std_logic_vector(3 downto 0) := x"0"; + variable BITS : std_logic_vector(4 downto 0); + begin + if CLK = '1' and CLK' event then + if FETCH_STATE = START_OP then + MOVEM_PVAR := x"0"; + elsif FETCH_STATE = INIT_EXEC_WB and MOVEM_COND = false and MOVEM_PVAR < x"F" and ALU_BSY = '0' then + MOVEM_PVAR := MOVEM_PVAR + '1'; -- No data to write. + elsif BIW_0(10) = '1' and MOVEM_FIRST_RD = true and FETCH_STATE = INIT_EXEC_WB and MOVEM_PVAR < x"F" and ALU_BSY = '0' then + MOVEM_PVAR := MOVEM_PVAR + '1'; -- Data has not been read. + elsif BIW_0(10) = '0' and FETCH_STATE = INIT_EXEC_WB and MOVEM_PVAR < x"F" and ALU_BSY = '0' then + MOVEM_PVAR := MOVEM_PVAR + '1'; -- Data has been written. + end if; + + if OP = MOVEM and ALU_INIT_I = '1' and ADR_MODE_I = "011" and MOVEM_ADn_I = '1' and MOVEM_PNTR(2 downto 0) = BIW_0(2 downto 0) then + MOVEM_INH_WR <= true; -- Do not write the addressing register. + elsif ALU_INIT_I = '1' then + MOVEM_INH_WR <= false; + end if; + + if FETCH_STATE = START_OP then + MOVEM_FIRST_RD <= false; + elsif OP = MOVEM and FETCH_STATE = FETCH_OPERAND and RD_RDY = '1' then + MOVEM_FIRST_RD <= true; + end if; + + if RESET_CPU = '1' or (FETCH_STATE /= START_OP and NEXT_FETCH_STATE = START_OP) then + BITS := "00000"; + MOVEM_LAST_WR <= false; + elsif OP = MOVEM and FETCH_STATE = START_OP and NEXT_FETCH_STATE /= START_OP and ADR_MODE_I = "100" then -- -(An). + for i in 0 to 15 loop + BITS := BITS + BIW_1(i); -- Count number of '1's. + end loop; + MOVEM_LAST_WR <= false; + elsif OP = MOVEM and ALU_INIT_I = '1' and BITS > "00001" then + BITS := BITS - '1'; + elsif OP = MOVEM and BITS = "00001" then + MOVEM_LAST_WR <= true; + end if; + + -- During the MOVEM instruction in memory to register operation and addressing modes "010", "101","110" the effective address might be + -- affected, if the addressing register is active in the register list mask. To deal with it, the effective address is stored until the + -- MOVEM has read all registers from memory addressed by the initial addressing register (old value). + -- This logic is modeled synchronously (one clock latency) due to the one clock delay of the address calculation. + if OP /= MOVEM or BIW_0(10) /= '1' or (ADR_MODE_I /= "010" and ADR_MODE_I /= "101" and ADR_MODE_I /= "110") then + STORE_AEFF <= '0'; + elsif FETCH_STATE /= START_OP and NEXT_FETCH_STATE = START_OP then + STORE_AEFF <= '0'; -- Operation completed. + elsif FETCH_STATE = SWITCH_STATE or FETCH_STATE = CALC_AEFF or FETCH_STATE = FETCH_OPERAND or FETCH_STATE = INIT_EXEC_WB then + STORE_AEFF <= '1'; + end if; + end if; + + -- This signal determines whether to handle address or data registers. + if ADR_MODE_I = "100" then -- -(An). + MOVEM_ADn_I <= not To_Bit(MOVEM_PVAR(3)); + MOVEM_ADn <= not To_Bit(MOVEM_PVAR(3)); + else + MOVEM_ADn_I <= To_Bit(MOVEM_PVAR(3)); + MOVEM_ADn <= To_Bit(MOVEM_PVAR(3)); + end if; + + INDEX := To_Integer(unsigned(MOVEM_PVAR)); + + -- The following signal determines if a register is affected or not, depending + -- on the status of the register list bit. + if OP = MOVEM and BIW_1(INDEX) = '1' then + MOVEM_COND <= true; + else + MOVEM_COND <= false; + end if; + + -- This signal determines whether to handle address or data registers. + if ADR_MODE_I = "100" then -- -(An). + MOVEM_PNTR <= not MOVEM_PVAR; -- Count down. + else + MOVEM_PNTR <= MOVEM_PVAR; + end if; + end process MOVEM_CONTROL; + + MOVEP_CONTROL: process(CLK, MOVEP_PNTR_I) + -- This logic handles the bytes to be written or read during the MOVEP + -- operation. In LONG mode 4 bytes are affected and in WORD mode two bytes. + begin + if CLK = '1' and CLK' event then + if RESET_CPU = '1' or (FETCH_STATE /= START_OP and NEXT_FETCH_STATE = START_OP) then + MOVEP_PNTR_I <= 0; + elsif FETCH_STATE = START_OP and (BIW_0(8 downto 6) = "101" or BIW_0(8 downto 6) = "111") then + MOVEP_PNTR_I <= 3; -- LONG. + elsif FETCH_STATE = START_OP then + MOVEP_PNTR_I <= 1; -- WORD. + elsif FETCH_STATE = INIT_EXEC_WB and ALU_BSY = '0' and MOVEP_PNTR_I /= 0 then + MOVEP_PNTR_I <= MOVEP_PNTR_I - 1; -- Register to memory + end if; + end if; + MOVEP_PNTR <= MOVEP_PNTR_I; + end process MOVEP_CONTROL; + + PHASE2_CONTROL: process + -- This is used for some operations which require + -- two control sequences. + begin + wait until CLK = '1' and CLK' event; + if NEXT_FETCH_STATE = START_OP then + PHASE2 <= false; + elsif (OP = ABCD or OP = SBCD) and FETCH_STATE = FETCH_OPERAND and RD_RDY = '1' then + PHASE2 <= true; -- One clock cycle delay for destination address calculation. + elsif (OP = ADDX or OP = SUBX) and FETCH_STATE = FETCH_OPERAND and RD_RDY = '1' then + PHASE2 <= true; -- One clock cycle delay for destination address calculation. + elsif OP = CMPM and FETCH_STATE = INIT_EXEC_WB and ALU_BSY = '0' then + PHASE2 <= true; -- Used as a control flow switch. + elsif OP = JSR and FETCH_STATE = SLEEP then + PHASE2 <= true; -- One clock cycle delay for address calculation. + elsif OP = PEA and FETCH_STATE = SWITCH_STATE then + PHASE2 <= true; -- One clock cycle delay for address calculation. + elsif OP = RTR and FETCH_STATE = INIT_EXEC_WB and NEXT_FETCH_STATE = CALC_AEFF then + PHASE2 <= true; -- Used as a control flow switch. + elsif OP = MOVE and FETCH_STATE = INIT_EXEC_WB and ALU_BSY = '0' and BIW_0(8 downto 6) > "100" then + PHASE2 <= true; -- Indicate destination address calculation is in progress. + end if; + end process PHASE2_CONTROL; + + STATE_REGs: process + begin + wait until CLK = '1' and CLK' event; + if RESET_CPU = '1' then + FETCH_STATE <= START_OP; + EXEC_WB_STATE <= IDLE; + elsif EW_ACK = '1' and OW_VALID = '0' then + FETCH_STATE <= START_OP; -- Bus error. + EXEC_WB_STATE <= IDLE; + elsif OPD_ACK = '1' and OW_VALID = '0' then + FETCH_STATE <= START_OP; -- Bus error. + EXEC_WB_STATE <= IDLE; + elsif DATA_RD_I = '1' and RD_RDY = '1' and DATA_VALID = '0' then + FETCH_STATE <= START_OP; -- Bus error. + EXEC_WB_STATE <= IDLE; + elsif DATA_WR_I = '1' and RD_RDY = '1' and DATA_VALID = '0' then + FETCH_STATE <= START_OP; -- Bus error. + EXEC_WB_STATE <= IDLE; + else + FETCH_STATE <= NEXT_FETCH_STATE; + EXEC_WB_STATE <= NEXT_EXEC_WB_STATE; + end if; + end process STATE_REGs; + + -- Debugging: + -- Use this signal to detect instructions in use in the writeback path (OP_WB_I) or in the fetch path (OP). + -- for these instructions you can halt the pipeline in the START_OP state to detect any problems. + -- with OP select + -- with OP_WB_I select + -- OP_TEST <= '1' when ADDA | ADDQ | EXG | LEA | LINK | MOVEA | MOVE_USP | MOVEC | MOVEM | MOVES | SUBA | SUBQ | UNLK | -- Address register manipulations. + -- ASL | ASR | LSL | LSR | ROTL | ROTR | ROXL | ROXR | DIVS | DIVU | -- Long ALU operations. (68K10, 68K30L have no barrel shifter). + -- ADD | AND_B | CLR | EOR | SUB | OR_B | CMP | CMPA | CMPM | NOT_B | NBCD | NEG | NEGX | SWAP | TAS | TST | + -- ANDI_TO_CCR | ANDI_TO_SR | EORI_TO_CCR | EORI_TO_SR | ORI_TO_CCR | ORI_TO_SR | MOVE_FROM_CCR | + -- MOVE_TO_CCR | MOVE_FROM_SR | MOVE_TO_SR | MOVE | MOVEQ | MOVEP | PEA | + -- ABCD | ADDX | SBCD | SUBX | BCHG | BCLR | BSET | BTST | EXT | + -- Bcc | BSR | CHK | DBcc | JSR | TRAPV | RTR | Scc | STOP | + -- ADDI | ANDI | SUBI | CMPI | EORI | ORI | MULS | MULU, '0' when others; + + FETCH_DEC: process(ADR_MODE_I, ALU_BSY, ALU_COND, AR_IN_USE, BIW_0, BIW_1, BRANCH_ATN, DR_IN_USE, EW_ACK, + EW_RDY, EXEC_WB_STATE, EXH_REQ, EXT_WORD, FETCH_STATE, MOVEM_COND, MOVEM_PNTR, MOVEP_PNTR_I, + NEXT_EXEC_WB_STATE, OP, OP_SIZE_I, OP_WB_I, OPD_ACK, OW_RDY, PHASE2, RD_RDY, TRACE_EN, WR_RDY) + -- ADH: avoid data hazard. + -- ASH: avoid structural hazard. + -- ACH: avoid control hazard. + begin + case FETCH_STATE is + when START_OP => + if OPD_ACK = '0' and OW_RDY = '0' then + NEXT_FETCH_STATE <= START_OP; + -- Debugging: + --elsif OP_TEST = '1' and ALU_BSY = '1' then + -- NEXT_FETCH_STATE <= START_OP; + else + case OP is + when ILLEGAL | RTE | TRAP | UNIMPLEMENTED => + NEXT_FETCH_STATE <= START_OP; + when DBcc | EXT | MOVEQ | SWAP => + if DR_IN_USE = '1' then + NEXT_FETCH_STATE <= START_OP; -- Wait, ADH. + else + NEXT_FETCH_STATE <= INIT_EXEC_WB; -- Proceed. + end if; + when ABCD | SBCD | ADDX | SUBX => + if BIW_0(3) = '0' and DR_IN_USE = '0' then -- ADH. + NEXT_FETCH_STATE <= INIT_EXEC_WB; -- Register to register. + elsif BIW_0(3) = '1' and AR_IN_USE = '0' then -- Check for destination addressing register. ADH. + NEXT_FETCH_STATE <= CALC_AEFF; -- Memory to memory. + else + NEXT_FETCH_STATE <= START_OP; -- Wait, ADH. + end if; + when ADD | ADDI | ADDQ | AND_B | ANDI | CMP | CMPI | EOR | EORI | + NBCD | NEG | NEGX | NOT_B | OR_B | ORI | SUB | SUBI | SUBQ | TST | TAS => + -- These instructions have to take the destination into aspect + -- because the destination is an ALU operand and may cause data hazards. + case BIW_0(5 downto 3) is + when "000" => -- Dn. + if DR_IN_USE = '0' then + NEXT_FETCH_STATE <= INIT_EXEC_WB; + else + NEXT_FETCH_STATE <= START_OP; + end if; + when "001" => -- An. + if (OP = ADD or OP = SUB or OP = AND_B or OP = EOR or OP = OR_B or OP = CMP) and (AR_IN_USE = '1' or DR_IN_USE = '1')then -- ADH. + NEXT_FETCH_STATE <= START_OP; + elsif AR_IN_USE = '0' then + NEXT_FETCH_STATE <= INIT_EXEC_WB; + else + NEXT_FETCH_STATE <= START_OP; + end if; + when "010" | "011" => -- (An), (An)+. + if AR_IN_USE = '1' then -- ADH. + NEXT_FETCH_STATE <= START_OP; -- Wait, ADH. + else + NEXT_FETCH_STATE <= FETCH_OPERAND; + end if; + when "100" => -- -(An). + if AR_IN_USE = '1' then -- ADH. + NEXT_FETCH_STATE <= START_OP; -- Wait, ADH. + else + NEXT_FETCH_STATE <= CALC_AEFF; + end if; + when "101" => + NEXT_FETCH_STATE <= FETCH_DISPL; + when "110" => + NEXT_FETCH_STATE <= FETCH_EXWORD_1; + when others => -- "111" + if BIW_0(2 downto 0) = "000" then + NEXT_FETCH_STATE <= FETCH_ABS_LO; + elsif BIW_0(2 downto 0) = "001" then + NEXT_FETCH_STATE <= FETCH_ABS_HI; + elsif BIW_0(2 downto 0) = "100" and OP_SIZE_I = LONG then + NEXT_FETCH_STATE <= FETCH_IDATA_B2; + elsif BIW_0(2 downto 0) = "100" then -- Word or byte. + NEXT_FETCH_STATE <= FETCH_IDATA_B1; + elsif BIW_0(2 downto 0) = "010" then + NEXT_FETCH_STATE <= FETCH_DISPL; + else + NEXT_FETCH_STATE <= FETCH_EXWORD_1; + end if; + end case; + when ADDA | BCHG | BCLR | BSET | BTST | CHK | CMPA | + DIVS | DIVU | MULS | MULU | MOVEA | MOVE_TO_CCR | MOVE_TO_SR | SUBA => + case BIW_0(5 downto 3) is + when "000" => -- Source is Dn. + if (OP = ADDA or OP = SUBA or OP = CMPA or OP = MOVEA) and (AR_IN_USE = '1' or DR_IN_USE = '1') then -- ADH. + NEXT_FETCH_STATE <= START_OP; + elsif DR_IN_USE = '0' then + NEXT_FETCH_STATE <= INIT_EXEC_WB; + else + NEXT_FETCH_STATE <= START_OP; + end if; + when "001" => -- Valid for ADDA, CMPA, MOVEA, SUBA; source is An. + if AR_IN_USE = '0' then + NEXT_FETCH_STATE <= INIT_EXEC_WB; -- ADH. + else + NEXT_FETCH_STATE <= START_OP; + end if; + when "010" | "011" => -- (An), (An)+. + if AR_IN_USE = '1' then -- ADH. + NEXT_FETCH_STATE <= START_OP; -- Wait, ADH! + else + NEXT_FETCH_STATE <= FETCH_OPERAND; + end if; + when "100" => -- -(An). + if AR_IN_USE = '1' then -- ADH. + NEXT_FETCH_STATE <= START_OP; -- Wait, ADH! + else + NEXT_FETCH_STATE <= CALC_AEFF; + end if; + when "101" => + NEXT_FETCH_STATE <= FETCH_DISPL; + when "110" => + NEXT_FETCH_STATE <= FETCH_EXWORD_1; + when others => -- "111" + if BIW_0(2 downto 0) = "000" then + NEXT_FETCH_STATE <= FETCH_ABS_LO; + elsif BIW_0(2 downto 0) = "001" then + NEXT_FETCH_STATE <= FETCH_ABS_HI; + elsif BIW_0(2 downto 0) = "100" and OP_SIZE_I = LONG then + NEXT_FETCH_STATE <= FETCH_IDATA_B2; + elsif BIW_0(2 downto 0) = "100" then -- Word or Byte. + NEXT_FETCH_STATE <= FETCH_IDATA_B1; + elsif BIW_0(2 downto 0) = "010" then + NEXT_FETCH_STATE <= FETCH_DISPL; + else + NEXT_FETCH_STATE <= FETCH_EXWORD_1; + end if; + end case; + when EXG => + if BIW_0(7 downto 3) = "10001" and (DR_IN_USE = '1' or AR_IN_USE = '1') then + NEXT_FETCH_STATE <= START_OP; -- Wait, ADH. + elsif BIW_0(7 downto 3) = "01000" and DR_IN_USE = '1' then + NEXT_FETCH_STATE <= START_OP; -- Wait, ADH. + elsif BIW_0(7 downto 3) = "01001" and AR_IN_USE = '1' then + NEXT_FETCH_STATE <= START_OP; -- Wait, ADH. + else + NEXT_FETCH_STATE <= INIT_EXEC_WB; + end if; + when NOP => -- Synchronize the instruction pipeline. + if ALU_BSY = '0' and EXEC_WB_STATE = IDLE then + NEXT_FETCH_STATE <= INIT_EXEC_WB; + else + NEXT_FETCH_STATE <= START_OP; + end if; + when MOVE_FROM_CCR | MOVE_FROM_SR => + if ALU_BSY = '0' then + case BIW_0(5 downto 3) is + when "000" => -- Destination is Dn. + if DR_IN_USE = '0' then + NEXT_FETCH_STATE <= INIT_EXEC_WB; + else + NEXT_FETCH_STATE <= START_OP; + end if; + when "010" | "011" | "100" => -- (An), (An)+, -(An). + if AR_IN_USE = '0' then + NEXT_FETCH_STATE <= INIT_EXEC_WB; + else + NEXT_FETCH_STATE <= START_OP; -- Wait, ADH. + end if; + when "101" => + NEXT_FETCH_STATE <= FETCH_DISPL; + when "110" => + NEXT_FETCH_STATE <= FETCH_EXWORD_1; + when others => -- "111" + if BIW_0(2 downto 0) = "000" then + NEXT_FETCH_STATE <= FETCH_ABS_LO; + else + NEXT_FETCH_STATE <= FETCH_ABS_HI; + end if; + end case; + else + NEXT_FETCH_STATE <= START_OP; + end if; + when ASL | ASR | LSL | LSR | ROTL | ROTR | ROXL | ROXR => + if BIW_0(7 downto 6) /= "11" then -- Register shifts. + if DR_IN_USE = '0' then + NEXT_FETCH_STATE <= INIT_EXEC_WB; -- ADH. + else + NEXT_FETCH_STATE <= START_OP; + end if; + else -- Memory shifts. + case BIW_0(5 downto 3) is + when "010" | "011" => -- (An), (An)+. + if AR_IN_USE = '0' then -- ADH. + NEXT_FETCH_STATE <= FETCH_OPERAND; + else + NEXT_FETCH_STATE <= START_OP; + end if; + when "100" => -- -(An). + if AR_IN_USE = '0' then -- ADH. + NEXT_FETCH_STATE <= CALC_AEFF; + else + NEXT_FETCH_STATE <= START_OP; + end if; + when "101" => + NEXT_FETCH_STATE <= FETCH_DISPL; + when "110" => + NEXT_FETCH_STATE <= FETCH_EXWORD_1; + when others => -- "111". + if BIW_0(2 downto 0) = "000" then + NEXT_FETCH_STATE <= FETCH_ABS_LO; + else + NEXT_FETCH_STATE <= FETCH_ABS_HI; + end if; + end case; + end if; + when BKPT => + -- Wait until the bus controller is free to avoid a structural + -- hazard due to the top level function code multiplexer which + -- switches the CPU_SPACE selector. + if ALU_BSY = '0' then + NEXT_FETCH_STATE <= FETCH_OPERAND; + else + NEXT_FETCH_STATE <= START_OP; + end if; + when CMPM | RTD | RTR | RTS => + if AR_IN_USE = '0' then -- ADH. + NEXT_FETCH_STATE <= FETCH_OPERAND; + else + NEXT_FETCH_STATE <= START_OP; + end if; + when CLR | JMP | JSR | LEA | PEA | Scc => -- No read access required. + case BIW_0(5 downto 3) is + when "000" => -- CLR, Scc. + if DR_IN_USE = '0' then + NEXT_FETCH_STATE <= INIT_EXEC_WB; + else + NEXT_FETCH_STATE <= START_OP; + end if; + when "001" | "010" | "011" | "100" => + if AR_IN_USE = '1' then + NEXT_FETCH_STATE <= START_OP; -- Wait, ADH. + elsif OP = LEA or OP = PEA then + NEXT_FETCH_STATE <= SWITCH_STATE; + else + NEXT_FETCH_STATE <= INIT_EXEC_WB; + end if; + when "101" => + NEXT_FETCH_STATE <= FETCH_DISPL; + when "110" => + NEXT_FETCH_STATE <= FETCH_EXWORD_1; + when others => -- "111" + if BIW_0(2 downto 0) = "000" then + NEXT_FETCH_STATE <= FETCH_ABS_LO; + elsif BIW_0(2 downto 0) = "001" then + NEXT_FETCH_STATE <= FETCH_ABS_HI; + elsif BIW_0(2 downto 0) = "010" then + NEXT_FETCH_STATE <= FETCH_DISPL; + else + NEXT_FETCH_STATE <= FETCH_EXWORD_1; + end if; + end case; + -- + -- The following condition is a special case for the + -- stack manipulating operations JSR and PEA. If A7 + -- is in use, we have to wait in all addressing modes. + if (OP = JSR or OP = PEA) and AR_IN_USE = '1' then + NEXT_FETCH_STATE <= START_OP; -- Wait, ADH. + end if; + when LINK | UNLK => + -- We have to wait for the ALU because the registers are written without pipelining + -- through the ALU and the stack is decremented early. For PEA we have to wait in + -- all addressing modes, if A7 is in use. + if OP = LINK and (ALU_BSY = '1' or AR_IN_USE = '1') then + NEXT_FETCH_STATE <= START_OP; -- Wait, ADH, ASH (two address registers are affected). + elsif OP = UNLK and ALU_BSY = '1' then + NEXT_FETCH_STATE <= START_OP; -- Wait, ADH, ASH (two address registers are affected). + else + NEXT_FETCH_STATE <= SWITCH_STATE; -- Stack pointer is decremented in this state. + end if; + when MOVE => + case BIW_0(5 downto 3) is -- Source operand. + when "000" => -- Dn. + -- Destination is -(An) and will be decremented here, wait. + if BIW_0(8 downto 6) = "100" and (AR_IN_USE = '1' or DR_IN_USE = '1') then + NEXT_FETCH_STATE <= START_OP; + elsif DR_IN_USE = '1' then + NEXT_FETCH_STATE <= START_OP; + else + NEXT_FETCH_STATE <= INIT_EXEC_WB; + end if; + when "001" => -- An. + if AR_IN_USE = '1' then + NEXT_FETCH_STATE <= START_OP; + else + NEXT_FETCH_STATE <= INIT_EXEC_WB; + end if; + when "010" | "011" => -- (An), (An)+. + if AR_IN_USE = '0' then + NEXT_FETCH_STATE <= FETCH_OPERAND; + else + NEXT_FETCH_STATE <= START_OP; + end if; + when "100" => -- -(An). + if AR_IN_USE = '0' then + NEXT_FETCH_STATE <= CALC_AEFF; + else + NEXT_FETCH_STATE <= START_OP; + end if; + when "101" => + NEXT_FETCH_STATE <= FETCH_DISPL; + when "110" => + NEXT_FETCH_STATE <= FETCH_EXWORD_1; + when others => + if BIW_0(2 downto 0) = "000" then + NEXT_FETCH_STATE <= FETCH_ABS_LO; + elsif BIW_0(2 downto 0) = "001" then + NEXT_FETCH_STATE <= FETCH_ABS_HI; + elsif BIW_0(2 downto 0) = "100" and BIW_0(13 downto 12) = "10" then -- Long. + NEXT_FETCH_STATE <= FETCH_IDATA_B2; + elsif BIW_0(2 downto 0) = "100" then -- Word or Byte. + NEXT_FETCH_STATE <= FETCH_IDATA_B1; + elsif BIW_0(2 downto 0) = "010" then + NEXT_FETCH_STATE <= FETCH_DISPL; + else + NEXT_FETCH_STATE <= FETCH_EXWORD_1; + end if; + end case; + when MOVEM => + case BIW_0(5 downto 3) is + when "010" | "011" | "100" => -- (An), (An)+, -(An). + if AR_IN_USE = '1' then -- ADH. + NEXT_FETCH_STATE <= START_OP; + else + NEXT_FETCH_STATE <= INIT_EXEC_WB; + end if; + when "101" => + NEXT_FETCH_STATE <= FETCH_DISPL; + when "110" => + NEXT_FETCH_STATE <= FETCH_EXWORD_1; + when others => + if BIW_0(2 downto 0) = "000" then + NEXT_FETCH_STATE <= FETCH_ABS_LO; + elsif BIW_0(2 downto 0) = "001" then + NEXT_FETCH_STATE <= FETCH_ABS_HI; + elsif BIW_0(2 downto 0) = "010" then + NEXT_FETCH_STATE <= FETCH_DISPL; + else + NEXT_FETCH_STATE <= FETCH_EXWORD_1; + end if; + end case; + when MOVEP => + if AR_IN_USE = '0' and BIW_0(7 downto 6) < "10" then + NEXT_FETCH_STATE <= SWITCH_STATE; -- Memory to register. + elsif AR_IN_USE = '0' and DR_IN_USE = '0' then -- ADH. + NEXT_FETCH_STATE <= SWITCH_STATE; -- Register to memory. + else + NEXT_FETCH_STATE <= START_OP; + end if; + when BSR | MOVE_USP => + -- MOVE_USP: wait until A7 has been updated to load the correct data to the ALU. + -- BSR: wait until A7 has been updated before decrementing. + + if AR_IN_USE = '0' then -- ADH. + NEXT_FETCH_STATE <= INIT_EXEC_WB; + else + NEXT_FETCH_STATE <= START_OP; + end if; + when MOVEC => + if BIW_0(0) = '1' and BIW_1(15) = '1' and AR_IN_USE = '1' then -- Address register is source. + NEXT_FETCH_STATE <= START_OP; -- Wait, ADH. + elsif BIW_0(0) = '1' and BIW_1(15) = '0' and DR_IN_USE = '1' then -- Data register is source. + NEXT_FETCH_STATE <= START_OP; -- Wait, ADH. + else + NEXT_FETCH_STATE <= INIT_EXEC_WB; -- AR, DR are destination. + end if; + when MOVES => + case BIW_0(5 downto 3) is + when "010" | "011" => -- (An), (An)+. + if BIW_1(11) = '0' and AR_IN_USE = '0' then -- ADH. + NEXT_FETCH_STATE <= FETCH_OPERAND; -- Memory to register. + elsif BIW_1(11) = '1' and AR_IN_USE = '0' then -- ADH. + NEXT_FETCH_STATE <= INIT_EXEC_WB; -- Register to memory. + else + NEXT_FETCH_STATE <= START_OP; -- Wait, ADH. + end if; + when "100" => -- -(An). + if BIW_1(11) = '0' and AR_IN_USE = '0' then -- ADH. + NEXT_FETCH_STATE <= CALC_AEFF; -- Memory to register. + elsif BIW_1(11) = '1' and AR_IN_USE = '0' then -- ADH. + NEXT_FETCH_STATE <= INIT_EXEC_WB; -- Register to memory. + else + NEXT_FETCH_STATE <= START_OP; -- Wait, ADH. + end if; + when "101" => + NEXT_FETCH_STATE <= FETCH_DISPL; + when "110" => + NEXT_FETCH_STATE <= FETCH_EXWORD_1; + when others => -- "111" + if BIW_0(2 downto 0) = "000" then + NEXT_FETCH_STATE <= FETCH_ABS_LO; + else + NEXT_FETCH_STATE <= FETCH_ABS_HI; + end if; + end case; + -- Register to memory: + if BIW_1(11) = '1' and BIW_1(15) = '1' and AR_IN_USE = '1' then -- ADH. + NEXT_FETCH_STATE <= START_OP; + elsif BIW_1(11) = '1' and BIW_1(15) = '0' and DR_IN_USE = '1' then -- ADH. + NEXT_FETCH_STATE <= START_OP; + end if; + when ANDI_TO_CCR | ANDI_TO_SR | EORI_TO_CCR | EORI_TO_SR | ORI_TO_CCR | ORI_TO_SR | RESET => + -- Wait until the status register / condition codes have been updated. Otherwise we + -- possibly have a data hazard using the wrong condition codes for the operation. + -- Be aware: for the ANDI_TO_SR, EORI_TO_SR, MOVE_TO_SR and ORI_TOI_SR operations + -- the pipe flush results in automatically aligned condition codes. Nevertheless + -- we need this logic for the respective operations, if the pipe is not flushed, + -- in the case of non changing RAM space. + -- For the RESET: we should not reset in running writeback cycles. + if ALU_BSY = '1' then + NEXT_FETCH_STATE <= START_OP; + else + NEXT_FETCH_STATE <= INIT_EXEC_WB; + end if; + when others => -- Bcc, BRA, STOP, TRAPV. + NEXT_FETCH_STATE <= INIT_EXEC_WB; + end case; + end if; + when FETCH_DISPL => + case OP is + when ADD | CMP | SUB | AND_B | EOR | OR_B => + if (EW_ACK = '1' or EW_RDY = '1') and AR_IN_USE = '0' then -- ADH. + NEXT_FETCH_STATE <= CALC_AEFF; + else + NEXT_FETCH_STATE <= FETCH_DISPL; + end if; + when ADDA | BCHG | BCLR | BSET | BTST | CHK | CMPA | DIVS | DIVU | MULS | MULU | MOVE | MOVEA | MOVE_TO_CCR | MOVE_TO_SR | SUBA => + if (EW_ACK = '1' or EW_RDY = '1') and OP = MOVE and PHASE2 = true and AR_IN_USE = '0' then -- ADH. + NEXT_FETCH_STATE <= INIT_EXEC_WB; + elsif (EW_ACK = '1' or EW_RDY = '1') and AR_IN_USE = '0' then -- ADH. + NEXT_FETCH_STATE <= CALC_AEFF; + else + NEXT_FETCH_STATE <= FETCH_DISPL; + end if; + when ADDI | ADDQ | ANDI | CMPI | EORI | NBCD | NEG | NEGX | NOT_B | ORI | SUBI | SUBQ | TST | TAS | ASL | ASR | LSL | LSR | ROTL | ROTR | ROXL | ROXR => + if (EW_ACK = '1' or EW_RDY = '1') and AR_IN_USE = '0' then -- ADH. + NEXT_FETCH_STATE <= CALC_AEFF; + else + NEXT_FETCH_STATE <= FETCH_DISPL; + end if; + when MOVES => + if (EW_ACK = '1' or EW_RDY = '1') and AR_IN_USE = '0' and BIW_1(11) = '0' then + NEXT_FETCH_STATE <= CALC_AEFF; + elsif (EW_ACK = '1' or EW_RDY = '1') and AR_IN_USE = '0' then + NEXT_FETCH_STATE <= INIT_EXEC_WB; + else + NEXT_FETCH_STATE <= FETCH_DISPL; + end if; + when LEA | PEA => + if (EW_ACK = '1' or EW_RDY = '1') and AR_IN_USE = '0' then -- ADH. + NEXT_FETCH_STATE <= SWITCH_STATE; + else + NEXT_FETCH_STATE <= FETCH_DISPL; + end if; + when others => -- CLR, JMP, JSR, MOVE_FROM_CCR, MOVE_FROM_SR, MOVEM, Scc. + if (EW_ACK = '1' or EW_RDY = '1') and AR_IN_USE = '0' then -- ADH. + NEXT_FETCH_STATE <= INIT_EXEC_WB; + else + NEXT_FETCH_STATE <= FETCH_DISPL; + end if; + end case; + when FETCH_EXWORD_1 => + -- Be aware that the An registers which will be addressed by EXWORD_1 and are used for several addressing modes + -- are valid right after this state (because every address register manipulation requires no more than two clock cycles). + if EW_ACK = '1' or EW_RDY = '1' then -- Null displacement. + case OP is + when ADD | CMP | SUB | AND_B | EOR | OR_B => + if (BIW_1(15) = '0' and AR_IN_USE = '0' and DR_IN_USE = '0') or (BIW_1(15) = '1' and AR_IN_USE = '0') then -- ADH. + NEXT_FETCH_STATE <= CALC_AEFF; + else + NEXT_FETCH_STATE <= FETCH_EXWORD_1; + end if; + when ADDA | BCHG | BCLR | BSET | BTST | CHK | CMPA | DIVS | DIVU | MULS | MULU | MOVE | MOVEA | MOVE_TO_CCR | MOVE_TO_SR | SUBA => + if OP = MOVE and PHASE2 = true and BIW_1(15) = '0' and AR_IN_USE = '0' and DR_IN_USE = '0' then -- ADH. + NEXT_FETCH_STATE <= INIT_EXEC_WB; + elsif OP = MOVE and PHASE2 = true and BIW_1(15) = '1' and AR_IN_USE = '0' then -- ADH. + NEXT_FETCH_STATE <= INIT_EXEC_WB; + elsif (BIW_1(15) = '0' and AR_IN_USE = '0' and DR_IN_USE = '0') or (BIW_1(15) = '1' and AR_IN_USE = '0') then -- ADH. + NEXT_FETCH_STATE <= CALC_AEFF; + else + NEXT_FETCH_STATE <= FETCH_EXWORD_1; + end if; + when MOVES => + if (BIW_1(15) = '0' and AR_IN_USE = '0' and DR_IN_USE = '0') or (BIW_1(15) = '1' and AR_IN_USE = '0') then -- ADH. + if BIW_1(11) = '0' then + NEXT_FETCH_STATE <= CALC_AEFF; + else + NEXT_FETCH_STATE <= INIT_EXEC_WB; + end if; + else + NEXT_FETCH_STATE <= FETCH_EXWORD_1; + end if; + when ADDI | ADDQ | ANDI | CMPI | EORI | NBCD | NEG | NEGX | NOT_B | ORI | SUBI | SUBQ | TST | TAS | ASL | ASR | LSL | LSR | ROTL | ROTR | ROXL | ROXR => + if (BIW_1(15) = '0' and AR_IN_USE = '0' and DR_IN_USE = '0') or (BIW_1(15) = '1' and AR_IN_USE = '0') then -- ADH. + NEXT_FETCH_STATE <= CALC_AEFF; + else + NEXT_FETCH_STATE <= FETCH_EXWORD_1; + end if; + when LEA | PEA => + if (BIW_1(15) = '0' and AR_IN_USE = '0' and DR_IN_USE = '0') or (BIW_1(15) = '1' and AR_IN_USE = '0') then -- ADH. + NEXT_FETCH_STATE <= SWITCH_STATE; + else + NEXT_FETCH_STATE <= FETCH_EXWORD_1; + end if; + when others => -- CLR, JMP, JSR, MOVE_FROM_CCR, MOVE_FROM_SR, MOVEM, Scc. + if (BIW_1(15) = '0' and AR_IN_USE = '0' and DR_IN_USE = '0') or (BIW_1(15) = '1' and AR_IN_USE = '0') then -- ADH. + NEXT_FETCH_STATE <= INIT_EXEC_WB; + else + NEXT_FETCH_STATE <= FETCH_EXWORD_1; + end if; + end case; + else + NEXT_FETCH_STATE <= FETCH_EXWORD_1; + end if; + when FETCH_ABS_HI => + if EW_ACK = '1' then + NEXT_FETCH_STATE <= FETCH_ABS_LO; + else + NEXT_FETCH_STATE <= FETCH_ABS_HI; + end if; + when FETCH_ABS_LO => + if EW_ACK = '1' then + case OP is + when CLR | JMP | JSR | MOVE_FROM_CCR | MOVE_FROM_SR | MOVEM | Scc => + NEXT_FETCH_STATE <= INIT_EXEC_WB; + when LEA | PEA => + NEXT_FETCH_STATE <= SWITCH_STATE; + when MOVE => + if PHASE2 = false then + NEXT_FETCH_STATE <= CALC_AEFF; + else + NEXT_FETCH_STATE <= INIT_EXEC_WB; + end if; + when MOVES => + if BIW_1(11) = '0' then + NEXT_FETCH_STATE <= CALC_AEFF; + else + NEXT_FETCH_STATE <= INIT_EXEC_WB; + end if; + when others => + NEXT_FETCH_STATE <= CALC_AEFF; + end case; + else + NEXT_FETCH_STATE <= FETCH_ABS_LO; + end if; + when FETCH_IDATA_B2 => + if EW_ACK = '1' then + NEXT_FETCH_STATE <= FETCH_IDATA_B1; + else + NEXT_FETCH_STATE <= FETCH_IDATA_B2; + end if; + when FETCH_IDATA_B1 => + if EW_ACK = '1' or EW_RDY = '1' then + case OP is -- ADH. + when ADD | SUB | AND_B | OR_B | BTST | DIVS | DIVU | MULS | MULU | CHK | MOVE => + NEXT_FETCH_STATE <= SWITCH_STATE; + when ADDA | CMPA | SUBA | MOVEA => + NEXT_FETCH_STATE <= SWITCH_STATE; + when others => + if DR_IN_USE = '1' then -- ADH. + NEXT_FETCH_STATE <= FETCH_IDATA_B1; + else + NEXT_FETCH_STATE <= INIT_EXEC_WB; + end if; + end case; + else + NEXT_FETCH_STATE <= FETCH_IDATA_B1; + end if; + when CALC_AEFF => + NEXT_FETCH_STATE <= FETCH_OPERAND; -- One CLK calculation delay. + when FETCH_OPERAND => + if RD_RDY = '1' then + case OP is + when ABCD | ADDX | SBCD | SUBX => + if PHASE2 = false then + NEXT_FETCH_STATE <= CALC_AEFF; + else + NEXT_FETCH_STATE <= INIT_EXEC_WB; + end if; + when ADD | CMP | CHK | SUB | AND_B | EOR | OR_B | BCHG | BCLR | BSET | BTST | DIVS | DIVU | MULS | MULU => + if DR_IN_USE = '1' then + NEXT_FETCH_STATE <= SWITCH_STATE; + else + NEXT_FETCH_STATE <= INIT_EXEC_WB; + end if; + when ADDA | CMPA | SUBA => + if BIW_0(11 downto 9) = BIW_0(2 downto 0) and ADR_MODE_I = "011" then + NEXT_FETCH_STATE <= SWITCH_STATE; -- Postincrement (Ax)+, AX; wait before loading the ALU. + else + NEXT_FETCH_STATE <= INIT_EXEC_WB; + end if; + when MOVE => + if BIW_0(8 downto 6) = "100" and ADR_MODE_I = "011" then -- (An)+,-(An). + NEXT_FETCH_STATE <= SWITCH_STATE; + else + NEXT_FETCH_STATE <= INIT_EXEC_WB; + end if; + when others => + NEXT_FETCH_STATE <= INIT_EXEC_WB; + end case; + else + NEXT_FETCH_STATE <= FETCH_OPERAND; + end if; + when SWITCH_STATE => -- This state is used individually by several operations. + case OP is + when ADDA | CMPA | SUBA | MOVEA => -- Address register operations. + if AR_IN_USE = '0' then + NEXT_FETCH_STATE <= INIT_EXEC_WB; + else + NEXT_FETCH_STATE <= SWITCH_STATE; + end if; + when LEA | LINK | MOVE => + -- LEA: calculate effective address (1 clock cycle) load it in INIT_EXEC_WB. + -- LINK: used to load the decremented stack pointer. + -- MOVE: Used for (An)+,-(An). address mode. + NEXT_FETCH_STATE <= INIT_EXEC_WB; + when UNLK => -- SP is updated here. + NEXT_FETCH_STATE <= CALC_AEFF; + when MOVEM => -- MOVEM requires 1 CLK cycle for address calculation. + if MOVEM_COND = false then + NEXT_FETCH_STATE <= INIT_EXEC_WB; -- Cancel bus access. + else + NEXT_FETCH_STATE <= CALC_AEFF; + end if; + when MOVEP => -- Register select and displacement update. + if DR_IN_USE = '0' and BIW_0(7 downto 6) < "10" then + NEXT_FETCH_STATE <= CALC_AEFF; + elsif DR_IN_USE = '0' and ALU_BSY = '0' then -- ASH. + NEXT_FETCH_STATE <= INIT_EXEC_WB; -- Register to memory. + else + NEXT_FETCH_STATE <= SWITCH_STATE; + end if; + when PEA => + -- PEA requires two clock cycles here for effective adress calculation because it + -- is loaded early. The first clock cycle the address becomes valid and after the + -- second the address is loaded to the ALU for writing on the stack. + if PHASE2 = false then + NEXT_FETCH_STATE <= SWITCH_STATE; + else + NEXT_FETCH_STATE <= INIT_EXEC_WB; + end if; + when others => -- Data register operations. + if DR_IN_USE = '0' then + NEXT_FETCH_STATE <= INIT_EXEC_WB; + else + NEXT_FETCH_STATE <= SWITCH_STATE; + end if; + end case; + when INIT_EXEC_WB => + case OP is + when ANDI_TO_SR | EORI_TO_SR | MOVE_TO_SR | ORI_TO_SR => + if ALU_BSY = '0' and BRANCH_ATN = '1' then + NEXT_FETCH_STATE <= SLEEP; -- Wait for new processor context. + elsif ALU_BSY = '0' then + NEXT_FETCH_STATE <= START_OP; -- Proceed normally. + else + NEXT_FETCH_STATE <= INIT_EXEC_WB; + end if; + when Bcc | CHK | DBcc | JMP | TRAPV => + if ALU_BSY = '0' then + NEXT_FETCH_STATE <= SLEEP; + else + NEXT_FETCH_STATE <= INIT_EXEC_WB; + end if; + when JSR | MOVEC | TAS => + -- TAS provides a RMC operation so have to sleep a little bit ;-) + if ALU_BSY = '0' then + NEXT_FETCH_STATE <= SLEEP; + else + NEXT_FETCH_STATE <= INIT_EXEC_WB; + end if; + when BRA | BSR | RTD | RTS => + if ALU_BSY = '0' then + NEXT_FETCH_STATE <= START_OP; + else + NEXT_FETCH_STATE <= INIT_EXEC_WB; + end if; + when CMPM => + if ALU_BSY = '0' and PHASE2 = false then + NEXT_FETCH_STATE <= FETCH_OPERAND; -- Second compare required? + elsif ALU_BSY = '0' then -- ASH. + NEXT_FETCH_STATE <= START_OP; + else + NEXT_FETCH_STATE <= INIT_EXEC_WB; + end if; + when MOVE_USP => + if ALU_BSY = '0' and BIW_0(3) = '0' then -- An to USP. + NEXT_FETCH_STATE <= SLEEP; + elsif ALU_BSY = '0' then + NEXT_FETCH_STATE <= START_OP; -- USP to An. + else + NEXT_FETCH_STATE <= INIT_EXEC_WB; + end if; + when MOVE => + if ALU_BSY = '0' and PHASE2 = false then -- Load the Operand into the ALU here. + case BIW_0(8 downto 6) is -- Destination operand. + when "101" => + NEXT_FETCH_STATE <= FETCH_DISPL; + when "110" => + NEXT_FETCH_STATE <= FETCH_EXWORD_1; + when "111" => + if BIW_0(11 downto 9) = "000" then + NEXT_FETCH_STATE <= FETCH_ABS_LO; + else + NEXT_FETCH_STATE <= FETCH_ABS_HI; + end if; + when others => -- No destination address calculation required. + NEXT_FETCH_STATE <= START_OP; + end case; + elsif PHASE2 = true then -- ALU is not required at this point. + NEXT_FETCH_STATE <= START_OP; + else + NEXT_FETCH_STATE <= INIT_EXEC_WB; + end if; + when MOVEM => + if ALU_BSY = '0' and BIW_0(10) = '0' and ADR_MODE_I = "100" and MOVEM_PNTR = x"0" then -- -(An), register to memory. + NEXT_FETCH_STATE <= SLEEP; -- Data completely transfered to the ALU. + elsif ALU_BSY = '0' and BIW_0(10) = '0' and ADR_MODE_I /= "100" and MOVEM_PNTR = x"F" then -- Register to memory + NEXT_FETCH_STATE <= SLEEP; -- Data completely transfered to the ALU. + elsif ALU_BSY = '0' and BIW_0(10) = '1' and MOVEM_PNTR = x"F" then -- Memory to register. + NEXT_FETCH_STATE <= SLEEP; -- Data completely transfered to the ALU. + elsif ALU_BSY = '0' and BIW_0(10) = '1' then -- Memory to register. + NEXT_FETCH_STATE <= SWITCH_STATE; + else + NEXT_FETCH_STATE <= INIT_EXEC_WB; -- Register to memory. + end if; + when MOVEP => + if ALU_BSY = '0' and MOVEP_PNTR_I = 0 then + NEXT_FETCH_STATE <= START_OP; -- Ready. + elsif ALU_BSY = '0' and BIW_0(7 downto 6) < "10" then + NEXT_FETCH_STATE <= CALC_AEFF; -- Memory to register. + else + NEXT_FETCH_STATE <= INIT_EXEC_WB; -- Register to memory. + end if; + when NOP => + if ALU_BSY = '1' then -- ASH. + NEXT_FETCH_STATE <= INIT_EXEC_WB; -- Wait for all pending bus cycles to be completed. + else + NEXT_FETCH_STATE <= START_OP; + end if; + when RTR => + if ALU_BSY = '0' and PHASE2 = false then + NEXT_FETCH_STATE <= CALC_AEFF; + elsif ALU_BSY = '0' and PHASE2 = true then + NEXT_FETCH_STATE <= START_OP; + else + NEXT_FETCH_STATE <= INIT_EXEC_WB; + end if; + when STOP => + if ALU_BSY = '0' then -- ASH. + NEXT_FETCH_STATE <= SLEEP; + else + NEXT_FETCH_STATE <= INIT_EXEC_WB; + end if; + when UNLK => + if ALU_BSY = '0' and AR_IN_USE = '0' then -- ADH, ASH. + NEXT_FETCH_STATE <= START_OP; + else + NEXT_FETCH_STATE <= INIT_EXEC_WB; + end if; + when others => + if ALU_BSY = '0' then -- ASH. + NEXT_FETCH_STATE <= START_OP; + else + NEXT_FETCH_STATE <= INIT_EXEC_WB; -- ASH. + end if; + end case; + when SLEEP => + case OP is + when ANDI_TO_SR | EORI_TO_SR | MOVE_TO_SR | MOVEM | ORI_TO_SR | TAS => + -- MOVEM: wait until last register is written to avoid data hazards + -- because the ADR_IN_USE, AR_IN__USE and DR_IN_USE does not + -- work for MOVEM (several registers in use). + -- TAS is a read modify write instruction. + -- _TO_SR instructions wait for the change of the SBIT + -- and so for a new processor context. + if NEXT_EXEC_WB_STATE = IDLE then + NEXT_FETCH_STATE <= START_OP; + else + NEXT_FETCH_STATE <= SLEEP; + end if; + when JSR => + if PHASE2 = false then + NEXT_FETCH_STATE <= SLEEP; -- Wait for address calculation. + else + NEXT_FETCH_STATE <= START_OP; + end if; + when MOVE_USP | MOVEC => + -- MOVE_USP: wait for writeback not to conflict with AR_DEC in START_OP. + if NEXT_EXEC_WB_STATE = IDLE then + NEXT_FETCH_STATE <= START_OP; + else + NEXT_FETCH_STATE <= SLEEP; -- Wait for new processor context. + end if; + when DBcc => + -- DBcc: evaluate conditions. + if NEXT_EXEC_WB_STATE = IDLE then + NEXT_FETCH_STATE <= START_OP; + else + NEXT_FETCH_STATE <= SLEEP; + end if; + when STOP => + if TRACE_EN = '1' then + NEXT_FETCH_STATE <= START_OP; -- Do not perform a stop while tracing. + elsif EXH_REQ = '1' then + NEXT_FETCH_STATE <= START_OP; -- Wait on interrupt. + else + NEXT_FETCH_STATE <= SLEEP; + end if; + when others => -- Bcc, CHK, JMP, TRAPV. + -- Bcc: evaluate conditions. + -- CHK: use SWITCH_STATE for TRAP evaluation. + -- JMP: wait for address calculation. + -- TRAPV: check conditions. + NEXT_FETCH_STATE <= START_OP; + end case; + end case; + end process FETCH_DEC; + + EXEC_WB_DEC: process(ALU_COND, ALU_INIT_I, ALU_REQ, BIW_0_WB, BIW_1_WB, EXEC_WB_STATE, MOVEM_INH_WR, OP_WB_I, PHASE2, WR_RDY) + begin + case EXEC_WB_STATE is + when IDLE => -- OP is still valid here; OP_WB_I one clock later. + if ALU_INIT_I = '1' then + NEXT_EXEC_WB_STATE <= EXECUTE; + else + NEXT_EXEC_WB_STATE <= IDLE; + end if; + when EXECUTE => + if ALU_REQ = '1' then + case OP_WB_I is + when ABCD | SBCD | ADDX | SUBX => + if BIW_0_WB(3) = '0' then -- Register to register. + NEXT_EXEC_WB_STATE <= WRITEBACK; + else -- Memory to memory. + NEXT_EXEC_WB_STATE <= WRITE_DEST; + end if; + when ADD | SUB | AND_B | OR_B => + if BIW_0_WB(8) = '0' then + NEXT_EXEC_WB_STATE <= WRITEBACK; -- Destination is register. + else + NEXT_EXEC_WB_STATE <= WRITE_DEST; -- Destination is in memory. + end if; + when ADDA | SUBA | ANDI_TO_SR | DIVS | DIVU | EORI_TO_SR | EXG | EXT | LEA | MOVE_TO_CCR | + MOVE_TO_SR | MOVE_USP | MOVEA | MOVEC | MOVEQ | MULS | MULU | ORI_TO_SR | STOP | SWAP | UNLK => + NEXT_EXEC_WB_STATE <= WRITEBACK; + when ADDI | ADDQ | ANDI | BCHG | BCLR | BSET | CLR | EOR | EORI | + MOVE_FROM_CCR | MOVE_FROM_SR | NBCD | NEG | NEGX | NOT_B | ORI | Scc | SUBI | SUBQ | TAS => + if BIW_0_WB(5 downto 3) = "000" then + NEXT_EXEC_WB_STATE <= WRITEBACK; -- Destination is a data register. + elsif BIW_0_WB(5 downto 3) = "001" then -- Valid for ADDQ and SUBQ. + NEXT_EXEC_WB_STATE <= WRITEBACK; -- Destination is an address register. + else + NEXT_EXEC_WB_STATE <= WRITE_DEST; -- Destination is in memory. + end if; + when ASL | ASR | LSL | LSR | ROTL | ROTR | ROXL | ROXR => + if BIW_0_WB(7 downto 6) /= "11" then + NEXT_EXEC_WB_STATE <= WRITEBACK; -- Register shifts. + else + NEXT_EXEC_WB_STATE <= WRITE_DEST; -- Memory shifts. + end if; + when DBcc => + if ALU_COND = true then + NEXT_EXEC_WB_STATE <= IDLE; + else + NEXT_EXEC_WB_STATE <= WRITEBACK; + end if; + when MOVE => + if BIW_0_WB(8 downto 6) = "000" then + NEXT_EXEC_WB_STATE <= WRITEBACK; -- Destination is register. + elsif PHASE2 = false then + NEXT_EXEC_WB_STATE <= WRITE_DEST; -- Destination is in memory. + else + NEXT_EXEC_WB_STATE <= EXECUTE; -- Wait for PHASE2 address calculation. + end if; + when BSR | JSR | LINK | PEA => + NEXT_EXEC_WB_STATE <= WRITE_DEST; + when MOVEM => + if OP_WB_I = MOVEM and MOVEM_INH_WR = true then + NEXT_EXEC_WB_STATE <= IDLE; -- Discard the write cycle. + elsif BIW_0_WB(10) = '1' then + NEXT_EXEC_WB_STATE <= WRITEBACK; -- Destination is register. + else + NEXT_EXEC_WB_STATE <= WRITE_DEST; -- Destination is in memory. + end if; + when MOVEP => + if BIW_0_WB(7 downto 6) < "10" then + NEXT_EXEC_WB_STATE <= WRITEBACK; -- Memory to register. + else + NEXT_EXEC_WB_STATE <= WRITE_DEST; -- Register to memory. + end if; + when MOVES => + if BIW_1_WB(11) = '0' then + NEXT_EXEC_WB_STATE <= WRITEBACK; -- Destination is register. + else + NEXT_EXEC_WB_STATE <= WRITE_DEST; -- Destination is in memory. + end if; + -- Default is for: + -- ANDI_TO_CCR, Bcc, CHK, CMP, CMPA, CMPI, CMPM + -- EORI_TO_CCR, ORI_TO_CCR, RTR, TRAPV, TST. + when others => + NEXT_EXEC_WB_STATE <= IDLE; + end case; + else + NEXT_EXEC_WB_STATE <= EXECUTE; + end if; + when WRITEBACK => + NEXT_EXEC_WB_STATE <= IDLE; + when WRITE_DEST => + if WR_RDY = '1' then + NEXT_EXEC_WB_STATE <= IDLE; + else + NEXT_EXEC_WB_STATE <= WRITE_DEST; + end if; + end case; + end process EXEC_WB_DEC; +end BEHAVIOUR; diff --git a/common/CPU/68K10/wf68k10_data_registers.vhd b/common/CPU/68K10/wf68k10_data_registers.vhd new file mode 100644 index 00000000..0825ed7b --- /dev/null +++ b/common/CPU/68K10/wf68k10_data_registers.vhd @@ -0,0 +1,137 @@ +------------------------------------------------------------------------ +---- ---- +---- WF68K10 IP Core: Data register logic. ---- +---- ---- +---- Description: ---- +---- These are the eight data registers. The logic provides two ---- +---- read and two write ports providing simultaneos access. For ---- +---- more information refer to the MC68010 User' Manual. ---- +---- ---- +---- Author(s): ---- +---- - Wolfgang Foerster, wf@experiment-s.de; wf@inventronik.de ---- +---- ---- +------------------------------------------------------------------------ +---- ---- +---- Copyright 2014-2019 Wolfgang Foerster Inventronik GmbH. ---- +---- ---- +---- This documentation describes Open Hardware and is licensed ---- +---- under the CERN OHL v. 1.2. You may redistribute and modify ---- +---- this documentation under the terms of the CERN OHL v.1.2. ---- +---- (http://ohwr.org/cernohl). This documentation is distributed ---- +---- WITHOUT ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING OF ---- +---- MERCHANTABILITY, SATISFACTORY QUALITY AND FITNESS FOR A ---- +---- PARTICULAR PURPOSE. Please see the CERN OHL v.1.2 for ---- +---- applicable conditions ---- +---- ---- +------------------------------------------------------------------------ +-- +-- Revision History +-- +-- Revision 2K14B 20141201 WF +-- Initial Release. +-- + +library work; +use work.WF68K10_PKG.all; + +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_unsigned.all; + +entity WF68K10_DATA_REGISTERS is + port ( + CLK : in std_logic; + RESET : in bit; + + -- Data lines: + DR_IN_1 : in std_logic_vector(31 downto 0); + DR_IN_2 : in std_logic_vector(31 downto 0); + DR_OUT_1 : out std_logic_vector(31 downto 0); + DR_OUT_2 : out std_logic_vector(31 downto 0); + + -- Registers controls: + DR_SEL_WR_1 : in std_logic_vector(2 downto 0); + DR_SEL_WR_2 : in std_logic_vector(2 downto 0); + DR_SEL_RD_1 : in std_logic_vector(2 downto 0); + DR_SEL_RD_2 : in std_logic_vector(2 downto 0); + DR_WR_1 : in bit; + DR_WR_2 : in bit; + DR_MARK_USED : in bit; + USE_DPAIR : in boolean; + DR_IN_USE : out bit; + UNMARK : in bit; + + OP_SIZE : in OP_SIZETYPE + ); +end entity WF68K10_DATA_REGISTERS; + +architecture BEHAVIOUR of WF68K10_DATA_REGISTERS is +type DR_TYPE is array(0 to 7) of std_logic_vector(31 downto 0); +signal DR : DR_TYPE; -- Data registers D0 to D7. +signal DR_PNTR_WR_1 : integer range 0 to 7; +signal DR_PNTR_WR_2 : integer range 0 to 7; +signal DR_PNTR_RD_1 : integer range 0 to 7; +signal DR_PNTR_RD_2 : integer range 0 to 7; +signal DR_SEL_WR_I1 : std_logic_vector(2 downto 0); +signal DR_SEL_WR_I2 : std_logic_vector(2 downto 0); +signal DR_USED_1 : std_logic_vector(3 downto 0); +signal DR_USED_2 : std_logic_vector(3 downto 0); +begin + INBUFFER: process + begin + wait until CLK = '1' and CLK' event; + if DR_MARK_USED = '1' then + DR_SEL_WR_I1 <= DR_SEL_WR_1; + DR_SEL_WR_I2 <= DR_SEL_WR_2; + end if; + end process INBUFFER; + + DR_PNTR_WR_1 <= conv_integer(DR_SEL_WR_I1); + DR_PNTR_WR_2 <= conv_integer(DR_SEL_WR_I2); + DR_PNTR_RD_1 <= conv_integer(DR_SEL_RD_1); + DR_PNTR_RD_2 <= conv_integer(DR_SEL_RD_2); + + P_IN_USE: process + begin + wait until CLK = '1' and CLK' event; + if RESET = '1' or UNMARK = '1' then + DR_USED_1(3) <= '0'; + DR_USED_2(3) <= '0'; + elsif DR_MARK_USED = '1' then + DR_USED_1 <= '1' & DR_SEL_WR_1; + if USE_DPAIR = true then + DR_USED_2 <= '1' & DR_SEL_WR_2; + end if; + end if; + end process P_IN_USE; + + DR_IN_USE <= '1' when DR_USED_1(3) = '1' and DR_USED_1(2 downto 0) = DR_SEL_RD_1 else + '1' when DR_USED_1(3) = '1' and DR_USED_1(2 downto 0) = DR_SEL_RD_2 else + '1' when DR_USED_2(3) = '1' and DR_USED_2(2 downto 0) = DR_SEL_RD_1 else + '1' when DR_USED_2(3) = '1' and DR_USED_2(2 downto 0) = DR_SEL_RD_2 else '0'; + + DR_OUT_1 <= DR(DR_PNTR_RD_1); + DR_OUT_2 <= DR(DR_PNTR_RD_2); + + REGISTERS: process + begin + wait until CLK = '1' and CLK' event; + if RESET = '1' then + DR <= (others => (others => '0')); + end if; + if DR_WR_1 = '1' then + case OP_SIZE is + when LONG => DR(DR_PNTR_WR_1) <= DR_IN_1; + when WORD => DR(DR_PNTR_WR_1)(15 downto 0) <= DR_IN_1(15 downto 0); + when Byte => DR(DR_PNTR_WR_1)(7 downto 0) <= DR_IN_1(7 downto 0); + end case; + end if; + if DR_WR_2 = '1' then + case OP_SIZE is + when LONG => DR(DR_PNTR_WR_2) <= DR_IN_2; + when WORD => DR(DR_PNTR_WR_2)(15 downto 0) <= DR_IN_2(15 downto 0); + when Byte => DR(DR_PNTR_WR_2)(7 downto 0) <= DR_IN_2(7 downto 0); + end case; + end if; + end process REGISTERS; +end BEHAVIOUR; diff --git a/common/CPU/68K10/wf68k10_exception_handler.vhd b/common/CPU/68K10/wf68k10_exception_handler.vhd new file mode 100644 index 00000000..25d5f913 --- /dev/null +++ b/common/CPU/68K10/wf68k10_exception_handler.vhd @@ -0,0 +1,818 @@ +------------------------------------------------------------------------ +---- ---- +---- WF68K10 IP Core: this is the exception handler module. ---- +---- ---- +---- Description: ---- +---- This is the exception handler which is responsible for the ---- +---- interrupt management of the external interrupt and internal ---- +---- exception processing. It manages auto-vectored interrupt ---- +---- cycles, priority resolving and correct vector numbers. ---- +---- For further information concerning the functionality of this ---- +---- module refer to the MC68010 User's Manual and to the MC68K ---- +---- family Programmer's Reference Manual. ---- +---- ---- +---- ---- +---- Author(s): ---- +---- - Wolfgang Foerster, wf@experiment-s.de; wf@inventronik.de ---- +---- ---- +------------------------------------------------------------------------ +---- ---- +---- Copyright © 2014-2019 Wolfgang Foerster Inventronik GmbH. ---- +---- ---- +---- This documentation describes Open Hardware and is licensed ---- +---- under the CERN OHL v. 1.2. You may redistribute and modify ---- +---- this documentation under the terms of the CERN OHL v.1.2. ---- +---- (http://ohwr.org/cernohl). This documentation is distributed ---- +---- WITHOUT ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING OF ---- +---- MERCHANTABILITY, SATISFACTORY QUALITY AND FITNESS FOR A ---- +---- PARTICULAR PURPOSE. Please see the CERN OHL v.1.2 for ---- +---- applicable conditions ---- +---- ---- +------------------------------------------------------------------------ +-- +-- Revision History +-- +-- Revision 2K14B 20141201 WF +-- Initial Release. +-- Revision 2K16A 20141201 WF +-- Fixed a bug in PC_LOAD. +-- Revision 2K18A (unreleased) WF +-- Removed REST_BIW_0. +-- Removed FC_OUT. +-- Removed ADR_CPY. +-- Removed PC_OFFSET. +-- Fixed the vector calculation of INT vectors. +-- Fixed faulty modeling in IRQ_FILTER. +-- Implemented the AVEC_FILTER to better meet bus timings. +-- STACK_POS_VAR is initialized earlier to be valid for early asserted ISP_DEC. +-- Update the IRQ mask only for RESET and interrupts. +-- External interrupts are postponed if any system controllers are in initialize operation status. +-- RTE now loads the address offset correctly when entering the handler. +-- Rearranged address error handling. +-- Revision 2K19B 20191224 WF +-- Introduced signal synchronization in the P_D process to avoid malfunction by hazards. +-- The processor VERSION is now 32 bit wide. +-- + +library work; +use work.WF68K10_PKG.all; + +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_unsigned.all; + +entity WF68K10_EXCEPTION_HANDLER is + generic(VERSION : std_logic_vector(31 downto 0) := x"20191224"); + port( + CLK : in std_logic; + RESET : in bit; + K6800n : in std_logic; + + BUSY_MAIN : in bit; + BUSY_OPD : in bit; + + EXH_REQ : out bit; + BUSY_EXH : out bit; + + ADR_IN : in std_logic_vector(31 downto 0); + ADR_OFFSET : out std_logic_vector(31 downto 0); + CPU_SPACE : out bit; + + DATA_0 : in std_logic; + DATA_RD : out bit; + DATA_WR : out bit; + DATA_IN : in std_logic_vector(31 downto 0); + + OP_SIZE : out OP_SIZETYPE; -- Operand size. + DATA_RDY : in bit; + DATA_VALID : in std_logic; + + OPCODE_RDY : in bit; -- OPCODE is available. + + STATUS_REG_IN : in std_logic_vector(15 downto 0); + SR_CPY : out std_logic_vector(15 downto 0); + SR_INIT : out bit; + SR_WR : out bit; + + ISP_DEC : out bit; + ISP_LOAD : out bit; + PC_INC : out bit; + PC_LOAD : out bit; + PC_RESTORE : out bit; + + STACK_FORMAT : out std_logic_vector(3 downto 0); + STACK_POS : out integer range 0 to 31; + + SP_ADD_DISPL : out bit; + DISPLACEMENT : out std_logic_vector(7 downto 0); + + IPIPE_FILL : out bit; + IPIPE_FLUSH : out bit; + RESTORE_ISP_PC : out bit; + + HALT_OUTn : out std_logic; + + -- Interrupt controls: + INT_TRIG : in bit; + IRQ_IN : in std_logic_vector(2 downto 0); + IRQ_PEND : out std_logic_vector(2 downto 0); + AVECn : in std_logic; + IPENDn : out bit; + IVECT_OFFS : out std_logic_vector(9 downto 0); -- Interrupt vector offset. + + -- Trap signals: + TRAP_AERR : in bit; + TRAP_BERR : in bit; + TRAP_CHK : in bit; + TRAP_DIVZERO : in bit; + TRAP_ILLEGAL : in bit; + TRAP_CODE_OPC : in TRAPTYPE_OPC; -- T_1010, T_1111, T_ILLEGAL, T_TRAP, T_PRIV. + TRAP_VECTOR : in std_logic_vector(3 downto 0); + TRAP_V : in bit; + EX_TRACE_IN : in bit; + VBR_WR : in bit; + VBR : out std_logic_vector(31 downto 0) + ); +end entity WF68K10_EXCEPTION_HANDLER; + +architecture BEHAVIOR of WF68K10_EXCEPTION_HANDLER is +type EX_STATES is (IDLE, BUILD_STACK, CALC_VECT_No, EXAMINE_VERSION, GET_VECTOR, HALTED, INIT, READ_BOTTOM, + REFILL_PIPE, RESTORE_ISP, RESTORE_PC, RESTORE_STATUS, UPDATE_PC, VALIDATE_FRAME); + +type EXCEPTIONS is (EX_NONE, EX_1010, EX_1111, EX_AERR, EX_BERR, EX_CHK, EX_DIVZERO, EX_FORMAT, EX_ILLEGAL, + EX_INT, EX_PRIV, EX_RESET, EX_RTE, EX_TRACE, EX_TRAP, EX_TRAPV); + +signal ACCESS_ERR : bit; +signal AVEC : bit; +signal DATA_RD_I : bit; +signal DATA_WR_I : bit; +signal DOUBLE_BUSFLT : bit; +signal EXCEPTION : EXCEPTIONS; -- Currently executed exception. +signal EX_STATE : EX_STATES := IDLE; +signal NEXT_EX_STATE : EX_STATES; +signal EX_P_1010 : bit; -- ..._P are the pending exceptions. +signal EX_P_1111 : bit; +signal EX_P_AERR : bit; +signal EX_P_BERR : bit; +signal EX_P_CHK : bit; +signal EX_P_DIVZERO : bit; +signal EX_P_FORMAT : bit; +signal EX_P_ILLEGAL : bit; +signal EX_P_INT : bit; +signal EX_P_RESET : bit; +signal EX_P_RTE : bit; +signal EX_P_PRIV : bit; +signal EX_P_TRACE : bit; +signal EX_P_TRAP : bit; +signal EX_P_TRAPV : bit; +signal INT_VECT : std_logic_vector(31 downto 0); -- Interrupt vector. +signal IRQ : std_logic_vector(2 downto 0); +signal IRQ_PEND_I : std_logic_vector(2 downto 0); +signal PIPE_CNT : std_logic_vector(1 downto 0); +signal PIPE_FULL : boolean; +signal STACK_CNT : integer range 0 to 46; +signal STACK_FORMAT_I : std_logic_vector(3 downto 0); +signal SYS_INIT : bit; +begin + + BUSY_EXH <= '1' when EX_STATE /= IDLE else '0'; + + IRQ_FILTER : process + -- This logic is intended to avoid spurious IRQs due + -- to setup / hold violations (IRQ_IN may operate in + -- a different clock domain). + variable IRQ_TMP_1 : std_logic_vector(2 downto 0) := "000"; + variable IRQ_TMP_2 : std_logic_vector(2 downto 0) := "000"; + begin + wait until CLK = '0' and CLK' event; + if IRQ_TMP_1 = IRQ_TMP_2 then + IRQ <= IRQ_TMP_2; + end if; + IRQ_TMP_2 := IRQ_TMP_1; + IRQ_TMP_1 := IRQ_IN; + end process IRQ_FILTER; + + AVEC_FILTER : process + -- We need a flip flop for the incoming AVECn to meet + -- the timing requirements of the bus interface. AVECn + -- is asserted (low active) before DATA_RDY of the + -- bus interface. AVEC stays asserted until DATA_RDY. + begin + wait until CLK = '1' and CLK' event; + if AVECn = '0' then + AVEC <= '1'; + elsif DATA_RDY = '1' or RESET = '1' then + AVEC <= '0'; + end if; + end process AVEC_FILTER; + + PENDING: process + -- The exceptions which occurs are stored in this pending register until the + -- interrupt handler handled the respective exception. + -- The TRAP_PRIV, TRAP_1010, TRAP_1111, TRAP_ILLEGAL, TRAP_OP and TRAP_V may be a strobe + -- of 1 clock period. All others must be strobes of 1 clock period.. + variable INT7_TRIG : boolean; + variable INT_VAR : std_logic_vector(2 downto 0); + variable SR_VAR : std_logic_vector(2 downto 0); + begin + wait until CLK = '1' and CLK' event; + if RESET = '1' then + EX_P_RESET <= '1'; + elsif EX_STATE = RESTORE_PC and DATA_RDY = '1' and EXCEPTION = EX_RESET then + EX_P_RESET <= '0'; + end if; + -- + if TRAP_BERR = '1' then + EX_P_BERR <= '1'; + elsif EX_STATE /= IDLE and DATA_RDY = '1' and DATA_VALID = '0' then + EX_P_BERR <= '1'; + elsif EX_STATE = INIT and EXCEPTION = EX_BERR then + EX_P_BERR <= '0'; -- Reset in the beginning to enable retriggering. + elsif SYS_INIT = '1' then + EX_P_BERR <= '0'; + end if; + -- + if TRAP_AERR = '1' then + EX_P_AERR <= '1'; + elsif EX_STATE = BUILD_STACK and EXCEPTION = EX_AERR then + EX_P_AERR <= '0'; + elsif SYS_INIT = '1' then + EX_P_AERR <= '0'; + end if; + -- + if EX_TRACE_IN = '1' then + EX_P_TRACE <= '1'; + elsif EX_STATE = BUILD_STACK and EXCEPTION = EX_TRACE then + EX_P_TRACE <= '0'; + elsif SYS_INIT = '1' then + EX_P_TRACE <= '0'; + end if; + -- + if IRQ = "111" and SR_VAR = "111" and STATUS_REG_IN(10 downto 8) /= "111" then + INT7_TRIG := true; -- Trigger by lowering the mask from 7 to any value. + elsif IRQ = "111" and INT_VAR < "111" then + INT7_TRIG := true; -- Trigger when level 7 is entered. + else + INT7_TRIG := false; + end if; + -- + SR_VAR := STATUS_REG_IN(10 downto 8); -- Update after use! + INT_VAR := IRQ; -- Update after use! + -- + if SYS_INIT = '1' then -- Reset when disabling the interrupts. + EX_P_INT <= '0'; + IRQ_PEND_I <= "111"; -- This is required for system startup. + elsif EX_STATE = GET_VECTOR and DATA_RDY = '1' then + EX_P_INT <= '0'; + elsif INT7_TRIG = true then -- Level 7 is nonmaskable ... + EX_P_INT <= '1'; + IRQ_PEND_I <= IRQ; + elsif INT_TRIG = '1' and STATUS_REG_IN(10 downto 8) < IRQ then + EX_P_INT <= '1'; + IRQ_PEND_I <= IRQ; + end if; + -- + -- The following nine traps never appear at the same time: + if TRAP_CHK = '1' then + EX_P_CHK <= '1'; + elsif TRAP_DIVZERO = '1' then + EX_P_DIVZERO <= '1'; + elsif TRAP_CODE_OPC = T_TRAP then + EX_P_TRAP <= '1'; + elsif TRAP_V = '1' then + EX_P_TRAPV <= '1'; + elsif TRAP_CODE_OPC = T_PRIV then + EX_P_PRIV <= '1'; + elsif TRAP_CODE_OPC = T_1010 then + EX_P_1010 <= '1'; + elsif TRAP_CODE_OPC = T_1111 then + EX_P_1111 <= '1'; + elsif TRAP_CODE_OPC = T_ILLEGAL then + EX_P_ILLEGAL <= '1'; + elsif TRAP_ILLEGAL = '1' then -- Used for BKPT. + EX_P_ILLEGAL <= '1'; + elsif EX_STATE = VALIDATE_FRAME and DATA_RDY = '1' and DATA_VALID = '1' and NEXT_EX_STATE = IDLE then + EX_P_FORMAT <= '1'; + elsif EX_STATE = EXAMINE_VERSION and DATA_RDY = '1' and DATA_VALID = '1' and NEXT_EX_STATE = IDLE then + EX_P_FORMAT <= '1'; + elsif TRAP_CODE_OPC = T_RTE then + EX_P_RTE <= '1'; + elsif EX_STATE = REFILL_PIPE and NEXT_EX_STATE /= REFILL_PIPE then -- Clear after IPIPE_FLUSH. + case EXCEPTION is + when EX_1010 | EX_1111 | EX_CHK | EX_DIVZERO | EX_ILLEGAL | EX_TRAP | EX_TRAPV | EX_FORMAT | EX_PRIV | EX_RTE => + EX_P_CHK <= '0'; + EX_P_DIVZERO <= '0'; + EX_P_PRIV <= '0'; + EX_P_1010 <= '0'; + EX_P_1111 <= '0'; + EX_P_ILLEGAL <= '0'; + EX_P_RTE <= '0'; + EX_P_TRAP <= '0'; + EX_P_TRAPV <= '0'; + EX_P_FORMAT <= '0'; + when others => + null; + end case; + -- Clear all possible traps during reset exception because the + -- signal EXCEPTION is not valid at this time: + elsif SYS_INIT = '1' then + EX_P_CHK <= '0'; + EX_P_DIVZERO <= '0'; + EX_P_PRIV <= '0'; + EX_P_1010 <= '0'; + EX_P_1111 <= '0'; + EX_P_ILLEGAL <= '0'; + EX_P_RTE <= '0'; + EX_P_TRAP <= '0'; + EX_P_TRAPV <= '0'; + EX_P_FORMAT <= '0'; + end if; + end process PENDING; + + ACCESS_ERR <= '1' when EX_STATE = RESTORE_PC and DATA_RDY = '1' and DATA_0 = '1' else -- Odd PC value. + '1' when DATA_RDY = '1' and DATA_VALID = '0' else '0'; -- Bus error. + + IRQ_PEND <= IRQ_PEND_I when EXCEPTION = EX_RESET or EXCEPTION = EX_INT else STATUS_REG_IN(10 downto 8); + IPENDn <= '0' when EX_P_INT = '1' or EX_P_RESET = '1' or EX_P_TRACE = '1' else '1'; + + -- This signal is asserted eraly to indicate the respective controller to stay in its idle state. + -- The exception is then inserted before a new operation has been loaded and processed. + EXH_REQ <= '0' when EX_STATE /= IDLE else + '1' when TRAP_CODE_OPC /= NONE else + '1' when (EX_P_RESET or EX_P_BERR or EX_P_AERR or EX_P_DIVZERO) = '1' else + '1' when (EX_P_CHK or EX_P_TRAPV or EX_P_TRACE or EX_P_FORMAT or EX_P_INT) = '1' else '0'; + + INT_VECTOR: process + -- This process provides the vector base register handling and + -- the interrupt vector number INT_VECT, which is determined + -- during interrupt processing. + variable VECT_No : std_logic_vector(9 downto 2) := "00000000"; + variable VB_REG : std_logic_vector(31 downto 0) := x"00000000"; + begin + wait until CLK = '1' and CLK' event; + if VBR_WR = '1' then + VB_REG := DATA_IN; + elsif SYS_INIT = '1' then + VB_REG := (others => '0'); + end if; + -- + if EX_STATE = CALC_VECT_No or EX_STATE = GET_VECTOR then + case EXCEPTION is + when EX_RESET => VECT_No := x"00"; + when EX_BERR => VECT_No := x"02"; + when EX_AERR => VECT_No := x"03"; + when EX_ILLEGAL => VECT_No := x"04"; + when EX_DIVZERO => VECT_No := x"05"; + when EX_CHK => VECT_No := x"06"; + when EX_TRAPV => VECT_No := x"07"; + when EX_PRIV => VECT_No := x"08"; + when EX_TRACE => VECT_No := x"09"; + when EX_1010 => VECT_No := x"0A"; + when EX_1111 => VECT_No := x"0B"; + when EX_FORMAT => VECT_No := x"0E"; + -- The uninitialized interrupt vector number x"0F" + -- is provided by the peripheral interrupt source + -- during the auto vector bus cycle. + when EX_INT => + if DATA_RDY = '1' and AVEC = '1' then + VECT_No := x"18" + IRQ_PEND_I; -- Autovector. + elsif DATA_RDY = '1' and DATA_VALID = '0' then + VECT_No := x"18"; -- Spurious interrupt. + elsif DATA_RDY = '1' then + -- This is the vector number provided by the device. + -- If the returned VECT_No is x"0F" then it is the + -- uninitialized interrupt vector due to non initia- + -- lized vector register of the peripheral device. + VECT_No := DATA_IN(7 downto 0); -- Non autovector. + end if; + when EX_TRAP => VECT_No := x"2" & TRAP_VECTOR; + when others => VECT_No := (others => '-'); -- Don't care. + end case; + end if; + -- + INT_VECT <= VB_REG + (VECT_No & "00"); + VBR <= VB_REG; + IVECT_OFFS <= VECT_No & "00"; + end process INT_VECTOR; + + STORE_CURRENT_EXCEPTION: process + -- The exceptions which occurs are stored in the following flags until the + -- interrupt handler handled the respective exception. + -- This process also stores the current processed exception for further use. + -- The update takes place in the IDLE EX_STATE. + begin + wait until CLK = '1' and CLK' event; + -- Priority level 0: + if EX_STATE = IDLE and EX_P_RESET = '1' then + EXCEPTION <= EX_RESET; + -- Priority level 1: + elsif EX_STATE = IDLE and EX_P_AERR = '1' then + EXCEPTION <= EX_AERR; + elsif EX_STATE = IDLE and EX_P_BERR = '1' then + EXCEPTION <= EX_BERR; + -- Priority level 2: + -- BREAKPOINT is part of the main controller. + elsif EX_STATE = IDLE and EX_P_CHK = '1' then + EXCEPTION <= EX_CHK; + elsif EX_STATE = IDLE and EX_P_DIVZERO = '1' then + EXCEPTION <= EX_DIVZERO; + elsif EX_STATE = IDLE and EX_P_TRAP = '1' then + EXCEPTION <= EX_TRAP; + elsif EX_STATE = IDLE and EX_P_TRAPV = '1' then + EXCEPTION <= EX_TRAPV; + elsif EX_STATE = IDLE and EX_P_FORMAT = '1' then + EXCEPTION <= EX_FORMAT; + -- Priority level 3: + elsif EX_STATE = IDLE and EX_P_ILLEGAL = '1' then + EXCEPTION <= EX_ILLEGAL; + elsif EX_STATE = IDLE and EX_P_RTE = '1' then + EXCEPTION <= EX_RTE; + elsif EX_STATE = IDLE and EX_P_1010 = '1' then + EXCEPTION <= EX_1010; + elsif EX_STATE = IDLE and EX_P_1111 = '1' then + EXCEPTION <= EX_1111; + elsif EX_STATE = IDLE and EX_P_PRIV = '1' then + EXCEPTION <= EX_PRIV; + elsif EX_STATE = IDLE and EX_P_TRACE = '1' then + EXCEPTION <= EX_TRACE; + elsif EX_STATE = IDLE and EX_P_INT = '1' then + EXCEPTION <= EX_INT; + elsif NEXT_EX_STATE = IDLE then + EXCEPTION <= EX_NONE; + end if; + end process STORE_CURRENT_EXCEPTION; + + CPU_SPACE <= '1' when NEXT_EX_STATE = GET_VECTOR else '0'; + + ADR_OFFSET <= x"000000" & "00000" & PIPE_CNT & '0' when EX_STATE = REFILL_PIPE else + x"00000004" when NEXT_EX_STATE = RESTORE_PC and EXCEPTION = EX_RESET else + x"00000002" when NEXT_EX_STATE = RESTORE_PC else + x"00000006" when NEXT_EX_STATE = VALIDATE_FRAME else + x"0000001A" when NEXT_EX_STATE = EXAMINE_VERSION else + x"0000001E" when NEXT_EX_STATE = READ_BOTTOM else + INT_VECT when NEXT_EX_STATE = UPDATE_PC else x"00000000"; -- Default is top of the stack (STATUS). + + OP_SIZE <= LONG when K6800n = '1' and EX_STATE = INIT and EXCEPTION /= EX_AERR and EXCEPTION /= EX_BERR else -- First access of AERR or BERR is WORD. + LONG when NEXT_EX_STATE = RESTORE_ISP or NEXT_EX_STATE = RESTORE_PC else + LONG when NEXT_EX_STATE = UPDATE_PC else + LONG when K6800n = '0' and NEXT_EX_STATE = BUILD_STACK and (STACK_CNT = 7 or STACK_CNT = 3) and DATA_RDY = '1' else -- Words 7 and 3 are word wide. + LONG when K6800n = '0' and NEXT_EX_STATE = BUILD_STACK and STACK_CNT /= 7 and STACK_CNT /= 3 else + LONG when K6800n = '1' and NEXT_EX_STATE = BUILD_STACK and STACK_CNT = 29 and DATA_RDY = '1' else -- Always long access, except word 29. + LONG when K6800n = '1' and NEXT_EX_STATE = BUILD_STACK and STACK_CNT /= 29 else + LONG when EX_STATE = UPDATE_PC or NEXT_EX_STATE = RESTORE_PC else + LONG when NEXT_EX_STATE = EXAMINE_VERSION else + BYTE when EX_STATE = GET_VECTOR and NEXT_EX_STATE = GET_VECTOR else WORD; + + DISPLACEMENT <= x"08" when STACK_FORMAT_I = x"0" and K6800n = '1' else -- 68K10. + x"3A" when STACK_FORMAT_I = x"8" and K6800n = '1' else -- 68K10. + x"06" when STACK_FORMAT_I = x"0" else x"0E"; -- 68K00. + + SP_ADD_DISPL <= '1' when EX_STATE = RESTORE_STATUS and DATA_RDY = '1' and DATA_VALID = '1' else '0'; + + P_D: process(CLK, DATA_RDY) + -- These flip flops are necessary to delay + -- the read and writes during BUILD_STACK + -- and restoring the system because the + -- address calculation in the address + -- section requires one clock. + -- Important note: to avoid asynchronous reset by data hazards the + -- resetting signal is synchronized on the negative clock edge. + variable DATA_RDY_VAR : bit; + begin + if CLK = '0' and CLK' event then + DATA_RDY_VAR := DATA_RDY; + end if; + -- + if DATA_RDY_VAR = '1' then + DATA_RD <= '0'; + elsif CLK = '1' and CLK' event then + DATA_RD <= DATA_RD_I; + end if; + + if DATA_RDY_VAR = '1' then + DATA_WR <= '0'; + elsif CLK = '1' and CLK' event then + DATA_WR <= DATA_WR_I; + end if; + end process P_D; + + DATA_RD_I <= '0' when DATA_RDY = '1' else + '1' when NEXT_EX_STATE = GET_VECTOR else + '1' when NEXT_EX_STATE = VALIDATE_FRAME else + '1' when NEXT_EX_STATE = EXAMINE_VERSION else + '1' when NEXT_EX_STATE = READ_BOTTOM else + '1' when NEXT_EX_STATE = RESTORE_ISP else + '1' when NEXT_EX_STATE = RESTORE_STATUS else + '1' when NEXT_EX_STATE = UPDATE_PC else + '1' when NEXT_EX_STATE = RESTORE_PC else '0'; + + DATA_WR_I <= '0' when DATA_RDY = '1' else + '1' when EX_STATE = BUILD_STACK else '0'; + + ISP_LOAD <= '1' when EX_STATE = RESTORE_ISP and DATA_RDY = '1' and DATA_VALID = '1' else '0'; + PC_RESTORE <= '1' when EX_STATE = RESTORE_PC and DATA_RDY = '1' and DATA_VALID = '1' else '0'; + PC_LOAD <= '1' when EXCEPTION /= EX_RESET and EXCEPTION /= EX_RTE and EX_STATE /= REFILL_PIPE and NEXT_EX_STATE = REFILL_PIPE else '0'; + + IPIPE_FILL <= '1' when EX_STATE = REFILL_PIPE else '0'; + + -- This signal forces the PC logic in the address register section to calculate the address + -- of the next instruction. This address is written on the stack. For the following + -- instructions the old PC value is stacked: BERR, AERR, ILLEGAL, PRIV, TRACE, 1010, 1111, FORMAT. + PC_INC <= '1' when EXCEPTION = EX_CHK and EX_STATE /= BUILD_STACK and NEXT_EX_STATE = BUILD_STACK else + '1' when EXCEPTION = EX_DIVZERO and EX_STATE /= BUILD_STACK and NEXT_EX_STATE = BUILD_STACK else + '1' when EXCEPTION = EX_INT and EX_STATE /= BUILD_STACK and NEXT_EX_STATE = BUILD_STACK else + '1' when EXCEPTION = EX_TRAP and EX_STATE /= BUILD_STACK and NEXT_EX_STATE = BUILD_STACK else + '1' when EXCEPTION = EX_TRAPV and EX_STATE /= BUILD_STACK and NEXT_EX_STATE = BUILD_STACK else '0'; + + ISP_DEC <= '1' when EX_STATE = INIT and EXCEPTION /= EX_RESET and EXCEPTION /= EX_RTE else -- Early due to one clock cycle address calculation. + '1' when EX_STATE = BUILD_STACK and DATA_RDY = '1' and NEXT_EX_STATE = BUILD_STACK else '0'; + + SR_INIT <= '1' when EX_STATE = INIT else '0'; + SR_WR <= '1' when EX_STATE = RESTORE_STATUS and DATA_RDY = '1' and DATA_VALID = '1' else '0'; + + SYS_INIT <= '1' when EX_STATE = IDLE and EX_P_RESET = '1' else '0'; + + -- The processor gets halted, if a bus error occurs in the stacking or updating states during + -- the exception processing of a bus error, an address error or a reset. + HALT_OUTn <= '0' when EX_STATE = HALTED else '1'; + + RESTORE_ISP_PC <= '1' when EXCEPTION = EX_RESET and (NEXT_EX_STATE = RESTORE_ISP or EX_STATE = RESTORE_ISP) else + '1' when EXCEPTION = EX_RESET and (NEXT_EX_STATE = RESTORE_PC or EX_STATE = RESTORE_PC) else + '1' when NEXT_EX_STATE = UPDATE_PC else '0'; + + IPIPE_FLUSH <= '1' when EXCEPTION = EX_RESET and EX_STATE /= REFILL_PIPE else + '1' when EXCEPTION /= EX_NONE and EX_STATE /= REFILL_PIPE and NEXT_EX_STATE = REFILL_PIPE else '0'; + + DOUBLE_BUSFLT <= '1' when (EXCEPTION = EX_AERR or EXCEPTION = EX_RESET) and EX_STATE = RESTORE_PC and DATA_RDY = '1' and DATA_0 = '1' else -- Odd PC value. + '1' when EX_STATE /= IDLE and EXCEPTION = EX_AERR and DATA_RDY = '1' and DATA_VALID = '0' else + '1' when EX_STATE /= IDLE and EXCEPTION = EX_BERR and DATA_RDY = '1' and DATA_VALID = '0' else + '1' when EX_STATE /= IDLE and EXCEPTION = EX_RESET and DATA_RDY = '1' and DATA_VALID = '0' else '0'; + + P_TMP_CPY: process + -- These registers contain a copy of system relevant state information + -- which is necessary for restoring the exception. Copies are provided + -- for the status register, the program counter and the effective address. + begin + wait until CLK = '1' and CLK' event; + if EX_STATE = IDLE and NEXT_EX_STATE /= IDLE then + SR_CPY <= STATUS_REG_IN; + end if; + end process P_TMP_CPY; + + STACK_CTRL: process + -- This process controls the stacking of the data to the stack. Depending + -- on the stack frame format, the number of words written to the stack is + -- adjusted to long words. See the DATA_2_PORT multiplexer in the top level + -- file for more information. + variable STACK_POS_VAR : integer range 0 to 31 := 0; + begin + wait until CLK = '1' and CLK' event; + if EX_STATE /= BUILD_STACK and NEXT_EX_STATE = BUILD_STACK then + case EXCEPTION is + when EX_AERR | EX_BERR => + if K6800n = '0' then + STACK_POS_VAR := 7; -- 68K00 bus or address error stack format. + else + STACK_POS_VAR := 29; -- Format 8. + end if; + STACK_FORMAT_I <= x"8"; + when others => + if K6800n = '0' then + STACK_POS_VAR := 3; -- 68K00 3 word stack format. + else + STACK_POS_VAR := 4; -- Format 0. + end if; + STACK_FORMAT_I <= x"0"; + end case; + elsif EX_STATE = VALIDATE_FRAME and DATA_RDY = '1' and DATA_VALID = '1' then + STACK_FORMAT_I <= DATA_IN(15 downto 12); + elsif EX_STATE = BUILD_STACK and DATA_RDY = '1' then + case STACK_POS_VAR is + when 29 | 7 | 3 => STACK_POS_VAR := STACK_POS_VAR - 1; -- WORD access. + when others => STACK_POS_VAR := STACK_POS_VAR - 2; -- LONG access. + end case; + end if; + -- + STACK_CNT <= STACK_POS_VAR; + STACK_POS <= STACK_POS_VAR; + end process STACK_CTRL; + + STACK_FORMAT <= STACK_FORMAT_I; + + PIPE_STATUS: process + -- This logic detects the status of the + -- instruction pipe prefetch in the + -- REFILL_PIPE state. + variable CNT : std_logic_vector(1 downto 0); + begin + wait until CLK = '1' and CLK' event; + if EX_STATE /= REFILL_PIPE then + PIPE_FULL <= false; + CNT := "00"; + elsif EX_STATE = REFILL_PIPE and OPCODE_RDY = '1' and CNT < "10" then + CNT := CNT + '1'; + elsif EX_STATE = REFILL_PIPE and OPCODE_RDY = '1' then + PIPE_FULL <= true; + end if; + PIPE_CNT <= CNT; + end process PIPE_STATUS; + + EXCEPTION_HANDLER_REG: process + -- This is the register portion of the + -- exception control state machine. + begin + wait until CLK = '1' and CLK' event; + if RESET = '1' then + EX_STATE <= IDLE; + else + EX_STATE <= NEXT_EX_STATE; + end if; + end process EXCEPTION_HANDLER_REG; + + EXCEPTION_HANDLER_DEC: process(ACCESS_ERR, BUSY_MAIN, BUSY_OPD, DATA_IN, DATA_VALID, DOUBLE_BUSFLT, EX_STATE, EX_P_RESET, EX_P_AERR, EX_P_BERR, + EX_P_TRACE, EX_P_INT, EX_P_ILLEGAL, EX_P_1010, EX_P_RTE, EX_P_1111, EX_P_FORMAT, EX_P_PRIV, EX_P_TRAP, EX_P_TRAPV, + EX_P_CHK, EX_P_DIVZERO, EXCEPTION, DATA_RDY, PIPE_FULL, STACK_CNT, K6800n) + begin + case EX_STATE is + when IDLE => + -- The priority of the exception execution is given by the + -- following construct. Although type 3 commands do not require + -- a prioritization, there is no drawback using these conditions. + -- The spurious interrupt and uninitialized interrupt never appear + -- as basic interrupts and therefore are not an interrupt source. + -- During IDLE, when an interrupt occurs, the status register copy + -- control is asserted and the current interrupt controll is given + -- to the STORE_EXCEPTION process. During bus or address errors, + -- the status register must be copied immediately to recognize + -- the current status for RWn etc. (before the faulty bus cycle is + -- finished). + if (BUSY_MAIN = '1' or BUSY_OPD = '1') and EX_P_RESET = '0' then + NEXT_EX_STATE <= IDLE; -- Wait until the pipelined architecture is ready. + elsif EX_P_RESET = '1' or EX_P_AERR = '1' or EX_P_BERR = '1' then + NEXT_EX_STATE <= INIT; + elsif EX_P_TRAP = '1' or EX_P_TRAPV = '1' or EX_P_CHK = '1' or EX_P_DIVZERO = '1' then + NEXT_EX_STATE <= INIT; + elsif EX_P_FORMAT = '1' then + NEXT_EX_STATE <= INIT; + elsif EX_P_TRACE = '1' or EX_P_ILLEGAL = '1' or EX_P_1010 = '1' or EX_P_1111 = '1' or EX_P_PRIV = '1' then + NEXT_EX_STATE <= INIT; + elsif EX_P_RTE = '1' then + NEXT_EX_STATE <= INIT; + elsif EX_P_INT = '1' then + NEXT_EX_STATE <= INIT; + else -- No exception. + NEXT_EX_STATE <= IDLE; + end if; + when INIT => + -- In this state, the supervisor mode is switched on (the S bit is set) + -- and the trace mode is switched off (the T bit is cleared). + -- Do not service, if halted. The current bus cycle is always finished + -- in this state. The worst case is a bus error which the finishes the + -- current bus cycle within the next clock cycle after BERR is asserted. + case EXCEPTION is + when EX_RTE => + -- This state is foreseen to handle the address offset + -- correctly in the case the ADR_ATN is already set + -- by the main controller. So we have to wait one + -- clock cycle to ensure this data hazard. + if K6800n = '1' then + NEXT_EX_STATE <= VALIDATE_FRAME; -- 68K10. + else + NEXT_EX_STATE <= RESTORE_PC; -- 68K00. + end if; + when EX_INT => + NEXT_EX_STATE <= GET_VECTOR; + when others => + NEXT_EX_STATE <= CALC_VECT_No; + end case; + when GET_VECTOR => + -- This state is intended to determine the vector number for the current process. + if DATA_RDY = '1' then + NEXT_EX_STATE <= BUILD_STACK; + else + NEXT_EX_STATE <= GET_VECTOR; + end if; + when CALC_VECT_No => + -- This state is introduced to control the generation of the vector number + -- for all exceptions except the external interrupts. + case EXCEPTION is + when EX_RESET => + NEXT_EX_STATE <= RESTORE_ISP; -- Do not stack anything but update the SSP and PC. + when others => + NEXT_EX_STATE <= BUILD_STACK; + end case; + -- The following states provide writing to the stack pointer or reading + -- the exception vector address from memory. If there is a bus error + -- or an address error during the read or write cycles, the processor + -- proceeds in two different ways: + -- If the errors occur during a reset, bus error or address error + -- exception processing, a double bus fault has occured. In + -- consequence, the processor halts due to catastrophic system failure. + -- If the errors occur during other exception processings, the current + -- processing is aborted and this exception handler state machine will + -- immediately begin with the bus error exception handling. + when BUILD_STACK => + if DOUBLE_BUSFLT = '1' then + NEXT_EX_STATE <= HALTED; + elsif ACCESS_ERR = '1' then + NEXT_EX_STATE <= IDLE; + elsif DATA_RDY = '1' and STACK_CNT = 2 then + NEXT_EX_STATE <= UPDATE_PC; + else + NEXT_EX_STATE <= BUILD_STACK; + end if; + when UPDATE_PC => + if DOUBLE_BUSFLT = '1' then + NEXT_EX_STATE <= HALTED; + elsif ACCESS_ERR = '1' then + NEXT_EX_STATE <= IDLE; + elsif DATA_RDY = '1' then + NEXT_EX_STATE <= REFILL_PIPE; + else + NEXT_EX_STATE <= UPDATE_PC; + end if; + when VALIDATE_FRAME => + if DATA_RDY = '1' and DATA_VALID = '0' then + NEXT_EX_STATE <= IDLE; -- Bus error. + elsif ACCESS_ERR = '1' then + NEXT_EX_STATE <= IDLE; + elsif DATA_RDY = '1' then + case DATA_IN(15 downto 12) is + when x"0" => + NEXT_EX_STATE <= RESTORE_PC; + when x"8" => + NEXT_EX_STATE <= EXAMINE_VERSION; + when others => + NEXT_EX_STATE <= IDLE; -- Format error. + end case; + else + NEXT_EX_STATE <= VALIDATE_FRAME; + end if; + when EXAMINE_VERSION => + if ACCESS_ERR = '1' then + NEXT_EX_STATE <= IDLE; + elsif DATA_RDY = '1' then + if DATA_IN /= VERSION then + NEXT_EX_STATE <= IDLE; -- Format error. + else + NEXT_EX_STATE <= READ_BOTTOM; + end if; + else + NEXT_EX_STATE <= EXAMINE_VERSION; + end if; + when READ_BOTTOM => + if ACCESS_ERR = '1' then + NEXT_EX_STATE <= IDLE; + elsif DATA_RDY = '1' then + NEXT_EX_STATE <= RESTORE_PC; + else + NEXT_EX_STATE <= READ_BOTTOM; + end if; + when RESTORE_STATUS => + if DOUBLE_BUSFLT = '1' then + NEXT_EX_STATE <= HALTED; + elsif ACCESS_ERR = '1' then + NEXT_EX_STATE <= IDLE; + elsif DATA_RDY = '1' then + NEXT_EX_STATE <= REFILL_PIPE; + else + NEXT_EX_STATE <= RESTORE_STATUS; + end if; + when RESTORE_ISP => + if DOUBLE_BUSFLT = '1' then + NEXT_EX_STATE <= HALTED; + elsif ACCESS_ERR = '1' then + NEXT_EX_STATE <= IDLE; + elsif DATA_RDY = '1' then + NEXT_EX_STATE <= RESTORE_PC; + else + NEXT_EX_STATE <= RESTORE_ISP; + end if; + when RESTORE_PC => + if DOUBLE_BUSFLT = '1' then + NEXT_EX_STATE <= HALTED; -- Double bus fault. + elsif ACCESS_ERR = '1' then + NEXT_EX_STATE <= IDLE; + elsif EXCEPTION = EX_RESET and DATA_RDY = '1' then + NEXT_EX_STATE <= REFILL_PIPE; + elsif DATA_RDY = '1' then + NEXT_EX_STATE <= RESTORE_STATUS; + else + NEXT_EX_STATE <= RESTORE_PC; + end if; + when REFILL_PIPE => + if DOUBLE_BUSFLT = '1' then + NEXT_EX_STATE <= HALTED; + elsif ACCESS_ERR = '1' then + NEXT_EX_STATE <= IDLE; + elsif PIPE_FULL = true then + NEXT_EX_STATE <= IDLE; + else + NEXT_EX_STATE <= REFILL_PIPE; + end if; + when HALTED => + -- Processor halted, Double bus error! + NEXT_EX_STATE <= HALTED; + end case; + end process EXCEPTION_HANDLER_DEC; +end BEHAVIOR; diff --git a/common/CPU/68K10/wf68k10_opcode_decoder.vhd b/common/CPU/68K10/wf68k10_opcode_decoder.vhd new file mode 100644 index 00000000..f935ddcf --- /dev/null +++ b/common/CPU/68K10/wf68k10_opcode_decoder.vhd @@ -0,0 +1,1228 @@ +------------------------------------------------------------------------ +---- ---- +---- WF68K10 IP Core: this is the bus controller module. ---- +---- ---- +---- Description: ---- +---- This module is a 68010 compatible instruction word decoder. ---- +---- It is primarily controlled by the following signals: ---- +---- OW_REQ, OPD_ACK, EW_REQ and EW_ACK. The handshaking is as ---- +---- follows: if a new instruction is required, assert the signal ---- +---- OW_REQ and wait until ACK is asserted by the decoder logic. ---- +---- Deassert OW_REQ right after ACK (in the same clock cycle). ---- +---- At this point, the required instruction has already been copied---- +---- from the pipe to the register BIW_0. The respective additional ---- +---- instruction words are located in BIW_1, BIW_2. For more infor- ---- +---- mation see the 68010 "Programmers Reference Manual" and the ---- +---- signal INSTR_LVL in this module. ---- +---- The extension request works in the same manner by asserting ---- +---- EW_REQ. At the time of EXT_ACK one extension word has been ---- +---- copied to EXT_WORD. ---- +---- Be aware that it is in the scope of the logic driving ---- +---- OW_REQ and EW_REQ to hold the instruction pipe aligned. ---- +---- This means in detail, that the correct number or instruction ---- +---- and extension words must be requested. Otherwise unpredictable ---- +---- processor behaviour will occur. Furthermore OW_REQ and EW_REQ ---- +---- must not be asserted the same time. ---- +---- This operation code decoder with the handshake logic as des- ---- +---- cribed above is the first pipeline stage of the CPU architec- ---- +---- ture. ---- +---- ---- +---- ---- +---- Author(s): ---- +---- Wolfgang Foerster, wf@experiment-s.de; wf@inventronik.de ---- +---- ---- +------------------------------------------------------------------------ +---- ---- +---- Copyright © 2014-2019 Wolfgang Foerster Inventronik GmbH. ---- +---- ---- +---- This documentation describes Open Hardware and is licensed ---- +---- under the CERN OHL v. 1.2. You may redistribute and modify ---- +---- this documentation under the terms of the CERN OHL v.1.2. ---- +---- (http://ohwr.org/cernohl). This documentation is distributed ---- +---- WITHOUT ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING OF ---- +---- MERCHANTABILITY, SATISFACTORY QUALITY AND FITNESS FOR A ---- +---- PARTICULAR PURPOSE. Please see the CERN OHL v.1.2 for ---- +---- applicable conditions ---- +---- ---- +------------------------------------------------------------------------ +-- +-- Revision History +-- +-- Revision 2K14B 20141201 WF +-- Initial Release. +-- Revision 2K16A 20161224 WF +-- Break the DBcc_LOOP when the exception handler is busy (see process P_LOOP). +-- Revision 2K18A 20180620 WF +-- Several minor improvements to meet better 68000 compatibility. +-- Removed illegal MOVEC control register patterns. +-- Removed REST_BIW_0. +-- Fixed the PW_EW_OFFSET calculation for JSR. +-- Rewritten DBcc loop. +-- Fix for unimplemented or illegal operations: PC is increased before stacked. +-- Removed CAHR, we have no cache. +-- Rearranged address error handling. +-- Revision 2K19B 20191224 WF +-- Introduced signal synchronization in the P_BSY process to avoid malfunction by hazards. +-- + + +library work; +use work.WF68K10_PKG.all; + +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_unsigned.all; + +entity WF68K10_OPCODE_DECODER is + generic(NO_LOOP : boolean); -- If true the DBcc loop mechanism is disabled. + port ( + CLK : in std_logic; + K6800n : in std_logic; -- '0' for MC68000 compatibility. + + OW_REQ_MAIN : in bit; -- Request from the execution unit. + EW_REQ_MAIN : in bit; -- Extension words request. + + EXH_REQ : in bit; -- Exception request. + BUSY_EXH : in bit; -- Exception handler is busy. + BUSY_MAIN : in bit; -- Main controller busy. + BUSY_OPD : out bit; -- This unit is busy. + + BKPT_INSERT : in bit; + BKPT_DATA : in std_logic_vector(15 downto 0); + + LOOP_EXIT : in bit; + LOOP_BSY : out bit; + + OPD_ACK_MAIN : out bit; -- Operation controller acknowledge. + EW_ACK : buffer bit; -- Extension word available. + + PC_INC : out bit; + PC_INC_EXH : in bit; + PC_ADR_OFFSET : out std_logic_vector(7 downto 0); + PC_EW_OFFSET : buffer std_logic_vector(3 downto 0); + PC_OFFSET : out std_logic_vector(7 downto 0); + + OPCODE_RD : out bit; + OPCODE_RDY : in bit; + OPCODE_VALID : in std_logic; + OPCODE_DATA : in std_logic_vector(15 downto 0); + + IPIPE_FILL : in bit; + IPIPE_FLUSH : in bit; -- Abandon the instruction pipe. + + -- Fault logic: + OW_VALID : out std_logic; -- Operation words valid. + + -- Trap logic: + SBIT : in std_logic; + TRAP_CODE : out TRAPTYPE_OPC; + + -- System control signals: + OP : buffer OP_68K; + BIW_0 : buffer std_logic_vector(15 downto 0); + BIW_1 : out std_logic_vector(15 downto 0); + BIW_2 : out std_logic_vector(15 downto 0); + EXT_WORD : out std_logic_vector(15 downto 0) + ); +end entity WF68K10_OPCODE_DECODER; + +architecture BEHAVIOR of WF68K10_OPCODE_DECODER is +type INSTR_LVL_TYPE is(D, C, B); +type IPIPE_TYPE is + record + D : std_logic_vector(15 downto 0); + C : std_logic_vector(15 downto 0); + B : std_logic_vector(15 downto 0); + end record; + +signal REQ : bit; +signal EW_REQ : bit; + +signal IPIPE : IPIPE_TYPE; +signal FIFO_RD : bit; +signal IPIPE_B_FAULT : std_logic; +signal IPIPE_C_FAULT : std_logic; +signal IPIPE_D_FAULT : std_logic; +signal IPIPE_PNTR : natural range 0 to 3; + +signal INSTR_LVL : INSTR_LVL_TYPE; +signal LOOP_ATN : boolean; +signal LOOP_BSY_I : boolean; +signal LOOP_OP : boolean; + +signal BKPT_REQ : bit; + +signal OP_I : OP_68K; + +signal OPCODE_FLUSH : bit; +signal OPCODE_RD_I : bit; +signal OPCODE_RDY_I : bit; +signal OW_REQ : bit; + +signal TRAP_CODE_I : TRAPTYPE_OPC; +signal FLUSHED : boolean; +signal PC_INC_I : bit; +signal PIPE_RDY : bit; +begin + P_BSY: process(CLK) + -- This logic requires asynchronous reset. This flip flop is intended + -- to break combinatorial loops. If an opcode cycle in the bus controller + -- unit is currently running, the actual PC address is stored during this + -- cycle. Therefore it is not possible to flush the pipe and manipulate + -- the PC during a running cycle. For the exception handler reading the + -- opcode is inhibited during a pipe flush. For the main controller unit + -- the pipe is flushed after a running opcode cycle. + -- Important note: to avoid asynchronous reset by data hazards the + -- resetting signals are synchronized on the negative clock edge. + variable OPCODE_RDY_VAR : bit; + variable BUSY_EXH_VAR : bit; + variable IPIPE_FILL_VAR : bit; + begin + if CLK = '0' and CLK' event then + OPCODE_RDY_VAR := OPCODE_RDY; + BUSY_EXH_VAR := BUSY_EXH; + IPIPE_FILL_VAR := IPIPE_FILL; + end if; + -- + if OPCODE_RDY_VAR = '1' then + OPCODE_RD_I <= '0'; + elsif BUSY_EXH_VAR = '1' and IPIPE_FILL_VAR = '0' then + OPCODE_RD_I <= '0'; + elsif CLK = '1' and CLK' event then + if IPIPE_FLUSH = '1' then + OPCODE_RD_I <= '1'; + elsif (LOOP_ATN = true and OPCODE_RD_I = '0') or LOOP_BSY_I = true then + OPCODE_RD_I <= '0'; + elsif IPIPE_PNTR < 3 then + OPCODE_RD_I <= '1'; + end if; + end if; + end process P_BSY; + + P_OPCODE_FLUSH: process + -- If there is a pending opcode cycle during a pipe flush, + -- an opcode mismatch will destroy scalar opcode processing. + -- To avoid this, we have to dismiss the upcoming opcode. + begin + wait until CLK = '1' and CLK' event; + if IPIPE_FLUSH = '1' and OPCODE_RD_I = '1' and OPCODE_RDY = '0' then + OPCODE_FLUSH <= '1'; + elsif OPCODE_RDY = '1' or BUSY_EXH = '1' then + OPCODE_FLUSH <= '0'; + end if; + end process P_OPCODE_FLUSH; + + OPCODE_RD <= OPCODE_RD_I; + OPCODE_RDY_I <= '0' when OPCODE_FLUSH = '1' else OPCODE_RDY; -- Dismiss the current read cycle. + BUSY_OPD <= '0' when EXH_REQ = '1' and BUSY_MAIN = '0' and IPIPE_PNTR > 0 and OPCODE_RD_I = '0' else -- Fill one opcode is sufficient here. + '1' when IPIPE_PNTR < 3 or OPCODE_RD_I = '1' else '0'; + + INSTRUCTION_PIPE: process + -- These are the instruction pipe FIFO registers. The opcodes are stored in IPIPE.B, IPIPE.C + -- and IPIPE.D which is copied to the instruction register or to the respective extension when + -- read. Be aware, that the pipe is always completely refilled to determine the correct INSTR_LVL + -- before it is copied to the execution unit. + variable IPIPE_D_VAR : std_logic_vector(15 downto 0); + begin + wait until CLK = '1' and CLK' event; + if IPIPE_FLUSH = '1' then + IPIPE.D <= (others => '0'); + IPIPE.C <= (others => '0'); + IPIPE.B <= (others => '0'); + IPIPE_PNTR <= 0; + elsif BKPT_INSERT = '1' then + IPIPE_D_VAR := IPIPE.D; + IPIPE.D <= BKPT_DATA; -- Insert the breakpoint data. + BKPT_REQ <= '1'; + elsif OW_REQ = '1' and BKPT_REQ = '1' then + IPIPE.D <= IPIPE_D_VAR; -- Restore from breakpoint. + BKPT_REQ <= '0'; + elsif LOOP_ATN = true and OPCODE_RD_I = '1' then + null; -- Wait for pending opcodes. + elsif OW_REQ = '1' and PIPE_RDY = '1' and OP_I = DBcc and LOOP_OP = true and IPIPE.C = x"FFFC" then -- Initialize the loop. + IPIPE.D <= BIW_0; -- This is the LEVEL D operation for the loop. + elsif OW_REQ = '1' and LOOP_BSY_I = true then + IPIPE.D <= BIW_0; -- Recycle the loop operations. + elsif LOOP_BSY_I = true then + null; -- Do not change the pipe during the loop. + elsif OW_REQ = '1' and INSTR_LVL = D and PIPE_RDY = '1' and IPIPE_PNTR = 2 then + if OPCODE_RDY_I = '1' then + IPIPE.D <= IPIPE.C; + IPIPE.C <= OPCODE_DATA; + IPIPE_D_FAULT <= IPIPE_C_FAULT; + IPIPE_C_FAULT <= not OPCODE_VALID; + else + IPIPE.D <= IPIPE.C; + IPIPE_D_FAULT <= IPIPE_C_FAULT; + IPIPE_PNTR <= IPIPE_PNTR - 1; + end if; + elsif OW_REQ = '1' and INSTR_LVL = D and PIPE_RDY = '1' and IPIPE_PNTR = 3 then + if OPCODE_RDY_I = '1' then + IPIPE.D <= IPIPE.C; + IPIPE.C <= IPIPE.B; + IPIPE.B <= OPCODE_DATA; + IPIPE_D_FAULT <= IPIPE_C_FAULT; + IPIPE_C_FAULT <= IPIPE_B_FAULT; + IPIPE_B_FAULT <= not OPCODE_VALID; + else + IPIPE.D <= IPIPE.C; + IPIPE.C <= IPIPE.B; + IPIPE_D_FAULT <= IPIPE_C_FAULT; + IPIPE_C_FAULT <= IPIPE_B_FAULT; + IPIPE_PNTR <= IPIPE_PNTR - 1; + end if; + elsif OW_REQ = '1' and INSTR_LVL = C and PIPE_RDY = '1' and IPIPE_PNTR = 2 then + if OPCODE_RDY_I = '1' then + IPIPE.D <= OPCODE_DATA; + IPIPE_D_FAULT <= not OPCODE_VALID; + IPIPE_PNTR <= IPIPE_PNTR - 1; + else + IPIPE_PNTR <= 0; + end if; + elsif OW_REQ = '1' and INSTR_LVL = C and PIPE_RDY = '1' and IPIPE_PNTR = 3 then + if OPCODE_RDY_I = '1' then + IPIPE.D <= IPIPE.B; + IPIPE.C <= OPCODE_DATA; + IPIPE_D_FAULT <= IPIPE_B_FAULT; + IPIPE_C_FAULT <= not OPCODE_VALID; + IPIPE_PNTR <= IPIPE_PNTR - 1; + else + IPIPE.D <= IPIPE.B; + IPIPE_D_FAULT <= IPIPE_B_FAULT; + IPIPE_PNTR <= IPIPE_PNTR - 2; + end if; + elsif OW_REQ = '1' and INSTR_LVL = B and PIPE_RDY = '1' then -- IPIPE_PNTR = 3. + if OPCODE_RDY_I = '1' then + IPIPE.D <= OPCODE_DATA; + IPIPE_D_FAULT <= not OPCODE_VALID; + IPIPE_PNTR <= IPIPE_PNTR - 2; + else + IPIPE_PNTR <= 0; + end if; + elsif EW_REQ = '1' and IPIPE_PNTR >= 1 then + case IPIPE_PNTR is + when 3 => + if OPCODE_RDY_I = '1' then + IPIPE.D <= IPIPE.C; + IPIPE.C <= IPIPE.B; + IPIPE.B <= OPCODE_DATA; + IPIPE_D_FAULT <= IPIPE_C_FAULT; + IPIPE_C_FAULT <= IPIPE_B_FAULT; + IPIPE_B_FAULT <= not OPCODE_VALID; + else + IPIPE.D <= IPIPE.C; + IPIPE.C <= IPIPE.B; + IPIPE_D_FAULT <= IPIPE_C_FAULT; + IPIPE_C_FAULT <= IPIPE_B_FAULT; + IPIPE_PNTR <= IPIPE_PNTR - 1; + end if; + when 2 => + if OPCODE_RDY_I = '1' then + IPIPE.D <= IPIPE.C; + IPIPE.C <= OPCODE_DATA; + IPIPE_D_FAULT <= IPIPE_C_FAULT; + IPIPE_C_FAULT <= not OPCODE_VALID; + else + IPIPE.D <= IPIPE.C; + IPIPE_D_FAULT <= IPIPE_C_FAULT; + IPIPE_PNTR <= IPIPE_PNTR - 1; + end if; + when 1 => + if OPCODE_RDY_I = '1' then + IPIPE.D <= OPCODE_DATA; + IPIPE_D_FAULT <= not OPCODE_VALID; + else + IPIPE_PNTR <= 0; + end if; + when others => null; + end case; + elsif OPCODE_RDY_I = '1' then + case IPIPE_PNTR is + when 2 => + IPIPE.B <= OPCODE_DATA; + IPIPE_B_FAULT <= not OPCODE_VALID; + IPIPE_PNTR <= 3; + when 1 => + IPIPE.C <= OPCODE_DATA; + IPIPE_C_FAULT <= not OPCODE_VALID; + IPIPE_PNTR <= 2; + when 0 => + IPIPE.D <= OPCODE_DATA; + IPIPE_D_FAULT <= not OPCODE_VALID; + IPIPE_PNTR <= 1; + when others => null; + end case; + end if; + end process INSTRUCTION_PIPE; + + P_FAULT: process + -- This are the fault flags for pipe B and C. + -- These flags are set, when an instruction + -- request uses either of the respective pipes. + begin + wait until CLK = '1' and CLK' event; + if IPIPE_FLUSH = '1' then + OW_VALID <= '0'; + elsif OW_REQ = '1' and LOOP_BSY_I = true then + OW_VALID <= '1'; + elsif OW_REQ = '1' and PIPE_RDY = '1' and INSTR_LVL = D then + OW_VALID <= not IPIPE_D_FAULT; + elsif OW_REQ = '1' and PIPE_RDY = '1' and INSTR_LVL = C then + OW_VALID <= not(IPIPE_D_FAULT or IPIPE_C_FAULT); + elsif OW_REQ = '1' and PIPE_RDY = '1' and INSTR_LVL = B then + OW_VALID <= not (IPIPE_D_FAULT or IPIPE_C_FAULT or IPIPE_B_FAULT); + elsif EW_REQ = '1' and PIPE_RDY = '1' then + OW_VALID <= not IPIPE_D_FAULT; + end if; + end process P_FAULT; + + OUTBUFFERS: process + variable OP_STOP : boolean; + begin + wait until CLK = '1' and CLK' event; + if OP_STOP = true and IPIPE_FLUSH = '1' then + TRAP_CODE <= NONE; + OP_STOP := false; + elsif IPIPE_FLUSH = '1' then + TRAP_CODE <= NONE; + elsif OP_STOP = true then + null; -- Do not update after PC is incremented. + elsif LOOP_ATN = true and OPCODE_RD_I = '1' then + null; -- Wait for pending opcodes. + elsif OW_REQ = '1' and LOOP_BSY_I = true then + OP <= OP_I; + BIW_0 <= IPIPE.D; + TRAP_CODE <= TRAP_CODE_I; + elsif OW_REQ = '1' and (PIPE_RDY = '1' or BKPT_REQ = '1') then + -- Be aware: all BIW are written unaffected + -- if they are all used. + OP <= OP_I; + BIW_0 <= IPIPE.D; + BIW_1 <= IPIPE.C; + BIW_2 <= IPIPE.B; + TRAP_CODE <= TRAP_CODE_I; + -- + if OP_I = STOP then + OP_STOP := true; + end if; + elsif EW_REQ = '1' and IPIPE_PNTR /= 0 then + EXT_WORD <= IPIPE.D; + end if; + end process OUTBUFFERS; + + LOOP_OP <= false when NO_LOOP = true else + true when OP = MOVE and BIW_0(8 downto 3) = "010010" else -- (Ay) to (Ax). + true when OP = MOVE and BIW_0(8 downto 3) = "011010" else -- (Ay) to (Ax)+. + true when OP = MOVE and BIW_0(8 downto 3) = "100010" else -- (Ay) to -(Ax). + true when OP = MOVE and BIW_0(8 downto 3) = "010011" else -- (Ay)+ to (Ax). + true when OP = MOVE and BIW_0(8 downto 3) = "011011" else -- (Ay)+ to (Ax)+. + true when OP = MOVE and BIW_0(8 downto 3) = "100011" else -- (Ay)+ to -(Ax). + true when OP = MOVE and BIW_0(8 downto 3) = "010100" else -- -(Ay) to (Ax). + true when OP = MOVE and BIW_0(8 downto 3) = "011100" else -- -(Ay) to (Ax)+. + true when OP = MOVE and BIW_0(8 downto 3) = "100100" else -- -(Ay) to -(Ax). + true when OP = MOVE and BIW_0(8 downto 3) = "100100" else -- -(Ay) to -(Ax). + true when OP = MOVE and BIW_0(8 downto 3) = "010000" else -- Dy to (Ax). + true when OP = MOVE and BIW_0(8 downto 3) = "011000" else -- Dy to (Ax)+. + true when OP = MOVE and BIW_0(8 downto 3) = "010001" else -- Ay to (Ax). + true when OP = MOVE and BIW_0(8 downto 3) = "011001" else -- Ay to (Ax)+. + true when (OP = ADD or OP = AND_B or OP = CMP or OP = EOR or OP = OR_B or OP = SUB) and BIW_0(5 downto 3) = "010" else -- (Ay) to Dx, Dx to (Ay). + true when (OP = ADD or OP = AND_B or OP = CMP or OP = EOR or OP = OR_B or OP = SUB) and BIW_0(5 downto 3) = "011" else -- (Ay)+ to Dx, Dx to (Ay)+. + true when (OP = ADD or OP = AND_B or OP = CMP or OP = EOR or OP = OR_B or OP = SUB) and BIW_0(5 downto 3) = "100" else -- -(Ay) to Dx, Dx to -(Ay). + true when (OP = ADDA or OP = CMPA or OP = SUBA) and BIW_0(5 downto 3) = "010" else -- (Ay) to Ax. + true when (OP = ADDA or OP = CMPA or OP = SUBA) and BIW_0(5 downto 3) = "011" else -- (Ay)+ to Ax. + true when (OP = ADDA or OP = CMPA or OP = SUBA) and BIW_0(5 downto 3) = "100" else -- -(Ay) to Ax. + true when OP = ABCD or OP = SBCD or OP = ADDX or OP = SUBX or OP = CMPM else -- -(Ay) to -(Ay), (Ay)+ to (Ay)+ for CMPM. + true when (OP = CLR or OP = NEG or OP = NEGX or OP = NOT_B or OP = TST or OP = NBCD) and BIW_0(5 downto 3) = "010" else -- (Ay). + true when (OP = CLR or OP = NEG or OP = NEGX or OP = NOT_B or OP = TST or OP = NBCD) and BIW_0(5 downto 3) = "011" else -- (Ay)+. + true when (OP = CLR or OP = NEG or OP = NEGX or OP = NOT_B or OP = TST or OP = NBCD) and BIW_0(5 downto 3) = "100" else -- -(Ay). + true when (OP = ASL or OP = ASR or OP = LSL or OP = LSR) and BIW_0(7 downto 3) = "11010" else -- (Ay) by #1. + true when (OP = ASL or OP = ASR or OP = LSL or OP = LSR) and BIW_0(7 downto 3) = "11011" else -- (Ay)+ by #1. + true when (OP = ASL or OP = ASR or OP = LSL or OP = LSR) and BIW_0(7 downto 3) = "11100" else -- -(Ay) by #1. + true when (OP = ROTL or OP = ROTR or OP = ROXL or OP = ROXR) and BIW_0(7 downto 3) = "11010" else -- (Ay) by #1. + true when (OP = ROTL or OP = ROTR or OP = ROXL or OP = ROXR) and BIW_0(7 downto 3) = "11011" else -- (Ay)+ by #1. + true when (OP = ROTL or OP = ROTR or OP = ROXL or OP = ROXR) and BIW_0(7 downto 3) = "11100" else false; -- -(Ay) by #1. + + -- This is the loop attention signal. There are several conditions to start a loop operation. + -- 1. A loop capable operation is in progress indicated by LOOP_OP. + -- 2. A DBcc operation is coming up (IPIPE.D). + -- 3. The displacement is minus four (IPIPE.C). + -- 4. The exception handler may not indicate a request. Otherwise the system may hang in a self + -- blocking mechanism concerning OW_REQ, LOOP_ATN, ALU_BSY. + LOOP_ATN <= false when EXH_REQ = '1' else + true when LOOP_BSY_I = false and LOOP_OP = true and OP_I = DBcc and IPIPE.C = x"FFFC" else false; -- IPIPE.C value must be minus four. + + P_LOOP: process + -- This flip flop controls the loop mode of the + -- processor. Refer to the MC68000 user manual + -- Appendix A for more information. + begin + wait until CLK = '1' and CLK' event; + if LOOP_ATN = true and OW_REQ = '1' and OPCODE_RD_I = '0' then + LOOP_BSY <= '1'; + LOOP_BSY_I <= true; + elsif LOOP_EXIT = '1' or BUSY_EXH = '1' then + LOOP_BSY <= '0'; + LOOP_BSY_I <= false; + end if; + end process P_LOOP; + + OW_REQ <= '0' when BUSY_EXH = '1' else OW_REQ_MAIN; + EW_REQ <= EW_REQ_MAIN; + + PIPE_RDY <= '1' when OW_REQ = '1' and IPIPE_PNTR = 3 and INSTR_LVL = B else + '1' when OW_REQ = '1' and IPIPE_PNTR > 1 and INSTR_LVL = C else + '1' when OW_REQ = '1' and IPIPE_PNTR > 1 and INSTR_LVL = D else -- We need always pipe C and D to determine the INSTR_LVL. + '1' when EW_REQ = '1' and IPIPE_PNTR > 0 else '0'; + + HANDSHAKING: process + -- Wee need these flip flops to ensure, that the OUTBUFFERS are + -- written when the respecktive _ACK signal is asserted. + -- The breakpoint cycles are valid for one word operations and + -- therefore does never start FPU operations. + begin + wait until CLK = '1' and CLK' event; + if EW_REQ = '1' and IPIPE_PNTR /= 0 then + EW_ACK <= '1'; + else + EW_ACK <= '0'; + end if; + + if IPIPE_FLUSH = '1' then + OPD_ACK_MAIN <= '0'; + elsif TRAP_CODE_I = T_PRIV then -- No action when priviledged. + OPD_ACK_MAIN <= '0'; + elsif OW_REQ = '1' and LOOP_BSY_I = true then + OPD_ACK_MAIN <= '1'; + elsif OW_REQ = '1' and (PIPE_RDY = '1' or BKPT_REQ = '1') then + OPD_ACK_MAIN <= '1'; + else + OPD_ACK_MAIN <= '0'; + end if; + end process HANDSHAKING; + + P_PC_OFFSET: process(CLK, BUSY_EXH, LOOP_BSY_I, LOOP_EXIT, OP, PC_INC_I) + -- Be Aware: the ADR_OFFSET requires the 'old' PC_VAR. + -- To arrange this, the ADR_OFFSET logic is located + -- above the PC_VAR logic. Do not change this! + -- The PC_VAR is modeled in a way, that the PC points + -- always to the BIW_0. + -- The PC_EW_OFFSET is also used for the calculation + -- of the correct PC value written to the stack pointer + -- during BSR, JSR and exceptions. + variable ADR_OFFSET : std_logic_vector(6 downto 0); + variable PC_VAR : std_logic_vector(6 downto 0); + variable PC_VAR_MEM : std_logic_vector(6 downto 0); + begin + if CLK = '1' and CLK' event then + if IPIPE_FLUSH = '1' then + ADR_OFFSET := "0000000"; + elsif PC_INC_I = '1' and OPCODE_RDY_I = '1' then + ADR_OFFSET := ADR_OFFSET + '1' - PC_VAR; + elsif OPCODE_RDY_I = '1' then + ADR_OFFSET := ADR_OFFSET + '1'; + elsif PC_INC_I = '1' then + ADR_OFFSET := ADR_OFFSET - PC_VAR; + end if; + -- + if BUSY_EXH = '0' then + PC_VAR_MEM := PC_VAR; -- Store the old offset to write back on the stack. + end if; + + if BUSY_EXH = '1' then + -- New PC is loaded by the exception handler. + -- So PC_VAR must be initialized. + PC_VAR := "0000000"; + elsif PC_INC_I = '1' or FLUSHED = true then + case INSTR_LVL is + when D => PC_VAR := "0000001"; + when C => PC_VAR := "0000010"; + when B => PC_VAR := "0000011"; + end case; + elsif EW_REQ = '1' and IPIPE_PNTR /= 0 then + PC_VAR := PC_VAR + '1'; + end if; + -- + if OW_REQ = '1' and BKPT_REQ = '1' then + PC_EW_OFFSET <= "0010"; -- Always level D operations. + elsif OW_REQ = '1' and PIPE_RDY = '1' and OP_I = JSR then -- Initialize. + PC_EW_OFFSET <= x"0"; + elsif OW_REQ = '1' and PIPE_RDY = '1' then -- BSR. + case INSTR_LVL is + when D => PC_EW_OFFSET <= "0010"; + when C => PC_EW_OFFSET <= "0100"; + when others => PC_EW_OFFSET <= "0110"; -- LONG displacement. + end case; + elsif EW_ACK = '1' and OP = JSR then -- Calculate the required extension words. + PC_EW_OFFSET <= PC_EW_OFFSET + "010"; + end if; + end if; + -- + if BUSY_EXH = '1' and PC_INC_I = '1' then + PC_OFFSET <= PC_VAR_MEM & '0'; + elsif OP = DBcc and LOOP_BSY_I = true and LOOP_EXIT = '0' then + -- Suppress to increment after DBcc operation during the loop to + -- handle a correct PC with displacement when looping around. + -- In non looping mode, the PC_ING is superseeded by + -- IPIPE_FLUSH in the PC logic. In loop mode we have no flush. + PC_OFFSET <= x"00"; + else + PC_OFFSET <= PC_VAR & '0'; + end if; + PC_ADR_OFFSET <= ADR_OFFSET & '0'; + end process P_PC_OFFSET; + + P_FLUSH: process + -- This flip flop is intended to control the incrementation + -- of the PC: normally the PC is updated in the end of an + -- operation (if a new opword is available) or otherwise in + -- the START_OP phase. When the instruction pipe is flushed, + -- it is required to increment the PC immediately to provide + -- the correct address for the pipe refilling. In this case + -- the PC update after the pipe refill is suppressed. + begin + wait until CLK = '1' and CLK' event; + if IPIPE_FLUSH = '1' then + FLUSHED <= true; + elsif OW_REQ = '1' and PIPE_RDY = '1' then + FLUSHED <= false; + end if; + end process P_FLUSH; + + PC_INC <= PC_INC_I; + PC_INC_I <= '0' when FLUSHED = true else -- Avoid double increment after a flushed pipe. + '1' when IPIPE_FLUSH = '1' and BUSY_MAIN = '1' else -- If the pipe is flushed, we need the new PC value for refilling. + '0' when BKPT_REQ = '1' else -- Do not update! + '1' when OW_REQ = '1' and PIPE_RDY = '1' else PC_INC_EXH; + + -- This signal indicates how many pipe stages are used at a time. + -- Be aware: all coprocessor commands are level D to meet the require- + -- ments of the scanPC. + INSTR_LVL <= D when TRAP_CODE_I = T_PRIV else -- Points to the first word. Required for stacking. + B when OP_I = ADDI and IPIPE.D(7 downto 6) = "10" else + B when OP_I = ANDI and IPIPE.D(7 downto 6) = "10" else + -- B when (OP_I = Bcc or OP_I = BRA or OP_I = BSR) and IPIPE.D(7 downto 0) = x"FF" else -- LONG for 68K10+. + B when OP_I = CMPI and IPIPE.D(7 downto 6) = "10" else + B when OP_I = EORI and IPIPE.D(7 downto 6) = "10" else + B when OP_I = ORI and IPIPE.D(7 downto 6) = "10" else + B when OP_I = SUBI and IPIPE.D(7 downto 6) = "10" else + C when OP_I = ADDI or OP_I = ANDI or OP_I = ANDI_TO_SR or OP_I = ANDI_TO_CCR else + C when (OP_I = BCHG or OP_I = BCLR or OP_I = BSET or OP_I = BTST) and IPIPE.D(8) = '0' else + C when (OP_I = Bcc or OP_I = BRA or OP_I = BSR) and IPIPE.D(7 downto 0) = x"00" else + C when OP_I = CMPI or OP_I = DBcc else + C when (OP_I = DIVS or OP_I = DIVU) and IPIPE.D(8 downto 6) = "001" else + C when OP_I = EORI or OP_I = EORI_TO_CCR or OP_I = EORI_TO_SR else + C when OP_I = LINK or OP_I = MOVEC else -- 68K00 and 68K10 have no long LINK. + C when OP_I = MOVEM or OP_I = MOVEP or OP_I = MOVES else + C when (OP_I = MULS or OP_I = MULU) and IPIPE.D(8 downto 6) = "000" else + C when OP_I = ORI_TO_CCR or OP_I = ORI_TO_SR or OP_I = ORI else + C when OP_I = RTD or OP_I = SUBI or OP_I = STOP else D; + + TRAP_CODE_I <= T_1010 when OP_I = UNIMPLEMENTED and IPIPE.D(15 downto 12) = x"A" else + T_1111 when OP_I = UNIMPLEMENTED and IPIPE.D(15 downto 12) = x"F" else + T_ILLEGAL when OP_I = ILLEGAL else + T_RTE when OP_I = RTE and SBIT = '1' else -- Handled like a trap simplifies the code. + T_TRAP when OP_I = TRAP else + T_PRIV when OP_I = ANDI_TO_SR and SBIT = '0' else + T_PRIV when OP_I = EORI_TO_SR and SBIT = '0' else + T_PRIV when OP_I = MOVE_TO_SR and SBIT = '0' else + T_PRIV when OP_I = MOVE_FROM_SR and SBIT = '0' and K6800n = '1' else -- This is for backward compatibility. + T_PRIV when (OP_I = MOVE_USP or OP_I = MOVEC or OP_I = MOVES) and SBIT = '0' else + T_PRIV when OP_I = ORI_TO_SR and SBIT = '0' else + T_PRIV when (OP_I = RESET or OP_I = RTE) and SBIT = '0' else + T_PRIV when OP_I = STOP and SBIT = '0' else NONE; + + OP_DECODE: process(IPIPE, K6800n) + begin + -- The default OPCODE is the ILLEGAL operation, if no of the following conditions are met. + -- If any not used bit pattern occurs, the CPU will result in an ILLEGAL trap. An exception of + -- this behavior is the OPCODE with the 1010 or the 1111 pattern in the four MSBs. + -- These lead to the respective traps. + OP_I <= ILLEGAL; + case IPIPE.D(15 downto 12) is -- Operation code map. + when x"0" => -- Bit manipulation / MOVEP / Immediate. + if IPIPE.D(11 downto 0) = x"03C" then + OP_I <= ORI_TO_CCR; + elsif IPIPE.D(11 downto 0) = x"07C" then + OP_I <= ORI_TO_SR; + elsif IPIPE.D(11 downto 0) = x"23C" then + OP_I <= ANDI_TO_CCR; + elsif IPIPE.D(11 downto 0) = x"27C" then + OP_I <= ANDI_TO_SR; + elsif IPIPE.D(11 downto 0) = x"A3C" then + OP_I <= EORI_TO_CCR; + elsif IPIPE.D(11 downto 0) = x"A7C" then + OP_I <= EORI_TO_SR; + elsif IPIPE.D(11 downto 8) = "1110" and IPIPE.D(7 downto 6) < "11" and IPIPE.D(5 downto 3) >= "010" and IPIPE.D(5 downto 3) < "111" and K6800n = '1' then + OP_I <= MOVES; + elsif IPIPE.D(11 downto 8) = "1110" and IPIPE.D(7 downto 6) < "11" and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "010" and K6800n = '1' then + OP_I <= MOVES; + elsif IPIPE.D(8 downto 6) > "011" and IPIPE.D(5 downto 3) = "001" then + OP_I <= MOVEP; + else + case IPIPE.D(5 downto 3) is -- Addressing mode. + when "000" | "010" | "011" | "100" | "101" | "110" => + -- Bit operations with static bit number: + if IPIPE.D(11 downto 6) = "100000" then + OP_I <= BTST; + elsif IPIPE.D(11 downto 6) = "100001" then + OP_I <= BCHG; + elsif IPIPE.D(11 downto 6) = "100010" then + OP_I <= BCLR; + elsif IPIPE.D(11 downto 6) = "100011" then + OP_I <= BSET; + -- Logic operations: + elsif IPIPE.D(11 downto 8) = x"0" and IPIPE.D(7 downto 6) < "11" then + OP_I <= ORI; + elsif IPIPE.D(11 downto 8) = x"2" and IPIPE.D(7 downto 6) < "11" then + OP_I <= ANDI; + elsif IPIPE.D(11 downto 8) = x"4" and IPIPE.D(7 downto 6) < "11" then + OP_I <= SUBI; + elsif IPIPE.D(11 downto 8) = x"6" and IPIPE.D(7 downto 6) < "11" then + OP_I <= ADDI; + elsif IPIPE.D(11 downto 8) = x"A" and IPIPE.D(7 downto 6) < "11" then + OP_I <= EORI; + elsif IPIPE.D(11 downto 8) = x"C" and IPIPE.D(7 downto 6) < "11" then + OP_I <= CMPI; + -- Bit operations with dynamic bit number: + elsif IPIPE.D(8 downto 6) = "100" then + OP_I <= BTST; + elsif IPIPE.D(8 downto 6) = "101" then + OP_I <= BCHG; + elsif IPIPE.D(8 downto 6) = "110" then + OP_I <= BCLR; + elsif IPIPE.D(8 downto 6) = "111" then + OP_I <= BSET; + end if; + when "111" => + -- In the addressing mode "111" not all register selections are valid. + -- Bit operations with static bit number: + if IPIPE.D(11 downto 6) = "100000" and IPIPE.D(2 downto 0) < "100" then + OP_I <= BTST; + elsif IPIPE.D(11 downto 6) = "100001" and IPIPE.D(2 downto 0) < "010" then + OP_I <= BCHG; + elsif IPIPE.D(11 downto 6) = "100010" and IPIPE.D(2 downto 0) < "010" then + OP_I <= BCLR; + elsif IPIPE.D(11 downto 6) = "100011" and IPIPE.D(2 downto 0) < "010" then + OP_I <= BSET; + -- Logic operations: + elsif IPIPE.D(11 downto 8) = x"0" and IPIPE.D(7 downto 6) < "11" and IPIPE.D(2 downto 0) < "010" then + OP_I <= ORI; + elsif IPIPE.D(11 downto 8) = x"2" and IPIPE.D(7 downto 6) < "11" and IPIPE.D(2 downto 0) < "010" then + OP_I <= ANDI; + elsif IPIPE.D(11 downto 8) = x"4" and IPIPE.D(7 downto 6) < "11" and IPIPE.D(2 downto 0) < "010" then + OP_I <= SUBI; + elsif IPIPE.D(11 downto 8) = x"6" and IPIPE.D(7 downto 6) < "11" and IPIPE.D(2 downto 0) < "010" then + OP_I <= ADDI; + elsif IPIPE.D(11 downto 8) = x"A" and IPIPE.D(7 downto 6) < "11" and IPIPE.D(2 downto 0) < "010" then + OP_I <= EORI; + elsif IPIPE.D(11 downto 8) = x"C" and IPIPE.D(7 downto 6) < "11" and IPIPE.D(2 downto 0) < "100" then + OP_I <= CMPI; + -- Bit operations with dynamic bit number: + elsif IPIPE.D(8 downto 6) = "100" and IPIPE.D(2 downto 0) < "101" then + OP_I <= BTST; + elsif IPIPE.D(8 downto 6) = "101" and IPIPE.D(2 downto 0) < "010" then + OP_I <= BCHG; + elsif IPIPE.D(8 downto 6) = "110" and IPIPE.D(2 downto 0) < "010" then + OP_I <= BCLR; + elsif IPIPE.D(8 downto 6) = "111" and IPIPE.D(2 downto 0) < "010" then + OP_I <= BSET; + end if; + when others => + null; + end case; + end if; + when x"1" => -- Move BYTE. + if IPIPE.D(8 downto 6) = "111" and IPIPE.D(11 downto 9) < "010" + and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "101" then + OP_I <= MOVE; + elsif IPIPE.D(8 downto 6) = "111" and IPIPE.D(11 downto 9) < "010" and IPIPE.D(5 downto 3) /= "001" and IPIPE.D(5 downto 3) /= "111" then + OP_I <= MOVE; + elsif IPIPE.D(8 downto 6) /= "001" and IPIPE.D(8 downto 6) /= "111" + and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "101" then + OP_I <= MOVE; + elsif IPIPE.D(8 downto 6) /= "001" and IPIPE.D(8 downto 6) /= "111" and IPIPE.D(5 downto 3) /= "001" and IPIPE.D(5 downto 3) /= "111" then + OP_I <= MOVE; + end if; + when x"2" | x"3" => -- Move WORD or LONG. + if IPIPE.D(8 downto 6) = "111" and IPIPE.D(11 downto 9) < "010" + and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "101" then + OP_I <= MOVE; + elsif IPIPE.D(8 downto 6) = "111" and IPIPE.D(11 downto 9) < "010" and IPIPE.D(5 downto 3) /= "111" then + OP_I <= MOVE; + elsif IPIPE.D(8 downto 6) = "001" and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "101" then + OP_I <= MOVEA; + elsif IPIPE.D(8 downto 6) = "001" and IPIPE.D(5 downto 3) /= "111" then + OP_I <= MOVEA; + elsif IPIPE.D(8 downto 6) /= "001" and IPIPE.D(8 downto 6) /= "111" and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "101" then + OP_I <= MOVE; + elsif IPIPE.D(8 downto 6) /= "001" and IPIPE.D(8 downto 6) /= "111" and IPIPE.D(5 downto 3) /= "111" then + OP_I <= MOVE; + end if; + when x"4" => -- Miscellaneous. + if IPIPE.D(11 downto 0) = x"E70" then + OP_I <= RESET; + elsif IPIPE.D(11 downto 0) = x"E71" then + OP_I <= NOP; + elsif IPIPE.D(11 downto 0) = x"E72" then + OP_I <= STOP; + elsif IPIPE.D(11 downto 0) = x"E73" then + OP_I <= RTE; + elsif IPIPE.D(11 downto 0) = x"E74" and K6800n = '1' then + OP_I <= RTD; + elsif IPIPE.D(11 downto 0) = x"E75" then + OP_I <= RTS; + elsif IPIPE.D(11 downto 0) = x"E76" then + OP_I <= TRAPV; + elsif IPIPE.D(11 downto 0) = x"E77" then + OP_I <= RTR; + elsif IPIPE.D(11 downto 0) = x"AFC" then + OP_I <= ILLEGAL; + elsif IPIPE.D(11 downto 1) = "11100111101" and IPIPE.C(11 downto 0) = x"000" and K6800n = '1' then + OP_I <= MOVEC; + elsif IPIPE.D(11 downto 1) = "11100111101" and IPIPE.C(11 downto 0) = x"001" and K6800n = '1' then + OP_I <= MOVEC; + elsif IPIPE.D(11 downto 1) = "11100111101" and IPIPE.C(11 downto 0) = x"800" and K6800n = '1' then + OP_I <= MOVEC; + elsif IPIPE.D(11 downto 1) = "11100111101" and IPIPE.C(11 downto 0) = x"801" and K6800n = '1' then + OP_I <= MOVEC; + elsif IPIPE.D(11 downto 1) = "11100111101" then + OP_I <= ILLEGAL; -- Not valid MOVEC patterns. + elsif IPIPE.D(11 downto 3) = "100001001" and K6800n = '1' then -- 68K10. + OP_I <= BKPT; + elsif IPIPE.D(11 downto 3) = "111001010" then + OP_I <= LINK; -- WORD. + elsif IPIPE.D(11 downto 3) = "111001011" then + OP_I <= UNLK; + elsif IPIPE.D(11 downto 3) = "100001000" then + OP_I <= SWAP; + elsif IPIPE.D(11 downto 4) = x"E4" then + OP_I <= TRAP; + elsif IPIPE.D(11 downto 4) = x"E6" then + OP_I <= MOVE_USP; + else + case IPIPE.D(5 downto 3) is -- Addressing mode. + when "000" | "010" | "011" | "100" | "101" | "110" => + if IPIPE.D(11 downto 6) = "110001" then + if IPIPE.C(11) = '1' then + OP_I <= DIVS; -- Long. + else + OP_I <= DIVU; -- Long. + end if; + elsif IPIPE.D(11 downto 6) = "001011" and K6800n = '1' then + OP_I <= MOVE_FROM_CCR; + elsif IPIPE.D(11 downto 6) = "000011" then + OP_I <= MOVE_FROM_SR; + elsif IPIPE.D(11 downto 6) = "010011" then + OP_I <= MOVE_TO_CCR; + elsif IPIPE.D(11 downto 6) = "011011" then + OP_I <= MOVE_TO_SR; + elsif IPIPE.D(11 downto 6) = "110000" then + if IPIPE.C(11) = '1' then + OP_I <= MULS; -- Long. + else + OP_I <= MULU; -- Long. + end if; + elsif IPIPE.D(11 downto 6) = "100000" then + OP_I <= NBCD; + elsif IPIPE.D(11 downto 6) = "101011" then + OP_I <= TAS; + end if; + when "111" => -- Not all registers are valid for this mode. + if IPIPE.D(11 downto 6) = "110001" and IPIPE.D(2 downto 0) < "101" then + if IPIPE.C(11) = '1' then + OP_I <= DIVS; -- Long. + else + OP_I <= DIVU; -- Long. + end if; + elsif IPIPE.D(11 downto 6) = "001011" and IPIPE.D(2 downto 0) < "010" and K6800n = '1' then + OP_I <= MOVE_FROM_CCR; + elsif IPIPE.D(11 downto 6) = "000011" and IPIPE.D(2 downto 0) < "010" then + OP_I <= MOVE_FROM_SR; + elsif IPIPE.D(11 downto 6) = "010011" and IPIPE.D(2 downto 0) < "101" then + OP_I <= MOVE_TO_CCR; + elsif IPIPE.D(11 downto 6) = "011011" and IPIPE.D(2 downto 0) < "101" then + OP_I <= MOVE_TO_SR; + elsif IPIPE.D(11 downto 6) = "110000" and IPIPE.D(2 downto 0) < "101" then + if IPIPE.C(11) = '1' then + OP_I <= MULS; -- Long. + else + OP_I <= MULU; -- Long. + end if; + elsif IPIPE.D(11 downto 6) = "100000" and IPIPE.D(2 downto 0) < "010" then + OP_I <= NBCD; + elsif IPIPE.D(11 downto 6) = "101011" and IPIPE.D(2 downto 0) < "010" then + OP_I <= TAS; + end if; + when others => + null; + end case; + + case IPIPE.D(5 downto 3) is -- Addressing mode. + when "010" | "101" | "110" => + if IPIPE.D(11 downto 6) = "100001" then + OP_I <= PEA; + elsif IPIPE.D(11 downto 6) = "111010" then + OP_I <= JSR; + elsif IPIPE.D(11 downto 6) = "111011" then + OP_I <= JMP; + end if; + when "111" => -- Not all registers are valid for this mode. + if IPIPE.D(11 downto 6) = "100001" and IPIPE.D(2 downto 0) < "100" then + OP_I <= PEA; + elsif IPIPE.D(11 downto 6) = "111010" and IPIPE.D(2 downto 0) < "100" then + OP_I <= JSR; + elsif IPIPE.D(11 downto 6) = "111011" and IPIPE.D(2 downto 0) < "100" then + OP_I <= JMP; + end if; + when others => + null; + end case; + + -- For the following operation codes a SIZE (IPIPE.D(7 downto 6)) is not valid. + -- For the following operation codes an addressing mode x"001" is not valid. + if IPIPE.D(7 downto 6) < "11" and IPIPE.D(5 downto 3) /= "001" and IPIPE.D(5 downto 3) /= "111" then + case IPIPE.D(11 downto 8) is + when x"0" => OP_I <= NEGX; + when x"2" => OP_I <= CLR; + when x"4" => OP_I <= NEG; + when x"6" => OP_I <= NOT_B; + when others => null; + end case; + -- Not all registers are valid for the addressing mode "111": + elsif IPIPE.D(7 downto 6) < "11" and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "010" then + case IPIPE.D(11 downto 8) is + when x"0" => OP_I <= NEGX; + when x"2" => OP_I <= CLR; + when x"4" => OP_I <= NEG; + when x"6" => OP_I <= NOT_B; + when others => null; + end case; + end if; + + if IPIPE.D(11 downto 8) = x"A" and IPIPE.D(7 downto 6) < "11" and IPIPE.D(5 downto 3) = "111" and (IPIPE.D(2 downto 0) < "010" or IPIPE.D(2 downto 0) = "100") then -- 68K + -- if IPIPE.D(11 downto 8) = x"A" and IPIPE.D(7 downto 6) < "11" and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "101" then -- 68K20 and up. + OP_I <= TST; -- For the 68K00 the byte addressing mode on address register direst is allowed. + elsif IPIPE.D(11 downto 8) = x"A" and IPIPE.D(7 downto 6) < "11" and IPIPE.D(5 downto 3) /= "111" then + case IPIPE.D(7 downto 6) is + when "01" | "10" => OP_I <= TST; -- Long or word, all addressing modes. + when others => -- Byte: Address register direct not allowed. + if IPIPE.D(5 downto 3) /= "001" then + OP_I <= TST; + end if; + end case; + end if; + + if IPIPE.D(11 downto 9) = "100" and IPIPE.D(5 downto 3) = "000" then + case IPIPE.D(8 downto 6) is -- Valid OPMODES for this operation code. + when "010" | "011" => OP_I <= EXT; + when others => null; + end case; + end if; + + if IPIPE.D(8 downto 6) = "111" then + case IPIPE.D(5 downto 3) is -- OPMODES. + when "010" | "101" | "110" => + OP_I <= LEA; + when "111" => + if IPIPE.D(2 downto 0) < "100" then -- Not all registers are valid for this OPMODE. + OP_I <= LEA; + end if; + when others => null; + end case; + end if; + + if IPIPE.D(11) = '1' and IPIPE.D(9 downto 7) = "001" then + if IPIPE.D(10) = '0' then -- Register to memory transfer. + case IPIPE.D(5 downto 3) is -- OPMODES, no postincrement addressing. + when "010" | "100" | "101" | "110" => + OP_I <= MOVEM; + when "111" => + if IPIPE.D(2 downto 0) = "000" or IPIPE.D(2 downto 0) = "001" then + OP_I <= MOVEM; + end if; + when others => null; + end case; + else -- Memory to register transfer, no predecrement addressing. + case IPIPE.D(5 downto 3) is -- OPMODES. + when "010" | "011" | "101" | "110" => + OP_I <= MOVEM; + when "111" => + if IPIPE.D(2 downto 0) < "100" then + OP_I <= MOVEM; + end if; + when others => null; + end case; + end if; + end if; + + -- The size must be "11" and the OPMODE may not be "001". + if IPIPE.D(8 downto 7) = "11" and IPIPE.D(6 downto 3) = x"7" and IPIPE.D(2 downto 0) < "101" then + OP_I <= CHK; -- CHK is WORD wide for the 68K10 and 68K00. + elsif IPIPE.D(8 downto 7) = "11" and IPIPE.D(6 downto 3) /= x"1" and IPIPE.D(6 downto 3) < x"7" then + OP_I <= CHK; -- CHK is WORD wide for the 68K10 and 68K00. + end if; + end if; + when x"5" => -- ADDQ / SUBQ / Scc / DBcc. + if IPIPE.D(7 downto 3) = "11001" then + OP_I <= DBcc; + elsif IPIPE.D(7 downto 6) = "11" and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "010" then + OP_I <= Scc; + elsif IPIPE.D(7 downto 6) = "11" and IPIPE.D(5 downto 3) /= "001" and IPIPE.D(5 downto 3) /= "111" then + OP_I <= Scc; + -- + elsif IPIPE.D(8) = '0' and IPIPE.D(7 downto 6) < "11" and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "010" then + OP_I <= ADDQ; + elsif IPIPE.D(8) = '0' and (IPIPE.D(7 downto 6) = "01" or IPIPE.D(7 downto 6) = "10") and IPIPE.D(5 downto 3) /= "111" then + OP_I <= ADDQ; + elsif IPIPE.D(8) = '0' and IPIPE.D(7 downto 6) = "00" and IPIPE.D(5 downto 3) /= "001" and IPIPE.D(5 downto 3) /= "111" then + OP_I <= ADDQ; + -- + elsif IPIPE.D(8) = '1' and IPIPE.D(7 downto 6) < "11" and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "010" then + OP_I <= SUBQ; + elsif IPIPE.D(8) = '1' and (IPIPE.D(7 downto 6) = "01" or IPIPE.D(7 downto 6) = "10") and IPIPE.D(5 downto 3) /= "111" then + OP_I <= SUBQ; + elsif IPIPE.D(8) = '1' and IPIPE.D(7 downto 6) = "00" and IPIPE.D(5 downto 3) /= "001" and IPIPE.D(5 downto 3) /= "111" then + OP_I <= SUBQ; + end if; + when x"6" => -- Bcc / BSR / BRA. + if IPIPE.D(11 downto 8) = x"0" then + OP_I <= BRA; + elsif IPIPE.D(11 downto 8) = x"1" then + OP_I <= BSR; + else + OP_I <= Bcc; + end if; + when x"7" => -- MOVEQ. + if IPIPE.D(8) = '0' then + OP_I <= MOVEQ; + end if; + when x"8" => -- OR / DIV / SBCD. + if IPIPE.D(8 downto 6) = "011" and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "101" then + OP_I <= DIVU; -- WORD. + elsif IPIPE.D(8 downto 6) = "011" and IPIPE.D(5 downto 3) /= "001" and IPIPE.D(5 downto 3) /= "111" then + OP_I <= DIVU; -- WORD. + elsif IPIPE.D(8 downto 6) = "111" and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "101" then + OP_I <= DIVS; -- WORD. + elsif IPIPE.D(8 downto 6) = "111" and IPIPE.D(5 downto 3) /= "001" and IPIPE.D(5 downto 3) /= "111" then + OP_I <= DIVS; -- WORD. + elsif IPIPE.D(8 downto 4) = "10000" then + OP_I <= SBCD; + end if; + -- + case IPIPE.D(8 downto 6) is + when "000" | "001" | "010" => + if IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "101" then + OP_I <= OR_B; + elsif IPIPE.D(5 downto 3) /= "001" and IPIPE.D(5 downto 3) /= "111" then + OP_I <= OR_B; + end if; + when "100" | "101" | "110" => + if IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "010" then + OP_I <= OR_B; + elsif IPIPE.D(5 downto 3) > "001" and IPIPE.D(5 downto 3) /= "111" then + OP_I <= OR_B; + end if; + when others => + null; + end case; + when x"9" => -- SUB / SUBX. + case IPIPE.D(8 downto 6) is + when "000" => -- Byte size. + if IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "101" then + OP_I <= SUB; + elsif IPIPE.D(5 downto 3) /= "111" and IPIPE.D(5 downto 3) /= "001" then + OP_I <= SUB; + end if; + when "001" | "010" => -- Word and long. + if IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "101" then + OP_I <= SUB; + elsif IPIPE.D(5 downto 3) /= "111" then + OP_I <= SUB; + end if; + when "100" => + if IPIPE.D(5 downto 3) = "000" or IPIPE.D(5 downto 3) = "001" then + OP_I <= SUBX; + elsif IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "010" then + OP_I <= SUB; + elsif IPIPE.D(5 downto 3) /= "111" and IPIPE.D(5 downto 3) /= "001" then -- Byte size. + OP_I <= SUB; + end if; + when "101" | "110" => + if IPIPE.D(5 downto 3) = "000" or IPIPE.D(5 downto 3) = "001" then + OP_I <= SUBX; + elsif IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "010" then + OP_I <= SUB; + elsif IPIPE.D(5 downto 3) /= "111" then -- Word and long. + OP_I <= SUB; + end if; + when "011" | "111" => + if IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "101" then + OP_I <= SUBA; + elsif IPIPE.D(5 downto 3) /= "111" then + OP_I <= SUBA; + end if; + when others => -- U, X, Z, W, H, L, -. + null; + end case; + when x"A" => -- (1010, Unassigned, Reserved). + OP_I <= UNIMPLEMENTED; + when x"B" => -- CMP / EOR. + if IPIPE.D(8) = '1' and IPIPE.D(7 downto 6) < "11" and IPIPE.D(5 downto 3) = "001" then + OP_I <= CMPM; + else + case IPIPE.D(8 downto 6) is -- OPMODE field. + when "000" => + if IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "101" then + OP_I <= CMP; + elsif IPIPE.D(5 downto 3) /= "001" and IPIPE.D(5 downto 3) /= "111" then + OP_I <= CMP; + end if; + when "001" | "010" => + if IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "101" then + OP_I <= CMP; + elsif IPIPE.D(5 downto 3) /= "111" then + OP_I <= CMP; + end if; + when "011" | "111" => + if IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "101" then + OP_I <= CMPA; + elsif IPIPE.D(5 downto 3) /= "111" then + OP_I <= CMPA; + end if; + when "100" | "101" | "110" => + if IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "101" then + OP_I <= EOR; + elsif IPIPE.D(5 downto 3) /= "001" and IPIPE.D(5 downto 3) /= "111" then + OP_I <= EOR; + end if; + when others => -- U, X, Z, W, H, L, -. + null; + end case; + end if; + when x"C" => -- AND / MUL / ABCD / EXG. + if IPIPE.D(8 downto 4) = "10000" then + OP_I <= ABCD; + elsif IPIPE.D(8 downto 6) = "011" and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "101" then + OP_I <= MULU; -- WORD. + elsif IPIPE.D(8 downto 6) = "011" and IPIPE.D(5 downto 3) /= "001" and IPIPE.D(5 downto 3) /= "111" then + OP_I <= MULU; -- WORD. + elsif IPIPE.D(8 downto 6) = "111" and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "101" then + OP_I <= MULS; -- WORD. + elsif IPIPE.D(8 downto 6) = "111" and IPIPE.D(5 downto 3) /= "001" and IPIPE.D(5 downto 3) /= "111" then + OP_I <= MULS; -- WORD. + elsif IPIPE.D(8 downto 3) = "101000" or IPIPE.D(8 downto 3) = "101001" or IPIPE.D(8 downto 3) = "110001" then + OP_I <= EXG; + else + case IPIPE.D(8 downto 6) is -- OPMODE + when "000" | "001" | "010" => + if IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "101" then + OP_I <= AND_B; + elsif IPIPE.D(5 downto 3) /= "001" and IPIPE.D(5 downto 3) /= "111" then + OP_I <= AND_B; + end if; + when "100" | "101" | "110" => + if IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "010" then + OP_I <= AND_B; + elsif IPIPE.D(5 downto 3) > "001" and IPIPE.D(5 downto 3) /= "111" then + OP_I <= AND_B; + end if; + when others => + null; + end case; + end if; + when x"D" => -- ADD / ADDX. + case IPIPE.D(8 downto 6) is + when "000" => + if IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "101" then + OP_I <= ADD; + elsif IPIPE.D(5 downto 3) /= "111" and IPIPE.D(5 downto 3) /= "001" then + OP_I <= ADD; + end if; + when "001" | "010" => + if IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "101" then + OP_I <= ADD; + elsif IPIPE.D(5 downto 3) /= "111" then + OP_I <= ADD; + end if; + when "100" => + if IPIPE.D(5 downto 3) = "000" or IPIPE.D(5 downto 3) = "001" then + OP_I <= ADDX; + elsif IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "010" then + OP_I <= ADD; + elsif IPIPE.D(5 downto 3) /= "111" and IPIPE.D(5 downto 3) /= "001" then + OP_I <= ADD; + end if; + when "101" | "110" => + if IPIPE.D(5 downto 3) = "000" or IPIPE.D(5 downto 3) = "001" then + OP_I <= ADDX; + elsif IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "010" then + OP_I <= ADD; + elsif IPIPE.D(5 downto 3) /= "111" then + OP_I <= ADD; + end if; + when "011" | "111" => + if IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "101" then + OP_I <= ADDA; + elsif IPIPE.D(5 downto 3) /= "111" then + OP_I <= ADDA; + end if; + when others => -- U, X, Z, W, H, L, -. + null; + end case; + when x"E" => -- Shift / Rotate. + if IPIPE.D(11 downto 6) = "000011" and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "010" then + OP_I <= ASR; -- Memory shifts. + elsif IPIPE.D(11 downto 6) = "000011" and IPIPE.D(5 downto 3) > "001" and IPIPE.D(5 downto 3) /= "111" then + OP_I <= ASR; -- Memory shifts. + elsif IPIPE.D(11 downto 6) = "000111" and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "010" then + OP_I <= ASL; -- Memory shifts. + elsif IPIPE.D(11 downto 6) = "000111" and IPIPE.D(5 downto 3) > "001" and IPIPE.D(5 downto 3) /= "111" then + OP_I <= ASL; -- Memory shifts. + elsif IPIPE.D(11 downto 6) = "001011" and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "010" then + OP_I <= LSR; -- Memory shifts. + elsif IPIPE.D(11 downto 6) = "001011" and IPIPE.D(5 downto 3) > "001" and IPIPE.D(5 downto 3) /= "111" then + OP_I <= LSR; -- Memory shifts. + elsif IPIPE.D(11 downto 6) = "001111" and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "010" then + OP_I <= LSL; -- Memory shifts. + elsif IPIPE.D(11 downto 6) = "001111" and IPIPE.D(5 downto 3) > "001" and IPIPE.D(5 downto 3) /= "111" then + OP_I <= LSL; -- Memory shifts. + elsif IPIPE.D(11 downto 6) = "010011" and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "010" then + OP_I <= ROXR; -- Memory shifts. + elsif IPIPE.D(11 downto 6) = "010011" and IPIPE.D(5 downto 3) > "001" and IPIPE.D(5 downto 3) /= "111" then + OP_I <= ROXR; -- Memory shifts. + elsif IPIPE.D(11 downto 6) = "010111" and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "010" then + OP_I <= ROXL; -- Memory shifts. + elsif IPIPE.D(11 downto 6) = "010111" and IPIPE.D(5 downto 3) > "001" and IPIPE.D(5 downto 3) /= "111" then + OP_I <= ROXL; -- Memory shifts. + elsif IPIPE.D(11 downto 6) = "011011" and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "010" then + OP_I <= ROTR; -- Memory shifts. + elsif IPIPE.D(11 downto 6) = "011011" and IPIPE.D(5 downto 3) > "001" and IPIPE.D(5 downto 3) /= "111" then + OP_I <= ROTR; -- Memory shifts. + elsif IPIPE.D(11 downto 6) = "011111" and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "010" then + OP_I <= ROTL; -- Memory shifts. + elsif IPIPE.D(11 downto 6) = "011111" and IPIPE.D(5 downto 3) > "001" and IPIPE.D(5 downto 3) /= "111" then + OP_I <= ROTL; -- Memory shifts. + elsif IPIPE.D(8) = '0' and IPIPE.D(7 downto 6) < "11" and IPIPE.D(4 downto 3) = "00" then + OP_I <= ASR; -- Register shifts. + elsif IPIPE.D(8) = '1' and IPIPE.D(7 downto 6) < "11" and IPIPE.D(4 downto 3) = "00" then + OP_I <= ASL; -- Register shifts. + elsif IPIPE.D(8) = '0' and IPIPE.D(7 downto 6) < "11" and IPIPE.D(4 downto 3) = "01" then + OP_I <= LSR; -- Register shifts. + elsif IPIPE.D(8) = '1' and IPIPE.D(7 downto 6) < "11" and IPIPE.D(4 downto 3) = "01" then + OP_I <= LSL; -- Register shifts. + elsif IPIPE.D(8) = '0' and IPIPE.D(7 downto 6) < "11" and IPIPE.D(4 downto 3) = "10" then + OP_I <= ROXR; -- Register shifts. + elsif IPIPE.D(8) = '1' and IPIPE.D(7 downto 6) < "11" and IPIPE.D(4 downto 3) = "10" then + OP_I <= ROXL; -- Register shifts. + elsif IPIPE.D(8) = '0' and IPIPE.D(7 downto 6) < "11" and IPIPE.D(4 downto 3) = "11" then + OP_I <= ROTR; -- Register shifts. + elsif IPIPE.D(8) = '1' and IPIPE.D(7 downto 6) < "11" and IPIPE.D(4 downto 3) = "11" then + OP_I <= ROTL; -- Register shifts. + end if; + when x"F" => -- 1111, Coprocessor Interface / 68K40 Extensions. + OP_I <= UNIMPLEMENTED; + when others => -- U, X, Z, W, H, L, -. + null; + end case; + end process OP_DECODE; +end BEHAVIOR; diff --git a/common/CPU/68K10/wf68k10_pkg.vhd b/common/CPU/68K10/wf68k10_pkg.vhd new file mode 100644 index 00000000..ee6c7b59 --- /dev/null +++ b/common/CPU/68K10/wf68k10_pkg.vhd @@ -0,0 +1,413 @@ +------------------------------------------------------------------------ +---- ---- +---- WF68K10 IP Core: this is the package file containing the data ---- +---- types and the component declarations. ---- +---- ---- +---- Author(s): ---- +---- Wolfgang Foerster, wf@experiment-s.de; wf@inventronik.de ---- +---- ---- +------------------------------------------------------------------------ +---- ---- +---- Copyright © 2014-2019 Wolfgang Foerster Inventronik GmbH. ---- +---- ---- +---- This documentation describes Open Hardware and is licensed ---- +---- under the CERN OHL v. 1.2. You may redistribute and modify ---- +---- this documentation under the terms of the CERN OHL v.1.2. ---- +---- (http://ohwr.org/cernohl). This documentation is distributed ---- +---- WITHOUT ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING OF ---- +---- MERCHANTABILITY, SATISFACTORY QUALITY AND FITNESS FOR A ---- +---- PARTICULAR PURPOSE. Please see the CERN OHL v.1.2 for ---- +---- applicable conditions ---- +---- ---- +------------------------------------------------------------------------ +-- +-- Revision History +-- +-- Revision 2K14B 20141201 WF +-- Initial Release. +-- Later revisions +-- Modifications according to changes of the entity in other modules. +-- + +library ieee; +use ieee.std_logic_1164.all; + +package WF68K10_PKG is +type OP_SIZETYPE is (LONG, WORD, BYTE); +-- The OPCODES AND, NOT, OR, ROR and ROL are defined keywords in VHDL. Therefore the assignment is +-- AND_B, NOT_B, OR_B, ROTR and ROTL. +type OP_68K is (ABCD, ADD, ADDA, ADDI, ADDQ, ADDX, AND_B, ANDI, ANDI_TO_CCR, ANDI_TO_SR, ASL, ASR, Bcc, BCHG, BCLR, + BKPT, BRA, BSET, BSR, BTST, CHK, CLR, CMP, CMPA, CMPI, CMPM, DBcc, DIVS, DIVU, EOR, EORI, EORI_TO_CCR, + EORI_TO_SR, EXG, EXT, ILLEGAL, JMP, JSR, LEA, LINK, LSL, LSR, MOVE, MOVE_FROM_CCR, MOVE_TO_CCR, + MOVE_FROM_SR, MOVE_TO_SR, MOVE_USP, MOVEA, MOVEC, MOVEM, MOVEP, MOVEQ, MOVES, MULS, MULU, NBCD, NEG, + NEGX, NOP, NOT_B, OR_B, ORI, ORI_TO_CCR, ORI_TO_SR, PEA, RESET, ROTL, ROTR, ROXL, ROXR, RTD, + RTE, RTR, RTS, SBCD, Scc, STOP, SUB, SUBA, SUBI, SUBQ, SUBX, SWAP, TAS, TRAP, TRAPV, TST, + UNLK, UNIMPLEMENTED); + +type TRAPTYPE_OPC is(NONE, T_1010, T_1111, T_ILLEGAL, T_TRAP, T_PRIV, T_RTE); -- None is the first entry and default. + +component WF68K10_ADDRESS_REGISTERS + port ( + CLK : in std_logic; + RESET : in bit; + AR_IN_1 : in std_logic_vector(31 downto 0); + AR_IN_2 : in std_logic_vector(31 downto 0); + AR_OUT_1 : out std_logic_vector(31 downto 0); + AR_OUT_2 : out std_logic_vector(31 downto 0); + INDEX_IN : in std_logic_vector(31 downto 0); + PC : out std_logic_vector(31 downto 0); + PC_EW_OFFSET : in std_logic_vector(3 downto 0); + STORE_ADR_FORMAT : in bit; + STORE_ABS_HI : in bit; + STORE_ABS_LO : in bit; + STORE_D16 : in bit; + STORE_DISPL : in bit; + STORE_AEFF : in bit; + OP_SIZE : in OP_SIZETYPE; + ADR_OFFSET : in std_logic_vector(31 downto 0); + ADR_MARK_USED : in bit; + ADR_IN_USE : out bit; + ADR_MODE : in std_logic_vector(2 downto 0); + AMODE_SEL : in std_logic_vector(2 downto 0); + ADR_EFF : out std_logic_vector(31 downto 0); + ADR_EFF_WB : out std_logic_vector(31 downto 0); + DFC : out std_logic_vector(2 downto 0); + DFC_WR : in bit; + SFC : out std_logic_vector(2 downto 0); + SFC_WR : in bit; + ISP_DEC : in bit; + ISP_WR : in bit; + USP_RD : in bit; + USP_WR : in bit; + AR_MARK_USED : in bit; + USE_APAIR : in boolean; + AR_IN_USE : out bit; + AR_SEL_RD_1 : in std_logic_vector(2 downto 0); + AR_SEL_RD_2 : in std_logic_vector(2 downto 0); + AR_SEL_WR_1 : in std_logic_vector(2 downto 0); + AR_SEL_WR_2 : in std_logic_vector(2 downto 0); + AR_DEC : in bit; + AR_INC : in bit; + AR_WR_1 : in bit; + AR_WR_2 : in bit; + UNMARK : in bit; + EXT_WORD : in std_logic_vector(15 downto 0); + SBIT : in std_logic; + SP_ADD_DISPL : in bit; + RESTORE_ISP_PC : in bit; + DISPLACEMENT : in std_logic_vector(31 downto 0); + PC_ADD_DISPL : in bit; + PC_INC : in bit; + PC_LOAD : in bit; + PC_RESTORE : in bit; + PC_OFFSET : in std_logic_vector(7 downto 0) + ); +end component; + +component WF68K10_ALU + port ( + CLK : in std_logic; + RESET : in bit; + LOAD_OP1 : in bit; + LOAD_OP2 : in bit; + LOAD_OP3 : in bit; + OP1_IN : in std_logic_vector(31 downto 0); + OP2_IN : in std_logic_vector(31 downto 0); + OP3_IN : in std_logic_vector(31 downto 0); + BITPOS_IN : in Std_Logic_Vector(4 downto 0); + RESULT : out std_logic_vector(63 downto 0); + ADR_MODE_IN : in std_logic_vector(2 downto 0); + OP_SIZE_IN : in OP_SIZETYPE; + OP_IN : in OP_68K; + OP_WB : in OP_68K; + BIW_0_IN : in std_logic_vector(11 downto 0); + BIW_1_IN : in std_logic_vector(15 downto 0); + SR_WR : in bit; + SR_INIT : in bit; + CC_UPDT : in bit; + STATUS_REG_OUT : out std_logic_vector(15 downto 0); + ALU_COND : out boolean; + ALU_INIT : in bit; + ALU_BSY : out bit; + ALU_REQ : out bit; + ALU_ACK : in bit; + IRQ_PEND : in std_logic_vector(2 downto 0); + TRAP_CHK : out bit; + TRAP_DIVZERO : out bit + ); +end component; + +component WF68K10_BUS_INTERFACE + port ( + CLK : in std_logic; + ADR_IN_P : in std_logic_vector(31 downto 0); + ADR_OUT_P : out std_logic_vector(31 downto 0); + FC_IN : in std_logic_vector(2 downto 0); + FC_OUT : out std_logic_vector(2 downto 0); + DATA_PORT_IN : in std_logic_vector(15 downto 0); + DATA_PORT_OUT : out std_logic_vector(15 downto 0); + DATA_FROM_CORE : in std_logic_vector(31 downto 0); + DATA_TO_CORE : out std_logic_vector(31 downto 0); + OPCODE_TO_CORE : out std_logic_vector(15 downto 0); + DATA_PORT_EN : out std_logic; + BUS_EN : out std_logic; + OP_SIZE : in OP_SIZETYPE; + RD_REQ : in bit; + WR_REQ : in bit; + DATA_RDY : out bit; + DATA_VALID : out std_logic; + OPCODE_REQ : in bit; + OPCODE_RDY : out bit; + OPCODE_VALID : out std_logic; + RMC : in bit; + BUSY_EXH : in bit; + INBUFFER : out std_logic_vector(31 downto 0); + OUTBUFFER : out std_logic_vector(31 downto 0); + SSW : out std_logic_vector(15 downto 0); + DTACKn : in std_logic; + ASn : out std_logic; + UDSn : out std_logic; + LDSn : out std_logic; + RWn : out std_logic; + RMCn : out std_logic; + DBENn : out std_logic; + E : out std_logic; + VMAn : out std_logic; + VMA_EN : out std_logic; + VPAn : in std_logic; + BRn : in std_logic; + BGACKn : in std_logic; + BGn : out std_logic; + RESET_STRB : in bit; + RESET_IN : in std_logic; + RESET_OUT : out std_logic; + RESET_CPU : out bit; + AVECn : in std_logic; + HALTn : in std_logic; + BERRn : in std_logic; + AERR : out bit; + BUS_BSY : out bit + ); +end component; + +component WF68K10_CONTROL + generic(NO_PIPELINE : boolean := false); -- If true the controller work in scalar mode. + port( + CLK : in std_logic; + RESET_CPU : in bit; + BUSY : out bit; + BUSY_EXH : in bit; + EXH_REQ : in bit; + INT_TRIG : out bit; + OW_REQ : out bit; + OW_VALID : in std_logic; + EW_REQ : out bit; + EW_ACK : in bit; + OPD_ACK : in bit; + ADR_MARK_USED : out bit; + ADR_IN_USE : in bit; + ADR_OFFSET : out std_logic_vector(5 downto 0); + DATA_RD : out bit; + DATA_WR : out bit; + DATA_RDY : in bit; + DATA_VALID : in std_logic; + RMC : out bit; + LOAD_OP2 : out bit; + LOAD_OP3 : out bit; + LOAD_OP1 : out bit; + STORE_ADR_FORMAT : out bit; + STORE_D16 : out bit; + STORE_DISPL : out bit; + STORE_ABS_HI : out bit; + STORE_ABS_LO : out bit; + STORE_AEFF : out bit; + STORE_IDATA_B2 : out bit; + STORE_IDATA_B1 : out bit; + OP : in OP_68K; + OP_SIZE : out OP_SIZETYPE; + BIW_0 : in std_logic_vector(13 downto 0); + BIW_1 : in std_logic_vector(15 downto 0); + EXT_WORD : in std_logic_vector(15 downto 0); + ADR_MODE : out std_logic_vector(2 downto 0); + AMODE_SEL : out std_logic_vector(2 downto 0); + OP_WB : out OP_68K; + OP_SIZE_WB : out OP_SIZETYPE; + BIW_0_WB_73 : out std_logic_vector(7 downto 3); + AR_MARK_USED : out bit; + USE_APAIR : out boolean; + AR_IN_USE : in bit; + AR_SEL_RD_1 : out std_logic_vector(2 downto 0); + AR_SEL_RD_2 : out std_logic_vector(2 downto 0); + AR_SEL_WR_1 : out std_logic_vector(2 downto 0); + AR_SEL_WR_2 : out std_logic_vector(2 downto 0); + AR_INC : out bit; + AR_DEC : out bit; + AR_WR_1 : out bit; + AR_WR_2 : out bit; + DR_MARK_USED : out bit; + USE_DPAIR : out boolean; + DR_IN_USE : in bit; + DR_SEL_RD_1 : out std_logic_vector(2 downto 0); + DR_SEL_RD_2 : out std_logic_vector(2 downto 0); + DR_SEL_WR_1 : out std_logic_vector(2 downto 0); + DR_SEL_WR_2 : out std_logic_vector(2 downto 0); + DR_WR_1 : out bit; + DR_WR_2 : out bit; + UNMARK : out bit; + DISPLACEMENT : out std_logic_vector(31 downto 0); + PC_ADD_DISPL : out bit; + PC_LOAD : out bit; + PC_INC_EXH : in bit; + SP_ADD_DISPL : out bit; + DFC_WR : out bit; + DFC_RD : out bit; + SFC_WR : out bit; + SFC_RD : out bit; + VBR_WR : out bit; + VBR_RD : out bit; + USP_RD : out bit; + USP_WR : out bit; + IPIPE_FLUSH : out bit; + ALU_INIT : out bit; + ALU_BSY : in bit; + ALU_REQ : in bit; + ALU_ACK : out bit; + BKPT_CYCLE : out bit; + BKPT_INSERT : out bit; + LOOP_BSY : in bit; + LOOP_SPLIT : out boolean; + LOOP_EXIT : out bit; + SR_WR : out bit; + MOVEM_ADn : out bit; + MOVEP_PNTR : out integer range 0 to 3; + CC_UPDT : out bit; + TRACE_EN : in std_logic; + ALU_COND : in boolean; + DBcc_COND : in boolean; + BRANCH_ATN : in bit; + RESET_STRB : out bit; + BERR : out bit; + EX_TRACE : out bit; + TRAP_ILLEGAL : out bit; + TRAP_V : out bit + ); +end component; + +component WF68K10_DATA_REGISTERS + port ( + CLK : in std_logic; + RESET : in bit; + DR_IN_1 : in std_logic_vector(31 downto 0); + DR_IN_2 : in std_logic_vector(31 downto 0); + DR_OUT_1 : out std_logic_vector(31 downto 0); + DR_OUT_2 : out std_logic_vector(31 downto 0); + DR_SEL_WR_1 : in std_logic_vector(2 downto 0); + DR_SEL_WR_2 : in std_logic_vector(2 downto 0); + DR_SEL_RD_1 : in std_logic_vector(2 downto 0); + DR_SEL_RD_2 : in std_logic_vector(2 downto 0); + DR_WR_1 : in bit; + DR_WR_2 : in bit; + DR_MARK_USED : in bit; + USE_DPAIR : in boolean; + DR_IN_USE : out bit; + UNMARK : in bit; + OP_SIZE : in OP_SIZETYPE + ); +end component; + +component WF68K10_EXCEPTION_HANDLER + generic(VERSION : std_logic_vector(31 downto 0)); + port ( + CLK : in std_logic; + RESET : in bit; + K6800n : in std_logic; + BUSY_MAIN : in bit; + BUSY_OPD : in bit; + EXH_REQ : out bit; + BUSY_EXH : out bit; + ADR_IN : in std_logic_vector(31 downto 0); + ADR_OFFSET : out std_logic_vector(31 downto 0); + CPU_SPACE : out bit; + DATA_0 : in std_logic; + DATA_RD : out bit; + DATA_WR : out bit; + DATA_IN : in std_logic_vector(31 downto 0); + OP_SIZE : out OP_SIZETYPE; + DATA_RDY : in bit; + DATA_VALID : in std_logic; + OPCODE_RDY : in bit; + STATUS_REG_IN : in std_logic_vector(15 downto 0); + SR_CPY : out std_logic_vector(15 downto 0); + SR_INIT : out bit; + SR_WR : out bit; + ISP_DEC : out bit; + ISP_LOAD : out bit; + PC_INC : out bit; + PC_LOAD : out bit; + PC_RESTORE : out bit; + STACK_FORMAT : out std_logic_vector(3 downto 0); + STACK_POS : out integer range 0 to 31; + SP_ADD_DISPL : out bit; + DISPLACEMENT : out std_logic_vector(7 downto 0); + IPIPE_FILL : out bit; + IPIPE_FLUSH : out bit; + RESTORE_ISP_PC : out bit; + HALT_OUTn : out std_logic; + INT_TRIG : in bit; + IRQ_IN : in std_logic_vector(2 downto 0); + IRQ_PEND : out std_logic_vector(2 downto 0); + AVECn : in std_logic; + IVECT_OFFS : out std_logic_vector(9 downto 0); + TRAP_AERR : in bit; + TRAP_BERR : in bit; + TRAP_CHK : in bit; + TRAP_DIVZERO : in bit; + TRAP_ILLEGAL : in bit; + TRAP_CODE_OPC : in TRAPTYPE_OPC; + TRAP_VECTOR : in std_logic_vector(3 downto 0); + TRAP_V : in bit; + EX_TRACE_IN : in bit; + VBR_WR : in bit; + VBR : out std_logic_vector(31 downto 0) + ); +end component; + +component WF68K10_OPCODE_DECODER + generic(NO_LOOP : boolean := false); -- If true the DBcc loop mechanism is disabled. + port ( + CLK : in std_logic; + K6800n : in std_logic; + OW_REQ_MAIN : in bit; + EW_REQ_MAIN : in bit; + EXH_REQ : in bit; + BUSY_EXH : in bit; + BUSY_MAIN : in bit; + BUSY_OPD : out bit; + BKPT_INSERT : in bit; + BKPT_DATA : in std_logic_vector(15 downto 0); + LOOP_EXIT : in bit; + LOOP_BSY : out bit; + OPD_ACK_MAIN : out bit; + EW_ACK : out bit; + PC_EW_OFFSET : out std_logic_vector(3 downto 0); + PC_INC : out bit; + PC_INC_EXH : in bit; + PC_ADR_OFFSET : out std_logic_vector(7 downto 0); + PC_OFFSET : out std_logic_vector(7 downto 0); + OPCODE_RD : out bit; + OPCODE_RDY : in bit; + OPCODE_VALID : in std_logic; + OPCODE_DATA : in std_logic_vector(15 downto 0); + IPIPE_FILL : in bit; + IPIPE_FLUSH : in bit; + OW_VALID : out std_logic; + SBIT : in std_logic; + TRAP_CODE : out TRAPTYPE_OPC; + OP : out OP_68K; + BIW_0 : out std_logic_vector(15 downto 0); + BIW_1 : out std_logic_vector(15 downto 0); + BIW_2 : out std_logic_vector(15 downto 0); + EXT_WORD : out std_logic_vector(15 downto 0) + ); +end component; +end WF68K10_PKG; diff --git a/common/CPU/68K10/wf68k10_top.vhd b/common/CPU/68K10/wf68k10_top.vhd new file mode 100644 index 00000000..b95b7d56 --- /dev/null +++ b/common/CPU/68K10/wf68k10_top.vhd @@ -0,0 +1,1257 @@ +------------------------------------------------------------------------ +---- ---- +---- This is the top level structural design unit of the 68K10 ---- +---- complex instruction set (CISC) microcontroller. It's program- ---- +---- ming model is (hopefully) fully compatible with Motorola's ---- +---- MC68010. This core features a pipelined architecture. In com- ---- +---- parision to the 68K10 the core supports a 32 bit wide adress ---- +---- bus. The processor generates the stack frame format 0, 2, A, B ---- +---- according to the 68K10 CPU. There is also support for multi- ---- +---- processor environments due to the RMCn signal. In conjunction ---- +---- with the 32 bit wide address bus this core is fully feature ---- +---- complete in comparision to the MC68012 processors. ---- +---- The DIVS, DIVU, MULS, MULU with LONG format is supported by ---- +---- this core. +---- ---- +---- Compatibility to the 68K00: ---- +---- The 68K10 is pin compatible with the 68K00 but it is not 100% ---- +---- software compatible due to differences in the programming ---- +---- model. The differences in detail are: ---- +---- 1. The following differences are implemented in this core but ---- +---- do not affect the 68K00 compatibility: ---- +---- The 68K00 does not feature A vector base register (VBR). ---- +---- The 68K00 does not feature the BKPT instruction. ---- +---- The 68K00 does not feature the MOVE_FROM_CCR instruction. ---- +---- The 68K00 does not feature the MOVEC instruction. ---- +---- The 68K00 does not feature the MOVES instruction. ---- +---- The 68K00 does not feature the RTD instruction. ---- +---- The 68K10 stack frames are more complex but backward ---- +---- compatible to the 68K00. ---- +---- 2. The following differences are implemented in this core and ---- +---- do affect the 68K00 compatibility: ---- +---- The MOVE_FROM_SR instruction is priviledged for the 68K10 ---- +---- but is not priviledged for the 68K00. To gain compati- ---- +---- bility the K6800n signal driven low deactivates the pri- ---- +---- viledged mechanism for this instruction. ---- +---- This core features the loop operation mode of the 68010. ---- +---- ---- +---- The signal K6800n driven low controls all affected hardware to ---- +---- meet the MC68000 compatibility. K6800n driven high switches to ---- +---- MC68010 compatibility. Beside the control of somepriviledged ---- +---- instructions there are also the stack frame and operand sizes ---- +---- and othe minor differences affected. ---- +---- ---- +---- Enjoy. ---- +---- ---- +---- Author(s): ---- +---- - Wolfgang Foerster, wf@experiment-s.de; wf@inventronik.de ---- +---- ---- +------------------------------------------------------------------------ +---- ---- +---- Copyright © 2014-2019 Wolfgang Foerster Inventronik GmbH. ---- +---- ---- +---- This documentation describes Open Hardware and is licensed ---- +---- under the CERN OHL v. 1.2. You may redistribute and modify ---- +---- this documentation under the terms of the CERN OHL v.1.2. ---- +---- (http://ohwr.org/cernohl). This documentation is distributed ---- +---- WITHOUT ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING OF ---- +---- MERCHANTABILITY, SATISFACTORY QUALITY AND FITNESS FOR A ---- +---- PARTICULAR PURPOSE. Please see the CERN OHL v.1.2 for ---- +---- applicable conditions ---- +---- ---- +------------------------------------------------------------------------ +-- +-- Revision History +-- +-- Revision 2K14B 20141201 WF +-- Initial Release. +-- Revision 2K16A 20160620 WF +-- Control section: fixed a bug in the MOVEM operation. Thanks to Raymond Mounissamy. +-- Address section: minor optimizations. +-- Address section: fixed a bug in PC_LOAD. +-- Top level: fixed the AR_IN_1 multiplexer. +-- Control: Break the DBcc_LOOP when the exception handler is busy (see process P_LOOP). +-- Opcode decoder: Break the DBcc_LOOP when the exception handler is busy (see process P_LOOP). +-- Revision 2K18A (unreleased) WF +-- Bus interface: Fixed a bug in the DATA_PORT_OUT multiplexer. Thanks to Gary Bingham for the support. +-- Bus interface: Fixed a bug in the DATA_INMUX multiplexer. Thanks to Gary Bingham for the support. +-- Control: Fixed a bug in MOVE An,-(Ay). Thanks to Gary Bingham for the support. +-- Top: changed ALU_OP1_IN multiplexer due to MOVE An,-(Ay) bug. +-- Address registers: Changed ADR_ATN logic to be valid one clock cycle earlier. +-- Top: bug fix: in MOVEM -(An) the initial addressing register is now written to memory. +-- Top: Correction in the BKPT address format: +-- Bus interface: RESET is now 124 instead of 512 clock cycles. +-- Top / Opdecoder / Exhandler: Removed REST_BIW_0. +-- Top: Adjusted exception frame data to 68K10. +-- Bus interface: Adjusted the SSW to 68K10. +-- Bus interface / Control: Removed RERUN_RMC. +-- Exception handler: Removed FC_OUT. +-- Exception handler: Removed ADR_CPY. +-- Exception handler: Removed PC_OFFSET. +-- Opcode decoder: Several minor improvements to meet better 68000 compatibility. +-- ALU: Bug fix: MOVEM sign extension. +-- Removed FB, FC, RB, RC and PC_REG from the design. +-- Control: Fixed wrong PEA behaviour. +-- Control: Fixed the displacement for LINK. +-- ALU: Fix for restoring correct values during the DIVS and DIVU in word format. +-- Opcode decoder: Removed illegal MOVEC control register patterns. +-- Control: Fixed the operation size for MOVEQ. +-- Control: ADDQ, SUBQ Fix: address registers are always written long. +-- Top, exception handler, address registers: Fixed PC restoring during exception processing. +-- Control: ADDI, ANDI, EORI, ORI, SUBI: address is not marked used if destination is Dn. +-- Control: ADDI, ANDI, EORI, ORI, SUBI: data register is marked used if destination is Dn. +-- Bus interface: Suppress bus faults during RESET instruction. +-- Bus interface: Optimized ASn and DSn timing for synchronous RAM. +-- Top: PC_OFFSET_OPD is now PC_OFFSET. +-- ALU: Fixed the SUBQ calculation. +-- Opcode decoder: Fixed the PW_EW_OFFSET calculation for JSR. +-- Top: fixed the value of DATA_IMMEDIATE for ADDQ and SUBQ in case of #8. +-- ALU: Rearanged the Offset for the JSR instruction. +-- Control: Fixed AR_MARK_USED in LINK. +-- ALU: EXT instruction uses now RESULT(63 downto 0). +-- Top: Introduced OP_WB form the control unit. +-- Top: Rearanged the AR_IN_1 multiplexer to avoid data hazards. +-- Top: Rearanged the AR_IN_2 multiplexer to avoid data hazards. +-- Top: Rearanged the DR_IN_1 multiplexer to avoid data hazards. +-- Top: Rearanged the DR_IN_2 multiplexer to avoid data hazards. +-- EXG: rearanged logic to meet the new top level multiplexers. +-- Control: LINK, UNLK: wait in START_OP until the ALU is ready (avoids possible data hazards). +-- Top: ALU_OP1_IN to meet the new EXG multiplexers. +-- Top: ALU_OP2_IN to meet the new EXG multiplexers. +-- Address registers: Fixed the writing of ISP_REG during EXG instruction with two address registers. +-- Control: MOVEM: Fixed predecrement mode for consecutive MOVEM -(An). +-- Control: MOVEP: MOVEP_PNTR is now correct for consecutive MOVEP. +-- Control: MOVEP: avoid structural hazard in SWITCH_STATE by waiting for ALU. +-- Control: LINK, UNLK: fixed the write back operation size. +-- Opcode decoder: Fixed PC_OFFSET value in case the exception handler send LOOP_EXIT. +-- Exception handler: Fixed the vector calculation of INT vectors. +-- Exception handler: Fixed faulty modelling in IRQ_FILTER. +-- Exception handler: Implemented the AVEC_FILTER to better meet bus timings. +-- Control: EOR: fixed a bug in the writeback mechanism. +-- Control: BSR, JSR: EXEC_WB state machine waits now for ALU_INIT. Avoid structural / data hazard. +-- Control: the instruction pipe is not flushed for MOVE_FROM_CCR, MOVE_FROM_SR, MOVE_USP, MOVEC. +-- ALU: Shifter signals now ready if shift width is zero. +-- Control: Modifications in the FETCH state machine to avoid several data hazards for MOVEM, MOVE_FROM_CCR, MOVE_FROM_SR. +-- Control: Modifications in the FETCH state machine to avoid several data hazards for ANDI_TO_CCR, ANDI_TO_SR, EORI_TO_CCR, EORI_TO_SR, ORI_TO_CCR, ORI_TO_SR. +-- Exception handler: The RTE exception has now highest priority (avoids mismatch). +-- Control: Bugfix: the condition codes were not updated if there was a pending interrupt. +-- Control: We have to stop a pending operation in case of a pending interrupt. This is done by rejecting OW_RDY. +-- TOP, Control, Exception handler Opcode Decoder: Rearanged PC_INC and ipipe flush logic. +-- Bus interface: DATA_PORT_EN timing optimization. +-- Bus interface: BUS_EN is now active except during arbitration. +-- Control: Write the undecremented Register for MOVE Ax, -(Ax). +-- Control: LINK A7 and PEA(A7) stacks the undecremented A7. +-- Bus interface: Rearanged the DATA_RDY vs. BUS_FLT logic. +-- ALU: Fixed wrong condition codes for AND_B, ANDI, EOR, EORI, OR_B, ORI and NOT_B. +-- Exception handler: Update the IRQ mask only for RESET and interrupts. +-- Bus interface: Opted out START_READ and CHK_RD. +-- Control: UNMARK is now asserted in the end of the write cycle. This avoids data hazards. +-- Exception handler: external interrupts are postponed if any system controllers are in initialize operation status. +-- ALU: Fixed writeback issues in the status register logic. +-- ALU: Fixed writing the stack pointer registers (SBIT_WB is used instead of SBIT). +-- Control: Fixed a MOVEC writeback issue (use BIW_WB... instead of BIW_...). +-- Control: Fixed a USP writeback issue (use BIW_WB... instead of BIW_...). +-- ALU, TOP: Fixed the condition code calculation for NEG and NEGX. +-- ALU: the address registers are always written long. +-- Top: opted out SBIT_AREG. +-- Address register bugfix: exception handler do not increment and decrement the USP any more. +-- Control: Introduced a switch NO_PIPELINE. +-- Address registers, Control: MOVEM-Fix see STORE_AEFF. +-- Control: DBcc: fixed a data hazard for DBcc_COND evaluation by waiting on the ALU result. +-- Control: Fixed DR_WR_1 locking against AR_WR_2. +-- Control: IPIPE is flushed, when there is a memory space change in the end of xx_TO_SR operations. +-- Control: To handle correct addressing, ADR_OFFSET is now cleared right in the end of the respective operation. +-- Control: Fixed a bug in EOR writing back in register direct mode. +-- ALU: Fixed a bug in MULU.W (input operands are now 16 bit wide). +-- Control: ADDQ and SUBQ: fixed (An)+ mode. An increments now. +-- Control: Fixed DIVS, DIVU in memory address modes (wrong control flow). +-- Control: ADDQ and SUBQ: fixed condition code control UPDT_CC. +-- Control: fixed a data hazard bug using addressing modes with index register. +-- Bus interface: UDSn and LDSn are now always enabled for opcode cycles (bugfix). +-- Opcode decoder: Rewritten DBcc loop. +-- Control: Rewritten DBcc loop for split loops. +-- Toplevel: changes for split loop operation. +-- Opcode decoder: Fix for unimplemented or illegal operations: PC is increased before stacked. +-- Exception handler: RTE now loads the address offset correctly when entering the handler. +-- Control: BTST: fixed (d16,Ax) addressing mode. +-- Bus interface: Fixed the faulty bus arbitration logic. +-- Opcode decoder: Removed CAHR, we have no cache. +-- Top: Removed a data hazard in the DR_IN_1 multiplexer (EXG operation). +-- Revision 2K19A 20190419 WF +-- For bug fixes and code optimizations see the RevisionHistory in the source code directory. +-- New feature: Branch prediction for the status register manipulation operations (BRANCH_ATN). +-- New fetch state CALC_AEFF which results in no need of ADR_ATN and a twice higher fmax. +-- Revision 2K19B 20191224 WF +-- Control: NOP explicitely synchronizes the instruction pipe now. +-- Opcode decoder: introduced signal synchronization in the P_BSY process to avoid malfunction by hazards. +-- Exception handler: introduced signal synchronization in the P_D process to avoid malfunction by hazards. +-- Top level, exception handler: the processor VERSION is now 32 bit wide. +-- Control: BUSY is now asserted when an opword is loaded and we have to wait in START_OP (avoids other controllers to reload the opword, see OW_REQ). +-- Control: removed a data hazard condition (A7) for JSR, PEA, LINK and UNLK in the beginning of the operation. +-- Address section: fixed the condition if UNMARK and AR_MARK_USED are asserted simultaneously (see process P_IN_USE). +-- Revision 2K20A 20200620 WF +-- Bus interface: ASn and DSn are not asserted in S0 any more. +-- Bus interface: some modifications to optimize the RETRY logic. +-- + +library work; +use work.WF68K10_PKG.all; + +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_unsigned.all; + +entity WF68K10_TOP is + generic( + VERSION : std_logic_vector(31 downto 0) := x"20191224"; -- CPU version number. + -- The following two switches are for debugging purposes. Default for both is false. + NO_PIPELINE : boolean := false; -- If true the main controller work in scalar mode. + NO_LOOP : boolean := false); -- If true the DBcc loop mechanism is disabled. + + port ( + CLK : in std_logic; + + -- Address and data: + ADR_OUT : out std_logic_vector(31 downto 0); + DATA_IN : in std_logic_vector(15 downto 0); + DATA_OUT : out std_logic_vector(15 downto 0); + DATA_EN : out std_logic; -- Enables the data port. + + -- System control: + BERRn : in std_logic; + RESET_INn : in std_logic; + RESET_OUT : out std_logic; -- Open drain. + HALT_INn : in std_logic; + HALT_OUTn : out std_logic; -- Open drain. + + -- Processor status: + FC_OUT : out std_logic_vector(2 downto 0); + + -- Interrupt control: + AVECn : in std_logic; + IPLn : in std_logic_vector(2 downto 0); + + -- Aynchronous bus control: + DTACKn : in std_logic; + ASn : out std_logic; + RWn : out std_logic; + RMCn : out std_logic; + UDSn : out std_logic; + LDSn : out std_logic; + DBENn : out std_logic; -- Data buffer enable. + BUS_EN : out std_logic; -- Enables ADR, ASn, UDSn, LDSn, RWn, RMCn and FC. + + -- Synchronous peripheral control: + E : out std_logic; + VMAn : out std_logic; + VMA_EN : out std_logic; + VPAn : in std_logic; + + -- Bus arbitration control: + BRn : in std_logic; + BGn : out std_logic; + BGACKn : in std_logic; + + -- Other controls: + K6800n : in std_logic -- Assert for 68K00 compatibility. + ); +end entity WF68K10_TOP; + +architecture STRUCTURE of WF68K10_TOP is +signal ADn : bit; +signal ADR_EFF : std_logic_vector(31 downto 0); +signal ADR_EFF_WB : std_logic_vector(31 downto 0); +signal ADR_L : std_logic_vector(31 downto 0); +signal ADR_LATCH : std_logic_vector(31 downto 0); +signal ADR_MODE : std_logic_vector(2 downto 0); +signal ADR_MODE_MAIN : std_logic_vector(2 downto 0); +signal ADR_IN_USE : bit; +signal ADR_OFFSET : std_logic_vector(31 downto 0); +signal ADR_OFFSET_EXH : std_logic_vector(31 downto 0); +signal ADR_OFFSET_MAIN : std_logic_vector(5 downto 0); +signal ADR_P : std_logic_vector(31 downto 0); +signal ADR_MARK_UNUSED_MAIN : bit; +signal ADR_MARK_USED : bit; +signal AERR : bit; +signal ALU_ACK : bit; +signal ALU_BSY : bit; +signal ALU_COND : boolean; +signal ALU_INIT : bit; +signal ALU_LOAD_OP1 : bit; +signal ALU_LOAD_OP2 : bit; +signal ALU_LOAD_OP3 : bit; +signal ALU_OP1_IN : std_logic_vector(31 downto 0); +signal ALU_OP2_IN : std_logic_vector(31 downto 0); +signal ALU_OP3_IN : std_logic_vector(31 downto 0); +signal ALU_REQ : bit; +signal ALU_RESULT : std_logic_vector(63 downto 0); +signal AMODE_SEL : std_logic_vector(2 downto 0); +signal AR_DEC : bit; +signal AR_CPY : std_logic_vector(31 downto 0); +signal AR_IN_1 : std_logic_vector(31 downto 0); +signal AR_IN_2 : std_logic_vector(31 downto 0); +signal AR_IN_USE : bit; +signal AR_INC : bit; +signal AR_MARK_USED : bit; +signal AR_OUT_1 : std_logic_vector(31 downto 0); +signal AR_OUT_2 : std_logic_vector(31 downto 0); +signal AR_SEL_RD_1 : std_logic_vector(2 downto 0); +signal AR_SEL_RD_1_MAIN : std_logic_vector(2 downto 0); +signal AR_SEL_RD_2 : std_logic_vector(2 downto 0); +signal AR_SEL_WR_1 : std_logic_vector(2 downto 0); +signal AR_SEL_WR_2 : std_logic_vector(2 downto 0); +signal AR_WR_1 : bit; +signal AR_WR_2 : bit; +signal AVECn_BUSIF : std_logic; +signal BERR_MAIN : bit; +signal BITPOS : std_logic_vector(4 downto 0); +signal BIW_0 : std_logic_vector(15 downto 0); +signal BIW_0_WB_73 : std_logic_vector(7 downto 3); +signal BIW_1 : std_logic_vector(15 downto 0); +signal BIW_2 : std_logic_vector(15 downto 0); +signal BKPT_CYCLE : bit; +signal BKPT_INSERT : bit; +signal BRANCH_ATN : bit; +signal BUS_BSY : bit; +signal BUSY_EXH : bit; +signal BUSY_MAIN : bit; +signal BUSY_OPD : bit; +signal BUSY_OPD_I : bit; +signal CC_UPDT : bit; +signal CPU_SPACE : bit; +signal CPU_SPACE_EXH : bit; +signal DFC : std_logic_vector(2 downto 0); +signal DFC_RD : bit; +signal DFC_WR : bit; +signal DR_MARK_USED : bit; +signal DATA_FROM_CORE : std_logic_vector(31 downto 0); +signal DATA : std_logic_vector(31 downto 0); +signal DATA_IN_EXH : std_logic_vector(31 downto 0); +signal DATA_IMMEDIATE : std_logic_vector(31 downto 0); +signal DATA_EXH : std_logic_vector(31 downto 0); +signal DATA_RD : bit; +signal DATA_WR : bit; +signal DATA_RD_EXH : bit; +signal DATA_WR_EXH : bit; +signal DATA_RD_MAIN : bit; +signal DATA_WR_MAIN : bit; +signal DATA_RDY : bit; +signal DATA_TO_CORE : std_logic_vector(31 downto 0); +signal DATA_VALID : std_logic; +signal DISPLACEMENT : std_logic_vector(31 downto 0); +signal DISPLACEMENT_MAIN : std_logic_vector(31 downto 0); +signal DISPLACEMENT_EXH : std_logic_vector(7 downto 0); +signal DATA_BUFFER : std_logic_vector(31 downto 0); +signal DBcc_COND : boolean; +signal DR_IN_1 : std_logic_vector(31 downto 0); +signal DR_IN_2 : std_logic_vector(31 downto 0); +signal DR_IN_USE : bit; +signal DR_OUT_2 : std_logic_vector(31 downto 0); +signal DR_OUT_1 : std_logic_vector(31 downto 0); +signal DR_SEL_WR_1 : std_logic_vector(2 downto 0); +signal DR_SEL_WR_2 : std_logic_vector(2 downto 0); +signal DR_SEL_RD_1 : std_logic_vector(2 downto 0); +signal DR_SEL_RD_2 : std_logic_vector(2 downto 0); +signal DR_WR_1 : bit; +signal DR_WR_2 : bit; +signal EW_ACK : bit; +signal EW_REQ_MAIN : bit; +signal EX_TRACE : bit; +signal EXEC_RDY : bit; +signal EXH_REQ : bit; +signal EXT_WORD : std_logic_vector(15 downto 0); +signal FAULT_ADR : std_logic_vector(31 downto 0); +signal FC_I : std_logic_vector(2 downto 0); +signal FC_LATCH : std_logic_vector(2 downto 0); +signal FC_OUT_I : std_logic_vector(2 downto 0); +signal IBUFFER : std_logic_vector(31 downto 0); +signal INBUFFER : std_logic_vector(31 downto 0); +signal INT_TRIG : bit; +signal IPL : std_logic_vector(2 downto 0); +signal ISP_DEC : bit; +signal ISP_LOAD : bit; +signal IVECT_OFFS : std_logic_vector(9 downto 0); +signal IRQ_PEND : std_logic_vector(2 downto 0); +signal IPIPE_FILL : bit; +signal IPIPE_FLUSH : bit; +signal IPIPE_FLUSH_EXH : bit; +signal IPIPE_FLUSH_MAIN : bit; +signal IPIPE_OFFESET : std_logic_vector(2 downto 0); +signal LOOP_BSY : bit; +signal LOOP_SPLIT : boolean; +signal LOOP_EXIT : bit; +signal MOVEP_PNTR : integer range 0 to 3; +signal OPCODE_RD : bit; +signal OPCODE_RDY : bit; +signal OPCODE_VALID : std_logic; +signal OPCODE_TO_CORE : std_logic_vector(15 downto 0); +signal OP_SIZE : OP_SIZETYPE; +signal OP_SIZE_BUS : OP_SIZETYPE; +signal OP_SIZE_EXH : OP_SIZETYPE; +signal OP_SIZE_MAIN : OP_SIZETYPE; +signal OP_SIZE_WB : OP_SIZETYPE; -- Writeback. +signal OPCODE_REQ : bit; +signal OPCODE_REQ_I : bit; +signal OW_VALID : std_logic; +signal OPD_ACK_MAIN : bit; +signal OP : OP_68K; +signal OP_WB : OP_68K; +signal OW_REQ_MAIN : bit; +signal OUTBUFFER : std_logic_vector(31 downto 0); +signal PC : std_logic_vector(31 downto 0); +signal PC_ADD_DISPL : bit; +signal PC_ADR_OFFSET : std_logic_vector(7 downto 0); +signal PC_EW_OFFSET : std_logic_vector(3 downto 0); +signal PC_INC : bit; +signal PC_INC_EXH : bit; +signal PC_INC_EXH_I : bit; +signal PC_L : std_logic_vector(31 downto 0); +signal PC_LOAD : bit; +signal PC_LOAD_EXH : bit; +signal PC_LOAD_MAIN : bit; +signal PC_OFFSET : std_logic_vector(7 downto 0); +signal PC_RESTORE_EXH : bit; +signal RD_REQ : bit; +signal RD_REQ_I : bit; +signal RMC : bit; +signal RESTORE_ISP_PC : bit; +signal RESET_CPU : bit; +signal RESET_IN : std_logic; +signal RESET_STRB : bit; +signal SP_ADD_DISPL : bit; +signal SP_ADD_DISPL_EXH : bit; +signal SP_ADD_DISPL_MAIN : bit; +signal SBIT : std_logic; +signal SSW : std_logic_vector(15 downto 0); +signal SFC : std_logic_vector(2 downto 0); +signal SFC_RD : bit; +signal SFC_WR : bit; +signal SR_CPY : std_logic_vector(15 downto 0); +signal SR_RD : bit; +signal SR_INIT : bit; +signal SR_WR : bit; +signal SR_WR_EXH : bit; +signal SR_WR_MAIN : bit; +signal STACK_FORMAT : std_logic_vector(3 downto 0); +signal STACK_POS : integer range 0 to 31; +signal STATUS_REG : std_logic_vector(15 downto 0); +signal STORE_ADR_FORMAT : bit; +signal STORE_ABS_HI : bit; +signal STORE_ABS_LO : bit; +signal STORE_AEFF : bit; +signal STORE_D16 : bit; +signal STORE_DISPL : bit; +signal STORE_IDATA_B1 : bit; +signal STORE_IDATA_B2 : bit; +signal TRAP_AERR : bit; +signal TRAP_ILLEGAL : bit; +signal TRAP_CODE_OPC : TRAPTYPE_OPC; +signal TRAP_CHK : bit; +signal TRAP_DIVZERO : bit; +signal TRAP_V : bit; +signal UNMARK : bit; +signal USE_APAIR : boolean; +signal USE_DFC : bit; +signal USE_SFC : bit; +signal USE_DPAIR : boolean; +signal USP_RD : bit; +signal USP_WR : bit; +signal VBR : std_logic_vector(31 downto 0); +signal VBR_WR : bit; +signal VBR_RD : bit; +signal WR_REQ : bit; +signal WR_REQ_I : bit; +-- Debugging: +signal DEBUG_TRIGGER : bit; +signal DEBUG_STAMP : std_logic_vector(31 downto 0); +begin + DEBUGGING : process + -- The DEBUG_STAMP register is intended + -- to count the instructions already passed. + -- The DEBUG_TRIGGER logic is a kind of a + -- breakpoint mechanism. It blocks the + -- main control state machine and thus halts + -- the system. + variable TRAPCNT : std_logic_vector(7 downto 0); + begin + wait until CLK = '1' and CLK' event; + if RESET_CPU = '1' then + DEBUG_STAMP <= x"00000000"; + --elsif PC_INC = '1' then + elsif PC_INC = '1' then + DEBUG_STAMP <= DEBUG_STAMP + '1'; + end if; + + -- Use this to detect a PC address. + --if RESET_CPU = '1' then + -- -DEBUG_TRIGGER <= '0'; + --elsif PC = x"00E0CB90" then -- screen_init. + -- -DEBUG_TRIGGER <= '1'; + --end if; + + -- Try this to detect not allowed register + -- controls. + --if RESET_CPU = '1' then + -- DEBUG_TRIGGER <= '0'; + --elsif AR_WR_1 = '1' and AR_INC = '1' then + -- DEBUG_TRIGGER <= '1'; + --elsif AR_WR_2 = '1' and AR_INC = '1' then + -- DEBUG_TRIGGER <= '1'; + --elsif AR_WR_1 = '1' and AR_DEC = '1' then + -- DEBUG_TRIGGER <= '1'; + --elsif AR_WR_2 = '1' and AR_DEC = '1' then + -- DEBUG_TRIGGER <= '1'; + --elsif AR_WR_1 = '1' and ISP_DEC = '1' then + -- DEBUG_TRIGGER <= '1'; + --elsif AR_WR_2 = '1' and ISP_DEC = '1' then + -- DEBUG_TRIGGER <= '1'; + --elsif AR_WR_1 = '1' and ISP_LOAD = '1' then + -- DEBUG_TRIGGER <= '1'; + --elsif AR_WR_2 = '1' and ISP_LOAD = '1' then + -- DEBUG_TRIGGER <= '1'; + --elsif ISP_LOAD = '1' and ISP_DEC = '1' then + -- DEBUG_TRIGGER <= '1'; + --elsif PC_LOAD = '1' and PC_INC = '1' then + -- DEBUG_TRIGGER <= '1'; + --end if; + + -- Test this to detect, if errouneously two registers are + -- written at the same time. + --if RESET_CPU = '1' then + -- DEBUG_TRIGGER <= '0'; + --elsif AR_WR_1 = '1' and AR_WR_2 = '1' and OP_WB /= EXG then + -- DEBUG_TRIGGER <= '1'; + --elsif AR_WR_1 = '1' and DR_WR_1 = '1' and OP_WB /= EXG then + -- DEBUG_TRIGGER <= '1'; + --elsif AR_WR_1 = '1' and DR_WR_2 = '1' and OP_WB /= EXG then + -- DEBUG_TRIGGER <= '1'; + --elsif AR_WR_2 = '1' and DR_WR_1 = '1' and OP_WB /= EXG then + -- DEBUG_TRIGGER <= '1'; + --elsif AR_WR_2 = '1' and DR_WR_2 = '1' and OP_WB /= EXG then + -- DEBUG_TRIGGER <= '1'; + --elsif DR_WR_1 = '1' and DR_WR_2 = '1' and OP_WB /= EXG then + -- DEBUG_TRIGGER <= '1'; + --end if; + + -- Size mismatch... + --if RESET_CPU = '1' then + -- DEBUG_TRIGGER <= '0'; + --elsif OP_SIZE_WB /= OP_SIZE and DATA_WR_MAIN = '1' then + -- DEBUG_TRIGGER <= '1'; + --end if; + + -- In this way, trigger output can be set + -- to any time in the program processing. + --if RESET_CPU = '1' then + -- DEBUG_TRIGGER <= '0'; + --elsif DEBUG_STAMP > x"002A0000" then + -- DEBUG_TRIGGER <= '1'; + --end if; + + -- Detects a system hang. + --if RESET_CPU = '1' or PC_INC = '1' then + -- TRAPCNT := x"00"; + -- DEBUG_TRIGGER <= '0'; + --elsif TRAPCNT < x"FF" then + -- TRAPCNT := TRAPCNT + '1'; + --else + -- DEBUG_TRIGGER <= '1'; + --end if; + + DEBUG_TRIGGER <= AR_DEC and (AR_WR_1 or AR_WR_2); + end process DEBUGGING; + + IDATA_BUFFER : process + -- This register stores the immediate data. + begin + wait until CLK = '1' and CLK' event; + if STORE_IDATA_B2 = '1' then + IBUFFER(31 downto 16) <= EXT_WORD; + elsif STORE_IDATA_B1 = '1' then + IBUFFER(15 downto 0) <= EXT_WORD; + end if; + end process IDATA_BUFFER; + + DATA_IMMEDIATE <= BIW_1 & BIW_2 when OP = ADDI and OP_SIZE = LONG else + BIW_1 & BIW_2 when OP = ANDI and OP_SIZE = LONG else + BIW_1 & BIW_2 when OP = CMPI and OP_SIZE = LONG else + BIW_1 & BIW_2 when OP = EORI and OP_SIZE = LONG else + BIW_1 & BIW_2 when OP = SUBI and OP_SIZE = LONG else + BIW_1 & BIW_2 when OP = ORI and OP_SIZE = LONG else + x"0000" & BIW_1 when OP = ANDI_TO_SR else + x"0000" & BIW_1 when OP = EORI_TO_SR else + x"0000" & BIW_1 when OP = ORI_TO_SR else + x"0000" & BIW_1 when OP = STOP else + x"0000" & BIW_1 when OP = ADDI and OP_SIZE = WORD else + x"0000" & BIW_1 when OP = ANDI and OP_SIZE = WORD else + x"0000" & BIW_1 when OP = CMPI and OP_SIZE = WORD else + x"0000" & BIW_1 when OP = EORI and OP_SIZE = WORD else + x"0000" & BIW_1 when OP = SUBI and OP_SIZE = WORD else + x"0000" & BIW_1 when OP = ORI and OP_SIZE = WORD else + x"000000" & BIW_1(7 downto 0) when OP = ANDI_TO_CCR else + x"000000" & BIW_1(7 downto 0) when OP = EORI_TO_CCR else + x"000000" & BIW_1(7 downto 0) when OP = ORI_TO_CCR else + x"000000" & BIW_1(7 downto 0) when OP = ADDI and OP_SIZE = BYTE else + x"000000" & BIW_1(7 downto 0) when OP = ANDI and OP_SIZE = BYTE else + x"000000" & BIW_1(7 downto 0) when OP = CMPI and OP_SIZE = BYTE else + x"000000" & BIW_1(7 downto 0) when OP = EORI and OP_SIZE = BYTE else + x"000000" & BIW_1(7 downto 0) when OP = SUBI and OP_SIZE = BYTE else + x"000000" & BIW_1(7 downto 0) when OP = ORI and OP_SIZE = BYTE else + x"00000008" when (OP = ADDQ or OP = SUBQ) and BIW_0(11 downto 9) = "000" else + x"000000" & "00000" & BIW_0(11 downto 9) when OP = ADDQ or OP = SUBQ else + x"000000" & BIW_0(7 downto 0) when OP = MOVEQ else + x"00000001" when OP = DBcc else + IBUFFER when OP_SIZE = LONG else x"0000" & IBUFFER(15 downto 0); + + -- Exception handler multiplexing: internal registers are place holders written as zeros. + DATA_EXH <= SR_CPY & PC(31 downto 16) when K6800n = '0' and STACK_FORMAT = x"0" and STACK_POS = 2 else -- 68K00 short stack frame. + x"0000" & PC(15 downto 0) when K6800n = '0' and STACK_FORMAT = x"0" and STACK_POS = 3 else -- 68K00 short stack frame. + x"0000" & FAULT_ADR(31 downto 16) when K6800n = '0' and STACK_FORMAT = x"8" and STACK_POS = 2 else -- 68K00 long stack frame. + FAULT_ADR(15 downto 0) & BIW_0 when K6800n = '0' and STACK_FORMAT = x"8" and STACK_POS = 4 else -- 68K00 long stack frame. + SR_CPY & PC(31 downto 16) when K6800n = '0' and STACK_FORMAT = x"8" and STACK_POS = 6 else -- 68K00 long stack frame. + x"0000" & PC(15 downto 0) when K6800n = '0' and STACK_FORMAT = x"8" and STACK_POS = 7 else -- 68K00 long stack frame. + SR_CPY & PC(31 downto 16) when STACK_POS = 2 else + PC(15 downto 0) & STACK_FORMAT & "00" & IVECT_OFFS when STACK_POS = 4 else + SSW & FAULT_ADR(31 downto 16) when STACK_POS = 6 else + FAULT_ADR(15 downto 0) & x"0000" when STACK_POS = 8 else + OUTBUFFER when STACK_POS = 10 else + INBUFFER when STACK_POS = 12 else + VERSION when STACK_POS = 14 else + DEBUG_STAMP when STACK_POS = 18 else + DEBUG_STAMP when DEBUG_TRIGGER = '1' and STACK_POS = 20 else (others => '0'); + + DATA_IN_EXH <= ALU_RESULT(31 downto 0) when BUSY_MAIN = '1' else DATA_TO_CORE; -- MOVEC handles the VBR. + + DATA_FROM_CORE <= DATA_EXH when BUSY_EXH = '1' else ALU_RESULT(31 downto 0); + + SP_ADD_DISPL <= SP_ADD_DISPL_MAIN or SP_ADD_DISPL_EXH; + + AR_SEL_RD_1 <= "111" when BUSY_EXH = '1' else AR_SEL_RD_1_MAIN; -- ISP during exception. + + AR_IN_1 <= DATA_TO_CORE when BUSY_EXH = '1' else + ALU_RESULT(31 downto 0) when ALU_BSY = '1' and AR_WR_1 = '1' else + ALU_RESULT(31 downto 0) when ALU_BSY = '1' and (DFC_WR = '1' or SFC_WR = '1' or USP_WR = '1') else + ADR_EFF when OP = JMP or OP = JSR else + AR_OUT_1 when OP = LINK or OP = UNLK else DATA_TO_CORE; -- Default used for RTD, RTR, RTS. + + AR_IN_2 <= ALU_RESULT(63 downto 32) when OP_WB = EXG else ALU_RESULT(31 downto 0); -- Default is for UNLK. + + DR_IN_1 <= ALU_RESULT(63 downto 32) when OP_WB = EXG and ALU_BSY = '1' and DR_WR_1 = '1' and BIW_0_WB_73 = "10001" else -- Address and data registers. + ALU_RESULT(31 downto 0); + + DR_IN_2 <= ALU_RESULT(63 downto 32); + + ALU_OP1_IN <= DATA_TO_CORE when SR_WR_EXH = '1' else + DATA_IMMEDIATE when OP = DBcc else + DR_OUT_1 when (OP = ABCD or OP = SBCD) and BIW_0(3) = '0' else + DATA_TO_CORE when OP = ABCD or OP = SBCD else + DR_OUT_1 when (OP = ADD or OP = SUB) and BIW_0(8) = '1' else + DR_OUT_1 when (OP = AND_B or OP = EOR or OP = OR_B) and BIW_0(8) = '1' else + DR_OUT_1 when (OP = ADDX or OP = SUBX) and BIW_0(3) = '0' else + DATA_TO_CORE when OP = ADDX or OP = SUBX else + DR_OUT_1 when OP = ASL or OP = ASR or OP = LSL or OP = LSR else + DR_OUT_1 when OP = ROTL or OP = ROTR or OP = ROXL or OP = ROXR else + DATA_TO_CORE when OP = CMPM else + PC + PC_EW_OFFSET when OP = BSR or OP = JSR else + ADR_EFF when OP = LEA or OP = PEA else + AR_OUT_2 when OP = MOVE and BIW_0(5 downto 3) = "001" else -- An to any location. + AR_OUT_1 when OP = MOVE_USP else + AR_OUT_1 when OP = EXG and BIW_0(7 downto 3) = "01001" else -- Two address registers. + DR_OUT_1 when OP = EXG else -- Two data registers. + VBR when OP = MOVEC and VBR_RD = '1' else + x"0000000" & '0' & SFC when OP = MOVEC and SFC_RD = '1' else + x"0000000" & '0' & DFC when OP = MOVEC and DFC_RD = '1' else + AR_OUT_1 when OP = MOVEC and BIW_1(15) = '1' else + DR_OUT_1 when OP = MOVEC else + DR_OUT_1 when OP = MOVEM and BIW_0(10) = '0' and ADn = '0' else -- Register to memory. + AR_CPY when OP = MOVEM and BIW_0(10) = '0' and AR_SEL_RD_1(2 downto 0) = AR_SEL_RD_2 and ADR_MODE = "100" else -- Register to memory in -(An) mode. + AR_OUT_2 when OP = MOVEM and BIW_0(10) = '0' else -- Register to memory. + DR_OUT_1 when OP = MOVES and BIW_1(11) = '1' and BIW_1(15) = '0' else -- Register to memory. + AR_OUT_2 when OP = MOVES and BIW_1(11) = '1' else -- Register to memory. + x"000000" & DR_OUT_1(31 downto 24) when OP = MOVEP and MOVEP_PNTR = 3 and BIW_0(7 downto 6) > "01" else + x"000000" & DR_OUT_1(23 downto 16) when OP = MOVEP and MOVEP_PNTR = 2 and BIW_0(7 downto 6) > "01" else + x"000000" & DR_OUT_1(15 downto 8) when OP = MOVEP and MOVEP_PNTR = 1 and BIW_0(7 downto 6) > "01" else + x"000000" & DR_OUT_1(7 downto 0) when OP = MOVEP and BIW_0(7 downto 6) > "01" else + DATA_TO_CORE(7 downto 0) & DR_OUT_1(23 downto 0) when OP = MOVEP and MOVEP_PNTR = 3 else + DR_OUT_1(31 downto 24) & DATA_TO_CORE(7 downto 0) & DR_OUT_1(15 downto 0) when OP = MOVEP and MOVEP_PNTR = 2 else + DR_OUT_1(31 downto 16) & DATA_TO_CORE(7 downto 0) & DR_OUT_1(7 downto 0) when OP = MOVEP and MOVEP_PNTR = 1 else + DR_OUT_1(31 downto 8) & DATA_TO_CORE(7 downto 0) when OP = MOVEP else + x"0000" & STATUS_REG(15 downto 8) & DR_OUT_1(7 downto 0) when OP = MOVE_TO_CCR and BIW_0(5 downto 3) = "000" else + x"0000" & STATUS_REG(15 downto 8) & DATA_IMMEDIATE(7 downto 0) when OP = MOVE_TO_CCR and BIW_0(5 downto 0) = "111100" else + x"0000" & STATUS_REG(15 downto 8) & DATA_TO_CORE(7 downto 0) when OP = MOVE_TO_CCR else + x"0000" & DR_OUT_1(15 downto 0) when OP = MOVE_TO_SR and BIW_0(5 downto 3) = "000" else + x"0000" & DATA_IMMEDIATE(15 downto 0) when OP = MOVE_TO_SR and BIW_0(5 downto 0) = "111100" else + x"0000" & DATA_TO_CORE(15 downto 0) when OP = MOVE_TO_SR else + x"000000" & "000" & STATUS_REG(4 downto 0) when OP = MOVE_FROM_CCR else + x"0000" & STATUS_REG when OP = MOVE_FROM_SR else + DATA_IMMEDIATE when OP = STOP else -- Status register information. + DATA_IMMEDIATE when OP = MOVEQ else + x"00000000" when OP = NEG or OP = NEGX or OP = NBCD else + DATA_IMMEDIATE when OP = ADDI or OP = CMPI or OP = SUBI or OP = ANDI or OP = EORI or OP = ORI else + DATA_IMMEDIATE when OP = ADDQ or OP = SUBQ else + DATA_IMMEDIATE when OP = ANDI_TO_CCR or OP = ANDI_TO_SR else + DATA_IMMEDIATE when OP = EORI_TO_CCR or OP = EORI_TO_SR else + DATA_IMMEDIATE when OP = ORI_TO_CCR or OP = ORI_TO_SR else + DR_OUT_1 when BIW_0(5 downto 3) = "000" else + AR_OUT_1 when BIW_0(5 downto 3) = "001" else + DATA_IMMEDIATE when BIW_0(5 downto 0) = "111100" else DATA_TO_CORE; + + ALU_OP2_IN <= DR_OUT_2 when (OP = ABCD or OP = SBCD) and BIW_0(3) = '0' else + DATA_TO_CORE when OP = ABCD or OP = SBCD else + DR_OUT_2 when (OP = ADDX or OP = SUBX) and BIW_0(3) = '0' else + DATA_TO_CORE when OP = ADDX or OP = SUBX else + DR_OUT_2 when (OP = ADD or OP = CMP or OP = SUB) and BIW_0(8) = '0' else + DR_OUT_2 when (OP = AND_B or OP = OR_B) and BIW_0(8) = '0' else + AR_OUT_2 when (OP = ADDA or OP = CMPA or OP = SUBA) else + DR_OUT_2 when OP = EXG and BIW_0(7 downto 3) = "01000" else -- Two data registers. + AR_OUT_2 when OP = EXG else + DR_OUT_2 when (OP = ASL or OP = ASR) and BIW_0(7 downto 6) /= "11" else -- Register shifts. + DR_OUT_2 when (OP = LSL or OP = LSR) and BIW_0(7 downto 6) /= "11" else -- Register shifts. + DR_OUT_2 when (OP = ROTL or OP = ROTR) and BIW_0(7 downto 6) /= "11" else -- Register shifts. + DR_OUT_2 when (OP = ROXL or OP = ROXR) and BIW_0(7 downto 6) /= "11" else -- Register shifts. + x"0000" & STATUS_REG when(OP = ANDI_TO_CCR or OP = ANDI_TO_SR) else + x"0000" & STATUS_REG when(OP = EORI_TO_CCR or OP = EORI_TO_SR) else + x"0000" & STATUS_REG when(OP = ORI_TO_CCR or OP = ORI_TO_SR) else + AR_OUT_2 when OP = CHK else + DATA_TO_CORE when OP = CMPM else + DR_OUT_2 when OP = DBcc or OP = SWAP else + DR_OUT_2 when OP = DIVS or OP = DIVU else + DR_OUT_2 when OP = MULS or OP = MULU else + AR_OUT_1 when OP = LINK else + DR_OUT_2 when BIW_0(5 downto 3) = "000" else + AR_OUT_2 when BIW_0(5 downto 3) = "001" else DATA_TO_CORE; + + ALU_OP3_IN <= DR_OUT_1; + + OP_SIZE <= OP_SIZE_EXH when BUSY_EXH = '1' else OP_SIZE_MAIN; + OP_SIZE_BUS <= OP_SIZE_WB when DATA_WR_MAIN = '1' else OP_SIZE; + + FC_OUT <= FC_OUT_I; + + PC_L <= PC + PC_ADR_OFFSET; + + PC_INC_EXH_I <= PC_INC_EXH when LOOP_SPLIT = false else '0'; -- Suppress for a split loop. + + ADR_MODE <= "010" when BUSY_EXH = '1' else ADR_MODE_MAIN; --(ISP) + + -- The bit field offset is byte aligned + ADR_OFFSET <= ADR_OFFSET_EXH when BUSY_EXH = '1' else + x"000000" & "00" & ADR_OFFSET_MAIN; + + DBcc_COND <= true when OP_WB = DBcc and ALU_RESULT(15 downto 0) = x"FFFF" else false; + + -- Take a branch if the CPU space will change: + BRANCH_ATN <= '1' when OP = ANDI_TO_SR and DATA_IMMEDIATE(13) = '0' and STATUS_REG(13) = '1' else + '1' when OP = EORI_TO_SR and DATA_IMMEDIATE(13) = '1' else + '1' when OP = ORI_TO_SR and DATA_IMMEDIATE(13) = '1' and STATUS_REG(13) = '0' else + '1' when OP = MOVE_TO_SR and BIW_0(5 downto 3) = "000" and DR_OUT_1(13) /= STATUS_REG(13) else + '1' when OP = MOVE_TO_SR and BIW_0(5 downto 0) = "111100" and DATA_IMMEDIATE(13) /= STATUS_REG(13) else + '1' when OP = MOVE_TO_SR and DATA_TO_CORE(13) /= STATUS_REG(13) else '0'; + + DATA_RD <= DATA_RD_EXH or DATA_RD_MAIN; + DATA_WR <= DATA_WR_EXH or DATA_WR_MAIN; + + P_BUSREQ: process + begin + wait until CLK = '1' and CLK' event; + -- We need these flip flops to avoid combinatorial loops: + -- The requests are valid until the Bus interface enters + -- its START_CYCLE bus phase and asserts there the BUS_BSY. + -- After the Bus interface enters the bus access state, + -- the requests are withdrawn. + if BUS_BSY = '0' then + RD_REQ_I <= DATA_RD; + WR_REQ_I <= DATA_WR; + OPCODE_REQ_I <= OPCODE_RD; + elsif BUS_BSY = '1' then + RD_REQ_I <= '0'; + WR_REQ_I <= '0'; + OPCODE_REQ_I <= '0'; + end if; + end process P_BUSREQ; + + MOVEM_AR_CPY: process + -- This temporary copy of the addressing register is used during the + -- MOVEM instruction in predecrement addressing mode -(An). The value + -- of the addressing register written to memory is the initial value + -- for 68000 and 68010 processors. + variable LOCK : boolean; + begin + wait until CLK = '1' and CLK' event; + if OPD_ACK_MAIN = '1' and OP = MOVEM and LOCK = false then + AR_CPY <= AR_OUT_1; + LOCK := true; + elsif OW_REQ_MAIN = '1' then + LOCK := false; + end if; + end process MOVEM_AR_CPY; + + RD_REQ <= DATA_RD when BUS_BSY = '0' else RD_REQ_I; + WR_REQ <= DATA_WR when BUS_BSY = '0' else WR_REQ_I; + OPCODE_REQ <= OPCODE_RD when BUS_BSY = '0' else OPCODE_REQ_I; + + DISPLACEMENT <= DISPLACEMENT_MAIN when BUSY_MAIN = '1' else x"000000" & DISPLACEMENT_EXH; + + SR_WR <= SR_WR_EXH or SR_WR_MAIN; + + IPIPE_FLUSH <= IPIPE_FLUSH_EXH or IPIPE_FLUSH_MAIN; + + AVECn_BUSIF <= AVECn when BUSY_EXH = '1' else '1'; -- Disabled during normal operation. + + CPU_SPACE <= '1' when OP = BKPT and DATA_RD_MAIN = '1' else + CPU_SPACE_EXH when BUSY_EXH = '1' else '0'; + + -- The BITPOS is valid for BCHG, BCLR, BSET and BTST it BITPOS spans 0 to 31 bytes, + -- when it is in register direct mode. It is modulo 8 in memory manipulation mode. + BITPOS <= BIW_1(4 downto 0) when (OP = BCHG or OP = BCLR or OP = BSET or OP = BTST) and BIW_0(8) = '0' and ADR_MODE = "000" else + "00" & BIW_1(2 downto 0) when (OP = BCHG or OP = BCLR or OP = BSET or OP = BTST) and BIW_0(8) = '0' else + DR_OUT_1(4 downto 0) when (OP = BCHG or OP = BCLR or OP = BSET or OP = BTST) and ADR_MODE = "000" else + "00" & DR_OUT_1(2 downto 0) when OP = BCHG or OP = BCLR or OP = BSET or OP = BTST else + BIW_1(10 downto 6) when BIW_1(11) = '0' and ADR_MODE = "000" else + "00" & BIW_1(8 downto 6) when BIW_1(11) = '0' else + DR_OUT_1(4 downto 0) when ADR_MODE = "000" else "00" & DR_OUT_1(2 downto 0); + + TRAP_AERR <= AERR when BUSY_EXH = '0' else '0'; -- No address error from the system during exception processing. + + USE_DFC <= '1' when OP_WB = MOVES and DATA_WR_MAIN = '1' else '0'; + USE_SFC <= '1' when OP_WB = MOVES and DATA_RD_MAIN = '1' else '0'; + + PC_LOAD <= PC_LOAD_EXH or PC_LOAD_MAIN; + + RESET_IN <= not RESET_INn; + + IPL <= not IPLn; + + SBIT <= STATUS_REG(13); + + ADR_L <= x"00000000" when BKPT_CYCLE = '1' else + x"FFFFFFF" & IRQ_PEND & '1' when CPU_SPACE_EXH = '1' else + ADR_EFF_WB when DATA_WR_MAIN = '1' else ADR_EFF; -- Exception handler uses ADR_EFF for read and write access. + + ADR_P <= ADR_LATCH when BUS_BSY = '1' else + ADR_L when DATA_RD = '1' or DATA_WR = '1' else PC_L; + + P_ADR_LATCHES: process + -- This register stores the address during a running bus cycle. + -- The signals RD_DATA, WR_DATA and RD_OPCODE may change during + -- the cycle. Opcode read is lower prioritized. + -- FAULT_ADR latches the faulty address for stacking it via + -- the exception handler. + -- The FC_LATCH register stores the function code during a running + -- bus cycle. + begin + wait until CLK = '1' and CLK' event; + if BUS_BSY = '0' then + ADR_LATCH <= ADR_P; + FC_LATCH <= FC_I; + elsif BERRn = '0' then + FAULT_ADR <= ADR_LATCH; + end if; + end process P_ADR_LATCHES; + + FC_I <= FC_LATCH when BUS_BSY = '1' else + SFC when USE_SFC = '1' else + DFC when USE_DFC = '1' else + "111" when (DATA_RD = '1' or DATA_WR = '1') and CPU_SPACE = '1' else + "101" when (DATA_RD = '1' or DATA_WR = '1') and SBIT = '1' else + "001" when DATA_RD = '1' or DATA_WR = '1' else + "110" when OPCODE_RD = '1' and SBIT = '1' else "010"; -- Default is OPCODE_RD and SBIT = '0'. + + I_ADDRESSREGISTERS: WF68K10_ADDRESS_REGISTERS + port map( + CLK => CLK, + RESET => RESET_CPU, + AR_IN_1 => AR_IN_1, + AR_IN_2 => AR_IN_2, + AR_OUT_1 => AR_OUT_1, + AR_OUT_2 => AR_OUT_2, + INDEX_IN => DR_OUT_1, -- From data register section. + PC => PC, + STORE_ADR_FORMAT => STORE_ADR_FORMAT, + STORE_ABS_HI => STORE_ABS_HI, + STORE_ABS_LO => STORE_ABS_LO, + STORE_D16 => STORE_D16, + STORE_DISPL => STORE_DISPL, + STORE_AEFF => STORE_AEFF, + OP_SIZE => OP_SIZE, + AR_MARK_USED => AR_MARK_USED, + USE_APAIR => USE_APAIR, + AR_IN_USE => AR_IN_USE, + AR_SEL_RD_1 => AR_SEL_RD_1, + AR_SEL_RD_2 => AR_SEL_RD_2, + AR_SEL_WR_1 => AR_SEL_WR_1, + AR_SEL_WR_2 => AR_SEL_WR_2, + ADR_OFFSET => ADR_OFFSET, -- Byte aligned. + ADR_MARK_USED => ADR_MARK_USED, + ADR_IN_USE => ADR_IN_USE, + ADR_MODE => ADR_MODE, + AMODE_SEL => AMODE_SEL, + ADR_EFF => ADR_EFF, + ADR_EFF_WB => ADR_EFF_WB, + DFC => DFC, + DFC_WR => DFC_WR, + SFC => SFC, + SFC_WR => SFC_WR, + ISP_DEC => ISP_DEC, + ISP_WR => ISP_LOAD, + USP_RD => USP_RD, + USP_WR => USP_WR, + AR_DEC => AR_DEC, + AR_INC => AR_INC, + AR_WR_1 => AR_WR_1, + AR_WR_2 => AR_WR_2, + UNMARK => UNMARK, + EXT_WORD => EXT_WORD, + SBIT => SBIT, + SP_ADD_DISPL => SP_ADD_DISPL, + RESTORE_ISP_PC => RESTORE_ISP_PC, + DISPLACEMENT => DISPLACEMENT, + PC_ADD_DISPL => PC_ADD_DISPL, + PC_EW_OFFSET => PC_EW_OFFSET, + PC_INC => PC_INC, + PC_LOAD => PC_LOAD, + PC_RESTORE => PC_RESTORE_EXH, + PC_OFFSET => PC_OFFSET + ); + + I_ALU: WF68K10_ALU + port map( + CLK => CLK, + RESET => RESET_CPU, + LOAD_OP3 => ALU_LOAD_OP3, + LOAD_OP2 => ALU_LOAD_OP2, + LOAD_OP1 => ALU_LOAD_OP1, + OP1_IN => ALU_OP1_IN, + OP2_IN => ALU_OP2_IN, + OP3_IN => ALU_OP3_IN, + BITPOS_IN => BITPOS, + RESULT => ALU_RESULT, + ADR_MODE_IN => ADR_MODE, + OP_SIZE_IN => OP_SIZE, + OP_IN => OP, + OP_WB => OP_WB, + BIW_0_IN => BIW_0(11 downto 0), + BIW_1_IN => BIW_1, + SR_WR => SR_WR, + SR_INIT => SR_INIT, + CC_UPDT => CC_UPDT, + STATUS_REG_OUT => STATUS_REG, + ALU_COND => ALU_COND, + ALU_INIT => ALU_INIT, + ALU_BSY => ALU_BSY, + ALU_REQ => ALU_REQ, + ALU_ACK => ALU_ACK, + IRQ_PEND => IRQ_PEND, + TRAP_CHK => TRAP_CHK, + TRAP_DIVZERO => TRAP_DIVZERO + ); + + I_BUS_IF: WF68K10_BUS_INTERFACE + port map( + CLK => CLK, + + ADR_IN_P => ADR_P, + ADR_OUT_P => ADR_OUT, + + FC_IN => FC_I, + FC_OUT => FC_OUT_I, + + DATA_PORT_IN => DATA_IN, + DATA_PORT_OUT => DATA_OUT, + DATA_FROM_CORE => DATA_FROM_CORE, + DATA_TO_CORE => DATA_TO_CORE, + OPCODE_TO_CORE => OPCODE_TO_CORE, + + DATA_PORT_EN => DATA_EN, + BUS_EN => BUS_EN, + + OP_SIZE => OP_SIZE_BUS, + + RD_REQ => RD_REQ, + WR_REQ => WR_REQ, + DATA_RDY => DATA_RDY, + DATA_VALID => DATA_VALID, + OPCODE_REQ => OPCODE_REQ, + OPCODE_RDY => OPCODE_RDY, + OPCODE_VALID => OPCODE_VALID, + RMC => RMC, + BUSY_EXH => BUSY_EXH, + SSW => SSW, + INBUFFER => INBUFFER, + OUTBUFFER => OUTBUFFER, + + DTACKn => DTACKn, + ASn => ASn, + UDSn => UDSn, + LDSn => LDSn, + RWn => RWn, + RMCn => RMCn, + DBENn => DBENn, + + E => E, + VMAn => VMAn, + VMA_EN => VMA_EN, + VPAn => VPAn, + + BRn => BRn, + BGACKn => BGACKn, + BGn => BGn, + + RESET_STRB => RESET_STRB, + RESET_IN => RESET_IN, + RESET_OUT => RESET_OUT, + RESET_CPU => RESET_CPU, + + AVECn => AVECn_BUSIF, + HALTn => HALT_INn, + BERRn => BERRn, + AERR => AERR, + + BUS_BSY => BUS_BSY + ); + + I_CONTROL: WF68K10_CONTROL + generic map(NO_PIPELINE => NO_PIPELINE) + port map( + CLK => CLK, + RESET_CPU => RESET_CPU, + BUSY => BUSY_MAIN, + BUSY_EXH => BUSY_EXH, + EXH_REQ => EXH_REQ, + INT_TRIG => INT_TRIG, + OW_REQ => OW_REQ_MAIN, + OW_VALID => OW_VALID, + EW_REQ => EW_REQ_MAIN, + EW_ACK => EW_ACK, + OPD_ACK => OPD_ACK_MAIN, + ADR_MARK_USED => ADR_MARK_USED, + ADR_IN_USE => ADR_IN_USE, + ADR_OFFSET => ADR_OFFSET_MAIN, + DATA_RD => DATA_RD_MAIN, + DATA_WR => DATA_WR_MAIN, + DATA_RDY => DATA_RDY, + DATA_VALID => DATA_VALID, + RMC => RMC, + LOAD_OP1 => ALU_LOAD_OP1, + LOAD_OP2 => ALU_LOAD_OP2, + LOAD_OP3 => ALU_LOAD_OP3, + STORE_ADR_FORMAT => STORE_ADR_FORMAT, + STORE_ABS_HI => STORE_ABS_HI, + STORE_ABS_LO => STORE_ABS_LO, + STORE_D16 => STORE_D16, + STORE_DISPL => STORE_DISPL, + STORE_AEFF => STORE_AEFF, + STORE_IDATA_B1 => STORE_IDATA_B1, + STORE_IDATA_B2 => STORE_IDATA_B2, + OP => OP, + OP_SIZE => OP_SIZE_MAIN, + BIW_0 => BIW_0(13 downto 0), + BIW_1 => BIW_1, + EXT_WORD => EXT_WORD, + ADR_MODE => ADR_MODE_MAIN, + AMODE_SEL => AMODE_SEL, + OP_WB => OP_WB, + OP_SIZE_WB => OP_SIZE_WB, + BIW_0_WB_73 => BIW_0_WB_73, + AR_MARK_USED => AR_MARK_USED, + AR_IN_USE => AR_IN_USE, + AR_SEL_RD_1 => AR_SEL_RD_1_MAIN, + AR_SEL_RD_2 => AR_SEL_RD_2, + AR_SEL_WR_1 => AR_SEL_WR_1, + AR_SEL_WR_2 => AR_SEL_WR_2, + AR_INC => AR_INC, + AR_DEC => AR_DEC, + AR_WR_1 => AR_WR_1, + AR_WR_2 => AR_WR_2, + DR_MARK_USED => DR_MARK_USED, + USE_APAIR => USE_APAIR, + USE_DPAIR => USE_DPAIR, + DR_IN_USE => DR_IN_USE, + DR_SEL_WR_1 => DR_SEL_WR_1, + DR_SEL_WR_2 => DR_SEL_WR_2, + DR_SEL_RD_1 => DR_SEL_RD_1, + DR_SEL_RD_2 => DR_SEL_RD_2, + DR_WR_1 => DR_WR_1, + DR_WR_2 => DR_WR_2, + UNMARK => UNMARK, + DISPLACEMENT => DISPLACEMENT_MAIN, + PC_ADD_DISPL => PC_ADD_DISPL, + PC_LOAD => PC_LOAD_MAIN, + PC_INC_EXH => PC_INC_EXH, + SP_ADD_DISPL => SP_ADD_DISPL_MAIN, + DFC_RD => DFC_RD, + DFC_WR => DFC_WR, + SFC_RD => SFC_RD, + SFC_WR => SFC_WR, + VBR_RD => VBR_RD, + VBR_WR => VBR_WR, + USP_RD => USP_RD, + USP_WR => USP_WR, + IPIPE_FLUSH => IPIPE_FLUSH_MAIN, + ALU_INIT => ALU_INIT, + ALU_BSY => ALU_BSY, + ALU_REQ => ALU_REQ, + ALU_ACK => ALU_ACK, + BKPT_CYCLE => BKPT_CYCLE, + BKPT_INSERT => BKPT_INSERT, + LOOP_BSY => LOOP_BSY, + LOOP_SPLIT => LOOP_SPLIT, + LOOP_EXIT => LOOP_EXIT, + SR_WR => SR_WR_MAIN, + MOVEM_ADn => ADn, + MOVEP_PNTR => MOVEP_PNTR, + CC_UPDT => CC_UPDT, + TRACE_EN => STATUS_REG(15), + ALU_COND => ALU_COND, + DBcc_COND => DBcc_COND, + BRANCH_ATN => BRANCH_ATN, + RESET_STRB => RESET_STRB, + BERR => BERR_MAIN, + EX_TRACE => EX_TRACE, + TRAP_V => TRAP_V, + TRAP_ILLEGAL => TRAP_ILLEGAL + ); + + I_DATA_REGISTERS: WF68K10_DATA_REGISTERS + port map( + CLK => CLK, + RESET => RESET_CPU, + DR_IN_1 => DR_IN_1, + DR_IN_2 => DR_IN_2, + DR_OUT_2 => DR_OUT_2, + DR_OUT_1 => DR_OUT_1, + DR_SEL_WR_1 => DR_SEL_WR_1, + DR_SEL_WR_2 => DR_SEL_WR_2, + DR_SEL_RD_1 => DR_SEL_RD_1, + DR_SEL_RD_2 => DR_SEL_RD_2, + DR_WR_1 => DR_WR_1, + DR_WR_2 => DR_WR_2, + DR_MARK_USED => DR_MARK_USED, + USE_DPAIR => USE_DPAIR, + DR_IN_USE => DR_IN_USE, + UNMARK => UNMARK, + OP_SIZE => OP_SIZE_WB + ); + + I_EXC_HANDLER: WF68K10_EXCEPTION_HANDLER + generic map(VERSION => VERSION) + port map( + CLK => CLK, + K6800n => K6800n, + + RESET => RESET_CPU, + + BUSY_MAIN => BUSY_MAIN, + BUSY_OPD => BUSY_OPD, + + EXH_REQ => EXH_REQ, + BUSY_EXH => BUSY_EXH, + + ADR_IN => ADR_EFF, + ADR_OFFSET => ADR_OFFSET_EXH, + CPU_SPACE => CPU_SPACE_EXH, + + DATA_0 => DATA_TO_CORE(0), + DATA_RD => DATA_RD_EXH, + DATA_WR => DATA_WR_EXH, + DATA_IN => DATA_IN_EXH, + + OP_SIZE => OP_SIZE_EXH, + DATA_RDY => DATA_RDY, + DATA_VALID => DATA_VALID, + + OPCODE_RDY => OPCODE_RDY, + + STATUS_REG_IN => STATUS_REG, + SR_CPY => SR_CPY, + SR_INIT => SR_INIT, + + SR_WR => SR_WR_EXH, + ISP_DEC => ISP_DEC, + ISP_LOAD => ISP_LOAD, + PC_LOAD => PC_LOAD_EXH, + PC_INC => PC_INC_EXH, + PC_RESTORE => PC_RESTORE_EXH, + + STACK_FORMAT => STACK_FORMAT, + STACK_POS => STACK_POS, + + SP_ADD_DISPL => SP_ADD_DISPL_EXH, + DISPLACEMENT => DISPLACEMENT_EXH, + IPIPE_FILL => IPIPE_FILL, + IPIPE_FLUSH => IPIPE_FLUSH_EXH, + RESTORE_ISP_PC => RESTORE_ISP_PC, + + HALT_OUTn => HALT_OUTn, + + INT_TRIG => INT_TRIG, + IRQ_IN => IPL, + IRQ_PEND => IRQ_PEND, + AVECn => AVECn, + IVECT_OFFS => IVECT_OFFS, + + TRAP_AERR => TRAP_AERR, + TRAP_BERR => BERR_MAIN, + TRAP_CHK => TRAP_CHK, + TRAP_DIVZERO => TRAP_DIVZERO, + TRAP_ILLEGAL => TRAP_ILLEGAL, + TRAP_CODE_OPC => TRAP_CODE_OPC, + TRAP_VECTOR => BIW_0(3 downto 0), + TRAP_V => TRAP_V, + EX_TRACE_IN => EX_TRACE, + VBR_WR => VBR_WR, + VBR => VBR + ); + + I_OPCODE_DECODER: WF68K10_OPCODE_DECODER + generic map(NO_LOOP => NO_LOOP) + port map( + CLK => CLK, + K6800n => K6800n, + + OW_REQ_MAIN => OW_REQ_MAIN, + EW_REQ_MAIN => EW_REQ_MAIN, + + EXH_REQ => EXH_REQ, + BUSY_EXH => BUSY_EXH, + BUSY_MAIN => BUSY_MAIN, + BUSY_OPD => BUSY_OPD, + + BKPT_INSERT => BKPT_INSERT, + BKPT_DATA => DATA_TO_CORE(15 downto 0), + + LOOP_EXIT => LOOP_EXIT, + LOOP_BSY => LOOP_BSY, + + OPD_ACK_MAIN => OPD_ACK_MAIN, + EW_ACK => EW_ACK, + + PC_INC => PC_INC, + PC_INC_EXH => PC_INC_EXH_I, + PC_ADR_OFFSET => PC_ADR_OFFSET, + PC_EW_OFFSET => PC_EW_OFFSET, + PC_OFFSET => PC_OFFSET, + + OPCODE_RD => OPCODE_RD, + OPCODE_RDY => OPCODE_RDY, + OPCODE_VALID => OPCODE_VALID, + OPCODE_DATA => OPCODE_TO_CORE, + + IPIPE_FILL => IPIPE_FILL, + IPIPE_FLUSH => IPIPE_FLUSH, + + -- Fault logic: + OW_VALID => OW_VALID, + + -- Trap logic: + SBIT => SBIT, + TRAP_CODE => TRAP_CODE_OPC, + + -- System control: + OP => OP, + BIW_0 => BIW_0, + BIW_1 => BIW_1, + BIW_2 => BIW_2, + EXT_WORD => EXT_WORD + ); +end STRUCTURE; diff --git a/common/CPU/68K30L/license/cern_ohl_v_1_2.odt b/common/CPU/68K30L/license/cern_ohl_v_1_2.odt new file mode 100644 index 00000000..0e4038a4 Binary files /dev/null and b/common/CPU/68K30L/license/cern_ohl_v_1_2.odt differ diff --git a/common/CPU/68K30L/license/cern_ohl_v_1_2.pdf b/common/CPU/68K30L/license/cern_ohl_v_1_2.pdf new file mode 100644 index 00000000..99ce718d Binary files /dev/null and b/common/CPU/68K30L/license/cern_ohl_v_1_2.pdf differ diff --git a/common/CPU/68K30L/license/cern_ohl_v_1_2.txt b/common/CPU/68K30L/license/cern_ohl_v_1_2.txt new file mode 100644 index 00000000..62aab65d --- /dev/null +++ b/common/CPU/68K30L/license/cern_ohl_v_1_2.txt @@ -0,0 +1,897 @@ + + + + +CERN Open Hardware Licence - cern_ohl_v_1_2.txt - Open Hardware Repository + + + + + + + + + + + + + + + + + + + +
+
+ + + + +
+ + +
+ +

cern_ohl_v_1_2.txt

+ +
+

Licence text in text format. - + Javier Serrano, 2013-09-06 10:05

+

Download (8.9 kB)

+ +
+  +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1
CERN Open Hardware Licence v1.2 
+
2
+
3
Preamble
+
4
+
5
Through this CERN Open Hardware Licence ("CERN OHL") version 1.2, CERN
+
6
wishes to provide a tool to foster collaboration and sharing among
+
7
hardware designers.  The CERN OHL is copyright CERN. Anyone is welcome
+
8
to use the CERN OHL, in unmodified form only, for the distribution of
+
9
their own Open Hardware designs. Any other right is reserved. Release
+
10
of hardware designs under the CERN OHL does not constitute an
+
11
endorsement of the licensor or its designs nor does it imply any
+
12
involvement by CERN in the development of such designs.
+
13
+
14
1. Definitions
+
15
+
16
In this Licence, the following terms have the following meanings:
+
17
 
+
18
“Licence” means this CERN OHL.
+
19
+
20
“Documentation” means schematic diagrams, designs, circuit or circuit
+
21
board layouts, mechanical drawings, flow charts and descriptive text,
+
22
and other explanatory material that is explicitly stated as being made
+
23
available under the conditions of this Licence. The Documentation may
+
24
be in any medium, including but not limited to computer files and
+
25
representations on paper, film, or any other media.
+
26
+
27
“Documentation Location” means a location where the Licensor has
+
28
placed Documentation, and which he believes will be publicly
+
29
accessible for at least three years from the first communication to
+
30
the public or distribution of Documentation.
+
31
+
32
“Product” means either an entire, or any part of a, device built using
+
33
the Documentation or the modified Documentation.
+
34
+
35
“Licensee” means any natural or legal person exercising rights under
+
36
this Licence.
+
37
+
38
“Licensor” means any natural or legal person that creates or modifies
+
39
Documentation and subsequently communicates to the public and/ or
+
40
distributes the resulting Documentation under the terms and conditions
+
41
of this Licence.
+
42
+
43
A Licensee may at the same time be a Licensor, and vice versa. 
+
44
+
45
Use of the masculine gender includes the feminine and neuter genders
+
46
and is employed solely to facilitate reading.
+
47
+
48
2. Applicability
+
49
+
50
2.1. This Licence governs the use, copying, modification,
+
51
communication to the public and distribution of the Documentation, and
+
52
the manufacture and distribution of Products. By exercising any right
+
53
granted under this Licence, the Licensee irrevocably accepts these
+
54
terms and conditions.
+
55
+
56
2.2. This Licence is granted by the Licensor directly to the Licensee,
+
57
and shall apply worldwide and without limitation in time. The Licensee
+
58
may assign his licence rights or grant sub-licences.
+
59
+
60
2.3. This Licence does not extend to software, firmware, or code
+
61
loaded into programmable devices which may be used in conjunction with
+
62
the Documentation, the modified Documentation or with Products, unless
+
63
such software, firmware, or code is explicitly expressed to be subject
+
64
to this Licence. The use of such software, firmware, or code is
+
65
otherwise subject to the applicable licence terms and conditions.
+
66
+
67
3. Copying, modification, communication to the public and distribution
+
68
of the Documentation
+
69
+
70
3.1. The Licensee shall keep intact all copyright and trademarks
+
71
notices, all notices referring to Documentation Location, and all
+
72
notices that refer to this Licence and to the disclaimer of warranties
+
73
that are included in the Documentation. He shall include a copy
+
74
thereof in every copy of the Documentation or, as the case may be,
+
75
modified Documentation, that he communicates to the public or
+
76
distributes.
+
77
+
78
3.2. The Licensee may copy, communicate to the public and distribute
+
79
verbatim copies of the Documentation, in any medium, subject to the
+
80
requirements specified in section 3.1.
+
81
+
82
3.3. The Licensee may modify the Documentation or any portion thereof
+
83
provided that upon modification of the Documentation, the Licensee
+
84
shall make the modified Documentation available from a Documentation
+
85
Location such that it can be easily located by an original Licensor
+
86
once the Licensee communicates to the public or distributes the
+
87
modified Documentation under section 3.4, and, where required by
+
88
section 4.1, by a recipient of a Product. However, the Licensor shall
+
89
not assert his rights under the foregoing proviso unless or until a
+
90
Product is distributed.
+
91
+
92
3.4. The Licensee may communicate to the public and distribute the
+
93
modified Documentation (thereby in addition to being a Licensee also
+
94
becoming a Licensor), always provided that he shall:
+
95
+
96
a) comply with section 3.1;
+
97
+
98
b) cause the modified Documentation to carry prominent notices stating
+
99
that the Licensee has modified the Documentation, with the date and
+
100
description of the modifications;
+
101
+
102
c) cause the modified Documentation to carry a new Documentation
+
103
Location notice if the original Documentation provided for one;
+
104
+
105
d) make available the modified Documentation at the same level of
+
106
abstraction as that of the Documentation, in the preferred format for
+
107
making modifications to it (e.g. the native format of the CAD tool as
+
108
applicable), and in the event that format is proprietary, in a format
+
109
viewable with a tool licensed under an OSI-approved license if the
+
110
proprietary tool can create it; and
+
111
+
112
e) license the modified Documentation under the terms and conditions
+
113
of this Licence or, where applicable, a later version of this Licence
+
114
as may be issued by CERN.
+
115
+
116
3.5. The Licence includes a non-exclusive licence to those patents or
+
117
registered designs that are held by, under the control of, or
+
118
sub-licensable by the Licensor, to the extent necessary to make use of
+
119
the rights granted under this Licence. The scope of this section 3.5
+
120
shall be strictly limited to the parts of the Documentation or
+
121
modified Documentation created by the Licensor.
+
122
+
123
4. Manufacture and distribution of Products
+
124
+
125
4.1. The Licensee may manufacture or distribute Products always
+
126
provided that, where such manufacture or distribution requires a
+
127
licence under this Licence the Licensee provides to each recipient of
+
128
such Products an easy means of accessing a copy of the Documentation
+
129
or modified Documentation, as applicable, as set out in section 3.
+
130
+
131
4.2. The Licensee is invited to inform any Licensor who has indicated
+
132
his wish to receive this information about the type, quantity and
+
133
dates of production of Products the Licensee has (had) manufactured
+
134
+
135
5. Warranty and liability
+
136
+
137
5.1. DISCLAIMER – The Documentation and any modified Documentation are
+
138
provided "as is" and any express or implied warranties, including, but
+
139
not limited to, implied warranties of merchantability, of satisfactory
+
140
quality, non-infringement of third party rights, and fitness for a
+
141
particular purpose or use are disclaimed in respect of the
+
142
Documentation, the modified Documentation or any Product. The Licensor
+
143
makes no representation that the Documentation, modified
+
144
Documentation, or any Product, does or will not infringe any patent,
+
145
copyright, trade secret or other proprietary right. The entire risk as
+
146
to the use, quality, and performance of a Product shall be with the
+
147
Licensee and not the Licensor. This disclaimer of warranty is an
+
148
essential part of this Licence and a condition for the grant of any
+
149
rights granted under this Licence. The Licensee warrants that it does
+
150
not act in a consumer capacity.
+
151
+
152
5.2. LIMITATION OF LIABILITY – The Licensor shall have no liability
+
153
for direct, indirect, special, incidental, consequential, exemplary,
+
154
punitive or other damages of any character including, without
+
155
limitation, procurement of substitute goods or services, loss of use,
+
156
data or profits, or business interruption, however caused and on any
+
157
theory of contract, warranty, tort (including negligence), product
+
158
liability or otherwise, arising in any way in relation to the
+
159
Documentation, modified Documentation and/or the use, manufacture or
+
160
distribution of a Product, even if advised of the possibility of such
+
161
damages, and the Licensee shall hold the Licensor(s) free and harmless
+
162
from any liability, costs, damages, fees and expenses, including
+
163
claims by third parties, in relation to such use.
+
164
+
165
6. General
+
166
+
167
6.1. Except for the rights explicitly granted hereunder, this Licence
+
168
does not imply or represent any transfer or assignment of intellectual
+
169
property rights to the Licensee.
+
170
+
171
6.2. The Licensee shall not use or make reference to any of the names
+
172
(including acronyms and abbreviations), images, or logos under which
+
173
the Licensor is known, save in so far as required to comply with
+
174
section 3. Any such permitted use or reference shall be factual and
+
175
shall in no event suggest any kind of endorsement by the Licensor or
+
176
its personnel of the modified Documentation or any Product, or any
+
177
kind of implication by the Licensor or its personnel in the
+
178
preparation of the modified Documentation or Product.
+
179
+
180
6.3. CERN may publish updated versions of this Licence which retain
+
181
the same general provisions as this version, but differ in detail so
+
182
far this is required and reasonable. New versions will be published
+
183
with a unique version number.
+
184
+
185
6.4. This Licence shall terminate with immediate effect, upon written
+
186
notice and without involvement of a court if the Licensee fails to
+
187
comply with any of its terms and conditions, or if the Licensee
+
188
initiates legal action against Licensor in relation to this
+
189
Licence. Section 5 shall continue to apply.
+
+
+ + + + + + +
+
+
+ + + + +
+
+ + + + + + diff --git a/common/CPU/68K30L/license/cern_ohl_v_1_2_howto.odt b/common/CPU/68K30L/license/cern_ohl_v_1_2_howto.odt new file mode 100644 index 00000000..0a1ea6ba Binary files /dev/null and b/common/CPU/68K30L/license/cern_ohl_v_1_2_howto.odt differ diff --git a/common/CPU/68K30L/license/cern_ohl_v_1_2_howto.pdf b/common/CPU/68K30L/license/cern_ohl_v_1_2_howto.pdf new file mode 100644 index 00000000..feec8175 Binary files /dev/null and b/common/CPU/68K30L/license/cern_ohl_v_1_2_howto.pdf differ diff --git a/common/CPU/68K30L/wf68K30L.sdc b/common/CPU/68K30L/wf68K30L.sdc new file mode 100644 index 00000000..9f93ed49 --- /dev/null +++ b/common/CPU/68K30L/wf68K30L.sdc @@ -0,0 +1,40 @@ +# +# Copyright 2014 Wolfgang Foerster Inventronik GmbH. +# +# This documentation describes Open Hardware and is licensed +# under the CERN OHL v. 1.2. You may redistribute and modify +# this documentation under the terms of the CERN OHL v.1.2. +# (http://ohwr.org/cernohl). This documentation is distributed +# WITHOUT ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING OF +# MERCHANTABILITY, SATISFACTORY QUALITY AND FITNESS FOR A +# PARTICULAR PURPOSE. Please see the CERN OHL v.1.2 for +# applicable conditions + +# Revision History + +# Revision 2K14B 20140922 WF +# Initial Release. + + +#************************************************************** +# Time Information +#************************************************************** + +# set_time_format -unit ns -decimal_places 3 + + + +#************************************************************** +# Create Clock +#************************************************************** + +# create_clock -name CLK -period 100.000 -waveform {0.000 50.000} [get_ports {CLK}] +create_clock -period 32.000 -name CLK [get_ports {CLK}] + +#derive_pll_clocks +#derive_pll_clocks -use_net_name +derive_clock_uncertainty + +#set_clock_groups -exclusive -group {CLK_PLL1} +#set_clock_groups -exclusive -group {CLK_PLL2} +#set_clock_groups -exclusive -group {CODEC_SCLK} diff --git a/common/CPU/68K30L/wf68k30L_address_registers.vhd b/common/CPU/68K30L/wf68k30L_address_registers.vhd new file mode 100644 index 00000000..0e7bd05f --- /dev/null +++ b/common/CPU/68K30L/wf68k30L_address_registers.vhd @@ -0,0 +1,680 @@ +------------------------------------------------------------------------ +---- ---- +---- WF68K30L IP Core: Address register logic. ---- +---- ---- +---- Description: ---- +---- This module provides the address registers, stack pointers, ---- +---- the address arithmetics, the program counter logic and the SFC ---- +---- and DFC registers. The address registers are accessible by two ---- +---- read and two write ports simultaneously. For more information ---- +---- refer to the MC68030 User' Manual. ---- +---- ---- +---- Author(s): ---- +---- - Wolfgang Foerster, wf@experiment-s.de; wf@inventronik.de ---- +---- ---- +------------------------------------------------------------------------ +---- ---- +---- Copyright 2014-2019 Wolfgang Foerster Inventronik GmbH. ---- +---- ---- +---- This documentation describes Open Hardware and is licensed ---- +---- under the CERN OHL v. 1.2. You may redistribute and modify ---- +---- this documentation under the terms of the CERN OHL v.1.2. ---- +---- (http://ohwr.org/cernohl). This documentation is distributed ---- +---- WITHOUT ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING OF ---- +---- MERCHANTABILITY, SATISFACTORY QUALITY AND FITNESS FOR A ---- +---- PARTICULAR PURPOSE. Please see the CERN OHL v.1.2 for ---- +---- applicable conditions ---- +---- ---- +------------------------------------------------------------------------ +-- +-- Revision History +-- +-- Revision 2K14B 20141201 WF +-- Initial Release. +-- Revision 2K16A 20160620 WF +-- Minor optimizations. +-- Revision 2K18A 20180620 WF +-- Changed ADR_ATN logic to be valid one clock cycle earlier. +-- Fixed PC restoring during exception processing. +-- Fixed the writing ISP_REG during EXG instruction with two address registers. +-- Fixed writing the stack pointer registers (MSBIT is used now). +-- The address registers are always written long. +-- Bugfix: exception handler do not increment and decrement the USP any more. +-- MOVEM-Fix: the effective address in memory to register is stored (STORE_AEFF) not to be overwritten in case the addressing register is also loaded. +-- Revision 2K19A 2019## WF +-- Removed ADR_ATN. We do not need this any more. +-- Fixed the condition if UNMARK and AR_MARK_USED are asserted simultaneously (see process P_IN_USE). +-- Fixed the '0' conditions for AR_IN_USE. +-- + +use work.WF68K30L_PKG.all; + +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_unsigned.all; + +entity WF68K30L_ADDRESS_REGISTERS is + port ( + CLK : in std_logic; + RESET : in bit; + + -- Address and data: + AR_IN_1 : in std_logic_vector(31 downto 0); + AR_IN_2 : in std_logic_vector(31 downto 0); + AR_OUT_1 : out std_logic_vector(31 downto 0); + AR_OUT_2 : out std_logic_vector(31 downto 0); + INDEX_IN : in std_logic_vector(31 downto 0); + PC : out std_logic_vector(31 downto 0); -- Program counter (or sPC) always word aligned. + PC_EW_OFFSET : in std_logic_vector(3 downto 0); -- Offset to the first address extension word. + FETCH_MEM_ADR : in bit; + STORE_ADR_FORMAT : in bit; + STORE_ABS_HI : in bit; + STORE_ABS_LO : in bit; + STORE_D16 : in bit; + STORE_D32_LO : in bit; + STORE_D32_HI : in bit; + STORE_DISPL : in bit; + STORE_MEM_ADR : in bit; + STORE_OD_HI : in bit; + STORE_OD_LO : in bit; + STORE_AEFF : in bit; + OP_SIZE : in OP_SIZETYPE; + + ADR_OFFSET : in std_logic_vector(31 downto 0); + ADR_MARK_USED : in bit; + USE_APAIR : in boolean; + ADR_IN_USE : out bit; + + ADR_MODE : in std_logic_vector(2 downto 0); + AMODE_SEL : in std_logic_vector(2 downto 0); + USE_DREG : in bit; -- Use data register as address pointer. + ADR_EFF : out std_logic_vector(31 downto 0); -- This is the effective address. + ADR_EFF_WB : out std_logic_vector(31 downto 0); -- This is the effective address. + + DFC : out std_logic_vector(2 downto 0); + DFC_WR : in bit; + SFC : out std_logic_vector(2 downto 0); + SFC_WR : in bit; + + ISP_DEC : in bit; + ISP_RD : in bit; + ISP_WR : in bit; + MSP_RD : in bit; + MSP_WR : in bit; + USP_RD : in bit; + USP_WR : in bit; + + -- Registers controls: + AR_MARK_USED : in bit; + AR_IN_USE : out bit; + AR_SEL_RD_1 : in std_logic_vector(2 downto 0); + AR_SEL_RD_2 : in std_logic_vector(2 downto 0); + AR_SEL_WR_1 : in std_logic_vector(2 downto 0); + AR_SEL_WR_2 : in std_logic_vector(2 downto 0); + AR_DEC : in bit; -- Address register decrement. + AR_INC : in bit; -- Address register increment. + AR_WR_1 : in bit; -- Address register write. + AR_WR_2 : in bit; -- Address register write. + UNMARK : in bit; + + EXT_WORD : in std_logic_vector(15 downto 0); + + MBIT : in std_logic; + SBIT : in std_logic; + + SP_ADD_DISPL : in bit; + RESTORE_ISP_PC : in bit; + + -- Other controls: + DISPLACEMENT : in std_logic_vector(31 downto 0); + PC_ADD_DISPL : in bit; + PC_INC : in bit; -- Program counter increment. + PC_LOAD : in bit; -- Program counter write. + PC_RESTORE : in bit; + PC_OFFSET : in std_logic_vector(7 downto 0) + ); +end entity WF68K30L_ADDRESS_REGISTERS; + +architecture BEHAVIOR of WF68K30L_ADDRESS_REGISTERS is +type AR_TYPE is array(0 to 6) of std_logic_vector(31 downto 0); +signal ADR_EFF_I : std_logic_vector(31 downto 0); +signal AR : AR_TYPE; -- Address registers A0 to A6. +signal AR_OUT_1_I : std_logic_vector(31 downto 0); +signal AR_OUT_2_I : std_logic_vector(31 downto 0); +signal ADR_WB : std_logic_vector(32 downto 0); +signal AR_PNTR_1 : integer range 0 to 7; +signal AR_PNTR_2 : integer range 0 to 7; +signal AR_PNTR_WB_1 : integer range 0 to 7; +signal AR_PNTR_WB_2 : integer range 0 to 7; +signal AR_USED_1 : std_logic_vector(3 downto 0); +signal AR_USED_2 : std_logic_vector(3 downto 0); +signal B_S : std_logic := '0'; -- Base register suppress. +signal BD_SIZE : std_logic_vector(1 downto 0); -- Indexed / Indirect. +signal DFC_REG : std_logic_vector(2 downto 0); -- Special function code registers. +signal F_E : std_logic; -- Full extension word. +signal I_IS : std_logic_vector(2 downto 0); -- Indexed / Indirect. +signal I_S : std_logic; -- Index suppress. +signal ISP_REG : std_logic_vector(31 downto 0); -- Interrupt stack pointer (refers to A7'' in the supervisor mode). +signal MSBIT : std_logic_vector(1 downto 0); +signal MSP_REG : std_logic_vector(31 downto 0); -- Master stack pointer (refers to A7' in the supervisor mode). +signal PC_I : std_logic_vector(31 downto 0); -- Active program counter. +signal SCALE : std_logic_vector(1 downto 0); -- Scale information for the index. +signal SFC_REG : std_logic_vector(2 downto 0); -- Special function code registers. +signal USP_REG : std_logic_vector(31 downto 0); -- User stack pointer (refers to A7 in the user mode.). +begin + INBUFFER: process + begin + wait until CLK = '1' and CLK' event; + if AR_MARK_USED = '1' then + AR_PNTR_WB_1 <= conv_integer(AR_SEL_WR_1); + AR_PNTR_WB_2 <= conv_integer(AR_SEL_WR_2); + end if; + end process INBUFFER; + + AR_PNTR_1 <= conv_integer(AR_SEL_RD_1); + AR_PNTR_2 <= conv_integer(AR_SEL_RD_2); + + P_IN_USE: process + variable DELAY : boolean; + begin + wait until CLK = '1' and CLK' event; + if RESET = '1' or (UNMARK = '1' and AR_MARK_USED = '0') then + AR_USED_1(3) <= '0'; + AR_USED_2(3) <= '0'; + elsif AR_MARK_USED = '1' then + AR_USED_1 <= '1' & AR_SEL_WR_1; + if USE_APAIR = true then + AR_USED_2 <= '1' & AR_SEL_WR_2; + end if; + MSBIT <= MBIT & SBIT; + end if; + -- + if RESET = '1' or (UNMARK = '1' and AR_MARK_USED = '0') then + ADR_WB(32) <= '0'; + DELAY := false; + elsif ADR_MARK_USED = '1' then + DELAY := true; -- One clock cycle address calculation delay. + elsif DELAY = true then + ADR_WB <= '1' & ADR_EFF_I; + DELAY := false; + end if; + end process P_IN_USE; + + AR_IN_USE <= '0' when AR_USED_1(3) = '1' and AR_USED_1(2 downto 0) = "111" and SBIT = '1' and MSBIT(1) /= MBIT else -- Wrong stack pointer. + '0' when AR_USED_2(3) = '1' and AR_USED_2(2 downto 0) = "111" and SBIT = '1' and MSBIT(1) /= MBIT else -- Wrong stack pointer. + '1' when AR_USED_1(3) = '1' and AR_USED_1(2 downto 0) = AR_SEL_RD_1 else + '1' when AR_USED_1(3) = '1' and AR_USED_1(2 downto 0) = AR_SEL_RD_2 else + '1' when AR_USED_2(3) = '1' and AR_USED_2(2 downto 0) = AR_SEL_RD_1 else + '1' when AR_USED_2(3) = '1' and AR_USED_2(2 downto 0) = AR_SEL_RD_2 else '0'; + + AR_OUT_1 <= AR_OUT_1_I; + AR_OUT_2 <= AR_OUT_2_I; + + ADR_IN_USE <= '1' when ADR_WB(32) = '1' and ADR_WB(31 downto 2) = ADR_EFF_I(31 downto 2) else -- Actual long word address. + '1' when ADR_WB(32) = '1' and ADR_WB(31 downto 2) - '1' = ADR_EFF_I(31 downto 2) else -- Lock a misaligned access. + '1' when ADR_WB(32) = '1' and ADR_WB(31 downto 2) + '1' = ADR_EFF_I(31 downto 2) else '0'; -- Lock a misaligned access. + + ADR_FORMAT: process + begin + wait until CLK = '1' and CLK' event; + if STORE_ADR_FORMAT = '1' then + SCALE <= EXT_WORD(10 downto 9); + F_E <= EXT_WORD(8); + B_S <= EXT_WORD(7); + I_S <= EXT_WORD(6); + BD_SIZE <= EXT_WORD(5 downto 4); + I_IS <= EXT_WORD(2 downto 0); + end if; + end process ADR_FORMAT; + + ADDRESS_MODES: process(ADR_MODE, AMODE_SEL, AR, AR_IN_1, AR_PNTR_1, B_S, + CLK, F_E, FETCH_MEM_ADR, I_S, I_IS, ISP_REG, MBIT, MSP_REG, + PC_EW_OFFSET, PC_I, RESTORE_ISP_PC, SBIT, USE_DREG, USP_REG) + -- The effective address calculation takes place in this process depending on the + -- selected addressing mode. + -- The PC address (PC_I) used for the address calculation points to the first + -- extension word used. + variable ABS_ADDRESS : std_logic_vector(31 downto 0); + variable ADR_EFF_VAR : std_logic_vector(31 downto 0); + variable ADR_EFF_TMP : std_logic_vector(31 downto 0); + variable ADR_MUX : std_logic_vector(31 downto 0); + variable BASE_DISPL : std_logic_vector(31 downto 0); + variable I_S_IS : std_logic_vector(3 downto 0); + variable INDEX : std_logic_vector(31 downto 0) := x"00000000"; + variable INDEX_SCALED : std_logic_vector(31 downto 0); + variable MEM_ADR : std_logic_vector(31 downto 0); + variable OUTER_DISPL : std_logic_vector(31 downto 0); + variable PCVAR : std_logic_vector(31 downto 0); + begin + I_S_IS := I_S & I_IS; + PCVAR := PC_I + PC_EW_OFFSET; -- This is the address of the extension word. + + if CLK = '1' and CLK' event then + -- This logic selects the INDEX from one of the data registers or from one of + -- the address registers. Furthermore the index needs to be sign extended from + -- 8 bit to 32 bit or from 16 bit to 32 bit dependent on the address mode. + -- In case of a long word operation, no extension is required. The index is + -- multiplied by 1, 2, 4 or 8. + if STORE_ADR_FORMAT = '1' and EXT_WORD(15) = '0' and EXT_WORD(11) = '1' then + INDEX := INDEX_IN; -- Long data register. + elsif STORE_ADR_FORMAT = '1' and EXT_WORD(15) = '0' then + for i in 31 downto 16 loop + INDEX(i) := INDEX_IN(15); + end loop; + INDEX(15 downto 0) := INDEX_IN(15 downto 0); -- Sign extended data register; + elsif STORE_ADR_FORMAT = '1' and EXT_WORD(11) = '1' then -- Long address register. + if EXT_WORD(14 downto 12) = "111" and SBIT = '1' and MBIT = '1' then + INDEX := MSP_REG; + elsif EXT_WORD(14 downto 12) = "111" and SBIT = '1' and MBIT = '0' then + INDEX := ISP_REG; + elsif EXT_WORD(14 downto 12) = "111" and SBIT = '0' then + INDEX := USP_REG; + else + INDEX := AR(conv_integer(EXT_WORD(14 downto 12))); + end if; + elsif STORE_ADR_FORMAT = '1' then -- Sign extended address register; + if EXT_WORD(14 downto 12) = "111" and SBIT = '1' and MBIT = '1' then + for i in 31 downto 16 loop + INDEX(i) := MSP_REG(15); + end loop; + INDEX(15 downto 0) := MSP_REG(15 downto 0); + elsif EXT_WORD(14 downto 12) = "111" and SBIT = '1' and MBIT = '0' then + for i in 31 downto 16 loop + INDEX(i) := ISP_REG(15); + end loop; + INDEX(15 downto 0) := ISP_REG(15 downto 0); + elsif EXT_WORD(14 downto 12) = "111" and SBIT = '0' then + for i in 31 downto 16 loop + INDEX(i) := USP_REG(15); + end loop; + INDEX(15 downto 0) := USP_REG(15 downto 0); + else + for i in 31 downto 16 loop + INDEX(i) := AR(conv_integer(EXT_WORD(14 downto 12)))(15); + end loop; + INDEX(15 downto 0) := AR(conv_integer(EXT_WORD(14 downto 12)))(15 downto 0); + end if; + end if; + -- + case SCALE is + when "00" => INDEX_SCALED := INDEX; -- Multiple by 1. + when "01" => INDEX_SCALED := INDEX(30 downto 0) & '0'; -- Multiple by 2. + when "10" => INDEX_SCALED := INDEX(29 downto 0) & "00"; -- Multiple by 4. + when others => INDEX_SCALED := INDEX(28 downto 0) & "000"; -- Multiple by 8. + end case; + -- + -- Register for memory indirect addressing modes. + if STORE_MEM_ADR = '1' then + MEM_ADR := AR_IN_1; + end if; + -- + -- The displacement needs to be sign extended from 8 bit to 32, from 16 bit to 32 bit or + -- not extended dependent on the address mode. + if RESET = '1' then + BASE_DISPL := (others => '0'); -- Null base displacement. + elsif STORE_ADR_FORMAT = '1' and EXT_WORD(8) = '1' and EXT_WORD(5 downto 4) = "01" then + BASE_DISPL := (others => '0'); -- Null base displacement. + elsif STORE_ADR_FORMAT = '1' and EXT_WORD(8) = '0' then + for i in 31 downto 8 loop + BASE_DISPL(i) := EXT_WORD(7); + end loop; + BASE_DISPL(7 downto 0) := EXT_WORD(7 downto 0); + elsif STORE_D16 = '1' then + for i in 31 downto 16 loop + BASE_DISPL(i) := EXT_WORD(15); + end loop; + BASE_DISPL(15 downto 0) := EXT_WORD; + elsif STORE_D32_LO = '1' then + if BD_SIZE = "10" then -- Word displacement. + for i in 31 downto 16 loop + BASE_DISPL(i) := EXT_WORD(15); + end loop; + end if; + BASE_DISPL(15 downto 0) := EXT_WORD; + elsif STORE_D32_HI = '1' then + BASE_DISPL(31 downto 16) := EXT_WORD; + elsif STORE_DISPL = '1' then + BASE_DISPL := DISPLACEMENT; + end if; + -- + -- The outer displacement may be NULL, WORD or LONG. + if STORE_ADR_FORMAT = '1' and EXT_WORD(8) = '1' and EXT_WORD(1 downto 0) = "01" then + OUTER_DISPL := (others => '0'); -- Null outer displacement. + elsif STORE_OD_LO = '1' then + if I_IS(1 downto 0) = "10" then + for i in 31 downto 16 loop + OUTER_DISPL(i) := EXT_WORD(15); + end loop; + end if; + OUTER_DISPL(15 downto 0) := EXT_WORD; + elsif STORE_OD_HI = '1' then + OUTER_DISPL(31 downto 16) := EXT_WORD; + end if; + -- + if STORE_ABS_LO = '1' then + if AMODE_SEL = "000" then + for i in 31 downto 16 loop + ABS_ADDRESS(i) := EXT_WORD(15); + end loop; + end if; + ABS_ADDRESS(15 downto 0) := EXT_WORD; + elsif STORE_ABS_HI = '1' then + ABS_ADDRESS(31 downto 16) := EXT_WORD; + end if; + end if; + + if ADR_MODE = "110" and FETCH_MEM_ADR = '1' and F_E = '1' and B_S = '1' then + ADR_MUX := x"00000000"; -- Base register suppress. + elsif ADR_MODE = "111" and FETCH_MEM_ADR = '1' and AMODE_SEL = "011" and F_E = '1' and B_S = '1' then + ADR_MUX := x"00000000"; -- Base register suppress. + elsif USE_DREG = '1' then + ADR_MUX := AR_IN_1; + else + case AR_PNTR_1 is + when 7 => + if SBIT = '1' and MBIT = '0' then + ADR_MUX := ISP_REG; + elsif SBIT = '1' then + ADR_MUX := MSP_REG; + else + ADR_MUX := USP_REG; + end if; + when others => ADR_MUX := AR(AR_PNTR_1); + end case; + end if; + + case ADR_MODE is + -- when "000" | "001" => Direct address modes: no effective address required. + when "010" | "011" | "100" => + ADR_EFF_VAR := ADR_MUX; -- (An), (An)+, -(An). + when "101" => -- Address register indirect with offset. Assembler syntax: (d16,An). + ADR_EFF_VAR := ADR_MUX + BASE_DISPL; -- (d16,An). + when "110" => + if F_E = '0' then -- Brief extension word. + ADR_EFF_VAR := ADR_MUX + BASE_DISPL + INDEX_SCALED; -- (d8, An, Xn, SIZE*SCALE). + else -- Full extension word. + case I_S_IS is + when "0000" | "1000" => -- No memory indirect action. + ADR_EFF_VAR := ADR_MUX + BASE_DISPL + INDEX_SCALED; -- (bd, An, Xn, SIZE*SCALE). + when "0001" | "0010" | "0011" => -- Memory indirect preindexed. + if FETCH_MEM_ADR = '1' then + ADR_EFF_VAR := ADR_MUX + BASE_DISPL + INDEX_SCALED; + else + ADR_EFF_VAR := MEM_ADR + OUTER_DISPL; + end if; + when "0101" | "0110" | "0111" => -- Memory indirect postindexed. + if FETCH_MEM_ADR = '1' then + ADR_EFF_VAR := ADR_MUX + BASE_DISPL; + else + ADR_EFF_VAR := MEM_ADR + INDEX_SCALED + OUTER_DISPL; + end if; + when "1001" | "1010" | "1011" => -- Memory indirect. + if FETCH_MEM_ADR = '1' then + ADR_EFF_VAR := ADR_MUX + BASE_DISPL; + else + ADR_EFF_VAR := MEM_ADR + OUTER_DISPL; + end if; + when others => + ADR_EFF_VAR := (others => '-'); -- Reserved, don't care. + end case; + end if; + when "111" => + case AMODE_SEL is + when "000" | "001" => + ADR_EFF_VAR := ABS_ADDRESS; + when "010" => -- (d16, PC). + ADR_EFF_VAR := PCVAR + BASE_DISPL; + when "011" => + if F_E = '0' then -- Brief extension word. + -- Assembler syntax: (d8,PC,Xn.SIZE*SCALE). + ADR_EFF_VAR := PCVAR + BASE_DISPL + INDEX_SCALED; -- (d8, PC, Xn, SIZE*SCALE). + else -- Full extension word. + case I_S_IS is + when "0000" | "1000" => -- No memory indirect action. + ADR_EFF_VAR := PCVAR + BASE_DISPL + INDEX_SCALED; -- (bd, PC, Xn, SIZE*SCALE). + when "0001" | "0010" | "0011" => -- Memory indirect preindexed. + if FETCH_MEM_ADR = '1' then + ADR_EFF_VAR := PCVAR + BASE_DISPL + INDEX_SCALED; + else + ADR_EFF_VAR := MEM_ADR + OUTER_DISPL; + end if; + when "0101" | "0110" | "0111" => -- Memory indirect postindexed. + if FETCH_MEM_ADR = '1' then + ADR_EFF_VAR := PCVAR + BASE_DISPL; + else + ADR_EFF_VAR := MEM_ADR + INDEX_SCALED + OUTER_DISPL; + end if; + when "1001" | "1010" | "1011" => -- Memory indirect. + if FETCH_MEM_ADR = '1' then + ADR_EFF_VAR := PCVAR + BASE_DISPL; + else + ADR_EFF_VAR := MEM_ADR + OUTER_DISPL; + end if; + when others => + ADR_EFF_VAR := (others => '-'); -- Reserved, don't care. + end case; + end if; + when others => + ADR_EFF_VAR := (others => '-'); -- Don't care, while not used. + end case; + when others => + ADR_EFF_VAR := (others => '-'); -- Result not required. + end case; + -- + if CLK = '1' and CLK' event then + if RESTORE_ISP_PC = '1' then + ADR_EFF_I <= ADR_OFFSET; -- During system initialization. + elsif STORE_AEFF = '1' then -- Used for MOVEM. + ADR_EFF_I <= ADR_EFF_TMP + ADR_OFFSET; -- Keep the effective address. See also CONTROL section. + else -- Normal operation: + ADR_EFF_I <= ADR_EFF_VAR + ADR_OFFSET; + ADR_EFF_TMP := ADR_EFF_VAR; + end if; + end if; + end process ADDRESS_MODES; + + ADR_EFF <= ADR_EFF_I; + ADR_EFF_WB <= ADR_WB(31 downto 0); + + -- Data outputs: + AR_OUT_1_I <= ISP_REG when ISP_RD = '1' else + MSP_REG when MSP_RD = '1' else + USP_REG when USP_RD = '1' else + AR(AR_PNTR_1) when AR_PNTR_1 < 7 else + MSP_REG when SBIT = '1' and MBIT = '1' else + ISP_REG when SBIT = '1' and MBIT = '0' else USP_REG; + + AR_OUT_2_I <= AR(AR_PNTR_2) when AR_PNTR_2 < 7 else + MSP_REG when SBIT = '1' and MBIT = '1' else + ISP_REG when SBIT = '1' and MBIT = '0' else USP_REG; + + PC <= PC_I; + + PROGRAM_COUNTER: process + -- Note: PC_LOAD and PC_ADD_DISPL must be highest + -- prioritized. The reason is that in case of jumps + -- or branches the Ipipe is flushed in connection + -- with PC_INC. In such cases PC_LOAD or PC_ADD_DISPL + -- are asserted simultaneously with PC_INC. + begin + wait until CLK = '1' and CLK' event; + if RESET = '1' then + PC_I <= (others => '0'); + elsif PC_LOAD = '1' then + PC_I <= AR_IN_1; + elsif PC_ADD_DISPL = '1' then + PC_I <= PC_I + DISPLACEMENT; + elsif PC_RESTORE = '1' then + PC_I <= AR_IN_1; -- Keep prioritization! + elsif PC_INC = '1' then + PC_I <= PC_I + PC_OFFSET; + end if; + end process PROGRAM_COUNTER; + + STACK_POINTERS: process + -- The registers are modeled in a way + -- that write and simultaneously increment + -- decrement and others are possible for + -- different registers. + begin + wait until CLK = '1' and CLK' event; + + ---------------------------------------- MSP section ---------------------------------------- + if RESET = '1' then + MSP_REG <= (others => '0'); + elsif AR_WR_1 = '1' and AR_PNTR_WB_1 = 7 and MSBIT = "11" then + MSP_REG <= AR_IN_1; -- Always written long. + end if; + + if AR_INC = '1' and AR_PNTR_1 = 7 and SBIT = '1' and MBIT = '1' then + case OP_SIZE is + when BYTE => MSP_REG <= MSP_REG + "10"; -- Increment by two! + when WORD => MSP_REG <= MSP_REG + "10"; -- Increment by two. + when others => MSP_REG <= MSP_REG + "100"; -- Increment by four, (LONG). + end case; + end if; + + if AR_DEC = '1' and AR_PNTR_1 = 7 and SBIT = '1' and MBIT = '1' then + case OP_SIZE is + when BYTE => MSP_REG <= MSP_REG - "10"; -- Decrement by two! + when WORD => MSP_REG <= MSP_REG - "10"; -- Decrement by two. + when others => MSP_REG <= MSP_REG - "100"; -- Decrement by four, (LONG). + end case; + end if; + + if MSP_WR = '1' then + MSP_REG <= AR_IN_1; + elsif SP_ADD_DISPL = '1' and AR_INC = '1' and SBIT = '1' and MBIT = '1' then + MSP_REG <= MSP_REG + DISPLACEMENT + "100"; -- Used for RTD. + elsif SP_ADD_DISPL = '1' and SBIT = '1' and MBIT = '1' then + MSP_REG <= MSP_REG + DISPLACEMENT; + end if; + + ---------------------------------------- ISP section ---------------------------------------- + if RESET = '1' then + ISP_REG <= (others => '0'); + elsif AR_WR_1 = '1' and AR_PNTR_WB_1 = 7 and MSBIT = "01" then + ISP_REG <= AR_IN_1; -- Always written long. + end if; + + if AR_INC = '1' and AR_PNTR_1 = 7 and SBIT = '1' and MBIT = '0' then + case OP_SIZE is + when BYTE => ISP_REG <= ISP_REG + "10"; -- Increment by two! + when WORD => ISP_REG <= ISP_REG + "10"; -- Increment by two. + when others => ISP_REG <= ISP_REG + "100"; -- Increment by four, (LONG). + end case; + end if; + + if ISP_DEC = '1' or (AR_DEC = '1' and AR_PNTR_1 = 7 and SBIT = '1' and MBIT = '0') then + case OP_SIZE is + when BYTE => ISP_REG <= ISP_REG - "10"; -- Decrement by two! + when WORD => ISP_REG <= ISP_REG - "10"; -- Decrement by two. + when others => ISP_REG <= ISP_REG - "100"; -- Decrement by four, (LONG). + end case; + end if; + + if ISP_WR = '1' then + ISP_REG <= AR_IN_1; + elsif SP_ADD_DISPL = '1' and AR_INC = '1' and SBIT = '1' and MBIT = '0' then + ISP_REG <= ISP_REG + DISPLACEMENT + "100"; -- Used for RTD. + elsif SP_ADD_DISPL = '1' and SBIT = '1' and MBIT = '0' then + ISP_REG <= ISP_REG + DISPLACEMENT; + end if; + + ---------------------------------------- USP section ---------------------------------------- + if RESET = '1' then + USP_REG <= (others => '0'); + elsif AR_WR_1 = '1' and AR_PNTR_WB_1 = 7 and MSBIT(0) = '0' then + USP_REG <= AR_IN_1; -- Always written long. + end if; + + if AR_INC = '1' and AR_PNTR_1 = 7 and SBIT = '0' then + case OP_SIZE is + when BYTE => USP_REG <= USP_REG + "10"; -- Increment by two! + when WORD => USP_REG <= USP_REG + "10"; -- Increment by two. + when others => USP_REG <= USP_REG + "100"; -- Increment by four, (LONG). + end case; + end if; + + if AR_DEC = '1' and AR_PNTR_1 = 7 and SBIT = '0' then + case OP_SIZE is + when BYTE => USP_REG <= USP_REG - "10"; -- Decrement by two! + when WORD => USP_REG <= USP_REG - "10"; -- Decrement by two. + when others => USP_REG <= USP_REG - "100"; -- Decrement by four, (LONG). + end case; + end if; + + if USP_WR = '1' then + USP_REG <= AR_IN_1; + elsif SP_ADD_DISPL = '1' and AR_INC = '1' and SBIT = '0' then + USP_REG <= USP_REG + DISPLACEMENT + "100"; -- Used for RTD. + elsif SP_ADD_DISPL = '1' and SBIT = '0' then + USP_REG <= USP_REG + DISPLACEMENT; + end if; + + if AR_WR_2 = '1' and AR_PNTR_WB_2 = 7 and MSBIT = "11" then + MSP_REG <= AR_IN_2; -- Used for EXG and UNLK. + elsif AR_WR_2 = '1' and AR_PNTR_WB_2 = 7 and MSBIT = "01" then + ISP_REG <= AR_IN_2; -- Used for EXG and UNLK. + elsif AR_WR_2 = '1' and AR_PNTR_WB_2 = 7 then + USP_REG <= AR_IN_2; -- Used for EXG and UNLK. + end if; + end process STACK_POINTERS; + + ADDRESS_REGISTERS: process + -- The registers are modeled in a way + -- that write and simultaneously increment + -- decrement and others are possible for + -- different registers. + begin + -- + wait until CLK = '1' and CLK' event; + + if RESET = '1' then + AR <= (others => (Others => '0')); + end if; + + if AR_WR_1 = '1' and AR_PNTR_WB_1 < 7 then + AR(AR_PNTR_WB_1) <= AR_IN_1; -- Always written long. + end if; + + if AR_INC = '1' and AR_PNTR_1 < 7 then + case OP_SIZE is + when BYTE => AR(AR_PNTR_1) <= AR(AR_PNTR_1) + '1'; + when WORD => AR(AR_PNTR_1) <= AR(AR_PNTR_1) + "10"; + when others => AR(AR_PNTR_1) <= AR(AR_PNTR_1) + "100"; + end case; + end if; + + if AR_DEC = '1' and AR_PNTR_1 < 7 then + case OP_SIZE is + when BYTE => AR(AR_PNTR_1) <= AR(AR_PNTR_1) - '1'; + when WORD => AR(AR_PNTR_1) <= AR(AR_PNTR_1) - "10"; + when others => AR(AR_PNTR_1) <= AR(AR_PNTR_1) - "100"; + end case; + end if; + + if AR_WR_2 = '1' and AR_PNTR_WB_2 < 7 then + AR(AR_PNTR_WB_2) <= AR_IN_2; -- Used for EXG and UNLK. + end if; + end process ADDRESS_REGISTERS; + + FCODES: process + -- These flip flops provide the alternate function + -- code registers. + variable SFC_REG : std_logic_vector(2 downto 0); + variable DFC_REG : std_logic_vector(2 downto 0); + begin + wait until CLK = '1' and CLK' event; + if DFC_WR = '1' then + DFC_REG := AR_IN_1(2 downto 0); + end if; + -- + if SFC_WR = '1' then + SFC_REG := AR_IN_1(2 downto 0); + end if; + -- + DFC <= DFC_REG; + SFC <= SFC_REG; + end process FCODES; +end BEHAVIOR; diff --git a/common/CPU/68K30L/wf68k30L_alu.vhd b/common/CPU/68K30L/wf68k30L_alu.vhd new file mode 100644 index 00000000..58d5cdaf --- /dev/null +++ b/common/CPU/68K30L/wf68k30L_alu.vhd @@ -0,0 +1,1264 @@ +------------------------------------------------------------------------ +---- ---- +---- WF68K30L IP Core: Address register logic. ---- +---- ---- +---- Description: ---- +---- This arithmetical logical unit handles all integer operations. ---- +---- The shift operations are computed by a standard shifter within ---- +---- up to 32 clock cycles depending on the shift width. This unit ---- +---- also handles the bit field operations within one clock cycle. ---- +---- The multiplication is modeled as a hardware multiplier which ---- +---- calculates the result in one clock cycle. The division requi- ---- +---- res 32 clock cycles for 32 bit wide operands. The date which ---- +---- is required for the respective operation is stored in regis- ---- +---- ters. The ALU works together with the writeback of the oper- ---- +---- ands as third stage in the pipelined architecture. The hand- ---- +---- shaking is provided by ALU_REQ, ALU_ACK and ALU_BUSY. For more ---- +---- information refer to the MC68010 User' Manual. ---- +---- ---- +---- ---- +---- Author(s): ---- +---- - Wolfgang Foerster, wf@experiment-s.de; wf@inventronik.de ---- +---- ---- +------------------------------------------------------------------------ +---- ---- +---- Copyright 2014-2019 Wolfgang Foerster Inventronik GmbH. ---- +---- ---- +---- This documentation describes Open Hardware and is licensed ---- +---- under the CERN OHL v. 1.2. You may redistribute and modify ---- +---- this documentation under the terms of the CERN OHL v.1.2. ---- +---- (http://ohwr.org/cernohl). This documentation is distributed ---- +---- WITHOUT ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING OF ---- +---- MERCHANTABILITY, SATISFACTORY QUALITY AND FITNESS FOR A ---- +---- PARTICULAR PURPOSE. Please see the CERN OHL v.1.2 for ---- +---- applicable conditions ---- +---- ---- +------------------------------------------------------------------------ +-- +-- Revision History +-- +-- Revision 2K14B 20141201 WF +-- Initial Release. +-- Revision 2K14B 20141201 WF +-- Fixed the CAS and CAS2 conditional testing. Thanks to Raymond Mounissamy for the correct code. +-- Revision 2K18A 20180620 WF +-- Bug fix: MOVEM sign extension. +-- Fix for restoring correct values during the DIVS and DIVU in word format. +-- Fixed the SUBQ calculation. +-- Rearranged the Offset for the JSR instruction. +-- EXT instruction uses now RESULT(63 downto 0). +-- Shifter signals now ready if shift width is zero. +-- Fixed wrong condition codes for AND_B, ANDI, EOR, EORI, OR_B, ORI and NOT_B. +-- Fixed writeback issues in the status register logic. +-- Fixed the condition code calculation for NEG and NEGX. +-- Revision 2K19A 20190620 WF +-- Fixed a bug in MULU.W (input operands are now 16 bit wide). +-- + +library work; +use work.WF68K30L_PKG.all; + +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_unsigned.all; +use ieee.numeric_std.all; + +entity WF68K30L_ALU is + port ( + CLK : in std_logic; + RESET : in bit; + + LOAD_OP1 : in bit; + LOAD_OP2 : in bit; + LOAD_OP3 : in bit; + + OP1_IN : in Std_Logic_Vector(31 downto 0); + OP2_IN : in Std_Logic_Vector(31 downto 0); + OP3_IN : in Std_Logic_Vector(31 downto 0); + + BF_OFFSET_IN : in Std_Logic_Vector(31 downto 0); + BF_WIDTH_IN : in Std_Logic_Vector(5 downto 0); + BITPOS_IN : in Std_Logic_Vector(4 downto 0); + + RESULT : out Std_Logic_Vector(63 downto 0); + + ADR_MODE_IN : in Std_Logic_Vector(2 downto 0); + OP_SIZE_IN : in OP_SIZETYPE; + OP_IN : in OP_68K; + OP_WB : in OP_68K; + BIW_0_IN : in Std_Logic_Vector(11 downto 0); + BIW_1_IN : in Std_Logic_Vector(15 downto 0); + + -- The Flags: + SR_WR : in bit; + SR_INIT : in bit; + SR_CLR_MBIT : in bit; + CC_UPDT : in bit; + + STATUS_REG_OUT : out std_logic_vector(15 downto 0); + ALU_COND : out boolean; + + -- Status and Control: + ALU_INIT : in bit; -- Strobe. + ALU_BSY : out bit; + ALU_REQ : buffer bit; + ALU_ACK : in bit; + USE_DREG : in bit; -- Used for CAS2, CHK2, CMP2. + HILOn : in bit; + IRQ_PEND : in std_logic_vector(2 downto 0); + TRAP_CHK : out bit; -- Trap due to the CHK, CHK2 instructions. + TRAP_DIVZERO : out bit -- Trap due to divide by zero. + ); +end entity WF68K30L_ALU; + +architecture BEHAVIOUR of WF68K30L_ALU is +type DIV_STATES is (IDLE, INIT, CALC); +type SHIFT_STATES is (IDLE, RUN); +signal ALU_COND_I : boolean; +signal ADR_MODE : Std_Logic_Vector(2 downto 0); +signal BITPOS : integer range 0 to 31; +signal BF_DATA_IN : Std_Logic_Vector(39 downto 0); +signal BF_LOWER_BND : integer range 0 to 39; +signal BF_OFFSET : Std_Logic_Vector(31 downto 0); +signal BF_UPPER_BND : integer range 0 to 39; +signal BF_WIDTH : integer range 1 to 32; +signal BIW_0 : Std_Logic_Vector(11 downto 0); +signal BIW_1 : Std_Logic_Vector(15 downto 0); +signal CAS2_COND : boolean; +signal CB_BCD : std_logic; +signal CHK_CMP_COND : boolean; +signal CHK2CMP2_DR : bit; +signal DIV_RDY : bit; +signal DIV_STATE : DIV_STATES := IDLE; +signal MSB : integer range 0 to 31; +signal OP : OP_68K := UNIMPLEMENTED; +signal OP1 : Std_Logic_Vector(31 downto 0); +signal OP2 : Std_Logic_Vector(31 downto 0); +signal OP3 : Std_Logic_Vector(31 downto 0); +signal OP1_SIGNEXT : Std_Logic_Vector(31 downto 0); +signal OP2_SIGNEXT : Std_Logic_Vector(31 downto 0); +signal OP3_SIGNEXT : Std_Logic_Vector(31 downto 0); +signal OP_SIZE : OP_SIZETYPE := LONG; +signal QUOTIENT : unsigned(31 downto 0); +signal REMAINDER : unsigned(31 downto 0); +signal RESULT_BCDOP : Std_Logic_Vector(7 downto 0); +signal RESULT_BITFIELD : Std_Logic_Vector(39 downto 0); +signal RESULT_BITOP : Std_Logic_Vector(31 downto 0); +signal RESULT_INTOP : Std_Logic_Vector(31 downto 0); +signal RESULT_LOGOP : Std_Logic_Vector(31 downto 0); +signal RESULT_MUL : Std_Logic_Vector(63 downto 0); +signal RESULT_SHIFTOP : Std_Logic_Vector(31 downto 0); +signal RESULT_OTHERS : Std_Logic_Vector(31 downto 0); +signal SHIFT_STATE : SHIFT_STATES; +signal SHIFT_WIDTH : Std_Logic_Vector(5 downto 0); +signal SHIFT_WIDTH_IN : Std_Logic_Vector(5 downto 0); +signal SHFT_LOAD : bit; +signal SHFT_RDY : bit; +signal SHFT_EN : bit; +signal STATUS_REG : Std_Logic_Vector(15 downto 0); +signal VFLAG_DIV : std_logic; +signal XFLAG_SHFT : std_logic; +signal XNZVC : Std_Logic_Vector(4 downto 0); +begin + PARAMETER_BUFFER: process + begin + wait until CLK = '1' and CLK' event; + if ALU_INIT = '1' then + ADR_MODE <= ADR_MODE_IN; + CHK2CMP2_DR <= USE_DREG; + OP_SIZE <= OP_SIZE_IN; + OP <= OP_IN; + BIW_0 <= BIW_0_IN; + BIW_1 <= BIW_1_IN; + BF_OFFSET <= BF_OFFSET_IN; + BITPOS <= To_Integer(unsigned(BITPOS_IN)); + BF_WIDTH <= To_Integer(unsigned(BF_WIDTH_IN)); + BF_UPPER_BND <= 39 - To_Integer(unsigned(BITPOS_IN)); + SHIFT_WIDTH <= SHIFT_WIDTH_IN; + -- + if To_Integer(unsigned(BITPOS_IN)) + To_Integer(unsigned(BF_WIDTH_IN)) > 40 then + BF_LOWER_BND <= 0; + else + BF_LOWER_BND <= 40 - (To_Integer(unsigned(BITPOS_IN)) + To_Integer(unsigned(BF_WIDTH_IN))); + end if; + end if; + end process PARAMETER_BUFFER; + + OPERANDS: process + -- During instruction execution, the buffers are written + -- before or during ALU_INIT and copied to the operands + -- during ALU_INIT. + variable OP1_BUFFER : Std_Logic_Vector(31 downto 0); + variable OP2_BUFFER : Std_Logic_Vector(31 downto 0); + variable OP3_BUFFER : Std_Logic_Vector(31 downto 0); + begin + wait until CLK = '1' and CLK' event; + if LOAD_OP1 = '1' then + OP1_BUFFER := OP1_IN; + end if; + + if LOAD_OP2 = '1' then + OP2_BUFFER := OP2_IN; + end if; + + if LOAD_OP3 = '1' then + OP3_BUFFER := OP3_IN; + end if; + + if ALU_INIT = '1' then + OP1 <= OP1_BUFFER; + OP2 <= OP2_BUFFER; + OP3 <= OP3_BUFFER; + end if; + end process OPERANDS; + + P_BUSY: process + begin + wait until CLK = '1' and CLK' event; + if ALU_INIT = '1' then + ALU_BSY <= '1'; + elsif ALU_ACK = '1' or RESET = '1' then + ALU_BSY <= '0'; + end if; + -- This signal requests the control state machine to proceed when the ALU is ready. + if ALU_ACK = '1' then + ALU_REQ <= '0'; + elsif (OP = ASL or OP = ASR or OP = LSL or OP = LSR or OP = ROTL or OP = ROTR or OP = ROXL or OP = ROXR) and SHFT_RDY = '1' then + ALU_REQ <= '1'; + elsif (OP = DIVS or OP = DIVU) and DIV_RDY = '1' then + ALU_REQ <= '1'; + elsif OP_IN = DIVS or OP_IN = DIVU then + null; + elsif OP_IN = ASL or OP_IN = ASR or OP_IN = LSL or OP_IN = LSR then + null; + elsif OP_IN = ROTL or OP_IN = ROTR or OP_IN = ROXL or OP_IN = ROXR then + null; + elsif ALU_INIT = '1' then + ALU_REQ <= '1'; + end if; + end process P_BUSY; + + with OP_SIZE select + MSB <= 31 when LONG, + 15 when WORD, + 7 when BYTE; + + SIGNEXT: process(OP, OP1, OP2, OP3, OP_SIZE) + -- This module provides the required sign extensions. + begin + case OP_SIZE is + when LONG => + OP1_SIGNEXT <= OP1; + OP2_SIGNEXT <= OP2; + OP3_SIGNEXT <= OP3; + when WORD => + for i in 31 downto 16 loop + OP1_SIGNEXT(i) <= OP1(15); + OP2_SIGNEXT(i) <= OP2(15); + OP3_SIGNEXT(i) <= OP3(15); + end loop; + OP1_SIGNEXT(15 downto 0) <= OP1(15 downto 0); + OP2_SIGNEXT(15 downto 0) <= OP2(15 downto 0); + OP3_SIGNEXT(15 downto 0) <= OP3(15 downto 0); + when BYTE => + for i in 31 downto 8 loop + OP1_SIGNEXT(i) <= OP1(7); + OP2_SIGNEXT(i) <= OP2(7); + OP3_SIGNEXT(i) <= OP3(7); + end loop; + OP1_SIGNEXT(7 downto 0) <= OP1(7 downto 0); + OP2_SIGNEXT(7 downto 0) <= OP2(7 downto 0); + OP3_SIGNEXT(7 downto 0) <= OP3(7 downto 0); + end case; + end process SIGNEXT; + + P_BCDOP: process(OP, STATUS_REG, OP1, OP2) + -- The BCD operations are all byte wide and unsigned. + variable X_IN_I : unsigned(0 downto 0); + variable TEMP0 : unsigned(4 downto 0); + variable TEMP1 : unsigned(4 downto 0); + variable Z_0 : unsigned(3 downto 0); + variable C_0 : unsigned(0 downto 0); + variable Z_1 : unsigned(3 downto 0); + variable C_1 : std_logic; + variable S_0 : unsigned(3 downto 0); + variable S_1 : unsigned(3 downto 0); + begin + X_IN_I(0) := STATUS_REG(4); -- Inverted extended Flag. + + case OP is + when ABCD => + TEMP0 := unsigned('0' & OP2(3 downto 0)) + unsigned('0' & OP1(3 downto 0)) + ("0000" & X_IN_I); + when NBCD => + TEMP0 := unsigned(OP1(4 downto 0)) - unsigned('0' & OP2(3 downto 0)) - ("0000" & X_IN_I); + when others => -- Valid for SBCD. + TEMP0 := unsigned('0' & OP2(3 downto 0)) - unsigned('0' & OP1(3 downto 0)) - ("0000" & X_IN_I); + end case; + + if Std_Logic_Vector(TEMP0) > "01001" then + Z_0 := "0110"; + C_0 := "1"; + else + Z_0 := "0000"; + C_0 := "0"; + end if; + + case OP is + when ABCD => + TEMP1 := unsigned('0' & OP2(7 downto 4)) + unsigned('0' & OP1(7 downto 4)) + ("0000" & C_0); + when NBCD => + TEMP1 := unsigned(OP1(4 downto 0)) - unsigned('0' & OP2(7 downto 4)) - ("0000" & X_IN_I); + when others => -- Valid for SBCD. + TEMP1 := unsigned('0' & OP2(7 downto 4)) - unsigned('0' & OP1(7 downto 4)) - ("0000" & C_0); + end case; + + if Std_Logic_Vector(TEMP1) > "01001" then + Z_1 := "0110"; + C_1 := '1'; + else + Z_1 := "0000"; + C_1 := '0'; + end if; + + case OP is + when ABCD => + S_1 := TEMP1(3 downto 0) + Z_1; + S_0 := TEMP0(3 downto 0) + Z_0; + when others => -- Valid for SBCD, NBCD. + S_1 := TEMP1(3 downto 0) - Z_1; + S_0 := TEMP0(3 downto 0) - Z_0; + end case; + -- + CB_BCD <= C_1; + RESULT_BCDOP(7 downto 4) <= Std_Logic_Vector(S_1); + RESULT_BCDOP(3 downto 0) <= Std_Logic_Vector(S_0); + end process P_BCDOP; + + BF_DATA_IN <= OP3 & OP2(7 downto 0); + + P_BITFIELD_OP: process(BF_DATA_IN, BF_LOWER_BND, BF_OFFSET, BF_UPPER_BND, BF_WIDTH, BIW_1, OP, OP1) + variable BF_NZ : boolean; + variable BFFFO_CNT : std_logic_vector(5 downto 0); + begin + RESULT_BITFIELD <= BF_DATA_IN; -- Default. + case OP is + when BFCHG => + for i in RESULT_BITFIELD'range loop + if i >= BF_LOWER_BND and i <= BF_UPPER_BND then + RESULT_BITFIELD(i) <= not BF_DATA_IN(i); + end if; + end loop; + when BFCLR => + for i in RESULT_BITFIELD'range loop + if i >= BF_LOWER_BND and i <= BF_UPPER_BND then + RESULT_BITFIELD(i) <= '0'; + end if; + end loop; + when BFEXTS => -- Result is in (39 downto 8). + for i in 31 downto 0 loop + if i <= BF_WIDTH - 1 and BF_LOWER_BND + i <= 39 then + RESULT_BITFIELD(i + 8) <= BF_DATA_IN(BF_LOWER_BND + i); + end if; + end loop; + -- + for i in RESULT_BITFIELD'range loop + if i >= 8 + BF_WIDTH then + RESULT_BITFIELD(i) <= BF_DATA_IN(BF_UPPER_BND); + end if; + end loop; + when BFEXTU => -- Result is in (39 downto 8). + for i in 31 downto 0 loop + if i <= BF_WIDTH - 1 and BF_LOWER_BND + i <= 39 then + RESULT_BITFIELD(i + 8) <= BF_DATA_IN(BF_LOWER_BND + i); + end if; + end loop; + -- + for i in RESULT_BITFIELD'range loop + if i >= 8 + BF_WIDTH then + RESULT_BITFIELD(i) <= '0'; + end if; + end loop; + when BFFFO => -- Result is in (39 downto 8). + BF_NZ := false; + BFFFO_CNT := "000000"; + for i in BF_DATA_IN'range loop + if i <= BF_UPPER_BND and i >= BF_LOWER_BND then + if BF_DATA_IN(i) = '0' and BF_NZ = false then + BFFFO_CNT := BFFFO_CNT + '1'; + else + BF_NZ := true; + end if; + end if; + end loop; + -- + RESULT_BITFIELD <= (BF_OFFSET + BFFFO_CNT) & x"00"; + when BFINS => + for i in RESULT_BITFIELD'range loop + if i <= BF_WIDTH - 1 and (BF_UPPER_BND - i) >= 0 then + RESULT_BITFIELD(BF_UPPER_BND - i) <= OP1(BF_WIDTH - i - 1); + end if; + end loop; + when BFSET => + for i in RESULT_BITFIELD'range loop + if i >= BF_LOWER_BND and i <= BF_UPPER_BND then + RESULT_BITFIELD(i) <= '1'; + end if; + end loop; + when others => -- BFTST. + null; -- no calculation required for BFTST. + end case; + end process P_BITFIELD_OP; + + P_BITOP: process(BITPOS, OP, OP2) + -- Bit manipulation operations. + begin + RESULT_BITOP <= OP2; -- The default is the unmanipulated data. + -- + case OP is + when BCHG => + RESULT_BITOP(BITPOS) <= not OP2(BITPOS); + when BCLR => + RESULT_BITOP(BITPOS) <= '0'; + when BSET => + RESULT_BITOP(BITPOS) <= '1'; + when others => + RESULT_BITOP <= OP2; -- Dummy, no result required for BTST. + end case; + end process P_BITOP; + + DIVISION: process + variable BITCNT : integer range 0 to 64; + variable DIVIDEND : unsigned(63 downto 0); + variable DIVISOR : unsigned(31 downto 0); + variable QUOTIENT_REST : unsigned(31 downto 0); + variable QUOTIENT_VAR : unsigned(31 downto 0); + variable REMAINDER_REST : unsigned(31 downto 0); + variable REMAINDER_VAR : unsigned(31 downto 0); + -- Be aware, that the destination and source operands + -- may be reloaded during the division operation. For + -- this, we use the restore values in case of an overflow. + begin + wait until CLK = '1' and CLK' event; + DIV_RDY <= '0'; + case DIV_STATE is + when IDLE => + if ALU_INIT = '1' and (OP_IN = DIVS or OP_IN = DIVU) then + DIV_STATE <= INIT; + end if; + when INIT => + if OP = DIVS and OP_SIZE = LONG and BIW_1(10) = '1' and OP3(31) = '1' then -- 64 bit signed negative dividend. + DIVIDEND := unsigned(not (OP3 & OP2) + '1'); + elsif (OP = DIVS or OP = DIVU) and OP_SIZE = LONG and BIW_1(10) = '1' then -- 64 bit positive or unsigned dividend. + DIVIDEND := unsigned(OP3 & OP2); + elsif OP = DIVS and OP2(31) = '1' then -- 32 bit signed negative dividend. + DIVIDEND := x"00000000" & unsigned(not(OP2) + '1'); + else -- 32 bit positive or unsigned dividend. + DIVIDEND := x"00000000" & unsigned(OP2); + end if; + + if OP = DIVS and OP_SIZE = LONG and OP1(31) = '1' then -- 32 bit signed negative divisor. + DIVISOR := unsigned(not OP1 + '1'); + elsif OP_SIZE = LONG then -- 32 bit positive or unsigned divisor. + DIVISOR := unsigned(OP1); + elsif OP = DIVS and OP_SIZE = WORD and OP1(15) = '1' then -- 16 bit signed negative divisor. + DIVISOR := x"0000" & unsigned(not OP1(15 downto 0) + '1'); + else -- 16 bit positive or unsigned divisor. + DIVISOR := x"0000" & unsigned(OP1(15 downto 0)); + end if; + + VFLAG_DIV <= '0'; + QUOTIENT <= (others => '0'); + QUOTIENT_VAR := (others => '0'); + QUOTIENT_REST := unsigned(OP2); + + REMAINDER <= (others => '0'); + REMAINDER_VAR := (others => '0'); + + case OP_SIZE is + when LONG => REMAINDER_REST := unsigned(OP3); + when others => REMAINDER_REST := unsigned(x"0000" & OP2(31 downto 16)); + end case; + + if OP_SIZE = LONG and BIW_1(10) = '1' then + BITCNT := 64; + else + BITCNT := 32; + end if; + + if DIVISOR = x"00000000" then -- Division by zero. + QUOTIENT <= (others => '1'); + REMAINDER <= (others => '1'); + DIV_STATE <= IDLE; + DIV_RDY <= '1'; + elsif x"00000000" & DIVISOR > DIVIDEND then -- Divisor > dividend. + REMAINDER <= DIVIDEND(31 downto 0); + DIV_STATE <= IDLE; + DIV_RDY <= '1'; + elsif x"00000000" & DIVISOR = DIVIDEND then -- Result is 1. + QUOTIENT <= x"00000001"; + DIV_STATE <= IDLE; + DIV_RDY <= '1'; + else + DIV_STATE <= CALC; + end if; + when CALC => + BITCNT := BITCNT - 1; + -- + if REMAINDER_VAR & DIVIDEND(BITCNT) < DIVISOR then + REMAINDER_VAR := REMAINDER_VAR(30 downto 0) & DIVIDEND(BITCNT); + elsif OP_SIZE = LONG and BITCNT > 31 then -- Division overflow in 64 bit mode. + VFLAG_DIV <= '1'; + DIV_STATE <= IDLE; + DIV_RDY <= '1'; + QUOTIENT <= QUOTIENT_REST; + REMAINDER <= REMAINDER_REST; + elsif OP_SIZE = WORD and BITCNT > 15 then -- Division overflow in 64 bit mode. + VFLAG_DIV <= '1'; + DIV_STATE <= IDLE; + DIV_RDY <= '1'; + QUOTIENT <= QUOTIENT_REST; + REMAINDER <= REMAINDER_REST; + else + REMAINDER_VAR := (REMAINDER_VAR(30 downto 0) & DIVIDEND(BITCNT)) - DIVISOR; + QUOTIENT_VAR(BITCNT) := '1'; + end if; + -- + if BITCNT = 0 then + -- Adjust signs: + if OP = DIVS and OP_SIZE = LONG and BIW_1(10) = '1' and (OP3(31) xor OP1(31)) = '1' then + QUOTIENT <= not QUOTIENT_VAR + 1; -- Negative, change sign. + elsif OP = DIVS and OP_SIZE = LONG and BIW_1(10) = '0' and (OP2(31) xor OP1(31)) = '1' then + QUOTIENT <= not QUOTIENT_VAR + 1; -- Negative, change sign. + elsif OP = DIVS and OP_SIZE = WORD and (OP2(31) xor OP1(15)) = '1' then + QUOTIENT <= not QUOTIENT_VAR + 1; -- Negative, change sign. + else + QUOTIENT <= QUOTIENT_VAR; + end if; + -- + REMAINDER <= REMAINDER_VAR; + DIV_RDY <= '1'; + DIV_STATE <= IDLE; + end if; + end case; + end process DIVISION; + + P_INTOP: process(OP, OP1, OP1_SIGNEXT, OP2, OP2_SIGNEXT, ADR_MODE, STATUS_REG, RESULT_INTOP) + -- The integer arithmetics ADD, SUB, NEG and CMP in their different variations are modelled here. + variable X_IN_I : Std_Logic_Vector(0 downto 0); + variable RESULT : unsigned(31 downto 0); + begin + X_IN_I(0) := STATUS_REG(4); -- Extended Flag. + case OP is + when ADDA => -- No sign extension for the destination. + RESULT := unsigned(OP2) + unsigned(OP1_SIGNEXT); + when ADDQ => + case ADR_MODE is + when "001" => RESULT := unsigned(OP2) + unsigned(OP1); -- No sign extension for address destination. + when others => RESULT := unsigned(OP2_SIGNEXT) + unsigned(OP1); + end case; + when SUBQ => + case ADR_MODE is + when "001" => RESULT := unsigned(OP2) - unsigned(OP1); -- No sign extension for address destination. + when others => RESULT := unsigned(OP2_SIGNEXT) - unsigned(OP1); + end case; + when ADD | ADDI => + RESULT := unsigned(OP2_SIGNEXT) + unsigned(OP1_SIGNEXT); + when ADDX => + RESULT := unsigned(OP2_SIGNEXT) + unsigned(OP1_SIGNEXT) + unsigned(X_IN_I); + when CMPA | DBcc | SUBA => -- No sign extension for the destination. + RESULT := unsigned(OP2) - unsigned(OP1_SIGNEXT); + when CAS | CAS2 | CMP | CMPI | CMPM | SUB | SUBI => + RESULT := unsigned(OP2_SIGNEXT) - unsigned(OP1_SIGNEXT); + when SUBX => + RESULT := unsigned(OP2_SIGNEXT) - unsigned(OP1_SIGNEXT) - unsigned(X_IN_I); + when NEG => + RESULT := unsigned(OP1_SIGNEXT) - unsigned(OP2_SIGNEXT); + when NEGX => + RESULT := unsigned(OP1_SIGNEXT) - unsigned(OP2_SIGNEXT) - unsigned(X_IN_I); + when CLR => + RESULT := (others => '0'); + when others => + RESULT := (others => '0'); -- Don't care. + end case; + RESULT_INTOP <= Std_Logic_Vector(RESULT); + end process P_INTOP; + + P_LOGOP: process(OP, OP1, OP2) + -- This process provides the logic operations: + -- AND, OR, XOR and NOT. + -- The logic operations require no signed / unsigned + -- modelling. + begin + case OP is + when AND_B | ANDI | ANDI_TO_CCR | ANDI_TO_SR => + RESULT_LOGOP <= OP1 and OP2; + when OR_B | ORI | ORI_TO_CCR | ORI_TO_SR => + RESULT_LOGOP <= OP1 or OP2; + when EOR | EORI | EORI_TO_CCR | EORI_TO_SR => + RESULT_LOGOP <= OP1 xor OP2; + when others => -- NOT_B. + RESULT_LOGOP <= not OP2; + end case; + end process P_LOGOP; + + RESULT_MUL <= Std_Logic_Vector(signed(OP1_SIGNEXT) * signed(OP2_SIGNEXT)) when OP = MULS else + Std_Logic_Vector(unsigned(OP1) * unsigned(OP2)) when OP_SIZE = LONG else + Std_Logic_Vector(unsigned(x"0000" & OP1(15 downto 0)) * unsigned(x"0000" & OP2(15 downto 0))); + + P_OTHERS: process(ALU_COND_I, BIW_0, OP, OP1, OP2, OP3, OP1_SIGNEXT, OP2_SIGNEXT, OP_SIZE, HILOn) + -- This process provides the calculation for special operations. + variable RESULT : unsigned(31 downto 0); + begin + RESULT := (others => '0'); + case OP is + when CAS => + RESULT := unsigned(OP2); -- Destination operand. + when CAS2 => -- Destination operands. + case HILOn is + when '1' => RESULT := unsigned(OP3); + when others => RESULT := unsigned(OP2); + end case; + when EXT => + case BIW_0(8 downto 6) is + when "011" => + for i in 31 downto 16 loop + RESULT(i) := OP2(15); + end loop; + RESULT(15 downto 0) := unsigned(OP2(15 downto 0)); + when others => -- Word. + for i in 15 downto 8 loop + RESULT(i) := OP2(7); + end loop; + RESULT(31 downto 16) := unsigned(OP2(31 downto 16)); + RESULT(7 downto 0) := unsigned(OP2(7 downto 0)); + end case; + when EXTB => + for i in 31 downto 8 loop + RESULT(i) := OP2(7); + end loop; + RESULT(7 downto 0) := unsigned(OP2(7 downto 0)); + when JSR => + RESULT := unsigned(OP1) + "10"; -- Add offset of two to the Pointer of the last extension word. + when MOVEQ => + for i in 31 downto 8 loop + RESULT(i) := OP1(7); + end loop; + RESULT(7 downto 0) := unsigned(OP1(7 downto 0)); + when Scc => + if ALU_COND_I = true then + RESULT := (others => '1'); + else + RESULT := (others => '0'); + end if; + when SWAP => + RESULT := unsigned(OP2(15 downto 0)) & unsigned(OP2(31 downto 16)); + when TAS => + RESULT := x"000000" & '1' & unsigned(OP2(6 downto 0)); -- Set the MSB. + when PACK => + RESULT := x"0000" & (unsigned(OP1(15 downto 0)) + unsigned(OP2(15 downto 0))); + when UNPK => + RESULT := x"0000" & (unsigned(OP1(15 downto 0)) + unsigned(x"0" & OP2(7 downto 4) & x"0" & OP2(3 downto 0))); + when LINK | TST => + RESULT := unsigned(OP2); + when MOVEA | MOVEM | MOVES => + RESULT := unsigned(OP1_SIGNEXT); + when others => -- MOVE_FROM_CCR, MOVE_TO_CCR, MOVE_FROM_SR, MOVE_TO_SR, MOVE, MOVEC, MOVEP, STOP. + RESULT := unsigned(OP1); + end case; + RESULT_OTHERS <= Std_Logic_Vector(RESULT); + end process P_OTHERS; + + SHFT_LOAD <= '1' when ALU_INIT = '1' and (OP_IN = ASL or OP_IN = ASR) else + '1' when ALU_INIT = '1' and (OP_IN = LSL or OP_IN = LSR) else + '1' when ALU_INIT = '1' and (OP_IN = ROTL or OP_IN = ROTR) else + '1' when ALU_INIT = '1' and (OP_IN = ROXL or OP_IN = ROXR) else '0'; + + SHIFT_WIDTH_IN <= "000001" when BIW_0_IN(7 downto 6) = "11" else -- Memory shifts. + "001000" when BIW_0_IN(5) = '0' and BIW_0_IN(11 downto 9) = "000" else -- Direct. + "000" & BIW_0_IN(11 downto 9) when BIW_0_IN(5) = '0' else -- Direct. + OP1_IN(5 downto 0); + + P_SHFT_CTRL: process + -- The variable shift or rotate length requires a control + -- to achieve the correct OPERAND manipulation. + variable BIT_CNT : std_logic_vector(5 downto 0); + begin + wait until CLK = '1' and CLK' event; + + SHFT_RDY <= '0'; + + if SHIFT_STATE = IDLE then + if SHFT_LOAD = '1' and SHIFT_WIDTH_IN = "000000" then + SHFT_RDY <= '1'; + elsif SHFT_LOAD = '1' then + SHIFT_STATE <= RUN; + BIT_CNT := SHIFT_WIDTH_IN; + SHFT_EN <= '1'; + else + SHIFT_STATE <= IDLE; + BIT_CNT := (others => '0'); + SHFT_EN <= '0'; + end if; + elsif SHIFT_STATE = RUN then + if BIT_CNT = "000001" then + SHIFT_STATE <= IDLE; + SHFT_EN <= '0'; + SHFT_RDY <= '1'; + else + SHIFT_STATE <= RUN; + BIT_CNT := BIT_CNT - '1'; + SHFT_EN <= '1'; + end if; + end if; + end process P_SHFT_CTRL; + + SHIFTER: process + begin + wait until CLK = '1' and CLK' event; + if SHFT_LOAD = '1' then -- Load data in the shifter unit. + RESULT_SHIFTOP <= OP2_IN; -- Load data for the shift or rotate operations. + elsif SHFT_EN = '1' then -- Shift and rotate operations: + case OP is + when ASL => + if OP_SIZE = LONG then + RESULT_SHIFTOP <= RESULT_SHIFTOP(30 downto 0) & '0'; + elsif OP_SIZE = WORD then + RESULT_SHIFTOP <= x"0000" & RESULT_SHIFTOP(14 downto 0) & '0'; + else -- OP_SIZE = BYTE. + RESULT_SHIFTOP <= x"000000" & RESULT_SHIFTOP(6 downto 0) & '0'; + end if; + when ASR => + if OP_SIZE = LONG then + RESULT_SHIFTOP <= RESULT_SHIFTOP(31) & RESULT_SHIFTOP(31 downto 1); + elsif OP_SIZE = WORD then + RESULT_SHIFTOP <= x"0000" & RESULT_SHIFTOP(15) & RESULT_SHIFTOP(15 downto 1); + else -- OP_SIZE = BYTE. + RESULT_SHIFTOP <= x"000000" & RESULT_SHIFTOP(7) & RESULT_SHIFTOP(7 downto 1); + end if; + when LSL => + if OP_SIZE = LONG then + RESULT_SHIFTOP <= RESULT_SHIFTOP(30 downto 0) & '0'; + elsif OP_SIZE = WORD then + RESULT_SHIFTOP <= x"0000" & RESULT_SHIFTOP(14 downto 0) & '0'; + else -- OP_SIZE = BYTE. + RESULT_SHIFTOP <= x"000000" & RESULT_SHIFTOP(6 downto 0) & '0'; + end if; + when LSR => + if OP_SIZE = LONG then + RESULT_SHIFTOP <= '0' & RESULT_SHIFTOP(31 downto 1); + elsif OP_SIZE = WORD then + RESULT_SHIFTOP <= x"0000" & '0' & RESULT_SHIFTOP(15 downto 1); + else -- OP_SIZE = BYTE. + RESULT_SHIFTOP <= x"000000" & '0' & RESULT_SHIFTOP(7 downto 1); + end if; + when ROTL => + if OP_SIZE = LONG then + RESULT_SHIFTOP <= RESULT_SHIFTOP(30 downto 0) & RESULT_SHIFTOP(31); + elsif OP_SIZE = WORD then + RESULT_SHIFTOP <= x"0000" & RESULT_SHIFTOP(14 downto 0) & RESULT_SHIFTOP(15); + else -- OP_SIZE = BYTE. + RESULT_SHIFTOP <= x"000000" & RESULT_SHIFTOP(6 downto 0) & RESULT_SHIFTOP(7); + end if; + -- X not affected; + when ROTR => + if OP_SIZE = LONG then + RESULT_SHIFTOP <= RESULT_SHIFTOP(0) & RESULT_SHIFTOP(31 downto 1); + elsif OP_SIZE = WORD then + RESULT_SHIFTOP <= x"0000" & RESULT_SHIFTOP(0) & RESULT_SHIFTOP(15 downto 1); + else -- OP_SIZE = BYTE. + RESULT_SHIFTOP <= x"000000" & RESULT_SHIFTOP(0) & RESULT_SHIFTOP(7 downto 1); + end if; + -- X not affected; + when ROXL => + if OP_SIZE = LONG then + RESULT_SHIFTOP <= RESULT_SHIFTOP(30 downto 0) & XFLAG_SHFT; + elsif OP_SIZE = WORD then + RESULT_SHIFTOP <= x"0000" & RESULT_SHIFTOP(14 downto 0) & XFLAG_SHFT; + else -- OP_SIZE = BYTE. + RESULT_SHIFTOP <= x"000000" & RESULT_SHIFTOP(6 downto 0) & XFLAG_SHFT; + end if; + when ROXR => + if OP_SIZE = LONG then + RESULT_SHIFTOP <= XFLAG_SHFT & RESULT_SHIFTOP(31 downto 1); + elsif OP_SIZE = WORD then + RESULT_SHIFTOP <= x"0000" & XFLAG_SHFT & RESULT_SHIFTOP(15 downto 1); + else -- OP_SIZE = BYTE. + RESULT_SHIFTOP <= x"000000" & XFLAG_SHFT & RESULT_SHIFTOP(7 downto 1); + end if; + when others => null; -- Unaffected, forbidden. + end case; + end if; + end process SHIFTER; + + P_OUT: process + begin + wait until CLK = '1' and CLK' event; + if ALU_REQ = '1' then + case OP is + when ABCD | NBCD | SBCD => + RESULT <= x"00000000000000" & RESULT_BCDOP; -- Byte only. + when BFCHG | BFCLR | BFEXTS | BFEXTU | BFFFO | BFINS | BFSET | BFTST => + case HILOn is + when '1' => RESULT <= x"00000000" & RESULT_BITFIELD(39 downto 8); + when others => RESULT <= x"00000000000000" & RESULT_BITFIELD(7 downto 0); + end case; + when BCHG | BCLR | BSET | BTST => + RESULT <= x"00000000" & RESULT_BITOP; + when ADD | ADDA | ADDI | ADDQ | ADDX | CLR | CMP | CMPA | CMPI => + RESULT <= x"00000000" & RESULT_INTOP; + when CMPM | DBcc | NEG | NEGX | SUB | SUBA | SUBI | SUBQ | SUBX => + RESULT <= x"00000000" & RESULT_INTOP; + when AND_B | ANDI | EOR | EORI | NOT_B | OR_B | ORI => + RESULT <= x"00000000" & RESULT_LOGOP; + when ANDI_TO_SR | EORI_TO_SR | ORI_TO_SR => -- Used for branch prediction. + RESULT <= x"00000000" & RESULT_LOGOP; + when ASL | ASR | LSL | LSR | ROTL | ROTR | ROXL | ROXR => + RESULT <= x"00000000" & RESULT_SHIFTOP; + when DIVS | DIVU => + case OP_SIZE is + when LONG => RESULT <= Std_Logic_Vector(REMAINDER) & Std_Logic_Vector(QUOTIENT); + when others => RESULT <= x"00000000" & Std_Logic_Vector(REMAINDER(15 downto 0)) & Std_Logic_Vector(QUOTIENT(15 downto 0)); + end case; + when MULS | MULU => + RESULT <= RESULT_MUL; + when PACK => + RESULT <= x"00000000000000" & RESULT_OTHERS(11 downto 8) & RESULT_OTHERS (3 downto 0); + when others => + RESULT <= OP2 & RESULT_OTHERS; -- OP2 is used for EXG. + end case; + end if; + end process P_OUT; + + -- Out of bounds condition: + CHK_CMP_COND <= true when OP = CHK and OP2_SIGNEXT(MSB) = '1' else -- Negative destination. + true when OP = CHK and signed(OP2_SIGNEXT) > signed(OP1_SIGNEXT) else + true when (OP = CHK2 or OP = CMP2) and CHK2CMP2_DR = '1' and OP_SIZE = LONG and OP2 < OP1 else + true when (OP = CHK2 or OP = CMP2) and CHK2CMP2_DR = '1' and OP_SIZE = LONG and OP2 > OP3 else + true when (OP = CHK2 or OP = CMP2) and CHK2CMP2_DR = '1' and OP_SIZE = WORD and OP2(15 downto 0) < OP1(15 downto 0) else + true when (OP = CHK2 or OP = CMP2) and CHK2CMP2_DR = '1' and OP_SIZE = WORD and OP2(15 downto 0) > OP3(15 downto 0) else + true when (OP = CHK2 or OP = CMP2) and CHK2CMP2_DR = '1' and OP2(7 downto 0) < OP1(7 downto 0) else + true when (OP = CHK2 or OP = CMP2) and CHK2CMP2_DR = '1' and OP2(7 downto 0) > OP3(7 downto 0) else + true when (OP = CHK2 or OP = CMP2) and CHK2CMP2_DR = '0' and signed(OP2_SIGNEXT) < signed(OP1_SIGNEXT) else + true when (OP = CHK2 or OP = CMP2) and CHK2CMP2_DR = '0' and signed(OP2_SIGNEXT) > signed(OP3_SIGNEXT) else false; + + -- All traps must be modeled as strobes. + TRAP_CHK <= '1' when ALU_ACK = '1' and (OP = CHK or OP = CHK2) and CHK_CMP_COND = true else '0'; + TRAP_DIVZERO <= '1' when ALU_INIT = '1' and (OP_IN = DIVS or OP_IN = DIVU) and OP1_IN = x"00000000" else '0'; + + COND_CODES: process(BF_DATA_IN, BF_LOWER_BND, BF_UPPER_BND, BIW_1, BITPOS, CB_BCD, CHK_CMP_COND, CLK, OP1, OP1_SIGNEXT, OP2, OP2_SIGNEXT, + OP3, OP3_SIGNEXT, MSB, OP, OP_SIZE, QUOTIENT, RESULT_BCDOP, RESULT_INTOP, RESULT_LOGOP, RESULT_MUL, RESULT_SHIFTOP, + RESULT_OTHERS, SHIFT_WIDTH, STATUS_REG, USE_DREG, VFLAG_DIV, XFLAG_SHFT) + -- In this process all the condition codes X (eXtended), N (Negative) + -- Z (Zero), V (oVerflow) and C (Carry / borrow) are calculated for + -- all integer operations. Except for the MULS, MULU, DIVS, DIVU the + -- new conditions are valid one clock cycle after the operation starts. + -- For the multiplication and the division, the codes are valid after + -- BUSY is released. + variable TMP : std_logic; + variable Z, RM, SM, DM : std_logic; + variable CFLAG_SHFT : std_logic; + variable VFLAG_SHFT : std_logic; + variable NFLAG_DIV : std_logic; + variable NFLAG_MUL : std_logic; + variable VFLAG_MUL : std_logic; + variable RM_SM_DM : bit_vector(2 downto 0); + begin + -- Shifter C, X and V flags: + if CLK = '1' and CLK' event then + if SHFT_LOAD = '1' or SHIFT_WIDTH = "000000" then + XFLAG_SHFT <= STATUS_REG(4); + elsif SHFT_EN = '1' then + case OP is + when ROTL | ROTR => + XFLAG_SHFT <= STATUS_REG(4); -- Unaffected. + when ASL | LSL | ROXL => + case OP_SIZE is + when LONG => + XFLAG_SHFT <= RESULT_SHIFTOP(31); + when WORD => + XFLAG_SHFT <= RESULT_SHIFTOP(15); + when BYTE => + XFLAG_SHFT <= RESULT_SHIFTOP(7); + end case; + when others => -- ASR, LSR, ROXR. + XFLAG_SHFT <= RESULT_SHIFTOP(0); + end case; + end if; + -- + if (OP = ROXL or OP = ROXR) and SHIFT_WIDTH = "000000" then + CFLAG_SHFT := STATUS_REG(4); + elsif SHIFT_WIDTH = "000000" then + CFLAG_SHFT := '0'; + elsif SHFT_EN = '1' then + case OP is + when ASL | LSL | ROTL | ROXL => + case OP_SIZE is + when LONG => + CFLAG_SHFT := RESULT_SHIFTOP(31); + when WORD => + CFLAG_SHFT := RESULT_SHIFTOP(15); + when BYTE => + CFLAG_SHFT := RESULT_SHIFTOP(7); + end case; + when others => -- ASR, LSR, ROTR, ROXR + CFLAG_SHFT := RESULT_SHIFTOP(0); + end case; + end if; + -- + -- This logic provides a detection of any toggling of the most significant + -- bit of the shifter unit during the ASL shift process. For all other shift + -- operations, the V flag is always zero. + if SHFT_LOAD = '1' or SHIFT_WIDTH = "000000" then + VFLAG_SHFT := '0'; + elsif SHFT_EN = '1' then + case OP is + when ASL => -- ASR MSB is always unchanged. + if OP_SIZE = LONG then + VFLAG_SHFT := (RESULT_SHIFTOP(31) xor RESULT_SHIFTOP(30)) or VFLAG_SHFT; + elsif OP_SIZE = WORD then + VFLAG_SHFT := (RESULT_SHIFTOP(15) xor RESULT_SHIFTOP(14)) or VFLAG_SHFT; + else -- OP_SIZE = BYTE. + VFLAG_SHFT := (RESULT_SHIFTOP(7) xor RESULT_SHIFTOP(6)) or VFLAG_SHFT; + end if; + when others => + VFLAG_SHFT := '0'; + end case; + end if; + end if; + + -- DIVISION: + if OP_SIZE = LONG and QUOTIENT(31) = '1' then + NFLAG_DIV := '1'; + elsif OP_SIZE = WORD and QUOTIENT(15) = '1' then + NFLAG_DIV := '1'; + else + NFLAG_DIV := '0'; + end if; + + -- Integer operations: + case OP is + when ADD | ADDI | ADDQ | ADDX | CMP | CMPA | CMPI | CMPM | NEG | NEGX | SUB | SUBI | SUBQ | SUBX => + RM := RESULT_INTOP(MSB); + SM := OP1_SIGNEXT(MSB); + DM := OP2_SIGNEXT(MSB); + when others => + RM := '-'; SM := '-'; DM := '-'; + end case; + + RM_SM_DM := To_Bit(RM) & To_Bit(SM) & To_Bit(DM); + + -- Multiplication: + if OP_SIZE = LONG and BIW_1(10) = '1' and RESULT_MUL(63) = '1' then -- 64 bit result. + NFLAG_MUL := '1'; + elsif RESULT_MUL(31) = '1' then -- 32 bit result. + NFLAG_MUL := '1'; + else + NFLAG_MUL := '0'; + end if; + + if OP_SIZE = LONG and BIW_1(10) = '0' and OP = MULS and RESULT_MUL(31) = '0' and RESULT_MUL(63 downto 32) /= x"00000000" then + VFLAG_MUL := '1'; + elsif OP_SIZE = LONG and BIW_1(10) = '0' and OP = MULS and RESULT_MUL(31) = '1' and RESULT_MUL(63 downto 32) /= x"FFFFFFFF" then + VFLAG_MUL := '1'; + elsif OP_SIZE = LONG and BIW_1(10) = '0' and OP = MULU and RESULT_MUL(63 downto 32) /= x"00000000" then + VFLAG_MUL := '1'; + else + VFLAG_MUL := '0'; + end if; + + -- The Z Flag: + TMP := '0'; + case OP is + when ADD | ADDI | ADDQ | ADDX | CAS | CAS2 | CMP | CMPA | CMPI | CMPM | NEG | NEGX | SUB | SUBI | SUBQ | SUBX => + for i in RESULT_INTOP'range loop + if i <= MSB then + TMP:= TMP or RESULT_INTOP(i); -- Detect '1'. + end if; + end loop; + Z := not TMP; -- Invert for Z fLAG . + when AND_B | ANDI | EOR | EORI | OR_B | ORI | NOT_B => + for i in RESULT_LOGOP'range loop + if i <= MSB then + TMP:= TMP or RESULT_LOGOP(i); -- Detect '1'. + end if; + end loop; + Z := not TMP; -- Invert for Z fLAG . + when ASL | ASR | LSL | LSR | ROTL | ROTR | ROXL | ROXR => + for i in RESULT_SHIFTOP'range loop + if i <= MSB then + TMP:= TMP or RESULT_SHIFTOP(i); -- Detect '1'. + end if; + end loop; + Z := not TMP; -- Invert for Z fLAG . + when BFCHG | BFCLR | BFEXTS | BFEXTU | BFFFO | BFINS | BFSET | BFTST => + for i in BF_DATA_IN'range loop + if i >= BF_LOWER_BND and i <= BF_UPPER_BND then + TMP := TMP or BF_DATA_IN(i); -- Detect '1'. + end if; + end loop; + Z := not TMP; + when CHK2 | CMP2 => + if USE_DREG = '1' and OP_SIZE = LONG and OP2 = OP1 then + Z := '1'; + elsif USE_DREG = '1' and OP_SIZE = LONG and OP2 = OP3 then + Z:= '1'; + elsif USE_DREG = '1' and OP_SIZE = WORD and OP2(15 downto 0) = OP1(15 downto 0) then + Z:= '1'; + elsif USE_DREG = '1' and OP_SIZE = WORD and OP2(15 downto 0) = OP3(15 downto 0) then + Z:= '1'; + elsif USE_DREG = '1' and OP2(7 downto 0) = OP1(7 downto 0) then + Z:= '1'; + elsif USE_DREG = '1' and OP2(7 downto 0) = OP3(7 downto 0) then + Z:= '1'; + elsif USE_DREG = '0' and OP2_SIGNEXT = OP1_SIGNEXT then + Z := '1'; + elsif USE_DREG = '0' and OP2_SIGNEXT = OP3_SIGNEXT then + Z := '1'; + else + Z := '0'; + end if; + when BCHG | BCLR | BSET | BTST => + Z := not OP2(BITPOS); + when DIVS | DIVU => + if QUOTIENT = x"00000000" then + Z := '1'; + else + Z := '0'; + end if; + when EXT | EXTB | MOVE | SWAP | TST => + for i in RESULT_OTHERS'range loop + if i <= MSB then + TMP:= TMP or RESULT_OTHERS(i); -- Detect '1'. + end if; + end loop; + Z := not TMP; -- Invert for Z fLAG . + when MULS | MULU => + if OP_SIZE = LONG and BIW_1(10) = '1' and RESULT_MUL = x"0000000000000000" then -- 64 bit result. + Z := '1'; + elsif RESULT_MUL(31 downto 0) = x"00000000" then -- 32 bit result. + Z := '1'; + else + Z := '0'; + end if; + when TAS => + for i in OP2_SIGNEXT'range loop + if i <= MSB then + TMP := TMP or OP2_SIGNEXT(i); -- Detect '1'. + end if; + end loop; + Z := not TMP; -- Invert for Z fLAG . + when others => + Z := '0'; + end case; + + case OP is + when ABCD | NBCD | SBCD => + if RESULT_BCDOP = x"00" then -- N and V are undefined, don't care. + XNZVC <= CB_BCD & '-' & STATUS_REG(2) & '-' & CB_BCD; + else + XNZVC <= CB_BCD & '-' & '0' & '-' & CB_BCD; + end if; + when ADD | ADDI | ADDQ | ADDX => + if (SM = '1' and DM = '1') or (RM = '0' and SM = '1') or (RM = '0' and DM = '1') then + XNZVC(4) <= '1'; + XNZVC(0) <= '1'; + else + XNZVC(4) <= '0'; + XNZVC(0) <= '0'; + end if; + -- + if Z = '1' then + if OP = ADDX then + XNZVC(3 downto 2) <= '0' & STATUS_REG(2); + else + XNZVC(3 downto 2) <= "01"; + end if; + else + XNZVC(3 downto 2) <= RM & '0'; + end if; + -- + case RM_SM_DM is + when "011" => XNZVC(1) <= '1'; + when "100" => XNZVC(1) <= '1'; + when others => XNZVC(1) <= '0'; + end case; + when AND_B | ANDI | EOR | EORI | OR_B | ORI | NOT_B => + XNZVC <= STATUS_REG(4) & RESULT_LOGOP(MSB) & Z & "00"; + when ANDI_TO_CCR | EORI_TO_CCR | ORI_TO_CCR => + XNZVC <= RESULT_LOGOP(4 downto 0); + when ASL | ASR | LSL | LSR | ROTL | ROTR | ROXL | ROXR => + XNZVC <= XFLAG_SHFT & RESULT_SHIFTOP(MSB) & Z & VFLAG_SHFT & CFLAG_SHFT; + when BCHG | BCLR | BSET | BTST => + XNZVC <= STATUS_REG(4 downto 3) & Z & STATUS_REG(1 downto 0); + when BFCHG | BFCLR | BFEXTS | BFEXTU | BFFFO | BFINS | BFSET | BFTST => + XNZVC <= STATUS_REG(4) & BF_DATA_IN(BF_UPPER_BND) & Z & "00"; + when CLR => + XNZVC <= STATUS_REG(4) & "0100"; + when SUB | SUBI | SUBQ | SUBX => + if (SM = '1' and DM = '0') or (RM = '1' and SM = '1') or (RM = '1' and DM = '0') then + XNZVC(4) <= '1'; + XNZVC(0) <= '1'; + else + XNZVC(4) <= '0'; + XNZVC(0) <= '0'; + end if; + -- + if Z = '1' then + if OP = SUBX then + XNZVC(3 downto 2) <= '0' & STATUS_REG(2); + else + XNZVC(3 downto 2) <= "01"; + end if; + else + XNZVC(3 downto 2) <= RM & '0'; + end if; + -- + case RM_SM_DM is + when "001" => XNZVC(1) <= '1'; + when "110" => XNZVC(1) <= '1'; + when others => XNZVC(1) <= '0'; + end case; + when CAS | CAS2 | CMP | CMPA | CMPI | CMPM => + XNZVC(4) <= STATUS_REG(4); + -- + if Z = '1' then + XNZVC(3 downto 2) <= "01"; + else + XNZVC(3 downto 2) <= RM & '0'; + end if; + -- + case RM_SM_DM is + when "001" => XNZVC(1) <= '1'; + when "110" => XNZVC(1) <= '1'; + when others => XNZVC(1) <= '0'; + end case; + -- + if (SM = '1' and DM = '0') or (RM = '1' and SM = '1') or (RM = '1' and DM = '0') then + XNZVC(0) <= '1'; + else + XNZVC(0) <= '0'; + end if; + when CHK => + if OP2_SIGNEXT(MSB) = '1' then + XNZVC <= STATUS_REG(4) & '1' & "000"; + elsif CHK_CMP_COND = true then + XNZVC <= STATUS_REG(4) & '0' & "000"; + else + XNZVC <= STATUS_REG(4 downto 3) & "000"; + end if; + when CHK2 | CMP2 => + if CHK_CMP_COND = true then + XNZVC <= STATUS_REG(4) & '0' & '0' & '0' & '1'; + else + XNZVC <= STATUS_REG(4) & '0' & Z & '0' & '0'; + end if; + when DIVS | DIVU => + XNZVC <= STATUS_REG(4) & NFLAG_DIV & Z & VFLAG_DIV & '0'; + when EXT | EXTB | MOVE | TST => + XNZVC <= STATUS_REG(4) & RESULT_OTHERS(MSB) & Z & "00"; + when MOVEQ => + if OP1_SIGNEXT(7 downto 0) = x"00" then + XNZVC <= STATUS_REG(4) & "0100"; + else + XNZVC <= STATUS_REG(4) & OP1_SIGNEXT(7) & "000"; + end if; + when MULS | MULU => + XNZVC <= STATUS_REG(4) & NFLAG_MUL & Z & VFLAG_MUL & '0'; + when NEG | NEGX => + XNZVC(4) <= DM or RM; + -- + if Z = '1' then + if OP = NEGX then + XNZVC(3 downto 2) <= '0' & STATUS_REG(2); + else + XNZVC(3 downto 2) <= "01"; + end if; + else + XNZVC(3 downto 2) <= RM & '0'; + end if; + -- + XNZVC(1) <= DM and RM; + XNZVC(0) <= DM or RM; + when RTR => + XNZVC <= OP2(4 downto 0); + when SWAP => + XNZVC <= STATUS_REG(4) & RESULT_OTHERS(MSB) & Z & "00"; + when others => -- TAS, Byte only. + XNZVC <= STATUS_REG(4) & OP2_SIGNEXT(MSB) & Z & "00"; + end case; + end process COND_CODES; + + CAS_CONDITIONS: process(CLK) + begin + if CLK = '1' and CLK' event then + if LOAD_OP2 = '1' and XNZVC(2) = '1' then + CAS2_COND <= true; + elsif LOAD_OP2 = '1' then + CAS2_COND <= false; + end if; + end if; + end process CAS_CONDITIONS; + + ALU_COND <= ALU_COND_I; -- This signal may not be registerd to meet a correct timing. + -- Status register conditions: (STATUS_REG(4) = X, STATUS_REG(3) = N, STATUS_REG(2) = Z, STATUS_REG(1) = V, STATUS_REG(0) = C.) + ALU_COND_I <= false when OP = CAS2 and CAS2_COND = false else + true when (OP = CAS or OP = CAS2) and OP_SIZE = LONG and RESULT_INTOP = x"00000000" else + true when (OP = CAS or OP = CAS2) and OP_SIZE = WORD and RESULT_INTOP (15 downto 0) = x"0000" else + true when OP = CAS and RESULT_INTOP (7 downto 0) = x"00" else + false when OP = CAS or OP = CAS2 else + true when OP = TRAPV and STATUS_REG(1) = '1' else + false when OP = TRAPV else + true when BIW_0(11 downto 8) = x"0" else -- True. + true when BIW_0(11 downto 8) = x"2" and (STATUS_REG(2) nor STATUS_REG(0)) = '1' else -- High. + true when BIW_0(11 downto 8) = x"3" and (STATUS_REG(2) or STATUS_REG(0)) = '1' else -- Low or same. + true when BIW_0(11 downto 8) = x"4" and STATUS_REG(0) = '0' else -- Carry clear. + true when BIW_0(11 downto 8) = x"5" and STATUS_REG(0) = '1' else -- Carry set. + true when BIW_0(11 downto 8) = x"6" and STATUS_REG(2) = '0' else -- Not Equal. + true when BIW_0(11 downto 8) = x"7" and STATUS_REG(2) = '1' else -- Equal. + true when BIW_0(11 downto 8) = x"8" and STATUS_REG(1) = '0' else -- Overflow clear. + true when BIW_0(11 downto 8) = x"9" and STATUS_REG(1) = '1' else -- Overflow set. + true when BIW_0(11 downto 8) = x"A" and STATUS_REG(3) = '0' else -- Plus. + true when BIW_0(11 downto 8) = x"B" and STATUS_REG(3) = '1' else -- Minus. + true when BIW_0(11 downto 8) = x"C" and (STATUS_REG(3) xnor STATUS_REG(1)) = '1' else -- Greater or Equal. + true when BIW_0(11 downto 8) = x"D" and (STATUS_REG(3) xor STATUS_REG(1)) = '1' else -- Less than. + true when BIW_0(11 downto 8) = x"E" and STATUS_REG(3 downto 1) = "101" else -- Greater than. + true when BIW_0(11 downto 8) = x"E" and STATUS_REG(3 downto 1) = "000" else -- Greater than. + true when BIW_0(11 downto 8) = x"F" and STATUS_REG(2) = '1' else -- Less or equal. + true when BIW_0(11 downto 8) = x"F" and (STATUS_REG(3) xor STATUS_REG(1)) = '1' else false; -- Less or equal. + + P_STATUS_REG: process + -- This process is the status register with it's related logic. + -- The status register is written 16 bit wide for MOVE_TO_CCR (the ALU result is 16 bit wide). + -- The status register is written entirely for ANDI_TO_SR, EORI_TO_SR, ORI_TO_SR. + -- The status register lower byte is written for ANDI_TO_CCR, EORI_TO_CCR, ORI_TO_CCR. + variable SREG_MEM : std_logic_vector(15 downto 0) := x"0000"; + begin + wait until CLK = '1' and CLK' event; + -- + if CC_UPDT = '1' then + SREG_MEM(4 downto 0) := XNZVC; + end if; + -- + if SR_INIT = '1' then + SREG_MEM(15 downto 13) := "001"; -- Trace cleared, S = '1'. + SREG_MEM(10 downto 8) := IRQ_PEND; -- Update IRQ level. + end if; + -- + if SR_CLR_MBIT = '1' then + SREG_MEM(12) := '0'; + elsif SR_WR = '1' and OP_IN = RTE then -- Written by the exception handler, no ALU required. + SREG_MEM := OP1_IN(15 downto 0); + elsif SR_WR = '1' and (OP_WB = MOVE_TO_CCR or OP_WB = MOVE_TO_SR or OP_WB = STOP) then + SREG_MEM := RESULT_OTHERS(15 downto 0); + elsif SR_WR = '1' and (OP_WB = ANDI_TO_CCR or OP_WB = EORI_TO_CCR or OP_WB = ORI_TO_CCR) then + SREG_MEM(7 downto 5) := RESULT_LOGOP(7 downto 5); -- Bits 4 downto 0 are written via CC_UPDT. + elsif SR_WR = '1' then -- ANDI_TO_SR, EORI_TO_SR, ORI_TO_SR. + SREG_MEM := RESULT_LOGOP(15 downto 0); + end if; + -- + STATUS_REG <= SREG_MEM; -- Fully populated status register. + --STATUS_REG <= SREG_MEM(15 downto 12) & '0' & SREG_MEM(10 downto 8) & "000" & SREG_MEM(4 downto 0); -- Partially populated. + end process P_STATUS_REG; + -- + STATUS_REG_OUT <= STATUS_REG; +end BEHAVIOUR; diff --git a/common/CPU/68K30L/wf68k30L_bus_interface.vhd b/common/CPU/68K30L/wf68k30L_bus_interface.vhd new file mode 100644 index 00000000..474b10ae --- /dev/null +++ b/common/CPU/68K30L/wf68k30L_bus_interface.vhd @@ -0,0 +1,879 @@ +------------------------------------------------------------------------ +---- ---- +---- WF68K30L IP Core: this is the bus interface. ---- +---- ---- +---- Description: ---- +---- This module is a 68030 compatible bus controller featuring ---- +---- all of the 68030 bus interface functionality. ---- +---- ---- +---- Bus cycle operation: ---- +---- A bus cycle is invoked by either asserting RD_REQ, WR_REQ or ---- +---- OPCODE_REQ. Data is provided immediately or after the ---- +---- respective bus cycle has finished. The RD_REQ, WR_REQ or ---- +---- OPCODE_REQ signals should stay asserted until the respective ---- +---- _RDY signal from the bus controller indicates, that the data ---- +---- is available. These _RDY signals are strobes. If more than one ---- +---- read or write request are asserted the same time, RD_REQ is ---- +---- prioritized over WR_REQ and OPCODE_REQ has lowest priority. ---- +---- For more information of the signal functionality of the bus ---- +---- controller entity see also the comments below. ---- +---- ---- +---- Remarks: ---- +---- ---- +---- Bus arbitration topics: ---- +---- Additionally to the single wire and the three wire bus arbi- ---- +---- tration as described in the 68030 hardware manual, the bus ---- +---- controller also features the two wire arbitration as des- ---- +---- cribed in the documentation of the 68020 processor. ---- +---- ---- +---- Author(s): ---- +---- - Wolfgang Foerster, wf@experiment-s.de; wf@inventronik.de ---- +---- ---- +------------------------------------------------------------------------ +---- ---- +---- Copyright © 2014-2019 Wolfgang Foerster Inventronik GmbH. ---- +---- ---- +---- This documentation describes Open Hardware and is licensed ---- +---- under the CERN OHL v. 1.2. You may redistribute and modify ---- +---- this documentation under the terms of the CERN OHL v.1.2. ---- +---- (http://ohwr.org/cernohl). This documentation is distributed ---- +---- WITHOUT ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING OF ---- +---- MERCHANTABILITY, SATISFACTORY QUALITY AND FITNESS FOR A ---- +---- PARTICULAR PURPOSE. Please see the CERN OHL v.1.2 for ---- +---- applicable conditions ---- +---- ---- +------------------------------------------------------------------------ +-- +-- Revision History +-- +-- Revision 2K14B 20141201 WF +-- Initial Release. +-- Revision 2K18A 20180620 WF +-- Suppress bus faults during RESET instruction. +-- Optimized ASn and DSn timing for synchronous RAM. +-- DATA_PORT_EN timing optimization. +-- BUS_EN is now active except during arbitration. +-- Rearanged the DATA_RDY vs. BUS_FLT logic. +-- Opted out START_READ and CHK_RD. +-- Fixed the faulty bus arbitration logic. +-- Rearranged address error handling. +-- Revision 2K20A 20200620 WF +-- ASn and DSn are not asserted in S0 any more. +-- Some modifications to optimize the RETRY logic. +-- Fixed a bug in the DSACK_MEM logic (now switches explicitely to "00"). +-- + +library work; +use work.WF68K30L_PKG.all; + +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_unsigned.all; +use ieee.numeric_std.all; + +entity WF68K30L_BUS_INTERFACE is + port ( + -- System control: + CLK : in std_logic; -- System clock. + + -- Adress bus: + ADR_IN_P : in std_logic_vector(31 downto 0); -- Logical address line inputs. + ADR_OUT_P : out std_logic_vector(31 downto 0); -- Address line outputs. + + -- Function code relevant stuff: + FC_IN : in std_logic_vector(2 downto 0); -- Function codes. + FC_OUT : out std_logic_vector(2 downto 0); -- Physical function codes (top level entity). + + -- Data bus: + DATA_PORT_IN : in std_logic_vector(31 downto 0); -- Data bus input lines (top level entity). + DATA_PORT_OUT : out std_logic_vector(31 downto 0); -- Data bus output lines (top level entity). + DATA_FROM_CORE : in std_logic_vector(31 downto 0); -- Internal bus input lines. + DATA_TO_CORE : out std_logic_vector(31 downto 0); -- Internal data bus output lines. + OPCODE_TO_CORE : out std_logic_vector(15 downto 0); -- Internal instruction bus output lines. + + -- Tri state controls: + DATA_PORT_EN : out std_logic; -- For the data bus. + BUS_EN : out std_logic; -- For all other bus control signals. + + -- Transfer and operation size: + SIZE : out std_logic_vector(1 downto 0); -- This is the size information (top level entity). + OP_SIZE : in OP_SIZETYPE; -- Used for bus access control. + + -- Control signals: + RD_REQ : in bit; -- Read data. + WR_REQ : in bit; -- Write data. + DATA_RDY : out bit; -- Indicates 'new data available' (this is a strobe). + DATA_VALID : out std_logic; -- The data buffer contains valid data when '1'. + OPCODE_REQ : in bit; -- Read opcode. + OPCODE_RDY : out bit; -- Indicates 'new opcode available' (this is a strobe). + OPCODE_VALID : out std_logic; -- The opcode buffer contains valid data when '1'. + RMC : in bit; -- Indicates a read modify write operation. + BUSY_EXH : in bit; + INBUFFER : out std_logic_vector(31 downto 0); -- Used by the exception handler for stack frame type B. + OUTBUFFER : out std_logic_vector(31 downto 0); -- Used by the exception handler for stack frame types A and B. + SSW_80 : out std_logic_vector(8 downto 0); + + -- Asynchronous bus control signals: + DSACKn : in std_logic_vector(1 downto 0); -- Asynchronous bus cycle termination (top level entity). + ASn : out std_logic; -- Adress select (top level entity). + DSn : out std_logic; -- Data select (top level entity). + RWn : out std_logic; -- Hi is read, low = write (top level entity). + RMCn : out std_logic; -- Read modify write indicator (top level entity). + ECSn : out std_logic; -- External cycle start (top level entity). + OCSn : out std_logic; -- Operand cycle start (top level entity). + DBENn : out std_logic; -- Data buffer enable (top level entity). + + -- Synchronous bus control: + STERMn : in std_logic; -- Synchronous bus cycle termination (top level entity). + + -- Bus arbitration: + BRn : in std_logic; -- Bus request (top level entity). + BGACKn : in std_logic; -- Bus grant acknowledge (top level entity). + BGn : out std_logic; -- Bus grant (top level entity). + + -- Exception signals: + RESET_IN : in std_logic; -- System's reset input (top level entity). + RESET_STRB : in bit; -- From Core: force external reset. + RESET_OUT : out std_logic; -- System's reset output open drain enable. + RESET_CPU : out bit; -- Internal reset used for CPU initialization. + AVECn : in std_logic; -- Auto interrupt vector input (top level entity). + HALTn : in std_logic; -- Halt (top level entity). + BERRn : in std_logic; -- Bus error (top level entity). + AERR : buffer bit; -- Core internal address error. + + BUS_BSY : out bit -- Bus is busy when '1'. + ); +end entity WF68K30L_BUS_INTERFACE; + +architecture BEHAVIOR of WF68K30L_BUS_INTERFACE is +type BUS_CTRL_STATES is (IDLE, START_CYCLE, DATA_C1C4); +type ARB_STATES is(IDLE, GRANT, WAIT_RELEASE_3WIRE); +type BUS_WIDTH_TYPE is(LONG_32, WORD, BYTE); +type TIME_SLICES is (IDLE, S0, S1, S2, S3, S4, S5); +signal ADR_10 : std_logic_vector(1 downto 0); +signal ADR_OFFSET : std_logic_vector(5 downto 0); +signal ADR_OUT_I : std_logic_vector(31 downto 0); +signal AERR_I : bit; +signal ARB_STATE : ARB_STATES := IDLE; +signal AVEC_In : std_logic; +signal BGACK_In : std_logic; +signal BR_In : std_logic; +signal BUS_CTRL_STATE : BUS_CTRL_STATES; +signal BUS_CYC_RDY : bit; +signal BUS_FLT : std_logic; +signal BUS_WIDTH : BUS_WIDTH_TYPE; +signal DATA_INMUX : std_logic_vector(31 downto 0); +signal DATA_RDY_I : bit; +signal DBUFFER : std_logic_vector(31 downto 0); +signal DSACK_In : std_logic_vector(1 downto 0); +signal DSACK_MEM : std_logic_vector(1 downto 0); +signal OCS_INH : bit; +signal HALT_In : std_logic; +signal HALTED : bit; +signal NEXT_ARB_STATE : ARB_STATES; +signal NEXT_BUS_CTRL_STATE : BUS_CTRL_STATES; +signal OBUFFER : std_logic_vector(15 downto 0); +signal OPCODE_ACCESS : bit; +signal OPCODE_RDY_I : bit; +signal READ_ACCESS : bit; +signal RESET_CPU_I : bit; +signal RESET_OUT_I : std_logic; +signal RETRY : bit; +signal SIZE_D : std_logic_vector(1 downto 0); +signal SIZE_I : std_logic_vector(1 downto 0); +signal SIZE_N : std_logic_vector(2 downto 0) := "000"; +signal SLICE_CNT_N : std_logic_vector(2 downto 0); +signal SLICE_CNT_P : std_logic_vector(2 downto 0); +signal STERM_Dn : std_logic; +signal T_SLICE : TIME_SLICES; +signal WAITSTATES : bit; +signal WP_BUFFER : std_logic_vector(31 downto 0); +signal WRITE_ACCESS : bit; +begin + P_SYNC: process(CLK) + -- These flip flops synchronize external signals on the negative clock edge. This + -- meets the requirement of sampling these signals in the end of S2 for asynchronous + -- bus access. Be aware, that we have to buffer the RETRY signal to prevent the bus + -- controller of spurious or timing critical BERRn and/or HALTn signals. The logic + -- for BUS_FLT and RETRY is coded in a way that we have a bus error or a retry + -- condition but not both at the same time. + -- Note: there is no need to synchronize the already synchronous bus control signals + variable BERR_VARn : std_logic; + variable HALT_VARn : std_logic; + begin + if CLK = '0' and CLK' event then + DSACK_In <= DSACKn; + BR_In <= BRn; + BGACK_In <= BGACKn; + AVEC_In <= AVECn; + HALT_VARn := HALTn; + BERR_VARn := BERRn; + end if; + -- + if CLK = '1' and CLK' event then + if BUS_CTRL_STATE = START_CYCLE then + AERR <= AERR_I; -- AERR_I is valid in this state. + else + AERR <= '0'; + end if; + -- + HALT_In <= HALTn or HALT_VARn; + -- + if BUS_CTRL_STATE = DATA_C1C4 then + if (BERRn nand BERR_VARn) = '1' and (HALTn or HALT_VARn) = '0' and SIZE_N /= "000" then + RETRY <= '1'; + elsif T_SLICE = IDLE and (BERRn = '1' and HALTn = '1' and BERR_VARn = '1' and HALT_VARn = '1') then + RETRY <= '0'; + elsif RETRY = '0' then + BUS_FLT <= (BERRn nor BERR_VARn) and HALT_VARn and HALTn; + end if; + else + BUS_FLT <= '0'; + RETRY <= '0'; + end if; + -- + STERM_Dn <= STERMn; -- Delay to update the SIZE_N and SIZE_M before BUS_CYC_RDY is asserted. + end if; + end process P_SYNC; + + ACCESSTYPE: process + -- This logic stores the execution unit control + -- signals during the current bus access. This is + -- important for the bus control signals to be + -- stable during the complete bus access. + begin + wait until CLK = '1' and CLK' event; + if BUS_CTRL_STATE = START_CYCLE then + if READ_ACCESS = '1' or WRITE_ACCESS = '1' or OPCODE_ACCESS = '1' then + null; -- Do not start either new cycle. + elsif RD_REQ = '1' then + READ_ACCESS <= '1'; + elsif WR_REQ = '1' then + WRITE_ACCESS <= '1'; + elsif OPCODE_REQ = '1' then + OPCODE_ACCESS <= '1'; + end if; + elsif AERR = '1' then -- Reject due to address error. + READ_ACCESS <= '0'; + WRITE_ACCESS <= '0'; + OPCODE_ACCESS <= '0'; + elsif BUS_CTRL_STATE = DATA_C1C4 and NEXT_BUS_CTRL_STATE = IDLE and SIZE_N = "000" then + READ_ACCESS <= '0'; + WRITE_ACCESS <= '0'; + OPCODE_ACCESS <= '0'; + end if; + end process ACCESSTYPE; + + P_DF: process + -- This is the logic which provides the fault flags for data cycles and + -- input and output buffer information. + variable SIZEVAR : std_logic_vector(1 downto 0) := "00"; + begin + wait until CLK = '1' and CLK' event; + if BUSY_EXH = '0' then -- Do not alter during exception processing. + case OP_SIZE is + when LONG => SIZEVAR := "10"; + when WORD => SIZEVAR := "01"; + when BYTE => SIZEVAR := "00"; + end case; + -- + if BUS_CTRL_STATE = START_CYCLE and NEXT_BUS_CTRL_STATE = DATA_C1C4 then + SSW_80 <= To_StdLogicVector('0' & RMC & not WR_REQ) & SIZEVAR & '0' & FC_IN; + elsif BUS_CTRL_STATE = DATA_C1C4 and (READ_ACCESS = '1' or WRITE_ACCESS = '1') and BUS_FLT = '1' then + SSW_80(8) <= '1'; + end if; + + OUTBUFFER <= WP_BUFFER; -- Used for exception stack frame type A and B. + INBUFFER <= DATA_INMUX; -- Used for exception stack frame type B. + end if; + end process P_DF; + + WRITEBACK_INFO: process + -- This registers stor writeback relevant information. + begin + wait until CLK = '1' and CLK' event; + if BUS_CTRL_STATE = IDLE and NEXT_BUS_CTRL_STATE = START_CYCLE then -- Freeze during a bus cycle. + WP_BUFFER <= DATA_FROM_CORE; + end if; + end process WRITEBACK_INFO; + + P_BUSWIDTH: process + -- These flip flops store the bus width information + -- during the current bus access. + begin + wait until CLK = '1' and CLK' event; + if BUS_CTRL_STATE = IDLE then + DSACK_MEM <= "11"; + elsif DSACK_In /= "11" then + DSACK_MEM <= DSACK_In; + end if; + end process P_BUSWIDTH; + + BUS_WIDTH <= WORD when DSACKn = "01" or DSACK_MEM = "01" else + BYTE when DSACKn = "10" or DSACK_MEM = "10" else + LONG_32; -- Also used during synchronous cycles. + + BUS_BSY <= '1' when BUS_CTRL_STATE /= IDLE else '0'; + + PARTITIONING: process + -- This logic gives information about the remaining bus cycles The initial + -- size is sampled right before the bus acces. This requires the RD_REQ + -- and WR_REQ signals to work on the positive clock edge. + variable RESTORE_VAR : std_logic_vector(2 downto 0) := "000"; + begin + wait until CLK = '1' and CLK' event; + + if BUS_CTRL_STATE = DATA_C1C4 and T_SLICE = S1 then -- On positive clock edge. + RESTORE_VAR := SIZE_N; -- We need this initial value for early RETRY. + end if; + -- + if RESET_CPU_I = '1' then + SIZE_N <= "000"; + elsif BUS_CTRL_STATE /= DATA_C1C4 and NEXT_BUS_CTRL_STATE = DATA_C1C4 then + if RD_REQ = '1' or WR_REQ = '1' then + case OP_SIZE is + when LONG => SIZE_N <= "100"; + when WORD => SIZE_N <= "010"; + when BYTE => SIZE_N <= "001"; + end case; + else -- OPCODE_ACCESS. + SIZE_N <= "010"; -- WORD. + end if; + end if; + + -- Decrementing the size information: + -- In this logic all permutations are considered. This allows a dynamically changing bus size. + if RETRY = '1' then + SIZE_N <= RESTORE_VAR; + elsif BUS_CTRL_STATE = DATA_C1C4 and ((T_SLICE = S1 and STERMn = '0') or (T_SLICE = S3 and WAITSTATES = '0')) then -- On positive clock edge. + if BUS_WIDTH = LONG_32 and SIZE_N > x"3" and ADR_OUT_I(1 downto 0) = "01" then + SIZE_N <= SIZE_N - "11"; + elsif BUS_WIDTH = LONG_32 and SIZE_N > x"2" and ADR_OUT_I(1 downto 0) = "10" then + SIZE_N <= SIZE_N - "10"; + elsif BUS_WIDTH = LONG_32 and SIZE_N > x"1" and ADR_OUT_I(1 downto 0) = "11" then + SIZE_N <= SIZE_N - '1'; + elsif BUS_WIDTH = LONG_32 then + SIZE_N <= "000"; + -- + elsif BUS_WIDTH = WORD and ADR_OUT_I(1 downto 0) = "11" then + SIZE_N <= SIZE_N - '1'; + elsif BUS_WIDTH = WORD and ADR_OUT_I(1 downto 0) = "01" then + SIZE_N <= SIZE_N - '1'; + elsif BUS_WIDTH = WORD and SIZE_N = "001" then + SIZE_N <= SIZE_N - '1'; + elsif BUS_WIDTH = WORD then + SIZE_N <= SIZE_N - "10"; + -- + elsif BUS_WIDTH = BYTE then + SIZE_N <= SIZE_N - '1'; + end if; + end if; + -- + if (BUS_FLT = '1' and HALT_In = '1') then -- Abort bus cycle. + SIZE_N <= "000"; + end if; + end process PARTITIONING; + + SIZE_I <= SIZE_N(1 downto 0) when T_SLICE = S0 or T_SLICE = S1 else SIZE_D; + SIZE <= SIZE_I; + + P_DELAY: process + -- This delay is responsible for a correct SIZE_I information. Use this, if the + -- process PARTITIONING works on the positive clock edge. The SIZE_I information + -- is delayed by half a clock cycle to be valid just in time of sampling the INMUX. + begin + wait until CLK = '1' and CLK' event; + SIZE_D <= SIZE_N(1 downto 0); + end process P_DELAY; + + BUS_STATE_REG: process + -- This is the bus controller's state register. + begin + wait until CLK = '1' and CLK' event; + BUS_CTRL_STATE <= NEXT_BUS_CTRL_STATE; + end process BUS_STATE_REG; + + BUS_CTRL_DEC: process(ADR_IN_P, ADR_OUT_I, ARB_STATE, BGACK_In, BR_In, BUS_CTRL_STATE, BUS_CYC_RDY, BUS_FLT, HALT_In, + OPCODE_ACCESS, OPCODE_REQ, RD_REQ, READ_ACCESS, RESET_CPU_I, RMC, SIZE_N, WR_REQ, WRITE_ACCESS) + -- This is the bus controller's state machine decoder. A SIZE_N count of "000" means that all bytes + -- to be transfered. After a bus transfer a value of x"0" indicates that no further bytes are required + -- for a bus transfer. + begin + case BUS_CTRL_STATE is + when IDLE => + if RESET_CPU_I = '1' then + NEXT_BUS_CTRL_STATE <= IDLE; -- Reset condition (bus cycle terminated). + elsif HALT_In = '0' then + NEXT_BUS_CTRL_STATE <= IDLE; -- This is the 'HALT' condition. + elsif (BR_In = '0' and RMC = '0') or ARB_STATE /= IDLE or BGACK_In = '0' then + NEXT_BUS_CTRL_STATE <= IDLE; -- Arbitration, wait! + elsif RD_REQ = '1' and SIZE_N = "000" then + NEXT_BUS_CTRL_STATE <= START_CYCLE; -- New read cycle. + elsif WR_REQ = '1' and SIZE_N = "000" then + NEXT_BUS_CTRL_STATE <= START_CYCLE; -- New write cycle. + elsif OPCODE_REQ = '1' and SIZE_N = "000" then + NEXT_BUS_CTRL_STATE <= START_CYCLE; -- New read cycle. + elsif READ_ACCESS = '1' or WRITE_ACCESS = '1' or OPCODE_ACCESS = '1' then + NEXT_BUS_CTRL_STATE <= START_CYCLE; -- Pending (split) bus cycles. + else + NEXT_BUS_CTRL_STATE <= IDLE; + end if; + when START_CYCLE => + if RD_REQ = '1' then + NEXT_BUS_CTRL_STATE <= DATA_C1C4; + elsif WR_REQ = '1' then + NEXT_BUS_CTRL_STATE <= DATA_C1C4; + elsif OPCODE_REQ = '1' and ADR_IN_P(0) = '1' then + NEXT_BUS_CTRL_STATE <= IDLE; -- Abort due to address error. + elsif OPCODE_REQ = '1' and ADR_IN_P(0) = '1' then + NEXT_BUS_CTRL_STATE <= IDLE; -- Abort due to address error. + elsif OPCODE_REQ = '1' then + NEXT_BUS_CTRL_STATE <= DATA_C1C4; + else + NEXT_BUS_CTRL_STATE <= IDLE; + end if; + when DATA_C1C4 => + if BUS_CYC_RDY = '1' and SIZE_N = "000" then + NEXT_BUS_CTRL_STATE <= IDLE; + else + NEXT_BUS_CTRL_STATE <= DATA_C1C4; + end if; + end case; + end process BUS_CTRL_DEC; + + P_ADR_OFFS: process + -- This process provides a temporary address offset during + -- bus access. + variable OFFSET_VAR : std_logic_vector(2 downto 0) := "000"; + begin + wait until CLK = '1' and CLK' event; + if RESET_CPU_I = '1' then + OFFSET_VAR := "000"; + elsif (T_SLICE = S2 and STERMn = '0') or T_SLICE = S3 then + case BUS_WIDTH is + when LONG_32 => + case ADR_OUT_I(1 downto 0) is + when "11" => OFFSET_VAR := "001"; + when "10" => OFFSET_VAR := "010"; + when "01" => OFFSET_VAR := "011"; + when others => OFFSET_VAR := "100"; + end case; + when WORD => + case ADR_OUT_I(1 downto 0) is + when "01" | "11" => OFFSET_VAR := "001"; + when others => OFFSET_VAR := "010"; + end case; + when BYTE => + OFFSET_VAR := "001"; + end case; + end if; + -- + if RESET_CPU_I = '1' then + ADR_OFFSET <= (others => '0'); + elsif RETRY = '1' then + null; -- Do not update if there is a retry cycle. + elsif BUS_CTRL_STATE /= IDLE and NEXT_BUS_CTRL_STATE = IDLE then + ADR_OFFSET <= (others => '0'); + elsif BUS_CYC_RDY = '1' then + ADR_OFFSET <= ADR_OFFSET + OFFSET_VAR; + end if; + end process P_ADR_OFFS; + + ADR_OUT_I <= ADR_IN_P + ADR_OFFSET; + ADR_OUT_P <= ADR_OUT_I; + + P_ADR_10: process + -- This logic is registered to enhance the system performance concerning fmax. + begin + wait until CLK = '1' and CLK' event; + ADR_10 <= ADR_OUT_I(1 downto 0); + end process P_ADR_10; + + -- Address and bus errors: + AERR_I <= '1' when BUS_CTRL_STATE = START_CYCLE and OPCODE_REQ = '1' and RD_REQ = '0' and WR_REQ = '0' and ADR_IN_P(0) = '1' else '0'; + + FC_OUT <= FC_IN; + + -- The output multiplexer is as follows: + -- SIZE ADR Bytes (L = long word port, W = word port, B = Byte port, x = not used by either port) + -- 00 00 3 (L, W, B) 2 (L, W ) 1 (L ) 0 (L ) + -- 00 01 3 ( B) 3 (L, W ) 2 (L ) 1 (L ) + -- 00 10 3 ( W, B) 2 ( W ) 3 (L ) 2 (L ) + -- 00 11 3 ( B) 2 ( W ) -----x----- 0 (L ) + -- 11 00 2 (L, W, B) 1 (L, W ) 0 (L ) -----x----- + -- 11 01 2 ( B) 2 (L, W ) 1 (L ) 0 (L ) + -- 11 10 1 ( W, B) 0 ( W ) 1 (L ) 0 (L ) + -- 11 11 1 ( B) 1 ( W ) -----x----- 1 (L ) + -- 10 00 1 (L, W, B) 0 (L, W ) -----x----- -----x----- + -- 10 01 1 ( B) 1 (L, W ) 0 (L ) -----x----- + -- 10 10 1 ( W, B) 0 ( W ) 1 (L ) 0 (L ) + -- 10 11 1 ( B) 1 ( W ) -----x----- 1 (L ) + -- 01 00 0 (L, W, B) -----x----- -----x----- -----x----- + -- 01 01 0 ( B) 0 (L, W ) -----x----- -----x----- + -- 01 10 0 ( W, B) -----x----- 0 (L ) -----x----- + -- 01 11 0 ( B) 0 ( W ) -----x----- 0 (L ) + + DATA_PORT_OUT <= -- Data output multiplexer. + -- LONG: + WP_BUFFER(31 downto 0) when SIZE_I = "00" and ADR_OUT_I(1 downto 0) = "00" else + WP_BUFFER(31 downto 24) & WP_BUFFER(31 downto 8) when SIZE_I = "00" and ADR_OUT_I(1 downto 0) = "01" else + WP_BUFFER(31 downto 16) & WP_BUFFER(31 downto 16) when SIZE_I = "00" and ADR_OUT_I(1 downto 0) = "10" else + WP_BUFFER(31 downto 24) & WP_BUFFER(31 downto 16) & WP_BUFFER(31 downto 24) when SIZE_I = "00" and ADR_OUT_I(1 downto 0) = "11" else + -- 3 bytes: + WP_BUFFER(23 downto 0) & WP_BUFFER(31 downto 24) when SIZE_I = x"3" and ADR_OUT_I(1 downto 0) = "00" else + WP_BUFFER(23 downto 16) & WP_BUFFER(23 downto 0) when SIZE_I = "11" and ADR_OUT_I(1 downto 0) = "01" else + WP_BUFFER(23 downto 8) & WP_BUFFER(23 downto 8) when SIZE_I = "11" and ADR_OUT_I(1 downto 0) = "10" else + WP_BUFFER(23 downto 16) & WP_BUFFER(23 downto 8) & WP_BUFFER(23 downto 16) when SIZE_I = "11" and ADR_OUT_I(1 downto 0) = "11" else + -- Word: + WP_BUFFER(15 downto 0) & WP_BUFFER(15 downto 0) when SIZE_I = "10" and ADR_OUT_I(1 downto 0) = "00" else + WP_BUFFER(15 downto 8) & WP_BUFFER(15 downto 0) & WP_BUFFER(15 downto 8) when SIZE_I = "10" and ADR_OUT_I(1 downto 0) = "01" else + WP_BUFFER(15 downto 0) & WP_BUFFER(15 downto 0) when SIZE_I = "10" and ADR_OUT_I(1 downto 0) = "10" else + WP_BUFFER(15 downto 8) & WP_BUFFER(15 downto 0) & WP_BUFFER(15 downto 8) when SIZE_I = "10" and ADR_OUT_I(1 downto 0) = "11" else + -- Byte: + WP_BUFFER(7 downto 0) & WP_BUFFER(7 downto 0) & WP_BUFFER(7 downto 0) & WP_BUFFER(7 downto 0); -- SIZE = "01". + + IN_MUX: process + -- This is the input multiplexer which can handle up to four bytes. + begin + wait until CLK = '0' and CLK' event; + -- + if ((T_SLICE = S2 or T_SLICE = S3) and STERMn = '0') or T_SLICE = S4 then + case BUS_WIDTH is + when BYTE => + case SIZE_I is + when "00" => DATA_INMUX(31 downto 24) <= DATA_PORT_IN(31 downto 24); -- LONG. + when "11" => DATA_INMUX(23 downto 16) <= DATA_PORT_IN(31 downto 24); -- Three bytes. + when "10" => DATA_INMUX(15 downto 8) <= DATA_PORT_IN(31 downto 24); -- Word. + when others => DATA_INMUX(7 downto 0) <= DATA_PORT_IN(31 downto 24); -- Byte. + end case; + when WORD => + case SIZE_I is + when "01" => -- Byte. + case ADR_10 is + when "00" | "10" => DATA_INMUX(7 downto 0) <= DATA_PORT_IN(31 downto 24); + when others => DATA_INMUX(7 downto 0) <= DATA_PORT_IN(23 downto 16); -- "01", "11". + end case; + when "10" => -- Word. + case ADR_10 is + when "00" => DATA_INMUX(15 downto 0) <= DATA_PORT_IN(31 downto 16); + when "01" => DATA_INMUX(15 downto 8) <= DATA_PORT_IN(23 downto 16); + when "10" => DATA_INMUX(15 downto 0) <= DATA_PORT_IN(31 downto 16); + when others => DATA_INMUX(15 downto 8) <= DATA_PORT_IN(23 downto 16); -- "11". + end case; + when "11" => -- Three bytes. + case ADR_10 is + when "00" => DATA_INMUX(23 downto 8) <= DATA_PORT_IN(31 downto 16); + when "01" => DATA_INMUX(23 downto 16) <= DATA_PORT_IN(23 downto 16); + when "10" => DATA_INMUX(23 downto 8) <= DATA_PORT_IN(31 downto 16); + when others => DATA_INMUX(23 downto 16) <= DATA_PORT_IN(23 downto 16); -- "11". + end case; + when others => -- "00" = LONG. + case ADR_10 is + when "00" => DATA_INMUX(31 downto 16) <= DATA_PORT_IN(31 downto 16); + when "01" => DATA_INMUX(31 downto 24) <= DATA_PORT_IN(23 downto 16); + when "10" => DATA_INMUX(31 downto 16) <= DATA_PORT_IN(31 downto 16); + when others => DATA_INMUX(31 downto 24) <= DATA_PORT_IN(23 downto 16); -- "11". + end case; + end case; + when LONG_32 => + case SIZE_I is + when "01" => -- Byte. + case ADR_10 is + when "00" => DATA_INMUX(7 downto 0) <= DATA_PORT_IN(31 downto 24); + when "01" => DATA_INMUX(7 downto 0) <= DATA_PORT_IN(23 downto 16); + when "10" => DATA_INMUX(7 downto 0) <= DATA_PORT_IN(15 downto 8); + when others => DATA_INMUX(7 downto 0) <= DATA_PORT_IN(7 downto 0); -- "11". + end case; + when "10" => -- Word. + case ADR_10 is + when "00" => DATA_INMUX(15 downto 0) <= DATA_PORT_IN(31 downto 16); + when "01" => DATA_INMUX(15 downto 0) <= DATA_PORT_IN(23 downto 8); + when "10" => DATA_INMUX(15 downto 0) <= DATA_PORT_IN(15 downto 0); + when others => DATA_INMUX(15 downto 8) <= DATA_PORT_IN(7 downto 0); -- "11". + end case; + when "11" => -- Three bytes. + case ADR_10 is + when "00" => DATA_INMUX(23 downto 0) <= DATA_PORT_IN(31 downto 8); + when "01" => DATA_INMUX(23 downto 0) <= DATA_PORT_IN(23 downto 0); + when "10" => DATA_INMUX(23 downto 8) <= DATA_PORT_IN(15 downto 0); + when others => DATA_INMUX(23 downto 16) <= DATA_PORT_IN(7 downto 0); -- "11". + end case; + when others => -- "00" = LONG. + case ADR_10 is + when "00" => DATA_INMUX(31 downto 0) <= DATA_PORT_IN(31 downto 0); + when "01" => DATA_INMUX(31 downto 8) <= DATA_PORT_IN(23 downto 0); + when "10" => DATA_INMUX(31 downto 16) <= DATA_PORT_IN(15 downto 0); + when others => DATA_INMUX(31 downto 24) <= DATA_PORT_IN(7 downto 0); -- "11". + end case; + end case; + end case; + end if; + end process IN_MUX; + + VALIDATION: process + -- These flip flops detect a fault during the read operation over one or + -- several bytes or during the write operation. + begin + wait until CLK = '1' and CLK' event; + -- + if RESET_CPU_I = '1' then + OPCODE_VALID <= '1'; + elsif OPCODE_ACCESS = '1' and BUS_CTRL_STATE = DATA_C1C4 and BUS_FLT = '1' then + OPCODE_VALID <= '0'; + elsif OPCODE_RDY_I = '1' then + OPCODE_VALID <= '1'; -- Reset after use, TRAP_BERR is asserted during DATA_RDY. + end if; + -- + if RESET_CPU_I = '1' then + DATA_VALID <= '1'; + elsif BUS_CTRL_STATE = DATA_C1C4 and BUS_FLT = '1' then + DATA_VALID <= '0'; + elsif DATA_RDY_I = '1' then + DATA_VALID <= '1'; -- Reset after use, TRAP_BERR is asserted during DATA_RDY. + end if; + end process VALIDATION; + + PREFETCH_BUFFERS: process + -- These are the data and the operation code input registers. After a last read to the registered + -- input multiplexer, the respective data is copied from the input multiplexer to these buffers. + -- The opcode buffer is always written with 32 bit data. The data buffers may contain invalid bytes + -- in case of word or byte data size. + variable DBUFFER_MEM : std_logic_vector(31 downto 8) := x"000000"; + variable RDY_VAR : bit := '0'; + begin + wait until CLK = '1' and CLK' event; + -- + OPCODE_RDY_I <= '0'; -- This is a strobe. + DATA_RDY_I <= '0'; -- This is a strobe. + -- + -- The following variable is responsible, that the _RDY signals are + -- always strobes. + if DATA_RDY_I = '1' or OPCODE_RDY_I = '1' then + RDY_VAR := '0'; + elsif BUS_CTRL_STATE = START_CYCLE then + RDY_VAR := '1'; + end if; + -- Opcode cycle: + if AERR_I = '1' then + OPCODE_RDY_I <= '1'; + elsif OPCODE_ACCESS = '1' and BUS_CTRL_STATE = DATA_C1C4 and BUS_CYC_RDY = '1' and SIZE_N = "000" then + -- Instruction prefetches are always long and on word boundaries. + -- The word is available after the first word read. + OBUFFER <= DATA_INMUX(15 downto 0); + OPCODE_RDY_I <= RDY_VAR; + end if; + -- Data cycle: + if WRITE_ACCESS = '1' and BUS_CTRL_STATE = DATA_C1C4 and BUS_CYC_RDY = '1' and SIZE_N = "000" then + DATA_RDY_I <= RDY_VAR; + elsif READ_ACCESS = '1' and BUS_CTRL_STATE = DATA_C1C4 and BUS_CYC_RDY = '1' then + case OP_SIZE is + when LONG => + if SIZE_N = "000" then + DBUFFER <= DATA_INMUX; + DATA_RDY_I <= RDY_VAR; + end if; + when WORD => + if SIZE_N = "000" then + DBUFFER <= x"0000" & DATA_INMUX(15 downto 0); + DATA_RDY_I <= RDY_VAR; + end if; + when BYTE => -- Byte always aligned. + DATA_RDY_I <= RDY_VAR; + DBUFFER <= x"000000" & DATA_INMUX(7 downto 0); + end case; + end if; + end process PREFETCH_BUFFERS; + + DATA_RDY <= DATA_RDY_I; + OPCODE_RDY <= OPCODE_RDY_I; + + DATA_TO_CORE <= DBUFFER; + OPCODE_TO_CORE <= OBUFFER; + + WAITSTATES <= '0' when T_SLICE /= S3 else + '1' when RESET_OUT_I = '1' else -- No bus fault during RESET instruction. + '0' when DSACK_In /= "11" else -- For asynchronous bus cycles. + '0' when STERMn = '0' else -- For synchronous bus cycles. + '0' when ADR_IN_P(19 downto 16) = x"F" and AVEC_In = '0' else -- Interrupt acknowledge space cycle. + '0' when BUS_FLT = '1' else -- In case of a bus error; + '0' when RESET_CPU_I = '1' else '1'; -- A CPU reset terminates the current bus cycle. + + SLICES: process(CLK) + -- This process provides the central timing for the read, write and read modify write cycle as also + -- for the bus arbitration procedure. Be aware, that the bus controller state machine changes it's + -- state on the positive clock edge. The BUS_CYC_RDY signal is asserted during S3 or S5. So the + -- slice counter working on the positive clock edge may change it's state. + begin + if CLK = '1' and CLK' event then + if BUS_CTRL_STATE = IDLE then + SLICE_CNT_P <= "111"; -- Init. + elsif RETRY = '1' then + SLICE_CNT_P <= "111"; -- Stay in IDLE, go to IDLE. + elsif BUS_CTRL_STATE /= IDLE and NEXT_BUS_CTRL_STATE = IDLE then + SLICE_CNT_P <= "111"; -- Init. + elsif SLICE_CNT_P = "001" and STERMn = '0' then -- Synchronous cycle. + SLICE_CNT_P <= "110"; -- Ready. + elsif SLICE_CNT_P = "010" then + if RETRY = '1' then + SLICE_CNT_P <= "111"; -- Go IDLE. + elsif BUS_CTRL_STATE = DATA_C1C4 and NEXT_BUS_CTRL_STATE = IDLE then + SLICE_CNT_P <= "111"; -- Ready. + else + SLICE_CNT_P <= "000"; -- Go on. + end if; + elsif WAITSTATES = '0' then + SLICE_CNT_P <= SLICE_CNT_P + '1'; -- Cycle active. + end if; + end if; + -- + if CLK = '0' and CLK' event then + SLICE_CNT_N <= SLICE_CNT_P; -- Follow the P counter. + end if; + end process SLICES; + + T_SLICE <= S0 when SLICE_CNT_P = "000" and SLICE_CNT_N = "111" else + S1 when SLICE_CNT_P = "000" and SLICE_CNT_N = "000" else + S2 when SLICE_CNT_P = "001" and SLICE_CNT_N = "000" else + S3 when SLICE_CNT_P = "001" and SLICE_CNT_N = "001" else + S4 when SLICE_CNT_P = "010" and SLICE_CNT_N = "001" else + S5 when SLICE_CNT_P = "010" and SLICE_CNT_N = "010" else + S3 when SLICE_CNT_P = "110" else -- This is a waitstate cycle for synchronous bus cycles to update SIZE_N before latching data. + S0 when SLICE_CNT_P = "000" and SLICE_CNT_N = "010" else IDLE; -- Rollover from state S5 to S0. + + P_OCS: process + -- This flip flop enables the output of the OCSn signal for + -- the first bus cycle and locks OCSn for all other bus cycles. + -- ECSn is locked only during cache burst access. + begin + wait until CLK = '1' and CLK' event; + -- + if BUS_CTRL_STATE = START_CYCLE and NEXT_BUS_CTRL_STATE /= IDLE then + OCS_INH <= '0'; + elsif BUS_CYC_RDY = '1' and RETRY = '0' then -- No inhibit if first portion results in a retry cycle. + OCS_INH <= '1'; + end if; + end process P_OCS; + + -- Bus control signals: + RWn <= '0' when WRITE_ACCESS = '1' and BUS_CTRL_STATE = DATA_C1C4 else '1'; + RMCn <= '0' when RMC = '1' else '1'; + ECSn <= '0' when T_SLICE = S0 else '1'; + OCSn <= '0' when T_SLICE = S0 and OCS_INH = '0' else '1'; + ASn <= '0' when T_SLICE = S1 or T_SLICE = S2 or T_SLICE = S3 or T_SLICE = S4 else '1'; + DSn <= '0' when (T_SLICE = S3 or T_SLICE = S4 or T_SLICE = S5) and WRITE_ACCESS = '1' else -- Write. + '0' when T_SLICE = S1 or T_SLICE = S2 or T_SLICE = S3 or T_SLICE = S4 else '1'; -- Read. + + DBENn <= '0' when (T_SLICE = S1 or T_SLICE = S2 or T_SLICE = S3 or T_SLICE = S4 or T_SLICE = S5) and WRITE_ACCESS = '1' else -- Write. + '0' when T_SLICE = S2 or T_SLICE = S3 or T_SLICE = S4 else '1'; -- Read. + + -- Bus tri state controls: + BUS_EN <= '1' when ARB_STATE = IDLE and RESET_CPU_I = '0' else '0'; + DATA_PORT_EN <= '1' when WRITE_ACCESS = '1' and ARB_STATE = IDLE and RESET_CPU_I = '0' else '0'; + + -- Progress controls: + BUS_CYC_RDY <= '0' when RETRY = '1' else + '1' when STERM_Dn = '0' else -- Synchronous cycles. STERMn delayed to update the SIZE_N and SIZE_M before BUS_CYC_RDY is asserted. + '1' when T_SLICE = S5 else '0'; -- Asynchronous cycles. + + -- Bus arbitration: + ARB_REG: process + -- This is the arbiters state register. + begin + wait until CLK = '1' and CLK' event; + -- + if RESET_CPU_I = '1' then + ARB_STATE <= IDLE; + else + ARB_STATE <= NEXT_ARB_STATE; + end if; + end process ARB_REG; + + ARB_DEC: process(ARB_STATE, BGACK_In, BR_In, BUS_CTRL_STATE, RETRY, RMC) + -- This is the bus arbitration state machine's decoder. It can handle single-, two- + -- or three wire arbitration. The two wire arbitration is done in the GRANT state + -- by negating BRn. + begin + case ARB_STATE is + when IDLE => + if RMC = '1' and RETRY = '0' then + NEXT_ARB_STATE <= IDLE; -- Arbitration in RETRY operation is possible. + elsif BGACK_In = '0' and BUS_CTRL_STATE = IDLE then -- This is the single wire arbitration. + NEXT_ARB_STATE <= WAIT_RELEASE_3WIRE; + elsif BR_In = '0' and BUS_CTRL_STATE = IDLE then -- Wait until the bus is free. + NEXT_ARB_STATE <= GRANT; + else + NEXT_ARB_STATE <= IDLE; + end if; + when GRANT => + if BGACK_In = '0' then + NEXT_ARB_STATE <= WAIT_RELEASE_3WIRE; + elsif BR_In = '1' then + NEXT_ARB_STATE <= IDLE; -- Resume normal operation. + else + NEXT_ARB_STATE <= GRANT; + end if; + when WAIT_RELEASE_3WIRE => + if BGACK_In = '1' and BR_In = '0' then + NEXT_ARB_STATE <= GRANT; -- Re-enter new arbitration. + elsif BGACK_In = '1' then + NEXT_ARB_STATE <= IDLE; + else + NEXT_ARB_STATE <= WAIT_RELEASE_3WIRE; + end if; + end case; + end process ARB_DEC; + + BGn <= '0' when ARB_STATE = GRANT else '1'; + + -- RESET logic: + RESET_FILTER: process + -- This process filters the incoming reset pin. + -- If RESET_IN and HALT_In are asserted together for longer + -- than 10 clock cycles over the execution of a CPU reset + -- command, the CPU reset is released. + variable STARTUP : boolean := false; + variable TMP : std_logic_vector(3 downto 0) := x"0"; + begin + wait until CLK = '1' and CLK' event; + -- + if RESET_IN = '1' and HALT_In = '0' and RESET_OUT_I = '0' and TMP < x"F" then + TMP := TMP + '1'; + elsif RESET_IN = '0' or HALT_In = '1' or RESET_OUT_I = '1' then + TMP := x"0"; + end if; + if TMP > x"A" then + RESET_CPU_I <= '1'; -- Release internal reset. + STARTUP := true; + elsif STARTUP = false then + RESET_CPU_I <= '1'; + else + RESET_CPU_I <= '0'; + end if; + end process RESET_FILTER; + + RESET_TIMER: process + -- This logic is responsible for the assertion of the + -- reset output for 512 clock cycles, during the reset + -- command. The LOCK variable avoids re-initialisation + -- of the counter in the case that the RESET_EN is no + -- strobe. + variable TMP : std_logic_vector(8 downto 0) := "000000000"; + begin + wait until CLK = '1' and CLK' event; + -- + if RESET_STRB = '1' or TMP > "000000000" then + RESET_OUT_I <= '1'; + else + RESET_OUT_I <= '0'; + end if; + -- + if RESET_STRB = '1' then + TMP := "111111111"; -- 512 initial value. + elsif TMP > "000000000" then + TMP := TMP - '1'; + end if; + end process RESET_TIMER; + + RESET_CPU <= RESET_CPU_I; + RESET_OUT <= RESET_OUT_I; +end BEHAVIOR; diff --git a/common/CPU/68K30L/wf68k30L_control.vhd b/common/CPU/68K30L/wf68k30L_control.vhd new file mode 100644 index 00000000..166f4282 --- /dev/null +++ b/common/CPU/68K30L/wf68k30L_control.vhd @@ -0,0 +1,2553 @@ +------------------------------------------------------------------------ +---- ---- +---- WF68K30L IP Core: this is the main controller to handle all ---- +---- integer instructions. ---- +---- ---- +---- Description: ---- +---- This controller handles all integer instructions and provides ---- +---- all required system control signals. The instructions are ---- +---- requested from the instruction prefetch unit in the opcode ---- +---- decoder unit. The data is mostly written to the ALU and after- ---- +---- wards from the ALU to the writeback logic. This pipelined ---- +---- structure requires a correct management of data in use. Any ---- +---- address or data registers or memory addresses which are in use ---- +---- are marked by a flag not to be used befor written back. Any ---- +---- time data or address reegisters or the effective address are ---- +---- in the writeback pipe, the respective use flag is evaluated. ---- +---- Instructions like MOVE read unused source and the destination ---- +---- is written, when the ALU and writeback controller 'free'. ---- +---- Instructions like ADD, SUB etc. read unused source and desti- ---- +---- nations and write back the destination, when the operands are ---- +---- not used any more and the ALU and writeback controller are not ---- +---- in use by another operation. ---- +---- The main controller is the second pipeline stage of the CPU. ---- +---- The pipelining structure also requires some special treatment ---- +---- for the system control instructions as described as follows: ---- +------------------------------------------------------------------------ +---- System Control Instructions: ---- +---- There are several instructions which require the instruction ---- +---- pipe to be flushed as described in the following. For further ---- +---- information refer to the 68Kxx data sheets. ---- +---- ---- +---- 1. TRAP generating: ---- +---- The following instructions result in a pipe flush when the ---- +---- exception handler takes control over the system: ---- +---- BKPT, CHK, ILLEGAL, TRAP, TRAPV ---- +---- There are some other indirect conditions flushing the pipe ---- +---- such as the STOP which is invoked by an external interrupt.---- +---- ---- +---- 2. Privilege violations: ---- +---- Some instructions may result in a privilege violation ---- +---- when executed in user space. The result will be a ---- +---- privilege violation trap and the ipipe is flushed when ---- +---- the exception handler takes over. The instructions are: ---- +---- ANDI_TO_SR, EORI_TO_SR, ORI_TO_SR, MOVEC, MOVES, MOVE_USP, ---- +---- MOVE_FROM_SR, MOVE_TO_SR, RESET, RTE and STOP ---- +---- ---- +---- 3. Branches and Jumps: ---- +---- In case of branches and jumps and the respective return ---- +---- operations it is required to flush the instruction pipe. ---- +---- If PC value changes due to any branch or jump, it is neces- ---- +---- sary to flush the instruction pipe to invalidate already ---- +---- loaded 'old' instructions. This affects: ---- +---- BRA, BSR, Bcc, DBcc, JMP, JSR and the returns: ---- +---- RTD, RTR, RTS, RTE and also STOP. ---- +---- ---- +------------------------------------------------------------------------ +---- Data hazards: ---- +---- To avoid malfunction by using old data several things have ---- +---- to be taken into account: ---- +---- 1. Operations manipulating the system registers must wait ---- +---- in the end of the operation until the ALU has updated ---- +---- the condition codes. These operations are ANDI_TO_SR, ---- +---- EORI_TO_SR, ORI_TO_SR, MOVE_TO_SR and MOVEC. ---- +---- 2. Operations using the staus register must not start until ---- +---- the ALU has updated the condition codes. These operations ---- +---- are MOVE_FROM_CCR, MOVE_FROM_SR and MOVEC. ---- +---- 3. Operations using the stack pointer must not start until ---- +---- the stack pointer is updated by the previous operation. ---- +---- Operations using the stack pointer are RTD, RTR, RTS, ---- +---- MOVEC, MOVE_USP and UNLK. ---- +---- 4. Operations manipulating the stack pointer without using ---- +---- the ALU must not start until the stack is written by the ---- +---- previous operation. Stack pointer manipulating operations ---- +---- are BSR, JSR, LINK and PEA. ---- +------------------------------------------------------------------------ +---- ---- +---- Remarks: ---- +---- ---- +---- Author(s): ---- +---- - Wolfgang Foerster, wf@experiment-s.de; wf@inventronik.de ---- +---- ---- +------------------------------------------------------------------------ +---- ---- +---- Copyright © 2014-2019 Wolfgang Foerster Inventronik GmbH. ---- +---- ---- +---- This documentation describes Open Hardware and is licensed ---- +---- under the CERN OHL v. 1.2. You may redistribute and modify ---- +---- this documentation under the terms of the CERN OHL v.1.2. ---- +---- (http://ohwr.org/cernohl). This documentation is distributed ---- +---- WITHOUT ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING OF ---- +---- MERCHANTABILITY, SATISFACTORY QUALITY AND FITNESS FOR A ---- +---- PARTICULAR PURPOSE. Please see the CERN OHL v.1.2 for ---- +---- applicable conditions ---- +---- ---- +------------------------------------------------------------------------ +-- +-- Revision History +-- +-- Revision 2K14B 20141201 WF +-- Initial Release. +-- Revision 2K16A 20160620 WF +-- Fixed a bug in the MOVEM operation. +-- Revision 2K18A (unreleased) WF +-- Fixed a bug in MOVE An,-(Ay). Thanks to Gary Bingham for the support. +-- Fixed wrong PEA behaviour. +-- Fixed the displacement for LINK. +-- Fixed AR_MARK_USED in LINK. +-- Fixed the operation size for MOVEQ. +-- ADDQ, SUBQ Fix: address registers are always written long. +-- ADDI, ANDI, EORI, ORI, SUBI: address is not marked used if destination is Dn. +-- ADDI, ANDI, EORI, ORI, SUBI: data register is marked used if destination is Dn. +-- EXG: rearranged logic to meet the new top level multiplexers. +-- LINK, UNLK: wait in START_OP until the ALU is ready (avoids possible data hazards). +-- LINK, UNLK: fixed the write back operation size. +-- MOVEM: Fixed predecrement mode for consecutive MOVEM -(An). +-- MOVEP: MOVEP_PNTR is now correct for consecutive MOVEP. +-- MOVEP: avoid structural hazard in SWITCH_STATE by waiting for ALU. +-- EOR: fixed a bug in the writeback mechanism. +-- BSR, JSR: EXEC_WB state machine waits now for ALU_INIT. Avoid structural / data hazard. +-- The instruction pipe is not flushed for ANDI_TO_CCR, EORI_TO_CCR, ORI_TO_CCR. +-- The instruction pipe is not flushed for MOVE_FROM_CCR, MOVE_TO_CCR, MOVE_FROM_SR, MOVE_USP, MOVEC. +-- Modifications in the FETCH state machine to avoid several data hazards for MOVEM, MOVE_FROM_CCR, MOVE_FROM_SR. +-- Modifications in the FETCH state machine to avoid several data hazards for ANDI_TO_CCR, ANDI_TO_SR, EORI_TO_CCR, EORI_TO_SR, ORI_TO_CCR, ORI_TO_SR. +-- We have to stop a pending operation in case of a pending interrupt. This is done by rejecting OW_RDY. +-- TOP, CONTROL, Exception Handler Opcode Decoder: Rearranged PC_INC and ipipe flush logic. +-- Write the undecremented Register for MOVE Ax, -(Ax). +-- LINK A7 and PEA(A7) stacks the undecremented A7. +-- Control: LINK A7 and PEA(A7) stacks the undecremented A7. +-- Bus interface: Rearranged the DATA_RDY vs. BUS_FLT logic. +-- UNMARK is now asserted in the end of the write cycle. This avoids data hazards. +-- Fixed a MOVEC writeback issue (use BIW_WB... instead of BIW_...). +-- Fixed a USP writeback issue (use BIW_WB... instead of BIW_...). +-- Introduced a switch NO_PIPELINE. +-- MOVEM-Fix: the effective address in memory to register is stored (STORE_AEFF) not to be overwritten in case the addressing register is also loaded. +-- DBcc: fixed a data hazard for DBcc_COND evaluation by waiting on the ALU result. +-- Fixed DR_WR_1 locking against AR_WR_2. +-- IPIPE is flushed, when there is a memory space change in the end of xx_TO_SR operations. +-- To handle correct addressing, ADR_OFFSET is now cleared right in the end of the respective operation. +-- Fixed a bug in EOR writing back in register direct mode. +-- ADDQ and SUBQ: fixed (An)+ mode. An increments now. +-- Fixed DIVS, DIVU in memory address modes (wrong control flow). +-- ADDQ and SUBQ: fixed condition code control UPDT_CC. +-- Fixed a data hazard bug using addressing modes with index register. +-- Implemented the 68K10 loop mechanism. +-- Fixed several pipelinig issues (hazards). +-- Revision 2K19A 20190419 WF +-- Introdeced a new state CALC_AEFF which results in no need of ADR_ATN and a twice highre fmax. +-- Revision 2K19B 20191224 WF +-- NOP explicitely synchronizes the instruction pipe now. +-- The controller must be BUSY when an opword is loaded and we have to wait in START_OP (avoids other controllers to reload the opword, see OW_REQ). +-- Control: BUSY is now asserted when an opword is loaded and we have to wait in START_OP (avoids other controllers to reload the opword, see OW_REQ). +-- Removed a data hazard condition (A7) for JSR, PEA, LINK and UNLK in the beginning of the operation. +-- + +use work.WF68K30L_PKG.all; + +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_unsigned.all; +use ieee.numeric_std.all; + +entity WF68K30L_CONTROL is + generic(NO_PIPELINE : boolean := false); -- If true the controller work in scalar mode. + port ( + CLK : in std_logic; -- System clock. + RESET_CPU : in bit; -- CPU reset. + + BUSY : out bit; -- Main controller finished an execution. + BUSY_EXH : in bit; + EXH_REQ : in bit; + INT_TRIG : out bit; + + OW_REQ : out bit; -- Operation words request. + OW_VALID : in std_logic; -- Operation words is valid. + EW_REQ : out bit; -- Extension word request. + EW_ACK : in bit; -- Extension word available. + OPD_ACK : in bit; -- Opcode has new data. + + ADR_MARK_USED : out bit; + ADR_IN_USE : in bit; + ADR_OFFSET : out std_logic_vector(5 downto 0); + + DATA_RD : out bit; + DATA_WR : out bit; + DATA_RDY : in bit; + DATA_VALID : in std_logic; + RMC : out bit; + + FETCH_MEM_ADR : out bit; + LOAD_OP1 : out bit; + LOAD_OP2 : out bit; + LOAD_OP3 : out bit; + STORE_ADR_FORMAT : out bit; + STORE_D16 : out bit; + STORE_D32_LO : out bit; + STORE_D32_HI : out bit; + STORE_DISPL : out bit; + STORE_OD_HI : out bit; + STORE_OD_LO : out bit; + STORE_ABS_HI : out bit; + STORE_ABS_LO : out bit; + STORE_IDATA_B2 : out bit; + STORE_IDATA_B1 : out bit; + STORE_MEM_ADR : out bit; + STORE_AEFF : out bit; + + -- System control signals: + OP : in OP_68K; + OP_SIZE : out OP_SIZETYPE; + BIW_0 : in std_logic_vector(13 downto 0); + BIW_1 : in std_logic_vector(15 downto 0); + BIW_2 : in std_logic_vector(15 downto 0); + EXT_WORD : in std_logic_vector(15 downto 0); + + ADR_MODE : out std_logic_vector(2 downto 0); + AMODE_SEL : out std_logic_vector(2 downto 0); + USE_DREG : out bit; + HILOn : out bit; + + OP_WB : out OP_68K; + OP_SIZE_WB : out OP_SIZETYPE; + BIW_0_WB_73 : out std_logic_vector(7 downto 3); -- Used for EXG. + + AR_MARK_USED : out bit; + USE_APAIR : out boolean; + AR_IN_USE : in bit; + AR_SEL_RD_1 : out std_logic_vector(2 downto 0); + AR_SEL_RD_2 : out std_logic_vector(2 downto 0); + AR_SEL_WR_1 : out std_logic_vector(2 downto 0); + AR_SEL_WR_2 : out std_logic_vector(2 downto 0); + AR_INC : out bit; + AR_DEC : out bit; + AR_WR_1 : out bit; + AR_WR_2 : out bit; + + DR_MARK_USED : out bit; + USE_DPAIR : out boolean; + DR_IN_USE : in bit; + DR_SEL_WR_1 : out std_logic_vector(2 downto 0); + DR_SEL_WR_2 : out std_logic_vector(2 downto 0); + DR_SEL_RD_1 : out std_logic_vector(2 downto 0); + DR_SEL_RD_2 : out std_logic_vector(2 downto 0); + DR_WR_1 : out bit; + DR_WR_2 : out bit; + + UNMARK : out bit; + + DISPLACEMENT : out std_logic_vector(31 downto 0); + PC_ADD_DISPL : out bit; + PC_LOAD : out bit; + PC_INC_EXH : in bit; + + SP_ADD_DISPL : out bit; + + DFC_WR : out bit; + DFC_RD : out bit; + SFC_WR : out bit; + SFC_RD : out bit; + + VBR_WR : out bit; + VBR_RD : out bit; + + ISP_RD : out bit; + ISP_WR : out bit; + MSP_RD : out bit; + MSP_WR : out bit; + USP_RD : out bit; + USP_WR : out bit; + + IPIPE_FLUSH : out bit; -- Abandon the instruction pipeline. + + ALU_INIT : out bit; + ALU_BSY : in bit; + ALU_REQ : in bit; + ALU_ACK : out bit; + + BKPT_CYCLE : out bit; + BKPT_INSERT : out bit; + + LOOP_BSY : in bit; + LOOP_SPLIT : out boolean; + LOOP_EXIT : out bit; + + BF_OFFSET : in Std_Logic_Vector(2 downto 0); + BF_WIDTH : in Std_Logic_Vector(5 downto 0); + + SR_WR : out bit; + MOVEM_ADn : out bit; + MOVEP_PNTR : out integer range 0 to 3; + CC_UPDT : out bit; + TRACE_MODE : in std_logic_vector(1 downto 0); + VBIT : in std_logic; + ALU_COND : in boolean; + DBcc_COND : in boolean; + BRANCH_ATN : in bit; + RESET_STRB : out bit; + BERR : out bit; + STATUSn : out bit; + EX_TRACE : out bit; + TRAP_cc : out bit; + TRAP_ILLEGAL : out bit; -- Used for BKPT. + TRAP_V : out bit + ); +end entity WF68K30L_CONTROL; + +architecture BEHAVIOUR of WF68K30L_CONTROL is +type BF_BYTEMATRIX is array (0 to 7, 1 to 32) of integer range 1 to 5; +-- The BF_BYTES constant selects the number of bytes required for read +-- or write during the bit field operations. This table is valid for +-- positive and negative offsets when using the twos complement in +-- the offset field. +constant BF_BYTES_I : BF_BYTEMATRIX := + ((1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4), + (1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,5), + (1,1,1,1,1,1,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,5,5), + (1,1,1,1,1,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5), + (1,1,1,1,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5), + (1,1,1,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5), + (1,1,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5), + (1,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5)); +-- +type FETCH_STATES is (START_OP, CALC_AEFF, FETCH_DISPL, FETCH_EXWORD_1, FETCH_D_LO, FETCH_D_HI, FETCH_OD_HI, FETCH_OD_LO, FETCH_ABS_HI, + FETCH_ABS_LO, FETCH_IDATA_B2, FETCH_IDATA_B1, FETCH_MEMADR, FETCH_OPERAND, INIT_EXEC_WB, SLEEP, SWITCH_STATE); +type EXEC_WB_STATES is (IDLE, EXECUTE, ADR_PIPELINE, WRITEBACK, WRITE_DEST); +signal FETCH_STATE : FETCH_STATES; +signal NEXT_FETCH_STATE : FETCH_STATES; +signal EXEC_WB_STATE : EXEC_WB_STATES; +signal NEXT_EXEC_WB_STATE : EXEC_WB_STATES; +signal ADR_MARK_USED_I : bit; +signal ADR_MODE_I : std_logic_vector(2 downto 0); +signal ALU_INIT_I : bit; +signal ALU_TRIG : bit; +signal AR_DEC_I : bit; +signal AR_WR_I : bit; +signal AR_WR_II : bit; +signal BF_BYTES : integer range 0 to 5; +signal BF_HILOn : bit; +signal BF_OFFSET_I : integer range 0 to 7; +signal BF_WIDTH_I : integer range 1 to 32; +signal BIW_0_WB : std_logic_vector(11 downto 0); +signal BIW_1_WB : std_logic_vector(15 downto 0); +signal DATA_RD_I : bit; +signal DATA_WR_I : bit; +signal EW_RDY : bit; +signal INIT_ENTRY : bit; +signal IPIPE_FLUSH_I : bit; +signal LOOP_EXIT_I : bit; +signal MEM_INDIRECT : bit; +signal MEMADR_RDY : bit; +signal MOVEM_ADn_I : bit; +signal MOVEM_ADn_WB : bit; +signal MOVEM_COND : boolean; +signal MOVEM_FIRST_RD : boolean; +signal MOVEM_INH_WR : boolean; +signal MOVEM_LAST_WR : boolean; +signal MOVEM_PNTR : std_logic_vector(3 downto 0); +signal MOVEP_PNTR_I : integer range 0 to 3; +signal OD_REQ_16 : std_logic; +signal OD_REQ_32 : std_logic; +signal OP_SIZE_I : OP_SIZETYPE; +signal OP_WB_I : OP_68K := UNIMPLEMENTED; +signal OW_RDY : bit; +signal PC_ADD_DISPL_I : bit; +signal PC_LOAD_I : bit; +signal PHASE2 : boolean; +signal RD_RDY : bit; +signal READ_CYCLE : bit; +signal SBIT_I : bit; +signal SR_WR_I : bit; +signal UPDT_CC : bit; +signal WR_RDY : bit; +signal WRITE_CYCLE : bit; +-- Debugging: +signal OP_TEST : bit; +begin + BUSY <= '1' when OPD_ACK = '1' else -- Early indication. + '1' when OW_RDY = '1' and OP /= ILLEGAL and OP /= RTE and OP /= TRAP and OP /= UNIMPLEMENTED else -- In progress MAIN is now busy. + '1' when LOOP_BSY = '1' else -- Finish the DBcc loop. + '1' when ALU_BSY = '1' else -- Busy, wait. + '1' when FETCH_STATE /= START_OP else '0'; -- Main controller is busy. + + -- The interrupt must not be activated when the controller is in its START_OP + -- state and fetches new OPWORDS. so we define the trigger for the interrupt + -- in the end of the FETCH phase. The SLEEP state is important for STOP. + INT_TRIG <= '1' when FETCH_STATE = INIT_EXEC_WB or FETCH_STATE = SLEEP else '0'; + + OW_REQ <= '0' when BUSY_EXH = '1' else + '0' when EXH_REQ = '1' and LOOP_BSY = '0' else -- Non interrupt exception requests, loop has priority. + '0' when OPD_ACK = '1' or OW_RDY = '1' else + '1' when NO_PIPELINE = true and FETCH_STATE = START_OP and ALU_BSY = '0' else + '1' when NO_PIPELINE = false and FETCH_STATE = START_OP else '0'; + + DATA_AVAILABLE: process + -- These flip flops store the information whether the data required in the different + -- states is available or not. This is necessary in case of delayed cycles for + -- example if the required address register is not ready to be read. + begin + wait until CLK = '1' and CLK' event; + if RESET_CPU = '1' then + OW_RDY <= '0'; + elsif FETCH_STATE = START_OP and NEXT_FETCH_STATE /= START_OP then + OW_RDY <= '0'; -- Reset. + elsif FETCH_STATE = START_OP and (OP = ILLEGAL or OP = RTE or OP = TRAP or OP = UNIMPLEMENTED) and BUSY_EXH = '1' then + OW_RDY <= '0'; -- Done. + elsif OPD_ACK = '1' then + OW_RDY <= '1'; -- Set. + end if; + + if FETCH_STATE = START_OP then + EW_RDY <= '0'; + elsif FETCH_STATE = FETCH_DISPL and NEXT_FETCH_STATE /= FETCH_DISPL then + EW_RDY <= '0'; + elsif FETCH_STATE = FETCH_EXWORD_1 and NEXT_FETCH_STATE /= FETCH_EXWORD_1 then + EW_RDY <= '0'; + elsif FETCH_STATE = FETCH_D_LO and NEXT_FETCH_STATE /= FETCH_D_LO then + EW_RDY <= '0'; + elsif FETCH_STATE = FETCH_IDATA_B1 and NEXT_FETCH_STATE /= FETCH_IDATA_B1 then + EW_RDY <= '0'; + elsif (FETCH_STATE = FETCH_DISPL or FETCH_STATE = FETCH_EXWORD_1 or FETCH_STATE = FETCH_IDATA_B1 or FETCH_STATE = FETCH_D_LO) and EW_ACK = '1' then + EW_RDY <= '1'; + end if; + + if FETCH_STATE = START_OP then + MEMADR_RDY <= '0'; + elsif FETCH_STATE = FETCH_MEMADR and NEXT_FETCH_STATE /= FETCH_MEMADR then + MEMADR_RDY <= '0'; + elsif FETCH_STATE = FETCH_MEMADR and DATA_RDY = '1' then + MEMADR_RDY <= '1'; + end if; + end process DATA_AVAILABLE; + + EW_REQ <= '0' when EW_ACK = '1' or EW_RDY = '1' else + '1' when FETCH_STATE = FETCH_DISPL or FETCH_STATE = FETCH_EXWORD_1 else + '1' when FETCH_STATE = FETCH_D_HI or FETCH_STATE = FETCH_D_LO else + '1' when FETCH_STATE = FETCH_OD_HI or FETCH_STATE = FETCH_OD_LO else + '1' when FETCH_STATE = FETCH_ABS_HI or FETCH_STATE = FETCH_ABS_LO else + '1' when FETCH_STATE = FETCH_IDATA_B2 or FETCH_STATE = FETCH_IDATA_B1 else + '1' when FETCH_STATE /= FETCH_DISPL and NEXT_FETCH_STATE = FETCH_DISPL else + '1' when FETCH_STATE /= FETCH_EXWORD_1 and NEXT_FETCH_STATE = FETCH_EXWORD_1 else + '1' when FETCH_STATE /= FETCH_D_HI and NEXT_FETCH_STATE = FETCH_D_HI else + '1' when FETCH_STATE /= FETCH_D_LO and NEXT_FETCH_STATE = FETCH_D_LO else + '1' when FETCH_STATE /= FETCH_OD_HI and NEXT_FETCH_STATE = FETCH_OD_HI else + '1' when FETCH_STATE /= FETCH_OD_LO and NEXT_FETCH_STATE = FETCH_OD_LO else + '1' when FETCH_STATE /= FETCH_ABS_HI and NEXT_FETCH_STATE = FETCH_ABS_HI else + '1' when FETCH_STATE /= FETCH_ABS_LO and NEXT_FETCH_STATE = FETCH_ABS_LO else + '1' when FETCH_STATE /= FETCH_IDATA_B2 and NEXT_FETCH_STATE = FETCH_IDATA_B2 else + '1' when FETCH_STATE /= FETCH_IDATA_B1 and NEXT_FETCH_STATE = FETCH_IDATA_B1 else '0'; + + CYCLECONTROL: process + -- This process contros the read and write signals, if + -- asserted simultaneously. In this way, a read cycle is + -- not interrupted by a write cycle and vice versa. + begin + wait until CLK = '1' and CLK' event; + if DATA_RDY = '1' then + WRITE_CYCLE <= '0'; + READ_CYCLE <= '0'; + elsif DATA_WR_I = '1' then + WRITE_CYCLE <= '1'; + READ_CYCLE <= '0'; + elsif DATA_RD_I = '1' then + READ_CYCLE <= '1'; + WRITE_CYCLE <= '0'; + end if; + end process CYCLECONTROL; + + RD_RDY <= DATA_RDY when READ_CYCLE = '1' else '0'; + WR_RDY <= DATA_RDY when WRITE_CYCLE = '1' else '0'; + + INIT_ENTRY <= '1' when FETCH_STATE /= INIT_EXEC_WB and NEXT_FETCH_STATE = INIT_EXEC_WB else '0'; + + DATA_RD <= DATA_RD_I; + DATA_RD_I <= '0' when DATA_WR_I = '1' and READ_CYCLE = '0' and WRITE_CYCLE = '0' else -- Write is prioritized. + '0' when WRITE_CYCLE = '1' else -- Do not read during a write cycle. + '0' when ADR_IN_USE = '1' else -- Avoid data hazards. + '0' when DATA_RDY = '1' or MEMADR_RDY = '1' else + '1' when FETCH_STATE = FETCH_MEMADR else + '1' when FETCH_STATE = FETCH_OPERAND else '0'; + + DATA_WR <= DATA_WR_I; + DATA_WR_I <= '0' when READ_CYCLE = '1' else -- Do not write during a read cycle. + '0' when DATA_RDY = '1' else + '1' when EXEC_WB_STATE = WRITE_DEST else '0'; + + RMC <= '1' when (OP = CAS or OP = CAS2 or OP = TAS) and FETCH_STATE /= START_OP else '0'; + + ALU_ACK <= '1' when EXEC_WB_STATE = EXECUTE and NEXT_EXEC_WB_STATE = IDLE else + '1' when EXEC_WB_STATE = WRITEBACK else + '0' when (OP_WB_I = BFCHG or OP_WB_I = BFCLR) and EXEC_WB_STATE = WRITE_DEST and BF_BYTES = 5 else + '0' when (OP_WB_I = BFINS or OP_WB_I = BFSET) and EXEC_WB_STATE = WRITE_DEST and BF_BYTES = 5 else + '1' when EXEC_WB_STATE = WRITE_DEST and WR_RDY = '1' else '0'; + + FETCH_MEM_ADR <= '1' when FETCH_STATE = FETCH_MEMADR else '0'; + STORE_MEM_ADR <= '1' when FETCH_STATE = FETCH_MEMADR and RD_RDY = '1' and DATA_VALID = '1' else '0'; + + -- Store the extension word right in the end due to used data and/or address registers. + STORE_ADR_FORMAT <= '1' when FETCH_STATE = FETCH_EXWORD_1 and NEXT_FETCH_STATE /= FETCH_EXWORD_1 else '0'; + + STORE_D16 <= '1' when FETCH_STATE = FETCH_DISPL and EW_ACK = '1' else '0'; + STORE_D32_LO <= '1' when FETCH_STATE = FETCH_D_LO and EW_ACK = '1' else '0'; + STORE_D32_HI <= '1' when FETCH_STATE = FETCH_D_HI and EW_ACK = '1' else '0'; + + STORE_DISPL <= '1' when OP = MOVEP and FETCH_STATE = START_OP and NEXT_FETCH_STATE /= START_OP and BIW_0(7 downto 6) < "10" else -- Memory to register. + '1' when OP = MOVEP and FETCH_STATE = SWITCH_STATE else '0'; -- Register to memory. + + STORE_OD_HI <= '1' when FETCH_STATE = FETCH_OD_HI and EW_ACK = '1' else '0'; + STORE_OD_LO <= '1' when FETCH_STATE = FETCH_OD_LO and EW_ACK = '1' else '0'; + + STORE_ABS_HI <= '1' when FETCH_STATE = FETCH_ABS_HI and EW_ACK = '1' else '0'; + STORE_ABS_LO <= '1' when FETCH_STATE = FETCH_ABS_LO and EW_ACK = '1' else '0'; + + STORE_IDATA_B2 <= '1' when FETCH_STATE = FETCH_IDATA_B2 and EW_ACK = '1' else '0'; + STORE_IDATA_B1 <= '1' when FETCH_STATE = FETCH_IDATA_B1 and EW_ACK = '1' else '0'; + + LOAD_OP1 <= '1' when OP = BFINS and INIT_ENTRY = '1' else -- Load insertion pattern. + '1' when (OP = CHK2 or OP = CMP2) and FETCH_STATE = FETCH_OPERAND and RD_RDY = '1' and DATA_VALID = '1' and PHASE2 = false else + '1' when OP = CMPM and FETCH_STATE = FETCH_OPERAND and RD_RDY = '1' and DATA_VALID = '1' and PHASE2 = true else + '1' when OP = MOVE and BIW_0(8 downto 6) = "100" and BIW_0(5 downto 3) = "001" and BIW_0(11 downto 9) = BIW_0(2 downto 0) and INIT_ENTRY = '1' else -- Load early to write the undecremented Register for Ax, -(Ax). + '1' when OP = MOVES and FETCH_STATE = START_OP and NEXT_FETCH_STATE /= START_OP and ADR_MODE_I = "100" and BIW_1(15) = '1' and BIW_1(11) = '1' and BIW_1(14 downto 12) = BIW_0(2 downto 0) else -- Load the adressing register before decrementing. + '1' when OP = PEA and FETCH_STATE = SWITCH_STATE and PHASE2 = true else -- Load early not to stack the decremented value. + '0' when OP = BFINS or OP = CHK2 or OP = CMP2 or OP = CMPM or OP = PEA else + '0' when OP = MOVE and BIW_0(8 downto 6) = "100" and BIW_0(5 downto 3) = "001" and BIW_0(11 downto 9) = BIW_0(2 downto 0) else + '0' when OP = MOVES and ADR_MODE_I = "100" and BIW_1(15) = '1' and BIW_1(11) = '1' and BIW_1(14 downto 12) = BIW_0(2 downto 0) else -- Do not load the decremented addressing register. + '0' when OP = PEA and ADR_MODE_I = "001" and BIW_0(2 downto 0) = "111" else + '1' when ALU_INIT_I = '1' else '0'; + + LOAD_OP2 <= '1' when (OP = ABCD or OP = SBCD) and FETCH_STATE = FETCH_OPERAND and RD_RDY = '1' and DATA_VALID = '1' and PHASE2 = false else + '1' when (OP = ADDX or OP = SUBX) and FETCH_STATE = FETCH_OPERAND and RD_RDY = '1' and DATA_VALID = '1' and PHASE2 = false else + '1' when (OP = ABCD or OP = SBCD) and FETCH_STATE = INIT_EXEC_WB and BIW_0(3) = '0' else -- Register direct. + '1' when (OP = ADDX or OP = SUBX) and FETCH_STATE = INIT_EXEC_WB and BIW_0(3) = '0' else -- Register direct. + '1' when (OP = BFCHG or OP = BFCLR) and FETCH_STATE = FETCH_OPERAND and RD_RDY = '1' and DATA_VALID = '1' and BF_HILOn = '0' else + '1' when (OP = BFINS or OP = BFSET) and FETCH_STATE = FETCH_OPERAND and RD_RDY = '1' and DATA_VALID = '1' and BF_HILOn = '0' else + '1' when (OP = BFEXTS or OP = BFEXTU) and FETCH_STATE = FETCH_OPERAND and RD_RDY = '1' and DATA_VALID = '1' and BF_HILOn = '0' else + '1' when (OP = BFFFO or OP = BFTST) and FETCH_STATE = FETCH_OPERAND and RD_RDY = '1' and DATA_VALID = '1' and BF_HILOn = '0' else + '1' when OP = CMPM and FETCH_STATE = FETCH_OPERAND and RD_RDY = '1' and DATA_VALID = '1' and PHASE2 = false else + '1' when OP = LINK and BIW_0(2 downto 0) = "111" and FETCH_STATE = START_OP and NEXT_FETCH_STATE /= START_OP else -- Load early not to stack the decremented address register. + '0' when OP = ABCD or OP = SBCD or OP = ADDX or OP = SUBX or OP = CMPM else + '0' when OP = BFCHG or OP = BFCLR or OP = BFEXTS or OP = BFEXTU or OP = BFFFO or OP = BFINS or OP = BFSET or OP = BFTST else + '0' when OP = LINK and BIW_0(2 downto 0) = "111" else + '1' when INIT_ENTRY = '1' else '0'; + + LOAD_OP3 <= '1' when (OP = BFCHG or OP = BFCLR or OP = BFINS or OP = BFSET) and BIW_0(5 downto 3) = "000" and INIT_ENTRY = '1' else + '1' when (OP = BFEXTS or OP = BFEXTU or OP = BFFFO or OP = BFTST) and BIW_0(5 downto 3) = "000" and INIT_ENTRY = '1' else + '1' when (OP = BFCHG or OP = BFCLR) and FETCH_STATE = FETCH_OPERAND and RD_RDY = '1' and DATA_VALID = '1' and BF_HILOn = '1' else + '1' when (OP = BFINS or OP = BSET) and FETCH_STATE = FETCH_OPERAND and RD_RDY = '1' and DATA_VALID = '1' and BF_HILOn = '1' else + '1' when (OP = BFEXTS or OP = BFEXTU) and FETCH_STATE = FETCH_OPERAND and RD_RDY = '1' and DATA_VALID = '1' and BF_HILOn = '1' else + '1' when (OP = BFFFO or OP = BFTST) and FETCH_STATE = FETCH_OPERAND and RD_RDY = '1' and DATA_VALID = '1' and BF_HILOn = '1' else + '1' when OP = CAS2 and INIT_ENTRY = '1' and PHASE2 = false else -- Memory operand 2. + '1' when (OP = CHK2 or OP = CMP2) and FETCH_STATE = FETCH_OPERAND and RD_RDY = '1' and DATA_VALID = '1' and PHASE2 = true else + '1' when (OP = DIVS or OP = DIVU) and OP_SIZE_I = LONG and BIW_1(10) = '1' and INIT_ENTRY = '1' else '0'; -- 64 bit operand. + + SR_WR <= SR_WR_I; + SR_WR_I <= '1' when (OP_WB_I = ANDI_TO_SR or OP_WB_I = EORI_TO_SR or OP_WB_I = ORI_TO_SR) and EXEC_WB_STATE = WRITEBACK else + '1' when (OP_WB_I = MOVE_TO_CCR or OP_WB_I = MOVE_TO_SR) and EXEC_WB_STATE = WRITEBACK else + '1' when OP_WB_I = STOP and EXEC_WB_STATE = WRITEBACK else '0'; + + HILOn <= '1' when OP_WB_I = CAS2 and FETCH_STATE = FETCH_OPERAND and PHASE2 = false else + '1' when OP_WB_I = CAS2 and EXEC_WB_STATE = WRITEBACK and PHASE2 = false else + '0' when OP = CAS2 else BF_HILOn; -- Select destinations. + + -- Addressing mode: + ADR_MODE <= ADR_MODE_I; + ADR_MODE_I <= "010" when OP = BSR or OP = CAS2 or OP = LINK or OP = UNLK else -- (An), (Dn). + "010" when OP = RTD or OP = RTR or OP = RTS else -- (An). + "011" when OP = CMPM else -- (An)+ + "100" when OP = ABCD or OP = SBCD else -- -(An). + "100" when OP = ADDX or OP = SUBX else -- -(An). + "100" when OP = PACK or OP = UNPK else -- -(An). + "101" when OP = MOVEP else -- (d16, An). + -- The following two conditions change the address mode right in the end of the fetch phase. + "010" when (OP = JSR or OP = PEA) and FETCH_STATE = INIT_EXEC_WB and ALU_BSY = '0' else -- (A7). + BIW_0(8 downto 6) when OP = MOVE and FETCH_STATE = INIT_EXEC_WB and ALU_BSY = '0' else + BIW_0(8 downto 6) when OP = MOVE and PHASE2 = true else + BIW_0(5 downto 3); + + -- This is the selector for the address mode "111". + AMODE_SEL <= BIW_0(11 downto 9) when OP = MOVE and (NEXT_FETCH_STATE = INIT_EXEC_WB or FETCH_STATE = INIT_EXEC_WB) else + BIW_0(11 downto 9) when OP = MOVE and PHASE2 = true else BIW_0(2 downto 0); + + -- Used for the addressing modes and as source selector. + -- In case of the addressing modes, the selector mus be valid one clock cycle before the bus cycle + -- starts due to the pipeline stage for ADR_REG in the address register section. + AR_SEL_RD_1 <= BIW_0(11 downto 9) when (OP = ABCD or OP = SBCD) and FETCH_STATE = START_OP else + BIW_0(11 downto 9) when (OP = ABCD or OP = SBCD) and FETCH_STATE = CALC_AEFF and PHASE2 = false else + BIW_0(11 downto 9) when (OP = ABCD or OP = SBCD) and FETCH_STATE = FETCH_OPERAND and PHASE2 = false and RD_RDY = '0' else -- Destination first. + BIW_0(11 downto 9) when (OP = ABCD or OP = SBCD) and FETCH_STATE = INIT_EXEC_WB else + BIW_0(11 downto 9) when (OP = ADDX or OP = SUBX) and FETCH_STATE = START_OP else + BIW_0(11 downto 9) when (OP = ADDX or OP = SUBX) and FETCH_STATE = CALC_AEFF and PHASE2 = false else + BIW_0(11 downto 9) when (OP = ADDX or OP = SUBX) and FETCH_STATE = FETCH_OPERAND and PHASE2 = false and RD_RDY = '0' else -- Destination first. + BIW_0(11 downto 9) when (OP = ADDX or OP = SUBX) and FETCH_STATE = INIT_EXEC_WB else + BIW_0(11 downto 9) when OP = CMPM and FETCH_STATE = FETCH_OPERAND and PHASE2 = false else -- Fetch destination. + BIW_0(11 downto 9) when OP = MOVE and FETCH_STATE = FETCH_MEMADR and PHASE2 = true else + BIW_0(11 downto 9) when OP = MOVE and FETCH_STATE = START_OP and BIW_0(5 downto 3) < "010" and BIW_0(8 downto 6) /= "000" else -- Dn, An. + BIW_0(11 downto 9) when OP = MOVE and FETCH_STATE = CALC_AEFF and PHASE2 = true else + BIW_0(11 downto 9) when OP = MOVE and FETCH_STATE = FETCH_OPERAND and RD_RDY = '1' and BIW_0(8 downto 6) = "100" and BIW_0(5 downto 3) /= "011" else -- All except (An)+,-(An). + BIW_0(11 downto 9) when OP = MOVE and FETCH_STATE = FETCH_IDATA_B1 and BIW_0(8 downto 6) /= "000" else + BIW_0(11 downto 9) when OP = MOVE and FETCH_STATE = FETCH_ABS_LO and BIW_0(8 downto 6) /= "000" and PHASE2 = false else + BIW_0(11 downto 9) when OP = MOVE and FETCH_STATE = SWITCH_STATE and BIW_0(8 downto 6) /= "000" else + BIW_0(11 downto 9) when OP = MOVE and FETCH_STATE = INIT_EXEC_WB and BIW_0(8 downto 6) /= "000" else + BIW_1(14 downto 12) when OP = MOVEC and BIW_0(0) = '1' else -- MOVEC: general register to control register. + "111" when OP = BSR or OP = MOVEC else -- Stack pointers. + BIW_0(11 downto 9) when (OP = PACK or OP = UNPK) and FETCH_STATE = START_OP and BIW_0(3) = '0' and DR_IN_USE = '0' else -- Destination address. + BIW_0(11 downto 9) when (OP = PACK or OP = UNPK) and FETCH_STATE = FETCH_OPERAND and RD_RDY = '1' else -- Destination address. + BIW_0(11 downto 9) when (OP = PACK or OP = UNPK) and FETCH_STATE = INIT_EXEC_WB else -- Destination address. + BIW_1(14 downto 12) when OP = CAS2 and FETCH_STATE = START_OP else -- Address operand. + BIW_1(14 downto 12) when OP = CAS2 and FETCH_STATE = FETCH_OPERAND and PHASE2 = false else -- Address operand. + BIW_2(14 downto 12) when OP = CAS2 and FETCH_STATE = CALC_AEFF else -- Address operand. + BIW_2(14 downto 12) when OP = CAS2 and FETCH_STATE = FETCH_OPERAND else -- Address operand. + BIW_1(14 downto 12) when OP_WB_I = CAS2 and (EXEC_WB_STATE = EXECUTE or EXEC_WB_STATE = ADR_PIPELINE) else -- Address operand. + BIW_2(14 downto 12) when OP_WB_I = CAS2 and EXEC_WB_STATE = WRITE_DEST else -- Address operand. + "111" when (OP = JSR or OP = LINK) and FETCH_STATE = START_OP else -- Select the SP to decrement. + "111" when OP = PEA and FETCH_STATE = SWITCH_STATE and PHASE2 = true else -- Select the SP to decrement. + "111" when (OP = JSR or OP = LINK or OP = PEA) and FETCH_STATE = INIT_EXEC_WB else -- Writeback address is the SP. + "111" when OP = RTD or OP = RTR or OP = RTS else -- Stack pointer. + "111" when OP = UNLK and (FETCH_STATE = START_OP or FETCH_STATE = CALC_AEFF or FETCH_STATE = FETCH_OPERAND) else -- Check in START_OP to avoid dataz hazards! + BIW_0(2 downto 0) when OP = ABCD or OP = ADD or OP = ADDA or OP = ADDI or OP = ADDQ or OP = ADDX or OP = AND_B or OP = ANDI else + BIW_0(2 downto 0) when OP = ASL or OP = ASR or OP = BCHG or OP = BCLR or OP = BSET or OP = BTST or OP = BFCHG or OP = BFCLR else + BIW_0(2 downto 0) when OP = BFEXTS or OP = BFEXTU or OP = BFFFO or OP = BFINS or OP = BFSET or OP = BFTST else + BIW_0(2 downto 0) when OP = CAS or OP = CHK or OP = CHK2 or OP = CLR or OP = CMP or OP = CMPA or OP = CMPI or OP = CMPM or OP = CMP2 else + BIW_0(2 downto 0) when OP = DIVS or OP = DIVU or OP = EOR or OP = EORI or OP = EXG or OP = JMP or OP = JSR or OP = LEA or OP = LINK or OP = LSL or OP = LSR else + BIW_0(2 downto 0) when OP = MOVE or OP = MOVEA or OP = MOVE_FROM_CCR or OP = MOVE_FROM_SR or OP = MOVE_TO_CCR or OP = MOVE_TO_SR else + BIW_0(2 downto 0) when OP = MOVE_USP or OP = MOVEM or OP = MOVEP or OP = MOVES or OP = MULS or OP = MULU else + BIW_0(2 downto 0) when OP = NBCD or OP = NEG or OP = NEGX or OP = NOT_B or OP = OR_B or OP = ORI or OP = PACK or OP = PEA else + BIW_0(2 downto 0) when OP = ROTL or OP = ROTR or OP = ROXL or OP = ROXR or OP = SBCD or OP = Scc or OP = SUB or OP = SUBA else + BIW_0(2 downto 0) when OP = SUBI or OP = SUBQ or OP = SUBX or OP = TAS or OP = TST or OP = UNLK or OP = UNPK else "000"; + + -- Always the destination. + AR_SEL_WR_1 <= BIW_0(2 downto 0) when OP = ADDQ or OP = SUBQ else + BIW_0(2 downto 0) when OP = EXG and BIW_0(7 downto 3) = "10001" else -- Data and Address register. + BIW_1(14 downto 12) when OP = MOVEC or OP = MOVES else + "111" when OP = UNLK and FETCH_STATE = START_OP else + BIW_0(2 downto 0) when OP = LINK else + MOVEM_PNTR(2 downto 0) when OP = MOVEM else + BIW_0(2 downto 0) when OP = MOVE_USP else + BIW_0(11 downto 9); -- ADDA, EXG, LEA, MOVE, MOVEA, SUBA. + + AR_WR_1 <= AR_WR_I; + AR_WR_I <= '1' when OP = LINK and FETCH_STATE = INIT_EXEC_WB and ALU_BSY = '0' else + '1' when OP = UNLK and FETCH_STATE = SWITCH_STATE and NEXT_FETCH_STATE /= SWITCH_STATE else -- Write An to SP. + '0' when EXEC_WB_STATE /= WRITEBACK else + '1' when OP_WB_I = ADDA or OP_WB_I = SUBA else + '1' when (OP_WB_I = ADDQ or OP_WB_I = SUBQ) and BIW_0_WB(5 downto 3) = "001" else + '1' when OP_WB_I = EXG and BIW_0_WB(7 downto 3) = "01001" else -- Two address registers. + '1' when OP_WB_I = EXG and BIW_0_WB(7 downto 3) = "10001" else -- Data and Address register. + '1' when OP_WB_I = LEA else + '1' when OP_WB_I = MOVE_USP and BIW_0_WB(3) = '1' else + '1' when OP_WB_I = MOVEA else + '1' when OP_WB_I = MOVEC and BIW_1_WB(15) = '1' and BIW_0_WB(0) = '0' else -- To general register. + '1' when OP_WB_I = MOVES and BIW_1_WB(15) = '1' else + '1' when OP_WB_I = MOVEM and MOVEM_ADn_WB = '1' else '0'; + + AR_SEL_RD_2 <= BIW_1(14 downto 12) when OP = CHK2 or OP = CMP2 else + MOVEM_PNTR(2 downto 0) when OP = MOVEM else -- This is the non addressing output. + BIW_1(14 downto 12) when OP = MOVES else + BIW_0(2 downto 0) when OP = ADDQ or OP = MOVE or OP = SUBQ or OP = TST else + BIW_0(2 downto 0) when OP = EXG and BIW_0(7 downto 3) = "10001" else -- Data and address register. + BIW_0(11 downto 9) when OP = ADDA or OP = CMPA or OP = EXG or OP = SUBA else "000"; + + AR_SEL_WR_2 <= BIW_0(2 downto 0); -- Used for EXG, UNLK. + + AR_WR_2 <= AR_WR_II; + AR_WR_II <= '1' when OP_WB_I = UNLK and EXEC_WB_STATE = WRITEBACK else -- Write (SP) to An. + '1' when OP_WB_I = EXG and EXEC_WB_STATE = WRITEBACK and BIW_0_WB(7 downto 3) = "01001" else '0'; -- Two address registers. + + AR_INC <= '1' when (OP = ADD or OP = CMP or OP = SUB) and ADR_MODE_I = "011" and ALU_INIT_I = '1' else + '1' when (OP = ADDA or OP = CMPA or OP = SUBA) and ADR_MODE_I = "011" and FETCH_STATE = FETCH_OPERAND and DATA_RDY = '1' else + '1' when (OP = ADDI or OP = CMPI or OP = SUBI) and ADR_MODE_I = "011" and ALU_INIT_I = '1' else + '1' when (OP = ADDQ or OP = SUBQ) and ADR_MODE_I = "011" and ALU_INIT_I = '1' else + '1' when (OP = AND_B or OP = EOR or OP = OR_B) and ADR_MODE_I = "011" and ALU_INIT_I = '1' else + '1' when (OP = ANDI or OP = EORI or OP = ORI) and ADR_MODE_I = "011" and ALU_INIT_I = '1' else + '1' when (OP = ASL or OP = ASR or OP = LSL or OP = LSR) and BIW_0(7 downto 3) = "11011" and ALU_INIT_I = '1' else + '1' when (OP = ROTL or OP = ROTR or OP = ROXL or OP = ROXR) and BIW_0(7 downto 3) = "11011" and ALU_INIT_I = '1' else + '1' when (OP = BCHG or OP = BCLR or OP = BSET or OP = BTST) and ADR_MODE_I = "011" and ALU_INIT_I = '1' else + '1' when (OP = CAS or OP = TAS) and ADR_MODE_I = "011" and FETCH_STATE = INIT_EXEC_WB and NEXT_FETCH_STATE /= INIT_EXEC_WB else + '1' when (OP = CHK or OP = CLR or OP = TST or OP = Scc) and ADR_MODE_I = "011" and ALU_INIT_I = '1' else + '1' when (OP = NBCD or OP = NEG or OP = NEGX or OP = NOT_B) and ADR_MODE_I = "011" and ALU_INIT_I = '1' else + '1' when OP = CMPM and FETCH_STATE = FETCH_OPERAND and RD_RDY = '1' and DATA_VALID = '1' else + '1' when (OP = MULS or OP = MULU or OP = DIVS or OP = DIVU) and ADR_MODE_I = "011" and ALU_INIT_I = '1' else + '1' when (OP = MOVE_FROM_CCR or OP = MOVE_FROM_SR) and ADR_MODE_I = "011" and FETCH_STATE = INIT_EXEC_WB and NEXT_FETCH_STATE /= INIT_EXEC_WB else + '1' when (OP = MOVE_TO_CCR or OP = MOVE_TO_SR) and ADR_MODE_I = "011" and FETCH_STATE = INIT_EXEC_WB and NEXT_FETCH_STATE /= INIT_EXEC_WB else + '1' when OP = MOVE and ADR_MODE_I = "011" and FETCH_STATE = FETCH_OPERAND and NEXT_FETCH_STATE /= FETCH_OPERAND else + '1' when OP = MOVE and BIW_0(8 downto 6) = "011" and FETCH_STATE = INIT_EXEC_WB and NEXT_FETCH_STATE /= INIT_EXEC_WB else + '1' when OP = MOVEA and ADR_MODE_I = "011" and FETCH_STATE = INIT_EXEC_WB and NEXT_FETCH_STATE /= INIT_EXEC_WB else + '1' when OP = MOVEM and ADR_MODE_I = "011" and ALU_INIT_I = '1' else + '1' when OP = MOVES and ADR_MODE_I = "011" and ALU_INIT_I = '1' else + '1' when (OP = UNLK or OP = RTD or OP = RTR or OP = RTS) and FETCH_STATE = FETCH_OPERAND and RD_RDY = '1' and DATA_VALID = '1' else '0'; + + with OP select + AR_DEC_I <= '1' when ABCD | ADD | ADDA | ADDI | ADDQ | ADDX | AND_B | ANDI | ASL | ASR | BCHG | BCLR | BSET | BTST | CHK | CMP | CMPA | CMPI | + DIVS | DIVU | EOR | EORI | LSL | LSR | MOVE | MOVEA | MOVE_TO_CCR | MOVE_TO_SR | MOVES | MULS | MULU | NBCD | NEG | NEGX | + NOT_B | OR_B | ORI | ROTL | ROTR | ROXL | ROXR | SBCD | SUB | SUBA | SUBI | SUBQ | SUBX | TAS | TST, '0' when others; + + AR_DEC <= AR_DEC_I when ADR_MODE_I = "100" and FETCH_STATE /= CALC_AEFF and NEXT_FETCH_STATE = CALC_AEFF else + '1' when (OP = BSR or OP = JSR or OP = LINK) and FETCH_STATE = START_OP and NEXT_FETCH_STATE /= START_OP else + '1' when (OP = CLR or OP = Scc) and ADR_MODE_I = "100" and INIT_ENTRY = '1' else + '1' when OP = MOVE and BIW_0(8 downto 6) = "100" and BIW_0(5 downto 3) /= "011" and INIT_ENTRY = '1' else -- (An)+, -(An) + '1' when OP = MOVE and BIW_0(8 downto 6) = "100" and FETCH_STATE = SWITCH_STATE else -- Needed for source (An)+ mode. + '1' when OP = MOVEM and ADR_MODE_I = "100" and INIT_ENTRY = '1' else -- Decrement before the first bus access. + '1' when OP = MOVEM and ADR_MODE_I = "100" and ALU_INIT_I = '1' and MOVEM_LAST_WR = false else -- After the last bus access the address register is not decremented. + '1' when (OP = MOVE_FROM_CCR or OP = MOVE_FROM_SR) and ADR_MODE_I = "100" and INIT_ENTRY = '1' else + '1' when OP = MOVES and ADR_MODE_I = "100" and BIW_1(11) = '1' and INIT_ENTRY = '1' else + '1' when (OP = PACK or OP = UNPK) and BIW_0(3) = '1' and INIT_ENTRY = '1' else + -- PEA: decrement late in SWITCH_STATE not to decremented address register for PEA (xx,A7,yy) address modi. + '1' when OP = PEA and FETCH_STATE = SWITCH_STATE and PHASE2 = true else '0'; + + DR_SEL_RD_1 <= EXT_WORD(14 downto 12) when FETCH_STATE = FETCH_EXWORD_1 else -- Index register + BIW_0(11 downto 9) when (OP = ADD or OP = SUB) and BIW_0(8) = '1' else + BIW_0(11 downto 9) when (OP = AND_B or OP = EOR or OP = OR_B) and BIW_0(8) = '1' else + BIW_0(11 downto 9) when OP = BCHG or OP = BCLR or OP = BSET or OP = BTST else + BIW_0(11 downto 9) when OP = ASL or OP = ASR or OP = LSL or OP = LSR else + BIW_0(11 downto 9) when OP = ROTL or OP = ROTR or OP = ROXL or OP = ROXR else + BIW_0(2 downto 0) when (OP = BFCHG or OP = BFCLR or OP = BFEXTS or OP = BFEXTU) and FETCH_STATE = START_OP and BIW_0(5 downto 3) = "000" else + BIW_0(2 downto 0) when (OP = BFCHG or OP = BFCLR or OP = BFEXTS or OP = BFEXTU) and FETCH_STATE = START_OP and BIW_0(5 downto 3) = "001" else + BIW_0(2 downto 0) when (OP = BFCHG or OP = BFCLR or OP = BFEXTS or OP = BFEXTU) and FETCH_STATE = FETCH_ABS_LO else + BIW_0(2 downto 0) when (OP = BFFFO or OP = BFINS or OP = BFSET or OP = BFTST) and FETCH_STATE = START_OP and BIW_0(5 downto 3) = "000" else + BIW_0(2 downto 0) when (OP = BFFFO or OP = BFINS or OP = BFSET or OP = BFTST) and FETCH_STATE = START_OP and BIW_0(5 downto 3) = "001" else + BIW_0(2 downto 0) when (OP = BFFFO or OP = BFINS or OP = BFSET or OP = BFTST) and FETCH_STATE = FETCH_ABS_LO else + BIW_1(8 downto 6) when (OP = BFCHG or OP = BFCLR or OP = BFEXTS or OP = BFEXTU) else -- Width value. + BIW_1(8 downto 6) when (OP = BFFFO or OP = BFINS or OP = BFSET or OP = BFTST) else -- Width value. + BIW_1(2 downto 0) when OP = CAS else -- Compare operand. + BIW_1(14 downto 12) when OP = CAS2 and FETCH_STATE = START_OP else -- Address operand. + BIW_1(14 downto 12) when OP = CAS2 and FETCH_STATE = FETCH_OPERAND and PHASE2 = false else -- Address operand. + BIW_2(14 downto 12) when OP = CAS2 and FETCH_STATE = CALC_AEFF else -- Address operand. + BIW_2(14 downto 12) when OP = CAS2 and FETCH_STATE = FETCH_OPERAND else -- Address operand. + BIW_1(14 downto 12) when OP_WB_I = CAS2 and BIW_1(15) = '0' and (EXEC_WB_STATE = EXECUTE or EXEC_WB_STATE = ADR_PIPELINE) else -- Address operand. + BIW_2(14 downto 12) when OP_WB_I = CAS2 and BIW_2(15) = '0' and EXEC_WB_STATE = WRITE_DEST else -- Address operand. + BIW_1(2 downto 0) when OP = CAS2 and PHASE2 = false else -- Compare operand. + BIW_2(2 downto 0) when OP = CAS2 else -- Compare operand. + BIW_1(2 downto 0) when (OP = DIVS or OP = DIVU) and FETCH_STATE /= INIT_EXEC_WB and BIW_0(8 downto 6) = "001" else -- LONG 64. + MOVEM_PNTR(2 downto 0) when OP = MOVEM else + BIW_0(11 downto 9) when OP = MOVEP else + BIW_1(14 downto 12) when OP = MOVEC or OP = MOVES else + BIW_0(2 downto 0) when OP = ADD or OP = AND_B or OP = OR_B or OP = SUB else + BIW_0(2 downto 0) when OP = ABCD or OP = ADDA or OP = ADDX or OP = CHK or OP = CMP or OP = CMPA else + BIW_0(11 downto 9) when OP = EXG and BIW_0(7 downto 3) = "10001" else -- Data and address register. + BIW_0(2 downto 0) when OP = DIVS or OP = DIVU or OP = EXG else + BIW_0(2 downto 0) when OP = MOVE or OP = MOVEA or OP = MOVE_TO_CCR or OP = MOVE_TO_SR or OP = MULS or OP = MULU or OP= PACK else + BIW_0(2 downto 0) when OP = SBCD or OP = SUBA or OP = SUBX or OP = UNPK else "000"; + + DR_SEL_WR_1 <= BIW_1(14 downto 12) when OP = BFEXTS or OP = BFEXTU or OP = BFFFO else + BIW_1(14 downto 12) when OP = MOVEC or OP = MOVES else + BIW_0(11 downto 9) when OP = ABCD or OP = SBCD else + BIW_0(11 downto 9) when OP = ADDX or OP = SUBX else + BIW_0(11 downto 9) when OP = ADD or OP = SUB else + BIW_0(11 downto 9) when OP = AND_B or OP = OR_B else + BIW_0(11 downto 9) when (OP = DIVS or OP = DIVU) and OP_SIZE_I = WORD else + BIW_1(14 downto 12) when OP = DIVS or OP = DIVU else + BIW_0(11 downto 9) when (OP = MULS or OP = MULU) and OP_SIZE_I = WORD else + BIW_1(14 downto 12) when OP = MULS or OP = MULU else -- Low order result and operand. + BIW_0(11 downto 9) when OP = EXG else + BIW_0(11 downto 9) when OP = MOVE or OP = MOVEP or OP = MOVEQ else + BIW_0(11 downto 9) when OP = PACK or OP = UNPK else + BIW_1(2 downto 0) when OP = CAS else -- Compare operand. + BIW_1(2 downto 0) when OP_WB_I = CAS2 and EXEC_WB_STATE = EXECUTE else -- Compare operand 1. + BIW_2(2 downto 0) when OP_WB_I = CAS2 and EXEC_WB_STATE = WRITEBACK else -- Compare operand 2. + MOVEM_PNTR(2 downto 0) when OP = MOVEM else + BIW_0(2 downto 0); + + DR_WR_1 <= '1' when OP_WB_I = EXG and EXEC_WB_STATE = WRITEBACK and BIW_0_WB(7 downto 3) = "10001" else -- Address- and data register. + '0' when AR_WR_I = '1' else -- This is the locking AR against DR. + '0' when AR_WR_II = '1' else -- This is the locking AR against DR. + '0' when OP_WB_I = ANDI_TO_SR or OP_WB_I = EORI_TO_SR or OP_WB_I = ORI_TO_SR else + '0' when OP_WB_I = MOVE_TO_CCR or OP_WB_I = MOVE_TO_SR else + '0' when OP_WB_I = MOVE_USP else -- USP is written. + '0' when OP_WB_I = MOVEC and BIW_0_WB(0) = '1' else -- To control register. + '0' when OP_WB_I = STOP else -- SR is written but not DR. + '1' when EXEC_WB_STATE = WRITEBACK else '0'; + + DR_SEL_RD_2 <= BIW_0(11 downto 9) when OP = ABCD or OP = SBCD or OP = ADDX or OP = SUBX else + BIW_0(2 downto 0) when (OP = ADD or OP = AND_B or OP = OR_B or OP = SUB) and BIW_0(8) = '1' else + BIW_0(11 downto 9) when OP = ADD or OP = CMP or OP = SUB or OP = AND_B or OP = OR_B else + BIW_0(11 downto 9) when OP = CHK or OP = EXG else + BIW_1(14 downto 12) when OP = BFINS and FETCH_STATE = START_OP and BIW_0(5 downto 3) = "000" else + BIW_1(14 downto 12) when OP = BFINS and FETCH_STATE = START_OP and BIW_0(5 downto 3) = "001" else + BIW_1(14 downto 12) when OP = BFINS and FETCH_STATE = FETCH_ABS_LO else + BIW_1(8 downto 6) when OP = CAS else -- Update operand. + BIW_1(8 downto 6) when OP = CAS2 and PHASE2 = false else -- Update operand. + BIW_2(8 downto 6) when OP = CAS2 else -- Update operand. + BIW_1(14 downto 12) when OP = CHK2 or OP = CMP2 else + BIW_0(11 downto 9) when (OP = DIVS or OP = DIVU) and BIW_0(7) = '1' else -- WORD size. + BIW_1(14 downto 12) when (OP = DIVS or OP = DIVU) else -- Quotient low portion. + BIW_0(11 downto 9) when (OP = MULS or OP = MULU) and BIW_0(7) = '1' else -- WORD size. + BIW_1(14 downto 12) when (OP = MULS or OP = MULU) else + BIW_0(2 downto 0) when OP = BCHG or OP = BCLR or OP = BSET or OP = BTST else + BIW_0(2 downto 0) when OP = ADDI or OP = ADDQ or OP = ANDI or OP = BCHG or OP = BCLR or OP = BSET or OP = BTST or OP = CMPI else + BIW_0(2 downto 0) when OP = DBcc or OP = EOR or OP = EORI or OP = EXT or OP = EXTB or OP = NBCD or OP = NEG or OP = NEGX else + BIW_0(2 downto 0) when OP = NOT_B or OP = ORI or OP = SUBI or OP = SUBQ or OP = SWAP or OP = TAS or OP = TST else + BIW_0(2 downto 0) when OP = ASL or OP = ASR or OP = LSL or OP = LSR else + BIW_0(2 downto 0) when OP = ROTL or OP = ROTR or OP = ROXL or OP = ROXR else "000"; + + DR_SEL_WR_2 <= BIW_0(2 downto 0) when OP = EXG else BIW_1(2 downto 0); -- Default is for DIVS and DIVU, MULS, MULU. + + -- Normally source register. Writte in a few exceptions. + DR_WR_2 <= '1' when OP_WB_I = EXG and EXEC_WB_STATE = WRITEBACK and BIW_0_WB(7 downto 3) = "01000" else -- Two data registers. + '1' when OP_WB_I = DIVS and EXEC_WB_STATE = WRITEBACK and BIW_0_WB(8 downto 6) = "001" and BIW_1_WB(14 downto 12) /= BIW_1_WB(2 downto 0) else + '1' when OP_WB_I = DIVU and EXEC_WB_STATE = WRITEBACK and BIW_0_WB(8 downto 6) = "001" and BIW_1_WB(14 downto 12) /= BIW_1_WB(2 downto 0) else + '1' when OP_WB_I = MULS and EXEC_WB_STATE = WRITEBACK and BIW_0_WB(8 downto 6) = "000" and BIW_1_WB(10) = '1' and BIW_1_WB(14 downto 12) /= BIW_1_WB(2 downto 0) else + '1' when OP_WB_I = MULU and EXEC_WB_STATE = WRITEBACK and BIW_0_WB(8 downto 6) = "000" and BIW_1_WB(10) = '1' and BIW_1_WB(14 downto 12) /= BIW_1_WB(2 downto 0) else '0'; + + USE_DREG <= '1' when OP = CAS2 and BIW_1(15) = '0' and PHASE2 = false else + '1' when OP = CAS2 and BIW_2(15) = '0' else + '1' when (OP = CHK2 or OP = CMP2) and BIW_1(15) = '0' and FETCH_STATE = FETCH_OPERAND and RD_RDY = '1' and PHASE2 = true else -- Select destination register. + '1' when (OP = CHK2 or OP = CMP2) and BIW_1(15) = '0' and ALU_INIT_I = '1' else '0'; -- Store compare information + + WB_BUFFER: process + -- This process stores the data for the + -- WRITEBACK or the WRITE_DEST procedure. + -- The MOVEM condition is foreseen to bring + -- the ADn_WB and the PNTR_WB right in time + -- befor the address or data registers are + -- marked used. + begin + wait until CLK = '1' and CLK' event; + if (OP_WB_I = BFCHG or OP_WB_I = BFCLR or OP_WB_I = BFINS or OP_WB_I = BFSET) and EXEC_WB_STATE = WRITE_DEST and WR_RDY = '1' and BF_BYTES = 5 then + -- This condition may not overwhelm the ALU_INIT_I sowe have to wait in INIT_EXEC_WB for the + -- bit field operations until the last bus cycle finishes. + OP_SIZE_WB <= BYTE; -- Remaining Byte. + elsif OP = LINK and FETCH_STATE = START_OP and NEXT_FETCH_STATE = SWITCH_STATE then + OP_SIZE_WB <= OP_SIZE_I; -- Bring this information early because the registers are written early. + elsif ALU_INIT_I = '1' then + if OP = DIVS or OP = DIVU or OP = MULS or OP = MULU then + OP_SIZE_WB <= LONG; + elsif OP = MOVEM and BIW_0(10) = '1' then -- Memory to register. + OP_SIZE_WB <= LONG; -- Registers are always written long. + else + OP_SIZE_WB <= OP_SIZE_I; -- Store right in the end before data processing starts. + end if; + + MOVEM_ADn_WB <= MOVEM_ADn_I; + OP_WB_I <= OP; + BIW_0_WB <= BIW_0(11 downto 0); + BIW_1_WB <= BIW_1; + end if; + end process WB_BUFFER; + + OP_WB <= OP_WB_I; + BIW_0_WB_73 <= BIW_0_WB(7 downto 3); + + OP_SIZE <= OP_SIZE_I; + OP_SIZE_I <= LONG when FETCH_STATE = FETCH_MEMADR and RD_RDY = '0' else -- (RD_RDY: release early to provide correct OP_SIZE. + LONG when (OP = ADDA or OP = CMPA or OP = SUBA) and BIW_0(8 downto 7) = "11" else + LONG when (OP = BCHG or OP = BCLR or OP = BTST or OP = BSET) and BIW_0(5 downto 3) = "000" else + LONG when (OP = BFCHG or OP = BFCLR or OP = BFINS or OP = BFSET) and BIW_0(5 downto 3) = "000" else + LONG when (OP = BFEXTS or OP = BFEXTU or OP = BFFFO or OP = BFTST) and BIW_0(5 downto 3) = "000" else + LONG when (OP = BFCHG or OP = BFCLR or OP = BFINS or OP = BFSET) and BF_BYTES > 2 else + LONG when (OP = BFEXTS or OP = BFEXTU or OP = BFFFO or OP = BFTST) and BF_BYTES > 2 else + LONG when OP = EXT and BIW_0(8 downto 6) = "011" else + LONG when OP = BSR or OP = EXG or OP = EXTB or OP = JSR or OP = LEA or OP = LINK or OP = PEA or OP = SWAP or OP = UNLK else + LONG when (OP = CAS or OP = CAS2) and BIW_0(10 downto 9) = "11" else + LONG when OP = CHK and BIW_0(8 downto 7) = "10" else + LONG when (OP = CHK2 or OP = CMP2) and BIW_0(10 downto 9) = "10" else + LONG when (OP = MOVE or OP = MOVEA) and BIW_0(13 downto 12) = "10" else + LONG when OP = MOVEC or OP = MOVEQ or OP = MOVE_USP or OP = RTD or OP = RTS else + LONG when OP = MOVEM and BIW_0(6) = '1' else + LONG when OP = MOVEP and FETCH_STATE = INIT_EXEC_WB and BIW_0(7 downto 6) < "10" else -- Writeback to registers is long (see top level multiplexer). + LONG when (OP = DIVS or OP = DIVU or OP = MULS or OP = MULU) and BIW_0(7) = '0' else + LONG when OP = RTR and PHASE2 = true else -- Read PC. + WORD when (OP = ADDA or OP = CMPA or OP = SUBA) and BIW_0(8 downto 7) = "01" else + WORD when (OP = ASL or OP = ASR) and BIW_0(7 downto 6) = "11" else -- Memory shifts. + WORD when OP = ANDI_TO_SR or OP = EORI_TO_SR or OP = ORI_TO_SR else + WORD when (OP = BFCHG or OP = BFCLR or OP = BFINS or OP = BFSET) and BF_BYTES = 2 else + WORD when (OP = BFEXTS or OP = BFEXTU or OP = BFFFO or OP = BFTST) and BF_BYTES = 2 else + WORD when OP = BKPT and FETCH_STATE = FETCH_OPERAND and DATA_RD_I = '1' else + WORD when (OP = CAS or OP = CAS2) and BIW_0(10 downto 9) = "10" else + WORD when OP = CHK and BIW_0(8 downto 7) = "11" else + WORD when (OP = CHK2 or OP = CMP2) and BIW_0(10 downto 9) = "01" else + WORD when OP = DBcc or OP = EXT else + WORD when (OP = LSL or OP = LSR) and BIW_0(7 downto 6) = "11" else -- Memory shifts. + WORD when (OP = MOVE or OP = MOVEA) and BIW_0(13 downto 12) = "11" else + WORD when OP = MOVE_FROM_CCR or OP = MOVE_TO_CCR else + WORD when OP = MOVE_FROM_SR or OP = MOVE_TO_SR else + WORD when OP = MOVEM or OP = RTR else + WORD when OP = DIVS or OP = DIVU or OP = MULS or OP = MULU else + WORD when OP = PACK and (NEXT_FETCH_STATE = FETCH_OPERAND or FETCH_STATE = FETCH_OPERAND) and INIT_ENTRY = '0' else -- Read data is word wide. + WORD when (OP = ROTL or OP = ROTR) and BIW_0(7 downto 6) = "11" else -- Memory shifts. + WORD when (OP = ROXL or OP = ROXR) and BIW_0(7 downto 6) = "11" else -- Memory shifts. + WORD when OP = UNPK and (INIT_ENTRY = '1' or FETCH_STATE = INIT_EXEC_WB) else -- Writeback data is a word. + BYTE when OP = ABCD or OP = NBCD or OP = SBCD else + BYTE when OP = ANDI_TO_CCR or OP = EORI_TO_CCR or OP = ORI_TO_CCR else + BYTE when OP = BCHG or OP = BCLR or OP = BTST or OP = BSET else + BYTE when OP = BFCHG or OP = BFCLR or OP = BFINS or OP = BFSET else + BYTE when OP = BFEXTS or OP = BFEXTU or OP = BFFFO or OP = BFTST else + BYTE when OP = CAS and BIW_0(10 downto 9) = "01" else + BYTE when (OP = CHK2 or OP = CMP2) and BIW_0(10 downto 9) = "00" else + BYTE when OP = MOVE or OP = MOVEP else + BYTE when OP = PACK else -- Writeback data is a byte. + BYTE when OP = Scc or OP = TAS else + BYTE when OP = UNPK else -- Read data is byte wide. + -- The following are default settings for all other OP_SIZE relevant operations. + BYTE when BIW_0(7 downto 6) = "00" else + WORD when BIW_0(7 downto 6) = "01" else LONG; + + BKPT_CYCLE <= '1' when OP = BKPT and FETCH_STATE = FETCH_OPERAND and DATA_RD_I = '1' else '0'; + BKPT_INSERT <= '1' when OP = BKPT and FETCH_STATE = FETCH_OPERAND and RD_RDY = '1' and DATA_VALID = '1' else '0'; + + -- All traps must be modeled as strobes. Be aware that the TRAP_cc is released right in the end of the TRAPcc operation. + -- This is necessary to meet the timing requirements (BUSY_EXH, IPIPE_FLUSH, PC_INC) to provide the next PC address. See + -- the exception handler unit for more details. + TRAP_ILLEGAL <= '1' when OP = BKPT and FETCH_STATE = FETCH_OPERAND and RD_RDY = '1' and DATA_VALID = '0' else '0'; + + TRAP_cc <= '1' when OP = TRAPcc and ALU_COND = true and FETCH_STATE = SLEEP and NEXT_FETCH_STATE = START_OP else '0'; + TRAP_V <= '1' when OP = TRAPV and ALU_COND = true and FETCH_STATE = SLEEP and NEXT_FETCH_STATE = START_OP else '0'; + + BERR <= '0' when FETCH_STATE = START_OP and EXEC_WB_STATE = IDLE else -- Disable when controller is not active. + '0' when OP = BKPT else -- No bus error during breakpoint cycle. + '1' when DATA_RDY = '1' and DATA_VALID = '0' else + '1' when OPD_ACK = '1' and OW_VALID = '0' else + '1' when EW_ACK = '1' and OW_VALID = '0' else '0'; + + SFC_RD <= '1' when OP = MOVEC and BIW_0(0) = '0' and BIW_1(11 downto 0) = x"000" else '0'; + SFC_WR <= '1' when OP_WB_I = MOVEC and BIW_0_WB(0) = '1' and BIW_1(11 downto 0) = x"000" and EXEC_WB_STATE = WRITEBACK else '0'; + + DFC_RD <= '1' when OP = MOVEC and BIW_0(0) = '0' and BIW_1(11 downto 0) = x"001" else '0'; + DFC_WR <= '1' when OP_WB_I = MOVEC and BIW_0(0) = '1' and BIW_1_WB(11 downto 0) = x"001" and EXEC_WB_STATE = WRITEBACK else '0'; + + VBR_RD <= '1' when OP = MOVEC and BIW_0(0) = '0' and BIW_1(11 downto 0) = x"801" else '0'; + VBR_WR <= '1' when OP_WB_I = MOVEC and BIW_0_WB(0) = '1' and BIW_1_WB(11 downto 0) = x"801" and EXEC_WB_STATE = WRITEBACK else '0'; + + ISP_RD <= '1' when OP = MOVEC and BIW_0(0) = '0' and BIW_1(11 downto 0) = x"804" else '0'; + ISP_WR <= '1' when OP_WB_I = MOVEC and BIW_0_WB(0) = '1' and BIW_1_WB(11 downto 0) = x"804" and EXEC_WB_STATE = WRITEBACK else '0'; + + MSP_RD <= '1' when OP = MOVEC and BIW_0(0) = '0' and BIW_1(11 downto 0) = x"803" else '0'; + MSP_WR <= '1' when OP_WB_I = MOVEC and BIW_0_WB(0) = '1' and BIW_1_WB(11 downto 0) = x"803" and EXEC_WB_STATE = WRITEBACK else '0'; + + USP_RD <= '1' when OP = MOVE_USP and BIW_0(3) = '1' else + '1' when OP = MOVEC and BIW_0(0) = '0' and BIW_1(11 downto 0) = x"800" else '0'; + USP_WR <= '1' when OP_WB_I = MOVE_USP and EXEC_WB_STATE = WRITEBACK and BIW_0_WB(3) = '0' else + '1' when OP_WB_I = MOVEC and BIW_0_WB(0) = '1' and BIW_1_WB(11 downto 0) = x"800" and EXEC_WB_STATE = WRITEBACK else '0'; + + P_DISPLACEMENT: process + variable DISPL_VAR : std_logic_vector(31 downto 0); + begin + wait until CLK = '1' and CLK' event; + case OP is + when Bcc | BRA | BSR => + case BIW_0(7 downto 0) is + when x"FF" => + DISPL_VAR := BIW_1 & BIW_2; + when x"00" => + for i in 16 to 31 loop + DISPL_VAR(i) := BIW_1(15); + end loop; + DISPL_VAR(15 downto 0) := BIW_1; + when others => + for i in 8 to 31 loop + DISPL_VAR(i) := BIW_0(7); + end loop; + DISPL_VAR(7 downto 0) := BIW_0(7 downto 0); + end case; + when DBcc | MOVEP | RTD => + for i in 16 to 31 loop + DISPL_VAR(i) := BIW_1(15); + end loop; + DISPL_VAR(15 downto 0) := BIW_1; + when others => -- Used for LINK. + case BIW_0(11 downto 3) is + when "100000001" => -- Long. + DISPL_VAR := BIW_1 & BIW_2; + when others => -- Word. + for i in 16 to 31 loop + DISPL_VAR(i) := BIW_1(15); + end loop; + DISPL_VAR(15 downto 0) := BIW_1; + end case; + end case; + -- + case OP is + when LINK | MOVEP => DISPLACEMENT <= DISPL_VAR; + when others => DISPLACEMENT <= DISPL_VAR + "10"; + end case; + end process P_DISPLACEMENT; + + PC_ADD_DISPL <= PC_ADD_DISPL_I; + PC_ADD_DISPL_I <= '1' when OP = Bcc and FETCH_STATE /= START_OP and NEXT_FETCH_STATE = START_OP and ALU_COND = true else + '1' when (OP = BRA or OP = BSR) and FETCH_STATE /= START_OP and NEXT_FETCH_STATE = START_OP else + '1' when OP = DBcc and FETCH_STATE /= START_OP and NEXT_FETCH_STATE = START_OP and ALU_COND = false and DBcc_COND = false else '0'; + + PC_LOAD <= PC_LOAD_I; + PC_LOAD_I <= '1' when (OP = JMP or OP = JSR) and FETCH_STATE /= START_OP and NEXT_FETCH_STATE = START_OP else + '1' when (OP = RTD or OP = RTR or OP = RTS) and FETCH_STATE /= START_OP and NEXT_FETCH_STATE = START_OP else '0'; + + -- The pipe is flushed for the system control instructions. Be aware, that the operations resulting in an exception + -- like the CHK or TRAP operations flush the pipe via the exception handler. + -- Context switch may occur from: + -- changing the PC value (branches etc.) + -- changing the RAM space (status register MSBs). + -- changing Function codes or the active stack pointer. + IPIPE_FLUSH <= IPIPE_FLUSH_I; + IPIPE_FLUSH_I <= '1' when (OP = BRA or OP = BSR) and FETCH_STATE /= START_OP and NEXT_FETCH_STATE = START_OP else + '1' when OP = Bcc and FETCH_STATE /= START_OP and NEXT_FETCH_STATE = START_OP and ALU_COND = true else + '1' when OP = DBcc and LOOP_BSY = '0' and FETCH_STATE /= START_OP and NEXT_FETCH_STATE = START_OP and ALU_COND = false and DBcc_COND = false else + '1' when OP = DBcc and LOOP_EXIT_I = '1' and (ALU_COND = true or DBcc_COND = true) else -- Flush the pipe after a finished loop. + '1' when (OP = ANDI_TO_SR or OP = EORI_TO_SR or OP = MOVE_TO_SR or OP = ORI_TO_SR) and FETCH_STATE = SLEEP and NEXT_FETCH_STATE = START_OP else + '1' when (OP = JMP or OP = JSR) and FETCH_STATE /= START_OP and NEXT_FETCH_STATE = START_OP else + '1' when OP = MOVEC and BIW_0(0) = '1' and FETCH_STATE /= START_OP and NEXT_FETCH_STATE = START_OP else -- Writing control registers. + '1' when (OP = RTD or OP = RTR or OP = RTS) and FETCH_STATE /= START_OP and NEXT_FETCH_STATE = START_OP else '0'; + + SP_ADD_DISPL <= '1' when OP = LINK and FETCH_STATE = INIT_EXEC_WB and ALU_BSY = '0' else + '1' when OP = RTD and FETCH_STATE = FETCH_OPERAND and RD_RDY = '1' and DATA_VALID = '1' else '0'; + + ALU_TRIG <= '0' when ALU_BSY = '1' or FETCH_STATE /= INIT_EXEC_WB else + '0' when (OP = CHK2 or OP = CMP2 or OP = CMPM) and PHASE2 = false else + '0' when OP = MOVE and PHASE2 = true else -- no ALU required after second portion of address calculation. + '0' when OP = MOVEM and MOVEM_COND = false else + '0' when OP = MOVEM and BIW_0(10) = '1' and MOVEM_FIRST_RD = false else -- Do not load before the first read access. + '0' when OP = RTR and PHASE2 = true else '1'; -- RTR: not when PC is loaded. + + -- This is the signal loading the operands into the ALU registers: + ALU_INIT <= ALU_INIT_I; + with OP select + ALU_INIT_I <= ALU_TRIG when ABCD | ADD | ADDA | ADDI | ADDQ | ADDX | AND_B | ANDI | ANDI_TO_CCR | ANDI_TO_SR | ASL | ASR | Bcc | BCHG | + BCLR | BFCHG | BFCLR | BFEXTS | BFEXTU | BFFFO | BFINS | BFSET | BFTST | BSET | BSR | BTST | CAS | CAS2 | + CHK | CHK2 | CLR | CMP | CMPA | CMPI | CMPM | CMP2 | DBcc | DIVS | DIVU | EOR | EORI | EORI_TO_CCR | EORI_TO_SR | + EXG | EXT | EXTB | JSR | LEA | LINK | LSL | LSR | MOVE | MOVEA | MOVE_FROM_CCR | MOVE_TO_CCR | MOVE_FROM_SR | + MOVE_TO_SR | MOVE_USP | MOVEC | MOVEM | MOVEQ | MOVEP | MOVES | MULS | MULU | NBCD | NEG | NEGX | NOT_B | OR_B | + ORI | ORI_TO_CCR | ORI_TO_SR | PACK | PEA | ROTL | ROTR | ROXL | ROXR | RTR | SBCD | Scc | SUB | SUBA | SUBI | + SUBQ | SUBX | SWAP | STOP | TAS | TRAPV | TRAPcc | TST | UNLK | UNPK, '0' when others; + + ADR_FORMAT: process + begin + wait until CLK = '1' and CLK' event; + if FETCH_STATE = FETCH_EXWORD_1 and EW_ACK = '1' and EXT_WORD(8) = '1' then + case EXT_WORD(1 downto 0) is + when "11" => + MEM_INDIRECT <= '1'; + OD_REQ_32 <= '1'; + OD_REQ_16 <= '0'; + when "10" => + MEM_INDIRECT <= '1'; + OD_REQ_32 <= '0'; + OD_REQ_16 <= '1'; + when "01" => + MEM_INDIRECT <= '1'; + OD_REQ_32 <= '0'; + OD_REQ_16 <= '0'; + when others => + MEM_INDIRECT <= '0'; + OD_REQ_32 <= '0'; + OD_REQ_16 <= '0'; + end case; + end if; + end process ADR_FORMAT; + + UPDT_CC <= '0' when (OP_WB_I = ADDQ or OP_WB_I = SUBQ) and BIW_0_WB(5 downto 3) = "001" else -- No update for ADDQ and SUBQ when destination is an address register. + '0' when OP = CAS2 and FETCH_STATE = INIT_EXEC_WB and EXEC_WB_STATE = WRITEBACK else -- First 'Z' flag was zero, do not update the second access. + '0' when OP = CAS2 and FETCH_STATE = INIT_EXEC_WB and EXEC_WB_STATE = WRITE_DEST and PHASE2 = true else ALU_REQ; -- Suppress third update. + + with OP_WB_I select + CC_UPDT <= UPDT_CC when ABCD | ADD | ADDI | ADDQ | ADDX | AND_B | ANDI | ANDI_TO_CCR | ASL | ASR | BCHG | BCLR | + BFCHG | BFCLR | BFEXTS | BFEXTU | BFFFO | BFINS | BFSET | BFTST | BSET | BTST | + CAS | CAS2 | CHK | CHK2 | CLR | CMP | CMPA | CMPI | CMPM | CMP2 | DIVS | DIVU | + EOR | EORI | EORI_TO_CCR | EXT | EXTB | LSL | LSR | MOVE | MOVEQ | MULS | MULU | NBCD | + NEG | NEGX | NOT_B | OR_B | ORI | ORI_TO_CCR | ROTL | ROTR | ROXL | ROXR | RTR | SBCD | + SUB | SUBI | SUBQ | SUBX | SWAP | TAS | TST, '0' when others; + + ADR_MARK_USED_I <= '1' when OP = MOVE and FETCH_STATE = INIT_EXEC_WB and PHASE2 = true else -- Destination address calculation done. + '0' when FETCH_STATE /= INIT_EXEC_WB or ALU_BSY = '1' else -- Deactivate except in the end of INIT_EXEC_WB. + '1' when OP = BFCHG or OP = BFCLR or OP = BFINS or OP = BFSET or OP = BSR or OP = JSR or OP = LINK or OP = PEA else + '1' when (OP = ADDI or OP = ANDI or OP = EOR or OP = EORI or OP = ORI or OP = SUBI) and BIW_0(5 downto 3) /= "000" else + '1' when (OP = ABCD or OP = SBCD or OP = ADDX or OP = SUBX) and BIW_0(3) = '1' else + '1' when (OP = ADD or OP = AND_B or OP = OR_B or OP = SUB) and BIW_0(8) = '1' else + '1' when (OP = ADDQ or OP = BCHG or OP = BCLR or OP = BSET or OP = CLR or OP = MOVE_FROM_CCR or OP = MOVE_FROM_SR) and BIW_0(5 downto 3) > "001" else + '1' when (OP = NBCD or OP = NEG or OP = NEGX or OP = NOT_B or OP = Scc or OP = SUBQ or OP = TAS) and BIW_0(5 downto 3) > "001" else + '1' when (OP = ASL or OP = ASR or OP = LSL or OP = LSR) and BIW_0(7 downto 6) = "11" else -- Memory shifts. + '1' when (OP = ROTL or OP = ROTR or OP = ROXL or OP = ROXR) and BIW_0(7 downto 6) = "11" else -- Memory shifts. + '1' when OP = MOVE and PHASE2 = false and BIW_0(8 downto 6) /= "000" and BIW_0(8 downto 6) < "101" else -- We do not need destination address calculation access. + '1' when OP = MOVEM and BIW_0(10) = '0' and MOVEM_COND = true else -- Register to memory. + '1' when OP = MOVEP and BIW_0(7 downto 6) > "01" else -- Register to Memory. + '1' when OP = MOVES and BIW_1(11) = '1' else -- Register to memory. + '1' when (OP = PACK or OP = UNPK) and BIW_0(3) = '1' else '0'; + + ADR_MARK_USED <= '1' when (OP_WB_I = BFCHG or OP_WB_I = BFCLR) and EXEC_WB_STATE = WRITE_DEST and WR_RDY = '1' and BF_BYTES = 5 else + '1' when (OP_WB_I = BFINS or OP_WB_I = BFSET) and EXEC_WB_STATE = WRITE_DEST and WR_RDY = '1' and BF_BYTES = 5 else + '1' when OP_WB_I = CAS and EXEC_WB_STATE = EXECUTE and ALU_COND = true else + '1' when OP_WB_I = CAS2 and EXEC_WB_STATE = ADR_PIPELINE and ALU_COND = true else + '1' when OP_WB_I = CAS2 and EXEC_WB_STATE = WRITE_DEST and WR_RDY = '1' and PHASE2 = false else ADR_MARK_USED_I; + + AR_MARK_USED <= '1' when OP = UNLK and FETCH_STATE /= SWITCH_STATE and NEXT_FETCH_STATE = SWITCH_STATE else -- This is for An to SP. + '1' when OP = LINK and FETCH_STATE = SWITCH_STATE and NEXT_FETCH_STATE /= SWITCH_STATE else -- This is for SP to An. + '0' when FETCH_STATE /= INIT_EXEC_WB or NEXT_FETCH_STATE = INIT_EXEC_WB else -- Deactivate except in the end of INIT_EXEC_WB. + '1' when OP = ADDA or OP = SUBA else + '1' when (OP = ADDQ or OP = SUBQ) and BIW_0(5 downto 3) = "001" else + '1' when OP = EXG and BIW_0(7 downto 3) /= "01000" else + '1' when OP = LEA else + '1' when OP = MOVE_USP else + '1' when OP = MOVEM and BIW_0(10) = '1' and MOVEM_ADn_I = '1' and MOVEM_COND = true else -- Memory to register. + '1' when OP = MOVEA else + '1' when OP = MOVEC and BIW_0(0) = '0' and BIW_1(15) = '1' else -- Destination is Ax. + '1' when OP = MOVES and BIW_1(15) = '1' and BIW_1(11) = '0' else + '1' when OP = UNLK else '0'; + + DR_MARK_USED <= '1' when OP_WB_I = CAS and EXEC_WB_STATE = EXECUTE and ALU_COND = false else + '1' when OP_WB_I = CAS2 and EXEC_WB_STATE = EXECUTE and ALU_COND = false else + '1' when OP_WB_I = CAS2 and EXEC_WB_STATE = WRITEBACK and PHASE2 = false else + '0' when FETCH_STATE /= INIT_EXEC_WB or NEXT_FETCH_STATE = INIT_EXEC_WB else -- Deactivate except in the end of INIT_EXEC_WB. + '1' when (OP = ABCD or OP = SBCD) and BIW_0(3) = '0' else + '1' when (OP = ADDX or OP = SUBX) and BIW_0(3) = '0' else + '1' when (OP = ADDQ or OP = SUBQ) and BIW_0(5 downto 3) = "000" else + '1' when (OP = ADD or OP = SUB) and BIW_0(8) = '0' else + '1' when (OP = ADDI or OP = ANDI or OP = EOR or OP = EORI or OP = ORI or OP = SUBI) and BIW_0(5 downto 3) = "000" else + '1' when (OP = AND_B or OP = OR_B) and BIW_0(8) = '0' else + '1' when (OP = ASL or OP = ASR) and BIW_0(7 downto 6) /= "11" else + '1' when (OP = LSL or OP = LSR) and BIW_0(7 downto 6) /= "11" else + '1' when (OP = ROTL or OP = ROTR) and BIW_0(7 downto 6) /= "11" else + '1' when (OP = ROXL or OP = ROXR) and BIW_0(7 downto 6) /= "11" else + '1' when (OP = BCHG or OP = BCLR or OP = BSET) and BIW_0(5 downto 3) = "000" else + '1' when (OP = BFCHG or OP = BFCLR or OP = BFINS or OP = BFSET) and BIW_0(5 downto 3) = "000" else + '1' when OP = BFEXTS or OP = BFEXTU or OP = BFFFO else + '1' when (OP = CLR or OP = TAS or OP = Scc) and BIW_0(5 downto 3) = "000" else + '1' when OP = DBcc or OP = DIVS or OP = DIVU or OP = MULS or OP = MULU else + '1' when OP = EXG and BIW_0(7 downto 3) /= "01001" else + '1' when OP = EXT or OP = EXTB or OP = SWAP else + '1' when OP = MOVE and BIW_0(8 downto 6) = "000" else + '1' when (OP = MOVE_FROM_CCR or OP = MOVE_FROM_SR) and BIW_0(5 downto 3) = "000" else + '1' when OP = MOVEM and BIW_0(10) = '1' and MOVEM_ADn_I = '0' and MOVEM_COND = true else -- Memory to register. + '1' when OP = MOVEP and BIW_0(7 downto 6) < "10" else -- Memory to register. + '1' when OP = MOVEC and BIW_0(0) = '0' and BIW_1(15) = '0' else -- Destination is Dx. + '1' when OP = MOVEQ else + '1' when OP = MOVES and BIW_1(15) = '0' and BIW_1(11) = '0' else + '1' when (OP = NBCD or OP = NEG or OP = NEGX or OP = NOT_B) and BIW_0(5 downto 3) = "000" else + '1' when (OP = PACK or OP = UNPK) and BIW_0(3) = '0' else '0'; + + UNMARK <= '1' when EXEC_WB_STATE /= IDLE and NEXT_EXEC_WB_STATE = IDLE else '0'; -- Release a pending write cycle when done. + + -- These signals indicates, that two registers are prepared to be written. In this case, the values + -- in both of these registers are invalidated before the writeback. + USE_APAIR <= true when OP = EXG and BIW_0(7 downto 3) = "01001" else false; + USE_DPAIR <= true when OP = EXG and BIW_0(7 downto 3) = "01000" else + true when (OP = DIVS or OP = DIVU) and OP_SIZE_I = LONG and BIW_1(14 downto 12) /= BIW_1(2 downto 0) else + true when (OP = MULS or OP = MULU) and OP_SIZE_I = LONG and BIW_1(10) = '1' and BIW_1(14 downto 12) /= BIW_1(2 downto 0) else false; + + LOOP_EXIT <= LOOP_EXIT_I; + LOOP_EXIT_I <= '1' when OP /= DBcc and LOOP_BSY = '1' and FETCH_STATE /= START_OP and NEXT_FETCH_STATE = START_OP and EXH_REQ = '1' else -- Exception! break the loop. + '1' when OP = DBcc and LOOP_BSY = '1' and FETCH_STATE = SLEEP and NEXT_FETCH_STATE = START_OP and (ALU_COND = true or DBcc_COND = true) else '0'; -- 68010 loop mechanism. + + LOOP_CTRL: process + -- This flip flop indicates, if a DBcc loop operation has finished if the exception handler indicates an interrupt. + -- If so, no action is required. If the loop is split (when not finished) the exception handler may not increment + -- the PC to hold the value of the loop operation. + begin + wait until CLK = '1' and CLK' event; + if FETCH_STATE = START_OP and NEXT_FETCH_STATE /= START_OP then + LOOP_SPLIT <= false; + elsif PC_INC_EXH = '1' then + LOOP_SPLIT <= false; + elsif OP /= DBcc and EXH_REQ = '1' and LOOP_BSY = '1' and FETCH_STATE = SLEEP and NEXT_FETCH_STATE = START_OP then + LOOP_SPLIT <= true; + end if; + end process LOOP_CTRL; + + + BF_OFFSET_I <= To_Integer(unsigned(BF_OFFSET)); + BF_WIDTH_I <= To_Integer(unsigned(BF_WIDTH)); + + RESET_STRB <= '1' when OP = RESET and INIT_ENTRY = '1' else '0'; + + EX_TRACE <= '0' when OP = ILLEGAL or OP = UNIMPLEMENTED else + '1' when TRACE_MODE = "10" and OPD_ACK = '1' and FETCH_STATE = START_OP and OP = TRAP else + '1' when TRACE_MODE = "10" and FETCH_STATE /= START_OP and NEXT_FETCH_STATE = START_OP else + '1' when TRACE_MODE = "01" and FETCH_STATE = INIT_EXEC_WB and ALU_BSY = '0' and OP = TRAP else + '1' when TRACE_MODE = "01" and FETCH_STATE = INIT_EXEC_WB and ALU_BSY = '0' and OP = TRAPcc and ALU_COND = true else + '1' when TRACE_MODE = "01" and FETCH_STATE = INIT_EXEC_WB and ALU_BSY = '0' and OP = TRAPV and VBIT = '1' else + '1' when TRACE_MODE = "01" and SR_WR_I = '1' else -- Status register manipulations. + '1' when TRACE_MODE = "01" and (PC_ADD_DISPL_I or PC_LOAD_I) = '1' else '0'; -- All branches and jumps. + + P_STATUSn: process + -- This logic is registered to enhance the system performance concerning fmax. + begin + wait until CLK = '1' and CLK' event; + if FETCH_STATE = START_OP and NEXT_FETCH_STATE /= START_OP then + STATUSn <= '0'; + else + STATUSn <= '1'; + end if; + end process P_STATUSn; + + ADDRESS_OFFSET: process + variable ADR_OFFS_VAR: std_logic_vector(5 downto 0) := "000000"; + begin + wait until CLK = '1' and CLK' event; + if FETCH_STATE = START_OP then + ADR_OFFS_VAR := "000000"; + else + case OP is + when BFCHG | BFCLR | BFINS | BFSET => + if FETCH_STATE = FETCH_OPERAND and RD_RDY = '1' and BF_BYTES = 5 then + ADR_OFFS_VAR := ADR_OFFS_VAR + "100"; -- Another Byte required. + elsif INIT_ENTRY = '1' then + ADR_OFFS_VAR := "000000"; -- Restore. + elsif FETCH_STATE = INIT_EXEC_WB and ALU_BSY = '0' and BF_BYTES = 5 then + ADR_OFFS_VAR := ADR_OFFS_VAR + "100"; -- Another Byte required. + end if; + when BFEXTS | BFEXTU | BFFFO | BFTST => + if FETCH_STATE = FETCH_OPERAND and RD_RDY = '1' and BF_BYTES = 5 then + ADR_OFFS_VAR := ADR_OFFS_VAR + "100"; -- Another Byte required. + end if; + when CHK2 | CMP2 => + if FETCH_STATE = FETCH_OPERAND and RD_RDY = '1' and OP_SIZE_I = LONG then + ADR_OFFS_VAR := ADR_OFFS_VAR + "100"; + elsif FETCH_STATE = FETCH_OPERAND and RD_RDY = '1' and OP_SIZE_I = WORD then + ADR_OFFS_VAR := ADR_OFFS_VAR + "10"; + elsif FETCH_STATE = FETCH_OPERAND and RD_RDY = '1' then + ADR_OFFS_VAR := ADR_OFFS_VAR + '1'; + end if; + when MOVEM => + if ADR_MODE_I = "011" or ADR_MODE_I = "100" then -- (An)+, -(An). + null; -- Offset comes from addressing register. + elsif BIW_0(10) = '1' and MOVEM_FIRST_RD = false then + null; -- Do not increment before the first bus access. + elsif MOVEM_COND = true and FETCH_STATE = INIT_EXEC_WB and ALU_BSY = '0' and OP_SIZE_I = LONG then + ADR_OFFS_VAR := ADR_OFFS_VAR + "100"; -- Register to memory. + elsif MOVEM_COND = true and FETCH_STATE = INIT_EXEC_WB and ALU_BSY = '0' then + ADR_OFFS_VAR := ADR_OFFS_VAR + "10"; -- Register to memory. + end if; + when MOVEP => + if FETCH_STATE = INIT_EXEC_WB and ALU_BSY = '0' then + ADR_OFFS_VAR := ADR_OFFS_VAR + "10"; + end if; + when others => null; + end case; + end if; + ADR_OFFSET <= ADR_OFFS_VAR; + end process ADDRESS_OFFSET; + + BITFIELD_CONTROL: process + begin + wait until CLK = '1' and CLK' event; + if FETCH_STATE = START_OP then + case OP is + when BFCHG | BFCLR | BFEXTS | BFEXTU | BFFFO | BFINS | BFSET | BFTST => + if NEXT_FETCH_STATE = INIT_EXEC_WB then + BF_BYTES <= 4; -- Register access. + else + BF_BYTES <= BF_BYTES_I(BF_OFFSET_I, BF_WIDTH_I); + end if; + BF_HILOn <= '1'; + when others => null; + end case; + elsif FETCH_STATE = FETCH_OPERAND then + if RD_RDY = '1' and BF_BYTES = 5 then + BF_BYTES <= 1; + BF_HILOn <= '0'; + elsif RD_RDY = '1' then + BF_BYTES <= BF_BYTES_I(BF_OFFSET_I, BF_WIDTH_I); -- Restore. + BF_HILOn <= '1'; -- Restore. + end if; + elsif EXEC_WB_STATE = WRITE_DEST then + if WR_RDY = '1' and BF_BYTES = 5 then + BF_BYTES <= 1; + BF_HILOn <= '0'; + elsif WR_RDY = '1' then + BF_HILOn <= '1'; -- Restore. + end if; + end if; + end process BITFIELD_CONTROL; + + MOVEM_CONTROL: process(ADR_MODE_I, CLK, BIW_0, BIW_1, OP, RESET_CPU, FETCH_STATE, NEXT_FETCH_STATE, ALU_BSY, MOVEM_PNTR) + variable INDEX : integer range 0 to 15 := 0; + variable MOVEM_PVAR : std_logic_vector(3 downto 0) := x"0"; + variable BITS : std_logic_vector(4 downto 0); + begin + if CLK = '1' and CLK' event then + if FETCH_STATE = START_OP then + MOVEM_PVAR := x"0"; + elsif FETCH_STATE = INIT_EXEC_WB and MOVEM_COND = false and MOVEM_PVAR < x"F" and ALU_BSY = '0' then + MOVEM_PVAR := MOVEM_PVAR + '1'; -- No data to write. + elsif BIW_0(10) = '1' and MOVEM_FIRST_RD = true and FETCH_STATE = INIT_EXEC_WB and MOVEM_PVAR < x"F" and ALU_BSY = '0' then + MOVEM_PVAR := MOVEM_PVAR + '1'; -- Data has not been read. + elsif BIW_0(10) = '0' and FETCH_STATE = INIT_EXEC_WB and MOVEM_PVAR < x"F" and ALU_BSY = '0' then + MOVEM_PVAR := MOVEM_PVAR + '1'; -- Data has been written. + end if; + + if OP = MOVEM and ALU_INIT_I = '1' and ADR_MODE_I = "011" and MOVEM_ADn_I = '1' and MOVEM_PNTR(2 downto 0) = BIW_0(2 downto 0) then + MOVEM_INH_WR <= true; -- Do not write the addressing register. + elsif ALU_INIT_I = '1' then + MOVEM_INH_WR <= false; + end if; + + if FETCH_STATE = START_OP then + MOVEM_FIRST_RD <= false; + elsif OP = MOVEM and FETCH_STATE = FETCH_OPERAND and RD_RDY = '1' then + MOVEM_FIRST_RD <= true; + end if; + + if RESET_CPU = '1' or (FETCH_STATE /= START_OP and NEXT_FETCH_STATE = START_OP) then + BITS := "00000"; + MOVEM_LAST_WR <= false; + elsif OP = MOVEM and FETCH_STATE = START_OP and NEXT_FETCH_STATE /= START_OP and ADR_MODE_I = "100" then -- -(An). + for i in 0 to 15 loop + BITS := BITS + BIW_1(i); -- Count number of '1's. + end loop; + MOVEM_LAST_WR <= false; + elsif OP = MOVEM and ALU_INIT_I = '1' and BITS > "00001" then + BITS := BITS - '1'; + elsif OP = MOVEM and BITS = "00001" then + MOVEM_LAST_WR <= true; + end if; + + -- During the MOVEM instruction in memory to register operation and addressing modes "010", "101","110" the effective address might be + -- affected, if the addressing register is active in the register list mask. To deal with it, the effective address is stored until the + -- MOVEM has read all registers from memory addressed by the initial addressing register (old value). + -- This logic is modeled synchronously (one clock latency) due to the one clock delay of the address calculation. + if OP /= MOVEM or BIW_0(10) /= '1' or (ADR_MODE_I /= "010" and ADR_MODE_I /= "101" and ADR_MODE_I /= "110") then + STORE_AEFF <= '0'; + elsif FETCH_STATE /= START_OP and NEXT_FETCH_STATE = START_OP then + STORE_AEFF <= '0'; -- Operation completed. + elsif FETCH_STATE = SWITCH_STATE or FETCH_STATE = CALC_AEFF or FETCH_STATE = FETCH_OPERAND or FETCH_STATE = INIT_EXEC_WB then + STORE_AEFF <= '1'; + end if; + end if; + + -- This signal determines whether to handle address or data registers. + if ADR_MODE_I = "100" then -- -(An). + MOVEM_ADn_I <= not To_Bit(MOVEM_PVAR(3)); + MOVEM_ADn <= not To_Bit(MOVEM_PVAR(3)); + else + MOVEM_ADn_I <= To_Bit(MOVEM_PVAR(3)); + MOVEM_ADn <= To_Bit(MOVEM_PVAR(3)); + end if; + + INDEX := To_Integer(unsigned(MOVEM_PVAR)); + + -- The following signal determines if a register is affected or not, depending + -- on the status of the register list bit. + if OP = MOVEM and BIW_1(INDEX) = '1' then + MOVEM_COND <= true; + else + MOVEM_COND <= false; + end if; + + -- This signal determines whether to handle address or data registers. + if ADR_MODE_I = "100" then -- -(An). + MOVEM_PNTR <= not MOVEM_PVAR; -- Count down. + else + MOVEM_PNTR <= MOVEM_PVAR; + end if; + end process MOVEM_CONTROL; + + MOVEP_CONTROL: process(CLK, MOVEP_PNTR_I) + -- This logic handles the bytes to be written or read during the MOVEP + -- operation. In LONG mode 4 bytes are affected and in WORD mode two bytes. + begin + if CLK = '1' and CLK' event then + if RESET_CPU = '1' or (FETCH_STATE /= START_OP and NEXT_FETCH_STATE = START_OP) then + MOVEP_PNTR_I <= 0; + elsif FETCH_STATE = START_OP and (BIW_0(8 downto 6) = "101" or BIW_0(8 downto 6) = "111") then + MOVEP_PNTR_I <= 3; -- LONG. + elsif FETCH_STATE = START_OP then + MOVEP_PNTR_I <= 1; -- WORD. + elsif FETCH_STATE = INIT_EXEC_WB and ALU_BSY = '0' and MOVEP_PNTR_I /= 0 then + MOVEP_PNTR_I <= MOVEP_PNTR_I - 1; -- Register to memory + end if; + end if; + MOVEP_PNTR <= MOVEP_PNTR_I; + end process MOVEP_CONTROL; + + PHASE2_CONTROL: process + -- This is used for some operations which require + -- two control sequences. + begin + wait until CLK = '1' and CLK' event; + if NEXT_FETCH_STATE = START_OP then + PHASE2 <= false; + elsif (OP = ABCD or OP = SBCD) and FETCH_STATE = FETCH_OPERAND and RD_RDY = '1' then + PHASE2 <= true; -- One clock cycle delay for destination address calculation. + elsif (OP = ADDX or OP = SUBX) and FETCH_STATE = FETCH_OPERAND and RD_RDY = '1' then + PHASE2 <= true; -- One clock cycle delay for destination address calculation. + elsif OP = CAS2 and FETCH_STATE = INIT_EXEC_WB and ALU_BSY = '0' and PHASE2 = false then + PHASE2 <= true; -- Used as a control flow switch. + elsif OP = CAS2 and FETCH_STATE = INIT_EXEC_WB and ALU_BSY = '0' then + PHASE2 <= false; -- Prepare for writeback / write destination. + elsif OP_WB_I = CAS2 and EXEC_WB_STATE = WRITEBACK then + PHASE2 <= true; -- Used as a control flow switch. + elsif OP_WB_I = CAS2 and EXEC_WB_STATE = WRITE_DEST and WR_RDY = '1' then + PHASE2 <= true; -- Used as a control flow switch. + elsif (OP = CHK2 or OP = CMP2 or OP = CMPM) and FETCH_STATE = INIT_EXEC_WB and ALU_BSY = '0' then + PHASE2 <= true; -- Used as a control flow switch. + elsif OP = JSR and FETCH_STATE = SLEEP then + PHASE2 <= true; -- One clock cycle delay for address calculation. + elsif OP = PEA and FETCH_STATE = SWITCH_STATE then + PHASE2 <= true; -- One clock cycle delay for address calculation. + elsif OP = RTR and FETCH_STATE = INIT_EXEC_WB and NEXT_FETCH_STATE = CALC_AEFF then + PHASE2 <= true; -- Used as a control flow switch. + elsif OP = MOVE and FETCH_STATE = INIT_EXEC_WB and ALU_BSY = '0' and BIW_0(8 downto 6) > "100" then + PHASE2 <= true; -- Indicate destination address calculation is in progress. + end if; + end process PHASE2_CONTROL; + + STATE_REGs: process + begin + wait until CLK = '1' and CLK' event; + if RESET_CPU = '1' then + FETCH_STATE <= START_OP; + EXEC_WB_STATE <= IDLE; + elsif EW_ACK = '1' and OW_VALID = '0' then + FETCH_STATE <= START_OP; -- Bus error. + EXEC_WB_STATE <= IDLE; + elsif OPD_ACK = '1' and OW_VALID = '0' then + FETCH_STATE <= START_OP; -- Bus error. + EXEC_WB_STATE <= IDLE; + elsif DATA_RD_I = '1' and RD_RDY = '1' and DATA_VALID = '0' then + FETCH_STATE <= START_OP; -- Bus error. + EXEC_WB_STATE <= IDLE; + elsif DATA_WR_I = '1' and RD_RDY = '1' and DATA_VALID = '0' then + FETCH_STATE <= START_OP; -- Bus error. + EXEC_WB_STATE <= IDLE; + else + FETCH_STATE <= NEXT_FETCH_STATE; + EXEC_WB_STATE <= NEXT_EXEC_WB_STATE; + end if; + end process STATE_REGs; + + -- Debugging: + -- Use this signal to detect instructions in use in the writeback path (OP_WB_I) or in the fetch path (OP). + -- for these instructions you can halt the pipeline in the START_OP state to detect any problems. + -- with OP select + -- with OP_WB_I select + -- OP_TEST <= '1' when ADDA | ADDQ | EXG | LEA | LINK | MOVEA | MOVE_USP | MOVEC | MOVEM | MOVES | SUBA | SUBQ | UNLK | -- Address register manipulations. + -- ASL | ASR | LSL | LSR | ROTL | ROTR | ROXL | ROXR | DIVS | DIVU | -- Long ALU operations. (68K10, 68K30L have no barrel shifter). + -- ADD | AND_B | CLR | EOR | SUB | OR_B | CMP | CMPA | CMPM | NOT_B | NBCD | NEG | NEGX | SWAP | TAS | TST + -- ANDI_TO_CCR | ANDI_TO_SR | EORI_TO_CCR | EORI_TO_SR | ORI_TO_CCR | ORI_TO_SR | MOVE_FROM_CCR | + -- MOVE_TO_CCR | MOVE_FROM_SR | MOVE_TO_SR | MOVE | MOVEQ | MOVEP | PEA | + -- ABCD | ADDX | SBCD | SUBX | BCHG | BCLR | BSET | BTST | EXT | + -- Bcc | BSR | CHK | DBcc | JSR | TRAPV | RTR | Scc | STOP | + -- ADDI | ANDI | SUBI | CMPI | EORI | ORI | MULS | MULU, '0' when others; + + FETCH_DEC: process(ADR_MODE_I, ALU_BSY, ALU_COND, AR_IN_USE, BF_BYTES, BIW_0, BIW_1, BRANCH_ATN, DR_IN_USE, EW_ACK, EW_RDY, EXH_REQ, + EXEC_WB_STATE, EXT_WORD, FETCH_STATE, MEM_INDIRECT, MEMADR_RDY, MOVEM_COND, MOVEM_PNTR, MOVEP_PNTR_I, NEXT_EXEC_WB_STATE, + OP, OP_SIZE_I, OP_WB_I, OPD_ACK, OW_RDY, PHASE2, RD_RDY, TRACE_MODE, OD_REQ_32, OD_REQ_16, WR_RDY) + -- ADH: avoid data hazard. + -- ASH: avoid structural hazard. + -- ASH: avoid control hazard. + begin + case FETCH_STATE is + when START_OP => + if OPD_ACK = '0' and OW_RDY = '0' then + NEXT_FETCH_STATE <= START_OP; + -- Debugging: + --elsif OP_TEST = '1' and ALU_BSY = '1' then + -- NEXT_FETCH_STATE <= START_OP; + else + case OP is + when ILLEGAL | RTE | TRAP | UNIMPLEMENTED => + NEXT_FETCH_STATE <= START_OP; + when DBcc | EXT | EXTB | MOVEQ | SWAP => + if DR_IN_USE = '1' then + NEXT_FETCH_STATE <= START_OP; -- Wait, ADH. + else + NEXT_FETCH_STATE <= INIT_EXEC_WB; -- Proceed. + end if; + when ABCD | SBCD | ADDX | SUBX | PACK | UNPK => + if BIW_0(3) = '0' and DR_IN_USE = '0' then -- Check for destination addressing register. ADH. + NEXT_FETCH_STATE <= INIT_EXEC_WB; -- Register to register. + elsif BIW_0(3) = '1' and AR_IN_USE = '0' then -- Check for destination addressing register. ADH. + NEXT_FETCH_STATE <= CALC_AEFF; -- Memory to memory. + else + NEXT_FETCH_STATE <= START_OP; -- Wait, ADH. + end if; + when ADD | ADDI | ADDQ | AND_B | ANDI | CAS | CMP | CMPI | EOR | EORI | + NBCD | NEG | NEGX | NOT_B | OR_B | ORI | SUB | SUBI | SUBQ | TST | TAS => + -- These instructions have to take the destination into aspect + -- because the destination is an ALU operand and may cause data hazards. + case BIW_0(5 downto 3) is + when "000" => -- Dn. + if DR_IN_USE = '0' then + NEXT_FETCH_STATE <= INIT_EXEC_WB; + else + NEXT_FETCH_STATE <= START_OP; + end if; + when "001" => -- An. + if (OP = ADD or OP = SUB or OP = AND_B or OP = EOR or OP = OR_B or OP = CMP) and (AR_IN_USE = '1' or DR_IN_USE = '1')then -- ADH. + NEXT_FETCH_STATE <= START_OP; + elsif AR_IN_USE = '0' then + NEXT_FETCH_STATE <= INIT_EXEC_WB; + else + NEXT_FETCH_STATE <= START_OP; + end if; + when "010" | "011" => -- (An), (An)+. + if AR_IN_USE = '1' then -- ADH. + NEXT_FETCH_STATE <= START_OP; -- Wait, ADH. + else + NEXT_FETCH_STATE <= FETCH_OPERAND; + end if; + when "100" => -- -(An). + if AR_IN_USE = '1' then -- ADH. + NEXT_FETCH_STATE <= START_OP; -- Wait, ADH. + else + NEXT_FETCH_STATE <= CALC_AEFF; + end if; + when "101" => + NEXT_FETCH_STATE <= FETCH_DISPL; + when "110" => + NEXT_FETCH_STATE <= FETCH_EXWORD_1; + when others => -- "111" + if BIW_0(2 downto 0) = "000" then + NEXT_FETCH_STATE <= FETCH_ABS_LO; + elsif BIW_0(2 downto 0) = "001" then + NEXT_FETCH_STATE <= FETCH_ABS_HI; + elsif BIW_0(2 downto 0) = "100" and OP_SIZE_I = LONG then + NEXT_FETCH_STATE <= FETCH_IDATA_B2; + elsif BIW_0(2 downto 0) = "100" then -- Word or byte. + NEXT_FETCH_STATE <= FETCH_IDATA_B1; + elsif BIW_0(2 downto 0) = "010" then + NEXT_FETCH_STATE <= FETCH_DISPL; + else + NEXT_FETCH_STATE <= FETCH_EXWORD_1; + end if; + end case; + when ADDA | BCHG | BCLR | BFCHG | BFCLR | BFEXTS | BFEXTU | BFFFO | BFINS | BFSET | BFTST | BSET | BTST | CHK | CHK2 | CMP2 | CMPA | + DIVS | DIVU | MULS | MULU | MOVEA | MOVE_TO_CCR | MOVE_TO_SR | SUBA => + case BIW_0(5 downto 3) is + when "000" => -- Source is Dn. + if (OP = ADDA or OP = SUBA or OP = CMPA or OP = MOVEA) and (AR_IN_USE = '1' or DR_IN_USE = '1') then -- ADH. + NEXT_FETCH_STATE <= START_OP; + elsif DR_IN_USE = '0' then + NEXT_FETCH_STATE <= INIT_EXEC_WB; + else + NEXT_FETCH_STATE <= START_OP; + end if; + when "001" => -- Valid for ADDA, CMPA, MOVEA, SUBA; source is An. + if AR_IN_USE = '0' then + NEXT_FETCH_STATE <= INIT_EXEC_WB; -- ADH. + else + NEXT_FETCH_STATE <= START_OP; + end if; + when "010" | "011" => -- (An), (An)+. + if AR_IN_USE = '1' then -- ADH. + NEXT_FETCH_STATE <= START_OP; -- Wait, ADH! + else + NEXT_FETCH_STATE <= FETCH_OPERAND; + end if; + when "100" => -- -(An). + if AR_IN_USE = '1' then -- ADH. + NEXT_FETCH_STATE <= START_OP; -- Wait, ADH! + else + NEXT_FETCH_STATE <= CALC_AEFF; + end if; + when "101" => + NEXT_FETCH_STATE <= FETCH_DISPL; + when "110" => + NEXT_FETCH_STATE <= FETCH_EXWORD_1; + when others => -- "111" + if BIW_0(2 downto 0) = "000" then + NEXT_FETCH_STATE <= FETCH_ABS_LO; + elsif BIW_0(2 downto 0) = "001" then + NEXT_FETCH_STATE <= FETCH_ABS_HI; + elsif BIW_0(2 downto 0) = "100" and OP_SIZE_I = LONG then + NEXT_FETCH_STATE <= FETCH_IDATA_B2; + elsif BIW_0(2 downto 0) = "100" then -- Word or Byte. + NEXT_FETCH_STATE <= FETCH_IDATA_B1; + elsif BIW_0(2 downto 0) = "010" then + NEXT_FETCH_STATE <= FETCH_DISPL; + else + NEXT_FETCH_STATE <= FETCH_EXWORD_1; + end if; + end case; + when EXG => + if BIW_0(7 downto 3) = "10001" and (DR_IN_USE = '1' or AR_IN_USE = '1') then + NEXT_FETCH_STATE <= START_OP; -- Wait, ADH. + elsif BIW_0(7 downto 3) = "01000" and DR_IN_USE = '1' then + NEXT_FETCH_STATE <= START_OP; -- Wait, ADH. + elsif BIW_0(7 downto 3) = "01001" and AR_IN_USE = '1' then + NEXT_FETCH_STATE <= START_OP; -- Wait, ADH. + else + NEXT_FETCH_STATE <= INIT_EXEC_WB; + end if; + when NOP => -- Synchronize the instruction pipeline. + if ALU_BSY = '0' and EXEC_WB_STATE = IDLE then + NEXT_FETCH_STATE <= INIT_EXEC_WB; + else + NEXT_FETCH_STATE <= START_OP; + end if; + when MOVE_FROM_CCR | MOVE_FROM_SR => + if ALU_BSY = '0' then + case BIW_0(5 downto 3) is + when "000" => -- Destination is Dn. + if DR_IN_USE = '0' then + NEXT_FETCH_STATE <= INIT_EXEC_WB; + else + NEXT_FETCH_STATE <= START_OP; + end if; + when "010" | "011" | "100" => -- (An), (An)+, -(An). + if AR_IN_USE = '0' then + NEXT_FETCH_STATE <= INIT_EXEC_WB; + else + NEXT_FETCH_STATE <= START_OP; -- Wait, ADH. + end if; + when "101" => + NEXT_FETCH_STATE <= FETCH_DISPL; + when "110" => + NEXT_FETCH_STATE <= FETCH_EXWORD_1; + when others => -- "111" + if BIW_0(2 downto 0) = "000" then + NEXT_FETCH_STATE <= FETCH_ABS_LO; + else + NEXT_FETCH_STATE <= FETCH_ABS_HI; + end if; + end case; + else + NEXT_FETCH_STATE <= START_OP; + end if; + when ASL | ASR | LSL | LSR | ROTL | ROTR | ROXL | ROXR => + if BIW_0(7 downto 6) /= "11" then -- Register shifts. + if DR_IN_USE = '0' then + NEXT_FETCH_STATE <= INIT_EXEC_WB; -- ADH. + else + NEXT_FETCH_STATE <= START_OP; + end if; + else -- Memory shifts. + case BIW_0(5 downto 3) is + when "010" | "011" => -- (An), (An)+. + if AR_IN_USE = '0' then -- ADH. + NEXT_FETCH_STATE <= FETCH_OPERAND; + else + NEXT_FETCH_STATE <= START_OP; + end if; + when "100" => -- -(An). + if AR_IN_USE = '0' then -- ADH. + NEXT_FETCH_STATE <= CALC_AEFF; + else + NEXT_FETCH_STATE <= START_OP; + end if; + when "101" => + NEXT_FETCH_STATE <= FETCH_DISPL; + when "110" => + NEXT_FETCH_STATE <= FETCH_EXWORD_1; + when others => -- "111". + if BIW_0(2 downto 0) = "000" then + NEXT_FETCH_STATE <= FETCH_ABS_LO; + else + NEXT_FETCH_STATE <= FETCH_ABS_HI; + end if; + end case; + end if; + when BKPT => + -- Wait until the bus controller is free to avoid a structural + -- hazard due to the top level function code multiplexer which + -- switches on the CPU_SPACE selector. + if ALU_BSY = '0' then + NEXT_FETCH_STATE <= FETCH_OPERAND; + else + NEXT_FETCH_STATE <= START_OP; + end if; + when CAS2 | CMPM | RTD | RTR | RTS => + if AR_IN_USE = '0' then -- ADH. + NEXT_FETCH_STATE <= FETCH_OPERAND; + else + NEXT_FETCH_STATE <= START_OP; + end if; + when CLR | JMP | JSR | LEA | PEA | Scc => -- No read access required. + case BIW_0(5 downto 3) is + when "000" => -- CLR, Scc. + if DR_IN_USE = '0' then + NEXT_FETCH_STATE <= INIT_EXEC_WB; + else + NEXT_FETCH_STATE <= START_OP; + end if; + when "001" | "010" | "011" | "100" => + if AR_IN_USE = '1' then + NEXT_FETCH_STATE <= START_OP; -- Wait, ADH. + elsif OP = LEA or OP = PEA then + NEXT_FETCH_STATE <= SWITCH_STATE; + else + NEXT_FETCH_STATE <= INIT_EXEC_WB; + end if; + when "101" => + NEXT_FETCH_STATE <= FETCH_DISPL; + when "110" => + NEXT_FETCH_STATE <= FETCH_EXWORD_1; + when others => -- "111" + if BIW_0(2 downto 0) = "000" then + NEXT_FETCH_STATE <= FETCH_ABS_LO; + elsif BIW_0(2 downto 0) = "001" then + NEXT_FETCH_STATE <= FETCH_ABS_HI; + elsif BIW_0(2 downto 0) = "010" then + NEXT_FETCH_STATE <= FETCH_DISPL; + else + NEXT_FETCH_STATE <= FETCH_EXWORD_1; + end if; + end case; + -- + -- The following condition is a special case for the + -- stack manipulating operations JSR and PEA. If A7 + -- is in use, we have to wait in all addressing modes. + if (OP = JSR or OP = PEA) and AR_IN_USE = '1' then + NEXT_FETCH_STATE <= START_OP; -- Wait, ADH. + end if; + when LINK | UNLK => + -- We have to wait for the ALU because the registers are written without pipelining + -- through the ALU and the stack is decremented early. For PEA we have to wait in + -- all addressing modes, if A7 is in use. + if OP = LINK and (ALU_BSY = '1' or AR_IN_USE = '1') then + NEXT_FETCH_STATE <= START_OP; -- Wait, ADH, ASH (two address registers are affected). + elsif OP = UNLK and ALU_BSY = '1' then + NEXT_FETCH_STATE <= START_OP; -- Wait, ADH, ASH (two address registers are affected). + else + NEXT_FETCH_STATE <= SWITCH_STATE; -- Stack pointer is decremented in this state. + end if; + when MOVE => + case BIW_0(5 downto 3) is -- Source operand. + when "000" => -- Dn. + -- Destination is -(An) and will be decremented here, wait. + if BIW_0(8 downto 6) = "100" and (AR_IN_USE = '1' or DR_IN_USE = '1') then + NEXT_FETCH_STATE <= START_OP; + elsif DR_IN_USE = '1' then + NEXT_FETCH_STATE <= START_OP; + else + NEXT_FETCH_STATE <= INIT_EXEC_WB; + end if; + when "001" => -- An. + if AR_IN_USE = '1' then + NEXT_FETCH_STATE <= START_OP; + else + NEXT_FETCH_STATE <= INIT_EXEC_WB; + end if; + when "010" | "011" => -- (An), (An)+. + if AR_IN_USE = '0' then + NEXT_FETCH_STATE <= FETCH_OPERAND; + else + NEXT_FETCH_STATE <= START_OP; + end if; + when "100" => -- -(An). + if AR_IN_USE = '0' then + NEXT_FETCH_STATE <= CALC_AEFF; + else + NEXT_FETCH_STATE <= START_OP; + end if; + when "101" => + NEXT_FETCH_STATE <= FETCH_DISPL; + when "110" => + NEXT_FETCH_STATE <= FETCH_EXWORD_1; + when others => + if BIW_0(2 downto 0) = "000" then + NEXT_FETCH_STATE <= FETCH_ABS_LO; + elsif BIW_0(2 downto 0) = "001" then + NEXT_FETCH_STATE <= FETCH_ABS_HI; + elsif BIW_0(2 downto 0) = "100" and BIW_0(13 downto 12) = "10" then -- Long. + NEXT_FETCH_STATE <= FETCH_IDATA_B2; + elsif BIW_0(2 downto 0) = "100" then -- Word or Byte. + NEXT_FETCH_STATE <= FETCH_IDATA_B1; + elsif BIW_0(2 downto 0) = "010" then + NEXT_FETCH_STATE <= FETCH_DISPL; + else + NEXT_FETCH_STATE <= FETCH_EXWORD_1; + end if; + end case; + when MOVEM => + case BIW_0(5 downto 3) is + when "010" | "011" | "100" => -- (An), (An)+, -(An). + if AR_IN_USE = '1' then -- ADH. + NEXT_FETCH_STATE <= START_OP; + else + NEXT_FETCH_STATE <= INIT_EXEC_WB; + end if; + when "101" => + NEXT_FETCH_STATE <= FETCH_DISPL; + when "110" => + NEXT_FETCH_STATE <= FETCH_EXWORD_1; + when others => + if BIW_0(2 downto 0) = "000" then + NEXT_FETCH_STATE <= FETCH_ABS_LO; + elsif BIW_0(2 downto 0) = "001" then + NEXT_FETCH_STATE <= FETCH_ABS_HI; + elsif BIW_0(2 downto 0) = "010" then + NEXT_FETCH_STATE <= FETCH_DISPL; + else + NEXT_FETCH_STATE <= FETCH_EXWORD_1; + end if; + end case; + when MOVEP => + if AR_IN_USE = '0' and BIW_0(7 downto 6) < "10" then + NEXT_FETCH_STATE <= SWITCH_STATE; -- Memory to register. + elsif AR_IN_USE = '0' and DR_IN_USE = '0' then -- ADH. + NEXT_FETCH_STATE <= SWITCH_STATE; -- Register to memory. + else + NEXT_FETCH_STATE <= START_OP; + end if; + when BSR | MOVE_USP => + -- MOVE_USP: wait until A7 has been updated to load the correct data to the ALU. + -- BSR: wait until A7 has been updated before decrementing. + if AR_IN_USE = '0' then -- ADH. + NEXT_FETCH_STATE <= INIT_EXEC_WB; + else + NEXT_FETCH_STATE <= START_OP; + end if; + when MOVEC => + if BIW_0(0) = '1' and BIW_1(15) = '1' and AR_IN_USE = '1' then -- Address register is source. + NEXT_FETCH_STATE <= START_OP; -- Wait, ADH. + elsif BIW_0(0) = '1' and BIW_1(15) = '0' and DR_IN_USE = '1' then -- Data register is source. + NEXT_FETCH_STATE <= START_OP; -- Wait, ADH. + else + NEXT_FETCH_STATE <= INIT_EXEC_WB; + end if; + when MOVES => + case BIW_0(5 downto 3) is + when "010" | "011" => -- (An), (An)+. + if BIW_1(11) = '0' and AR_IN_USE = '0' then -- ADH. + NEXT_FETCH_STATE <= FETCH_OPERAND; -- Memory to register. + elsif BIW_1(11) = '1' and AR_IN_USE = '0' then -- ADH. + NEXT_FETCH_STATE <= INIT_EXEC_WB; -- Register to memory. + else + NEXT_FETCH_STATE <= START_OP; -- Wait, ADH. + end if; + when "100" => -- -(An). + if BIW_1(11) = '0' and AR_IN_USE = '0' then -- ADH. + NEXT_FETCH_STATE <= CALC_AEFF; -- Memory to register. + elsif BIW_1(11) = '1' and AR_IN_USE = '0' then -- ADH. + NEXT_FETCH_STATE <= INIT_EXEC_WB; -- Register to memory. + else + NEXT_FETCH_STATE <= START_OP; -- Wait, ADH. + end if; + when "101" => + NEXT_FETCH_STATE <= FETCH_DISPL; + when "110" => + NEXT_FETCH_STATE <= FETCH_EXWORD_1; + when others => -- "111" + if BIW_0(2 downto 0) = "000" then + NEXT_FETCH_STATE <= FETCH_ABS_LO; + else + NEXT_FETCH_STATE <= FETCH_ABS_HI; + end if; + end case; + -- Register to memory: + if BIW_1(11) = '1' and BIW_1(15) = '1' and AR_IN_USE = '1' then -- ADH. + NEXT_FETCH_STATE <= START_OP; + elsif BIW_1(11) = '1' and BIW_1(15) = '0' and DR_IN_USE = '1' then -- ADH. + NEXT_FETCH_STATE <= START_OP; + end if; + when ANDI_TO_CCR | ANDI_TO_SR | EORI_TO_CCR | EORI_TO_SR | ORI_TO_CCR | ORI_TO_SR | RESET => + -- Wait until the status register / condition codes have been updated. Otherwise we + -- possibly have a data hazard using the wrong condition codes for the operation. + -- Be aware: for the ANDI_TO_SR, EORI_TO_SR, MOVE_TO_SR and ORI_TOI_SR operations + -- the pipe flush results in automatically aligned condition codes. Nevertheless + -- we need this logic for the respective operations, if the pipe is not flushed, + -- in the case of non changing RAM space. + -- For the RESET: we should not reset in running writeback cycles. + if ALU_BSY = '1' then + NEXT_FETCH_STATE <= START_OP; + else + NEXT_FETCH_STATE <= INIT_EXEC_WB; + end if; + when others => -- Bcc, BRA, STOP, TRAPV. + NEXT_FETCH_STATE <= INIT_EXEC_WB; + end case; + end if; + when FETCH_DISPL => + case OP is + when ADD | CMP | SUB | AND_B | EOR | OR_B => + if (EW_ACK = '1' or EW_RDY = '1') and AR_IN_USE = '0' then -- ADH. + NEXT_FETCH_STATE <= CALC_AEFF; + else + NEXT_FETCH_STATE <= FETCH_DISPL; + end if; + when ADDA | BCHG | BCLR | BFCHG | BFCLR | BFEXTS | BFEXTU | BFFFO | BFINS | BFSET | BFTST | BSET | BTST | CHK | CHK2 | CMP2 | CMPA | DIVS | DIVU | MULS | MULU | MOVE | MOVEA | MOVE_TO_CCR | MOVE_TO_SR | SUBA => + if (EW_ACK = '1' or EW_RDY = '1') and OP = MOVE and PHASE2 = true and AR_IN_USE = '0' then -- ADH. + NEXT_FETCH_STATE <= INIT_EXEC_WB; + elsif (EW_ACK = '1' or EW_RDY = '1') and AR_IN_USE = '0' then -- ADH. + NEXT_FETCH_STATE <= CALC_AEFF; + else + NEXT_FETCH_STATE <= FETCH_DISPL; + end if; + when ADDI | ADDQ | ANDI | CAS | CMPI | EORI | NBCD | NEG | NEGX | NOT_B | ORI | SUBI | SUBQ | TST | TAS | ASL | ASR | LSL | LSR | ROTL | ROTR | ROXL | ROXR => + if (EW_ACK = '1' or EW_RDY = '1') and AR_IN_USE = '0' then -- ADH. + NEXT_FETCH_STATE <= CALC_AEFF; + else + NEXT_FETCH_STATE <= FETCH_DISPL; + end if; + when MOVES => + if (EW_ACK = '1' or EW_RDY = '1') and AR_IN_USE = '0' and BIW_1(11) = '0' then + NEXT_FETCH_STATE <= CALC_AEFF; + elsif (EW_ACK = '1' or EW_RDY = '1') and AR_IN_USE = '0' then + NEXT_FETCH_STATE <= INIT_EXEC_WB; + else + NEXT_FETCH_STATE <= FETCH_DISPL; + end if; + when LEA | PEA => + if (EW_ACK = '1' or EW_RDY = '1') and AR_IN_USE = '0' then -- ADH. + NEXT_FETCH_STATE <= SWITCH_STATE; + else + NEXT_FETCH_STATE <= FETCH_DISPL; + end if; + when others => -- CLR, JMP, JSR, MOVE_FROM_CCR, MOVE_FROM_SR, MOVEM, Scc. + if (EW_ACK = '1' or EW_RDY = '1') and AR_IN_USE = '0' then -- ADH. + NEXT_FETCH_STATE <= INIT_EXEC_WB; + else + NEXT_FETCH_STATE <= FETCH_DISPL; + end if; + end case; + when FETCH_EXWORD_1 => + -- Be aware that the An registers which will be addressed by EXWORD_1 and are used for several addressing modes + -- are valid right after this state (because every address register manipulation requires no more than two clock cycles). + if EW_ACK = '1' and EXT_WORD(8) = '1' and EXT_WORD(5 downto 4) = "11" then -- 32 bit displacement. + NEXT_FETCH_STATE <= FETCH_D_HI; + elsif EW_ACK = '1' and EXT_WORD(8) = '1' and EXT_WORD(5 downto 4) = "10" then -- 16 bit displacement. + NEXT_FETCH_STATE <= FETCH_D_LO; + elsif EW_ACK = '1' and EXT_WORD(8) = '1' and EXT_WORD(5 downto 4) = "00" then -- Reserved. + NEXT_FETCH_STATE <= START_OP; + elsif EW_ACK = '1' and EXT_WORD(8) = '1' and EXT_WORD(1 downto 0) = "11" then + NEXT_FETCH_STATE <= FETCH_OD_HI; -- Long outer displacement. + elsif EW_ACK = '1' and EXT_WORD(8) = '1' and EXT_WORD(1 downto 0) = "10" then + NEXT_FETCH_STATE <= FETCH_OD_LO; -- Word outer displacement. + elsif EW_ACK = '1' and EXT_WORD(8) = '1' and EXT_WORD(1 downto 0) = "01" then + NEXT_FETCH_STATE <= FETCH_MEMADR; -- Null outer displacement, go to intermediate address. + elsif EW_ACK = '1' or EW_RDY = '1' then -- Null displacement, no outer displacement. + case OP is + when ADD | CMP | SUB | AND_B | EOR | OR_B => + if (BIW_1(15) = '0' and AR_IN_USE = '0' and DR_IN_USE = '0') or (BIW_1(15) = '1' and AR_IN_USE = '0') then -- ADH. + NEXT_FETCH_STATE <= CALC_AEFF; + else + NEXT_FETCH_STATE <= FETCH_EXWORD_1; + end if; + when ADDA | BCHG | BCLR | BFCHG | BFCLR | BFEXTS | BFEXTU | BFFFO | BFINS | BFSET | BFTST | BSET | BTST | CHK | CHK2 | CMP2 | CMPA | DIVS | DIVU | MULS | MULU | MOVE | MOVEA | MOVE_TO_CCR | MOVE_TO_SR | SUBA => + if OP = MOVE and PHASE2 = true and BIW_1(15) = '0' and AR_IN_USE = '0' and DR_IN_USE = '0' then -- ADH. + NEXT_FETCH_STATE <= INIT_EXEC_WB; + elsif OP = MOVE and PHASE2 = true and BIW_1(15) = '1' and AR_IN_USE = '0' then -- ADH. + NEXT_FETCH_STATE <= INIT_EXEC_WB; + elsif (BIW_1(15) = '0' and AR_IN_USE = '0' and DR_IN_USE = '0') or (BIW_1(15) = '1' and AR_IN_USE = '0') then -- ADH. + NEXT_FETCH_STATE <= CALC_AEFF; + else + NEXT_FETCH_STATE <= FETCH_EXWORD_1; + end if; + when MOVES => + if (BIW_1(15) = '0' and AR_IN_USE = '0' and DR_IN_USE = '0') or (BIW_1(15) = '1' and AR_IN_USE = '0') then -- ADH. + if BIW_1(11) = '0' then + NEXT_FETCH_STATE <= CALC_AEFF; + else + NEXT_FETCH_STATE <= INIT_EXEC_WB; + end if; + else + NEXT_FETCH_STATE <= FETCH_EXWORD_1; + end if; + when ADDI | ADDQ | ANDI | CAS | CMPI | EORI | NBCD | NEG | NEGX | NOT_B | ORI | SUBI | SUBQ | TST | TAS | ASL | ASR | LSL | LSR | ROTL | ROTR | ROXL | ROXR => + if (BIW_1(15) = '0' and AR_IN_USE = '0' and DR_IN_USE = '0') or (BIW_1(15) = '1' and AR_IN_USE = '0') then -- ADH. + NEXT_FETCH_STATE <= CALC_AEFF; + else + NEXT_FETCH_STATE <= FETCH_EXWORD_1; + end if; + when LEA | PEA => + if (BIW_1(15) = '0' and AR_IN_USE = '0' and DR_IN_USE = '0') or (BIW_1(15) = '1' and AR_IN_USE = '0') then -- ADH. + NEXT_FETCH_STATE <= SWITCH_STATE; + else + NEXT_FETCH_STATE <= FETCH_EXWORD_1; + end if; + when others => -- CLR, JMP, JSR, MOVE_FROM_CCR, MOVE_FROM_SR, MOVEM, Scc. + if (BIW_1(15) = '0' and AR_IN_USE = '0' and DR_IN_USE = '0') or (BIW_1(15) = '1' and AR_IN_USE = '0') then -- ADH. + NEXT_FETCH_STATE <= INIT_EXEC_WB; + else + NEXT_FETCH_STATE <= FETCH_EXWORD_1; + end if; + end case; + else + NEXT_FETCH_STATE <= FETCH_EXWORD_1; + end if; + when FETCH_D_HI => + if EW_ACK = '1' then + NEXT_FETCH_STATE <= FETCH_D_LO; + else + NEXT_FETCH_STATE <= FETCH_D_HI; + end if; + when FETCH_D_LO => + if EW_ACK = '1' and OD_REQ_32 = '1' then + NEXT_FETCH_STATE <= FETCH_OD_HI; + elsif EW_ACK = '1' and OD_REQ_16 = '1' then + NEXT_FETCH_STATE <= FETCH_OD_LO; + elsif EW_ACK = '1' and MEM_INDIRECT = '1' then -- Null displacement. + NEXT_FETCH_STATE <= FETCH_MEMADR; + elsif EW_ACK = '1' or EW_RDY = '1' then + case OP is + when ADD | CMP | SUB | AND_B | EOR | OR_B => + if AR_IN_USE = '0' then -- ADH. + NEXT_FETCH_STATE <= CALC_AEFF; + else + NEXT_FETCH_STATE <= FETCH_D_LO; + end if; + when ADDA | BCHG | BCLR | BFCHG | BFCLR | BFEXTS | BFEXTU | BFFFO | BFINS | BFSET | BFTST | BSET | BTST | CHK | CHK2| CMP2 | CMPA | DIVS | DIVU | MULS | MULU | MOVE | MOVEA | MOVE_TO_CCR | MOVE_TO_SR | SUBA => + if OP = MOVE and PHASE2 = true and AR_IN_USE = '0' then -- ADH. + NEXT_FETCH_STATE <= INIT_EXEC_WB; + elsif AR_IN_USE = '0' then -- ADH. + NEXT_FETCH_STATE <= CALC_AEFF; + else + NEXT_FETCH_STATE <= FETCH_D_LO; + end if; + when MOVES => + if AR_IN_USE = '1' then -- ADH. + NEXT_FETCH_STATE <= FETCH_D_LO; -- Wait, ADH. + elsif BIW_1(11) = '0' then + NEXT_FETCH_STATE <= CALC_AEFF; + else + NEXT_FETCH_STATE <= INIT_EXEC_WB; + end if; + when ADDI | ADDQ | ANDI | CAS | CMPI | EORI | NBCD | NEG | NEGX | NOT_B | ORI | SUBI | SUBQ | TST | TAS | ASL | ASR | LSL | LSR | ROTL | ROTR | ROXL | ROXR => + if AR_IN_USE = '0' then -- ADH. + NEXT_FETCH_STATE <= CALC_AEFF; + else + NEXT_FETCH_STATE <= FETCH_D_LO; + end if; + when LEA | PEA => + if AR_IN_USE = '0' then -- ADH. + NEXT_FETCH_STATE <= SWITCH_STATE; + else + NEXT_FETCH_STATE <= FETCH_D_LO; + end if; + when others => -- CLR, JMP, JSR, MOVE_FROM_CCR, MOVE_FROM_SR, MOVEM, Scc. + if AR_IN_USE = '0' then -- ADH. + NEXT_FETCH_STATE <= INIT_EXEC_WB; + else + NEXT_FETCH_STATE <= FETCH_D_LO; + end if; + end case; + else + NEXT_FETCH_STATE <= FETCH_D_LO; + end if; + when FETCH_OD_HI => + if EW_ACK = '1' then + NEXT_FETCH_STATE <= FETCH_OD_LO; + else + NEXT_FETCH_STATE <= FETCH_OD_HI; + end if; + when FETCH_OD_LO => + if EW_ACK = '1' then + NEXT_FETCH_STATE <= FETCH_MEMADR; + else + NEXT_FETCH_STATE <= FETCH_OD_LO; + end if; + when FETCH_MEMADR => + if RD_RDY = '1' or MEMADR_RDY = '1' then + case OP is + when ADD | CMP | SUB | AND_B | EOR | OR_B => + if AR_IN_USE = '0' then -- ADH. + NEXT_FETCH_STATE <= CALC_AEFF; + else + NEXT_FETCH_STATE <= FETCH_MEMADR; + end if; + when ADDA | BCHG | BCLR | BFCHG | BFCLR | BFEXTS | BFEXTU | BFFFO | BFINS | BFSET | BFTST | BSET | BTST | CHK | CHK2| CMP2 | CMPA | DIVS | DIVU | MULS | MULU | MOVE | MOVEA | MOVE_TO_CCR | MOVE_TO_SR | SUBA => + if OP = MOVE and PHASE2 = true and AR_IN_USE = '0' then -- ADH. + NEXT_FETCH_STATE <= INIT_EXEC_WB; + elsif AR_IN_USE = '0' then -- ADH. + NEXT_FETCH_STATE <= CALC_AEFF; + else + NEXT_FETCH_STATE <= FETCH_MEMADR; + end if; + when MOVES => + if AR_IN_USE = '1' then -- ADH. + NEXT_FETCH_STATE <= FETCH_MEMADR; -- Wait, ADH. + elsif BIW_1(11) = '0' then + NEXT_FETCH_STATE <= CALC_AEFF; + else + NEXT_FETCH_STATE <= INIT_EXEC_WB; + end if; + when ADDI | ADDQ | ANDI | CAS | CMPI | EORI | NBCD | NEG | NEGX | NOT_B | ORI | SUBI | SUBQ | TST | TAS | ASL | ASR | LSL | LSR | ROTL | ROTR | ROXL | ROXR => + if AR_IN_USE = '0' then -- ADH. + NEXT_FETCH_STATE <= CALC_AEFF; + else + NEXT_FETCH_STATE <= FETCH_MEMADR; + end if; + when LEA | PEA => + if AR_IN_USE = '0' then -- ADH. + NEXT_FETCH_STATE <= SWITCH_STATE; + else + NEXT_FETCH_STATE <= FETCH_MEMADR; + end if; + when others => -- CLR, JMP, JSR, MOVE_FROM_CCR, MOVE_FROM_SR, MOVEM, Scc. + if AR_IN_USE = '0' then -- ADH. + NEXT_FETCH_STATE <= INIT_EXEC_WB; + else + NEXT_FETCH_STATE <= FETCH_MEMADR; + end if; + end case; + else + NEXT_FETCH_STATE <= FETCH_MEMADR; + end if; + when FETCH_ABS_HI => + if EW_ACK = '1' then + NEXT_FETCH_STATE <= FETCH_ABS_LO; + else + NEXT_FETCH_STATE <= FETCH_ABS_HI; + end if; + when FETCH_ABS_LO => + if EW_ACK = '1' then + case OP is + when CLR | JMP | JSR | MOVE_FROM_CCR | MOVE_FROM_SR | MOVEM | Scc => + NEXT_FETCH_STATE <= INIT_EXEC_WB; + when LEA | PEA => + NEXT_FETCH_STATE <= SWITCH_STATE; + when MOVE => + if PHASE2 = false then + NEXT_FETCH_STATE <= CALC_AEFF; + else + NEXT_FETCH_STATE <= INIT_EXEC_WB; + end if; + when MOVES => + if BIW_1(11) = '0' then + NEXT_FETCH_STATE <= CALC_AEFF; + else + NEXT_FETCH_STATE <= INIT_EXEC_WB; + end if; + when others => + NEXT_FETCH_STATE <= CALC_AEFF; + end case; + else + NEXT_FETCH_STATE <= FETCH_ABS_LO; + end if; + when FETCH_IDATA_B2 => + if EW_ACK = '1' then + NEXT_FETCH_STATE <= FETCH_IDATA_B1; + else + NEXT_FETCH_STATE <= FETCH_IDATA_B2; + end if; + when FETCH_IDATA_B1 => + if EW_ACK = '1' or EW_RDY = '1' then + case OP is -- ADH. + when ADD | SUB | AND_B | OR_B | BTST | DIVS | DIVU | MULS | MULU | CHK | MOVE => + NEXT_FETCH_STATE <= SWITCH_STATE; + when ADDA | CMPA | SUBA | MOVEA => + NEXT_FETCH_STATE <= SWITCH_STATE; + when others => + if DR_IN_USE = '1' then -- ADH. + NEXT_FETCH_STATE <= FETCH_IDATA_B1; + else + NEXT_FETCH_STATE <= INIT_EXEC_WB; + end if; + end case; + else + NEXT_FETCH_STATE <= FETCH_IDATA_B1; + end if; + when CALC_AEFF => + NEXT_FETCH_STATE <= FETCH_OPERAND; -- One CLK calculation delay. + when FETCH_OPERAND => + if RD_RDY = '1' then + case OP is + when ABCD | ADDX | SBCD | SUBX => + if PHASE2 = false then + NEXT_FETCH_STATE <= CALC_AEFF; + else + NEXT_FETCH_STATE <= INIT_EXEC_WB; + end if; + when ADD | CMP | CHK | SUB | AND_B | EOR | OR_B | BCHG | BCLR | BSET | BTST | DIVS | DIVU | MULS | MULU => + if DR_IN_USE = '1' then + NEXT_FETCH_STATE <= SWITCH_STATE; + else + NEXT_FETCH_STATE <= INIT_EXEC_WB; + end if; + when ADDA | CMPA | SUBA => + if BIW_0(11 downto 9) = BIW_0(2 downto 0) and ADR_MODE_I = "011" then + NEXT_FETCH_STATE <= SWITCH_STATE; -- Postincrement (Ax)+, AX; wait before loading the ALU. + else + NEXT_FETCH_STATE <= INIT_EXEC_WB; + end if; + when BFCHG | BFCLR | BFEXTS | BFEXTU | BFFFO | BFINS | BFSET | BFTST => + if BF_BYTES = 5 then -- Another Byte required. + NEXT_FETCH_STATE <= CALC_AEFF; + else + NEXT_FETCH_STATE <= INIT_EXEC_WB; + end if; + when MOVE => + if BIW_0(8 downto 6) = "100" and ADR_MODE_I = "011" then -- (An)+,-(An). + NEXT_FETCH_STATE <= SWITCH_STATE; + else + NEXT_FETCH_STATE <= INIT_EXEC_WB; + end if; + when others => + NEXT_FETCH_STATE <= INIT_EXEC_WB; + end case; + else + NEXT_FETCH_STATE <= FETCH_OPERAND; + end if; + when SWITCH_STATE => -- This state is used individually by several operations. + case OP is + when ADDA | CMPA | SUBA | MOVEA => -- Address register operations. + if AR_IN_USE = '0' then + NEXT_FETCH_STATE <= INIT_EXEC_WB; + else + NEXT_FETCH_STATE <= SWITCH_STATE; + end if; + when LEA | LINK | MOVE => + -- LEA: calculate effective address (1 clock cycle) load it in INIT_EXEC_WB. + -- LINK: used to load the decremented stack pointer. + -- MOVE: Used for (An)+,-(An). address mode. + NEXT_FETCH_STATE <= INIT_EXEC_WB; + when UNLK => -- SP is updated here. + NEXT_FETCH_STATE <= CALC_AEFF; + when MOVEM => -- MOVEM requires 1 CLK cycle for address calculation. + if MOVEM_COND = false then + NEXT_FETCH_STATE <= INIT_EXEC_WB; -- Cancel bus access. + else + NEXT_FETCH_STATE <= CALC_AEFF; + end if; + when MOVEP => -- Register select and displacement update. + if DR_IN_USE = '0' and BIW_0(7 downto 6) < "10" then + NEXT_FETCH_STATE <= CALC_AEFF; + elsif DR_IN_USE = '0' and ALU_BSY = '0' then -- ASH. + NEXT_FETCH_STATE <= INIT_EXEC_WB; -- Register to memory. + else + NEXT_FETCH_STATE <= SWITCH_STATE; + end if; + when PEA => + -- PEA requires two clock cycles here for effective adress calculation because it + -- is loaded early. The first clock cycle the address becomes valid and after the + -- second the address is loaded to the ALU for writing on the stack. + if PHASE2 = false then + NEXT_FETCH_STATE <= SWITCH_STATE; + else + NEXT_FETCH_STATE <= INIT_EXEC_WB; + end if; + when others => -- Data register operations. + if DR_IN_USE = '0' then + NEXT_FETCH_STATE <= INIT_EXEC_WB; + else + NEXT_FETCH_STATE <= SWITCH_STATE; + end if; + end case; + when INIT_EXEC_WB => + case OP is + when ANDI_TO_SR | EORI_TO_SR | MOVE_TO_SR | ORI_TO_SR => + if ALU_BSY = '0' and BRANCH_ATN = '1' then + NEXT_FETCH_STATE <= SLEEP; -- Wait for new processor context. + elsif ALU_BSY = '0' then + NEXT_FETCH_STATE <= START_OP; -- Proceed normally. + else + NEXT_FETCH_STATE <= INIT_EXEC_WB; + end if; + when Bcc | CHK | DBcc | JMP | TRAPcc | TRAPV => + if ALU_BSY = '0' then + NEXT_FETCH_STATE <= SLEEP; -- Check conditions. + else + NEXT_FETCH_STATE <= INIT_EXEC_WB; + end if; + when CAS | JSR | MOVEC | TAS => + -- CAS, TAS provide a RMC operation so have to sleep a little bit ;-) + if ALU_BSY = '0' then + NEXT_FETCH_STATE <= SLEEP; + else + NEXT_FETCH_STATE <= INIT_EXEC_WB; + end if; + when BRA | BSR | RTD | RTS => + if ALU_BSY = '0' then + NEXT_FETCH_STATE <= START_OP; + else + NEXT_FETCH_STATE <= INIT_EXEC_WB; + end if; + when BFCHG | BFCLR | BFINS | BFSET => + if ALU_BSY = '0' and BF_BYTES < 5 then + NEXT_FETCH_STATE <= START_OP; + elsif ALU_BSY = '0' then + NEXT_FETCH_STATE <= SLEEP; + else + NEXT_FETCH_STATE <= INIT_EXEC_WB; -- Wait, ASH. + end if; + when CAS2 => -- RMC operation. + if ALU_BSY = '0' and PHASE2 = false then + NEXT_FETCH_STATE <= CALC_AEFF; -- Second compare. + elsif ALU_BSY = '0' then + NEXT_FETCH_STATE <= SLEEP; + else + NEXT_FETCH_STATE <= INIT_EXEC_WB; + end if; + when CHK2 => + if ALU_BSY = '0' and PHASE2 = false then + NEXT_FETCH_STATE <= FETCH_OPERAND; -- Second compare required? + elsif ALU_BSY = '0' then -- ASH. + NEXT_FETCH_STATE <= SLEEP; + else + NEXT_FETCH_STATE <= INIT_EXEC_WB; + end if; + when CMP2 | CMPM => + if ALU_BSY = '0' and PHASE2 = false then + NEXT_FETCH_STATE <= FETCH_OPERAND; -- Second compare required? + elsif ALU_BSY = '0' then -- ASH. + NEXT_FETCH_STATE <= START_OP; + else + NEXT_FETCH_STATE <= INIT_EXEC_WB; + end if; + when MOVE_USP => + if ALU_BSY = '0' and BIW_0(3) = '0' then -- An to USP. + NEXT_FETCH_STATE <= SLEEP; + elsif ALU_BSY = '0' then + NEXT_FETCH_STATE <= START_OP; -- USP to An. + else + NEXT_FETCH_STATE <= INIT_EXEC_WB; + end if; + when MOVE => + if ALU_BSY = '0' and PHASE2 = false then -- Load the Operand into the ALU here. + case BIW_0(8 downto 6) is -- Destination operand. + when "101" => + NEXT_FETCH_STATE <= FETCH_DISPL; + when "110" => + NEXT_FETCH_STATE <= FETCH_EXWORD_1; + when "111" => + if BIW_0(11 downto 9) = "000" then + NEXT_FETCH_STATE <= FETCH_ABS_LO; + else + NEXT_FETCH_STATE <= FETCH_ABS_HI; + end if; + when others => -- No destination address calculation required. + NEXT_FETCH_STATE <= START_OP; + end case; + elsif PHASE2 = true then -- ALU is not required at this point. + NEXT_FETCH_STATE <= START_OP; + else + NEXT_FETCH_STATE <= INIT_EXEC_WB; + end if; + when MOVEM => + if ALU_BSY = '0' and BIW_0(10) = '0' and ADR_MODE_I = "100" and MOVEM_PNTR = x"0" then -- -(An), register to memory. + NEXT_FETCH_STATE <= SLEEP; -- Data completely transfered to the ALU. + elsif ALU_BSY = '0' and BIW_0(10) = '0' and ADR_MODE_I /= "100" and MOVEM_PNTR = x"F" then -- Register to memory + NEXT_FETCH_STATE <= SLEEP; -- Data completely transfered to the ALU. + elsif ALU_BSY = '0' and BIW_0(10) = '1' and MOVEM_PNTR = x"F" then -- Memory to register. + NEXT_FETCH_STATE <= SLEEP; -- Data completely transfered to the ALU. + elsif ALU_BSY = '0' and BIW_0(10) = '1' then -- Memory to register. + NEXT_FETCH_STATE <= SWITCH_STATE; + else + NEXT_FETCH_STATE <= INIT_EXEC_WB; -- Register to memory. + end if; + when MOVEP => + if ALU_BSY = '0' and MOVEP_PNTR_I = 0 then + NEXT_FETCH_STATE <= START_OP; -- Ready. + elsif ALU_BSY = '0' and BIW_0(7 downto 6) < "10" then + NEXT_FETCH_STATE <= CALC_AEFF; -- Memory to register. + else + NEXT_FETCH_STATE <= INIT_EXEC_WB; -- Register to memory. + end if; + when NOP => + if ALU_BSY = '1' then -- ASH. + NEXT_FETCH_STATE <= INIT_EXEC_WB; -- Wait for all pending bus cycles to be completed. + else + NEXT_FETCH_STATE <= START_OP; + end if; + when RTR => + if ALU_BSY = '0' and PHASE2 = false then + NEXT_FETCH_STATE <= CALC_AEFF; + elsif ALU_BSY = '0' and PHASE2 = true then + NEXT_FETCH_STATE <= START_OP; + else + NEXT_FETCH_STATE <= INIT_EXEC_WB; + end if; + when STOP => + if ALU_BSY = '0' then -- ASH. + NEXT_FETCH_STATE <= SLEEP; + else + NEXT_FETCH_STATE <= INIT_EXEC_WB; + end if; + when UNLK => + if ALU_BSY = '0' and AR_IN_USE = '0' then -- ADH, ASH. + NEXT_FETCH_STATE <= START_OP; + else + NEXT_FETCH_STATE <= INIT_EXEC_WB; + end if; + when others => + if ALU_BSY = '0' then -- ASH. + NEXT_FETCH_STATE <= START_OP; + else + NEXT_FETCH_STATE <= INIT_EXEC_WB; -- ASH. + end if; + end case; + when SLEEP => + case OP is + when ANDI_TO_SR | CAS | CAS2 | EORI_TO_SR | MOVE_TO_SR | MOVEM | ORI_TO_SR | TAS => + -- CAS, CAS2 and TAS are a read modify write instructions. + -- MOVEM: wait until last register is written to avoid data hazards + -- because the ADR_IN_USE, AR_IN__USE and DR_IN_USE does not + -- work for MOVEM (several registers in use). + -- TAS is a read modify write instruction. + -- _TO_SR instructions wait for the change of the SBIT + -- and so for a new processor context. + if NEXT_EXEC_WB_STATE = IDLE then + NEXT_FETCH_STATE <= START_OP; + else + NEXT_FETCH_STATE <= SLEEP; + end if; + when BFCHG | BFCLR | BFINS | BFSET => + if EXEC_WB_STATE = WRITE_DEST and WR_RDY = '1' and BF_BYTES = 1 then + -- Wait until second writeback access has been processed. + NEXT_FETCH_STATE <= START_OP; + else + NEXT_FETCH_STATE <= SLEEP; + end if; + when JSR => + if PHASE2 = false then + NEXT_FETCH_STATE <= SLEEP; -- Wait for address calculation. + else + NEXT_FETCH_STATE <= START_OP; + end if; + when MOVE_USP | MOVEC => + -- MOVE_USP: wait for writeback not to conflict with AR_DEC in START_OP. + if NEXT_EXEC_WB_STATE = IDLE then + NEXT_FETCH_STATE <= START_OP; + else + NEXT_FETCH_STATE <= SLEEP; -- Wait for new processor context. + end if; + when DBcc => + -- DBcc: evaluate conditions. + if NEXT_EXEC_WB_STATE = IDLE then + NEXT_FETCH_STATE <= START_OP; + else + NEXT_FETCH_STATE <= SLEEP; + end if; + when STOP => + if TRACE_MODE /= "00" then + NEXT_FETCH_STATE <= START_OP; -- Do not perform a stop while tracing. + elsif EXH_REQ = '1' then + NEXT_FETCH_STATE <= START_OP; -- Wait on interrupt. + else + NEXT_FETCH_STATE <= SLEEP; + end if; + when others => -- Bcc, CHK, JMP, TRAPV. + -- Bcc: evaluate conditions. + -- CHK: use SWITCH_STATE for TRAP evaluation. + -- CHK2: use SWITCH_STATE for TRAP evaluation. + -- JMP: wait for address calculation. + -- TRAPV: check conditions. + NEXT_FETCH_STATE <= START_OP; + end case; + end case; + end process FETCH_DEC; + + EXEC_WB_DEC: process(ALU_COND, ALU_INIT_I, ALU_REQ, BIW_0_WB, BIW_1_WB, BF_BYTES, EXEC_WB_STATE, FETCH_STATE, MOVEM_INH_WR, OP_WB_I, PHASE2, WR_RDY) + begin + case EXEC_WB_STATE is + when IDLE => + if ALU_INIT_I = '1' then + NEXT_EXEC_WB_STATE <= EXECUTE; + else + NEXT_EXEC_WB_STATE <= IDLE; + end if; + when EXECUTE => + if ALU_REQ = '1' then + case OP_WB_I is + when ABCD | SBCD | ADDX | SUBX | PACK | UNPK => + if BIW_0_WB(3) = '0' then -- Register to register. + NEXT_EXEC_WB_STATE <= WRITEBACK; + else -- Memory to memory. + NEXT_EXEC_WB_STATE <= WRITE_DEST; + end if; + when ADD | SUB | AND_B | OR_B => + if BIW_0_WB(8) = '0' then + NEXT_EXEC_WB_STATE <= WRITEBACK; -- Destination is register. + else + NEXT_EXEC_WB_STATE <= WRITE_DEST; -- Destination is in memory. + end if; + when ADDA | SUBA | ANDI_TO_SR | BFEXTS | BFEXTU | BFFFO | DIVS | DIVU | EORI_TO_SR | EXG | EXT | EXTB | + LEA | MOVE_TO_CCR | MOVE_TO_SR | MOVE_USP | MOVEA | MOVEC | MOVEQ | MULS | MULU | ORI_TO_SR | STOP | SWAP | UNLK => + NEXT_EXEC_WB_STATE <= WRITEBACK; + when ADDI | ADDQ | ANDI | BCHG | BCLR | BFCHG | BFCLR | BFINS | BFSET | BSET | CLR | EOR | EORI | + MOVE_FROM_CCR | MOVE_FROM_SR | NBCD | NEG | NEGX | NOT_B | ORI | Scc | SUBI | SUBQ | TAS => + if BIW_0_WB(5 downto 3) = "000" then + NEXT_EXEC_WB_STATE <= WRITEBACK; -- Destination is a data register. + elsif BIW_0_WB(5 downto 3) = "001" then -- Valid for ADDQ and SUBQ. + NEXT_EXEC_WB_STATE <= WRITEBACK; -- Destination is an address register. + else + NEXT_EXEC_WB_STATE <= WRITE_DEST; -- Destination is in memory. + end if; + when ASL | ASR | LSL | LSR | ROTL | ROTR | ROXL | ROXR => + if BIW_0_WB(7 downto 6) /= "11" then + NEXT_EXEC_WB_STATE <= WRITEBACK; -- Register shifts. + else + NEXT_EXEC_WB_STATE <= WRITE_DEST; -- Memory shifts. + end if; + when CAS => + if ALU_COND = false then + NEXT_EXEC_WB_STATE <= WRITEBACK; -- Update Dc. + else + NEXT_EXEC_WB_STATE <= WRITE_DEST; -- Update destination. + end if; + when CAS2 => + if FETCH_STATE = FETCH_OPERAND then + NEXT_EXEC_WB_STATE <= IDLE; -- Second read access. + elsif ALU_COND = false then + NEXT_EXEC_WB_STATE <= WRITEBACK; -- Update Dc. + else + NEXT_EXEC_WB_STATE <= ADR_PIPELINE; -- Update destination. + end if; + when DBcc => + if ALU_COND = true then + NEXT_EXEC_WB_STATE <= IDLE; + else + NEXT_EXEC_WB_STATE <= WRITEBACK; + end if; + when MOVE => + if BIW_0_WB(8 downto 6) = "000" then + NEXT_EXEC_WB_STATE <= WRITEBACK; -- Destination is register. + elsif PHASE2 = false then + NEXT_EXEC_WB_STATE <= WRITE_DEST; -- Destination is in memory. + else + NEXT_EXEC_WB_STATE <= EXECUTE; -- Wait for PHASE2 address calculation. + end if; + when BSR | JSR | LINK | PEA => + NEXT_EXEC_WB_STATE <= WRITE_DEST; + when MOVEM => + if OP_WB_I = MOVEM and MOVEM_INH_WR = true then + NEXT_EXEC_WB_STATE <= IDLE; -- Discard the write cycle. + elsif BIW_0_WB(10) = '1' then + NEXT_EXEC_WB_STATE <= WRITEBACK; -- Destination is register. + else + NEXT_EXEC_WB_STATE <= WRITE_DEST; -- Destination is in memory. + end if; + when MOVEP => + if BIW_0_WB(7 downto 6) < "10" then + NEXT_EXEC_WB_STATE <= WRITEBACK; -- Memory to register. + else + NEXT_EXEC_WB_STATE <= WRITE_DEST; -- Register to memory. + end if; + when MOVES => + if BIW_1_WB(11) = '0' then + NEXT_EXEC_WB_STATE <= WRITEBACK; -- Destination is register. + else + NEXT_EXEC_WB_STATE <= WRITE_DEST; -- Destination is in memory. + end if; + -- Default is for: + -- ANDI_TO_CCR, Bcc, BFTST, BTST, CHK, CHK2, + -- CMP, CMP2, CMPA, CMPI, CMPM, EORI_TO_CCR, + -- ORI_TO_CCR, RTR, TRAPV, TST. + when others => + NEXT_EXEC_WB_STATE <= IDLE; + end case; + else + NEXT_EXEC_WB_STATE <= EXECUTE; + end if; + when ADR_PIPELINE => -- Effective address calculation takes one clock cycle. + NEXT_EXEC_WB_STATE <= WRITE_DEST; + when WRITEBACK => + case OP_WB_I is + when CAS2 => + if PHASE2 = false then + NEXT_EXEC_WB_STATE <= WRITEBACK; -- Update Dc2 + else + NEXT_EXEC_WB_STATE <= IDLE; + end if; + when others => + NEXT_EXEC_WB_STATE <= IDLE; + end case; + when WRITE_DEST => + if WR_RDY = '1' then + case OP_WB_I is + when BFCHG | BFCLR | BFINS | BFSET => + if BF_BYTES <= 4 then + NEXT_EXEC_WB_STATE <= IDLE; + else + NEXT_EXEC_WB_STATE <= ADR_PIPELINE; + end if; + when CAS2 => + if PHASE2 = false then + NEXT_EXEC_WB_STATE <= WRITE_DEST; -- Update destination 2. + else + NEXT_EXEC_WB_STATE <= IDLE; + end if; + when others => NEXT_EXEC_WB_STATE <= IDLE; + end case; + else + NEXT_EXEC_WB_STATE <= WRITE_DEST; + end if; + end case; + end process EXEC_WB_DEC; +end BEHAVIOUR; diff --git a/common/CPU/68K30L/wf68k30L_data_registers.vhd b/common/CPU/68K30L/wf68k30L_data_registers.vhd new file mode 100644 index 00000000..b41a201a --- /dev/null +++ b/common/CPU/68K30L/wf68k30L_data_registers.vhd @@ -0,0 +1,137 @@ +------------------------------------------------------------------------ +---- ---- +---- WF68K30L IP Core: Data register logic. ---- +---- ---- +---- Description: ---- +---- These are the eight data registers. The logic provides two ---- +---- read and two write ports providing simultaneos access. For ---- +---- more information refer to the MC68030 User' Manual. ---- +---- ---- +---- Author(s): ---- +---- - Wolfgang Foerster, wf@experiment-s.de; wf@inventronik.de ---- +---- ---- +------------------------------------------------------------------------ +---- ---- +---- Copyright 2014-2019 Wolfgang Foerster Inventronik GmbH. ---- +---- ---- +---- This documentation describes Open Hardware and is licensed ---- +---- under the CERN OHL v. 1.2. You may redistribute and modify ---- +---- this documentation under the terms of the CERN OHL v.1.2. ---- +---- (http://ohwr.org/cernohl). This documentation is distributed ---- +---- WITHOUT ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING OF ---- +---- MERCHANTABILITY, SATISFACTORY QUALITY AND FITNESS FOR A ---- +---- PARTICULAR PURPOSE. Please see the CERN OHL v.1.2 for ---- +---- applicable conditions ---- +---- ---- +------------------------------------------------------------------------ +-- +-- Revision History +-- +-- Revision 2K14B 20141201 WF +-- Initial Release. +-- + +library work; +use work.WF68K30L_PKG.all; + +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_unsigned.all; + +entity WF68K30L_DATA_REGISTERS is + port ( + CLK : in std_logic; + RESET : in bit; + + -- Data lines: + DR_IN_1 : in std_logic_vector(31 downto 0); + DR_IN_2 : in std_logic_vector(31 downto 0); + DR_OUT_1 : out std_logic_vector(31 downto 0); + DR_OUT_2 : out std_logic_vector(31 downto 0); + + -- Registers controls: + DR_SEL_WR_1 : in std_logic_vector(2 downto 0); + DR_SEL_WR_2 : in std_logic_vector(2 downto 0); + DR_SEL_RD_1 : in std_logic_vector(2 downto 0); + DR_SEL_RD_2 : in std_logic_vector(2 downto 0); + DR_WR_1 : in bit; + DR_WR_2 : in bit; + DR_MARK_USED : in bit; + USE_DPAIR : in boolean; + DR_IN_USE : out bit; + UNMARK : in bit; + + OP_SIZE : in OP_SIZETYPE + ); +end entity WF68K30L_DATA_REGISTERS; + +architecture BEHAVIOUR of WF68K30L_DATA_REGISTERS is +type DR_TYPE is array(0 to 7) of std_logic_vector(31 downto 0); +signal DR : DR_TYPE; -- Data registers D0 to D7. +signal DR_PNTR_WR_1 : integer range 0 to 7; +signal DR_PNTR_WR_2 : integer range 0 to 7; +signal DR_PNTR_RD_1 : integer range 0 to 7; +signal DR_PNTR_RD_2 : integer range 0 to 7; +signal DR_SEL_WR_I1 : std_logic_vector(2 downto 0); +signal DR_SEL_WR_I2 : std_logic_vector(2 downto 0); +signal DR_USED_1 : std_logic_vector(3 downto 0); +signal DR_USED_2 : std_logic_vector(3 downto 0); +begin + INBUFFER: process + begin + wait until CLK = '1' and CLK' event; + if DR_MARK_USED = '1' then + DR_SEL_WR_I1 <= DR_SEL_WR_1; + DR_SEL_WR_I2 <= DR_SEL_WR_2; + end if; + end process INBUFFER; + + DR_PNTR_WR_1 <= conv_integer(DR_SEL_WR_I1); + DR_PNTR_WR_2 <= conv_integer(DR_SEL_WR_I2); + DR_PNTR_RD_1 <= conv_integer(DR_SEL_RD_1); + DR_PNTR_RD_2 <= conv_integer(DR_SEL_RD_2); + + P_IN_USE: process + begin + wait until CLK = '1' and CLK' event; + if RESET = '1' or UNMARK = '1' then + DR_USED_1(3) <= '0'; + DR_USED_2(3) <= '0'; + elsif DR_MARK_USED = '1' then + DR_USED_1 <= '1' & DR_SEL_WR_1; + if USE_DPAIR = true then + DR_USED_2 <= '1' & DR_SEL_WR_2; + end if; + end if; + end process P_IN_USE; + + DR_IN_USE <= '1' when DR_USED_1(3) = '1' and DR_USED_1(2 downto 0) = DR_SEL_RD_1 else + '1' when DR_USED_1(3) = '1' and DR_USED_1(2 downto 0) = DR_SEL_RD_2 else + '1' when DR_USED_2(3) = '1' and DR_USED_2(2 downto 0) = DR_SEL_RD_1 else + '1' when DR_USED_2(3) = '1' and DR_USED_2(2 downto 0) = DR_SEL_RD_2 else '0'; + + DR_OUT_1 <= DR(DR_PNTR_RD_1); + DR_OUT_2 <= DR(DR_PNTR_RD_2); + + REGISTERS: process + begin + wait until CLK = '1' and CLK' event; + if RESET = '1' then + DR <= (others => (others => '0')); + end if; + if DR_WR_1 = '1' then + case OP_SIZE is + when LONG => DR(DR_PNTR_WR_1) <= DR_IN_1; + when WORD => DR(DR_PNTR_WR_1)(15 downto 0) <= DR_IN_1(15 downto 0); + when Byte => DR(DR_PNTR_WR_1)(7 downto 0) <= DR_IN_1(7 downto 0); + end case; + end if; + if DR_WR_2 = '1' then + case OP_SIZE is + when LONG => DR(DR_PNTR_WR_2) <= DR_IN_2; + when WORD => DR(DR_PNTR_WR_2)(15 downto 0) <= DR_IN_2(15 downto 0); + when Byte => DR(DR_PNTR_WR_2)(7 downto 0) <= DR_IN_2(7 downto 0); + end case; + end if; + end process REGISTERS; +end BEHAVIOUR; diff --git a/common/CPU/68K30L/wf68k30L_exception_handler.vhd b/common/CPU/68K30L/wf68k30L_exception_handler.vhd new file mode 100644 index 00000000..46ce0896 --- /dev/null +++ b/common/CPU/68K30L/wf68k30L_exception_handler.vhd @@ -0,0 +1,934 @@ +------------------------------------------------------------------------ +---- ---- +---- WF68K30L IP Core: this is the exception handler module. ---- +---- ---- +---- Description: ---- +---- This is the exception handler which is responsible for the ---- +---- interrupt management of the external interrupt and internal ---- +---- exception processing. It manages auto-vectored interrupt ---- +---- cycles, priority resolving and correct vector numbers. ---- +---- For further information concerning the functionality of this ---- +---- module refer to the MC68030 User's Manual and to the MC68K ---- +---- family Programmer's Reference Manual. ---- +------------------------------------------------------------------------ +---- ---- +---- Remarks: ---- +---- The relationship between the STATUSn signal and the execution ---- +---- of the next pending exception is handled by the BUSY signals. ---- +---- If the pending interrupt is not signaled in time, when the ---- +---- main controller signal STATUSn, the next instruction is ---- +---- executed and afterwards the exception. When the pending ---- +---- exception is asserted before the STATUSn of one of the main ---- +---- controller, the exception is executed immediately. ---- +---- ---- +---- A bus error at an instruction boundary may occur, when the ---- +---- operation word fetched from the instruction pipe is invalid. ---- +---- Bus errors which occur at the time of the instruction boundary ---- +---- but where released early or at the same time due to the pipe- ---- +---- lined structure are treated as regular bus errors not related ---- +---- with the instruction boundary. The signal IBOUND is used to ---- +---- handle this situations correctly. ---- +---- ---- +---- This exception handler uses a simple logic for the handling ---- +---- the RTE instruction. In comparision to the full featured 68K30 ---- +---- it cannot complete from defective bus exception stack frames. ---- +---- It is assumed, that a software handler has modified the images ---- +---- in the exception stack frame for a bus handler so that the RTE ---- +---- instruction restores from a correct stack frame. ---- +---- ---- +---- Author(s): ---- +---- - Wolfgang Foerster, wf@experiment-s.de; wf@inventronik.de ---- +---- ---- +------------------------------------------------------------------------ +---- ---- +---- Copyright © 2014-2019 Wolfgang Foerster Inventronik GmbH. ---- +---- ---- +---- This documentation describes Open Hardware and is licensed ---- +---- under the CERN OHL v. 1.2. You may redistribute and modify ---- +---- this documentation under the terms of the CERN OHL v.1.2. ---- +---- (http://ohwr.org/cernohl). This documentation is distributed ---- +---- WITHOUT ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING OF ---- +---- MERCHANTABILITY, SATISFACTORY QUALITY AND FITNESS FOR A ---- +---- PARTICULAR PURPOSE. Please see the CERN OHL v.1.2 for ---- +---- applicable conditions ---- +---- ---- +------------------------------------------------------------------------ +-- +-- Revision History +-- +-- Revision 2K14B 20141201 WF +-- Initial Release. +-- Revision 2K16A 20141201 WF +-- Fixed a bug in PC_LOAD. +-- Revision 2K18A 20180620 WF +-- Removed REST_BIW_0. +-- Removed PC_OFFSET. +-- Fixed PC restoring during exception processing. +-- Fixed the vector calculation of INT vectors. +-- Fixed faulty modeling in IRQ_FILTER. +-- Implemented the AVEC_FILTER to better meet bus timings. +-- The RTE exception has now highest priority (avoids mismatch). +-- TOP, CONTROL, Exception Handler Opcode Decoder: Rearranged PC_INC and ipipe flush logic. +-- Update the IRQ mask only for RESET and interrupts. +-- External interrupts are postponed if any system controllers are in initialize operation status. +-- RTE now loads the address offset correctly when entering the handler. +-- Rearranged address error handling. +-- Revision 2K19B 20191224 WF +-- Introduced signal synchronization in the P_D process to avoid malfunction by hazards. +-- The processor VERSION is now 32 bit wide. +-- + +library work; +use work.WF68K30L_PKG.all; + +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_unsigned.all; + +entity WF68K30L_EXCEPTION_HANDLER is + generic(VERSION : std_logic_vector(31 downto 0) := x"20191224"); + port( + CLK : in std_logic; + RESET : in bit; + + BUSY_MAIN : in bit; + BUSY_OPD : in bit; + + EXH_REQ : out bit; + BUSY_EXH : out bit; + + ADR_IN : in std_logic_vector(31 downto 0); + ADR_CPY : out std_logic_vector(31 downto 0); + ADR_OFFSET : out std_logic_vector(31 downto 0); + CPU_SPACE : out bit; + + DATA_0 : in std_logic; + DATA_RD : out bit; + DATA_WR : out bit; + DATA_IN : in std_logic_vector(31 downto 0); + + OP_SIZE : out OP_SIZETYPE; -- Operand size. + DATA_RDY : in bit; + DATA_VALID : in std_logic; + + OPCODE_RDY : in bit; -- OPCODE is available. + OPD_ACK : in bit; -- Opword is available. + OW_VALID : in std_logic; -- Status from the opcode decoder. + + STATUS_REG_IN : in std_logic_vector(15 downto 0); + SR_CPY : out std_logic_vector(15 downto 0); + SR_INIT : out bit; + SR_CLR_MBIT : out bit; + SR_WR : out bit; + + ISP_DEC : out bit; + ISP_LOAD : out bit; + PC_INC : out bit; + PC_LOAD : out bit; + PC_RESTORE : out bit; + + STACK_FORMAT : out std_logic_vector(3 downto 0); + STACK_POS : out integer range 0 to 46; + + SP_ADD_DISPL : out bit; + DISPLACEMENT : out std_logic_vector(7 downto 0); + + IPIPE_FILL : out bit; + IPIPE_FLUSH : out bit; + REFILLn : out std_logic; + RESTORE_ISP_PC : out bit; + + HALT_OUTn : out std_logic; + STATUSn : out bit; + + -- Interrupt controls: + INT_TRIG : in bit; + IRQ_IN : in std_logic_vector(2 downto 0); + IRQ_PEND : out std_logic_vector(2 downto 0); + AVECn : in std_logic; + IPENDn : out std_logic; + IVECT_OFFS : out std_logic_vector(9 downto 0); -- Interrupt vector offset. + + + -- Trap signals: + TRAP_AERR : in bit; + TRAP_BERR : in bit; + TRAP_CHK : in bit; + TRAP_DIVZERO : in bit; + TRAP_ILLEGAL : in bit; + TRAP_CODE_OPC : in TRAPTYPE_OPC; -- T_1010, T_1111, T_ILLEGAL, T_TRAP, T_PRIV. + TRAP_VECTOR : in std_logic_vector(3 downto 0); + TRAP_cc : in bit; + TRAP_V : in bit; + EX_TRACE_IN : in bit; + VBR_WR : in bit; + VBR : out std_logic_vector(31 downto 0) + ); +end entity WF68K30L_EXCEPTION_HANDLER; + +architecture BEHAVIOR of WF68K30L_EXCEPTION_HANDLER is +type EX_STATES is (IDLE, BUILD_STACK, BUILD_TSTACK, CALC_VECT_No, EXAMINE_VERSION, GET_VECTOR, HALTED, INIT, READ_BOTTOM, + READ_TOP, REFILL_PIPE, RESTORE_ISP, RESTORE_PC, RESTORE_STATUS, UPDATE_PC, SWITCH_STATE, VALIDATE_FRAME); + +type EXCEPTIONS is (EX_NONE, EX_1010, EX_1111, EX_AERR, EX_BERR, EX_CHK, EX_DIVZERO, EX_FORMAT, EX_ILLEGAL, + EX_INT, EX_PRIV, EX_RESET, EX_RTE, EX_TRACE, EX_TRAP, EX_TRAPcc, EX_TRAPV); + +signal ACCESS_ERR : bit; +signal AVEC : bit; +signal DATA_RD_I : bit; +signal DATA_WR_I : bit; +signal DOUBLE_BUSFLT : bit; +signal EXCEPTION : EXCEPTIONS; -- Currently executed exception. +signal EX_STATE : EX_STATES := IDLE; +signal NEXT_EX_STATE : EX_STATES; +signal EX_P_1010 : bit; -- ..._P are the pending exceptions. +signal EX_P_1111 : bit; +signal EX_P_AERR : bit; +signal EX_P_BERR : bit; +signal EX_P_CHK : bit; +signal EX_P_DIVZERO : bit; +signal EX_P_FORMAT : bit; +signal EX_P_ILLEGAL : bit; +signal EX_P_INT : bit; +signal EX_P_RESET : bit; +signal EX_P_RTE : bit; +signal EX_P_PRIV : bit; +signal EX_P_TRACE : bit; +signal EX_P_TRAP : bit; +signal EX_P_TRAPcc : bit; +signal EX_P_TRAPV : bit; +signal INT_VECT : std_logic_vector(31 downto 0); -- Interrupt vector. +signal IBOUND : boolean; +signal IRQ : std_logic_vector(2 downto 0); +signal IRQ_PEND_I : std_logic_vector(2 downto 0); +signal MBIT : std_logic; +signal PIPE_CNT : std_logic_vector(1 downto 0); +signal PIPE_FULL : boolean; +signal STACK_CNT : integer range 0 to 46; +signal STACK_FORMAT_I : std_logic_vector(3 downto 0); +signal SYS_INIT : bit; +begin + BUSY_EXH <= '1' when EX_STATE /= IDLE else '0'; + + IRQ_FILTER : process + -- This logic is intended to avoid spurious IRQs due + -- to setup / hold violations (IRQ_IN may operate in + -- a different clock domain). + variable IRQ_TMP_1 : std_logic_vector(2 downto 0) := "000"; + variable IRQ_TMP_2 : std_logic_vector(2 downto 0) := "000"; + begin + wait until CLK = '0' and CLK' event; + if IRQ_TMP_1 = IRQ_TMP_2 then + IRQ <= IRQ_TMP_2; + end if; + IRQ_TMP_2 := IRQ_TMP_1; + IRQ_TMP_1 := IRQ_IN; + end process IRQ_FILTER; + + AVEC_FILTER : process + -- We need a flip flop for the incoming AVECn to meet + -- the timing requirements of the bus interface. AVECn + -- is asserted (low active) before DATA_RDY of the + -- bus interface. AVEC stays asserted until DATA_RDY. + begin + wait until CLK = '1' and CLK' event; + if AVECn = '0' then + AVEC <= '1'; + elsif DATA_RDY = '1' or RESET = '1' then + AVEC <= '0'; + end if; + end process AVEC_FILTER; + + INSTRUCTION_BOUNDARY: process + -- This flip flop indicates a bus error exception, + -- when the micro sequencer is at an instruction + -- boundary. + begin + wait until CLK = '1' and CLK' event; + if RESET = '1' then + IBOUND <= false; + elsif OPD_ACK = '1' and OW_VALID = '0' then + IBOUND <= true; + elsif EX_STATE = BUILD_STACK then + IBOUND <= false; + end if; + end process INSTRUCTION_BOUNDARY; + + PENDING: process + -- The exceptions which occurs are stored in this pending register until the + -- interrupt handler handled the respective exception. + -- The TRAP_PRIV, TRAP_1010, TRAP_1111, TRAP_ILLEGAL, TRAP_OP and TRAP_V may be a strobe + -- of 1 clock period. All others must be strobes of 1 clock period.. + variable INT7_TRIG : boolean; + variable INT_VAR : std_logic_vector(2 downto 0); + variable SR_VAR : std_logic_vector(2 downto 0); + begin + wait until CLK = '1' and CLK' event; + if RESET = '1' then + EX_P_RESET <= '1'; + elsif EX_STATE = RESTORE_PC and DATA_RDY = '1' and EXCEPTION = EX_RESET then + EX_P_RESET <= '0'; + end if; + -- + if TRAP_BERR = '1' then + EX_P_BERR <= '1'; + elsif EX_STATE /= IDLE and DATA_RDY = '1' and DATA_VALID = '0' then + EX_P_BERR <= '1'; + elsif EX_STATE = INIT and EXCEPTION = EX_BERR then + EX_P_BERR <= '0'; -- Reset in the beginning to enable retriggering. + elsif SYS_INIT = '1' then + EX_P_BERR <= '0'; + end if; + -- + if TRAP_AERR = '1' then + EX_P_AERR <= '1'; + elsif EX_STATE = BUILD_STACK and EXCEPTION = EX_AERR then + EX_P_AERR <= '0'; + elsif SYS_INIT = '1' then + EX_P_AERR <= '0'; + end if; + -- + if EX_TRACE_IN = '1' then + EX_P_TRACE <= '1'; + elsif EX_STATE = BUILD_STACK and EXCEPTION = EX_TRACE then + EX_P_TRACE <= '0'; + elsif SYS_INIT = '1' then + EX_P_TRACE <= '0'; + end if; + -- + if IRQ = "111" and SR_VAR = "111" and STATUS_REG_IN(10 downto 8) /= "111" then + INT7_TRIG := true; -- Trigger by lowering the mask from 7 to any value. + elsif IRQ = "111" and INT_VAR < "111" then + INT7_TRIG := true; -- Trigger when level 7 is entered. + else + INT7_TRIG := false; + end if; + -- + SR_VAR := STATUS_REG_IN(10 downto 8); -- Update after use! + INT_VAR := IRQ; -- Update after use! + -- + if SYS_INIT = '1' then -- Reset when disabling the interrupts. + EX_P_INT <= '0'; + IRQ_PEND_I <= "111"; -- This is required for system startup. + elsif EX_STATE = GET_VECTOR and DATA_RDY = '1' then + EX_P_INT <= '0'; + elsif INT7_TRIG = true then -- Level 7 is nonmaskable ... + EX_P_INT <= '1'; + IRQ_PEND_I <= IRQ; + elsif INT_TRIG = '1' and STATUS_REG_IN(10 downto 8) < IRQ then + EX_P_INT <= '1'; + IRQ_PEND_I <= IRQ; + end if; + -- + -- The following nine traps never appear at the same time: + if TRAP_CHK = '1' then + EX_P_CHK <= '1'; + elsif TRAP_DIVZERO = '1' then + EX_P_DIVZERO <= '1'; + elsif TRAP_CODE_OPC = T_TRAP then + EX_P_TRAP <= '1'; + elsif TRAP_cc = '1' then + EX_P_TRAPcc <= '1'; + elsif TRAP_V = '1' then + EX_P_TRAPV <= '1'; + elsif TRAP_CODE_OPC = T_PRIV then + EX_P_PRIV <= '1'; + elsif TRAP_CODE_OPC = T_1010 then + EX_P_1010 <= '1'; + elsif TRAP_CODE_OPC = T_1111 then + EX_P_1111 <= '1'; + elsif TRAP_CODE_OPC = T_ILLEGAL then + EX_P_ILLEGAL <= '1'; + elsif TRAP_ILLEGAL = '1' then -- Used for BKPT. + EX_P_ILLEGAL <= '1'; + elsif EX_STATE = VALIDATE_FRAME and DATA_RDY = '1' and DATA_VALID = '1' and NEXT_EX_STATE = IDLE then + EX_P_FORMAT <= '1'; + elsif EX_STATE = EXAMINE_VERSION and DATA_RDY = '1' and DATA_VALID = '1' and NEXT_EX_STATE = IDLE then + EX_P_FORMAT <= '1'; + elsif TRAP_CODE_OPC = T_RTE then + EX_P_RTE <= '1'; + elsif EX_STATE = REFILL_PIPE and NEXT_EX_STATE /= REFILL_PIPE then -- Clear after IPIPE_FLUSH. + case EXCEPTION is + when EX_1010 | EX_1111 | EX_CHK | EX_DIVZERO | EX_ILLEGAL | EX_TRAP | EX_TRAPcc | EX_TRAPV | EX_FORMAT | EX_PRIV | EX_RTE => + EX_P_CHK <= '0'; + EX_P_DIVZERO <= '0'; + EX_P_PRIV <= '0'; + EX_P_1010 <= '0'; + EX_P_1111 <= '0'; + EX_P_ILLEGAL <= '0'; + EX_P_RTE <= '0'; + EX_P_TRAP <= '0'; + EX_P_TRAPcc <= '0'; + EX_P_TRAPV <= '0'; + EX_P_FORMAT <= '0'; + when others => + null; + end case; + -- Clear all possible traps during reset exception because the + -- signal EXCEPTION is not valid at this time: + elsif SYS_INIT = '1' then + EX_P_CHK <= '0'; + EX_P_DIVZERO <= '0'; + EX_P_PRIV <= '0'; + EX_P_1010 <= '0'; + EX_P_1111 <= '0'; + EX_P_ILLEGAL <= '0'; + EX_P_RTE <= '0'; + EX_P_TRAP <= '0'; + EX_P_TRAPV <= '0'; + EX_P_FORMAT <= '0'; + end if; + end process PENDING; + + ACCESS_ERR <= '1' when EX_STATE = RESTORE_PC and DATA_RDY = '1' and DATA_0 = '1' else -- Odd PC value. + '1' when DATA_RDY = '1' and DATA_VALID = '0' else '0'; -- Bus error. + + IRQ_PEND <= IRQ_PEND_I when EXCEPTION = EX_RESET or EXCEPTION = EX_INT else STATUS_REG_IN(10 downto 8); + IPENDn <= '0' when EX_P_INT = '1' or EX_P_RESET = '1' or EX_P_TRACE = '1' else '1'; + + -- This signal is asserted eraly to indicate the respective controller to stay in its idle state. + -- The exception is then inserted before a new operation has been loaded and processed. + EXH_REQ <= '0' when EX_STATE /= IDLE else + '1' when TRAP_CODE_OPC /= NONE else + '1' when (EX_P_RESET or EX_P_BERR or EX_P_AERR or EX_P_DIVZERO or EX_P_CHK) = '1' else + '1' when (EX_P_TRAPcc or EX_P_TRAPV or EX_P_TRACE or EX_P_FORMAT or EX_P_INT) = '1' else '0'; + + INT_VECTOR: process + -- This process provides the vector base register handling and + -- the interrupt vector number INT_VECT, which is determined + -- during interrupt processing. + variable VECT_No : std_logic_vector(9 downto 2) := "00000000"; + variable VB_REG : std_logic_vector(31 downto 0) := x"00000000"; + begin + wait until CLK = '1' and CLK' event; + if VBR_WR = '1' then + VB_REG := DATA_IN; + elsif SYS_INIT = '1' then + VB_REG := (others => '0'); + end if; + -- + if EX_STATE = CALC_VECT_No or EX_STATE = GET_VECTOR then + case EXCEPTION is + when EX_RESET => VECT_No := x"00"; + when EX_BERR => VECT_No := x"02"; + when EX_AERR => VECT_No := x"03"; + when EX_ILLEGAL => VECT_No := x"04"; + when EX_DIVZERO => VECT_No := x"05"; + when EX_CHK => VECT_No := x"06"; + when EX_TRAPcc => VECT_No := x"07"; + when EX_TRAPV => VECT_No := x"07"; + when EX_PRIV => VECT_No := x"08"; + when EX_TRACE => VECT_No := x"09"; + when EX_1010 => VECT_No := x"0A"; + when EX_1111 => VECT_No := x"0B"; + when EX_FORMAT => VECT_No := x"0E"; + -- The uninitialized interrupt vector number x"0F" + -- is provided by the peripheral interrupt source + -- during the auto vector bus cycle. + when EX_INT => + if DATA_RDY = '1' and AVEC = '1' then + VECT_No := x"18" + IRQ_PEND_I; -- Autovector. + elsif DATA_RDY = '1' and DATA_VALID = '0' then + VECT_No := x"18"; -- Spurious interrupt. + elsif DATA_RDY = '1' then + -- This is the vector number provided by the device. + -- If the returned VECT_No is x"0F" then it is the + -- uninitialized interrupt vector due to non initia- + -- lized vector register of the peripheral device. + VECT_No := DATA_IN(7 downto 0); -- Non autovector. + end if; + when EX_TRAP => VECT_No := x"2" & TRAP_VECTOR; + when others => VECT_No := (others => '-'); -- Don't care. + end case; + end if; + -- + INT_VECT <= VB_REG + (VECT_No & "00"); + VBR <= VB_REG; + IVECT_OFFS <= VECT_No & "00"; + end process INT_VECTOR; + + STORE_CURRENT_EXCEPTION: process + -- The exceptions which occurs are stored in the following flags until the + -- interrupt handler handled the respective exception. + -- This process also stores the current processed exception for further use. + -- The update takes place in the IDLE EX_STATE. + begin + wait until CLK = '1' and CLK' event; + -- Priority level 0: + if EX_STATE = IDLE and EX_P_RESET = '1' then + EXCEPTION <= EX_RESET; + -- Priority level 1: + elsif EX_STATE = IDLE and EX_P_AERR = '1' then + EXCEPTION <= EX_AERR; + elsif EX_STATE = IDLE and EX_P_BERR = '1' then + EXCEPTION <= EX_BERR; + -- Priority level 2: + -- BREAKPOINT is part of the main controller. + elsif EX_STATE = IDLE and EX_P_CHK = '1' then + EXCEPTION <= EX_CHK; + elsif EX_STATE = IDLE and EX_P_TRAPcc = '1' then + EXCEPTION <= EX_TRAPcc; + elsif EX_STATE = IDLE and EX_P_DIVZERO = '1' then + EXCEPTION <= EX_DIVZERO; + elsif EX_STATE = IDLE and EX_P_TRAP = '1' then + EXCEPTION <= EX_TRAP; + elsif EX_STATE = IDLE and EX_P_TRAPV = '1' then + EXCEPTION <= EX_TRAPV; + elsif EX_STATE = IDLE and EX_P_FORMAT = '1' then + EXCEPTION <= EX_FORMAT; + -- Priority level 3: + elsif EX_STATE = IDLE and EX_P_ILLEGAL = '1' then + EXCEPTION <= EX_ILLEGAL; + elsif EX_STATE = IDLE and EX_P_RTE = '1' then + EXCEPTION <= EX_RTE; + elsif EX_STATE = IDLE and EX_P_1010 = '1' then + EXCEPTION <= EX_1010; + elsif EX_STATE = IDLE and EX_P_1111 = '1' then + EXCEPTION <= EX_1111; + elsif EX_STATE = IDLE and EX_P_PRIV = '1' then + EXCEPTION <= EX_PRIV; + elsif EX_STATE = IDLE and EX_P_TRACE = '1' then + EXCEPTION <= EX_TRACE; + elsif EX_STATE = IDLE and EX_P_INT = '1' then + EXCEPTION <= EX_INT; + elsif NEXT_EX_STATE = IDLE then + EXCEPTION <= EX_NONE; + end if; + end process STORE_CURRENT_EXCEPTION; + + CPU_SPACE <= '1' when NEXT_EX_STATE = GET_VECTOR else '0'; + + ADR_OFFSET <= x"000000" & "00000" & PIPE_CNT & '0' when EX_STATE = REFILL_PIPE else + x"00000004" when NEXT_EX_STATE = RESTORE_PC and EXCEPTION = EX_RESET else + x"00000002" when NEXT_EX_STATE = RESTORE_PC else + x"00000006" when NEXT_EX_STATE = VALIDATE_FRAME else + x"00000036" when NEXT_EX_STATE = EXAMINE_VERSION else + x"0000005C" when NEXT_EX_STATE = READ_BOTTOM else + INT_VECT when NEXT_EX_STATE = UPDATE_PC else x"00000000"; -- Default is top of the stack. + + OP_SIZE <= LONG when EX_STATE = INIT else -- Decrement the stack by four (ISP_DEC). + LONG when NEXT_EX_STATE = RESTORE_ISP or NEXT_EX_STATE = RESTORE_PC else + LONG when NEXT_EX_STATE = BUILD_STACK or NEXT_EX_STATE = BUILD_TSTACK else -- Always long access. + LONG when NEXT_EX_STATE = UPDATE_PC or EX_STATE = UPDATE_PC else + LONG when EX_STATE = SWITCH_STATE else + LONG when NEXT_EX_STATE = EXAMINE_VERSION else + BYTE when NEXT_EX_STATE = GET_VECTOR else WORD; + + with STACK_FORMAT_I select + DISPLACEMENT <= x"08" when x"0" | x"1", + x"0C" when x"2", + x"12" when x"9", + x"20" when x"A", + x"5C" when others; -- x"B". + + SP_ADD_DISPL <= '1' when EX_STATE = RESTORE_STATUS and DATA_RDY = '1' and DATA_VALID = '1' else '0'; + + P_D: process(CLK, DATA_RDY) + -- These flip flops are necessary to delay + -- the read and writes during BUILD_STACK + -- and restoring the system because the + -- address calculation in the address + -- section requires one clock. + -- Important note: to avoid asynchronous reset by data hazards the + -- resetting signal is synchronized on the negative clock edge. + variable DATA_RDY_VAR : bit; + begin + if CLK = '0' and CLK' event then + DATA_RDY_VAR := DATA_RDY; + end if; + -- + if DATA_RDY_VAR = '1' then + DATA_RD <= '0'; + elsif CLK = '1' and CLK' event then + DATA_RD <= DATA_RD_I; + end if; + + if DATA_RDY_VAR = '1' then + DATA_WR <= '0'; + elsif CLK = '1' and CLK' event then + DATA_WR <= DATA_WR_I; + end if; + end process P_D; + + DATA_RD_I <= '0' when DATA_RDY = '1' else + '1' when NEXT_EX_STATE = GET_VECTOR else + '1' when NEXT_EX_STATE = VALIDATE_FRAME else + '1' when NEXT_EX_STATE = EXAMINE_VERSION else + '1' when NEXT_EX_STATE = READ_TOP else + '1' when NEXT_EX_STATE = READ_BOTTOM else + '1' when NEXT_EX_STATE = RESTORE_ISP else + '1' when NEXT_EX_STATE = RESTORE_STATUS else + '1' when NEXT_EX_STATE = UPDATE_PC else + '1' when NEXT_EX_STATE = RESTORE_PC else '0'; + + DATA_WR_I <= '0' when DATA_RDY = '1' else + '1' when EX_STATE = BUILD_STACK else + '1' when EX_STATE = BUILD_TSTACK else '0'; + + ISP_LOAD <= '1' when EX_STATE = RESTORE_ISP and DATA_RDY = '1' and DATA_VALID = '1' else '0'; + PC_RESTORE <= '1' when EX_STATE = RESTORE_PC and DATA_RDY = '1' and DATA_VALID = '1' else '0'; + PC_LOAD <= '1' when EXCEPTION /= EX_RESET and EXCEPTION /= EX_RTE and EX_STATE /= REFILL_PIPE and NEXT_EX_STATE = REFILL_PIPE else '0'; + + IPIPE_FILL <= '1' when EX_STATE = REFILL_PIPE else '0'; + + -- This signal forces the PC logic in the address register section to calculate the address + -- of the next instruction. This address is written on the stack. For the following + -- instructions the old PC value is stacked: BERR, AERR, ILLEGAL, PRIV, TRACE, 1010, 1111, FORMAT. + PC_INC <= '1' when EXCEPTION = EX_CHK and EX_STATE /= BUILD_STACK and NEXT_EX_STATE = BUILD_STACK else + '1' when EXCEPTION = EX_DIVZERO and EX_STATE /= BUILD_STACK and NEXT_EX_STATE = BUILD_STACK else + '1' when EXCEPTION = EX_INT and EX_STATE /= BUILD_STACK and NEXT_EX_STATE = BUILD_STACK else + '1' when EXCEPTION = EX_TRAP and EX_STATE /= BUILD_STACK and NEXT_EX_STATE = BUILD_STACK else + '1' when EXCEPTION = EX_TRAPcc and EX_STATE /= BUILD_STACK and NEXT_EX_STATE = BUILD_STACK else + '1' when EXCEPTION = EX_TRAPV and EX_STATE /= BUILD_STACK and NEXT_EX_STATE = BUILD_STACK else '0'; + + ISP_DEC <= '1' when EX_STATE = INIT and EXCEPTION /= EX_RESET and EXCEPTION /= EX_RTE else -- Early due to one clock cycle address calculation. + '1' when EX_STATE = BUILD_STACK and DATA_RDY = '1' and NEXT_EX_STATE = BUILD_STACK else + '1' when EX_STATE = SWITCH_STATE else + '1' when EX_STATE = BUILD_TSTACK and DATA_RDY = '1' and NEXT_EX_STATE = BUILD_TSTACK else '0'; + + SR_INIT <= '1' when EX_STATE = INIT else '0'; + SR_CLR_MBIT <= '1' when EX_STATE = BUILD_STACK and DATA_RDY = '1' and STACK_CNT = 2 and EXCEPTION = EX_INT and MBIT = '1' else '0'; + SR_WR <= '1' when EX_STATE = RESTORE_STATUS and DATA_RDY = '1' and DATA_VALID = '1' else '0'; + + SYS_INIT <= '1' when EX_STATE = IDLE and EX_P_RESET = '1' else '0'; + + -- The processor gets halted, if a bus error occurs in the stacking or updating states during + -- the exception processing of a bus error, an address error or a reset. + HALT_OUTn <= '0' when EX_STATE = HALTED else '1'; + + RESTORE_ISP_PC <= '1' when EXCEPTION = EX_RESET and (NEXT_EX_STATE = RESTORE_ISP or EX_STATE = RESTORE_ISP) else + '1' when EXCEPTION = EX_RESET and (NEXT_EX_STATE = RESTORE_PC or EX_STATE = RESTORE_PC) else + '1' when NEXT_EX_STATE = UPDATE_PC else '0'; + + REFILLn <= '0' when EX_STATE = REFILL_PIPE else '1'; + + STACK_FORMAT <= STACK_FORMAT_I; + + IPIPE_FLUSH <= '1' when EXCEPTION = EX_RESET and EX_STATE /= REFILL_PIPE else + '1' when EXCEPTION /= EX_NONE and EX_STATE /= REFILL_PIPE and NEXT_EX_STATE = REFILL_PIPE else '0'; + + DOUBLE_BUSFLT <= '1' when (EXCEPTION = EX_AERR or EXCEPTION = EX_RESET) and EX_STATE = RESTORE_PC and DATA_RDY = '1' and DATA_0 = '1' else -- Odd PC value. + '1' when EX_STATE /= IDLE and EXCEPTION = EX_AERR and DATA_RDY = '1' and DATA_VALID = '0' else + '1' when EX_STATE /= IDLE and EXCEPTION = EX_BERR and DATA_RDY = '1' and DATA_VALID = '0' else + '1' when EX_STATE /= IDLE and EXCEPTION = EX_RESET and DATA_RDY = '1' and DATA_VALID = '0' else '0'; + + P_TMP_CPY: process + -- These registers contain a copy of system relevant state information + -- which is necessary for restoring the exception. Copies are provided + -- for the status register, the program counter and the effective address. + begin + wait until CLK = '1' and CLK' event; + if EX_STATE = IDLE and NEXT_EX_STATE /= IDLE then + SR_CPY <= STATUS_REG_IN; + ADR_CPY <= ADR_IN; + MBIT <= STATUS_REG_IN(12); + elsif EX_STATE = BUILD_STACK and NEXT_EX_STATE = SWITCH_STATE then + SR_CPY(13) <= '1'; -- Set S bit. + end if; + end process P_TMP_CPY; + + STACK_CTRL: process + -- This process controls the stacking of the data to the stack. Depending + -- on the stack frame format, the number of words written to the stack is + -- adjusted to long words. See the DATA_2_PORT multiplexer in the top level + -- file for more information. + variable STACK_POS_VAR : integer range 0 to 46 := 0; + begin + wait until CLK = '1' and CLK' event; + if EX_STATE /= BUILD_TSTACK and NEXT_EX_STATE = BUILD_TSTACK then + STACK_POS_VAR := 4; + STACK_FORMAT_I <= x"1"; + elsif EX_STATE /= BUILD_STACK and NEXT_EX_STATE = BUILD_STACK then + case EXCEPTION is + when EX_INT | EX_ILLEGAL | EX_1010 | EX_1111 | EX_FORMAT | EX_PRIV | EX_TRAP => + STACK_POS_VAR := 4; -- Format 0. + STACK_FORMAT_I <= x"0"; + when EX_CHK | EX_TRAPcc | EX_TRAPV | EX_TRACE | EX_DIVZERO => + STACK_POS_VAR := 6; -- Format 2. + STACK_FORMAT_I <= x"2"; + when EX_AERR | EX_BERR => + if IBOUND = true then + STACK_POS_VAR := 16; -- Format A. + STACK_FORMAT_I <= x"A"; + else + STACK_POS_VAR := 46; -- Format B. + STACK_FORMAT_I <= x"B"; + end if; + when others => null; + end case; + elsif EX_STATE = VALIDATE_FRAME and DATA_RDY = '1' and DATA_VALID = '1' then + STACK_FORMAT_I <= DATA_IN(15 downto 12); + elsif (EX_STATE = BUILD_STACK or EX_STATE = BUILD_TSTACK) and DATA_RDY = '1' then + STACK_POS_VAR := STACK_POS_VAR - 2; -- Always long words are written. + end if; + -- + STACK_CNT <= STACK_POS_VAR; + STACK_POS <= STACK_POS_VAR; + end process STACK_CTRL; + + P_STATUSn : process + -- This logic asserts the STATUSn permanently when the CPU is halted. + -- STATUSn is asserted for three clock cycles when the exception + -- processing starts for RESET, BERR, AERR, 1111, spurious inter- + -- rupt and autovectored interrupt. And for TRACE or external + -- interrupt exception it is asserted for two clock cycles. + variable CNT : std_logic_vector(1 downto 0); + begin + wait until CLK = '1' and CLK' event; + if EX_STATE = CALC_VECT_No then + case EXCEPTION is + when EX_RESET | EX_AERR | EX_BERR | EX_1111 => + CNT := "11"; + STATUSn <= '0'; + when EX_INT | EX_TRACE => + CNT := "10"; + when others => + CNT := "00"; + end case; + end if; + + if EX_STATE = HALTED then + STATUSn <= '0'; + elsif CNT > "00" then + CNT := CNT - '1'; + STATUSn <= '0'; + else + STATUSn <= '1'; + end if; + end process P_STATUSn; + + PIPE_STATUS: process + -- This logic detects the status of the + -- instruction pipe prefetch in the + -- REFILL_PIPE state. + variable CNT : std_logic_vector(1 downto 0); + begin + wait until CLK = '1' and CLK' event; + if EX_STATE /= REFILL_PIPE then + PIPE_FULL <= false; + CNT := "00"; + elsif EX_STATE = REFILL_PIPE and OPCODE_RDY = '1' and CNT < "10" then + CNT := CNT + '1'; + elsif EX_STATE = REFILL_PIPE and OPCODE_RDY = '1' then + PIPE_FULL <= true; + end if; + PIPE_CNT <= CNT; + end process PIPE_STATUS; + + EXCEPTION_HANDLER_REG: process + -- This is the register portion of the + -- exception control state machine. + begin + wait until CLK = '1' and CLK' event; + if RESET = '1' then + EX_STATE <= IDLE; + else + EX_STATE <= NEXT_EX_STATE; + end if; + end process EXCEPTION_HANDLER_REG; + + EXCEPTION_HANDLER_DEC: process(ACCESS_ERR, BUSY_MAIN, BUSY_OPD, DATA_IN, DATA_VALID, DOUBLE_BUSFLT, EX_STATE, EX_P_RESET, EX_P_AERR, EX_P_BERR, EX_P_TRACE, + EX_P_INT, EX_P_ILLEGAL, EX_P_1010, EX_P_TRAPcc, EX_P_RTE, EX_P_1111, EX_P_FORMAT, EX_P_PRIV, EX_P_TRAP, EX_P_TRAPV, + EX_P_CHK, EX_P_DIVZERO, EXCEPTION, DATA_RDY, PIPE_FULL, MBIT, STACK_CNT, STACK_FORMAT_I) + begin + case EX_STATE is + when IDLE => + -- The priority of the exception execution is given by the + -- following construct. Although type 3 commands do not require + -- a prioritization, there is no drawback using these conditions. + -- The spurious interrupt and uninitialized interrupt never appear + -- as basic interrupts and therefore are not an interrupt source. + -- During IDLE, when an interrupt occurs, the status register copy + -- control is asserted and the current interrupt controll is given + -- to the STORE_EXCEPTION process. During bus or address errors, + -- the status register must be copied immediately to recognize + -- the current status for RWn etc. (before the faulty bus cycle is + -- finished). + if (BUSY_MAIN = '1' or BUSY_OPD = '1') and EX_P_RESET = '0' then + NEXT_EX_STATE <= IDLE; -- Wait until the pipelined architecture is ready. + elsif EX_P_RESET = '1' or EX_P_AERR = '1' or EX_P_BERR = '1' then + NEXT_EX_STATE <= INIT; + elsif EX_P_TRAP = '1' or EX_P_TRAPcc = '1' or EX_P_TRAPV = '1' or EX_P_CHK = '1' or EX_P_DIVZERO = '1' then + NEXT_EX_STATE <= INIT; + elsif EX_P_FORMAT = '1' then + NEXT_EX_STATE <= INIT; + elsif EX_P_TRACE = '1' or EX_P_ILLEGAL = '1' or EX_P_1010 = '1' or EX_P_1111 = '1' or EX_P_PRIV = '1' then + NEXT_EX_STATE <= INIT; + elsif EX_P_RTE = '1' then + NEXT_EX_STATE <= INIT; + elsif EX_P_INT = '1' then + NEXT_EX_STATE <= INIT; + else -- No exception. + NEXT_EX_STATE <= IDLE; + end if; + when INIT => + -- In this state, the supervisor mode is switched on (the S bit is set) + -- and the trace mode is switched off (the T bit is cleared). + -- Do not service, if halted. The current bus cycle is always finished + -- in this state. The worst case is a bus error which the finishes the + -- current bus cycle within the next clock cycle after BERR is asserted. + case EXCEPTION is + when EX_RTE => + -- This state is foreseen to handle the address offset + -- correctly in the case the ADR_ATN is already set + -- by the main controller. So we have to wait one + -- clock cycle to ensure this data hazard. + NEXT_EX_STATE <= VALIDATE_FRAME; -- 68K10. + when EX_INT => + NEXT_EX_STATE <= GET_VECTOR; + when others => + NEXT_EX_STATE <= CALC_VECT_No; + end case; + when GET_VECTOR => + -- This state is intended to determine the vector number for the current process. + -- See also the process EXC_VECTOR for the handling of the vector determination. + if DATA_RDY = '1' then + NEXT_EX_STATE <= BUILD_STACK; + else + NEXT_EX_STATE <= GET_VECTOR; + end if; + when CALC_VECT_No => + -- This state is introduced to control the generation of the vector number + -- for all exceptions except the external interrupts. + case EXCEPTION is + when EX_RESET => + NEXT_EX_STATE <= RESTORE_ISP; -- Do not stack anything but update the SSP and PC. + when others => + NEXT_EX_STATE <= BUILD_STACK; + end case; + -- The following states provide writing to the stack pointer or reading + -- the exception vector address from memory. If there is a bus error + -- or an address error during the read or write cycles, the processor + -- proceeds in two different ways: + -- If the errors occur during a reset, bus error or address error + -- exception processing, a double bus fault has occured. In + -- consequence, the processor halts due to catastrophic system failure. + -- If the errors occur during other exception processings, the current + -- processing is aborted and this exception handler state machine will + -- immediately begin with the bus error exception handling. + when BUILD_STACK => + if DOUBLE_BUSFLT = '1' then + NEXT_EX_STATE <= HALTED; + elsif ACCESS_ERR = '1' then + NEXT_EX_STATE <= IDLE; + elsif DATA_RDY = '1' and STACK_CNT = 2 and EXCEPTION = EX_INT and MBIT = '1' then + NEXT_EX_STATE <= SWITCH_STATE; -- Build throwaway stack frame. + elsif DATA_RDY = '1' and STACK_CNT = 2 then + NEXT_EX_STATE <= UPDATE_PC; + else + NEXT_EX_STATE <= BUILD_STACK; + end if; + when SWITCH_STATE => -- Required to decrement the correct stack pointer. + NEXT_EX_STATE <= BUILD_TSTACK; + when BUILD_TSTACK => -- Build throwaway stack frame. + if ACCESS_ERR = '1' then + NEXT_EX_STATE <= IDLE; + elsif DATA_RDY = '1' and STACK_CNT = 2 then + NEXT_EX_STATE <= UPDATE_PC; + else + NEXT_EX_STATE <= BUILD_TSTACK; + end if; + when UPDATE_PC => + if DOUBLE_BUSFLT = '1' then + NEXT_EX_STATE <= HALTED; + elsif ACCESS_ERR = '1' then + NEXT_EX_STATE <= IDLE; + elsif DATA_RDY = '1' then + NEXT_EX_STATE <= REFILL_PIPE; + else + NEXT_EX_STATE <= UPDATE_PC; + end if; + when VALIDATE_FRAME => + if ACCESS_ERR = '1' then + NEXT_EX_STATE <= IDLE; + elsif DATA_RDY = '1' then + case DATA_IN(15 downto 12) is + when x"0" | x"1" | x"2" | x"9" => + NEXT_EX_STATE <= RESTORE_PC; + when x"A" | x"B" => + NEXT_EX_STATE <= EXAMINE_VERSION; + when others => + NEXT_EX_STATE <= IDLE; -- Format error. + end case; + else + NEXT_EX_STATE <= VALIDATE_FRAME; + end if; + when EXAMINE_VERSION => + if ACCESS_ERR = '1' then + NEXT_EX_STATE <= IDLE; + elsif DATA_RDY = '1' then + if DATA_IN /= VERSION then + NEXT_EX_STATE <= IDLE; -- Format error. + else + NEXT_EX_STATE <= READ_TOP; + end if; + else + NEXT_EX_STATE <= EXAMINE_VERSION; + end if; + when READ_TOP => + if ACCESS_ERR = '1' then + NEXT_EX_STATE <= IDLE; + elsif DATA_RDY = '1' then + NEXT_EX_STATE <= READ_BOTTOM; + else + NEXT_EX_STATE <= READ_TOP; + end if; + when READ_BOTTOM => + if ACCESS_ERR = '1' then + NEXT_EX_STATE <= IDLE; + elsif DATA_RDY = '1' then + NEXT_EX_STATE <= RESTORE_PC; + else + NEXT_EX_STATE <= READ_BOTTOM; + end if; + when RESTORE_STATUS => + if DOUBLE_BUSFLT = '1' then + NEXT_EX_STATE <= HALTED; + elsif ACCESS_ERR = '1' then + NEXT_EX_STATE <= IDLE; + elsif DATA_RDY = '1' and STACK_FORMAT_I = x"1" then + NEXT_EX_STATE <= VALIDATE_FRAME; -- Throwaway stack frame. + elsif DATA_RDY = '1' then + NEXT_EX_STATE <= REFILL_PIPE; + else + NEXT_EX_STATE <= RESTORE_STATUS; + end if; + when RESTORE_ISP => + if DOUBLE_BUSFLT = '1' then + NEXT_EX_STATE <= HALTED; + elsif ACCESS_ERR = '1' then + NEXT_EX_STATE <= IDLE; + elsif DATA_RDY = '1' then + NEXT_EX_STATE <= RESTORE_PC; + else + NEXT_EX_STATE <= RESTORE_ISP; + end if; + when RESTORE_PC => + if DOUBLE_BUSFLT = '1' then + NEXT_EX_STATE <= HALTED; -- Double bus fault. + elsif ACCESS_ERR = '1' then + NEXT_EX_STATE <= IDLE; + elsif EXCEPTION = EX_RESET and DATA_RDY = '1' then + NEXT_EX_STATE <= REFILL_PIPE; + elsif DATA_RDY = '1' then + NEXT_EX_STATE <= RESTORE_STATUS; + else + NEXT_EX_STATE <= RESTORE_PC; + end if; + when REFILL_PIPE => + if DOUBLE_BUSFLT = '1' then + NEXT_EX_STATE <= HALTED; + elsif ACCESS_ERR = '1' then + NEXT_EX_STATE <= IDLE; + elsif PIPE_FULL = true then + NEXT_EX_STATE <= IDLE; + else + NEXT_EX_STATE <= REFILL_PIPE; + end if; + when HALTED => + -- Processor halted, Double bus error! + NEXT_EX_STATE <= HALTED; + end case; + end process EXCEPTION_HANDLER_DEC; +end BEHAVIOR; + diff --git a/common/CPU/68K30L/wf68k30L_opcode_decoder.vhd b/common/CPU/68K30L/wf68k30L_opcode_decoder.vhd new file mode 100644 index 00000000..32d0a9aa --- /dev/null +++ b/common/CPU/68K30L/wf68k30L_opcode_decoder.vhd @@ -0,0 +1,1345 @@ +------------------------------------------------------------------------ +---- ---- +---- WF68K30L IP Core: this is the bus controller module. ---- +---- ---- +---- Description: ---- +---- This module is a 68030 compatible instruction word decoder. ---- +---- ---- +---- It is primarily controlled by the following signals: ---- +---- OW_REQ, OPD_ACK, EW_REQ and EW_ACK. The handshaking is as ---- +---- follows: if a new instruction is required, assert the signal ---- +---- OW_REQ and wait until ACK is asserted by the decoder logic. ---- +---- Deassert OW_REQ right after ACK (in the same clock cycle). ---- +---- At this point, the required instruction has already been copied---- +---- from the pipe to the register BIW_0. The respective additional ---- +---- instruction words are located in BIW_1, BIW_2. For more infor- ---- +---- mation see the 68010 "Programmers Reference Manual" and the ---- +---- signal INSTR_LVL in this module. ---- +---- The extension request works in the same manner by asserting ---- +---- EW_REQ. At the time of EXT_ACK one extension word has been ---- +---- copied to EXT_WORD. ---- +---- Be aware that it is in the scope of the logic driving ---- +---- OW_REQ and EW_REQ to hold the instruction pipe aligned. ---- +---- This means in detail, that the correct number or instruction ---- +---- and extension words must be requested. Otherwise unpredictable ---- +---- processor behaviour will occur. Furthermore OW_REQ and EW_REQ ---- +---- must not be asserted the same time. ---- +---- This operation code decoder with the handshake logic as des- ---- +---- cribed above is the first pipeline stage of the CPU architec- ---- +---- ture. ---- +---- ---- +---- ---- +---- Author(s): ---- +---- - Wolfgang Foerster, wf@experiment-s.de; wf@inventronik.de ---- +---- ---- +------------------------------------------------------------------------ +---- ---- +---- Copyright © 2014-2019 Wolfgang Foerster Inventronik GmbH. ---- +---- ---- +---- This documentation describes Open Hardware and is licensed ---- +---- under the CERN OHL v. 1.2. You may redistribute and modify ---- +---- this documentation under the terms of the CERN OHL v.1.2. ---- +---- (http://ohwr.org/cernohl). This documentation is distributed ---- +---- WITHOUT ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING OF ---- +---- MERCHANTABILITY, SATISFACTORY QUALITY AND FITNESS FOR A ---- +---- PARTICULAR PURPOSE. Please see the CERN OHL v.1.2 for ---- +---- applicable conditions ---- +---- ---- +------------------------------------------------------------------------ +-- +-- Revision History +-- +-- Revision 2K14B 20141201 WF +-- Initial Release. +-- Revision 2K18A 20180620 WF +-- Removed REST_BIW_0. +-- Fixed the PW_EW_OFFSET calculation for JSR. +-- TOP, CONTROL, Exception Handler Opcode Decoder: Rearranged PC_INC and ipipe flush logic. +-- Fix for unimplemented or illegal operations: PC is increased before stacked. +-- Implemented the 68K10 loop mechanism. +-- Removed CAHR, we have no cache. +-- Rearranged address error handling. +-- Revision 2K19B 20191224 WF +-- Introduced signal synchronization in the P_BSY process to avoid malfunction by hazards. +-- + +library work; +use work.WF68K30L_PKG.all; + +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_unsigned.all; + +entity WF68K30L_OPCODE_DECODER is + generic(NO_LOOP : boolean); -- If true the DBcc loop mechanism is disabled. + port ( + CLK : in std_logic; + + OW_REQ_MAIN : in bit; -- Request from the execution unit. + EW_REQ_MAIN : in bit; -- Extension words request. + + EXH_REQ : in bit; -- Exception request. + BUSY_EXH : in bit; -- Exception handler is busy. + BUSY_MAIN : in bit; -- Main controller busy. + BUSY_OPD : out bit; -- This unit is busy. + + BKPT_INSERT : in bit; + BKPT_DATA : in std_logic_vector(15 downto 0); + + LOOP_EXIT : in bit; + LOOP_BSY : out bit; + + OPD_ACK_MAIN : out bit; -- Operation controller acknowledge. + EW_ACK : buffer bit; -- Extension word available. + + PC_INC : out bit; + PC_INC_EXH : in bit; + PC_ADR_OFFSET : out std_logic_vector(7 downto 0); + PC_EW_OFFSET : buffer std_logic_vector(3 downto 0); + PC_OFFSET : out std_logic_vector(7 downto 0); + + OPCODE_RD : out bit; + OPCODE_RDY : in bit; + OPCODE_VALID : in std_logic; + OPCODE_DATA : in std_logic_vector(15 downto 0); + + IPIPE_FILL : in bit; + IPIPE_FLUSH : in bit; -- Abandon the instruction pipe. + + -- Fault logic: + OW_VALID : out std_logic; -- Operation words valid. + RC : out std_logic; -- Rerun flag on instruction pipe stage C. + RB : out std_logic; -- Rerun flag on instruction pipe stage B. + FC : out std_logic; -- Fault on use of instruction pipe stage C. + FB : out std_logic; -- Fault on use of instruction pipe stage B. + + -- Trap logic: + SBIT : in std_logic; + TRAP_CODE : out TRAPTYPE_OPC; + + -- System control signals: + OP : buffer OP_68K; + BIW_0 : buffer std_logic_vector(15 downto 0); + BIW_1 : out std_logic_vector(15 downto 0); + BIW_2 : out std_logic_vector(15 downto 0); + EXT_WORD : out std_logic_vector(15 downto 0) + ); +end entity WF68K30L_OPCODE_DECODER; + +architecture BEHAVIOR of WF68K30L_OPCODE_DECODER is +type INSTR_LVL_TYPE is(D, C, B); +type IPIPE_TYPE is + record + D : std_logic_vector(15 downto 0); + C : std_logic_vector(15 downto 0); + B : std_logic_vector(15 downto 0); + end record; + +signal REQ : bit; +signal EW_REQ : bit; + +signal IPIPE : IPIPE_TYPE; +signal FIFO_RD : bit; +signal IPIPE_B_FAULT : std_logic; +signal IPIPE_C_FAULT : std_logic; +signal IPIPE_D_FAULT : std_logic; +signal IPIPE_PNTR : natural range 0 to 3; + +signal INSTR_LVL : INSTR_LVL_TYPE; +signal LOOP_ATN : boolean; +signal LOOP_BSY_I : boolean; +signal LOOP_OP : boolean; + +signal BKPT_REQ : bit; + +signal OP_I : OP_68K; + +signal OPCODE_FLUSH : bit; +signal OPCODE_RD_I : bit; +signal OPCODE_RDY_I : bit; +signal OW_REQ : bit; + +signal TRAP_CODE_I : TRAPTYPE_OPC; +signal FLUSHED : boolean; +signal PC_INC_I : bit; +signal PIPE_RDY : bit; +begin + P_BSY: process(CLK) + -- This logic requires asynchronous reset. This flip flop is intended + -- to break combinatorial loops. If an opcode cycle in the bus controller + -- unit is currently running, the actual PC address is stored during this + -- cycle. Therefore it is not possible to flush the pipe and manipulate + -- the PC during a running cycle. For the exception handler reading the + -- opcode is inhibited during a pipe flush. For the main controller unit + -- and the coprocessor interface the pipe is flushed after a running + -- opcode cycle. + -- Important note: to avoid asynchronous reset by data hazards the + -- resetting signals are synchronized on the negative clock edge. + variable OPCODE_RDY_VAR : bit; + variable BUSY_EXH_VAR : bit; + variable IPIPE_FILL_VAR : bit; + begin + if CLK = '0' and CLK' event then + OPCODE_RDY_VAR := OPCODE_RDY; + BUSY_EXH_VAR := BUSY_EXH; + IPIPE_FILL_VAR := IPIPE_FILL; + end if; + -- + if OPCODE_RDY_VAR = '1' then + OPCODE_RD_I <= '0'; + elsif BUSY_EXH_VAR = '1' and IPIPE_FILL_VAR = '0' then + OPCODE_RD_I <= '0'; + elsif CLK = '1' and CLK' event then + if IPIPE_FLUSH = '1' then + OPCODE_RD_I <= '1'; + elsif (LOOP_ATN = true and OPCODE_RD_I = '0') or LOOP_BSY_I = true then + OPCODE_RD_I <= '0'; + elsif IPIPE_PNTR < 3 then + OPCODE_RD_I <= '1'; + end if; + end if; + end process P_BSY; + + P_OPCODE_FLUSH: process + -- If there is a pending opcode cycle during a pipe flush, + -- an opcode mismatch will destroy scalar opcode processing. + -- To avoid this, we have to dismiss the upcoming opcode. + begin + wait until CLK = '1' and CLK' event; + if IPIPE_FLUSH = '1' and OPCODE_RD_I = '1' and OPCODE_RDY = '0' then + OPCODE_FLUSH <= '1'; + elsif OPCODE_RDY = '1' or BUSY_EXH = '1' then + OPCODE_FLUSH <= '0'; + end if; + end process P_OPCODE_FLUSH; + + OPCODE_RD <= OPCODE_RD_I; + OPCODE_RDY_I <= '0' when OPCODE_FLUSH = '1' else OPCODE_RDY; -- Dismiss the current read cycle. + BUSY_OPD <= '0' when EXH_REQ = '1' and BUSY_MAIN = '0' and IPIPE_PNTR > 0 and OPCODE_RD_I = '0' else -- Fill one opcode is sufficient here. + '1' when IPIPE_PNTR < 3 or OPCODE_RD_I = '1' else '0'; + + INSTRUCTION_PIPE: process + -- These are the instruction pipe FIFO registers. The opcodes are stored in IPIPE.B, IPIPE.C + -- and IPIPE.D which is copied to the instruction register or to the respective extension when + -- read. Be aware, that the pipe is always completely refilled to determine the correct INSTR_LVL + -- before it is copied to the execution unit. + variable IPIPE_D_VAR : std_logic_vector(15 downto 0); + begin + wait until CLK = '1' and CLK' event; + if IPIPE_FLUSH = '1' then + IPIPE.D <= (others => '0'); + IPIPE.C <= (others => '0'); + IPIPE.B <= (others => '0'); + IPIPE_PNTR <= 0; + elsif BKPT_INSERT = '1' then + IPIPE_D_VAR := IPIPE.D; + IPIPE.D <= BKPT_DATA; -- Insert the breakpoint data. + BKPT_REQ <= '1'; + elsif OW_REQ = '1' and BKPT_REQ = '1' then + IPIPE.D <= IPIPE_D_VAR; -- Restore from breakpoint. + BKPT_REQ <= '0'; + elsif LOOP_ATN = true and OPCODE_RD_I = '1' then + null; -- Wait for pending opcodes. + elsif OW_REQ = '1' and PIPE_RDY = '1' and OP_I = DBcc and LOOP_OP = true and IPIPE.C = x"FFFC" then -- Initialize the loop. + IPIPE.D <= BIW_0; -- This is the LEVEL D operation for the loop. + elsif OW_REQ = '1' and LOOP_BSY_I = true then + IPIPE.D <= BIW_0; -- Recycle the loop operations. + elsif LOOP_BSY_I = true then + null; -- Do not change the pipe during the loop. + elsif OW_REQ = '1' and INSTR_LVL = D and PIPE_RDY = '1' and IPIPE_PNTR = 2 then + if OPCODE_RDY_I = '1' then + IPIPE.D <= IPIPE.C; + IPIPE.C <= OPCODE_DATA; + IPIPE_D_FAULT <= IPIPE_C_FAULT; + IPIPE_C_FAULT <= not OPCODE_VALID; + else + IPIPE.D <= IPIPE.C; + IPIPE_D_FAULT <= IPIPE_C_FAULT; + IPIPE_PNTR <= IPIPE_PNTR - 1; + end if; + elsif OW_REQ = '1' and INSTR_LVL = D and PIPE_RDY = '1' and IPIPE_PNTR = 3 then + if OPCODE_RDY_I = '1' then + IPIPE.D <= IPIPE.C; + IPIPE.C <= IPIPE.B; + IPIPE.B <= OPCODE_DATA; + IPIPE_D_FAULT <= IPIPE_C_FAULT; + IPIPE_C_FAULT <= IPIPE_B_FAULT; + IPIPE_B_FAULT <= not OPCODE_VALID; + else + IPIPE.D <= IPIPE.C; + IPIPE.C <= IPIPE.B; + IPIPE_D_FAULT <= IPIPE_C_FAULT; + IPIPE_C_FAULT <= IPIPE_B_FAULT; + IPIPE_PNTR <= IPIPE_PNTR - 1; + end if; + elsif OW_REQ = '1' and INSTR_LVL = C and PIPE_RDY = '1' and IPIPE_PNTR = 2 then + if OPCODE_RDY_I = '1' then + IPIPE.D <= OPCODE_DATA; + IPIPE_D_FAULT <= not OPCODE_VALID; + IPIPE_PNTR <= IPIPE_PNTR - 1; + else + IPIPE_PNTR <= 0; + end if; + elsif OW_REQ = '1' and INSTR_LVL = C and PIPE_RDY = '1' and IPIPE_PNTR = 3 then + if OPCODE_RDY_I = '1' then + IPIPE.D <= IPIPE.B; + IPIPE.C <= OPCODE_DATA; + IPIPE_D_FAULT <= IPIPE_B_FAULT; + IPIPE_C_FAULT <= not OPCODE_VALID; + IPIPE_PNTR <= IPIPE_PNTR - 1; + else + IPIPE.D <= IPIPE.B; + IPIPE_D_FAULT <= IPIPE_B_FAULT; + IPIPE_PNTR <= IPIPE_PNTR - 2; + end if; + elsif OW_REQ = '1' and INSTR_LVL = B and PIPE_RDY = '1' then -- IPIPE_PNTR = 3. + if OPCODE_RDY_I = '1' then + IPIPE.D <= OPCODE_DATA; + IPIPE_D_FAULT <= not OPCODE_VALID; + IPIPE_PNTR <= IPIPE_PNTR - 2; + else + IPIPE_PNTR <= 0; + end if; + elsif EW_REQ = '1' and IPIPE_PNTR >= 1 then + case IPIPE_PNTR is + when 3 => + if OPCODE_RDY_I = '1' then + IPIPE.D <= IPIPE.C; + IPIPE.C <= IPIPE.B; + IPIPE.B <= OPCODE_DATA; + IPIPE_D_FAULT <= IPIPE_C_FAULT; + IPIPE_C_FAULT <= IPIPE_B_FAULT; + IPIPE_B_FAULT <= not OPCODE_VALID; + else + IPIPE.D <= IPIPE.C; + IPIPE.C <= IPIPE.B; + IPIPE_D_FAULT <= IPIPE_C_FAULT; + IPIPE_C_FAULT <= IPIPE_B_FAULT; + IPIPE_PNTR <= IPIPE_PNTR - 1; + end if; + when 2 => + if OPCODE_RDY_I = '1' then + IPIPE.D <= IPIPE.C; + IPIPE.C <= OPCODE_DATA; + IPIPE_D_FAULT <= IPIPE_C_FAULT; + IPIPE_C_FAULT <= not OPCODE_VALID; + else + IPIPE.D <= IPIPE.C; + IPIPE_D_FAULT <= IPIPE_C_FAULT; + IPIPE_PNTR <= IPIPE_PNTR - 1; + end if; + when 1 => + if OPCODE_RDY_I = '1' then + IPIPE.D <= OPCODE_DATA; + IPIPE_D_FAULT <= not OPCODE_VALID; + else + IPIPE_PNTR <= 0; + end if; + when others => null; + end case; + elsif OPCODE_RDY_I = '1' then + case IPIPE_PNTR is + when 2 => + IPIPE.B <= OPCODE_DATA; + IPIPE_B_FAULT <= not OPCODE_VALID; + IPIPE_PNTR <= 3; + when 1 => + IPIPE.C <= OPCODE_DATA; + IPIPE_C_FAULT <= not OPCODE_VALID; + IPIPE_PNTR <= 2; + when 0 => + IPIPE.D <= OPCODE_DATA; + IPIPE_D_FAULT <= not OPCODE_VALID; + IPIPE_PNTR <= 1; + when others => null; + end case; + end if; + end process INSTRUCTION_PIPE; + + P_FAULT: process + -- This are the fault flags for pipe B and C. + -- These flags are set, when an instruction + -- request uses either of the respective pipes. + begin + wait until CLK = '1' and CLK' event; + if IPIPE_FLUSH = '1' then + OW_VALID <= '0'; + FC <= '0'; + FB <= '0'; + elsif OW_REQ = '1' and LOOP_BSY_I = true then + OW_VALID <= '1'; + elsif OW_REQ = '1' and PIPE_RDY = '1' and INSTR_LVL = D then + OW_VALID <= not IPIPE_D_FAULT; + FC <= '0'; + FB <= '0'; + elsif OW_REQ = '1' and PIPE_RDY = '1' and INSTR_LVL = C then + OW_VALID <= not(IPIPE_D_FAULT or IPIPE_C_FAULT); + FC <= IPIPE_C_FAULT; + FB <= '0'; + elsif OW_REQ = '1' and PIPE_RDY = '1' and INSTR_LVL = B then + OW_VALID <= not (IPIPE_D_FAULT or IPIPE_C_FAULT or IPIPE_B_FAULT); + FC <= IPIPE_C_FAULT; + FB <= IPIPE_B_FAULT; + elsif EW_REQ = '1' and PIPE_RDY = '1' then + OW_VALID <= not IPIPE_D_FAULT; + FC <= '0'; + FB <= '0'; + end if; + -- The Rerun Flags: + if IPIPE_FLUSH = '1' then + RC <= '0'; + RB <= '0'; + elsif (EW_REQ or OW_REQ) = '1' and PIPE_RDY = '1' then + RC <= IPIPE_C_FAULT; + RB <= IPIPE_B_FAULT; + end if; + end process P_FAULT; + + OUTBUFFERS: process + variable OP_STOP : boolean; + begin + wait until CLK = '1' and CLK' event; + if OP_STOP = true and IPIPE_FLUSH = '1' then + TRAP_CODE <= NONE; + OP_STOP := false; + elsif IPIPE_FLUSH = '1' then + TRAP_CODE <= NONE; + elsif OP_STOP = true then + null; -- Do not update after PC is incremented. + elsif LOOP_ATN = true and OPCODE_RD_I = '1' then + null; -- Wait for pending opcodes. + elsif OW_REQ = '1' and LOOP_BSY_I = true then + OP <= OP_I; + BIW_0 <= IPIPE.D; + TRAP_CODE <= TRAP_CODE_I; + elsif OW_REQ = '1' and (PIPE_RDY = '1' or BKPT_REQ = '1') then + -- Be aware: all BIW are written unaffected + -- if they are all used. + OP <= OP_I; + BIW_0 <= IPIPE.D; + BIW_1 <= IPIPE.C; + BIW_2 <= IPIPE.B; + TRAP_CODE <= TRAP_CODE_I; + -- + if OP_I = STOP then + OP_STOP := true; + end if; + elsif EW_REQ = '1' and IPIPE_PNTR /= 0 then + EXT_WORD <= IPIPE.D; + end if; + end process OUTBUFFERS; + + LOOP_OP <= false when NO_LOOP = true else + true when OP = MOVE and BIW_0(8 downto 3) = "010010" else -- (Ay) to (Ax). + true when OP = MOVE and BIW_0(8 downto 3) = "011010" else -- (Ay) to (Ax)+. + true when OP = MOVE and BIW_0(8 downto 3) = "100010" else -- (Ay) to -(Ax). + true when OP = MOVE and BIW_0(8 downto 3) = "010011" else -- (Ay)+ to (Ax). + true when OP = MOVE and BIW_0(8 downto 3) = "011011" else -- (Ay)+ to (Ax)+. + true when OP = MOVE and BIW_0(8 downto 3) = "100011" else -- (Ay)+ to -(Ax). + true when OP = MOVE and BIW_0(8 downto 3) = "010100" else -- -(Ay) to (Ax). + true when OP = MOVE and BIW_0(8 downto 3) = "011100" else -- -(Ay) to (Ax)+. + true when OP = MOVE and BIW_0(8 downto 3) = "100100" else -- -(Ay) to -(Ax). + true when OP = MOVE and BIW_0(8 downto 3) = "100100" else -- -(Ay) to -(Ax). + true when OP = MOVE and BIW_0(8 downto 3) = "010000" else -- Dy to (Ax). + true when OP = MOVE and BIW_0(8 downto 3) = "011000" else -- Dy to (Ax)+. + true when OP = MOVE and BIW_0(8 downto 3) = "010001" else -- Ay to (Ax). + true when OP = MOVE and BIW_0(8 downto 3) = "011001" else -- Ay to (Ax)+. + true when (OP = ADD or OP = AND_B or OP = CMP or OP = EOR or OP = OR_B or OP = SUB) and BIW_0(5 downto 3) = "010" else -- (Ay) to Dx, Dx to (Ay). + true when (OP = ADD or OP = AND_B or OP = CMP or OP = EOR or OP = OR_B or OP = SUB) and BIW_0(5 downto 3) = "011" else -- (Ay)+ to Dx, Dx to (Ay)+. + true when (OP = ADD or OP = AND_B or OP = CMP or OP = EOR or OP = OR_B or OP = SUB) and BIW_0(5 downto 3) = "100" else -- -(Ay) to Dx, Dx to -(Ay). + true when (OP = ADDA or OP = CMPA or OP = SUBA) and BIW_0(5 downto 3) = "010" else -- (Ay) to Ax. + true when (OP = ADDA or OP = CMPA or OP = SUBA) and BIW_0(5 downto 3) = "011" else -- (Ay)+ to Ax. + true when (OP = ADDA or OP = CMPA or OP = SUBA) and BIW_0(5 downto 3) = "100" else -- -(Ay) to Ax. + true when OP = ABCD or OP = SBCD or OP = ADDX or OP = SUBX or OP = CMPM else -- -(Ay) to -(Ay), (Ay)+ to (Ay)+ for CMPM. + true when (OP = CLR or OP = NEG or OP = NEGX or OP = NOT_B or OP = TST or OP = NBCD) and BIW_0(5 downto 3) = "010" else -- (Ay). + true when (OP = CLR or OP = NEG or OP = NEGX or OP = NOT_B or OP = TST or OP = NBCD) and BIW_0(5 downto 3) = "011" else -- (Ay)+. + true when (OP = CLR or OP = NEG or OP = NEGX or OP = NOT_B or OP = TST or OP = NBCD) and BIW_0(5 downto 3) = "100" else -- -(Ay). + true when (OP = ASL or OP = ASR or OP = LSL or OP = LSR) and BIW_0(7 downto 3) = "11010" else -- (Ay) by #1. + true when (OP = ASL or OP = ASR or OP = LSL or OP = LSR) and BIW_0(7 downto 3) = "11011" else -- (Ay)+ by #1. + true when (OP = ASL or OP = ASR or OP = LSL or OP = LSR) and BIW_0(7 downto 3) = "11100" else -- -(Ay) by #1. + true when (OP = ROTL or OP = ROTR or OP = ROXL or OP = ROXR) and BIW_0(7 downto 3) = "11010" else -- (Ay) by #1. + true when (OP = ROTL or OP = ROTR or OP = ROXL or OP = ROXR) and BIW_0(7 downto 3) = "11011" else -- (Ay)+ by #1. + true when (OP = ROTL or OP = ROTR or OP = ROXL or OP = ROXR) and BIW_0(7 downto 3) = "11100" else false; -- -(Ay) by #1. + + -- This is the loop attention signal. There are several conditions to start a loop operation. + -- 1. A loop capable operation is in progress indicated by LOOP_OP. + -- 2. A DBcc operation is coming up (IPIPE.D). + -- 3. The displacement is minus four (IPIPE.C). + -- 4. The exception handler may not indicate a request. Otherwise the system may hang in a self + -- blocking mechanism concerning OW_REQ, LOOP_ATN, ALU_BSY. + LOOP_ATN <= false when EXH_REQ = '1' else + true when LOOP_BSY_I = false and LOOP_OP = true and OP_I = DBcc and IPIPE.C = x"FFFC" else false; -- IPIPE.C value must be minus four. + + P_LOOP: process + -- This flip flop controls the loop mode of the + -- processor. Refer to the MC68000 user manual + -- Appendix A for more information. + begin + wait until CLK = '1' and CLK' event; + if LOOP_ATN = true and OW_REQ = '1' and OPCODE_RD_I = '0' then + LOOP_BSY <= '1'; + LOOP_BSY_I <= true; + elsif LOOP_EXIT = '1' or BUSY_EXH = '1' then + LOOP_BSY <= '0'; + LOOP_BSY_I <= false; + end if; + end process P_LOOP; + + OW_REQ <= '0' when BUSY_EXH = '1' else OW_REQ_MAIN; + EW_REQ <= EW_REQ_MAIN; + + PIPE_RDY <= '1' when OW_REQ = '1' and IPIPE_PNTR = 3 and INSTR_LVL = B else + '1' when OW_REQ = '1' and IPIPE_PNTR > 1 and INSTR_LVL = C else + '1' when OW_REQ = '1' and IPIPE_PNTR > 1 and INSTR_LVL = D else -- We need always pipe C and D to determine the INSTR_LVL. + '1' when EW_REQ = '1' and IPIPE_PNTR > 0 else '0'; + + HANDSHAKING: process + -- Wee need these flip flops to ensure, that the OUTBUFFERS are + -- written when the respecktive _ACK signal is asserted. + -- The breakpoint cycles are valid for one word operations and + -- therefore does never start FPU operations. + begin + wait until CLK = '1' and CLK' event; + if EW_REQ = '1' and IPIPE_PNTR /= 0 then + EW_ACK <= '1'; + else + EW_ACK <= '0'; + end if; + + if IPIPE_FLUSH = '1' then + OPD_ACK_MAIN <= '0'; + elsif TRAP_CODE_I = T_PRIV then -- No action when priviledged. + OPD_ACK_MAIN <= '0'; + elsif OW_REQ = '1' and LOOP_BSY_I = true then + OPD_ACK_MAIN <= '1'; + elsif OW_REQ = '1' and (PIPE_RDY = '1' or BKPT_REQ = '1') then + OPD_ACK_MAIN <= '1'; + else + OPD_ACK_MAIN <= '0'; + end if; + end process HANDSHAKING; + + P_PC_OFFSET: process(CLK, BUSY_EXH, LOOP_BSY_I, LOOP_EXIT, OP, PC_INC_I) + -- Be Aware: the ADR_OFFSET requires the 'old' PC_VAR. + -- To arrange this, the ADR_OFFSET logic is located + -- above the PC_VAR logic. Do not change this! + -- The PC_VAR is modeled in a way, that the PC points + -- always to the BIW_0. + -- The PC_EW_OFFSET is also used for the calculation + -- of the correct PC value written to the stack pointer + -- during BSR, JSR and exceptions. + variable ADR_OFFSET : std_logic_vector(6 downto 0); + variable PC_VAR : std_logic_vector(6 downto 0); + variable PC_VAR_MEM : std_logic_vector(6 downto 0); + begin + if CLK = '1' and CLK' event then + if IPIPE_FLUSH = '1' then + ADR_OFFSET := "0000000"; + elsif PC_INC_I = '1' and OPCODE_RDY_I = '1' then + ADR_OFFSET := ADR_OFFSET + '1' - PC_VAR; + elsif OPCODE_RDY_I = '1' then + ADR_OFFSET := ADR_OFFSET + '1'; + elsif PC_INC_I = '1' then + ADR_OFFSET := ADR_OFFSET - PC_VAR; + end if; + -- + if BUSY_EXH = '0' then + PC_VAR_MEM := PC_VAR; -- Store the old offset to write back on the stack. + end if; + + if BUSY_EXH = '1' then + -- New PC is loaded by the exception handler. + -- So PC_VAR must be initialized. + PC_VAR := "0000000"; + elsif PC_INC_I = '1' or FLUSHED = true then + case INSTR_LVL is + when D => PC_VAR := "0000001"; + when C => PC_VAR := "0000010"; + when B => PC_VAR := "0000011"; + end case; + elsif EW_REQ = '1' and IPIPE_PNTR /= 0 then + PC_VAR := PC_VAR + '1'; + end if; + -- + if OW_REQ = '1' and BKPT_REQ = '1' then + PC_EW_OFFSET <= "0010"; -- Always level D operations. + elsif OW_REQ = '1' and PIPE_RDY = '1' and OP_I = JSR then -- Initialize. + PC_EW_OFFSET <= x"0"; + elsif OW_REQ = '1' and PIPE_RDY = '1' then -- BSR. + case INSTR_LVL is + when D => PC_EW_OFFSET <= "0010"; + when C => PC_EW_OFFSET <= "0100"; + when others => PC_EW_OFFSET <= "0110"; -- LONG displacement. + end case; + elsif EW_ACK = '1' and OP = JSR then -- Calculate the required extension words. + PC_EW_OFFSET <= PC_EW_OFFSET + "010"; + end if; + end if; + -- + if BUSY_EXH = '1' and PC_INC_I = '1' then + PC_OFFSET <= PC_VAR_MEM & '0'; + elsif OP = DBcc and LOOP_BSY_I = true and LOOP_EXIT = '0' then + -- Suppress to increment after DBcc operation during the loop to + -- handle a correct PC with displacement when looping around. + -- In non looping mode, the PC_ING is superseeded by + -- IPIPE_FLUSH in the PC logic. In loop mode we have no flush. + PC_OFFSET <= x"00"; + else + PC_OFFSET <= PC_VAR & '0'; + end if; + PC_ADR_OFFSET <= ADR_OFFSET & '0'; + end process P_PC_OFFSET; + + P_FLUSH: process + -- This flip flop is intended to control the incrementation + -- of the PC: normally the PC is updated in the end of an + -- operation (if a new opword is available) or otherwise in + -- the START_OP phase. When the instruction pipe is flushed, + -- it is required to increment the PC immediately to provide + -- the correct address for the pipe refilling. In this case + -- the PC update after the pipe refill is suppressed. + begin + wait until CLK = '1' and CLK' event; + if IPIPE_FLUSH = '1' then + FLUSHED <= true; + elsif OW_REQ = '1' and PIPE_RDY = '1' then + FLUSHED <= false; + end if; + end process P_FLUSH; + + PC_INC <= PC_INC_I; + PC_INC_I <= '0' when FLUSHED = true else -- Avoid double increment after a flushed pipe. + '1' when IPIPE_FLUSH = '1' and BUSY_MAIN = '1' else -- If the pipe is flushed, we need the new PC value for refilling. + '0' when BKPT_REQ = '1' else -- Do not update! + '1' when OW_REQ = '1' and PIPE_RDY = '1' else PC_INC_EXH; + + + -- This signal indicates how many pipe stages are used at a time. + -- Be aware: all coprocessor commands are level D to meet the require- + -- ments of the scanPC. + INSTR_LVL <= D when TRAP_CODE_I = T_PRIV else -- Points to the first word. Required for stacking. + B when OP_I = ADDI and IPIPE.D(7 downto 6) = "10" else + B when OP_I = ANDI and IPIPE.D(7 downto 6) = "10" else + B when (OP_I = Bcc or OP_I = BRA or OP_I = BSR) and IPIPE.D(7 downto 0) = x"FF" else + B when OP_I = CAS2 or (OP_I = CMPI and IPIPE.D(7 downto 6) = "10") else + B when OP_I = EORI and IPIPE.D(7 downto 6) = "10" else + B when OP_I = LINK and IPIPE.D(11 downto 3) = "100000001" else -- LONG. + B when OP_I = ORI and IPIPE.D(7 downto 6) = "10" else + B when OP_I = SUBI and IPIPE.D(7 downto 6) = "10" else + B when OP_I = TRAPcc and IPIPE.D(2 downto 0) = "011" else + C when OP_I = ADDI or OP_I = ANDI or OP_I = ANDI_TO_SR or OP_I = ANDI_TO_CCR else + C when (OP_I = BCHG or OP_I = BCLR or OP_I = BSET or OP_I = BTST) and IPIPE.D(8) = '0' else + C when (OP_I = Bcc or OP_I = BRA or OP_I = BSR) and IPIPE.D(7 downto 0) = x"00" else + C when OP_I = BFCHG or OP_I = BFCLR or OP_I = BFEXTS or OP_I = BFEXTU else + C when OP_I = BFFFO or OP_I = BFINS or OP_I = BFSET or OP_I = BFTST else + C when OP_I = CAS or OP_I = CHK2 or OP_I = CMP2 or OP_I = CMPI or OP_I = DBcc else + C when (OP_I = DIVS or OP_I = DIVU) and IPIPE.D(8 downto 6) = "001" else + C when OP_I = EORI or OP_I = EORI_TO_CCR or OP_I = EORI_TO_SR else + C when OP_I = LINK or OP_I = MOVEC else + C when OP_I = MOVEM or OP_I = MOVEP or OP_I = MOVES else + C when (OP_I = MULS or OP_I = MULU) and IPIPE.D(8 downto 6) = "000" else + C when OP_I = ORI_TO_CCR or OP_I = ORI_TO_SR or OP_I = ORI else + C when OP_I = PACK or OP_I = RTD or OP_I = SUBI or OP_I = STOP else + C when OP_I = TRAPcc and IPIPE.D(2 downto 0) = "010" else + C when OP_I = UNPK else D; + + TRAP_CODE_I <= T_1010 when OP_I = UNIMPLEMENTED and IPIPE.D(15 downto 12) = x"A" else + T_1111 when OP_I = UNIMPLEMENTED and IPIPE.D(15 downto 12) = x"F" else + T_ILLEGAL when OP_I = ILLEGAL else + T_RTE when OP_I = RTE and SBIT = '1' else -- Handled like a trap simplifies the code. + T_TRAP when OP_I = TRAP else + T_PRIV when OP_I = ANDI_TO_SR and SBIT = '0' else + T_PRIV when OP_I = EORI_TO_SR and SBIT = '0' else + T_PRIV when (OP_I = MOVE_FROM_SR or OP_I = MOVE_TO_SR) and SBIT = '0' else + T_PRIV when (OP_I = MOVE_USP or OP_I = MOVEC or OP_I = MOVES) and SBIT = '0' else + T_PRIV when OP_I = ORI_TO_SR and SBIT = '0' else + T_PRIV when (OP_I = RESET or OP_I = RTE) and SBIT = '0' else + T_PRIV when OP_I = STOP and SBIT = '0' else NONE; + + OP_DECODE: process(IPIPE) + begin + -- The default OPCODE is the ILLEGAL operation, if no of the following conditions are met. + -- If any not used bit pattern occurs, the CPU will result in an ILLEGAL trap. An exception of + -- this behavior is the OPCODE with the 1010 or the 1111 pattern in the four MSBs. + -- These lead to the respective traps. + OP_I <= ILLEGAL; + case IPIPE.D(15 downto 12) is -- Operation code map. + when x"0" => -- Bit manipulation / MOVEP / Immediate. + if IPIPE.D(11 downto 0) = x"03C" then + OP_I <= ORI_TO_CCR; + elsif IPIPE.D(11 downto 0) = x"07C" then + OP_I <= ORI_TO_SR; + elsif IPIPE.D(11 downto 0) = x"23C" then + OP_I <= ANDI_TO_CCR; + elsif IPIPE.D(11 downto 0) = x"27C" then + OP_I <= ANDI_TO_SR; + elsif IPIPE.D(11 downto 0) = x"A3C" then + OP_I <= EORI_TO_CCR; + elsif IPIPE.D(11 downto 0) = x"A7C" then + OP_I <= EORI_TO_SR; + elsif IPIPE.D(11 downto 0) = "110011111100" then + OP_I <= CAS2; + elsif IPIPE.D(11 downto 0) = "111011111100" then + OP_I <= CAS2; + elsif IPIPE.D(11 downto 8) = "1110" and IPIPE.D(7 downto 6) < "11" and IPIPE.D(5 downto 3) >= "010" and IPIPE.D(5 downto 3) < "111" then + OP_I <= MOVES; + elsif IPIPE.D(11 downto 8) = "1110" and IPIPE.D(7 downto 6) < "11" and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "010" then + OP_I <= MOVES; + elsif IPIPE.D(8 downto 6) > "011" and IPIPE.D(5 downto 3) = "001" then + OP_I <= MOVEP; + elsif IPIPE.D(11) = '0' and IPIPE.D(10 downto 9) /= "11" and IPIPE.D(8 downto 6) = "011" and IPIPE.D(5 downto 3) = "010" and IPIPE.C(11) = '1' then + OP_I <= CHK2; + elsif IPIPE.D(11) = '0' and IPIPE.D(10 downto 9) /= "11" and IPIPE.D(8 downto 6) = "011" and IPIPE.D(5 downto 3) > "100" and IPIPE.D(5 downto 3) < "111" and IPIPE.C(11) = '1' then + OP_I <= CHK2; + elsif IPIPE.D(11) = '0' and IPIPE.D(10 downto 9) /= "11" and IPIPE.D(8 downto 6) = "011" and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "100" and IPIPE.C(11) = '1' then + OP_I <= CHK2; + elsif IPIPE.D(11) = '0' and IPIPE.D(10 downto 9) /= "11" and IPIPE.D(8 downto 6) = "011" and IPIPE.D(5 downto 3) = "010" and IPIPE.C(11) = '0' then + OP_I <= CMP2; + elsif IPIPE.D(11) = '0' and IPIPE.D(10 downto 9) /= "11" and IPIPE.D(8 downto 6) = "011" and IPIPE.D(5 downto 3) > "100" and IPIPE.D(5 downto 3) < "111" and IPIPE.C(11) = '0' then + OP_I <= CMP2; + elsif IPIPE.D(11) = '0' and IPIPE.D(10 downto 9) /= "11" and IPIPE.D(8 downto 6) = "011" and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "100" and IPIPE.C(11) = '0' then + OP_I <= CMP2; + elsif IPIPE.D(11) = '1' and IPIPE.d(10 downto 9) /= "00" and IPIPE.D(8 downto 6) = "011" and IPIPE.D(5 downto 3) > "001" and IPIPE.D(5 downto 3) < "111" then + OP_I <= CAS; + elsif IPIPE.D(11) = '1' and IPIPE.d(10 downto 9) /= "00" and IPIPE.D(8 downto 6) = "011" and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "010" then + OP_I <= CAS; + else + case IPIPE.D(5 downto 3) is -- Addressing mode. + when "000" | "010" | "011" | "100" | "101" | "110" => + -- Bit operations with static bit number: + if IPIPE.D(11 downto 6) = "100000" then + OP_I <= BTST; + elsif IPIPE.D(11 downto 6) = "100001" then + OP_I <= BCHG; + elsif IPIPE.D(11 downto 6) = "100010" then + OP_I <= BCLR; + elsif IPIPE.D(11 downto 6) = "100011" then + OP_I <= BSET; + -- Logic operations: + elsif IPIPE.D(11 downto 8) = x"0" and IPIPE.D(7 downto 6) < "11" then + OP_I <= ORI; + elsif IPIPE.D(11 downto 8) = x"2" and IPIPE.D(7 downto 6) < "11" then + OP_I <= ANDI; + elsif IPIPE.D(11 downto 8) = x"4" and IPIPE.D(7 downto 6) < "11" then + OP_I <= SUBI; + elsif IPIPE.D(11 downto 8) = x"6" and IPIPE.D(7 downto 6) < "11" then + OP_I <= ADDI; + elsif IPIPE.D(11 downto 8) = x"A" and IPIPE.D(7 downto 6) < "11" then + OP_I <= EORI; + elsif IPIPE.D(11 downto 8) = x"C" and IPIPE.D(7 downto 6) < "11" then + OP_I <= CMPI; + -- Bit operations with dynamic bit number: + elsif IPIPE.D(8 downto 6) = "100" then + OP_I <= BTST; + elsif IPIPE.D(8 downto 6) = "101" then + OP_I <= BCHG; + elsif IPIPE.D(8 downto 6) = "110" then + OP_I <= BCLR; + elsif IPIPE.D(8 downto 6) = "111" then + OP_I <= BSET; + end if; + when "111" => + -- In the addressing mode "111" not all register selections are valid. + -- Bit operations with static bit number: + if IPIPE.D(11 downto 6) = "100000" and IPIPE.D(2 downto 0) < "100" then + OP_I <= BTST; + elsif IPIPE.D(11 downto 6) = "100001" and IPIPE.D(2 downto 0) < "010" then + OP_I <= BCHG; + elsif IPIPE.D(11 downto 6) = "100010" and IPIPE.D(2 downto 0) < "010" then + OP_I <= BCLR; + elsif IPIPE.D(11 downto 6) = "100011" and IPIPE.D(2 downto 0) < "010" then + OP_I <= BSET; + -- Logic operations: + elsif IPIPE.D(11 downto 8) = x"0" and IPIPE.D(7 downto 6) < "11" and IPIPE.D(2 downto 0) < "010" then + OP_I <= ORI; + elsif IPIPE.D(11 downto 8) = x"2" and IPIPE.D(7 downto 6) < "11" and IPIPE.D(2 downto 0) < "010" then + OP_I <= ANDI; + elsif IPIPE.D(11 downto 8) = x"4" and IPIPE.D(7 downto 6) < "11" and IPIPE.D(2 downto 0) < "010" then + OP_I <= SUBI; + elsif IPIPE.D(11 downto 8) = x"6" and IPIPE.D(7 downto 6) < "11" and IPIPE.D(2 downto 0) < "010" then + OP_I <= ADDI; + elsif IPIPE.D(11 downto 8) = x"A" and IPIPE.D(7 downto 6) < "11" and IPIPE.D(2 downto 0) < "010" then + OP_I <= EORI; + elsif IPIPE.D(11 downto 8) = x"C" and IPIPE.D(7 downto 6) < "11" and IPIPE.D(2 downto 0) < "100" then + OP_I <= CMPI; + -- Bit operations with dynamic bit number: + elsif IPIPE.D(8 downto 6) = "100" and IPIPE.D(2 downto 0) < "101" then + OP_I <= BTST; + elsif IPIPE.D(8 downto 6) = "101" and IPIPE.D(2 downto 0) < "010" then + OP_I <= BCHG; + elsif IPIPE.D(8 downto 6) = "110" and IPIPE.D(2 downto 0) < "010" then + OP_I <= BCLR; + elsif IPIPE.D(8 downto 6) = "111" and IPIPE.D(2 downto 0) < "010" then + OP_I <= BSET; + end if; + when others => + null; + end case; + end if; + when x"1" => -- Move BYTE. + if IPIPE.D(8 downto 6) = "111" and IPIPE.D(11 downto 9) < "010" + and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "101" then + OP_I <= MOVE; + elsif IPIPE.D(8 downto 6) = "111" and IPIPE.D(11 downto 9) < "010" and IPIPE.D(5 downto 3) /= "001" and IPIPE.D(5 downto 3) /= "111" then + OP_I <= MOVE; + elsif IPIPE.D(8 downto 6) /= "001" and IPIPE.D(8 downto 6) /= "111" + and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "101" then + OP_I <= MOVE; + elsif IPIPE.D(8 downto 6) /= "001" and IPIPE.D(8 downto 6) /= "111" and IPIPE.D(5 downto 3) /= "001" and IPIPE.D(5 downto 3) /= "111" then + OP_I <= MOVE; + end if; + when x"2" | x"3" => -- Move WORD or LONG. + if IPIPE.D(8 downto 6) = "111" and IPIPE.D(11 downto 9) < "010" + and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "101" then + OP_I <= MOVE; + elsif IPIPE.D(8 downto 6) = "111" and IPIPE.D(11 downto 9) < "010" and IPIPE.D(5 downto 3) /= "111" then + OP_I <= MOVE; + elsif IPIPE.D(8 downto 6) = "001" and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "101" then + OP_I <= MOVEA; + elsif IPIPE.D(8 downto 6) = "001" and IPIPE.D(5 downto 3) /= "111" then + OP_I <= MOVEA; + elsif IPIPE.D(8 downto 6) /= "001" and IPIPE.D(8 downto 6) /= "111" and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "101" then + OP_I <= MOVE; + elsif IPIPE.D(8 downto 6) /= "001" and IPIPE.D(8 downto 6) /= "111" and IPIPE.D(5 downto 3) /= "111" then + OP_I <= MOVE; + end if; + when x"4" => -- Miscellaneous. + if IPIPE.D(11 downto 0) = x"E70" then + OP_I <= RESET; + elsif IPIPE.D(11 downto 0) = x"E71" then + OP_I <= NOP; + elsif IPIPE.D(11 downto 0) = x"E72" then + OP_I <= STOP; + elsif IPIPE.D(11 downto 0) = x"E73" then + OP_I <= RTE; + elsif IPIPE.D(11 downto 0) = x"E74" then + OP_I <= RTD; + elsif IPIPE.D(11 downto 0) = x"E75" then + OP_I <= RTS; + elsif IPIPE.D(11 downto 0) = x"E76" then + OP_I <= TRAPV; + elsif IPIPE.D(11 downto 0) = x"E77" then + OP_I <= RTR; + elsif IPIPE.D(11 downto 0) = x"AFC" then + OP_I <= ILLEGAL; + elsif IPIPE.D(11 downto 1) = "11100111101" and IPIPE.C(11 downto 0) = x"000" then + OP_I <= MOVEC; + elsif IPIPE.D(11 downto 1) = "11100111101" and IPIPE.C(11 downto 0) = x"001" then + OP_I <= MOVEC; + --elsif IPIPE.D(11 downto 1) = "11100111101" and IPIPE.C(11 downto 0) = x"002" then -- No cache. + -- OP_I <= MOVEC; + elsif IPIPE.D(11 downto 1) = "11100111101" and IPIPE.C(11 downto 0) = x"800" then + OP_I <= MOVEC; + elsif IPIPE.D(11 downto 1) = "11100111101" and IPIPE.C(11 downto 0) = x"801" then + OP_I <= MOVEC; + --elsif IPIPE.D(11 downto 1) = "11100111101" and IPIPE.C(11 downto 0) = x"802" then -- No cache. + -- OP_I <= MOVEC; + --elsif IPIPE.D(11 downto 1) = "11100111101" and IPIPE.C(11 downto 0) = x"803" then -- No MMU. + -- OP_I <= MOVEC; + --elsif IPIPE.D(11 downto 1) = "11100111101" and IPIPE.C(11 downto 0) = x"804" then -- No MMU. + -- OP_I <= MOVEC; + elsif IPIPE.D(11 downto 1) = "11100111101" then + OP_I <= ILLEGAL; -- Not valid MOVEC patterns. + elsif IPIPE.D(11 downto 3) = "100001001" then -- 68K20, 68K30, 68K40 + OP_I <= BKPT; + elsif IPIPE.D(11 downto 3) = "100000001" then -- 68K20, 68K30, 68K40 + OP_I <= LINK; -- LONG. + elsif IPIPE.D(11 downto 3) = "111001010" then + OP_I <= LINK; -- WORD. + elsif IPIPE.D(11 downto 3) = "111001011" then + OP_I <= UNLK; + elsif IPIPE.D(11 downto 3) = "100001000" then + OP_I <= SWAP; + elsif IPIPE.D(11 downto 4) = x"E4" then + OP_I <= TRAP; + elsif IPIPE.D(11 downto 4) = x"E6" then + OP_I <= MOVE_USP; + else + case IPIPE.D(5 downto 3) is -- Addressing mode. + when "000" | "010" | "011" | "100" | "101" | "110" => + if IPIPE.D(11 downto 6) = "110001" then + if IPIPE.C(11) = '1' then + OP_I <= DIVS; -- Long. + else + OP_I <= DIVU; -- Long. + end if; + elsif IPIPE.D(11 downto 6) = "001011" then + OP_I <= MOVE_FROM_CCR; + elsif IPIPE.D(11 downto 6) = "000011" then + OP_I <= MOVE_FROM_SR; + elsif IPIPE.D(11 downto 6) = "010011" then + OP_I <= MOVE_TO_CCR; + elsif IPIPE.D(11 downto 6) = "011011" then + OP_I <= MOVE_TO_SR; + elsif IPIPE.D(11 downto 6) = "110000" then + if IPIPE.C(11) = '1' then + OP_I <= MULS; -- Long. + else + OP_I <= MULU; -- Long. + end if; + elsif IPIPE.D(11 downto 6) = "100000" then + OP_I <= NBCD; + elsif IPIPE.D(11 downto 6) = "101011" then + OP_I <= TAS; + end if; + when "111" => -- Not all registers are valid for this mode. + if IPIPE.D(11 downto 6) = "110001" and IPIPE.D(2 downto 0) < "101" then + if IPIPE.C(11) = '1' then + OP_I <= DIVS; -- Long. + else + OP_I <= DIVU; -- Long. + end if; + elsif IPIPE.D(11 downto 6) = "001011" and IPIPE.D(2 downto 0) < "010" then + OP_I <= MOVE_FROM_CCR; + elsif IPIPE.D(11 downto 6) = "000011" and IPIPE.D(2 downto 0) < "010" then + OP_I <= MOVE_FROM_SR; + elsif IPIPE.D(11 downto 6) = "010011" and IPIPE.D(2 downto 0) < "101" then + OP_I <= MOVE_TO_CCR; + elsif IPIPE.D(11 downto 6) = "011011" and IPIPE.D(2 downto 0) < "101" then + OP_I <= MOVE_TO_SR; + elsif IPIPE.D(11 downto 6) = "110000" and IPIPE.D(2 downto 0) < "101" then + if IPIPE.C(11) = '1' then + OP_I <= MULS; -- Long. + else + OP_I <= MULU; -- Long. + end if; + elsif IPIPE.D(11 downto 6) = "100000" and IPIPE.D(2 downto 0) < "010" then + OP_I <= NBCD; + elsif IPIPE.D(11 downto 6) = "101011" and IPIPE.D(2 downto 0) < "010" then + OP_I <= TAS; + end if; + when others => + null; + end case; + + case IPIPE.D(5 downto 3) is -- Addressing mode. + when "010" | "101" | "110" => + if IPIPE.D(11 downto 6) = "100001" then + OP_I <= PEA; + elsif IPIPE.D(11 downto 6) = "111010" then + OP_I <= JSR; + elsif IPIPE.D(11 downto 6) = "111011" then + OP_I <= JMP; + end if; + when "111" => -- Not all registers are valid for this mode. + if IPIPE.D(11 downto 6) = "100001" and IPIPE.D(2 downto 0) < "100" then + OP_I <= PEA; + elsif IPIPE.D(11 downto 6) = "111010" and IPIPE.D(2 downto 0) < "100" then + OP_I <= JSR; + elsif IPIPE.D(11 downto 6) = "111011" and IPIPE.D(2 downto 0) < "100" then + OP_I <= JMP; + end if; + when others => + null; + end case; + + -- For the following operation codes a SIZE (IPIPE.D(7 downto 6)) is not valid. + -- For the following operation codes an addressing mode x"001" is not valid. + if IPIPE.D(7 downto 6) < "11" and IPIPE.D(5 downto 3) /= "001" and IPIPE.D(5 downto 3) /= "111" then + case IPIPE.D(11 downto 8) is + when x"0" => OP_I <= NEGX; + when x"2" => OP_I <= CLR; + when x"4" => OP_I <= NEG; + when x"6" => OP_I <= NOT_B; + when others => null; + end case; + -- Not all registers are valid for the addressing mode "111": + elsif IPIPE.D(7 downto 6) < "11" and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "010" then + case IPIPE.D(11 downto 8) is + when x"0" => OP_I <= NEGX; + when x"2" => OP_I <= CLR; + when x"4" => OP_I <= NEG; + when x"6" => OP_I <= NOT_B; + when others => null; + end case; + end if; + + -- if IPIPE.D(11 downto 8) = x"A" and IPIPE.D(7 downto 6) < "11" and IPIPE.D(5 downto 3) = "111" and (IPIPE.D(2 downto 0) < "010" or IPIPE.D(2 downto 0) = "100") then -- 68K + if IPIPE.D(11 downto 8) = x"A" and IPIPE.D(7 downto 6) < "11" and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "101" then + case IPIPE.D(7 downto 6) is + when "01" | "10" => OP_I <= TST; -- Long or word, all addressing modes. + when others => -- Byte: Address register direct not allowed. + if IPIPE.D(2 downto 0) /= "100" then + OP_I <= TST; + end if; + end case; + elsif IPIPE.D(11 downto 8) = x"A" and IPIPE.D(7 downto 6) < "11" and IPIPE.D(5 downto 3) /= "111" then + case IPIPE.D(7 downto 6) is + when "01" | "10" => OP_I <= TST; -- Long or word, all addressing modes. + when others => -- Byte: Address register direct not allowed. + if IPIPE.D(5 downto 3) /= "001" then + OP_I <= TST; + end if; + end case; + end if; + + if IPIPE.D(11 downto 9) = "100" and IPIPE.D(5 downto 3) = "000" then + case IPIPE.D(8 downto 6) is -- Valid OPMODES for this operation code. + when "010" | "011" => OP_I <= EXT; + when "111" => OP_I <= EXTB; + when others => null; + end case; + end if; + + if IPIPE.D(8 downto 6) = "111" then + case IPIPE.D(5 downto 3) is -- OPMODES. + when "010" | "101" | "110" => + OP_I <= LEA; + when "111" => + if IPIPE.D(2 downto 0) < "100" then -- Not all registers are valid for this OPMODE. + OP_I <= LEA; + end if; + when others => null; + end case; + end if; + + if IPIPE.D(11) = '1' and IPIPE.D(9 downto 7) = "001" then + if IPIPE.D(10) = '0' then -- Register to memory transfer. + case IPIPE.D(5 downto 3) is -- OPMODES, no postincrement addressing. + when "010" | "100" | "101" | "110" => + OP_I <= MOVEM; + when "111" => + if IPIPE.D(2 downto 0) = "000" or IPIPE.D(2 downto 0) = "001" then + OP_I <= MOVEM; + end if; + when others => null; + end case; + else -- Memory to register transfer, no predecrement addressing. + case IPIPE.D(5 downto 3) is -- OPMODES. + when "010" | "011" | "101" | "110" => + OP_I <= MOVEM; + when "111" => + if IPIPE.D(2 downto 0) < "100" then + OP_I <= MOVEM; + end if; + when others => null; + end case; + end if; + end if; + + -- The size must be "10" or "11" and the OPMODE may not be "001". + if IPIPE.D(8 downto 7) >= "10" and IPIPE.D(6 downto 3) = x"7" and IPIPE.D(2 downto 0) < "101" then + OP_I <= CHK; + elsif IPIPE.D(8 downto 7) >= "10" and IPIPE.D(6 downto 3) /= x"1" and IPIPE.D(6 downto 3) < x"7" then + OP_I <= CHK; + end if; + end if; + when x"5" => -- ADDQ / SUBQ / Scc / DBcc / TRAPcc. + if IPIPE.D(7 downto 3) = "11001" then + OP_I <= DBcc; + elsif IPIPE.D(7 downto 6) = "11" and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "010" then + OP_I <= Scc; + elsif IPIPE.D(7 downto 6) = "11" and IPIPE.D(5 downto 3) /= "001" and IPIPE.D(5 downto 3) /= "111" then + OP_I <= Scc; + -- + elsif IPIPE.D(8) = '0' and IPIPE.D(7 downto 6) < "11" and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "010" then + OP_I <= ADDQ; + elsif IPIPE.D(8) = '0' and (IPIPE.D(7 downto 6) = "01" or IPIPE.D(7 downto 6) = "10") and IPIPE.D(5 downto 3) /= "111" then + OP_I <= ADDQ; + elsif IPIPE.D(8) = '0' and IPIPE.D(7 downto 6) = "00" and IPIPE.D(5 downto 3) /= "001" and IPIPE.D(5 downto 3) /= "111" then + OP_I <= ADDQ; + -- + elsif IPIPE.D(8) = '1' and IPIPE.D(7 downto 6) < "11" and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "010" then + OP_I <= SUBQ; + elsif IPIPE.D(8) = '1' and (IPIPE.D(7 downto 6) = "01" or IPIPE.D(7 downto 6) = "10") and IPIPE.D(5 downto 3) /= "111" then + OP_I <= SUBQ; + elsif IPIPE.D(8) = '1' and IPIPE.D(7 downto 6) = "00" and IPIPE.D(5 downto 3) /= "001" and IPIPE.D(5 downto 3) /= "111" then + OP_I <= SUBQ; + -- + elsif IPIPE.D(7 downto 3) = "11111" then + OP_I <= TRAPcc; + end if; + when x"6" => -- Bcc / BSR / BRA. + if IPIPE.D(11 downto 8) = x"0" then + OP_I <= BRA; + elsif IPIPE.D(11 downto 8) = x"1" then + OP_I <= BSR; + else + OP_I <= Bcc; + end if; + when x"7" => -- MOVEQ. + if IPIPE.D(8) = '0' then + OP_I <= MOVEQ; + end if; + when x"8" => -- OR / DIV / SBCD / PACK / UNPK. + if IPIPE.D(8 downto 4) = "10100" then + OP_I <= PACK; + elsif IPIPE.D(8 downto 4) = "11000" then + OP_I <= UNPK; + elsif IPIPE.D(8 downto 6) = "011" and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "101" then + OP_I <= DIVU; -- WORD. + elsif IPIPE.D(8 downto 6) = "011" and IPIPE.D(5 downto 3) /= "001" and IPIPE.D(5 downto 3) /= "111" then + OP_I <= DIVU; -- WORD. + elsif IPIPE.D(8 downto 6) = "111" and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "101" then + OP_I <= DIVS; -- WORD. + elsif IPIPE.D(8 downto 6) = "111" and IPIPE.D(5 downto 3) /= "001" and IPIPE.D(5 downto 3) /= "111" then + OP_I <= DIVS; -- WORD. + elsif IPIPE.D(8 downto 4) = "10000" then + OP_I <= SBCD; + end if; + -- + case IPIPE.D(8 downto 6) is + when "000" | "001" | "010" => + if IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "101" then + OP_I <= OR_B; + elsif IPIPE.D(5 downto 3) /= "001" and IPIPE.D(5 downto 3) /= "111" then + OP_I <= OR_B; + end if; + when "100" | "101" | "110" => + if IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "010" then + OP_I <= OR_B; + elsif IPIPE.D(5 downto 3) > "001" and IPIPE.D(5 downto 3) /= "111" then + OP_I <= OR_B; + end if; + when others => + null; + end case; + when x"9" => -- SUB / SUBX. + case IPIPE.D(8 downto 6) is + when "000" => -- Byte size. + if IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "101" then + OP_I <= SUB; + elsif IPIPE.D(5 downto 3) /= "111" and IPIPE.D(5 downto 3) /= "001" then + OP_I <= SUB; + end if; + when "001" | "010" => -- Word and long. + if IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "101" then + OP_I <= SUB; + elsif IPIPE.D(5 downto 3) /= "111" then + OP_I <= SUB; + end if; + when "100" => + if IPIPE.D(5 downto 3) = "000" or IPIPE.D(5 downto 3) = "001" then + OP_I <= SUBX; + elsif IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "010" then + OP_I <= SUB; + elsif IPIPE.D(5 downto 3) /= "111" and IPIPE.D(5 downto 3) /= "001" then -- Byte size. + OP_I <= SUB; + end if; + when "101" | "110" => + if IPIPE.D(5 downto 3) = "000" or IPIPE.D(5 downto 3) = "001" then + OP_I <= SUBX; + elsif IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "010" then + OP_I <= SUB; + elsif IPIPE.D(5 downto 3) /= "111" then -- Word and long. + OP_I <= SUB; + end if; + when "011" | "111" => + if IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "101" then + OP_I <= SUBA; + elsif IPIPE.D(5 downto 3) /= "111" then + OP_I <= SUBA; + end if; + when others => -- U, X, Z, W, H, L, -. + null; + end case; + when x"A" => -- (1010, Unassigned, Reserved). + OP_I <= UNIMPLEMENTED; + when x"B" => -- CMP / EOR. + if IPIPE.D(8) = '1' and IPIPE.D(7 downto 6) < "11" and IPIPE.D(5 downto 3) = "001" then + OP_I <= CMPM; + else + case IPIPE.D(8 downto 6) is -- OPMODE field. + when "000" => + if IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "101" then + OP_I <= CMP; + elsif IPIPE.D(5 downto 3) /= "001" and IPIPE.D(5 downto 3) /= "111" then + OP_I <= CMP; + end if; + when "001" | "010" => + if IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "101" then + OP_I <= CMP; + elsif IPIPE.D(5 downto 3) /= "111" then + OP_I <= CMP; + end if; + when "011" | "111" => + if IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "101" then + OP_I <= CMPA; + elsif IPIPE.D(5 downto 3) /= "111" then + OP_I <= CMPA; + end if; + when "100" | "101" | "110" => + if IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "101" then + OP_I <= EOR; + elsif IPIPE.D(5 downto 3) /= "001" and IPIPE.D(5 downto 3) /= "111" then + OP_I <= EOR; + end if; + when others => -- U, X, Z, W, H, L, -. + null; + end case; + end if; + when x"C" => -- AND / MUL / ABCD / EXG. + if IPIPE.D(8 downto 4) = "10000" then + OP_I <= ABCD; + elsif IPIPE.D(8 downto 6) = "011" and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "101" then + OP_I <= MULU; -- WORD. + elsif IPIPE.D(8 downto 6) = "011" and IPIPE.D(5 downto 3) /= "001" and IPIPE.D(5 downto 3) /= "111" then + OP_I <= MULU; -- WORD. + elsif IPIPE.D(8 downto 6) = "111" and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "101" then + OP_I <= MULS; -- WORD. + elsif IPIPE.D(8 downto 6) = "111" and IPIPE.D(5 downto 3) /= "001" and IPIPE.D(5 downto 3) /= "111" then + OP_I <= MULS; -- WORD. + elsif IPIPE.D(8 downto 3) = "101000" or IPIPE.D(8 downto 3) = "101001" or IPIPE.D(8 downto 3) = "110001" then + OP_I <= EXG; + else + case IPIPE.D(8 downto 6) is -- OPMODE + when "000" | "001" | "010" => + if IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "101" then + OP_I <= AND_B; + elsif IPIPE.D(5 downto 3) /= "001" and IPIPE.D(5 downto 3) /= "111" then + OP_I <= AND_B; + end if; + when "100" | "101" | "110" => + if IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "010" then + OP_I <= AND_B; + elsif IPIPE.D(5 downto 3) > "001" and IPIPE.D(5 downto 3) /= "111" then + OP_I <= AND_B; + end if; + when others => + null; + end case; + end if; + when x"D" => -- ADD / ADDX. + case IPIPE.D(8 downto 6) is + when "000" => + if IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "101" then + OP_I <= ADD; + elsif IPIPE.D(5 downto 3) /= "111" and IPIPE.D(5 downto 3) /= "001" then + OP_I <= ADD; + end if; + when "001" | "010" => + if IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "101" then + OP_I <= ADD; + elsif IPIPE.D(5 downto 3) /= "111" then + OP_I <= ADD; + end if; + when "100" => + if IPIPE.D(5 downto 3) = "000" or IPIPE.D(5 downto 3) = "001" then + OP_I <= ADDX; + elsif IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "010" then + OP_I <= ADD; + elsif IPIPE.D(5 downto 3) /= "111" and IPIPE.D(5 downto 3) /= "001" then + OP_I <= ADD; + end if; + when "101" | "110" => + if IPIPE.D(5 downto 3) = "000" or IPIPE.D(5 downto 3) = "001" then + OP_I <= ADDX; + elsif IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "010" then + OP_I <= ADD; + elsif IPIPE.D(5 downto 3) /= "111" then + OP_I <= ADD; + end if; + when "011" | "111" => + if IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "101" then + OP_I <= ADDA; + elsif IPIPE.D(5 downto 3) /= "111" then + OP_I <= ADDA; + end if; + when others => -- U, X, Z, W, H, L, -. + null; + end case; + when x"E" => -- Shift / Rotate / Bit Field. + if IPIPE.D(11 downto 6) = "101011" and (IPIPE.D(5 downto 3) = "000" or IPIPE.D(5 downto 3) = "010") then + OP_I <= BFCHG; + elsif IPIPE.D(11 downto 6) = "101011" and (IPIPE.D(5 downto 3) >= "101" or IPIPE.D(5 downto 3) <= "110") then + OP_I <= BFCHG; + elsif IPIPE.D(11 downto 6) = "101011" and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "010" then + OP_I <= BFCHG; + elsif IPIPE.D(11 downto 6) = "110011" and (IPIPE.D(5 downto 3) = "000" or IPIPE.D(5 downto 3) = "010") then + OP_I <= BFCLR; + elsif IPIPE.D(11 downto 6) = "110011" and (IPIPE.D(5 downto 3) >= "101" or IPIPE.D(5 downto 3) <= "110") then + OP_I <= BFCLR; + elsif IPIPE.D(11 downto 6) = "110011" and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "010" then + OP_I <= BFCLR; + elsif IPIPE.D(11 downto 6) = "101111" and (IPIPE.D(5 downto 3) = "000" or IPIPE.D(5 downto 3) = "010") then + OP_I <= BFEXTS; + elsif IPIPE.D(11 downto 6) = "101111" and (IPIPE.D(5 downto 3) >= "101" or IPIPE.D(5 downto 3) <= "110") then + OP_I <= BFEXTS; + elsif IPIPE.D(11 downto 6) = "101111" and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "100" then + OP_I <= BFEXTS; + elsif IPIPE.D(11 downto 6) = "100111" and (IPIPE.D(5 downto 3) = "000" or IPIPE.D(5 downto 3) = "010") then + OP_I <= BFEXTU; + elsif IPIPE.D(11 downto 6) = "100111" and (IPIPE.D(5 downto 3) >= "101" or IPIPE.D(5 downto 3) <= "110") then + OP_I <= BFEXTU; + elsif IPIPE.D(11 downto 6) = "100111" and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "100" then + OP_I <= BFEXTU; + elsif IPIPE.D(11 downto 6) = "110111" and (IPIPE.D(5 downto 3) = "000" or IPIPE.D(5 downto 3) = "010") then + OP_I <= BFFFO; + elsif IPIPE.D(11 downto 6) = "110111" and (IPIPE.D(5 downto 3) >= "101" or IPIPE.D(5 downto 3) <= "110") then + OP_I <= BFFFO; + elsif IPIPE.D(11 downto 6) = "110111" and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "100" then + OP_I <= BFFFO; + elsif IPIPE.D(11 downto 6) = "111111" and (IPIPE.D(5 downto 3) = "000" or IPIPE.D(5 downto 3) = "010") then + OP_I <= BFINS; + elsif IPIPE.D(11 downto 6) = "111111" and (IPIPE.D(5 downto 3) >= "101" or IPIPE.D(5 downto 3) <= "110") then + OP_I <= BFINS; + elsif IPIPE.D(11 downto 6) = "111111" and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "010" then + OP_I <= BFINS; + elsif IPIPE.D(11 downto 6) = "111011" and (IPIPE.D(5 downto 3) = "000" or IPIPE.D(5 downto 3) = "010") then + OP_I <= BFSET; + elsif IPIPE.D(11 downto 6) = "111011" and (IPIPE.D(5 downto 3) >= "101" or IPIPE.D(5 downto 3) <= "110") then + OP_I <= BFSET; + elsif IPIPE.D(11 downto 6) = "111011" and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "010" then + OP_I <= BFSET; + elsif IPIPE.D(11 downto 6) = "100011" and (IPIPE.D(5 downto 3) = "000" or IPIPE.D(5 downto 3) = "010") then + OP_I <= BFTST; + elsif IPIPE.D(11 downto 6) = "100011" and (IPIPE.D(5 downto 3) >= "101" or IPIPE.D(5 downto 3) <= "110") then + OP_I <= BFTST; + elsif IPIPE.D(11 downto 6) = "100011" and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "100" then + OP_I <= BFTST; + elsif IPIPE.D(11 downto 6) = "000011" and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "010" then + OP_I <= ASR; -- Memory shifts. + elsif IPIPE.D(11 downto 6) = "000011" and IPIPE.D(5 downto 3) > "001" and IPIPE.D(5 downto 3) /= "111" then + OP_I <= ASR; -- Memory shifts. + elsif IPIPE.D(11 downto 6) = "000111" and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "010" then + OP_I <= ASL; -- Memory shifts. + elsif IPIPE.D(11 downto 6) = "000111" and IPIPE.D(5 downto 3) > "001" and IPIPE.D(5 downto 3) /= "111" then + OP_I <= ASL; -- Memory shifts. + elsif IPIPE.D(11 downto 6) = "001011" and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "010" then + OP_I <= LSR; -- Memory shifts. + elsif IPIPE.D(11 downto 6) = "001011" and IPIPE.D(5 downto 3) > "001" and IPIPE.D(5 downto 3) /= "111" then + OP_I <= LSR; -- Memory shifts. + elsif IPIPE.D(11 downto 6) = "001111" and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "010" then + OP_I <= LSL; -- Memory shifts. + elsif IPIPE.D(11 downto 6) = "001111" and IPIPE.D(5 downto 3) > "001" and IPIPE.D(5 downto 3) /= "111" then + OP_I <= LSL; -- Memory shifts. + elsif IPIPE.D(11 downto 6) = "010011" and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "010" then + OP_I <= ROXR; -- Memory shifts. + elsif IPIPE.D(11 downto 6) = "010011" and IPIPE.D(5 downto 3) > "001" and IPIPE.D(5 downto 3) /= "111" then + OP_I <= ROXR; -- Memory shifts. + elsif IPIPE.D(11 downto 6) = "010111" and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "010" then + OP_I <= ROXL; -- Memory shifts. + elsif IPIPE.D(11 downto 6) = "010111" and IPIPE.D(5 downto 3) > "001" and IPIPE.D(5 downto 3) /= "111" then + OP_I <= ROXL; -- Memory shifts. + elsif IPIPE.D(11 downto 6) = "011011" and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "010" then + OP_I <= ROTR; -- Memory shifts. + elsif IPIPE.D(11 downto 6) = "011011" and IPIPE.D(5 downto 3) > "001" and IPIPE.D(5 downto 3) /= "111" then + OP_I <= ROTR; -- Memory shifts. + elsif IPIPE.D(11 downto 6) = "011111" and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "010" then + OP_I <= ROTL; -- Memory shifts. + elsif IPIPE.D(11 downto 6) = "011111" and IPIPE.D(5 downto 3) > "001" and IPIPE.D(5 downto 3) /= "111" then + OP_I <= ROTL; -- Memory shifts. + elsif IPIPE.D(8) = '0' and IPIPE.D(7 downto 6) < "11" and IPIPE.D(4 downto 3) = "00" then + OP_I <= ASR; -- Register shifts. + elsif IPIPE.D(8) = '1' and IPIPE.D(7 downto 6) < "11" and IPIPE.D(4 downto 3) = "00" then + OP_I <= ASL; -- Register shifts. + elsif IPIPE.D(8) = '0' and IPIPE.D(7 downto 6) < "11" and IPIPE.D(4 downto 3) = "01" then + OP_I <= LSR; -- Register shifts. + elsif IPIPE.D(8) = '1' and IPIPE.D(7 downto 6) < "11" and IPIPE.D(4 downto 3) = "01" then + OP_I <= LSL; -- Register shifts. + elsif IPIPE.D(8) = '0' and IPIPE.D(7 downto 6) < "11" and IPIPE.D(4 downto 3) = "10" then + OP_I <= ROXR; -- Register shifts. + elsif IPIPE.D(8) = '1' and IPIPE.D(7 downto 6) < "11" and IPIPE.D(4 downto 3) = "10" then + OP_I <= ROXL; -- Register shifts. + elsif IPIPE.D(8) = '0' and IPIPE.D(7 downto 6) < "11" and IPIPE.D(4 downto 3) = "11" then + OP_I <= ROTR; -- Register shifts. + elsif IPIPE.D(8) = '1' and IPIPE.D(7 downto 6) < "11" and IPIPE.D(4 downto 3) = "11" then + OP_I <= ROTL; -- Register shifts. + end if; + when x"F" => -- 1111, Coprocessor Interface / 68K40 Extensions. + OP_I <= UNIMPLEMENTED; + when others => -- U, X, Z, W, H, L, -. + null; + end case; + end process OP_DECODE; +end BEHAVIOR; diff --git a/common/CPU/68K30L/wf68k30L_pkg.vhd b/common/CPU/68K30L/wf68k30L_pkg.vhd new file mode 100644 index 00000000..2ea7f306 --- /dev/null +++ b/common/CPU/68K30L/wf68k30L_pkg.vhd @@ -0,0 +1,457 @@ +------------------------------------------------------------------------ +---- ---- +---- WF68K30L IP Core: this is the package file containing the data ---- +---- types and the component declarations. ---- +---- ---- +---- Author(s): ---- +---- - Wolfgang Foerster, wf@experiment-s.de; wf@inventronik.de ---- +---- ---- +------------------------------------------------------------------------ +---- ---- +---- Copyright © 2014-2019 Wolfgang Foerster Inventronik GmbH. ---- +---- ---- +---- This documentation describes Open Hardware and is licensed ---- +---- under the CERN OHL v. 1.2. You may redistribute and modify ---- +---- this documentation under the terms of the CERN OHL v.1.2. ---- +---- (http://ohwr.org/cernohl). This documentation is distributed ---- +---- WITHOUT ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING OF ---- +---- MERCHANTABILITY, SATISFACTORY QUALITY AND FITNESS FOR A ---- +---- PARTICULAR PURPOSE. Please see the CERN OHL v.1.2 for ---- +---- applicable conditions ---- +---- ---- +------------------------------------------------------------------------ +-- +-- Revision History +-- +-- Revision 2K14B 20141201 WF +-- Initial Release. +-- Later revisions +-- Modifications according to changes of the entity in other modules. +-- + +library ieee; +use ieee.std_logic_1164.all; + +package WF68K30L_PKG is +type OP_SIZETYPE is (LONG, WORD, BYTE); +-- The OPCODES AND, NOT, OR, ROR and ROL are defined keywords in VHDL. Therefore the assignment is +-- AND_B, NOT_B, OR_B, ROTR and ROTL. +type OP_68K is (ABCD, ADD, ADDA, ADDI, ADDQ, ADDX, AND_B, ANDI, ANDI_TO_CCR, ANDI_TO_SR, ASL, ASR, Bcc, BCHG, BCLR, + BFCHG, BFCLR, BFEXTS, BFEXTU, BFFFO, BFINS, BFSET, BFTST, BKPT, BRA, BSET, BSR, BTST, CAS, CAS2, + CHK, CHK2, CLR, CMP, CMP2, CMPA, CMPI, CMPM, DBcc, DIVS, DIVU, EOR, EORI, EORI_TO_CCR, + EORI_TO_SR, EXG, EXT, EXTB, ILLEGAL, JMP, JSR, LEA, LINK, LSL, LSR, MOVE, MOVE_FROM_CCR, MOVE_TO_CCR, + MOVE_FROM_SR, MOVE_TO_SR, MOVE_USP, MOVEA, MOVEC, MOVEM, MOVEP, MOVEQ, MOVES, MULS, MULU, NBCD, NEG, + NEGX, NOP, NOT_B, OR_B, ORI, ORI_TO_CCR, ORI_TO_SR, PACK, PEA, RESET, ROTL, ROTR, ROXL, ROXR, RTD, + RTE, RTR, RTS, SBCD, Scc, STOP, SUB, SUBA, SUBI, SUBQ, SUBX, SWAP, TAS, TRAP, TRAPcc, TRAPV, TST, + UNLK, UNPK, UNIMPLEMENTED); + +type TRAPTYPE_OPC is(NONE, T_1010, T_1111, T_ILLEGAL, T_TRAP, T_PRIV, T_RTE); -- None is the first entry and default. + +component WF68K30L_ADDRESS_REGISTERS + port ( + CLK : in std_logic; + RESET : in bit; + AR_IN_1 : in std_logic_vector(31 downto 0); + AR_IN_2 : in std_logic_vector(31 downto 0); + AR_OUT_1 : out std_logic_vector(31 downto 0); + AR_OUT_2 : out std_logic_vector(31 downto 0); + INDEX_IN : in std_logic_vector(31 downto 0); + PC : out std_logic_vector(31 downto 0); + PC_EW_OFFSET : in std_logic_vector(3 downto 0); + FETCH_MEM_ADR : in bit; + STORE_ADR_FORMAT : in bit; + STORE_ABS_HI : in bit; + STORE_ABS_LO : in bit; + STORE_D16 : in bit; + STORE_D32_LO : in bit; + STORE_D32_HI : in bit; + STORE_DISPL : in bit; + STORE_MEM_ADR : in bit; + STORE_OD_HI : in bit; + STORE_OD_LO : in bit; + STORE_AEFF : in bit; + OP_SIZE : in OP_SIZETYPE; + ADR_OFFSET : in std_logic_vector(31 downto 0); + ADR_MARK_USED : in bit; + ADR_IN_USE : out bit; + ADR_MODE : in std_logic_vector(2 downto 0); + AMODE_SEL : in std_logic_vector(2 downto 0); + USE_DREG : in bit; + ADR_EFF : out std_logic_vector(31 downto 0); + ADR_EFF_WB : out std_logic_vector(31 downto 0); + DFC : out std_logic_vector(2 downto 0); + DFC_WR : in bit; + SFC : out std_logic_vector(2 downto 0); + SFC_WR : in bit; + ISP_DEC : in bit; + ISP_RD : in bit; + ISP_WR : in bit; + MSP_RD : in bit; + MSP_WR : in bit; + USP_RD : in bit; + USP_WR : in bit; + AR_MARK_USED : in bit; + USE_APAIR : in boolean; + AR_IN_USE : out bit; + AR_SEL_RD_1 : in std_logic_vector(2 downto 0); + AR_SEL_RD_2 : in std_logic_vector(2 downto 0); + AR_SEL_WR_1 : in std_logic_vector(2 downto 0); + AR_SEL_WR_2 : in std_logic_vector(2 downto 0); + AR_DEC : in bit; + AR_INC : in bit; + AR_WR_1 : in bit; + AR_WR_2 : in bit; + UNMARK : in bit; + EXT_WORD : in std_logic_vector(15 downto 0); + MBIT : in std_logic; + SBIT : in std_logic; + SP_ADD_DISPL : in bit; + RESTORE_ISP_PC : in bit; + DISPLACEMENT : in std_logic_vector(31 downto 0); + PC_ADD_DISPL : in bit; + PC_INC : in bit; + PC_LOAD : in bit; + PC_RESTORE : in bit; + PC_OFFSET : in std_logic_vector(7 downto 0) + ); +end component; + +component WF68K30L_ALU + port ( + CLK : in std_logic; + RESET : in bit; + LOAD_OP1 : in bit; + LOAD_OP2 : in bit; + LOAD_OP3 : in bit; + OP1_IN : in std_logic_vector(31 downto 0); + OP2_IN : in std_logic_vector(31 downto 0); + OP3_IN : in std_logic_vector(31 downto 0); + BF_OFFSET_IN : in Std_Logic_Vector(31 downto 0); + BF_WIDTH_IN : in Std_Logic_Vector(5 downto 0); + BITPOS_IN : in Std_Logic_Vector(4 downto 0); + RESULT : out std_logic_vector(63 downto 0); + ADR_MODE_IN : in std_logic_vector(2 downto 0); + OP_SIZE_IN : in OP_SIZETYPE; + OP_IN : in OP_68K; + OP_WB : in OP_68K; + BIW_0_IN : in std_logic_vector(11 downto 0); + BIW_1_IN : in std_logic_vector(15 downto 0); + SR_WR : in bit; + SR_INIT : in bit; + SR_CLR_MBIT : in bit; + CC_UPDT : in bit; + STATUS_REG_OUT : out std_logic_vector(15 downto 0); + ALU_COND : out boolean; + ALU_INIT : in bit; + ALU_BSY : out bit; + ALU_REQ : out bit; + ALU_ACK : in bit; + USE_DREG : in bit; + HILOn : in bit; + IRQ_PEND : in std_logic_vector(2 downto 0); + TRAP_CHK : out bit; + TRAP_DIVZERO : out bit + ); +end component; + +component WF68K30L_BUS_INTERFACE + port ( + CLK : in std_logic; + ADR_IN_P : in std_logic_vector(31 downto 0); + ADR_OUT_P : out std_logic_vector(31 downto 0); + FC_IN : in std_logic_vector(2 downto 0); + FC_OUT : out std_logic_vector(2 downto 0); + DATA_PORT_IN : in std_logic_vector(31 downto 0); + DATA_PORT_OUT : out std_logic_vector(31 downto 0); + DATA_FROM_CORE : in std_logic_vector(31 downto 0); + DATA_TO_CORE : out std_logic_vector(31 downto 0); + OPCODE_TO_CORE : out std_logic_vector(15 downto 0); + DATA_PORT_EN : out std_logic; + BUS_EN : out std_logic; + SIZE : out std_logic_vector(1 downto 0); + OP_SIZE : in OP_SIZETYPE; + RD_REQ : in bit; + WR_REQ : in bit; + DATA_RDY : out bit; + DATA_VALID : out std_logic; + OPCODE_REQ : in bit; + OPCODE_RDY : out bit; + OPCODE_VALID : out std_logic; + RMC : in bit; + BUSY_EXH : in bit; + INBUFFER : out std_logic_vector(31 downto 0); + OUTBUFFER : out std_logic_vector(31 downto 0); + SSW_80 : out std_logic_vector(8 downto 0); + DSACKn : in std_logic_vector(1 downto 0); + ASn : out std_logic; + DSn : out std_logic; + RWn : out std_logic; + RMCn : out std_logic; + ECSn : out std_logic; + OCSn : out std_logic; + DBENn : out std_logic; + STERMn : in std_logic; + BRn : in std_logic; + BGACKn : in std_logic; + BGn : out std_logic; + RESET_STRB : in bit; + RESET_IN : in std_logic; + RESET_OUT : out std_logic; + RESET_CPU : out bit; + AVECn : in std_logic; + HALTn : in std_logic; + BERRn : in std_logic; + AERR : out bit; + BUS_BSY : out bit + ); +end component; + +component WF68K30L_CONTROL + generic(NO_PIPELINE : boolean := false); -- If true the controller work in scalar mode. + port( + CLK : in std_logic; + RESET_CPU : in bit; + BUSY : out bit; + BUSY_EXH : in bit; + EXH_REQ : in bit; + INT_TRIG : out bit; + OW_REQ : out bit; + OW_VALID : in std_logic; + EW_REQ : out bit; + EW_ACK : in bit; + OPD_ACK : in bit; + ADR_MARK_USED : out bit; + ADR_IN_USE : in bit; + ADR_OFFSET : out std_logic_vector(5 downto 0); + DATA_RD : out bit; + DATA_WR : out bit; + DATA_RDY : in bit; + DATA_VALID : in std_logic; + RMC : out bit; + FETCH_MEM_ADR : out bit; + LOAD_OP2 : out bit; + LOAD_OP3 : out bit; + LOAD_OP1 : out bit; + STORE_ADR_FORMAT : out bit; + STORE_D16 : out bit; + STORE_D32_LO : out bit; + STORE_D32_HI : out bit; + STORE_DISPL : out bit; + STORE_OD_HI : out bit; + STORE_OD_LO : out bit; + STORE_ABS_HI : out bit; + STORE_ABS_LO : out bit; + STORE_IDATA_B2 : out bit; + STORE_IDATA_B1 : out bit; + STORE_MEM_ADR : out bit; + STORE_AEFF : out bit; + OP : in OP_68K; + OP_SIZE : out OP_SIZETYPE; + BIW_0 : in std_logic_vector(13 downto 0); + BIW_1 : in std_logic_vector(15 downto 0); + BIW_2 : in std_logic_vector(15 downto 0); + EXT_WORD : in std_logic_vector(15 downto 0); + ADR_MODE : out std_logic_vector(2 downto 0); + AMODE_SEL : out std_logic_vector(2 downto 0); + USE_DREG : out bit; + HILOn : out bit; + OP_WB : out OP_68K; + OP_SIZE_WB : out OP_SIZETYPE; + BIW_0_WB_73 : out std_logic_vector(7 downto 3); + AR_MARK_USED : out bit; + USE_APAIR : out boolean; + AR_IN_USE : in bit; + AR_SEL_RD_1 : out std_logic_vector(2 downto 0); + AR_SEL_RD_2 : out std_logic_vector(2 downto 0); + AR_SEL_WR_1 : out std_logic_vector(2 downto 0); + AR_SEL_WR_2 : out std_logic_vector(2 downto 0); + AR_INC : out bit; + AR_DEC : out bit; + AR_WR_1 : out bit; + AR_WR_2 : out bit; + DR_MARK_USED : out bit; + USE_DPAIR : out boolean; + DR_IN_USE : in bit; + DR_SEL_RD_1 : out std_logic_vector(2 downto 0); + DR_SEL_RD_2 : out std_logic_vector(2 downto 0); + DR_SEL_WR_1 : out std_logic_vector(2 downto 0); + DR_SEL_WR_2 : out std_logic_vector(2 downto 0); + DR_WR_1 : out bit; + DR_WR_2 : out bit; + UNMARK : out bit; + DISPLACEMENT : out std_logic_vector(31 downto 0); + PC_ADD_DISPL : out bit; + PC_LOAD : out bit; + PC_INC_EXH : in bit; + SP_ADD_DISPL : out bit; + DFC_WR : out bit; + DFC_RD : out bit; + SFC_WR : out bit; + SFC_RD : out bit; + VBR_WR : out bit; + VBR_RD : out bit; + ISP_RD : out bit; + ISP_WR : out bit; + MSP_RD : out bit; + MSP_WR : out bit; + USP_RD : out bit; + USP_WR : out bit; + IPIPE_FLUSH : out bit; + ALU_INIT : out bit; + ALU_BSY : in bit; + ALU_REQ : in bit; + ALU_ACK : out bit; + BKPT_CYCLE : out bit; + BKPT_INSERT : out bit; + LOOP_BSY : in bit; + LOOP_SPLIT : out boolean; + LOOP_EXIT : out bit; + BF_OFFSET : in Std_Logic_Vector(2 downto 0); + BF_WIDTH : in Std_Logic_Vector(5 downto 0); + SR_WR : out bit; + MOVEM_ADn : out bit; + MOVEP_PNTR : out integer range 0 to 3; + CC_UPDT : out bit; + TRACE_MODE : in std_logic_vector(1 downto 0); + VBIT : in std_logic; + ALU_COND : in boolean; + DBcc_COND : in boolean; + BRANCH_ATN : in bit; + RESET_STRB : out bit; + BERR : out bit; + STATUSn : out bit; + EX_TRACE : out bit; + TRAP_cc : out bit; + TRAP_ILLEGAL : out bit; + TRAP_V : out bit + ); +end component; + +component WF68K30L_DATA_REGISTERS + port ( + CLK : in std_logic; + RESET : in bit; + DR_IN_1 : in std_logic_vector(31 downto 0); + DR_IN_2 : in std_logic_vector(31 downto 0); + DR_OUT_1 : out std_logic_vector(31 downto 0); + DR_OUT_2 : out std_logic_vector(31 downto 0); + DR_SEL_WR_1 : in std_logic_vector(2 downto 0); + DR_SEL_WR_2 : in std_logic_vector(2 downto 0); + DR_SEL_RD_1 : in std_logic_vector(2 downto 0); + DR_SEL_RD_2 : in std_logic_vector(2 downto 0); + DR_WR_1 : in bit; + DR_WR_2 : in bit; + DR_MARK_USED : in bit; + USE_DPAIR : in boolean; + DR_IN_USE : out bit; + UNMARK : in bit; + OP_SIZE : in OP_SIZETYPE + ); +end component; + +component WF68K30L_EXCEPTION_HANDLER + generic(VERSION : std_logic_vector(31 downto 0)); + port ( + CLK : in std_logic; + RESET : in bit; + BUSY_MAIN : in bit; + BUSY_OPD : in bit; + EXH_REQ : out bit; + BUSY_EXH : out bit; + ADR_IN : in std_logic_vector(31 downto 0); + ADR_CPY : out std_logic_vector(31 downto 0); + ADR_OFFSET : out std_logic_vector(31 downto 0); + CPU_SPACE : out bit; + DATA_0 : in std_logic; + DATA_RD : out bit; + DATA_WR : out bit; + DATA_IN : in std_logic_vector(31 downto 0); + OP_SIZE : out OP_SIZETYPE; + DATA_RDY : in bit; + DATA_VALID : in std_logic; + OPCODE_RDY : in bit; + OPD_ACK : in bit; -- Opword is available. + OW_VALID : in std_logic; + STATUS_REG_IN : in std_logic_vector(15 downto 0); + SR_CPY : out std_logic_vector(15 downto 0); + SR_INIT : out bit; + SR_CLR_MBIT : out bit; + SR_WR : out bit; + ISP_DEC : out bit; + ISP_LOAD : out bit; + PC_INC : out bit; + PC_LOAD : out bit; + PC_RESTORE : out bit; + STACK_FORMAT : out std_logic_vector(3 downto 0); + STACK_POS : out integer range 0 to 46; + SP_ADD_DISPL : out bit; + DISPLACEMENT : out std_logic_vector(7 downto 0); + IPIPE_FILL : out bit; + IPIPE_FLUSH : out bit; + REFILLn : out std_logic; + RESTORE_ISP_PC : out bit; + HALT_OUTn : out std_logic; + STATUSn : out bit; + INT_TRIG : in bit; + IRQ_IN : in std_logic_vector(2 downto 0); + IRQ_PEND : out std_logic_vector(2 downto 0); + AVECn : in std_logic; + IPENDn : out std_logic; + IVECT_OFFS : out std_logic_vector(9 downto 0); + TRAP_AERR : in bit; + TRAP_BERR : in bit; + TRAP_CHK : in bit; + TRAP_DIVZERO : in bit; + TRAP_ILLEGAL : in bit; + TRAP_CODE_OPC : in TRAPTYPE_OPC; + TRAP_VECTOR : in std_logic_vector(3 downto 0); + TRAP_cc : in bit; + TRAP_V : in bit; + EX_TRACE_IN : in bit; + VBR_WR : in bit; + VBR : out std_logic_vector(31 downto 0) + ); +end component; + +component WF68K30L_OPCODE_DECODER + generic(NO_LOOP : boolean := false); -- If true the DBcc loop mechanism is disabled. + port ( + CLK : in std_logic; + OW_REQ_MAIN : in bit; + EW_REQ_MAIN : in bit; + EXH_REQ : in bit; + BUSY_EXH : in bit; + BUSY_MAIN : in bit; + BUSY_OPD : out bit; + BKPT_INSERT : in bit; + BKPT_DATA : in std_logic_vector(15 downto 0); + LOOP_EXIT : in bit; + LOOP_BSY : out bit; + OPD_ACK_MAIN : out bit; + EW_ACK : out bit; + PC_EW_OFFSET : out std_logic_vector(3 downto 0); + PC_INC : out bit; + PC_INC_EXH : in bit; + PC_ADR_OFFSET : out std_logic_vector(7 downto 0); + PC_OFFSET : out std_logic_vector(7 downto 0); + OPCODE_RD : out bit; + OPCODE_RDY : in bit; + OPCODE_VALID : in std_logic; + OPCODE_DATA : in std_logic_vector(15 downto 0); + IPIPE_FILL : in bit; + IPIPE_FLUSH : in bit; + OW_VALID : out std_logic; + RC : out std_logic; + RB : out std_logic; + FC : out std_logic; + FB : out std_logic; + SBIT : in std_logic; + TRAP_CODE : out TRAPTYPE_OPC; + OP : out OP_68K; + BIW_0 : out std_logic_vector(15 downto 0); + BIW_1 : out std_logic_vector(15 downto 0); + BIW_2 : out std_logic_vector(15 downto 0); + EXT_WORD : out std_logic_vector(15 downto 0) + ); +end component; +end WF68K30L_PKG; diff --git a/common/CPU/68K30L/wf68k30L_top.vhd b/common/CPU/68K30L/wf68k30L_top.vhd new file mode 100644 index 00000000..ba6089a7 --- /dev/null +++ b/common/CPU/68K30L/wf68k30L_top.vhd @@ -0,0 +1,1212 @@ +------------------------------------------------------------------------ +---- ---- +---- WF68K30L IP Core. ---- +---- ---- +---- This is the top level structural design unit of the 68K30L ---- +---- complex instruction set (CISC) microcontroller. It's program- ---- +---- ming model is (hopefully) fully compatible with Motorola's ---- +---- MC68030. This core features a pipelined architecture. In com- ---- +---- parision to the fully featured 68K30 the core has no MMU, no ---- +---- data and instruction cache and no coprocessor interface. This ---- +---- results in missing burstmodes which are not required due to ---- +---- lack of cache. Missing coprocessor operations are: ---- +---- cpBcc, cpDBcc, cpGEN, cpRESTORE, cpSAVE, cpScc, cpTRAPcc. ---- +---- Missing MMU operations are: PFLUSH, PLOAD, PMOVE and PTEST. ---- +---- The trap handler does not process the following exceptions ---- +---- which lack due to the missing MMU and coprocessor interface: ---- +---- PRE_EXC_CP, MID_EXC_CP , POST_EXC_CP, EXC_VECT_CP, MMU_CFG_ERR ---- +---- The shifter in the 68K30 is a barrel shifter and in this core ---- +---- it is a conventional shift register controlled logic. ---- +---- This core features the loop operation mode of the 68010 to ---- +---- deal with DBcc loops. This feature is a predecessor to the ---- +---- MC68020/30/40 caches. ---- +---- The exception handler works for the RTE but without taking the ---- +---- SSW into account which is intended to restore from a defectice ---- +---- bus error stack frame. ---- +---- ---- +---- Enjoy. ---- +---- ---- +---- Author(s): ---- +---- - Wolfgang Foerster, wf@experiment-s.de; wf@inventronik.de ---- +---- ---- +------------------------------------------------------------------------ +---- ---- +---- Copyright © 2014-2019 Wolfgang Foerster Inventronik GmbH. ---- +---- ---- +---- This documentation describes Open Hardware and is licensed ---- +---- under the CERN OHL v. 1.2. You may redistribute and modify ---- +---- this documentation under the terms of the CERN OHL v.1.2. ---- +---- (http://ohwr.org/cernohl). This documentation is distributed ---- +---- WITHOUT ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING OF ---- +---- MERCHANTABILITY, SATISFACTORY QUALITY AND FITNESS FOR A ---- +---- PARTICULAR PURPOSE. Please see the CERN OHL v.1.2 for ---- +---- applicable conditions ---- +---- ---- +------------------------------------------------------------------------ +-- +-- Revision History +-- +-- Revision 2K14B 20141201 WF +-- Initial Release. +-- Revision 2K16A 20160620 WF +-- Control section: fixed a bug in the MOVEM operation. Thanks to Raymond Mounissamy. +-- Address section: minor optimizations. +-- Revision 2K18A 20180620 WF +-- Control: Fixed a bug in MOVE An,-(Ay). Thanks to Gary Bingham for the support. +-- Top: changed ALU_OP1_IN multiplexer due to MOVE An,-(Ay) bug. +-- Address registers: Changed ADR_ATN logic to be valid one clock cycle earlier. +-- Revision 2K18A (unreleased) WF +-- Top / Opdecoder / Exhandler: Removed REST_BIW_0. +-- Exhandler: Removed PC_OFFSET. +-- ALU: Bug fix: MOVEM sign extension. +-- Address registers: Removed PC_REG. +-- Control: Fixed wrong PEA behaviour. +-- Control: Fixed the displacement for LINK. +-- ALU: Fix for restoring correct values during the DIVS and DIVU in word format. +-- Control: Fixed the operation size for MOVEQ. +-- Control: ADDQ, SUBQ Fix: address registers are always written long. +-- Top, exception handler, address registers: Fixed PC restoring during exception processing. +-- Control: ADDI, ANDI, EORI, ORI, SUBI: address is not marked used if destination is Dn. +-- Control: ADDI, ANDI, EORI, ORI, SUBI: data register is marked used if destination is Dn. +-- Bus interface: Suppress bus faults during RESET instruction. +-- Bus interface: Optimized ASn and DSn timing for synchronous RAM. +-- ALU: Fixed the SUBQ calculation. +-- Opcode decoder: Fixed the PW_EW_OFFSET calculation for JSR. +-- Top: fixed the value of DATA_IMMEDIATE for ADDQ and SUBQ in case of #8. +-- ALU: Rearanged the Offset for the JSR instruction. +-- Control: Fixed AR_MARK_USED in LINK. +-- ALU: EXT instruction uses now RESULT(63 downto 0). +-- Top: Introduced OP_WB form the control unit. +-- Top: Rearanged the AR_IN_1 multiplexer to avoid data hazards. +-- Top: Rearanged the AR_IN_2 multiplexer to avoid data hazards. +-- Top: Rearanged the DR_IN_1 multiplexer to avoid data hazards. +-- Top: Rearanged the DR_IN_2 multiplexer to avoid data hazards. +-- EXG: rearanged logic to meet the new top level multiplexers. +-- Control: LINK, UNLK: wait in START_OP until the ALU is ready (avoids possible data hazards). +-- Top: ALU_OP1_IN to meet the new EXG multiplexers. +-- Top: ALU_OP2_IN to meet the new EXG multiplexers. +-- Address registers: Fixed the writing of ISP_REG during EXG instruction with two address registers. +-- Control: MOVEM: Fixed predecrement mode for consecutive MOVEM -(An). +-- Control: MOVEP: MOVEP_PNTR is now correct for consecutive MOVEP. +-- Control: MOVEP: avoid structural hazard in SWITCH_STATE by waiting for ALU. +-- Control: LINK, UNLK: fixed the write back operation size. +-- Exception handler: Fixed the vector calculation of INT vectors. +-- Exception handler: Fixed faulty modelling in IRQ_FILTER. +-- Exception handler: Implemented the AVEC_FILTER to better meet bus timings. +-- Control: EOR: fixed a bug in the writeback mechanism. +-- Control: BSR, JSR: EXEC_WB state machine waits now for ALU_INIT. Avoid structural / data hazard. +-- Control: the instruction pipe is not flushed for MOVE_FROM_CCR, MOVE_FROM_SR, MOVE_USP, MOVEC. +-- Control: Modifications in the FETCH state machine to avoid several data hazards for MOVEM, MOVE_FROM_CCR, MOVE_FROM_SR. +-- Control: Modifications in the FETCH state machine to avoid several data hazards for ANDI_TO_CCR, ANDI_TO_SR, EORI_TO_CCR, EORI_TO_SR, ORI_TO_CCR, ORI_TO_SR. +-- Exception handler: The RTE exception has now highest priority (avoids mismatch). +-- Control: Bugfix: the condition codes were not updated if there was a pending interrupt. +-- Control: We have to stop a pending operation in case of a pending interrupt. This is done by rejecting OW_RDY. +-- TOP, Control, Exception handler Opcode Decoder: Rearanged PC_INC and ipipe flush logic. +-- Bus interface: BUS_EN is now active except during arbitration. +-- Control: Write the undecremented Register for MOVE Ax, -(Ax). +-- ALU: Fixed wrong condition codes for AND_B, ANDI, EOR, EORI, OR_B, ORI and NOT_B. +-- Exception handler: Update the IRQ mask only for RESET and interrupts. +-- Bus interface: Opted out START_READ and CHK_RD. +-- Control: UNMARK is now asserted in the end of the write cycle. This avoids data hazards. +-- Exception handler: external interrupts are postponed if any system controllers are in initialize operation status. +-- ALU: Fixed writeback issues in the status register logic. +-- ALU: Fixed writing the stack pointer registers (MSBIT is used now). +-- Control: Fixed a MOVEC writeback issue (use BIW_WB... instead of BIW_...). +-- Control: Fixed a USP writeback issue (use BIW_WB... instead of BIW_...). +-- ALU: the address registers are always written long. +-- Top: opted out SBIT_AREG and MBIT_AREG. +-- Address register bugfix: exception handler do not increment and decrement the USP any more. +-- Control: Introduced a switch NO_PIPELINE. +-- Address registers, Control: MOVEM-Fix see STORE_AEFF. +-- Control: DBcc: fixed a data hazard for DBcc_COND evaluation by waiting on the ALU result. +-- Control: Fixed DR_WR_1 locking against AR_WR_2. +-- Control: IPIPE is flushed, when there is a memory space change in the end of xx_TO_SR operations. +-- Control: To handle correct addressing, ADR_OFFSET is now cleared right in the end of the respective operation. +-- Control: Fixed a bug in EOR writing back in register direct mode. +-- ALU: Fixed a bug in MULU.W (input operands are now 16 bit wide). +-- Control: ADDQ and SUBQ: fixed (An)+ mode. An increments now. +-- Control: Fixed DIVS, DIVU in memory address modes (wrong control flow). +-- Control: ADDQ and SUBQ: fixed condition code control UPDT_CC. +-- Control: fixed a data hazard bug using addressing modes with index register. +-- Opcode decoder: Fix for unimplemented or illegal operations: PC is increased before stacked. +-- Exception handler: RTE now loads the address offset correctly when entering the handler. +-- Control: Implemented the 68K10 loop mechanism. +-- Opcode decoder Implemented the 68K10 loop mechanism. +-- Bus interface: Fixed the faulty bus arbitration logic. +-- Opcode decoder: Removed CAHR, we have no cache. +-- Top: Removed a data hazard in the DR_IN_1 multiplexer (EXG operation). +-- Revision 2K19A 20190419 WF +-- Control: Fixed several pipelinig issues (hazards). +-- New feature: Branch prediction for the status register manipulation operations (BRANCH_ATN). +-- Exception handler, Opcode decoder, Top: Rearranged address error handling. +-- Bus interface, Exception handler, Opcode decoder, Top: Rearranged address error handling. +-- Top, Address registers: Removed ADR_ATN. Not required any more. +-- Control: Introdeced a new state CALC_AEFF which results in no need of ADR_ATN and a twice highre fmax. +-- Revision 2K19B 20191224 WF +-- Control: NOP explicitely synchronizes the instruction pipe now. +-- Opcode decoder: introduced signal synchronization in the P_BSY process to avoid malfunction by hazards. +-- Exception handler: introduced signal synchronization in the P_D process to avoid malfunction by hazards. +-- Top level, exception handler: the processor VERSION is now 32 bit wide. +-- Control: BUSY is now asserted when an opword is loaded and we have to wait in START_OP (avoids other controllers to reload the opword, see OW_REQ). +-- Control: removed a data hazard condition (A7) for JSR, PEA, LINK and UNLK in the beginning of the operation. +-- Address section: fixed the condition if UNMARK and AR_MARK_USED are asserted simultaneously (see process P_IN_USE). +-- Address section: fixed the '0' conditions for AR_IN_USE. +-- Revision 2K20A 20200620 WF +-- Bus interface: ASn and DSn are not asserted in S0 any more. +-- Bus interface: some modifications to optimize the RETRY logic. +-- Bus interface: fixed a bug in the DSACK_MEM logic (now switches explicitely to "00"). +-- + +library work; +use work.WF68K30L_PKG.all; + +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_unsigned.all; + +entity WF68K30L_TOP is + generic(VERSION : std_logic_vector(31 downto 0) := x"20191224"; -- CPU version number. + -- The following two switches are for debugging purposes. Default for both is false. + NO_PIPELINE : boolean := false; -- If true the main controller work in scalar mode. + NO_LOOP : boolean := false); -- If true the DBcc loop mechanism is disabled. + + port ( + CLK : in std_logic; + + -- Address and data: + ADR_OUT : out std_logic_vector(31 downto 0); + DATA_IN : in std_logic_vector(31 downto 0); + DATA_OUT : out std_logic_vector(31 downto 0); + DATA_EN : out std_logic; -- Enables the data port. + + -- System control: + BERRn : in std_logic; + RESET_INn : in std_logic; + RESET_OUT : out std_logic; -- Open drain. + HALT_INn : in std_logic; + HALT_OUTn : out std_logic; -- Open drain. + + -- Processor status: + FC_OUT : out std_logic_vector(2 downto 0); + + -- Interrupt control: + AVECn : in std_logic; + IPLn : in std_logic_vector(2 downto 0); + IPENDn : out std_logic; + + -- Aynchronous bus control: + DSACKn : in std_logic_vector(1 downto 0); + SIZE : out std_logic_vector(1 downto 0); + ASn : out std_logic; + RWn : out std_logic; + RMCn : out std_logic; + DSn : out std_logic; + ECSn : out std_logic; + OCSn : out std_logic; + DBENn : out std_logic; -- Data buffer enable. + BUS_EN : out std_logic; -- Enables ADR, ASn, DSn, RWn, RMCn, FC and SIZE. + + -- Synchronous bus control: + STERMn : in std_logic; + + -- Status controls: + STATUSn : out std_logic; + REFILLn : out std_logic; + + -- Bus arbitration control: + BRn : in std_logic; + BGn : out std_logic; + BGACKn : in std_logic + ); +end entity WF68K30L_TOP; + +architecture STRUCTURE of WF68K30L_TOP is +signal ADn : bit; +signal ADR_CPY_EXH : std_logic_vector(31 downto 0); +signal ADR_EFF : std_logic_vector(31 downto 0); +signal ADR_EFF_WB : std_logic_vector(31 downto 0); +signal ADR_L : std_logic_vector(31 downto 0); +signal ADR_LATCH : std_logic_vector(31 downto 0); +signal ADR_MODE : std_logic_vector(2 downto 0); +signal ADR_MODE_MAIN : std_logic_vector(2 downto 0); +signal ADR_IN_USE : bit; +signal ADR_OFFSET : std_logic_vector(31 downto 0); +signal ADR_OFFSET_EXH : std_logic_vector(31 downto 0); +signal ADR_OFFSET_MAIN : std_logic_vector(5 downto 0); +signal ADR_P : std_logic_vector(31 downto 0); +signal ADR_MARK_UNUSED_MAIN : bit; +signal ADR_MARK_USED : bit; +signal AERR : bit; +signal ALU_ACK : bit; +signal ALU_BSY : bit; +signal ALU_COND : boolean; +signal ALU_INIT : bit; +signal ALU_LOAD_OP1 : bit; +signal ALU_LOAD_OP2 : bit; +signal ALU_LOAD_OP3 : bit; +signal ALU_OP1_IN : std_logic_vector(31 downto 0); +signal ALU_OP2_IN : std_logic_vector(31 downto 0); +signal ALU_OP3_IN : std_logic_vector(31 downto 0); +signal ALU_REQ : bit; +signal ALU_RESULT : std_logic_vector(63 downto 0); +signal AMODE_SEL : std_logic_vector(2 downto 0); +signal AR_DEC : bit; +signal AR_IN_1 : std_logic_vector(31 downto 0); +signal AR_IN_2 : std_logic_vector(31 downto 0); +signal AR_IN_USE : bit; +signal AR_INC : bit; +signal AR_MARK_USED : bit; +signal AR_OUT_1 : std_logic_vector(31 downto 0); +signal AR_OUT_2 : std_logic_vector(31 downto 0); +signal AR_SEL_RD_1 : std_logic_vector(2 downto 0); +signal AR_SEL_RD_1_MAIN : std_logic_vector(2 downto 0); +signal AR_SEL_RD_2 : std_logic_vector(2 downto 0); +signal AR_SEL_WR_1 : std_logic_vector(2 downto 0); +signal AR_SEL_WR_2 : std_logic_vector(2 downto 0); +signal AR_WR_1 : bit; +signal AR_WR_2 : bit; +signal AVECn_BUSIF : std_logic; +signal BERR_MAIN : bit; +signal BITPOS : std_logic_vector(4 downto 0); +signal BIW_0 : std_logic_vector(15 downto 0); +signal BIW_0_WB_73 : std_logic_vector(7 downto 3); +signal BIW_1 : std_logic_vector(15 downto 0); +signal BIW_2 : std_logic_vector(15 downto 0); +signal BF_OFFSET : std_logic_vector(31 downto 0); +signal BF_WIDTH : std_logic_vector(5 downto 0) := "100000"; -- Default needed for simulation! +signal BKPT_CYCLE : bit; +signal BKPT_INSERT : bit; +signal BRANCH_ATN : bit; +signal BUS_BSY : bit; +signal BUSY_EXH : bit; +signal BUSY_MAIN : bit; +signal BUSY_OPD : bit; +signal CC_UPDT : bit; +signal CPU_SPACE : bit; +signal CPU_SPACE_EXH : bit; +signal DFC : std_logic_vector(2 downto 0); +signal DFC_RD : bit; +signal DFC_WR : bit; +signal DR_WR_1 : bit; +signal DR_WR_2 : bit; +signal DR_MARK_USED : bit; +signal DATA_FROM_CORE : std_logic_vector(31 downto 0); +signal DATA : std_logic_vector(31 downto 0); +signal DATA_IN_EXH : std_logic_vector(31 downto 0); +signal DATA_IMMEDIATE : std_logic_vector(31 downto 0); +signal DATA_EXH : std_logic_vector(31 downto 0); +signal DATA_RD : bit; +signal DATA_WR : bit; +signal DATA_RD_EXH : bit; +signal DATA_WR_EXH : bit; +signal DATA_RD_MAIN : bit; +signal DATA_WR_MAIN : bit; +signal DATA_RDY : bit; +signal DATA_TO_CORE : std_logic_vector(31 downto 0); +signal DATA_VALID : std_logic; +signal DISPLACEMENT : std_logic_vector(31 downto 0); +signal DISPLACEMENT_MAIN : std_logic_vector(31 downto 0); +signal DISPLACEMENT_EXH : std_logic_vector(7 downto 0); +signal DATA_BUFFER : std_logic_vector(31 downto 0); +signal DBcc_COND : boolean; +signal DR_IN_1 : std_logic_vector(31 downto 0); +signal DR_IN_2 : std_logic_vector(31 downto 0); +signal DR_OUT_2 : std_logic_vector(31 downto 0); +signal DR_OUT_1 : std_logic_vector(31 downto 0); +signal DR_SEL_WR_1 : std_logic_vector(2 downto 0); +signal DR_SEL_WR_2 : std_logic_vector(2 downto 0); +signal DR_SEL_RD_1 : std_logic_vector(2 downto 0); +signal DR_SEL_RD_2 : std_logic_vector(2 downto 0); +signal DR_IN_USE : bit; +signal EW_ACK : bit; +signal EW_REQ_MAIN : bit; +signal EX_TRACE : bit; +signal EXEC_RDY : bit; +signal EXH_REQ : bit; +signal EXT_WORD : std_logic_vector(15 downto 0); +signal FAULT_ADR : std_logic_vector(31 downto 0); +signal FB : std_logic; +signal FC : std_logic; +signal FETCH_MEM_ADR : bit; +signal FC_I : std_logic_vector(2 downto 0); +signal FC_LATCH : std_logic_vector(2 downto 0); +signal HILOn : bit; +signal IBUFFER : std_logic_vector(31 downto 0); +signal INBUFFER : std_logic_vector(31 downto 0); +signal INT_TRIG : bit; +signal IPL : std_logic_vector(2 downto 0); +signal ISP_DEC : bit; +signal ISP_RD : bit; +signal ISP_LOAD_EXH : bit; +signal ISP_WR_MAIN : bit; +signal ISP_WR : bit; +signal IVECT_OFFS : std_logic_vector(9 downto 0); +signal IPEND_In : bit; +signal IRQ_PEND : std_logic_vector(2 downto 0); +signal IPIPE_FILL : bit; +signal IPIPE_FLUSH : bit; +signal IPIPE_FLUSH_EXH : bit; +signal IPIPE_FLUSH_MAIN : bit; +signal IPIPE_OFFESET : std_logic_vector(2 downto 0); +signal LOOP_BSY : bit; +signal LOOP_SPLIT : boolean; +signal LOOP_EXIT : bit; +signal MOVEP_PNTR : integer range 0 to 3; +signal MSP_RD : bit; +signal MSP_WR : bit; +signal OPCODE_RD : bit; +signal OPCODE_RDY : bit; +signal OPCODE_VALID : std_logic; +signal OPCODE_TO_CORE : std_logic_vector(15 downto 0); +signal OP_SIZE : OP_SIZETYPE; +signal OP_SIZE_BUS : OP_SIZETYPE; +signal OP_SIZE_EXH : OP_SIZETYPE; +signal OP_SIZE_MAIN : OP_SIZETYPE; +signal OP_SIZE_WB : OP_SIZETYPE; -- Writeback. +signal OPCODE_REQ : bit; +signal OPCODE_REQ_I : bit; +signal OW_VALID : std_logic; +signal OPD_ACK_MAIN : bit; +signal OP : OP_68K; +signal OP_WB : OP_68K; +signal OW_REQ_MAIN : bit; +signal OUTBUFFER : std_logic_vector(31 downto 0); +signal PC : std_logic_vector(31 downto 0); +signal PC_ADD_DISPL : bit; +signal PC_ADR_OFFSET : std_logic_vector(7 downto 0); +signal PC_EW_OFFSET : std_logic_vector(3 downto 0); +signal PC_INC : bit; +signal PC_INC_EXH : bit; +signal PC_INC_EXH_I : bit; +signal PC_L : std_logic_vector(31 downto 0); +signal PC_LOAD : bit; +signal PC_LOAD_EXH : bit; +signal PC_LOAD_MAIN : bit; +signal PC_OFFSET : std_logic_vector(7 downto 0); +signal PC_OFFSET_OPD : std_logic_vector(7 downto 0); +signal PC_RESTORE_EXH : bit; +signal RB : std_logic; +signal RC : std_logic; +signal RD_REQ : bit; +signal RD_REQ_I : bit; +signal RMC : bit; +signal REFILLn_EXH : std_logic; +signal RESTORE_ISP_PC : bit; +signal RESET_CPU : bit; +signal RESET_IN : std_logic; +signal RESET_STRB : bit; +signal SP_ADD_DISPL : bit; +signal SP_ADD_DISPL_EXH : bit; +signal SP_ADD_DISPL_MAIN : bit; +signal SBIT : std_logic; +signal SSW_80 : std_logic_vector(8 downto 0); +signal SFC : std_logic_vector(2 downto 0); +signal SFC_RD : bit; +signal SFC_WR : bit; +signal SR_CPY : std_logic_vector(15 downto 0); +signal SR_RD : bit; +signal SR_INIT : bit; +signal SR_CLR_MBIT : bit; +signal SR_WR : bit; +signal SR_WR_EXH : bit; +signal SR_WR_MAIN : bit; +signal STACK_FORMAT : std_logic_vector(3 downto 0); +signal STACK_POS : integer range 0 to 46; +signal STATUS_REG : std_logic_vector(15 downto 0); +signal STATUSn_MAIN : bit; +signal STATUSn_EXH : bit; +signal STORE_ADR_FORMAT : bit; +signal STORE_ABS_HI : bit; +signal STORE_ABS_LO : bit; +signal STORE_AEFF : bit; +signal STORE_D16 : bit; +signal STORE_D32_LO : bit; +signal STORE_D32_HI : bit; +signal STORE_DISPL : bit; +signal STORE_MEM_ADR : bit; +signal STORE_OD_HI : bit; +signal STORE_OD_LO : bit; +signal STORE_IDATA_B1 : bit; +signal STORE_IDATA_B2 : bit; +signal TRAP_AERR : bit; +signal TRAP_ILLEGAL : bit; +signal TRAP_CODE_OPC : TRAPTYPE_OPC; +signal TRAP_cc : bit; +signal TRAP_CHK : bit; +signal TRAP_DIVZERO : bit; +signal TRAP_V : bit; +signal UNMARK : bit; +signal USE_APAIR : boolean; +signal USE_DFC : bit; +signal USE_SFC : bit; +signal USE_DPAIR : boolean; +signal USE_DREG : bit; +signal USP_RD : bit; +signal USP_WR : bit; +signal VBR : std_logic_vector(31 downto 0); +signal VBR_WR : bit; +signal VBR_RD : bit; +signal WR_REQ : bit; +signal WR_REQ_I : bit; +begin + IDATA_BUFFER : process + -- This register stores the immediate data. + begin + wait until CLK = '1' and CLK' event; + if STORE_IDATA_B2 = '1' then + IBUFFER(31 downto 16) <= EXT_WORD; + elsif STORE_IDATA_B1 = '1' then + IBUFFER(15 downto 0) <= EXT_WORD; + end if; + end process IDATA_BUFFER; + + DATA_IMMEDIATE <= BIW_1 & BIW_2 when OP = ADDI and OP_SIZE = LONG else + BIW_1 & BIW_2 when OP = ANDI and OP_SIZE = LONG else + BIW_1 & BIW_2 when OP = CMPI and OP_SIZE = LONG else + BIW_1 & BIW_2 when OP = EORI and OP_SIZE = LONG else + BIW_1 & BIW_2 when OP = SUBI and OP_SIZE = LONG else + BIW_1 & BIW_2 when OP = ORI and OP_SIZE = LONG else + x"0000" & BIW_1 when OP = ANDI_TO_SR else + x"0000" & BIW_1 when OP = EORI_TO_SR else + x"0000" & BIW_1 when OP = ORI_TO_SR else + x"0000" & BIW_1 when OP = STOP else + x"0000" & BIW_1 when OP = ADDI and OP_SIZE = WORD else + x"0000" & BIW_1 when OP = ANDI and OP_SIZE = WORD else + x"0000" & BIW_1 when OP = CMPI and OP_SIZE = WORD else + x"0000" & BIW_1 when OP = EORI and OP_SIZE = WORD else + x"0000" & BIW_1 when OP = SUBI and OP_SIZE = WORD else + x"0000" & BIW_1 when OP = ORI and OP_SIZE = WORD else + x"000000" & BIW_1(7 downto 0) when OP = ANDI_TO_CCR else + x"000000" & BIW_1(7 downto 0) when OP = EORI_TO_CCR else + x"000000" & BIW_1(7 downto 0) when OP = ORI_TO_CCR else + x"000000" & BIW_1(7 downto 0) when OP = ADDI and OP_SIZE = BYTE else + x"000000" & BIW_1(7 downto 0) when OP = ANDI and OP_SIZE = BYTE else + x"000000" & BIW_1(7 downto 0) when OP = CMPI and OP_SIZE = BYTE else + x"000000" & BIW_1(7 downto 0) when OP = EORI and OP_SIZE = BYTE else + x"000000" & BIW_1(7 downto 0) when OP = SUBI and OP_SIZE = BYTE else + x"000000" & BIW_1(7 downto 0) when OP = ORI and OP_SIZE = BYTE else + x"00000008" when (OP = ADDQ or OP = SUBQ) and BIW_0(11 downto 9) = "000" else + x"000000" & "00000" & BIW_0(11 downto 9) when OP = ADDQ or OP = SUBQ else + x"000000" & BIW_0(7 downto 0) when OP = MOVEQ else + x"00000001" when OP = DBcc else + x"0000" & BIW_1(15 downto 0) when OP = PACK or OP = UNPK else + IBUFFER when OP_SIZE = LONG else x"0000" & IBUFFER(15 downto 0); + + -- Internal registers are place holders written as zeros. + DATA_EXH <= -- Exception handler multiplexing: + SR_CPY & PC(31 downto 16) when STACK_POS = 2 else + PC(15 downto 0) & STACK_FORMAT & "00" & IVECT_OFFS when STACK_POS = 4 else + PC when STACK_FORMAT = x"2" and STACK_POS = 6 else + PC when STACK_FORMAT = x"9" and STACK_POS = 6 else + BIW_0 & FC & FB & RC & RB & "000" & SSW_80 when STACK_POS = 6 else -- Format A and B. + BIW_1 & BIW_2 when STACK_POS = 8 else -- Format A and B. + FAULT_ADR when STACK_FORMAT = x"9" and STACK_POS = 10 else -- ADR_EFF_cp. + ADR_CPY_EXH when STACK_POS = 10 else + OUTBUFFER when STACK_POS = 14 else + PC + "100" when STACK_POS = 20 else --STAGE B address. + INBUFFER when STACK_POS = 24 else + VERSION when STACK_POS = 28 else x"00000000"; + + DATA_IN_EXH <= ALU_RESULT(31 downto 0) when BUSY_MAIN = '1' else DATA_TO_CORE; -- MOVEC handles the VBR. + + DATA_FROM_CORE <= DATA_EXH when BUSY_EXH = '1' else + DR_OUT_2 when OP_WB = CAS or OP_WB = CAS2 else -- Update operands. + ALU_RESULT(31 downto 0); + + SP_ADD_DISPL <= SP_ADD_DISPL_MAIN or SP_ADD_DISPL_EXH; + + AR_SEL_RD_1 <= "111" when BUSY_EXH = '1' else AR_SEL_RD_1_MAIN; -- ISP during exception. + + AR_IN_1 <= DATA_TO_CORE when BUSY_EXH = '1' else + ALU_RESULT(31 downto 0) when ALU_BSY = '1' and AR_WR_1 = '1' else + ALU_RESULT(31 downto 0) when ALU_BSY = '1' and (DFC_WR = '1' or SFC_WR = '1' or ISP_WR = '1' or MSP_WR = '1' or USP_WR = '1') else + ADR_EFF when OP = JMP or OP = JSR else + DATA_TO_CORE when FETCH_MEM_ADR = '1' else + DR_OUT_1 when USE_DREG = '1' else -- CAS2: Address register from data register. + AR_OUT_1 when OP = LINK or OP = UNLK else DATA_TO_CORE; -- Default used for RTD, RTR, RTS. + + AR_IN_2 <= ALU_RESULT(63 downto 32) when OP_WB = EXG else ALU_RESULT(31 downto 0); -- Default is for UNLK. + + DR_IN_1 <= ALU_RESULT(63 downto 32) when OP_WB = EXG and ALU_BSY = '1' and DR_WR_1 = '1' and BIW_0_WB_73 = "10001" else -- Address and data registers. + ALU_RESULT(31 downto 0); + + DR_IN_2 <= ALU_RESULT(63 downto 32); + + ALU_OP1_IN <= DATA_TO_CORE when SR_WR_EXH = '1' else + DATA_IMMEDIATE when OP = DBcc or OP = PACK or OP = UNPK else + DR_OUT_1 when (OP = ABCD or OP = SBCD) and BIW_0(3) = '0' else + DATA_TO_CORE when OP = ABCD or OP = SBCD else + DR_OUT_1 when (OP = ADD or OP = SUB) and BIW_0(8) = '1' else + DR_OUT_1 when (OP = AND_B or OP = EOR or OP = OR_B) and BIW_0(8) = '1' else + DR_OUT_1 when (OP = ADDX or OP = SUBX) and BIW_0(3) = '0' else + DATA_TO_CORE when OP = ADDX or OP = SUBX else + DR_OUT_1 when OP = ASL or OP = ASR or OP = LSL or OP = LSR else + DR_OUT_1 when OP = ROTL or OP = ROTR or OP = ROXL or OP = ROXR else + DR_OUT_2 when OP = BFINS else -- The pattern. + DR_OUT_1 when OP = CAS or OP = CAS2 else -- Compare operand. + DATA_TO_CORE when OP = CMPM else + PC + PC_EW_OFFSET when OP = BSR or OP = JSR else + ADR_EFF when OP = LEA or OP = PEA else + AR_OUT_2 when OP = MOVE and BIW_0(5 downto 3) = "001" else -- An to any location. + AR_OUT_1 when OP = MOVE_USP else + AR_OUT_1 when OP = EXG and BIW_0(7 downto 3) = "01001" else -- Two address registers. + DR_OUT_1 when OP = EXG else -- Two data registers. + VBR when OP = MOVEC and VBR_RD = '1' else + x"0000000" & '0' & SFC when OP = MOVEC and SFC_RD = '1' else + x"0000000" & '0' & DFC when OP = MOVEC and DFC_RD = '1' else + AR_OUT_1 when OP = MOVEC and (ISP_RD = '1' or MSP_RD = '1' or USP_RD = '1') else + AR_OUT_1 when OP = MOVEC and BIW_1(15) = '1' else + DR_OUT_1 when OP = MOVEC else + DR_OUT_1 when OP = MOVEM and BIW_0(10) = '0' and ADn = '0' else -- Register to memory. + AR_OUT_2 when OP = MOVEM and BIW_0(10) = '0' else -- Register to memory. + DR_OUT_1 when OP = MOVES and BIW_1(11) = '1' and BIW_1(15) = '0' else -- Register to memory. + AR_OUT_2 when OP = MOVES and BIW_1(11) = '1' else -- Register to memory. + x"000000" & DR_OUT_1(31 downto 24) when OP = MOVEP and MOVEP_PNTR = 3 and BIW_0(7 downto 6) > "01" else + x"000000" & DR_OUT_1(23 downto 16) when OP = MOVEP and MOVEP_PNTR = 2 and BIW_0(7 downto 6) > "01" else + x"000000" & DR_OUT_1(15 downto 8) when OP = MOVEP and MOVEP_PNTR = 1 and BIW_0(7 downto 6) > "01" else + x"000000" & DR_OUT_1(7 downto 0) when OP = MOVEP and BIW_0(7 downto 6) > "01" else + DATA_TO_CORE(7 downto 0) & DR_OUT_1(23 downto 0) when OP = MOVEP and MOVEP_PNTR = 3 else + DR_OUT_1(31 downto 24) & DATA_TO_CORE(7 downto 0) & DR_OUT_1(15 downto 0) when OP = MOVEP and MOVEP_PNTR = 2 else + DR_OUT_1(31 downto 16) & DATA_TO_CORE(7 downto 0) & DR_OUT_1(7 downto 0) when OP = MOVEP and MOVEP_PNTR = 1 else + DR_OUT_1(31 downto 8) & DATA_TO_CORE(7 downto 0) when OP = MOVEP else + x"0000" & STATUS_REG(15 downto 8) & DR_OUT_1(7 downto 0) when OP = MOVE_TO_CCR and BIW_0(5 downto 3) = "000" else + x"0000" & STATUS_REG(15 downto 8) & DATA_IMMEDIATE(7 downto 0) when OP = MOVE_TO_CCR and BIW_0(5 downto 0) = "111100" else + x"0000" & STATUS_REG(15 downto 8) & DATA_TO_CORE(7 downto 0) when OP = MOVE_TO_CCR else + x"0000" & DR_OUT_1(15 downto 0) when OP = MOVE_TO_SR and BIW_0(5 downto 3) = "000" else + x"0000" & DATA_IMMEDIATE(15 downto 0) when OP = MOVE_TO_SR and BIW_0(5 downto 0) = "111100" else + x"0000" & DATA_TO_CORE(15 downto 0) when OP = MOVE_TO_SR else + x"000000" & "000" & STATUS_REG(4 downto 0) when OP = MOVE_FROM_CCR else + x"0000" & STATUS_REG when OP = MOVE_FROM_SR else + DATA_IMMEDIATE when OP = STOP else -- Status register information. + DATA_IMMEDIATE when OP = MOVEQ else + x"00000000" when OP = NEG or OP = NEGX or OP = NBCD else + DATA_IMMEDIATE when OP = ADDI or OP = CMPI or OP = SUBI or OP = ANDI or OP = EORI or OP = ORI else + DATA_IMMEDIATE when OP = ADDQ or OP = SUBQ else + DATA_IMMEDIATE when OP = ANDI_TO_CCR or OP = ANDI_TO_SR else + DATA_IMMEDIATE when OP = EORI_TO_CCR or OP = EORI_TO_SR else + DATA_IMMEDIATE when OP = ORI_TO_CCR or OP = ORI_TO_SR else + DR_OUT_1 when BIW_0(5 downto 3) = "000" else + AR_OUT_1 when BIW_0(5 downto 3) = "001" else + DATA_IMMEDIATE when BIW_0(5 downto 0) = "111100" else DATA_TO_CORE; + + ALU_OP2_IN <= DR_OUT_2 when (OP = ABCD or OP = SBCD) and BIW_0(3) = '0' else + DATA_TO_CORE when OP = ABCD or OP = SBCD else + DR_OUT_2 when (OP = ADDX or OP = SUBX) and BIW_0(3) = '0' else + DATA_TO_CORE when OP = ADDX or OP = SUBX else + DR_OUT_2 when (OP = ADD or OP = CMP or OP = SUB) and BIW_0(8) = '0' else + DR_OUT_2 when (OP = AND_B or OP = OR_B) and BIW_0(8) = '0' else + AR_OUT_2 when (OP = ADDA or OP = CMPA or OP = SUBA) else + DR_OUT_2 when OP = EXG and BIW_0(7 downto 3) = "01000" else -- Two data registers. + AR_OUT_2 when OP = EXG else + DR_OUT_2 when (OP = ASL or OP = ASR) and BIW_0(7 downto 6) /= "11" else -- Register shifts. + DR_OUT_2 when (OP = LSL or OP = LSR) and BIW_0(7 downto 6) /= "11" else -- Register shifts. + DR_OUT_2 when (OP = ROTL or OP = ROTR) and BIW_0(7 downto 6) /= "11" else -- Register shifts. + DR_OUT_2 when (OP = ROXL or OP = ROXR) and BIW_0(7 downto 6) /= "11" else -- Register shifts. + x"0000" & STATUS_REG when(OP = ANDI_TO_CCR or OP = ANDI_TO_SR) else + x"0000" & STATUS_REG when(OP = EORI_TO_CCR or OP = EORI_TO_SR) else + x"0000" & STATUS_REG when(OP = ORI_TO_CCR or OP = ORI_TO_SR) else + DATA_TO_CORE when OP = CAS or OP = CAS2 else -- Destination operand. + DR_OUT_2 when (OP = CHK2 or OP = CMP2) and USE_DREG = '1' else + AR_OUT_2 when OP = CHK or OP = CHK2 or OP = CMP2 else + DATA_TO_CORE when OP = CMPM else + DR_OUT_2 when OP = DBcc or OP = SWAP else + DR_OUT_2 when OP = DIVS or OP = DIVU else + DR_OUT_2 when OP = MULS or OP = MULU else + DR_OUT_1 when (OP = PACK or OP = UNPK) and BIW_0(3) = '0' else -- Register direct. + DATA_TO_CORE when OP = PACK or OP = UNPK else + AR_OUT_1 when OP = LINK else + DR_OUT_2 when BIW_0(5 downto 3) = "000" else + AR_OUT_2 when BIW_0(5 downto 3) = "001" else DATA_TO_CORE; + + ALU_OP3_IN <= DATA_TO_CORE when (OP = BFCHG or OP = BFCLR or OP = BFEXTS or OP = BFEXTU) and BIW_0(5 downto 3) /= "000" else + DATA_TO_CORE when (OP = BFFFO or OP = BFINS or OP = BFSET or OP = BFTST) and BIW_0(5 downto 3) /= "000" else + DATA_TO_CORE when OP = CAS2 or OP = CHK2 or OP = CMP2 else DR_OUT_1; + + OP_SIZE <= OP_SIZE_EXH when BUSY_EXH = '1' else OP_SIZE_MAIN; + OP_SIZE_BUS <= OP_SIZE_WB when DATA_WR_MAIN = '1' else OP_SIZE; + + + PC_OFFSET <= PC_OFFSET_OPD; + PC_L <= PC + PC_ADR_OFFSET; + + PC_INC_EXH_I <= PC_INC_EXH when LOOP_SPLIT = false else '0'; -- Suppress for a split loop. + + ADR_MODE <= "010" when BUSY_EXH = '1' else ADR_MODE_MAIN; --(ISP) + + -- The bit field offset is byte aligned + ADR_OFFSET <= x"00000000" when FETCH_MEM_ADR = '1' else + ADR_OFFSET_EXH when BUSY_EXH = '1' else + "000" & BF_OFFSET(31 downto 3) + ADR_OFFSET_MAIN when (OP = BFCHG or OP = BFCLR or OP = BFEXTS or OP = BFEXTU) and BF_OFFSET(31) = '0' else + "111" & BF_OFFSET(31 downto 3) + ADR_OFFSET_MAIN when OP = BFCHG or OP = BFCLR or OP = BFEXTS or OP = BFEXTU else + "000" & BF_OFFSET(31 downto 3) + ADR_OFFSET_MAIN when (OP = BFFFO or OP = BFINS or OP = BFSET or OP = BFTST ) and BF_OFFSET(31) = '0' else + "111" & BF_OFFSET(31 downto 3) + ADR_OFFSET_MAIN when OP = BFFFO or OP = BFINS or OP = BFSET or OP = BFTST else + x"000000" & "00" & ADR_OFFSET_MAIN; + + DBcc_COND <= true when OP_WB = DBcc and ALU_RESULT(15 downto 0) = x"FFFF" else false; + + -- Take a branch if the CPU space will change: + BRANCH_ATN <= '1' when OP = ANDI_TO_SR and DATA_IMMEDIATE(13) = '0' and STATUS_REG(13) = '1' else + '1' when OP = ANDI_TO_SR and DATA_IMMEDIATE(12) = '0' and STATUS_REG(12) = '1' else + '1' when OP = EORI_TO_SR and DATA_IMMEDIATE(13) = '1' else + '1' when OP = EORI_TO_SR and DATA_IMMEDIATE(12) = '1' else + '1' when OP = ORI_TO_SR and DATA_IMMEDIATE(13) = '1' and STATUS_REG(13) = '0' else + '1' when OP = ORI_TO_SR and DATA_IMMEDIATE(12) = '1' and STATUS_REG(12) = '0' else + '1' when OP = MOVE_TO_SR and BIW_0(5 downto 3) = "000" and DR_OUT_1(13 downto 12) /= STATUS_REG(13 downto 12) else + '1' when OP = MOVE_TO_SR and BIW_0(5 downto 0) = "111100" and DATA_IMMEDIATE(13 downto 12) /= STATUS_REG(13 downto 12) else + '1' when OP = MOVE_TO_SR and DATA_TO_CORE(13 downto 12) /= STATUS_REG(13 downto 12) else '0'; + + DATA_RD <= DATA_RD_EXH or DATA_RD_MAIN; + DATA_WR <= DATA_WR_EXH or DATA_WR_MAIN; + + P_BUSREQ: process + begin + wait until CLK = '1' and CLK' event; + -- We need these flip flops to avoid combinatorial loops: + -- The requests are valid until the bus controller enters + -- its START_CYCLE bus phase and asserts there the BUS_BSY. + -- After the bus controller enters the bus access state, + -- the requests are withdrawn. + if BUS_BSY = '0' then + RD_REQ_I <= DATA_RD; + WR_REQ_I <= DATA_WR; + OPCODE_REQ_I <= OPCODE_RD; + elsif BUS_BSY = '1' then + RD_REQ_I <= '0'; + WR_REQ_I <= '0'; + OPCODE_REQ_I <= '0'; + end if; + end process P_BUSREQ; + + RD_REQ <= DATA_RD when BUS_BSY = '0' else RD_REQ_I; + WR_REQ <= DATA_WR when BUS_BSY = '0' else WR_REQ_I; + OPCODE_REQ <= OPCODE_RD when BUS_BSY = '0' else OPCODE_REQ_I; + + DISPLACEMENT <= DISPLACEMENT_MAIN when BUSY_MAIN = '1' else x"000000" & DISPLACEMENT_EXH; + + SR_WR <= SR_WR_EXH or SR_WR_MAIN; + + IPIPE_FLUSH <= IPIPE_FLUSH_EXH or IPIPE_FLUSH_MAIN; + + ISP_WR <= ISP_WR_MAIN or ISP_LOAD_EXH; + + AVECn_BUSIF <= AVECn when BUSY_EXH = '1' else '1'; + + CPU_SPACE <= '1' when OP = BKPT and DATA_RD_MAIN = '1' else + CPU_SPACE_EXH when BUSY_EXH = '1' else '0'; + + -- The bit field offset is bit wise. + BF_OFFSET <= (x"000000" & "000" & BIW_1(10 downto 6)) when BIW_1(11) = '0' else DR_OUT_1; + BF_WIDTH <= '0' & BIW_1(4 downto 0) when BIW_1(4 downto 0) /= "00000" and BIW_1(5) = '0' else + '0' & DR_OUT_1(4 downto 0) when DR_OUT_1(4 downto 0) /= "00000" and BIW_1(5) = '1' else "100000"; + + -- The BITPOS is valid for bit operations and bit field operations. For BCHG, BCLR, BSET and BTST + -- the BITPOS spans 0 to 31 bytes, when it is in register direct mode. It is modulo 8 in memory + -- manipulation mode. For the bit field operations in register direct mode it also in the + -- range 0 to 31. For bit fields in memory the value is byte wide (0 to 7) because the bit + -- field from a memory location are loaded from byte boundaries. + BITPOS <= BIW_1(4 downto 0) when (OP = BCHG or OP = BCLR or OP = BSET or OP = BTST) and BIW_0(8) = '0' and ADR_MODE = "000" else + "00" & BIW_1(2 downto 0) when (OP = BCHG or OP = BCLR or OP = BSET or OP = BTST) and BIW_0(8) = '0' else + DR_OUT_1(4 downto 0) when (OP = BCHG or OP = BCLR or OP = BSET or OP = BTST) and ADR_MODE = "000" else + "00" & DR_OUT_1(2 downto 0) when OP = BCHG or OP = BCLR or OP = BSET or OP = BTST else + BIW_1(10 downto 6) when BIW_1(11) = '0' and ADR_MODE = "000" else + "00" & BIW_1(8 downto 6) when BIW_1(11) = '0' else + DR_OUT_1(4 downto 0) when ADR_MODE = "000" else "00" & DR_OUT_1(2 downto 0); + + TRAP_AERR <= AERR when BUSY_EXH = '0' else '0'; -- No address error from the system during exception processing. + + USE_DFC <= '1' when OP_WB = MOVES and DATA_WR_MAIN = '1' else '0'; + USE_SFC <= '1' when OP_WB = MOVES and DATA_RD_MAIN = '1' else '0'; + + PC_LOAD <= PC_LOAD_EXH or PC_LOAD_MAIN; + + RESET_IN <= not RESET_INn; + IPL <= not IPLn; + + REFILL_STATUS: process + -- This tiny logic provides signal transition on the negative + -- clock edge. + begin + wait until CLK = '0' and CLK' event; + if (STATUSn_EXH and STATUSn_MAIN) = '1' then + STATUSn <= '1'; + else + STATUSn <= '0'; + end if; + REFILLn <= REFILLn_EXH; + end process REFILL_STATUS; + + SBIT <= STATUS_REG(13); + + ADR_L <= x"000000" & "000" & BIW_0(2 downto 0) & "00" when BKPT_CYCLE = '1' else + x"FFFFFFF" & IRQ_PEND & '1' when CPU_SPACE_EXH = '1' else + ADR_EFF_WB when DATA_WR_MAIN = '1' else ADR_EFF; -- Exception handler uses ADR_EFF for read and write access. + + ADR_P <= ADR_LATCH when BUS_BSY = '1' else + ADR_L when DATA_RD = '1' or DATA_WR = '1' else PC_L; + + P_ADR_LATCHES: process + -- This register stores the address during a running bus cycle. + -- The signals RD_DATA, WR_DATA and RD_OPCODE may change during + -- the cycle. Opcode read is lower prioritized. + -- FAULT_ADR latches the faulty address for stacking it via + -- the exception handler. + -- The FC_LATCH register stores the function code during a running + -- bus cycle. + begin + wait until CLK = '1' and CLK' event; + if BUS_BSY = '0' then + ADR_LATCH <= ADR_P; + FC_LATCH <= FC_I; + elsif BERRn = '0' then + FAULT_ADR <= ADR_LATCH; + end if; + end process P_ADR_LATCHES; + + FC_I <= FC_LATCH when BUS_BSY = '1' else + SFC when USE_SFC = '1' else + DFC when USE_DFC = '1' else + "111" when (DATA_RD = '1' or DATA_WR = '1') and CPU_SPACE = '1' else + "101" when (DATA_RD = '1' or DATA_WR = '1') and SBIT = '1' else + "001" when DATA_RD = '1' or DATA_WR = '1' else + "110" when OPCODE_RD = '1' and SBIT = '1' else "010"; -- Default is OPCODE_RD and SBIT = '0'. + + I_ADDRESSREGISTERS: WF68K30L_ADDRESS_REGISTERS + port map( + CLK => CLK, + RESET => RESET_CPU, + AR_IN_1 => AR_IN_1, + AR_IN_2 => AR_IN_2, + AR_OUT_1 => AR_OUT_1, + AR_OUT_2 => AR_OUT_2, + INDEX_IN => DR_OUT_1, -- From data register section. + PC => PC, + FETCH_MEM_ADR => FETCH_MEM_ADR, + STORE_ADR_FORMAT => STORE_ADR_FORMAT, + STORE_ABS_HI => STORE_ABS_HI, + STORE_ABS_LO => STORE_ABS_LO, + STORE_D16 => STORE_D16, + STORE_D32_LO => STORE_D32_LO, + STORE_D32_HI => STORE_D32_HI, + STORE_DISPL => STORE_DISPL, + STORE_MEM_ADR => STORE_MEM_ADR, + STORE_OD_HI => STORE_OD_HI, + STORE_OD_LO => STORE_OD_LO, + STORE_AEFF => STORE_AEFF, + OP_SIZE => OP_SIZE, + AR_MARK_USED => AR_MARK_USED, + USE_APAIR => USE_APAIR, + AR_IN_USE => AR_IN_USE, + AR_SEL_RD_1 => AR_SEL_RD_1, + AR_SEL_RD_2 => AR_SEL_RD_2, + AR_SEL_WR_1 => AR_SEL_WR_1, + AR_SEL_WR_2 => AR_SEL_WR_2, + ADR_OFFSET => ADR_OFFSET, -- Byte aligned. + ADR_MARK_USED => ADR_MARK_USED, + ADR_IN_USE => ADR_IN_USE, + ADR_MODE => ADR_MODE, + AMODE_SEL => AMODE_SEL, + USE_DREG => USE_DREG, + ADR_EFF => ADR_EFF, + ADR_EFF_WB => ADR_EFF_WB, + DFC => DFC, + DFC_WR => DFC_WR, + SFC => SFC, + SFC_WR => SFC_WR, + ISP_DEC => ISP_DEC, + ISP_RD => ISP_RD, + ISP_WR => ISP_WR, + MSP_RD => MSP_RD, + MSP_WR => MSP_WR, + USP_RD => USP_RD, + USP_WR => USP_WR, + AR_DEC => AR_DEC, + AR_INC => AR_INC, + AR_WR_1 => AR_WR_1, + AR_WR_2 => AR_WR_2, + UNMARK => UNMARK, + EXT_WORD => EXT_WORD, + MBIT => STATUS_REG(12), + SBIT => SBIT, + SP_ADD_DISPL => SP_ADD_DISPL, + RESTORE_ISP_PC => RESTORE_ISP_PC, + DISPLACEMENT => DISPLACEMENT, + PC_ADD_DISPL => PC_ADD_DISPL, + PC_EW_OFFSET => PC_EW_OFFSET, + PC_INC => PC_INC, + PC_LOAD => PC_LOAD, + PC_RESTORE => PC_RESTORE_EXH, + PC_OFFSET => PC_OFFSET + ); + + I_ALU: WF68K30L_ALU + port map( + CLK => CLK, + RESET => RESET_CPU, + LOAD_OP2 => ALU_LOAD_OP2, + LOAD_OP3 => ALU_LOAD_OP3, + LOAD_OP1 => ALU_LOAD_OP1, + OP1_IN => ALU_OP1_IN, + OP2_IN => ALU_OP2_IN, + OP3_IN => ALU_OP3_IN, + BF_OFFSET_IN => BF_OFFSET, + BF_WIDTH_IN => BF_WIDTH, + BITPOS_IN => BITPOS, + RESULT => ALU_RESULT, + ADR_MODE_IN => ADR_MODE, + USE_DREG => USE_DREG, + HILOn => HILOn, + OP_SIZE_IN => OP_SIZE, + OP_IN => OP, + OP_WB => OP_WB, + BIW_0_IN => BIW_0(11 downto 0), + BIW_1_IN => BIW_1, + SR_WR => SR_WR, + SR_INIT => SR_INIT, + SR_CLR_MBIT => SR_CLR_MBIT, + CC_UPDT => CC_UPDT, + STATUS_REG_OUT => STATUS_REG, + ALU_COND => ALU_COND, + ALU_INIT => ALU_INIT, + ALU_BSY => ALU_BSY, + ALU_REQ => ALU_REQ, + ALU_ACK => ALU_ACK, + IRQ_PEND => IRQ_PEND, + TRAP_CHK => TRAP_CHK, + TRAP_DIVZERO => TRAP_DIVZERO + ); + + I_BUS_IF: WF68K30L_BUS_INTERFACE + port map( + CLK => CLK, + + ADR_IN_P => ADR_P, + ADR_OUT_P => ADR_OUT, + + FC_IN => FC_I, + FC_OUT => FC_OUT, + + DATA_PORT_IN => DATA_IN, + DATA_PORT_OUT => DATA_OUT, + DATA_FROM_CORE => DATA_FROM_CORE, + DATA_TO_CORE => DATA_TO_CORE, + OPCODE_TO_CORE => OPCODE_TO_CORE, + + DATA_PORT_EN => DATA_EN, + BUS_EN => BUS_EN, + + SIZE => SIZE, + OP_SIZE => OP_SIZE_BUS, + + RD_REQ => RD_REQ, + WR_REQ => WR_REQ, + DATA_RDY => DATA_RDY, + DATA_VALID => DATA_VALID, + OPCODE_REQ => OPCODE_REQ, + OPCODE_RDY => OPCODE_RDY, + OPCODE_VALID => OPCODE_VALID, + RMC => RMC, + BUSY_EXH => BUSY_EXH, + SSW_80 => SSW_80, + INBUFFER => INBUFFER, + OUTBUFFER => OUTBUFFER, + + DSACKn => DSACKn, + ASn => ASn, + DSn => DSn, + RWn => RWn, + RMCn => RMCn, + ECSn => ECSn, + OCSn => OCSn, + DBENn => DBENn, + + STERMn => STERMn, + + BRn => BRn, + BGACKn => BGACKn, + BGn => BGn, + + RESET_STRB => RESET_STRB, + RESET_IN => RESET_IN, + RESET_OUT => RESET_OUT, + RESET_CPU => RESET_CPU, + + AVECn => AVECn_BUSIF, + HALTn => HALT_INn, + BERRn => BERRn, + AERR => AERR, + + BUS_BSY => BUS_BSY + ); + + I_CONTROL: WF68K30L_CONTROL + generic map(NO_PIPELINE => NO_PIPELINE) + port map( + CLK => CLK, + RESET_CPU => RESET_CPU, + BUSY => BUSY_MAIN, + BUSY_EXH => BUSY_EXH, + EXH_REQ => EXH_REQ, + INT_TRIG => INT_TRIG, + OW_REQ => OW_REQ_MAIN, + OW_VALID => OW_VALID, + EW_REQ => EW_REQ_MAIN, + EW_ACK => EW_ACK, + OPD_ACK => OPD_ACK_MAIN, + ADR_MARK_USED => ADR_MARK_USED, + ADR_IN_USE => ADR_IN_USE, + ADR_OFFSET => ADR_OFFSET_MAIN, + DATA_RD => DATA_RD_MAIN, + DATA_WR => DATA_WR_MAIN, + DATA_RDY => DATA_RDY, + DATA_VALID => DATA_VALID, + RMC => RMC, + FETCH_MEM_ADR => FETCH_MEM_ADR, + LOAD_OP1 => ALU_LOAD_OP1, + LOAD_OP2 => ALU_LOAD_OP2, + LOAD_OP3 => ALU_LOAD_OP3, + STORE_ADR_FORMAT => STORE_ADR_FORMAT, + STORE_ABS_HI => STORE_ABS_HI, + STORE_ABS_LO => STORE_ABS_LO, + STORE_D16 => STORE_D16, + STORE_D32_LO => STORE_D32_LO, + STORE_D32_HI => STORE_D32_HI, + STORE_DISPL => STORE_DISPL, + STORE_MEM_ADR => STORE_MEM_ADR, + STORE_OD_HI => STORE_OD_HI, + STORE_OD_LO => STORE_OD_LO, + STORE_AEFF => STORE_AEFF, + STORE_IDATA_B1 => STORE_IDATA_B1, + STORE_IDATA_B2 => STORE_IDATA_B2, + OP => OP, + OP_SIZE => OP_SIZE_MAIN, + BIW_0 => BIW_0(13 downto 0), + BIW_1 => BIW_1, + BIW_2 => BIW_2, + EXT_WORD => EXT_WORD, + ADR_MODE => ADR_MODE_MAIN, + AMODE_SEL => AMODE_SEL, + USE_DREG => USE_DREG, + HILOn => HILOn, + OP_WB => OP_WB, + OP_SIZE_WB => OP_SIZE_WB, + BIW_0_WB_73 => BIW_0_WB_73, + AR_MARK_USED => AR_MARK_USED, + AR_IN_USE => AR_IN_USE, + AR_SEL_RD_1 => AR_SEL_RD_1_MAIN, + AR_SEL_RD_2 => AR_SEL_RD_2, + AR_SEL_WR_1 => AR_SEL_WR_1, + AR_SEL_WR_2 => AR_SEL_WR_2, + AR_INC => AR_INC, + AR_DEC => AR_DEC, + AR_WR_1 => AR_WR_1, + AR_WR_2 => AR_WR_2, + DR_MARK_USED => DR_MARK_USED, + USE_APAIR => USE_APAIR, + USE_DPAIR => USE_DPAIR, + DR_IN_USE => DR_IN_USE, + DR_SEL_WR_1 => DR_SEL_WR_1, + DR_SEL_WR_2 => DR_SEL_WR_2, + DR_SEL_RD_1 => DR_SEL_RD_1, + DR_SEL_RD_2 => DR_SEL_RD_2, + DR_WR_1 => DR_WR_1, + DR_WR_2 => DR_WR_2, + UNMARK => UNMARK, + DISPLACEMENT => DISPLACEMENT_MAIN, + PC_ADD_DISPL => PC_ADD_DISPL, + PC_LOAD => PC_LOAD_MAIN, + PC_INC_EXH => PC_INC_EXH, + SP_ADD_DISPL => SP_ADD_DISPL_MAIN, + DFC_RD => DFC_RD, + DFC_WR => DFC_WR, + SFC_RD => SFC_RD, + SFC_WR => SFC_WR, + VBR_RD => VBR_RD, + VBR_WR => VBR_WR, + ISP_RD => ISP_RD, + ISP_WR => ISP_WR_MAIN, + MSP_RD => MSP_RD, + MSP_WR => MSP_WR, + USP_RD => USP_RD, + USP_WR => USP_WR, + IPIPE_FLUSH => IPIPE_FLUSH_MAIN, + ALU_INIT => ALU_INIT, + ALU_BSY => ALU_BSY, + ALU_REQ => ALU_REQ, + ALU_ACK => ALU_ACK, + BKPT_CYCLE => BKPT_CYCLE, + BKPT_INSERT => BKPT_INSERT, + LOOP_BSY => LOOP_BSY, + LOOP_SPLIT => LOOP_SPLIT, + LOOP_EXIT => LOOP_EXIT, + BF_OFFSET => BF_OFFSET(2 downto 0), + BF_WIDTH => BF_WIDTH, + SR_WR => SR_WR_MAIN, + MOVEM_ADn => ADn, + MOVEP_PNTR => MOVEP_PNTR, + CC_UPDT => CC_UPDT, + TRACE_MODE => STATUS_REG(15 downto 14), + VBIT => STATUS_REG(1), + ALU_COND => ALU_COND, + DBcc_COND => DBcc_COND, + BRANCH_ATN => BRANCH_ATN, + RESET_STRB => RESET_STRB, + BERR => BERR_MAIN, + STATUSn => STATUSn_MAIN, + EX_TRACE => EX_TRACE, + TRAP_cc => TRAP_cc, + TRAP_V => TRAP_V, + TRAP_ILLEGAL => TRAP_ILLEGAL + ); + + I_DATA_REGISTERS: WF68K30L_DATA_REGISTERS + port map( + CLK => CLK, + RESET => RESET_CPU, + DR_IN_1 => DR_IN_1, + DR_IN_2 => DR_IN_2, + DR_OUT_2 => DR_OUT_2, + DR_OUT_1 => DR_OUT_1, + DR_SEL_WR_1 => DR_SEL_WR_1, + DR_SEL_WR_2 => DR_SEL_WR_2, + DR_SEL_RD_1 => DR_SEL_RD_1, + DR_SEL_RD_2 => DR_SEL_RD_2, + DR_WR_1 => DR_WR_1, + DR_WR_2 => DR_WR_2, + DR_MARK_USED => DR_MARK_USED, + USE_DPAIR => USE_DPAIR, + DR_IN_USE => DR_IN_USE, + UNMARK => UNMARK, + OP_SIZE => OP_SIZE_WB + ); + + I_EXC_HANDLER: WF68K30L_EXCEPTION_HANDLER + generic map(VERSION => VERSION) + port map( + CLK => CLK, + + RESET => RESET_CPU, + BUSY_MAIN => BUSY_MAIN, + BUSY_OPD => BUSY_OPD, + + EXH_REQ => EXH_REQ, + BUSY_EXH => BUSY_EXH, + + ADR_IN => ADR_EFF, + ADR_CPY => ADR_CPY_EXH, + ADR_OFFSET => ADR_OFFSET_EXH, + CPU_SPACE => CPU_SPACE_EXH, + + DATA_0 => DATA_TO_CORE(0), + DATA_RD => DATA_RD_EXH, + DATA_WR => DATA_WR_EXH, + DATA_IN => DATA_IN_EXH, + + OP_SIZE => OP_SIZE_EXH, + DATA_RDY => DATA_RDY, + DATA_VALID => DATA_VALID, + + OPCODE_RDY => OPCODE_RDY, + OPD_ACK => OPD_ACK_MAIN, + OW_VALID => OW_VALID, + + STATUS_REG_IN => STATUS_REG, + SR_CPY => SR_CPY, + SR_INIT => SR_INIT, + SR_CLR_MBIT => SR_CLR_MBIT, + + SR_WR => SR_WR_EXH, + ISP_DEC => ISP_DEC, + ISP_LOAD => ISP_LOAD_EXH, + PC_LOAD => PC_LOAD_EXH, + PC_INC => PC_INC_EXH, + PC_RESTORE => PC_RESTORE_EXH, + + STACK_FORMAT => STACK_FORMAT, + STACK_POS => STACK_POS, + + SP_ADD_DISPL => SP_ADD_DISPL_EXH, + DISPLACEMENT => DISPLACEMENT_EXH, + IPIPE_FILL => IPIPE_FILL, + IPIPE_FLUSH => IPIPE_FLUSH_EXH, + REFILLn => REFILLn_EXH, + RESTORE_ISP_PC => RESTORE_ISP_PC, + + HALT_OUTn => HALT_OUTn, + STATUSn => STATUSn_EXH, + + INT_TRIG => INT_TRIG, + IRQ_IN => IPL, + IRQ_PEND => IRQ_PEND, + AVECn => AVECn, + IPENDn => IPENDn, + IVECT_OFFS => IVECT_OFFS, + + TRAP_AERR => TRAP_AERR, + TRAP_BERR => BERR_MAIN, + TRAP_CHK => TRAP_CHK, + TRAP_DIVZERO => TRAP_DIVZERO, + TRAP_ILLEGAL => TRAP_ILLEGAL, + TRAP_CODE_OPC => TRAP_CODE_OPC, + TRAP_VECTOR => BIW_0(3 downto 0), + TRAP_cc => TRAP_cc, + TRAP_V => TRAP_V, + EX_TRACE_IN => EX_TRACE, + VBR_WR => VBR_WR, + VBR => VBR + ); + + I_OPCODE_DECODER: WF68K30L_OPCODE_DECODER + generic map(NO_LOOP => NO_LOOP) + port map( + CLK => CLK, + + OW_REQ_MAIN => OW_REQ_MAIN, + EW_REQ_MAIN => EW_REQ_MAIN, + + EXH_REQ => EXH_REQ, + BUSY_EXH => BUSY_EXH, + BUSY_MAIN => BUSY_MAIN, + BUSY_OPD => BUSY_OPD, + + BKPT_INSERT => BKPT_INSERT, + BKPT_DATA => DATA_TO_CORE(15 downto 0), + + LOOP_EXIT => LOOP_EXIT, + LOOP_BSY => LOOP_BSY, + + OPD_ACK_MAIN => OPD_ACK_MAIN, + EW_ACK => EW_ACK, + + PC_INC => PC_INC, + PC_INC_EXH => PC_INC_EXH_I, + PC_ADR_OFFSET => PC_ADR_OFFSET, + PC_EW_OFFSET => PC_EW_OFFSET, + PC_OFFSET => PC_OFFSET_OPD, + + OPCODE_RD => OPCODE_RD, + OPCODE_RDY => OPCODE_RDY, + OPCODE_VALID => OPCODE_VALID, + OPCODE_DATA => OPCODE_TO_CORE, + + IPIPE_FILL => IPIPE_FILL, + IPIPE_FLUSH => IPIPE_FLUSH, + + -- Fault logic: + OW_VALID => OW_VALID, + RC => RC, + RB => RB, + FC => FC, + FB => FB, + + -- Trap logic: + SBIT => SBIT, + TRAP_CODE => TRAP_CODE_OPC, + + -- System control: + OP => OP, + BIW_0 => BIW_0, + BIW_1 => BIW_1, + BIW_2 => BIW_2, + EXT_WORD => EXT_WORD + ); +end STRUCTURE;