1 |
2 |
samiam9512 |
`timescale 1ns / 1ps
|
2 |
|
|
//////////////////////////////////////////////////////////////////////////////////
|
3 |
|
|
// Company:
|
4 |
|
|
// Engineer:
|
5 |
|
|
//
|
6 |
|
|
// Create Date: 23:25:07 09/20/2006
|
7 |
|
|
// Design Name:
|
8 |
|
|
// Module Name: testbench
|
9 |
|
|
// Project Name:
|
10 |
|
|
// Target Devices:
|
11 |
|
|
// Tool versions:
|
12 |
|
|
// Description:
|
13 |
|
|
//
|
14 |
|
|
// Dependencies:
|
15 |
|
|
//
|
16 |
|
|
// Revision:
|
17 |
|
|
// Revision 0.01 - File Created
|
18 |
|
|
// Additional Comments:
|
19 |
|
|
//
|
20 |
|
|
//////////////////////////////////////////////////////////////////////////////////
|
21 |
|
|
|
22 |
|
|
module testbench(addr, // Address out
|
23 |
|
|
data, // Data bus
|
24 |
|
|
readmem, // Memory read
|
25 |
|
|
writemem, // Memory write
|
26 |
|
|
readio, // Read I/O space
|
27 |
|
|
writeio, // Write I/O space
|
28 |
|
|
intr, // Interrupt request
|
29 |
|
|
inta, // Interrupt request
|
30 |
|
|
waitr, // Wait request
|
31 |
11 |
samiam9512 |
r, g, b, // vga colors
|
32 |
|
|
hsync_n, // vga horizontal sync negative
|
33 |
|
|
vsync_n, // vga vertical sync negative
|
34 |
18 |
samiam9512 |
ps2_clk, // keyboard clock
|
35 |
|
|
ps2_data, // keyboard data
|
36 |
11 |
samiam9512 |
reset_n, // Reset
|
37 |
18 |
samiam9512 |
clock, // System clock
|
38 |
|
|
diag); // diagnostic port
|
39 |
2 |
samiam9512 |
|
40 |
|
|
output [15:0] addr;
|
41 |
|
|
inout [7:0] data;
|
42 |
|
|
output readmem;
|
43 |
|
|
output writemem;
|
44 |
|
|
output readio;
|
45 |
|
|
output writeio;
|
46 |
9 |
samiam9512 |
output intr;
|
47 |
2 |
samiam9512 |
output inta;
|
48 |
18 |
samiam9512 |
output waitr;
|
49 |
11 |
samiam9512 |
output [2:0] r, g, b; // R,G,B color output buses
|
50 |
18 |
samiam9512 |
output hsync_n; // horizontal sync pulse
|
51 |
|
|
output vsync_n; // vertical sync pulse
|
52 |
|
|
input ps2_clk; // clock from keyboard
|
53 |
|
|
input ps2_data; // data from keyboard
|
54 |
11 |
samiam9512 |
input reset_n;
|
55 |
2 |
samiam9512 |
input clock;
|
56 |
18 |
samiam9512 |
output [7:0] diag; // diagnostic 8 bit port
|
57 |
2 |
samiam9512 |
|
58 |
11 |
samiam9512 |
//
|
59 |
|
|
// Instantiations
|
60 |
|
|
//
|
61 |
|
|
|
62 |
9 |
samiam9512 |
// selector block, we only use select 1, 2 and 3
|
63 |
|
|
select select1(addr, data, readio, writeio, romsel, ramsel, intsel,
|
64 |
18 |
samiam9512 |
trmsel, bootstrap, clock, reset);
|
65 |
2 |
samiam9512 |
|
66 |
11 |
samiam9512 |
// 8080 CPU
|
67 |
2 |
samiam9512 |
cpu8080 cpu(addr, data, readmem, writemem, readio, writeio, intr, inta, waitr,
|
68 |
18 |
samiam9512 |
reset, clock);
|
69 |
11 |
samiam9512 |
|
70 |
|
|
// Program rom
|
71 |
24 |
samiam9512 |
rom rom(addr[10:0], data, romsel&readmem); // unclocked rom
|
72 |
11 |
samiam9512 |
|
73 |
9 |
samiam9512 |
// neg clocked ram
|
74 |
18 |
samiam9512 |
ram ram(addr[9:0], data, ramsel, readmem, writemem, bootstrap, clock);
|
75 |
11 |
samiam9512 |
|
76 |
9 |
samiam9512 |
// neg clocked interrupt controller
|
77 |
|
|
intcontrol intc(addr[2:0], data, writeio, readio, intsel, intr, inta, int0, int1,
|
78 |
18 |
samiam9512 |
int2, int3, int4, int5, int6, int7, reset, clock);
|
79 |
2 |
samiam9512 |
|
80 |
11 |
samiam9512 |
// ADM3A dumb terminal
|
81 |
|
|
terminal adm3a(addr[0], data, writeio, readio, trmsel, r, g, b, hsync_n, vsync_n,
|
82 |
18 |
samiam9512 |
ps2_clk, ps2_data, reset, clock, diag);
|
83 |
11 |
samiam9512 |
|
84 |
|
|
// generate reset
|
85 |
|
|
assign reset = !reset_n;
|
86 |
|
|
|
87 |
18 |
samiam9512 |
// pull up or down unused lines
|
88 |
|
|
assign int0 = 0;
|
89 |
|
|
assign int1 = 0;
|
90 |
|
|
assign int2 = 0;
|
91 |
|
|
assign int3 = 0;
|
92 |
|
|
assign int4 = 0;
|
93 |
|
|
assign int5 = 0;
|
94 |
|
|
assign int6 = 0;
|
95 |
|
|
assign int7 = 0;
|
96 |
|
|
assign waitr = 0;
|
97 |
2 |
samiam9512 |
|
98 |
|
|
endmodule
|
99 |
|
|
|
100 |
|
|
////////////////////////////////////////////////////////////////////////////////
|
101 |
|
|
//
|
102 |
|
|
// Peripheral select unit
|
103 |
|
|
//
|
104 |
|
|
// This block implements a general purpose select generator. It has 4 select
|
105 |
|
|
// units, each capable of matching up to 6 bits of address, or 1kb of address
|
106 |
|
|
// resolution. The length and base address of each generated select can be
|
107 |
|
|
// specified, and each select can be mapped either to memory or I/O. In the case
|
108 |
|
|
// of I/O, the match for the select takes place on the lower 8 bits of the
|
109 |
|
|
// address, corresponding to the 0-255 addresses in the I/O space.
|
110 |
|
|
// Note that the selects must still be qualified with readmem, writemem,
|
111 |
|
|
// readio and writeio signals at the selected peripheral.
|
112 |
|
|
//
|
113 |
|
|
// The selector itself has an I/O address of 0, but this can be moved as well.
|
114 |
|
|
// However, the selector must remain in I/O space.
|
115 |
|
|
//
|
116 |
|
|
// A special "bootstrap" mode is implemented. After power on, and until the
|
117 |
|
|
// selector is configured by the processor, both select1 and select2 will be
|
118 |
|
|
// active, along with the output signal bootstrap. These should be connected as
|
119 |
|
|
// follows:
|
120 |
|
|
//
|
121 |
|
|
// select1: Connect to bootstrap ROM
|
122 |
|
|
// select2: Connect to RAM
|
123 |
|
|
// bootstrap: Connect to RAM output buffers to disable them when true
|
124 |
|
|
//
|
125 |
|
|
// In bootstrap mode, ROM and RAM selects are on until the bootstrap mode is
|
126 |
|
|
// turned off by a CPU I/O operation. The bootstrap signal indicates that
|
127 |
|
|
// bootstrap mode is active, and should be used to disable the RAM output
|
128 |
|
|
// buffers.
|
129 |
|
|
//
|
130 |
|
|
// Because the ROM does not perform writes, and the RAM is disabled from reads,
|
131 |
|
|
// the RAM will overlay the ROM in memory, with the ROM providing read data,
|
132 |
|
|
// and the RAM accepting write data. This is sometimes called "shadow mode".
|
133 |
|
|
// What it does is allow the CPU to copy the ROM to RAM by performing a block
|
134 |
|
|
// read and write to the same address, ie., it picks up the content at each
|
135 |
|
|
// address, then writes it back, effectively copying the ROM contents to the
|
136 |
|
|
// RAM. The CPU can then program the selects, exit bootstrap mode, and then
|
137 |
|
|
// execute entirely from the RAM copy of the bootstrap ROM.
|
138 |
|
|
//
|
139 |
|
|
// Bootstrapping this way accomplishes a few ends. First, because memory
|
140 |
|
|
// is limited on a 64kb machine, it allows RAM to occupy all of memory, without
|
141 |
|
|
// having to reserve a block of space permanently for the boostrap ROM. Second,
|
142 |
|
|
// ROM is usually a lot slower than RAM nowdays, so it is common to want to
|
143 |
|
|
// run from RAM instead of trying to execute directly from ROM.
|
144 |
|
|
//
|
145 |
|
|
// The reason that we gate the RAM output buffers with the bootstrap signal,
|
146 |
|
|
// instead of trying to gate the select signal with readmem, is that the latter
|
147 |
|
|
// would generate glitches, since the readmem signal is enveloped by the
|
148 |
|
|
// address, instead of vice versa. It also gives the RAM logic a chance to cut
|
149 |
|
|
// down on the delay of readmem to output drive enable.
|
150 |
|
|
//
|
151 |
|
|
// The Format of the registers in the select unit are:
|
152 |
|
|
//
|
153 |
|
|
// 7 6 5 4 3 2 1 0
|
154 |
|
|
// 0: C C C C X X X B - Main control register
|
155 |
|
|
// 1: X X X X X X X X - Unused
|
156 |
|
|
// 2: M M M M M M I E - Select 1 mask
|
157 |
|
|
// 3: C C C C C C X X - Select 1 compare
|
158 |
|
|
// 4: M M M M M M I E - Select 2 mask
|
159 |
|
|
// 5: C C C C C C X X - Select 2 compare
|
160 |
|
|
// 6: M M M M M M I E - Select 3 mask
|
161 |
|
|
// 7: C C C C C C X X - Select 3 compare
|
162 |
|
|
// 8: M M M M M M I E - Select 4 mask
|
163 |
9 |
samiam9512 |
// 9: C C C C C C X X - Select 4 compare
|
164 |
2 |
samiam9512 |
//
|
165 |
|
|
// The main control bits 7:4 contain the one of 16 base addresses for the
|
166 |
|
|
// select controller. It occupies 16 locations in the address space, of
|
167 |
|
|
// which only 9 are actually used. The compare bits reset to 0, so that the
|
168 |
|
|
// select unit occupies the I/O addresses $00-$0A on power up. The base address
|
169 |
|
|
// can be changed by writing the main control register, and the new address will
|
170 |
|
|
// take place on the next access. The select unit can only be addressed in the
|
171 |
|
|
// I/O space.
|
172 |
|
|
//
|
173 |
|
|
// The bootstrap bit is reset to 1, and can be written to 0 to turn off
|
174 |
|
|
// bootstrap mode.
|
175 |
|
|
//
|
176 |
|
|
|
177 |
|
|
module select(addr, data, readio, writeio, select1, select2, select3, select4,
|
178 |
|
|
bootstrap, clock, reset);
|
179 |
|
|
|
180 |
|
|
input [15:0] addr; // CPU address
|
181 |
|
|
inout [7:0] data; // CPU data bus
|
182 |
|
|
input readio; // I/O read
|
183 |
|
|
input writeio; // I/O write
|
184 |
|
|
output select1; // select 1
|
185 |
|
|
output select2; // select 1
|
186 |
|
|
output select3; // select 1
|
187 |
|
|
output select4; // select 1
|
188 |
|
|
output bootstrap; // bootstrap status
|
189 |
|
|
input clock; // CPU clock
|
190 |
|
|
input reset; // reset
|
191 |
|
|
reg bootstrap; // bootstrap mode
|
192 |
|
|
|
193 |
|
|
reg [7:4] seladr; // base I/O address of selector
|
194 |
|
|
reg [7:0] datai; // internal data
|
195 |
|
|
|
196 |
|
|
assign selacc = seladr == addr[7:4]; // form selector access
|
197 |
|
|
assign accmain = selacc && (addr[3:1] == 3'b000); // select main
|
198 |
|
|
assign acca = selacc && (addr[3:1] == 3'b001); // select 1
|
199 |
|
|
assign accb = selacc && (addr[3:1] == 3'b010); // select 2
|
200 |
|
|
assign accc = selacc && (addr[3:1] == 3'b011); // select 3
|
201 |
|
|
assign accd = selacc && (addr[3:1] == 3'b100); // select 4
|
202 |
|
|
|
203 |
|
|
// Control access to main select unit address. This has to be clocked to
|
204 |
|
|
// activate the address only after the cycle is over.
|
205 |
|
|
always @(posedge clock)
|
206 |
|
|
if (reset) begin
|
207 |
|
|
|
208 |
|
|
seladr <= 4'b0; // clear master select
|
209 |
|
|
bootstrap <= 1; // enable bootstrap mode
|
210 |
|
|
|
211 |
|
|
end else if (writeio&accmain) begin
|
212 |
|
|
|
213 |
|
|
seladr <= data[7:4]; // write master select
|
214 |
|
|
bootstrap <= data[0]; // write bootstrap mode bit
|
215 |
|
|
|
216 |
|
|
end else if (readio&accmain)
|
217 |
|
|
datai <= {seladr, 4'b0}; // read master select
|
218 |
|
|
|
219 |
|
|
selectone selecta(addr, data, writeio, readio, acca, select1i, reset);
|
220 |
|
|
selectone selectb(addr, data, writeio, readio, accb, select2i, reset);
|
221 |
|
|
selectone selectc(addr, data, writeio, readio, accc, select3, reset);
|
222 |
|
|
selectone selectd(addr, data, writeio, readio, accd, select4, reset);
|
223 |
|
|
|
224 |
|
|
assign data = readio&accmain ? datai: 8'bz; // enable output data
|
225 |
|
|
|
226 |
|
|
assign select1 = select1i | bootstrap; // enable select 1 via bootstrap
|
227 |
|
|
assign select2 = select2i | bootstrap; // enable select 2 via bootstrap
|
228 |
|
|
|
229 |
|
|
endmodule
|
230 |
|
|
|
231 |
|
|
//
|
232 |
|
|
// Individual select cell.
|
233 |
|
|
//
|
234 |
|
|
// This cell contains the mask and compare registers for each address. It
|
235 |
|
|
// handles the write and read of these registers, and forms a select signal
|
236 |
|
|
// based on them.
|
237 |
|
|
//
|
238 |
|
|
// Each register pair has the appearance:
|
239 |
|
|
//
|
240 |
|
|
// 7 6 5 4 3 2 1 0
|
241 |
|
|
// ================
|
242 |
|
|
// 0: M M M M M M I E - Mask register.
|
243 |
|
|
// 1: C C C C C C X X - Compare register.
|
244 |
|
|
//
|
245 |
|
|
// The mask register selects which bits will be used to form the compare
|
246 |
|
|
// value. This can be used to select any size from the combinations:
|
247 |
|
|
//
|
248 |
|
|
// 1 1 1 1 1 1 - Any 1kb block of memory, or 4 I/O address bits.
|
249 |
|
|
// 1 1 1 1 1 0 - Any 2kb block of memory, or 8 I/O address bits.
|
250 |
|
|
// 1 1 1 1 0 0 - Any 4kb block of memory, or 16 I/O address bits.
|
251 |
|
|
// 1 1 1 0 0 0 - Any 8kb block of memory, or 32 I/O address bits.
|
252 |
|
|
// 1 1 0 0 0 0 - Any 16kb block of memory, or 64 I/O address bits.
|
253 |
|
|
// 1 0 0 0 0 0 - Any 32kb block of memory, or 128 I/O address bits.
|
254 |
|
|
// 0 0 0 0 0 0 - All 64kb of memory, or all 256 I/O addresses
|
255 |
|
|
//
|
256 |
|
|
// Each block must be on its size, so for example, a 16kb block can only
|
257 |
|
|
// be on one of 4 positions in memory. If you use a pattern that isn't
|
258 |
|
|
// listed above, you are on your own to figure out the consequences.
|
259 |
|
|
// The selector does not weed out bad combinations, and you can select
|
260 |
|
|
// multiple blocks at once.
|
261 |
|
|
//
|
262 |
|
|
// Each of the mask and compare bytes can be both read and written.
|
263 |
|
|
//
|
264 |
|
|
// Note that the lower bits of the compare register aren't used, and always
|
265 |
|
|
// return zero.
|
266 |
|
|
//
|
267 |
|
|
// On reset, the mask and compare registers are both set to zero, which leaves
|
268 |
|
|
// the select block disabled.
|
269 |
|
|
//
|
270 |
|
|
|
271 |
|
|
module selectone(addr, data, write, read, selectin, selectout, reset);
|
272 |
|
|
|
273 |
|
|
input [15:0] addr; // address to match, 6 bits
|
274 |
|
|
inout [7:0] data; // CPU data
|
275 |
|
|
input write; // CPU write
|
276 |
|
|
input read; // CPU read
|
277 |
|
|
input selectin; // select for read/write
|
278 |
|
|
output selectout; // resulting select
|
279 |
|
|
input reset; // reset
|
280 |
|
|
|
281 |
|
|
reg [7:0] mask; // mask/control, 7:2 is mask, 1: I/O or /mem, 0: on/off
|
282 |
|
|
reg [7:2] comp; // Compare value
|
283 |
|
|
wire [5:0] iaddr; // multiplexed address
|
284 |
|
|
reg [7:0] datai; // data from output selector
|
285 |
|
|
|
286 |
|
|
// select what part of address, upper or lower byte, we compare, based on
|
287 |
|
|
// I/O or memory address
|
288 |
|
|
assign iaddr = mask[1] ? addr[7:2]: addr[15:10];
|
289 |
|
|
|
290 |
|
|
// Form select based on match
|
291 |
|
|
assign selectout = ((iaddr & mask[7:2]) == comp) & mask[0];
|
292 |
|
|
|
293 |
9 |
samiam9512 |
always @(addr, write, read, reset, selectin, data, comp, mask)
|
294 |
2 |
samiam9512 |
if (reset) begin
|
295 |
|
|
|
296 |
|
|
comp <= 6'b0; // clear registers
|
297 |
|
|
mask <= 8'b0;
|
298 |
|
|
|
299 |
|
|
end else if (write&selectin) begin
|
300 |
|
|
|
301 |
|
|
if (addr[0]) comp <= data[7:2]; // write comparitor data
|
302 |
|
|
else mask <= data; // write mask data
|
303 |
|
|
|
304 |
|
|
end else begin
|
305 |
|
|
|
306 |
|
|
if (addr[0]) datai <= {comp, 2'b0}; // read comparitor data
|
307 |
|
|
else datai <= mask; // read mask data
|
308 |
|
|
|
309 |
|
|
end
|
310 |
|
|
|
311 |
|
|
assign data = read&selectin ? datai: 8'bz; // enable output data
|
312 |
|
|
|
313 |
|
|
endmodule
|
314 |
|
|
|
315 |
9 |
samiam9512 |
////////////////////////////////////////////////////////////////////////////////
|
316 |
|
|
//
|
317 |
|
|
// INTERRUPT CONTROLLER
|
318 |
|
|
//
|
319 |
|
|
// Implements an 8 input interrupt controller. Each of the 8 interrupt lines has
|
320 |
|
|
// selectable positive edge, negative edge, positive level, and negative level
|
321 |
|
|
// triggering. Interrupts can be masked, and can be examined for state even when
|
322 |
|
|
// they are masked. Each interrupt can be triggered under software control.
|
323 |
|
|
// The priority for interrupts is fixed, with 0 being the highest, and 7 being
|
324 |
|
|
// the lowest.
|
325 |
|
|
//
|
326 |
|
|
// The controller can be connected to I/O or memory addresses. The control
|
327 |
|
|
// registers appear as:
|
328 |
|
|
//
|
329 |
|
|
// 7 6 5 4 3 2 1 0
|
330 |
|
|
// 00: M M M M M M M M - Mask register
|
331 |
|
|
// 01: S S S S S S S S - Status register
|
332 |
|
|
// 02: A A A A A A A A - Active register
|
333 |
|
|
// 03: P P P P P P P P - Polarity register
|
334 |
|
|
// 04: E E E E E E E E - Edge enable register
|
335 |
|
|
// 05: B B B B B B B B - Vector base address
|
336 |
|
|
//
|
337 |
|
|
// The mask register indicates if the interrupt source is to generate an
|
338 |
|
|
// interrupt. If the associated bit is 1, the interrupt is enabled, otherwise
|
339 |
|
|
// disabled.
|
340 |
|
|
//
|
341 |
|
|
// The status register indicates the current interrupt line status, for direct
|
342 |
|
|
// polling purposes.
|
343 |
|
|
//
|
344 |
|
|
// The active register is a flip/flop that goes to 1 anytime the trigger
|
345 |
|
|
// condition is satisfied. A 1 in this register will cause an interrupt to
|
346 |
|
|
// occur. If the mask for the interrupt is not enabled, the active bit will not
|
347 |
|
|
// be set no matter what the trigger states.
|
348 |
|
|
//
|
349 |
|
|
// The polarity register gives the line polarity that will trigger an interrupt.
|
350 |
|
|
// If the edge trigger bit is set, then the polarity indicates the resulting
|
351 |
|
|
// line AFTER the trigger. For example, an edge trigger with a 1 in the polarity
|
352 |
|
|
// register indicates that the trigger is a positive edge trigger.
|
353 |
|
|
//
|
354 |
|
|
// The edge enable register places an edge detector on the line. This will
|
355 |
|
|
// cause the interrupt to be triggered when an appropriate edge indicated by the
|
356 |
|
|
// polarity occurs. The edge mode is selected by a 1 bit, and the level mode is
|
357 |
|
|
// selected by a 0 bit. If the level mode is selected, the interrupt will occur
|
358 |
|
|
// anytime the interrupt line matches the state of the polarity bit.
|
359 |
|
|
//
|
360 |
|
|
// The vector registers each provide the lower 8 bits of a 16 bit vector for
|
361 |
|
|
// each interrupt.
|
362 |
|
|
//
|
363 |
|
|
// The base register provides the upper 8 bits of a 16 bit vector for each
|
364 |
|
|
// interrupt.
|
365 |
|
|
//
|
366 |
|
|
// An interrupt is generated anytime any bit is true in the active register.
|
367 |
|
|
// The interrupt request line is set true, and the controller will hold until
|
368 |
|
|
// an interrupt acknowledge occurs. When an interrupt acknowledge occurs, the
|
369 |
|
|
// controller will cycle through a three step sequence, with each sequence
|
370 |
|
|
// activated by the interrupt acknowledge signal.
|
371 |
|
|
//
|
372 |
|
|
// First, a $cd is placed on the data lines, indicating a call instruction.
|
373 |
|
|
// Second, the number of the interrupt that is highest priority is multipled
|
374 |
|
|
// * 4, and this is placed on the data lines.
|
375 |
|
|
// Third, the vector base address is placed on the data lines.
|
376 |
|
|
//
|
377 |
|
|
// The net result is that the CPU is vectored to one of 256 pages in the address
|
378 |
|
|
// space, with an offset of 4 bytes for each interrupt, as follows:
|
379 |
|
|
//
|
380 |
|
|
// 00: Vector 0
|
381 |
|
|
// 04: Vector 1
|
382 |
|
|
// 08: Vector 2
|
383 |
|
|
// 0C: Vector 3
|
384 |
|
|
// 10: Vector 4
|
385 |
|
|
// 14: Vector 5
|
386 |
|
|
// 18: Vector 6
|
387 |
|
|
// 1C: Vector 7
|
388 |
|
|
//
|
389 |
|
|
|
390 |
|
|
module intcontrol(addr, data, write, read, select, intr, inta, int0, int1, int2,
|
391 |
|
|
int3, int4, int5, int6, int7, reset, clock);
|
392 |
|
|
|
393 |
|
|
input [2:0] addr; // control register address
|
394 |
|
|
inout [7:0] data; // CPU data
|
395 |
|
|
input write; // CPU write
|
396 |
|
|
input read; // CPU read
|
397 |
|
|
input select; // controller select
|
398 |
|
|
output intr; // interrupt request
|
399 |
|
|
input inta; // interrupt acknowledge
|
400 |
|
|
input int0; // interrupt line 0
|
401 |
|
|
input int1; // interrupt line 1
|
402 |
|
|
input int2; // interrupt line 2
|
403 |
|
|
input int3; // interrupt line 3
|
404 |
|
|
input int4; // interrupt line 4
|
405 |
|
|
input int5; // interrupt line 5
|
406 |
|
|
input int6; // interrupt line 6
|
407 |
|
|
input int7; // interrupt line 7
|
408 |
|
|
input reset; // CPU reset
|
409 |
|
|
input clock; // CPU clock
|
410 |
|
|
|
411 |
|
|
reg [7:0] mask; // interrupt mask register
|
412 |
|
|
reg [7:0] active; // interrupt active register
|
413 |
|
|
reg [7:0] polarity; // interrupt polarity register
|
414 |
|
|
reg [7:0] edges; // interrupt edge control
|
415 |
|
|
reg [7:0] vbase; // vector base
|
416 |
|
|
reg [7:0] intpe; // positive edge interrupt detection
|
417 |
|
|
reg [7:0] intne; // negative edge interrupt detection
|
418 |
|
|
reg [7:0] datai; // data from output selector
|
419 |
|
|
reg [3:0] state; // state machine to run vectors
|
420 |
11 |
samiam9512 |
|
421 |
9 |
samiam9512 |
wire [7:0] activep; // interrupt active pending
|
422 |
|
|
|
423 |
11 |
samiam9512 |
// handle register reads and writes
|
424 |
9 |
samiam9512 |
|
425 |
|
|
always @(negedge clock)
|
426 |
|
|
if (reset) begin // reset
|
427 |
|
|
|
428 |
|
|
mask <= 8'b0; // clear mask
|
429 |
|
|
active <= 8'b0; // clear active
|
430 |
|
|
polarity <= 8'b0; // clear polarity
|
431 |
|
|
edges <= 8'b0; // clear edge
|
432 |
|
|
vbase <= 8'b0; // clear base
|
433 |
|
|
state <= 4'b0; // clear state machine
|
434 |
|
|
|
435 |
|
|
end else if (write&select) begin // CPU write
|
436 |
|
|
|
437 |
|
|
case (addr)
|
438 |
|
|
|
439 |
|
|
0: mask <= data; // set mask register
|
440 |
|
|
2: active <= data|activep; // set active register
|
441 |
|
|
3: polarity <= data; // set polarity register
|
442 |
|
|
4: edges <= data; // set edge register
|
443 |
|
|
5: vbase <= data; // set base register
|
444 |
|
|
|
445 |
|
|
endcase
|
446 |
|
|
|
447 |
|
|
end else if (read&select) begin // CPU read
|
448 |
|
|
|
449 |
|
|
case (addr)
|
450 |
|
|
|
451 |
|
|
0: datai <= mask; // get mask register
|
452 |
|
|
// get current line statuses
|
453 |
|
|
1: datai <= { int7, int6, int5, int4, int3, int2, int1, int0 };
|
454 |
|
|
2: datai <= active; // get active register
|
455 |
|
|
3: datai <= polarity; // get polarity register
|
456 |
|
|
4: datai <= edges; // get edge register
|
457 |
|
|
5: datai <= vbase; // get base register
|
458 |
|
|
|
459 |
|
|
endcase
|
460 |
|
|
|
461 |
|
|
end else if (inta) begin // CPU interrupt acknowledge
|
462 |
|
|
|
463 |
|
|
// run vectoring state machine
|
464 |
|
|
case (state)
|
465 |
|
|
|
466 |
|
|
// wait for inta, and assert 1st instruction byte
|
467 |
|
|
|
468 |
|
|
0: begin
|
469 |
|
|
|
470 |
|
|
datai <= 8'hcd; // place call instruction on datalines
|
471 |
|
|
state <= 1; // advance to low address
|
472 |
|
|
|
473 |
|
|
end
|
474 |
|
|
|
475 |
|
|
// assert low byte address
|
476 |
|
|
1: begin
|
477 |
|
|
|
478 |
|
|
// decode priority
|
479 |
|
|
if (active&8'h01) datai <= 8'h00;
|
480 |
|
|
else if (active&8'h02) datai <= 8'h04;
|
481 |
|
|
else if (active&8'h04) datai <= 8'h08;
|
482 |
|
|
else if (active&8'h08) datai <= 8'h0C;
|
483 |
|
|
else if (active&8'h10) datai <= 8'h10;
|
484 |
|
|
else if (active&8'h20) datai <= 8'h14;
|
485 |
|
|
else if (active&8'h40) datai <= 8'h18;
|
486 |
|
|
else if (active&8'h80) datai <= 8'h1C;
|
487 |
|
|
state <= 2; // advance to high address
|
488 |
|
|
|
489 |
|
|
end
|
490 |
|
|
|
491 |
|
|
// assert high address
|
492 |
|
|
2: if (inta) begin
|
493 |
|
|
|
494 |
|
|
datai <= vbase; // place page to vector
|
495 |
|
|
// reset highest priority interrupt
|
496 |
|
|
if (active&8'h01) active[0] <= activep[0];
|
497 |
|
|
else if (active&8'h02) active[1] <= activep[1];
|
498 |
|
|
else if (active&8'h04) active[2] <= activep[2];
|
499 |
|
|
else if (active&8'h08) active[3] <= activep[3];
|
500 |
|
|
else if (active&8'h10) active[4] <= activep[4];
|
501 |
|
|
else if (active&8'h20) active[5] <= activep[5];
|
502 |
|
|
else if (active&8'h40) active[6] <= activep[6];
|
503 |
|
|
else if (active&8'h80) active[7] <= activep[7];
|
504 |
|
|
state <= 0; // back to start state
|
505 |
|
|
|
506 |
|
|
end
|
507 |
|
|
|
508 |
|
|
endcase
|
509 |
|
|
|
510 |
|
|
end else active <= active|activep; // set active interrupts
|
511 |
|
|
|
512 |
|
|
// form active interrupt bits
|
513 |
|
|
assign activep = mask & (({ int7, int6, int5, int4, // levels
|
514 |
|
|
int3, int2, int1, int0 }^polarity & ~edges)|
|
515 |
|
|
(intpe&polarity&edges)| // positive edges
|
516 |
|
|
(intne&~polarity&edges)); // negative edges
|
517 |
|
|
|
518 |
|
|
// form interrupt edges
|
519 |
|
|
always @(posedge int0) intpe[0] <= 1;
|
520 |
|
|
always @(posedge int1) intpe[1] <= 1;
|
521 |
|
|
always @(posedge int2) intpe[2] <= 1;
|
522 |
|
|
always @(posedge int3) intpe[3] <= 1;
|
523 |
|
|
always @(posedge int4) intpe[4] <= 1;
|
524 |
|
|
always @(posedge int5) intpe[5] <= 1;
|
525 |
|
|
always @(posedge int6) intpe[6] <= 1;
|
526 |
|
|
always @(posedge int7) intpe[7] <= 1;
|
527 |
|
|
always @(negedge int0) intne[0] <= 1;
|
528 |
|
|
always @(negedge int1) intne[1] <= 1;
|
529 |
|
|
always @(negedge int2) intne[2] <= 1;
|
530 |
|
|
always @(negedge int3) intne[3] <= 1;
|
531 |
|
|
always @(negedge int4) intne[4] <= 1;
|
532 |
|
|
always @(negedge int5) intne[5] <= 1;
|
533 |
|
|
always @(negedge int6) intne[6] <= 1;
|
534 |
|
|
always @(negedge int7) intne[7] <= 1;
|
535 |
|
|
|
536 |
|
|
assign data = read&select|inta ? datai: 8'bz; // enable output data
|
537 |
|
|
assign intr = |active; // request interrupt on any active
|
538 |
|
|
|
539 |
|
|
endmodule
|
540 |
11 |
samiam9512 |
|
541 |
9 |
samiam9512 |
////////////////////////////////////////////////////////////////////////////////
|
542 |
|
|
//
|
543 |
|
|
// ROM CELL
|
544 |
|
|
//
|
545 |
|
|
// Hold the test instructions. Forms a simple read only cell, with tri-state
|
546 |
|
|
// enable outputs only.
|
547 |
|
|
//
|
548 |
|
|
|
549 |
2 |
samiam9512 |
module rom(addr, data, dataeno);
|
550 |
|
|
|
551 |
24 |
samiam9512 |
input [10:0] addr;
|
552 |
2 |
samiam9512 |
inout [7:0] data;
|
553 |
|
|
input dataeno;
|
554 |
|
|
|
555 |
|
|
reg [7:0] datao;
|
556 |
24 |
samiam9512 |
|
557 |
2 |
samiam9512 |
always @(addr) case (addr)
|
558 |
|
|
|
559 |
18 |
samiam9512 |
`include "test.rom" // get contents of memory
|
560 |
2 |
samiam9512 |
|
561 |
|
|
default datao = 8'h76; // hlt
|
562 |
|
|
|
563 |
|
|
endcase
|
564 |
|
|
|
565 |
|
|
// Enable drive for data output
|
566 |
|
|
assign data = dataeno ? datao: 8'bz;
|
567 |
|
|
|
568 |
|
|
endmodule
|
569 |
|
|
|
570 |
9 |
samiam9512 |
////////////////////////////////////////////////////////////////////////////////
|
571 |
|
|
//
|
572 |
|
|
// RAM CELL
|
573 |
|
|
//
|
574 |
|
|
// A clocked ram cell with individual select, read and write signals. Data is
|
575 |
|
|
// written on the positive edge when write is true. Data is enabled for output
|
576 |
|
|
// by the read signal asyncronously.
|
577 |
|
|
//
|
578 |
|
|
// A bootstrap mode is implemented that, when true, overrides the read signal
|
579 |
|
|
// and keeps the output drivers off.
|
580 |
|
|
//
|
581 |
|
|
|
582 |
2 |
samiam9512 |
module ram(addr, data, select, read, write, bootstrap, clock);
|
583 |
|
|
|
584 |
|
|
input [9:0] addr;
|
585 |
|
|
inout [7:0] data;
|
586 |
|
|
input select;
|
587 |
|
|
input read;
|
588 |
|
|
input write;
|
589 |
|
|
input clock;
|
590 |
|
|
input bootstrap;
|
591 |
|
|
|
592 |
|
|
reg [7:0] ramcore [1023:0]; // The ram store
|
593 |
|
|
reg [7:0] datao;
|
594 |
|
|
|
595 |
9 |
samiam9512 |
always @(negedge clock)
|
596 |
2 |
samiam9512 |
if (select) begin
|
597 |
|
|
|
598 |
|
|
if (write) ramcore[addr] <= data;
|
599 |
|
|
datao <= ramcore[addr];
|
600 |
|
|
|
601 |
|
|
end
|
602 |
|
|
|
603 |
|
|
// Enable drive for data output
|
604 |
|
|
assign data = (select&read&~bootstrap) ? datao: 8'bz;
|
605 |
|
|
|
606 |
|
|
endmodule
|