Repository navigation
Expand file tree
/
Copy pathprocessor.sv
More file actions
234 lines (199 loc) · 5.46 KB
/
Copy pathprocessor.sv
File metadata and controls
234 lines (199 loc) · 5.46 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
// needed for compatibility with IP
`timescale 1 ps / 1 ps
module processor #(
parameter INPUTS = 1,
parameter OUTPUTS = 1,
parameter CACHE_SIZE = 32
) (
input logic clk, reset,
input logic [0:INPUTS - 1] inputs, // reverse-indexed
output logic [0:OUTPUTS - 1] outputs // reverse-indexed
);
// writing state, used to steal RAM port from dst half
logic write;
logic [14:0] writeAddress;
logic [15:0] writeData;
// zero cache
logic [15:0] zero, zeroInc, nextZero;
// (read-only) memory ports for dst and src half
rom_port dstROMPort (clk);
rom_port srcROMPort (clk);
rom_port dstRAMPort (clk);
rom_port srcRAMPort (clk);
// memory modules
rom romInstance (
.clock(clk),
.address_a(dstROMPort.address),
.address_b(srcROMPort.address),
.q_a(dstROMPort.data),
.q_b(srcROMPort.data)
);
ram ramInstance (
.clock(clk),
.address_a(write ? writeAddress : dstRAMPort.address),
.address_b(srcRAMPort.address),
.q_a(dstRAMPort.data),
.q_b(srcRAMPort.data),
.data_a(writeData),
.data_b(16'bX),
.wren_a(write),
.wren_b(1'b0)
);
// RAM cache interfaces
cache_read_port #(.ADDR_WIDTH(15), .DATA_WIDTH(16)) dstCacheReadPort ();
cache_read_port #(.ADDR_WIDTH(15), .DATA_WIDTH(16)) srcCacheReadPort ();
cache_write_port #(.ADDR_WIDTH(15), .DATA_WIDTH(16)) cacheWritePort ();
cache #(.ENTRIES(CACHE_SIZE)) dstCache (
.reset,
.ramPort(dstRAMPort.CLIENT),
.reader(dstCacheReadPort.CACHE),
.writer(cacheWritePort.CACHE)
);
cache #(.ENTRIES(CACHE_SIZE)) srcCache (
.reset,
.ramPort(srcRAMPort.CLIENT),
.reader(srcCacheReadPort.CACHE),
.writer(cacheWritePort.CACHE)
);
assign cacheWritePort.write = write;
assign cacheWritePort.address = writeAddress;
assign cacheWritePort.data = writeData;
// half_processors
half_processor_in_port #(.INPUTS(INPUTS)) half_inputs (clk);
half_processor_out_port dst ();
half_processor_out_port src ();
// offsets come from assembly format
half_processor #(.OFFSET(1)) dstInstance (
.romPort(dstROMPort.CLIENT),
.ram(dstCacheReadPort.CLIENT),
.from_cpu(half_inputs.HALF),
.to_cpu(dst.HALF)
);
half_processor #(.OFFSET(3)) srcInstance (
.romPort(srcROMPort.CLIENT),
.ram(srcCacheReadPort.CLIENT),
.from_cpu(half_inputs.HALF),
.to_cpu(src.HALF)
);
// signal to let halves continue
logic proceed;
// are both halves ready?
logic ready;
// are both halves done?
logic done;
// are both halves jumping?
logic jumping;
// connect inputs
assign half_inputs.reset = reset;
assign half_inputs.proceed = proceed;
assign half_inputs.inputs = inputs;
assign half_inputs.zero = zero;
assign half_inputs.zeroInc = zeroInc;
assign half_inputs.jumpProceed = jumping;
// derive composite facts from both halves
assign ready = src.ready & dst.ready;
assign done = src.done | dst.done;
assign jumping = src.jumping & dst.jumping;
assign zeroInc = zero + 16'b1;
// output state
logic [0:OUTPUTS - 1] nextOutputs;
logic [15:0] outputAddress;
// state machine
enum logic [1:0] {
RESET, // state to wait in for a cycle while halves reset
RUN // the program is running one instruction
} ps, ns;
always_comb begin
write = 1'b0;
writeAddress = 15'bX;
writeData = 16'bX;
proceed = 1'b0;
nextOutputs = outputs;
outputAddress = 16'bX;
nextZero = zero;
if (~ready | done) begin
ns = ps;
nextZero = jumping ? zeroInc : zero;
end else case (ps)
RESET: ns = RUN;
RUN: begin
ns = RUN;
proceed = 1'b1;
if (dst.preAccumulator[15]) begin // negative register (output)
outputAddress = -(dst.preAccumulator + 16'b1 + INPUTS[15:0]);
nextOutputs[outputAddress] = src.accumulator[0];
end else if (dst.preAccumulator == 16'b0) begin
nextZero = zero + src.accumulator;
end else begin
write = 1'b1;
writeData = dst.accumulator + src.accumulator;
writeAddress = dst.preAccumulator[14:0];
end
end
endcase
end
always_ff @(posedge clk)
if (reset) begin
ps <= RESET;
outputs <= {OUTPUTS{1'b0}};
zero <= -16'b1;
end else begin
ps <= ns;
outputs <= nextOutputs;
zero <= nextZero;
end
endmodule
module processor_tb();
// this test bench looks like nothing! this is because it's reading from ROM
// please use processor_tb_rom.mif as rom.mif to get the full experience
logic clk, reset;
logic [0:1587] out;
processor #(.INPUTS(1), .OUTPUTS(1588), .CACHE_SIZE(32)) dut(
.clk, .reset,
.inputs(1'b0),
.outputs(out)
);
initial clk = 0;
initial forever #1 clk = ~clk;
// print all writes
logic ready;
assign ready = (dut.ready & ~dut.done & dut.proceed) | dut.jumping;
logic [15:0] dstAddr, dst, src;
assign dstAddr = dut.dst.preAccumulator;
assign dst = dut.dst.accumulator;
assign src = dut.src.accumulator;
int fd;
initial begin
fd = $fopen("processor_transcript.txt", "w");
while (1'b1) begin
if (dut.done) begin
$fdisplay(fd, "DONE");
$fclose(fd);
break;
end
if (~ready) begin
@(posedge ready);
end
@(negedge clk);
if (ready) begin
if (dut.jumping) begin
$fdisplay(fd, "BREAK\n");
end else if (dut.write) begin
$fdisplay(fd, "SET *%0d = %0d", $signed(dut.writeAddress), $signed(dut.writeData));
end else if (dut.outputAddress) begin
$fdisplay(fd, "OUTPUT *%0d = %0d", $signed(dstAddr), $signed(src));
end else begin
$fdisplay(fd, "ZERO = %0d", $signed(src + dst));
end
end
@(posedge clk);
end
end
initial begin
reset = 1;
@(posedge clk) reset = 0;
// repeat (4500) @(posedge clk);
repeat (4500) @(posedge clk);
$stop();
end
endmodule