1 |
56 |
dgisselq |
///////////////////////////////////////////////////////////////////////////////
|
2 |
|
|
//
|
3 |
|
|
// Filename: cpudefs.v
|
4 |
|
|
//
|
5 |
|
|
// Project: Zip CPU -- a small, lightweight, RISC CPU soft core
|
6 |
|
|
//
|
7 |
|
|
// Purpose: Some architectures have some needs, others have other needs.
|
8 |
|
|
// Some of my projects need a Zip CPU with pipelining, others
|
9 |
|
|
// can't handle the timing required to get the answer from the ALU
|
10 |
|
|
// back into the input for the ALU. As each different projects has
|
11 |
|
|
// different needs, I can either 1) reconfigure my entire baseline prior
|
12 |
|
|
// to building each project, or 2) host a configuration file which contains
|
13 |
|
|
// the information regarding each baseline. This file is that
|
14 |
|
|
// configuration file. It controls how the CPU (not the system,
|
15 |
|
|
// peripherals, or other) is defined and implemented. Several options
|
16 |
|
|
// are available within here, making the Zip CPU pipelined or not,
|
17 |
|
|
// able to handle a faster clock with more stalls or a slower clock with
|
18 |
|
|
// no stalls, etc.
|
19 |
|
|
//
|
20 |
|
|
// This file encapsulates those control options.
|
21 |
|
|
//
|
22 |
|
|
// The number of LUTs the Zip CPU uses varies dramatically with the
|
23 |
|
|
// options defined in this file.
|
24 |
|
|
//
|
25 |
|
|
//
|
26 |
|
|
// Creator: Dan Gisselquist, Ph.D.
|
27 |
|
|
// Gisselquist Tecnology, LLC
|
28 |
|
|
//
|
29 |
|
|
///////////////////////////////////////////////////////////////////////////////
|
30 |
|
|
//
|
31 |
|
|
// Copyright (C) 2015, Gisselquist Technology, LLC
|
32 |
|
|
//
|
33 |
|
|
// This program is free software (firmware): you can redistribute it and/or
|
34 |
|
|
// modify it under the terms of the GNU General Public License as published
|
35 |
|
|
// by the Free Software Foundation, either version 3 of the License, or (at
|
36 |
|
|
// your option) any later version.
|
37 |
|
|
//
|
38 |
|
|
// This program is distributed in the hope that it will be useful, but WITHOUT
|
39 |
|
|
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
|
40 |
|
|
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
41 |
|
|
// for more details.
|
42 |
|
|
//
|
43 |
|
|
// License: GPL, v3, as defined and found on www.gnu.org,
|
44 |
|
|
// http://www.gnu.org/licenses/gpl.html
|
45 |
|
|
//
|
46 |
|
|
//
|
47 |
|
|
///////////////////////////////////////////////////////////////////////////////
|
48 |
|
|
`ifndef CPUDEFS_H
|
49 |
|
|
`define CPUDEFS_H
|
50 |
|
|
//
|
51 |
|
|
//
|
52 |
|
|
// The first couple options control the Zip CPU instruction set, and how
|
53 |
|
|
// it handles various instructions within the set:
|
54 |
|
|
//
|
55 |
|
|
//
|
56 |
|
|
// OPT_CONDITIONAL_FLAGS controls whether or not a conditional instruction
|
57 |
|
|
// is allowed to set flags. If conditional instructions can set flags, then
|
58 |
|
|
// strings of conditional instructions will die whenever a flag setting
|
59 |
|
|
// instruction is executed. If they cannot, then you can execute a string
|
60 |
|
|
// of functions with no further conditions in them. Set this flag to enable
|
61 |
|
|
// strings of instructions, as these can be a lot cheaper than the pipeline
|
62 |
|
|
// stalls associated with a conditional branch.
|
63 |
|
|
//
|
64 |
|
|
// This option will likely be changed in the future so that "CMP" and "TST"
|
65 |
|
|
// instructions set the flags even if they are conditional, to allow multiple
|
66 |
|
|
// conditions to be tested at once.
|
67 |
|
|
//
|
68 |
|
|
// I recommend setting this flag
|
69 |
|
|
//
|
70 |
|
|
`define OPT_CONDITIONAL_FLAGS
|
71 |
|
|
//
|
72 |
|
|
//
|
73 |
|
|
//
|
74 |
|
|
// OPT_ILLEGAL_INSTRUCTION is part of a new section of code that is supposed
|
75 |
|
|
// to recognize illegal instructions and interrupt the CPU whenever one such
|
76 |
|
|
// instruction is encountered. The goal is to create a soft floating point
|
77 |
|
|
// unit via this approach, that can then be replaced with a true floating point
|
78 |
|
|
// unit. As I'm not there yet, it just catches illegal instructions and
|
79 |
|
|
// interrupts the CPU on any such instruction--when defined. Otherwise,
|
80 |
|
|
// illegal instructions are quietly ignored and their behaviour is ...
|
81 |
|
|
// undefined. (Many get treated like NOOPs ...)
|
82 |
|
|
//
|
83 |
|
|
// I recommend setting this flag, although it can be taken out if area is
|
84 |
|
|
// critical ...
|
85 |
|
|
//
|
86 |
|
|
`define OPT_ILLEGAL_INSTRUCTION
|
87 |
|
|
//
|
88 |
|
|
//
|
89 |
|
|
//
|
90 |
|
|
// OPT_MULTIPLY controls whether or not the multiply is built and included
|
91 |
|
|
// in the ALU by default. Set this option and a parameter will be set that
|
92 |
|
|
// includes the multiply. (This parameter may still be overridden, as with
|
93 |
|
|
// any parameter ...) If the multiply is not included and
|
94 |
|
|
// OPT_ILLEGAL_INSTRUCTION is set, then the multiply will create an illegal
|
95 |
|
|
// instruction that will then trip the illegal instruction trap.
|
96 |
|
|
//
|
97 |
|
|
//
|
98 |
|
|
`define OPT_MULTIPLY
|
99 |
|
|
//
|
100 |
|
|
//
|
101 |
|
|
//
|
102 |
|
|
// OPT_SINGLE_FETCH controls whether or not the prefetch has a cache, and
|
103 |
|
|
// whether or not it can issue one instruction per clock. When set, the
|
104 |
|
|
// prefetch has no cache, and only one instruction is fetched at a time.
|
105 |
|
|
// This effectively sets the CPU so that only one instruction is ever
|
106 |
|
|
// in the pipeline at once, and hence you may think of this as a "kill
|
107 |
|
|
// pipeline" option. However, since the pipelined fetch component uses so
|
108 |
|
|
// much area on the FPGA, this is an important option to use in trimming down
|
109 |
|
|
// used area if necessary. Hence, it needs to be maintained for that purpose.
|
110 |
|
|
// Be aware, though, it will drop your performance by a factor between 2x and
|
111 |
|
|
// 3x.
|
112 |
|
|
//
|
113 |
64 |
dgisselq |
// We can either pipeline our fetches, or issue one fetch at a time. Pipelined
|
114 |
|
|
// fetches are more complicated and therefore use more FPGA resources, while
|
115 |
|
|
// single fetches will cause the CPU to stall for about 5 stalls each
|
116 |
|
|
// instruction cycle, effectively reducing the instruction count per clock to
|
117 |
|
|
// about 0.2. However, the area cost may be worth it. Consider:
|
118 |
|
|
//
|
119 |
|
|
// Slice LUTs ZipSystem ZipCPU
|
120 |
|
|
// Single Fetching 2521 1734
|
121 |
|
|
// Pipelined fetching 2796 2046
|
122 |
|
|
// (These numbers may be dated, but should still be representative ...)
|
123 |
|
|
//
|
124 |
56 |
dgisselq |
// I recommend only defining this if you "need" to, if area is tight and
|
125 |
|
|
// speed isn't as important. Otherwise, just leave this undefined.
|
126 |
|
|
//
|
127 |
|
|
// `define OPT_SINGLE_FETCH
|
128 |
|
|
//
|
129 |
|
|
//
|
130 |
|
|
//
|
131 |
|
|
// The next several options are pipeline optimization options. They make no
|
132 |
|
|
// sense in a single instruction fetch mode, hence we #ifndef them so they
|
133 |
|
|
// are only defined if we are in a full pipelined mode (i.e. OPT_SINGLE_FETCH
|
134 |
|
|
// is not defined).
|
135 |
|
|
//
|
136 |
|
|
`ifndef OPT_SINGLE_FETCH
|
137 |
|
|
//
|
138 |
|
|
//
|
139 |
|
|
//
|
140 |
|
|
// OPT_PRECLEAR_BUS allows an upcoming, unconditional, LOD/STO instruction
|
141 |
|
|
// to kick the prefetch off the memory bus so that the LOD/STO instruction may
|
142 |
|
|
// use the bus without waiting for the prefetch cycle to complete. While it
|
143 |
|
|
// sounds like this should speed things up, it isn't clear that it speeds up
|
144 |
|
|
// programs that much--often the bus gets precleared for the LOD/STO, only
|
145 |
|
|
// to have the next instruction stall because it wasn't loaded in time.
|
146 |
|
|
//
|
147 |
|
|
// While I recommend setting this flag, that recommendation may change in the
|
148 |
|
|
// future.
|
149 |
|
|
//
|
150 |
|
|
`define OPT_PRECLEAR_BUS
|
151 |
|
|
//
|
152 |
|
|
//
|
153 |
|
|
//
|
154 |
|
|
// OPT_EARLY_BRANCHING is an attempt to execute a BRA statement as early
|
155 |
|
|
// as possible, to avoid as many pipeline stalls on a branch as possible.
|
156 |
|
|
// It's not tremendously successful yet--BRA's suffer 3 stalls instead of 5,
|
157 |
|
|
// but I intend to keep working on this approach until the number of stalls
|
158 |
|
|
// gets down to one or (ideally) zero. That way a "BRA" can be used as the
|
159 |
|
|
// compiler's branch prediction optimizer: BRA's don't stall, while branches on
|
160 |
|
|
// conditions will always suffer about 5 stalls or so.
|
161 |
|
|
//
|
162 |
|
|
// I recommend setting this flag, so as to turn early branching on.
|
163 |
|
|
//
|
164 |
|
|
`define OPT_EARLY_BRANCHING
|
165 |
|
|
//
|
166 |
|
|
//
|
167 |
|
|
//
|
168 |
|
|
// OPT_PIPELINED_BUS_ACCESS controls whether or not LOD/STO instructions
|
169 |
|
|
// can take advantaged of pipelined bus instructions. To be eligible, the
|
170 |
|
|
// operations must be identical (cannot pipeline loads and stores, just loads
|
171 |
|
|
// only or stores only), and the addresses must either be identical or one up
|
172 |
|
|
// from the previous address. Further, the load/store string must all have
|
173 |
|
|
// the same conditional. This approach gains the must use, in my humble
|
174 |
|
|
// opinion, when saving registers to or restoring registers from the stack
|
175 |
|
|
// at the beginning/end of a procedure, or when doing a context swap.
|
176 |
|
|
//
|
177 |
|
|
// I recommend setting this flag, for performance reasons, especially if your
|
178 |
|
|
// wishbone bus can handle pipelined bus accesses.
|
179 |
|
|
//
|
180 |
|
|
`define OPT_PIPELINED_BUS_ACCESS
|
181 |
|
|
//
|
182 |
|
|
//
|
183 |
|
|
//
|
184 |
|
|
// OPT_SINGLE_CYCLE controls how the Zip CPU handles operations where the
|
185 |
|
|
// second of two instructions uses a register output from the first of the
|
186 |
|
|
// two. If set, there will be no stalling between such a pair of instructions.
|
187 |
|
|
// If not set, the CPU will insert a stall between such a pair to give the
|
188 |
|
|
// result time to propagate to the second instruction. Other than the existence
|
189 |
|
|
// of a stall, the CPU will still yield the same results for the same
|
190 |
|
|
// instructions.
|
191 |
|
|
//
|
192 |
|
|
// The purpose of this is really timing: With this option defined, a logical
|
193 |
|
|
// or combinatorial mux is placed prior to the input of the ALU. This mux,
|
194 |
|
|
// together with whatever ALU operation is to take place, must both fit within
|
195 |
|
|
// one clock cycle. If they cannot be made to fit within the one clock cycle,
|
196 |
|
|
// then either the clock must be slowed down so that they can fit, or this
|
197 |
|
|
// flag needs to be turned off (not set) to get rid of the mux--hence speeding
|
198 |
|
|
// up the clock while slowing down some instructions.
|
199 |
|
|
//
|
200 |
|
|
`define OPT_SINGLE_CYCLE
|
201 |
|
|
//
|
202 |
|
|
//
|
203 |
|
|
`endif // OPT_SINGLE_FETCH
|
204 |
|
|
//
|
205 |
|
|
//
|
206 |
|
|
`endif // CPUDEFS_H
|