1 |
12 |
alfik |
/*
|
2 |
|
|
* Copyright 2010, Aleksander Osman, alfik@poczta.fm. All rights reserved.
|
3 |
|
|
*
|
4 |
|
|
* Redistribution and use in source and binary forms, with or without modification, are
|
5 |
|
|
* permitted provided that the following conditions are met:
|
6 |
|
|
*
|
7 |
|
|
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
8 |
|
|
* conditions and the following disclaimer.
|
9 |
|
|
*
|
10 |
|
|
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
11 |
|
|
* of conditions and the following disclaimer in the documentation and/or other materials
|
12 |
|
|
* provided with the distribution.
|
13 |
|
|
*
|
14 |
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
15 |
|
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
16 |
|
|
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR
|
17 |
|
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
18 |
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
19 |
|
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
20 |
|
|
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
21 |
|
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
22 |
|
|
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
23 |
|
|
*/
|
24 |
|
|
|
25 |
|
|
`timescale 10ns / 1ns
|
26 |
|
|
|
27 |
|
|
`define MICROPC_MAIN_LOOP 9'd53
|
28 |
|
|
|
29 |
|
|
module tb_ao68000();
|
30 |
|
|
|
31 |
|
|
// inputs
|
32 |
|
|
reg clk;
|
33 |
|
|
reg rst_n;
|
34 |
|
|
reg [31:0] data_in;
|
35 |
|
|
reg ack;
|
36 |
|
|
wire err;
|
37 |
|
|
wire rty;
|
38 |
|
|
wire [2:0] ipl;
|
39 |
|
|
|
40 |
|
|
// outputs
|
41 |
|
|
wire cyc;
|
42 |
|
|
wire [31:2] addr;
|
43 |
|
|
wire [31:0] data_out;
|
44 |
|
|
wire [3:0] sel;
|
45 |
|
|
wire stb;
|
46 |
|
|
wire we;
|
47 |
|
|
wire sgl;
|
48 |
|
|
wire blk;
|
49 |
|
|
wire rmw;
|
50 |
|
|
wire [2:0] cti;
|
51 |
|
|
wire [1:0] bte;
|
52 |
|
|
wire [2:0] fc;
|
53 |
|
|
wire reset_output;
|
54 |
|
|
wire blocked_output;
|
55 |
|
|
|
56 |
|
|
ao68000 ao68000_m(
|
57 |
|
|
.CLK_I(clk),
|
58 |
|
|
.reset_n(rst_n),
|
59 |
|
|
|
60 |
|
|
.DAT_I(data_in),
|
61 |
|
|
.ACK_I(ack),
|
62 |
|
|
.ERR_I(err),
|
63 |
|
|
.RTY_I(rty),
|
64 |
|
|
|
65 |
|
|
|
66 |
|
|
.CYC_O(cyc),
|
67 |
|
|
.ADR_O(addr),
|
68 |
|
|
.DAT_O(data_out),
|
69 |
|
|
.SEL_O(sel),
|
70 |
|
|
.STB_O(stb),
|
71 |
|
|
.WE_O(we),
|
72 |
|
|
|
73 |
|
|
.SGL_O(sgl),
|
74 |
|
|
.BLK_O(blk),
|
75 |
|
|
.RMW_O(rmw),
|
76 |
|
|
.CTI_O(cti),
|
77 |
|
|
.BTE_O(bte),
|
78 |
|
|
|
79 |
|
|
.fc_o(fc),
|
80 |
|
|
|
81 |
|
|
.ipl_i(ipl),
|
82 |
|
|
.reset_o(reset_output),
|
83 |
|
|
.blocked_o(blocked_output)
|
84 |
|
|
);
|
85 |
|
|
|
86 |
|
|
initial begin
|
87 |
|
|
clk = 1'b0;
|
88 |
|
|
forever #5 clk = ~clk;
|
89 |
|
|
end
|
90 |
|
|
|
91 |
|
|
reg [87:0] string;
|
92 |
|
|
reg [31:0] write_data_selected;
|
93 |
|
|
|
94 |
|
|
always @(posedge clk) begin
|
95 |
|
|
if(stb == 1'b1 && we == 1'b0 && addr == 30'd0 && ao68000_m.microcode_branch_m.micro_pc_0 == 9'd1) begin
|
96 |
|
|
#5
|
97 |
|
|
data_in = get_argument("SSP");
|
98 |
|
|
ack = 1'b1;
|
99 |
|
|
#10
|
100 |
|
|
data_in = 32'd0;
|
101 |
|
|
ack = 1'b0;
|
102 |
|
|
end
|
103 |
|
|
else if(stb == 1'b1 && we == 1'b0 && addr == 30'd1 && ao68000_m.microcode_branch_m.micro_pc_0 == 9'd1) begin
|
104 |
|
|
#5
|
105 |
|
|
data_in = get_argument("PC");
|
106 |
|
|
ack = 1'b1;
|
107 |
|
|
#10
|
108 |
|
|
data_in = 32'd0;
|
109 |
|
|
ack = 1'b0;
|
110 |
|
|
end
|
111 |
|
|
|
112 |
|
|
else if(stb == 1'b1 && we == 1'b0) begin
|
113 |
|
|
$display("memory read: address=%h, select=%h", addr, sel);
|
114 |
|
|
|
115 |
|
|
$sformat(string, "MEM%h", addr);
|
116 |
|
|
|
117 |
|
|
#5
|
118 |
|
|
data_in = get_argument(string);
|
119 |
|
|
ack = 1'b1;
|
120 |
|
|
#10
|
121 |
|
|
data_in = 32'd0;
|
122 |
|
|
ack = 1'b0;
|
123 |
|
|
end
|
124 |
|
|
|
125 |
|
|
else if(stb == 1'b1 && we == 1'b1) begin
|
126 |
|
|
if(sel == 4'd0) write_data_selected = 32'd0;
|
127 |
|
|
else if(sel == 4'd1) write_data_selected = { 24'd0, data_out[7:0] };
|
128 |
|
|
else if(sel == 4'd2) write_data_selected = { 16'd0, data_out[15:8], 8'd0 };
|
129 |
|
|
else if(sel == 4'd3) write_data_selected = { 16'd0, data_out[15:0] };
|
130 |
|
|
else if(sel == 4'd4) write_data_selected = { 8'd0, data_out[23:16], 16'd0 };
|
131 |
|
|
else if(sel == 4'd5) write_data_selected = { 8'd0, data_out[23:16], 8'd0, data_out[7:0] };
|
132 |
|
|
else if(sel == 4'd6) write_data_selected = { 8'd0, data_out[23:8], 8'd0 };
|
133 |
|
|
else if(sel == 4'd7) write_data_selected = { 8'd0, data_out[23:0] };
|
134 |
|
|
else if(sel == 4'd8) write_data_selected = { data_out[31:24], 24'd0 };
|
135 |
|
|
else if(sel == 4'd9) write_data_selected = { data_out[31:24], 16'd0, data_out[7:0] };
|
136 |
|
|
else if(sel == 4'd10) write_data_selected = { data_out[31:24], 8'd0, data_out[15:8], 8'd0 };
|
137 |
|
|
else if(sel == 4'd11) write_data_selected = { data_out[31:24], 8'd0, data_out[15:0] };
|
138 |
|
|
else if(sel == 4'd12) write_data_selected = { data_out[31:16], 16'd0 };
|
139 |
|
|
else if(sel == 4'd13) write_data_selected = { data_out[31:16], 8'd0, data_out[7:0] };
|
140 |
|
|
else if(sel == 4'd14) write_data_selected = { data_out[31:8], 8'd0 };
|
141 |
|
|
else if(sel == 4'd15) write_data_selected = data_out[31:0];
|
142 |
|
|
|
143 |
|
|
$display("memory write address=%h, select=%h: value=%h", addr, sel, write_data_selected);
|
144 |
|
|
|
145 |
|
|
#5
|
146 |
|
|
ack = 1'b1;
|
147 |
|
|
#10
|
148 |
|
|
ack = 1'b0;
|
149 |
|
|
end
|
150 |
|
|
|
151 |
|
|
end
|
152 |
|
|
|
153 |
|
|
function [31:0] get_argument(input [87:0] name);
|
154 |
|
|
reg [31:0] result;
|
155 |
|
|
begin
|
156 |
|
|
if( $value$plusargs({name, "=%h"}, result) == 0 ) begin
|
157 |
|
|
$display("Missing argument: %s", name);
|
158 |
|
|
$finish_and_return(-1);
|
159 |
|
|
end
|
160 |
|
|
get_argument = result;
|
161 |
|
|
end
|
162 |
|
|
endfunction
|
163 |
|
|
|
164 |
|
|
task load_state;
|
165 |
|
|
begin
|
166 |
|
|
ao68000_m.memory_registers_m.an_ram_inst.mem_data[0] = get_argument("A0");
|
167 |
|
|
ao68000_m.memory_registers_m.an_ram_inst.mem_data[1] = get_argument("A1");
|
168 |
|
|
ao68000_m.memory_registers_m.an_ram_inst.mem_data[2] = get_argument("A2");
|
169 |
|
|
ao68000_m.memory_registers_m.an_ram_inst.mem_data[3] = get_argument("A3");
|
170 |
|
|
ao68000_m.memory_registers_m.an_ram_inst.mem_data[4] = get_argument("A4");
|
171 |
|
|
ao68000_m.memory_registers_m.an_ram_inst.mem_data[5] = get_argument("A5");
|
172 |
|
|
ao68000_m.memory_registers_m.an_ram_inst.mem_data[6] = get_argument("A6");
|
173 |
|
|
ao68000_m.memory_registers_m.an_ram_inst.mem_data[7] = get_argument("SSP");
|
174 |
|
|
ao68000_m.memory_registers_m.usp = get_argument("USP");
|
175 |
|
|
|
176 |
|
|
ao68000_m.memory_registers_m.dn_ram_inst.mem_data[0] = get_argument("D0");
|
177 |
|
|
ao68000_m.memory_registers_m.dn_ram_inst.mem_data[1] = get_argument("D1");
|
178 |
|
|
ao68000_m.memory_registers_m.dn_ram_inst.mem_data[2] = get_argument("D2");
|
179 |
|
|
ao68000_m.memory_registers_m.dn_ram_inst.mem_data[3] = get_argument("D3");
|
180 |
|
|
ao68000_m.memory_registers_m.dn_ram_inst.mem_data[4] = get_argument("D4");
|
181 |
|
|
ao68000_m.memory_registers_m.dn_ram_inst.mem_data[5] = get_argument("D5");
|
182 |
|
|
ao68000_m.memory_registers_m.dn_ram_inst.mem_data[6] = get_argument("D6");
|
183 |
|
|
ao68000_m.memory_registers_m.dn_ram_inst.mem_data[7] = get_argument("D7");
|
184 |
|
|
|
185 |
|
|
ao68000_m.registers_m.pc = get_argument("PC");
|
186 |
|
|
|
187 |
|
|
ao68000_m.alu_m.sr = 16'd0;
|
188 |
|
|
ao68000_m.alu_m.sr[0] = get_argument("C");
|
189 |
|
|
ao68000_m.alu_m.sr[1] = get_argument("V");
|
190 |
|
|
ao68000_m.alu_m.sr[2] = get_argument("Z");
|
191 |
|
|
ao68000_m.alu_m.sr[3] = get_argument("N");
|
192 |
|
|
ao68000_m.alu_m.sr[4] = get_argument("X");
|
193 |
|
|
ao68000_m.alu_m.sr[10:8] = get_argument("IPM");
|
194 |
|
|
ao68000_m.alu_m.sr[13] = get_argument("S");
|
195 |
|
|
ao68000_m.alu_m.sr[15] = get_argument("T");
|
196 |
|
|
end
|
197 |
|
|
endtask
|
198 |
|
|
|
199 |
|
|
task dump_state;
|
200 |
|
|
begin
|
201 |
|
|
$write("A0: %h\n", ao68000_m.memory_registers_m.an_ram_inst.mem_data[0]);
|
202 |
|
|
$write("A1: %h\n", ao68000_m.memory_registers_m.an_ram_inst.mem_data[1]);
|
203 |
|
|
$write("A2: %h\n", ao68000_m.memory_registers_m.an_ram_inst.mem_data[2]);
|
204 |
|
|
$write("A3: %h\n", ao68000_m.memory_registers_m.an_ram_inst.mem_data[3]);
|
205 |
|
|
$write("A4: %h\n", ao68000_m.memory_registers_m.an_ram_inst.mem_data[4]);
|
206 |
|
|
$write("A5: %h\n", ao68000_m.memory_registers_m.an_ram_inst.mem_data[5]);
|
207 |
|
|
$write("A6: %h\n", ao68000_m.memory_registers_m.an_ram_inst.mem_data[6]);
|
208 |
|
|
$write("SSP: %h\n", ao68000_m.memory_registers_m.an_ram_inst.mem_data[7]);
|
209 |
|
|
$write("USP: %h\n", ao68000_m.memory_registers_m.usp);
|
210 |
|
|
|
211 |
|
|
$write("D0: %h\n", ao68000_m.memory_registers_m.dn_ram_inst.mem_data[0]);
|
212 |
|
|
$write("D1: %h\n", ao68000_m.memory_registers_m.dn_ram_inst.mem_data[1]);
|
213 |
|
|
$write("D2: %h\n", ao68000_m.memory_registers_m.dn_ram_inst.mem_data[2]);
|
214 |
|
|
$write("D3: %h\n", ao68000_m.memory_registers_m.dn_ram_inst.mem_data[3]);
|
215 |
|
|
$write("D4: %h\n", ao68000_m.memory_registers_m.dn_ram_inst.mem_data[4]);
|
216 |
|
|
$write("D5: %h\n", ao68000_m.memory_registers_m.dn_ram_inst.mem_data[5]);
|
217 |
|
|
$write("D6: %h\n", ao68000_m.memory_registers_m.dn_ram_inst.mem_data[6]);
|
218 |
|
|
$write("D7: %h\n", ao68000_m.memory_registers_m.dn_ram_inst.mem_data[7]);
|
219 |
|
|
|
220 |
|
|
$write("PC: %h\n", ao68000_m.registers_m.pc_valid);
|
221 |
|
|
|
222 |
|
|
$write("C: %h\n", ao68000_m.alu_m.sr[0]);
|
223 |
|
|
$write("V: %h\n", ao68000_m.alu_m.sr[1]);
|
224 |
|
|
$write("Z: %h\n", ao68000_m.alu_m.sr[2]);
|
225 |
|
|
$write("N: %h\n", ao68000_m.alu_m.sr[3]);
|
226 |
|
|
$write("X: %h\n", ao68000_m.alu_m.sr[4]);
|
227 |
|
|
$write("IPM: %h\n", ao68000_m.alu_m.sr[10:8]);
|
228 |
|
|
$write("S: %h\n", ao68000_m.alu_m.sr[13]);
|
229 |
|
|
$write("T: %h\n", ao68000_m.alu_m.sr[15]);
|
230 |
|
|
end
|
231 |
|
|
endtask
|
232 |
|
|
|
233 |
|
|
initial begin
|
234 |
|
|
$display("Be sure to set the MICROPC_MAIN_LOOP define to proper value (taken from ao68000.v)");
|
235 |
|
|
|
236 |
|
|
$dumpfile("tb_ao68000.vcd");
|
237 |
|
|
$dumpvars(0);
|
238 |
|
|
$dumpon();
|
239 |
|
|
|
240 |
|
|
rst_n = 1'b0;
|
241 |
|
|
#10 rst_n = 1'b1;
|
242 |
|
|
|
243 |
|
|
while(ao68000_m.microcode_branch_m.micro_pc_0 != `MICROPC_MAIN_LOOP) #10;
|
244 |
|
|
|
245 |
|
|
load_state();
|
246 |
|
|
|
247 |
|
|
$display("START TEST");
|
248 |
|
|
|
249 |
|
|
while(ao68000_m.microcode_branch_m.micro_pc_0 == `MICROPC_MAIN_LOOP) #10;
|
250 |
|
|
while(ao68000_m.microcode_branch_m.micro_pc_0 != `MICROPC_MAIN_LOOP) #10;
|
251 |
|
|
|
252 |
|
|
dump_state();
|
253 |
|
|
|
254 |
|
|
$dumpoff();
|
255 |
|
|
|
256 |
|
|
$finish();
|
257 |
|
|
end
|
258 |
|
|
|
259 |
|
|
initial begin
|
260 |
|
|
#3000
|
261 |
|
|
if(blocked_output == 1'b1) begin
|
262 |
|
|
dump_state();
|
263 |
|
|
$display("processor blocked: yes");
|
264 |
|
|
end
|
265 |
|
|
else begin
|
266 |
|
|
$display("Time limit exceeded.");
|
267 |
|
|
end
|
268 |
|
|
$finish();
|
269 |
|
|
end
|
270 |
|
|
|
271 |
|
|
endmodule
|