mi.v
45.7 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
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
// mi.v v1 Frank Berndt
// mips interface module;
// :set tabstop=4
module mi (
sysclk, randclk, rst_l, reset_l, reset_h, pll_lock,
divmode, coldrst_l, warmrst_l,
sysad_out, sysad_in, syscmd_out, syscmd_in,
pvalid_l, eok_l, evalid_l, int_l, nmi_l,
cbus_din, cbus_dout, cbus_error, cbus_select, cbus_command,
cbus_write_enable, cbus_write_request, cbus_read_request, cbus_grant,
dbus_din, dbus_dout, dbus_enable,
dma_request, dma_start, dma_last,
button, jchan_clk, fl_md,
pi_intr, si_intr, vi_intr, ai_intr, sp_intr, pipe_busy,
pi_flc_intr, pi_aes_intr, pi_ide_intr, pi_err_intr, pi_err_trap,
usb_intr,
v_recall, v_tread, v_time, v_me, v_we,
v0_addr, v0_in, v0_out,
v1_addr, v1_in, v1_out,
v2_addr, v2_in, v2_out,
version, secure, avctrl,
dbg_rst, dbg_boot, dbg_sena, dbg_sclk, dbg_swe, dbg_sre, dbg_si, dbg_so
);
`include "cbus.vh"
// module io ports;
input sysclk; // system clock;
input randclk; // random generator clock;
input rst_l; // chip reset;
output reset_l; // system reset, active low;
output reset_h; // system reset, active high;
input [1:0] pll_lock; // important plls are locked;
output [2:0] divmode; // cpu frequency divider;
output coldrst_l; // cpu cold reset;
output warmrst_l; // cpu warm reset;
input [31:0] sysad_out; // sysad from cpu;
output [31:0] sysad_in; // sysad to cpu;
input [4:0] syscmd_out; // syscmd from cpu;
output [4:0] syscmd_in; // syscmd to cpu;
input pvalid_l; // processor data valid;
output eok_l; // external agent ok;
output evalid_l; // external data valid;
output [4:0] int_l; // cpu interupts;
output nmi_l; // non-maskable interrupt;
input [31:0] cbus_din; // cbus data in;
output [31:0] cbus_dout; // cbus data out;
input cbus_error; // cbus error;
input [1:0] cbus_select; // cbus phase;
input [2:0] cbus_command; // cbus command;
input cbus_write_enable; // enable cbus drivers;
output cbus_write_request; // request cbus command cycle;
output cbus_read_request; // request cbus response cycle;
input cbus_grant; // cbus granted;
input [63:0] dbus_din; // dbus data in;
output [63:0] dbus_dout; // dbus data out;
input dbus_enable; // enable dbus drivers;
output dma_request; // dma request;
input dma_start; // first dbus word valid;
input dma_last; // last dbus word valid;
input button; // power/reset button;
input jchan_clk; // si joy channel clock;
input fl_md; // flash module detect;
input pi_intr; // pi interrupt;
input si_intr; // si interrupt;
input vi_intr; // vi interrupt;
input ai_intr; // ai interrupt;
input sp_intr; // sp interrupt;
input pipe_busy; // dp pipe busy;
input pi_flc_intr; // pi flash interrupt;
input pi_aes_intr; // pi aes interrupt;
input pi_ide_intr; // pi ide interrupt;
input pi_err_intr; // pi error interrupt;
input pi_err_trap; // pi error trap;
input [1:0] usb_intr; // usb interrupts;
output v_recall; // virage recall on hard reset;
output v_tread; // virage read for test enable;
output v_time; // virage time base;
output [2:0] v_me; // virage module enables;
output [2:0] v_we; // virage write enables;
output [15:2] v0_addr; // virage 0 address;
output [31:0] v0_in; // virage 0 write data;
input [31:0] v0_out; // virage 0 read data;
output [15:2] v1_addr; // virage 1 address;
output [31:0] v1_in; // virage 1 write data;
input [31:0] v1_out; // virage 1 read data;
output [15:2] v2_addr; // virage 2 address;
output [31:0] v2_in; // virage 2 write data;
input [31:0] v2_out; // virage 2 read data;
input [31:0] version; // chip version
output secure; // cpu in secure mode;
output [25:0] avctrl; // audio/video control;
input dbg_rst; // cpu reset for debug;
input dbg_boot; // boot from bram instead of rom;
input dbg_sena; // debug serial enable;
input dbg_sclk; // debug serial clock;
input dbg_swe; // debug serial write enable;
input dbg_sre; // debug serial read enable;
input dbg_si; // debug serial in;
output dbg_so; // debug serial out;
// system and cpu reset;
// chip reset (rst_l) triggers cold reset;
// cold reset takes long because of pll locking;
// memory data may be lost during cold reset;
// cold reset must be done upon change of divmode;
// warm reset can be issued by software and is much faster;
// do not release internal reset until the plls are locked;
wire hardrst; // cpu initiated cold reset;
wire softrst; // cpu initiated warm reset;
reg [13:0] rstcnt; // cold reset counter;
reg rstcold; // cpu cold reset;
reg v_recall; // v2 reset on recall;
reg v_tread; // v2 read at end of reset;
reg rstact; // sum of all warm reset sources;
reg [4:0] rstimer; // warm reset timer;
reg mi_reset_l; // mi internal reset;
always @(posedge sysclk)
begin
if(~rst_l | hardrst) begin
rstcnt <= 4'd0;
rstcold <= 1'b0;
v_recall <= 1'b0;
v_tread <= 1'b0;
end else begin
rstcnt <= {14{rstcnt[13]}} | (rstcnt + 1);
rstcold <= rstcold | rstcnt[2];
v_recall <= v_recall | rstcnt[11];
v_tread <= (rstcnt[13:12] == 2'b10);
end
rstact <= ~rstcnt[13] | hardrst | softrst | ~&pll_lock;
if(~rst_l | rstact)
rstimer <= 5'd0;
else
rstimer <= {5{rstimer[4]}} | (rstimer + 1);
mi_reset_l <= reset_l;
end
assign coldrst_l = rstcold & ~dbg_rst;
assign warmrst_l = rstimer[4] & ~dbg_rst;
// drive reset through buffer tree;
wire reset_l_in;
assign reset_l_in = rst_l & rstimer[4];
/*XXX
TBCTSRS reset_l_tree ( .H01(reset_l_in), .N01(reset_l) );
TBCTSRS reset_h_tree ( .H01(~reset_l_in), .N01(reset_h) );
*/
assign reset_l = reset_l_in;
assign reset_h = ~reset_l_in;
// serial debug interface;
reg [31:0] dbg_addr; // debug address;
reg dbg_write; // debug write command;
reg [31:0] dbg_data; // debug data, jtag clk domain;
reg [31:0] dbg_rdata; // debug read data, sysclk domain;
always @(posedge dbg_sclk)
begin
dbg_addr <= { dbg_addr[30:0], dbg_si };
dbg_write <= dbg_addr[31];
dbg_data <= dbg_sre? dbg_rdata : { dbg_data[30:0], dbg_write };
end
assign dbg_so = dbg_data[31];
// debug interface control;
// synchronize dbg_sena to cpu issue;
reg [1:0] dbg_ena; // enable debug access;
wire [31:0] iss_addr; // address to issue;
wire [4:0] iss_cmd; // command to issue;
assign iss_addr = dbg_ena[1]? dbg_addr : sysad_out;
assign iss_cmd = dbg_ena[1]? { 1'b0, dbg_write, 3'b011 } : syscmd_out;
// capture request address and command in issue cycle;
// address is used internally or sent out on the cbus;
wire cmd_iss; // command issue cycle;
reg [31:0] sys_addr; // request address;
reg [4:0] sys_cmd; // request type;
always @(posedge sysclk)
begin
if(cmd_iss) begin
sys_addr <= iss_addr;
sys_cmd <= iss_cmd;
end
end
// decode system command;
// SYSCMD[4] 0=addr 1=data;
// SYSCMD[3] 0=read 1=write;
// SYSCMD[2] 0=single 1=block;
// SYSCMD[1:0] length;
// treat CPU_SIZE_RSVD like 32-byte block command;
wire cmd_addr; // address phase;
wire cmd_data; // data phase;
wire cmd_read; // read request;
wire cmd_write; // write request;
wire cmd_single; // single request;
wire cmd_block; // block request;
wire cmd_sz8; // 8-byte block request;
wire cmd_sz16; // 16-byte block request;
wire cmd_sz32; // 32-byte block request;
assign cmd_addr = ~sys_cmd[4];
assign cmd_data = sys_cmd[4];
assign cmd_read = ~sys_cmd[3];
assign cmd_write = sys_cmd[3];
assign cmd_single = ~sys_cmd[2];
assign cmd_block = sys_cmd[2];
assign cmd_sz8 = cmd_block & (sys_cmd[1:0] == 2'b00);
assign cmd_sz16 = cmd_block & (sys_cmd[1:0] == 2'b01);
assign cmd_sz32 = cmd_block & sys_cmd[1];
// cpu issue control;
// stall cpu until cmd issued;
// stall cpu during debug take-over;
wire cpu_iss; // cpu comand issue;
reg eok_l; // issue control signal;
reg sys_iss; // sysad issue cycle;
reg sys_busy; // sysad busy with request;
wire wr_ack; // done with write request;
wire rsp_ack; // done with read response;
wire sys_ack; // done with request;
reg [4:0] sys_pipe; // request pipe;
reg [2:0] dbg_sync; // debug issue synchronizer;
wire dbg_iss; // debug issue cycle;
reg dbg_wdata_en; // debug write data enable;
assign sys_ack = wr_ack | rsp_ack;
always @(posedge sysclk)
begin
eok_l <= ~mi_reset_l | cmd_iss | (sys_busy & ~sys_ack) | dbg_ena[0];
sys_iss <= mi_reset_l & ~eok_l;
sys_busy <= mi_reset_l & ~sys_ack & (sys_busy | cmd_iss);
sys_pipe <= {5{mi_reset_l}} & { sys_pipe[3:0], cmd_iss };
dbg_ena[0] <= dbg_sena;
dbg_ena[1] <= dbg_ena[0] & (dbg_ena[1] | ~(sys_busy | cpu_iss));
dbg_sync <= { dbg_sync[1], dbg_sync[0] & dbg_ena[1], dbg_swe };
dbg_wdata_en <= dbg_iss;
end
assign cpu_iss = sys_iss & ~pvalid_l & ~syscmd_out[4];
assign dbg_iss = (dbg_sync[2:1] == 2'b01);
assign cmd_iss = cpu_iss | dbg_iss;
// decode important address spaces;
// main memory space is requesting cbus dma;
// old rdram control space is ignored/trapped in mi;
// boot space is handled in mi;
// pif ram space is ignored/trapped in mi;
// mi internal spaces do not request cbus;
wire [31:20] spc; // address space bits;
wire spc_mem; // main memory space serviced by dma;
wire spc_rdctl; // old rdram ctrl space;
wire spc_reg; // mi register space;
wire spc_boot; // boot space;
wire spc_bev; // boot exception vector address;
wire spc_pif; // pif space, 1fc0_07c0...07ff;
wire spc_mi; // mi internal address space, no cbus req;
wire spc_cbus; // cbus spaces;
assign spc = sys_addr[31:20];
assign spc_mem = spc[31] // 0x8000_0000 x64 space;
| (spc[31:24] == 8'h00) // 0x00xx_xxxx x36 space;
| (spc[31:24] == 8'h01) // 0x01xx_xxxx x64 space;
| (spc[31:24] == 8'h02); // 0x02xx_xxxx x64 space;
assign spc_rdctl = (spc[31:24] == 8'h03); // 0x03xx_xxxx;
assign spc_reg = (spc == `CBUS_MI);
assign spc_boot = (spc[31:20] == 12'h1fc); // 0x1fcx_xxxx;
assign spc_bev = (sys_addr[19:0] == 20'd0); // 0xxxx0_0000;
assign spc_pif = (sys_addr[19:6] == 14'h01f); // 0xxxx0_07cx;
assign spc_mi = spc_rdctl | spc_reg | spc_boot;
assign spc_cbus = ~spc_mem & ~spc_mi;
// provide registered versions of space decodes
// for heavily loaded muxes and selects;
// decode fetch from boot vector, single read from 1fc0_0000;
reg sel_mem; // buffered spc_mem;
reg sel_reg; // buffered spc_reg;
reg sel_boot; // buffered spc_boot;
reg sel_pif; // buffered spc_pif;
reg sel_mi; // buffered spc_mi;
reg sel_cbus; // buffered spc_cbus;
reg sel_dbus; // write dbus read data to rwbufs;
wire bev_fetch; // fetch from boot exception vector;
always @(posedge sysclk)
begin
sel_mem <= spc_mem;
sel_reg <= spc_reg;
sel_boot <= spc_boot;
sel_pif <= spc_boot & spc_pif;
sel_mi <= spc_mi;
sel_cbus <= spc_cbus;
sel_dbus <= sys_busy & spc_mem & cmd_read;
end
assign bev_fetch = sys_pipe[0] & cmd_single & cmd_read & spc_boot & spc_bev;
// buffer cpu write data;
// buffer sys_addr for mi internal units;
// lower bits can increment to support block requests;
// buffer mi_wdata because of bram, iram and virage loading;
wire secure; // cpu in secure mode;
wire sys_wdata_en; // cpu write data enable;
reg [31:0] sys_wdata; // cpu write data;
wire mi_req; // mi internal request;
reg [19:2] mi_addr; // mi internal device address;
reg [3:0] mi_cnt; // burst counter;
wire mi_bflip; // flip brom/bram spaces;
reg [31:0] mi_wdata; // mi internal write data;
assign sys_wdata_en = cmd_write & ~pvalid_l & syscmd_out[4];
assign mi_req = sys_pipe[0] & spc_mi;
always @(posedge sysclk)
begin
if(sys_wdata_en)
sys_wdata <= sysad_out;
else if(dbg_wdata_en)
sys_wdata <= dbg_data;
if(mi_req) begin
mi_cnt <= { 3'b000, cmd_read };
mi_addr <= sys_addr[19:2];
end else if(sel_boot & ~mi_cnt[3]) begin
mi_cnt <= mi_cnt + 1;
mi_addr[4:2] <= sys_addr[4:2] ^ mi_cnt[2:0];
end
mi_wdata <= sys_wdata;
end
// decode mi boot spaces;
// flip brom/bram address spaces based on RESET bit in MI_SEC_MODE;
wire mi_brxm; // brom/bram space;
wire mi_brom; // brom space;
wire mi_bram; // bram space;
wire mi_iram; // iram space;
wire mi_vmem; // virage memory space;
assign mi_brxm = (mi_addr[19:18] == 2'b00);
assign mi_brom = mi_brxm & (~mi_addr[17] ^ mi_bflip);
assign mi_bram = mi_brxm & (mi_addr[17] ^ mi_bflip);
assign mi_iram = (mi_addr[19:18] == 2'b01);
assign mi_vmem = (mi_addr[19:18] == 2'b10);
// cpu write control;
// all write data, except for register writes, end up in rwbuf;
// 8 deep for max of 8 word cycles on 32-bit sysad;
// duplicate single write data into both rwbuf halves;
wire wr_start; // start write pipe;
wire wr_last; // last write stage;
wire wr_pipe_clr; // clear write pipe;
reg [7:0] wr_pipe; // write control pipe;
assign wr_start = sys_pipe[0] & cmd_write;
assign wr_pipe_clr = mi_reset_l & ~wr_last;
always @(posedge sysclk)
begin
wr_pipe[0] <= wr_pipe_clr & wr_start;
wr_pipe[1] <= wr_pipe_clr & (wr_pipe[0] | (cmd_single & wr_start));
wr_pipe[7:2] <= {6{wr_pipe_clr}} & wr_pipe[6:1];
end
assign wr_last = (cmd_single & wr_pipe[0])
| (cmd_sz8 & wr_pipe[1])
| (cmd_sz16 & wr_pipe[3])
| (cmd_sz32 & wr_pipe[7]);
// decode byte enables for boot spaces;
// reads always return full width;
// enable all bytes for block requests;
reg [3:0] mi_be; // mi internal byte enables;
wire mi_write; // mi write signal;
reg [3:0] mi_we; // mi internal write enables;
assign mi_write = |wr_pipe & mi_reset_l;
always @(posedge sysclk)
begin
casex({ sys_cmd[2:0], sys_addr[1:0] })
5'b1xxxx: mi_be <= 4'b1111;
5'b00000: mi_be <= 4'b1000;
5'b00001: mi_be <= 4'b0100;
5'b00010: mi_be <= 4'b0010;
5'b00011: mi_be <= 4'b0001;
5'b0010x: mi_be <= 4'b1100;
5'b0011x: mi_be <= 4'b0011;
5'b010x0: mi_be <= 4'b1110;
5'b010x1: mi_be <= 4'b0111;
5'b011xx: mi_be <= 4'b1111;
endcase
mi_we <= {4{mi_write}} & mi_be;
end
// acknowledge comletion of memory requests;
// for writes, the earliest is so that the next cpu write does not
// overwrite the rwbuf before it has been read out to the dbus;
// dma_start satisfies this even for 4 word dbus write dma;
// for block reads (where the first word is bypassed) dma_start is used;
// for single reads (no bypass) must wait one more clock for rwbuf to be valid;
wire ack_mem_wr; // completion of dma write;
reg dma_start_del; // delayed dma start;
reg ack_mem_rd; // ok to start response;
assign ack_mem_wr = sel_mem & dma_start;
always @(posedge sysclk)
begin
dma_start_del <= dma_start;
ack_mem_rd <= sel_mem & (cmd_block? dma_start : dma_start_del);
end
// acknowledge completion of mi internal requests;
// all internal units (regs, brom, bram, iram, virage)
// are fast enough to complete access in a single clock;
// writes can be fully pipelined without sysad stalls;
// errors on mi writes disable write enables;
reg ack_mi_wr; // completion of mi internal write;
reg ack_mi_rd; // completion of mi internal read;
always @(posedge sysclk)
begin
ack_mi_wr <= sys_pipe[0] & spc_mi;
ack_mi_rd <= ack_mi_wr;
end
// acknowledge comletion of cbus requests;
// cbus writes, at time of cbus grant;
// cbus reads, when repsonse is seen;
reg ack_bnm; // ack block request error;
wire ack_cbus_wr; // completion of cbus write;
wire ack_cbus_rd; // cbus returns read response data;
assign ack_cbus_wr = sel_cbus & (ack_bnm | cbus_grant);
assign ack_cbus_rd = sel_cbus & (ack_bnm | (cbus_command == `CBUS_CMD_RSP));
// sum up all the write completion acks;
assign wr_ack = cmd_write & (ack_mem_wr | ack_mi_wr | ack_cbus_wr);
// mi error detection;
// detect accesses to non-cacheable spaces;
// all boot spaces and main memory are cacheable;
wire req_bnm; // block request to non-memory space;
reg err_bnm; // error in non-memory space;
wire werr_bnm; // write error in non-memory space;
wire en_ski_bnm; // enable secure kernel trap on illegal block writes;
wire en_wei_bnm; // enable write error intr on illegal block writes;
wire ski_bnm; // secure kernel trap on illegal block writes;
wire wei_bnm; // write error intr on illegal block writes;
assign req_bnm = cmd_block & ~(spc_boot | spc_mem);
always @(posedge sysclk)
begin
err_bnm <= req_bnm;
ack_bnm <= sys_pipe[1] & err_bnm;
end
assign werr_bnm = cmd_write & sys_pipe[1] & err_bnm;
assign ski_bnm = en_ski_bnm & werr_bnm;
assign wei_bnm = en_wei_bnm & werr_bnm;
// trap pif space requests;
// but only in non-secure mode;
wire acc_pif; // access pif space;
wire wacc_pif; // write to pif space;
wire en_ski_pif; // enable secure kernel trap on pif writes;
wire en_wei_pif; // enable write error intr on pif writes;
wire ski_pif; // secure kernel trap on pif writes;
wire wei_pif; // write error intr on pif writes;
assign acc_pif = ~secure & sel_pif;
assign wacc_pif = cmd_write & sys_pipe[1] & acc_pif;
assign ski_pif = en_ski_pif & wacc_pif;
assign wei_pif = en_wei_pif & wacc_pif;
// cpu read response control;
// always return response for size that the cpu requested;
// returning error in read response causes bus error exception;
// bypass first dbus word for block reads only;
wire rsp_start; // start read response pipe;
reg rsp_val; // valid response cycle;
wire rsp_term; // terminate response in next clock;
reg rsp_last; // last response cycle;
wire rsp_clr; // clear response pipe;
reg [2:0] rsp_cnt; // response cycle;
wire ber_bnm; // bus error on block req to non-cacheable spaces;
wire ber_pif; // bus error on pif space;
reg rsp_error; // error in read response;
reg dbus_byp; // bypass first dbus word to sysad;
assign rsp_start = ack_mem_rd | ack_mi_rd | ack_cbus_rd;
assign rsp_clr = mi_reset_l & sys_busy & cmd_read & ~rsp_last;
assign rsp_term = (cmd_single & rsp_start)
| (cmd_sz8 & rsp_cnt[0])
| (cmd_sz16 & (rsp_cnt[1:0] == 2'b11))
| (rsp_cnt == 3'b111);
always @(posedge sysclk)
begin
if(rsp_clr == 1'b0)
rsp_cnt <= 3'd0;
else if(rsp_start | rsp_val)
rsp_cnt <= rsp_cnt + 1;
rsp_val <= rsp_clr & (rsp_val | rsp_start);
rsp_last <= rsp_clr & rsp_term;
rsp_error <= (sel_cbus & cbus_error) | (ber_bnm & err_bnm) | (ber_pif & acc_pif);
dbus_byp <= sel_mem & cmd_block & dma_start;
end
assign rsp_ack = rsp_last;
// response command;
// external requests are not used, only return data identifiers;
// SYSCMD[4] 1 data identifier;
// SYSCMD[3] 0 last data item, 1 not last;
// SYSCMD[2] 0 response data, 1 not;
// SYSCMD[1] 0 no error, 1 error;
// SYSCMD[0] 1 no error checking (parity/ecc);
assign syscmd_in[4] = 1'b1;
assign syscmd_in[3] = ~rsp_last;
assign syscmd_in[2] = 1'b0;
assign syscmd_in[1] = rsp_error;
assign syscmd_in[0] = 1'b1;
assign evalid_l = ~rsp_val | dbg_ena[1];
// capture error state;
// disarm on reset, capture on cpu write;
wire err_trig; // write error event;
wire err_cap; // capture error state;
wire err_info_wr; // write to MI_ERR_INFO;
reg [31:0] err_addr; // write error address;
wire err_clr; // clear write error;
reg err_ski; // error handled by secure kernel trap;
reg err_wei; // error handled by write error interrupt;
wire err_val; // error is pending;
reg err_mult; // multiple write errors;
reg [2:0] err_type; // write error type;
wire [31:0] err_info; // write error info;
reg [31:0] err_data; // write error data;
assign err_trig = ski_bnm | wei_bnm | ski_pif | wei_pif;
assign err_cap = ~err_val & err_trig;
always @(posedge sysclk)
begin
if(err_cap) begin
err_addr <= sys_addr;
err_type <= sys_cmd[2:0];
end
if(err_cap & cmd_single)
err_data <= sys_wdata;
err_ski <= err_clr & (err_ski | ski_bnm | ski_pif);
err_wei <= err_clr & (err_wei | wei_bnm | wei_pif);
err_mult <= ~err_cap & (err_mult | err_trig);
end
assign err_val = err_ski | err_wei;
assign err_info = { 27'd0, err_val, err_mult, err_type };
// mi random generator;
// jitter based random generator for one bit;
// high frequency clock is sysclk;
// low frequency clock is output of video pll;
// randclk must be slower than sysclk;
reg [3:0] mi_rand; // shift flops, randclk domain;
reg [1:0] mi_rbit; // synchronizer, sysclk domain;
always @(posedge randclk)
begin
mi_rand <= { mi_rand[2:0], sysclk };
end
always @(posedge sysclk)
begin
mi_rbit <= { mi_rbit[0], ^mi_rand };
end
// request cbus for pio requests;
// do not issue cbus request if request errors;
// clear request on reset and grant;
wire cbus_clr_req; // clear cbus request;
wire cbus_wkick; // kick a cbus write request;
wire cbus_rkick; // kick a cbus read request;
reg cbus_write_request; // request cbus write;
reg cbus_read_request; // request cbus read;
assign cbus_clr_req = mi_reset_l & ~cbus_grant;
assign cbus_wkick = sys_pipe[0] & spc_cbus & cmd_write & ~req_bnm;
assign cbus_rkick = sys_pipe[0] & spc_cbus & cmd_read & ~req_bnm;
always @(posedge sysclk)
begin
cbus_write_request <= cbus_clr_req & (cbus_write_request | cbus_wkick);
cbus_read_request <= cbus_clr_req & (cbus_read_request | cbus_rkick);
end
// request dma for main memory address spaces;
// data move across the dbus;
// request read dma right away;
// request single write dma right away;
// request block write dma when rwbuf is sufficiently filled;
wire dma_wkick; // start a dma write request;
wire dma_kick; // start a dma request;
reg dma_request; // request cbus for dma;
assign dma_wkick = cmd_sz32? sys_pipe[4] : cmd_sz16? sys_pipe[2] : sys_pipe[0];
assign dma_kick = spc_mem & (cmd_read? sys_pipe[0] : dma_wkick);
always @(posedge sysclk)
begin
dma_request <= cbus_clr_req & (dma_request | dma_kick);
end
// dbus interface;
wire [63:0] dbus_in; // dbus read data;
reg [63:0] dbus_out; // dbus output register;
assign dbus_in = dbus_din;
wire [63:0] dbus_dout = dbus_enable ? dbus_out : {64{1'b0}};
// read/write buffer;
// single buffer, because of non-overlapping read/write;
// 4x64 bits, made of flip-flops;
// write data source is cpu or dbus data;
// 4->1 mux selects read data;
// always used in sequential order, independent of cpu order;
// sel_dbus has 64 loads, drive from flip-flop;
reg [63:0] rwbuf0; // read/write buf 0;
reg [63:0] rwbuf1; // read/write buf 1;
reg [63:0] rwbuf2; // read/write buf 2;
reg [63:0] rwbuf3; // read/write buf 3;
wire [63:0] rwbuf_in; // rwbuf write data;
wire [7:0] rwbuf_we; // buffer write enables, 32-bit words;
assign rwbuf_in[63:32] = sel_dbus? dbus_in[63:32] : sys_wdata[31:0];
assign rwbuf_in[31:0] = sel_dbus? dbus_in[31:0] : sys_wdata[31:0];
always @(posedge sysclk)
begin
if(rwbuf_we[0])
rwbuf0[63:32] <= rwbuf_in[63:32];
if(rwbuf_we[1])
rwbuf0[31:0] <= rwbuf_in[31:0];
if(rwbuf_we[2])
rwbuf1[63:32] <= rwbuf_in[63:32];
if(rwbuf_we[3])
rwbuf1[31:0] <= rwbuf_in[31:0];
if(rwbuf_we[4])
rwbuf2[63:32] <= rwbuf_in[63:32];
if(rwbuf_we[5])
rwbuf2[31:0] <= rwbuf_in[31:0];
if(rwbuf_we[6])
rwbuf3[63:32] <= rwbuf_in[63:32];
if(rwbuf_we[7])
rwbuf3[31:0] <= rwbuf_in[31:0];
end
// dbus data control;
// entirely controlled by dma_start and dma_last;
// pipe to align with moving data;
wire dbus_wstart; // dbus write start;
wire dbus_rstart; // dbus read start;
reg rwbuf_wstart; // start write to rwbuf;
reg [3:0] rwbuf_wpipe; // rwbuf write control pipe;
reg [2:0] rwbuf_rpipe; // rwbuf read control pipe;
wire [2:0] rwbuf_sel; // read mux selects;
assign dbus_wstart = cmd_write & dma_start;
assign dbus_rstart = cmd_read & dma_start;
always @(posedge sysclk)
begin
rwbuf_wpipe <= { rwbuf_wpipe[2:0], dbus_rstart };
rwbuf_rpipe <= { rwbuf_rpipe[1:0], dbus_wstart };
end
assign rwbuf_sel[0] = rsp_cnt[0] ^ sys_addr[2];
assign rwbuf_sel[1] = rsp_cnt[1] | rwbuf_rpipe[0] | rwbuf_rpipe[2];
assign rwbuf_sel[2] = rsp_cnt[2] | rwbuf_rpipe[1] | rwbuf_rpipe[2];
// rwbuf write control;
// write 32-bit words when cpu is writing;
// write 64-bit words when dbus is writing;
// each write enable has 32 loads;
// drive from registers through minimal logic;
assign rwbuf_we[0] = rwbuf_wpipe[0] | wr_pipe[0];
assign rwbuf_we[1] = rwbuf_wpipe[0] | wr_pipe[1];
assign rwbuf_we[2] = rwbuf_wpipe[1] | wr_pipe[2];
assign rwbuf_we[3] = rwbuf_wpipe[1] | wr_pipe[3];
assign rwbuf_we[4] = rwbuf_wpipe[2] | wr_pipe[4];
assign rwbuf_we[5] = rwbuf_wpipe[2] | wr_pipe[5];
assign rwbuf_we[6] = rwbuf_wpipe[3] | wr_pipe[6];
assign rwbuf_we[7] = rwbuf_wpipe[3] | wr_pipe[7];
// rwbuf read data path;
// always read 64-bits;
// bypass first 32-bit word from dbus to sysad_in,
// but only for block reads, not single reads;
wire [63:0] rwbuf_dox; // rwbuf 0/1 read mux;
wire [63:0] rwbuf_doy; // rwbuf 2/3 read mux;
wire [63:0] rwbuf_do; // selected rwbuf read data;
reg [31:0] rwbuf_wo; // selected rwbuf word;
assign rwbuf_dox = rwbuf_sel[1]? rwbuf1[63:0] : rwbuf0[63:0];
assign rwbuf_doy = rwbuf_sel[1]? rwbuf3[63:0] : rwbuf2[63:0];
assign rwbuf_do = rwbuf_sel[2]? rwbuf_doy: rwbuf_dox;
always @(posedge sysclk)
begin
rwbuf_wo <= dbus_byp? dbus_in[63:32]
: rwbuf_sel[0]? rwbuf_do[31:0] : rwbuf_do[63:32];
dbus_out <= rwbuf_do;
end
// cbus interface;
// cbus interface controls;
// decode cbus commands;
reg [31:0] cbus_in; // cbus input register;
wire [31:0] cbus_out; // cbus output data;
reg [31:0] cbus_dout; // cbus output register;
always @(posedge sysclk)
begin
cbus_in <= cbus_din;
cbus_dout <= {32{cbus_write_enable}} & cbus_out;
end
// determine dma request parameters;
// only care about sub-block order and length;
// new ri has hard-coded dma delays;
reg [4:0] dma_size; // dma size - 1;
reg [4:0] dma_len; // dma length;
wire dma_blkrd; // block read request;
wire dma_subblk; // sub-block order request;
wire dma_masked; // masked dma request;
wire dma_up; // increasing addresses;
wire dma_seq; // sequential order;
wire [7:0] dma_delay; // dma delay;
wire [31:0] cbus_len; // dma control;
always @(sys_cmd[2:0])
begin
casex(sys_cmd[2:0])
3'b000: dma_size <= 5'd0;
3'b001: dma_size <= 5'd1;
3'b010: dma_size <= 5'd2;
3'b011: dma_size <= 5'd3;
3'b100: dma_size <= 5'd7;
3'b101: dma_size <= 5'd15;
3'b11x: dma_size <= 5'd31;
endcase
end
always @(posedge sysclk)
begin
dma_len[4:3] <= dma_size[4:3];
dma_len[2:0] <= dma_size[2:0] + sys_addr[2:0];
end
assign dma_blkrd = cmd_block & cmd_read;
assign dma_subblk = dma_blkrd;
assign dma_masked = 1'b0;
assign dma_up = 1'b0;
assign dma_seq = dma_blkrd;
assign dma_delay = 8'd0;
assign cbus_len = {
dma_subblk, dma_masked, dma_up, dma_seq,
`CBUS_DEV_MI, dma_delay, cmd_read, { 2'b00, dma_len} };
// cbus write data mux;
// selects address, length or cbus write data;
// default to cbus write data, because they toggle the least;
wire cbus_sel_addr; // cbus wants address;
wire cbus_sel_len; // cbus wants dma length;
assign cbus_sel_addr = (cbus_select == `CBUS_SEL_ADDR);
assign cbus_sel_len = (cbus_select == `CBUS_SEL_LEN);
assign cbus_out = cbus_sel_addr? sys_addr
: cbus_sel_len? cbus_len : sys_wdata;
// compatible mi registers;
// put reg_addr into flip-flops to unload sys_addr;
reg [3:0] reg_addr; // register address bits;
wire ra_mode; // access MI_MODE;
wire ra_version; // access MI_VERSION;
wire ra_intr; // access MI_INTR;
wire ra_mask; // access MI_MASK;
assign ra_mode = (reg_addr == 4'h0);
assign ra_version = (reg_addr == 4'h1);
assign ra_intr = (reg_addr == 4'h2);
assign ra_mask = (reg_addr == 4'h3);
// new MI registers;
wire ra_ctrl; // access MI_CTRL;
wire ra_sec_mode; // access MI_SEC_MODE;
wire ra_sec_timer; // access MI_SEC_TIMER;
wire ra_sec_vtime; // access MI_SEC_VTIME;
wire ra_err_addr; // access MI_ERR_ADDR;
wire ra_err_data; // access MI_ERR_DATA;
wire ra_err_info; // access MI_ERR_INFO;
wire ra_random; // access MI_RANDOM;
wire ra_avctrl; // access MI_VCTRL;
wire ra_eintr; // access MI_EINTR;
wire ra_emask; // access MI_EMASK;
assign ra_ctrl = (reg_addr == 4'h4);
assign ra_sec_mode = (reg_addr == 4'h5);
assign ra_sec_timer = (reg_addr == 4'h6);
assign ra_sec_vtime = (reg_addr == 4'h7);
assign ra_err_addr = (reg_addr == 4'h8);
assign ra_err_data = (reg_addr == 4'h9);
assign ra_err_info = (reg_addr == 4'ha);
assign ra_random = (reg_addr == 4'hb);
assign ra_avctrl = (reg_addr == 4'hc);
assign ra_eintr = (reg_addr == 4'he);
assign ra_emask = (reg_addr == 4'hf);
// shadow decode for MI_INTR, MI_EINTR;
// shadow decode for MI_MASK, MI_EMASK;
wire ra_sintr; // access MI_INTR or MI_EINTR;
wire ra_smask; // access MI_MASK or MI_EMASK;
assign ra_sintr = ra_intr | ra_eintr;
assign ra_smask = ra_mask | ra_emask;
// register write control;
// accept only single requests to mi registers;
// block requests are detected and optionally fail;
// MI_VERSION, MI_INTR are read-only, writes are ignored;
// enable reg_addr only for register requests, to
// reduce toggling of register read data mux reg_rdata;
wire reg_req; // request to mi registers;
reg reg_acc; // register access cycle;
wire reg_write; // register write;
wire reg_read; // register read;
assign reg_req = sys_pipe[0] & spc_reg;
always @(posedge sysclk)
begin
if(reg_req)
reg_addr <= sys_addr[5:2];
reg_acc <= reg_req & cmd_single;
end
assign reg_write = reg_acc & cmd_write;
assign reg_read = reg_acc & cmd_read;
// MI_MASK write control;
// cleared on reset;
// intr masks are only modified when set or clear are set;
// MI_EMASK is shadow location with all mask bits;
wire [1:0] mask_we; // write to MI_MASK;
reg dp_mask; // dp intr mask;
reg pi_mask; // pi intr mask;
reg vi_mask; // vi intr mask;
reg ai_mask; // ai intr mask;
reg si_mask; // si intr mask;
reg sp_mask; // sp intr mask;
reg pi_flc_mask; // pi flash mask;
reg pi_aes_mask; // pi aes mask;
reg pi_ide_mask; // pi ide mask;
reg [1:0] usb_mask; // usb mask;
reg pi_err_mask; // pi error mask;
reg but_mask; // button intr mask;
reg md_mask; // md intr mask;
wire en_ide_intr; // unmask ide interrupt;
assign mask_we[0] = reg_write & ra_smask;
assign mask_we[1] = reg_write & ra_emask;
always @(posedge sysclk)
begin
if(mi_reset_l == 1'b0) begin
dp_mask <= 1'b0;
pi_mask <= 1'b0;
vi_mask <= 1'b0;
ai_mask <= 1'b0;
si_mask <= 1'b0;
sp_mask <= 1'b0;
pi_flc_mask <= 1'b0;
pi_aes_mask <= 1'b0;
pi_ide_mask <= 1'b0;
pi_err_mask <= 1'b0;
usb_mask <= 2'b00;
but_mask <= 1'b0;
md_mask <= 1'b0;
end else begin
if(mask_we[1] & ^sys_wdata[27:26])
md_mask <= sys_wdata[27];
if(mask_we[1] & ^sys_wdata[25:24])
but_mask <= sys_wdata[25];
if(mask_we[1] & ^sys_wdata[23:22])
usb_mask[1] <= sys_wdata[23];
if(mask_we[1] & ^sys_wdata[21:20])
usb_mask[0] <= sys_wdata[21];
if(mask_we[1] & ^sys_wdata[19:18])
pi_err_mask <= sys_wdata[19];
if(mask_we[1] & ^sys_wdata[17:16])
pi_ide_mask <= sys_wdata[17];
if(mask_we[1] & ^sys_wdata[15:14])
pi_aes_mask <= sys_wdata[15];
if(mask_we[1] & ^sys_wdata[13:12])
pi_flc_mask <= sys_wdata[13];
if(mask_we[0] & ^sys_wdata[11:10])
dp_mask <= sys_wdata[11];
if(mask_we[0] & ^sys_wdata[9:8])
pi_mask <= sys_wdata[9];
if(mask_we[0] & ^sys_wdata[7:6])
vi_mask <= sys_wdata[7];
if(mask_we[0] & ^sys_wdata[5:4])
ai_mask <= sys_wdata[5];
if(mask_we[0] & ^sys_wdata[3:2])
si_mask <= sys_wdata[3];
if(mask_we[0] & ^sys_wdata[1:0])
sp_mask <= sys_wdata[1];
end
end
assign err_info_wr = reg_write & ra_err_info; //XXX
assign err_clr = mi_reset_l & ~(reg_read & ra_err_info);
// mi control register;
// use upper bits to unload sys_wdata and spread reg_rdata;
wire mi_ctrl_wr; // write to MI_CTRL;
reg [19:13] mi_ctrl; // mi control register;
assign mi_ctrl_wr = reg_write & ra_ctrl;
assign hardrst = mi_ctrl_wr & sys_wdata[11];
assign softrst = mi_ctrl_wr & sys_wdata[12];
always @(posedge sysclk)
begin
if(mi_reset_l == 1'b0)
mi_ctrl[19:13] <= 7'd0;
else if(mi_ctrl_wr)
mi_ctrl[19:13] <= sys_wdata[19:13];
end
assign en_ide_intr = mi_ctrl[19];
assign en_ski_pif = mi_ctrl[18];
assign en_wei_pif = mi_ctrl[17];
assign ber_pif = mi_ctrl[16];
assign en_ski_bnm = mi_ctrl[15];
assign en_wei_bnm = mi_ctrl[14];
assign ber_bnm = mi_ctrl[13];
// cpu frequency control;
// divide mode must be valid during reset;
// set to x1 on chip reset, cpu can change later;
reg [2:0] divmode; // cpu frequency divider;
always @(posedge sysclk)
begin
if(rst_l == 1'b0)
divmode <= 3'b000;
else if(hardrst)
divmode <= sys_wdata[10:8];
end
// access to below registers is limited to secure mode;
wire rx_sec_mode; // access MI_SEC_MODE in secure mode;
wire rx_sec_timer; // access MI_SEC_TIMER in secure mode;
wire rx_sec_vtime; // access MI_SEC_VTIME in secure mode;
assign rx_sec_mode = secure & ra_sec_mode;
assign rx_sec_timer = secure & ra_sec_timer;
assign rx_sec_vtime = secure & ra_sec_vtime;
// secure timer;
// timer is enabled when spre_val is not 0;
wire stim_wr; // write to MI_SEC_TIMER;
reg [15:0] spre_val; // pre-scaler value;
reg [15:0] stim_val; // secure timer value;
reg stim_on; // secure timer is on;
assign stim_wr = reg_write & rx_sec_timer;
always @(posedge sysclk)
begin
if(mi_reset_l == 1'b0)
spre_val <= 16'd0;
else if(stim_wr)
spre_val <= sys_wdata[31:16];
if(stim_wr)
stim_val <= sys_wdata[15:0];
stim_on <= mi_reset_l & |spre_val;
end
// secure timer counters;
// re-load counters on writes to MI_SEC_TIMER;
reg stim_set; // re-init counters;
reg [15:0] spre_cnt; // pre-scaler counter;
wire spre_zero; // spre_cnt is 0;
reg stim_en; // enable stim_cnt for load or increment;
reg [15:0] stim_cnt; // secure timer counter;
wire stim_zero; // stim_cnt is 0;
reg stim_load; // timer tick and stim_cnt is 0;
assign spre_zero = (spre_cnt == 16'd0);
assign stim_zero = (stim_cnt == 16'd0);
always @(posedge sysclk)
begin
stim_set <= stim_wr;
if(stim_set | spre_zero)
spre_cnt <= spre_val;
else if(stim_on)
spre_cnt <= spre_cnt - 1;
stim_en <= stim_on & spre_zero;
stim_load <= stim_en & stim_zero;
if(stim_set | stim_load)
stim_cnt <= stim_val;
else if(stim_en)
stim_cnt <= stim_cnt - 1;
end
// secure mode control;
// this is the root of all security evil;
// sec_trig arms logic to enter secure mode;
// secure mode is actually entered on single read
// from boot exception vector 1fc0_0000;
// secure timer only triggers in non-secure mode;
// force scure mode in debug mode;
wire sec_mode_wr; // write to MI_SEC_MODE;
wire sec_mode_rd; // read from MI_SEC_MODE;
wire sec_trig_md; // md trigger;
wire sec_trig_but; // button trigger;
wire sec_trig_trap; // trap trigger;
wire sec_trig_fatal; // fatal system error trigger;
wire sec_trig_timer; // secure timer trigger;
wire sec_trig_app; // application trigger;
wire sec_mode_enter; // enter secure mode upon boot exception fetch;
reg sec_md_en; // enable secure md trap;
reg sec_but_en; // enable secure button trap;
reg sec_iram_en; // iram access enable bit;
reg [7:0] sec_mode; // secure mode register;
wire sec_trig; // sum of all secure mode triggers;
wire [31:0] mi_sec_mode; // all bits for read;
assign sec_mode_wr = reg_write & ra_sec_mode;
assign sec_mode_rd = reg_read & ra_sec_mode;
assign sec_trig_trap = ski_pif | ski_bnm;
assign sec_trig_fatal = ~secure & pi_err_trap;
assign sec_trig_timer = ~secure & stim_load;
assign sec_trig_app = ~secure & sec_mode_rd;
assign sec_mode_enter = (sec_mode[1] | sec_trig) & bev_fetch;
always @(posedge sysclk)
begin
if(mi_reset_l == 1'b0) begin
sec_md_en <= 1'b0;
sec_but_en <= 1'b0;
sec_iram_en <= 1'b0;
sec_mode <= 8'b0000_0010;
end else if(sec_mode_wr & secure) begin
sec_md_en <= sys_wdata[26];
sec_but_en <= sys_wdata[25];
sec_iram_en <= sys_wdata[24];
sec_mode[7] <= sys_wdata[7]? sec_mode[7] : sec_trig_md;
sec_mode[6] <= sys_wdata[6]? sec_mode[6] : sec_trig_but;
sec_mode[5] <= sys_wdata[5]? sec_mode[5] : sec_trig_trap;
sec_mode[4] <= sys_wdata[4]? sec_mode[4] : sec_trig_fatal;
sec_mode[3] <= sys_wdata[3]? sec_mode[3] : sec_trig_timer;
sec_mode[2] <= sys_wdata[2]? sec_mode[2] : sec_trig_app;
sec_mode[1:0] <= sys_wdata[1:0];
end else begin
sec_mode[7] <= sec_mode[7] | sec_trig_md;
sec_mode[6] <= sec_mode[6] | sec_trig_but;
sec_mode[5] <= sec_mode[5] | sec_trig_trap;
sec_mode[4] <= sec_mode[4] | sec_trig_fatal;
sec_mode[3] <= sec_mode[3] | sec_trig_timer;
sec_mode[2] <= sec_mode[2] | sec_trig_app;
sec_mode[0] <= sec_mode[0] | sec_mode_enter;
end
end
assign mi_bflip = ~sec_mode[1] | dbg_boot;
assign sec_trig = |sec_mode[7:2];
assign nmi_l = ~sec_trig;
assign secure = sec_mode[0] | dbg_ena[1];
assign mi_sec_mode = { 5'd0, sec_md_en, sec_but_en, sec_iram_en, 16'd0, sec_mode };
// mi internal control;
// drive read data mux selects from ff due to high loading;
wire acc_brom; // access brom;
wire acc_bram; // access bram;
wire acc_iram; // access iram;
wire acc_vmem; // access virage memories;
reg sel_brom; // select brom read data;
reg sel_bram; // select bram read data;
reg sel_iram; // select iram read data;
assign acc_brom = secure & sel_boot & mi_brom;
assign acc_bram = secure & sel_boot & mi_bram;
assign acc_iram = (secure | sec_iram_en) & sel_boot & mi_iram;
assign acc_vmem = secure & sel_boot & mi_vmem;
always @(posedge sysclk)
begin
sel_brom <= acc_brom;
sel_bram <= acc_bram;
sel_iram <= acc_iram;
end
// boot rom, 4kx32 bits;
// read access finishes within one clock;
// initialize with rom data from file;
wire brom_ena; // enable boot rom;
wire [31:0] brom_data; // boot rom read data;
assign brom_ena = acc_brom;
mi_brom brom (
.sysclk(sysclk),
.brom_ena(brom_ena),
.brom_addr(mi_addr[13:2]),
.brom_do(brom_data)
);
// boot sram, 64kbytes, 16kx32 with byte enables;
// boot exception vector need write access for secure mode;
// secure kernel needs writable space on-chip;
// read access finishes within one clock;
wire bram_ena; // boot ram enable;
wire [3:0] bram_we; // boot ram write-enables;
wire [31:0] bram_rdata; // boot ram read data;
assign bram_ena = acc_bram;
assign bram_we = mi_we;
mi_bram bram (
.sysclk(sysclk),
.bram_ena(bram_ena),
.bram_addr(mi_addr[15:2]),
.bram_di(mi_wdata),
.bram_we(bram_we),
.bram_do(bram_rdata)
);
// internal sram, 32kbytes, 8kx32 with byte enables;
// usable for secure kernel or application;
wire iram_ena; // iram ram enable;
wire [3:0] iram_we; // iram write enables;
wire [31:0] iram_rdata; // iram write data;
assign iram_ena = acc_iram;
assign iram_we = mi_we;
mi_iram iram (
.sysclk(sysclk),
.iram_ena(iram_ena),
.iram_addr(mi_addr[14:2]),
.iram_di(mi_wdata),
.iram_we(iram_we),
.iram_do(iram_rdata)
);
// virage time base;
// store controller needs 1us time base;
// divide sysclk, default is 62;
wire vtime_we; // pio write to MI_SEC_VTIME;
reg [7:1] vtime_val; // time divider value;
reg vtime_new; // new divider written;
reg [7:1] vtime_div; // divider;
wire vtime_zero; // divider is 0;
reg v_time; // time base clock;
wire [31:0] sec_vtime; // read back value;
assign vtime_we = reg_write & rx_sec_vtime;
assign vtime_zero = (vtime_div == 7'd0);
always @(posedge sysclk)
begin
if(mi_reset_l == 1'b0)
vtime_val <= 7'd31;
else if(vtime_we)
vtime_val <= sys_wdata[7:1];
vtime_new <= vtime_we | ~mi_reset_l;
if(vtime_new | vtime_zero)
vtime_div <= vtime_val;
else
vtime_div <= vtime_div - 1;
if(~mi_reset_l | vtime_new)
v_time <= 1'b0;
else if(vtime_zero)
v_time <= ~v_time;
end
assign sec_vtime = { 15'd0, v_time, vtime_div, 1'b0, vtime_val, 1'b0 };
// virage interface;
// two 512bit (16x32) modules (v0, v1);
// one 2kbits (64x32) module (v2);
// sram shadows novea storage area;
// the 2kbit module must support uncached fetches;
// sram can operate at full sysclk speed;
// block requests are not supported, dropped or error;
// mi executes 32-bit access, independent of virage width;
// drive all virage controls from ff for timing;
wire [2:0] mi_vena; // virage enables;
reg mi_vwe; // virage write enable;
reg [2:0] sel_vmem; // select virage read data;
assign mi_vena[0] = acc_vmem & (mi_addr[17:16] == 2'b00);
assign mi_vena[1] = acc_vmem & (mi_addr[17:16] == 2'b01);
assign mi_vena[2] = acc_vmem & (mi_addr[17:16] == 2'b10);
always @(posedge sysclk)
begin
mi_vwe <= mi_write & acc_vmem;
sel_vmem <= mi_vena;
end
assign v_me = mi_vena;
assign v_we = {3{mi_vwe}};
assign v0_addr = mi_addr[15:2];
assign v1_addr = mi_addr[15:2];
assign v2_addr = mi_addr[15:2];
assign v0_in = mi_wdata;
assign v1_in = mi_wdata;
assign v2_in = mi_wdata;
// dp interrupt handling;
// for some reason, done in the mi, instead of the dp;
// detect falling edge of pipe_busy to issue dp interrupt;
// clear on reset and on write to MI_MODE with bit 11 set;
reg dp_busy; // delayed dp (pipe) busy;
wire dp_intr_clr; // clear dp interrupt;
wire dp_intr_set; // set dp interrupt;
reg dp_intr; // dp interrupt status;
assign dp_intr_clr = ~mi_reset_l | (reg_write & ra_mode & sys_wdata[11]);
assign dp_intr_set = ~pipe_busy & dp_busy;
always @(posedge sysclk)
begin
dp_busy <= pipe_busy;
dp_intr <= (~dp_intr_clr & dp_intr) | dp_intr_set;
end
// module presence change detection;
reg md_sts; // delayed fl_md;
wire md_chg; // change in module status;
reg md_intr; // module change interrupt;
wire md_clr; // clear md change interrupt;
assign md_chg = (md_sts != fl_md);
assign md_clr = reg_write & ra_eintr & sys_wdata[13];
assign sec_trig_md = sec_md_en & md_chg;
always @(posedge sysclk)
begin
md_sts <= fl_md;
md_intr <= mi_reset_l & ((~md_clr & md_intr) | md_chg);
end
// video control register;
// in mi because vi/ai are kept in reset from bit in avctrl;
reg [25:0] avctrl; // controls for video pll, encoder, dac;
always @(posedge sysclk)
begin
if(mi_reset_l == 1'b0)
avctrl <= 26'h010_0003;
else if(reg_write & ra_avctrl)
avctrl <= sys_wdata[25:0];
end
// register read mux;
// no test modes, so MI_MODE returns 0;
wire but_sts; // button status;
reg but_intr; // button interrupt;
wire [5:0] rcp_intr_sts; // compatible rcp interrupts;
wire [5:0] rcp_intr_mask; // compatible rcp intr mask;
wire [7:0] bcp_intr_sts; // new device interrupts;
wire [7:0] bcp_intr_mask; // new device intr mask;
reg [31:0] reg_rdata; // mi register read data;
assign rcp_intr_sts = { dp_intr, pi_intr, vi_intr, ai_intr, si_intr, sp_intr };
assign rcp_intr_mask = { dp_mask, pi_mask, vi_mask, ai_mask, si_mask, sp_mask };
assign bcp_intr_sts = { md_intr, but_intr, usb_intr,
pi_err_intr, pi_ide_intr, pi_aes_intr, pi_flc_intr };
assign bcp_intr_mask = { md_mask, but_mask, usb_mask,
pi_err_mask, pi_ide_mask, pi_aes_mask, pi_flc_mask };
always @(posedge sysclk)
begin
reg_rdata <= ({32{ra_version}} & version)
| ({32{ra_sintr}} & { 8'd0, 10'd0, 8'd0, rcp_intr_sts })
| ({32{ra_smask}} & { 8'd0, 10'd0, 8'd0, rcp_intr_mask })
| ({32{ra_eintr}} & { 6'd0, md_sts, but_sts, 10'd0, bcp_intr_sts, rcp_intr_sts })
| ({32{ra_emask}} & { 6'd0, 2'd0, 10'd0, bcp_intr_mask, rcp_intr_mask })
| ({32{ra_ctrl}} & { 12'd0, mi_ctrl[19:13], 2'd0, divmode, 8'd0 })
| ({32{rx_sec_mode}} & mi_sec_mode)
| ({32{rx_sec_timer}} & { stim_cnt, stim_val })
| ({32{rx_sec_vtime}} & sec_vtime)
| ({32{ra_err_addr}} & err_addr)
| ({32{ra_err_info}} & err_info)
| ({32{ra_err_data}} & err_data)
| ({32{ra_random}} & { 31'd0, mi_rbit[1] })
| ({32{ra_avctrl}} & { 6'd0, avctrl });
end
// mi internal read data select;
// and-or type to output 0 if nothing selected;
reg [31:0] mi_rdata; // mi read data;
always @(posedge sysclk)
begin
mi_rdata <= ({32{sel_reg}} & reg_rdata)
| ({32{sel_brom}} & brom_data)
| ({32{sel_bram}} & bram_rdata)
| ({32{sel_iram}} & iram_rdata)
| ({32{sel_vmem[0]}} & v0_out)
| ({32{sel_vmem[1]}} & v1_out)
| ({32{sel_vmem[2]}} & v2_out);
end
// sysad read data path;
// cbus_in is response data from cbus mux reg in arbiter;
// rwbuf_wo is data from rwbufs or mi registers;
// capture read data for debug interface;
assign sysad_in = sel_cbus? cbus_in : sel_mi? mi_rdata : rwbuf_wo;
always @(posedge sysclk)
begin
if(rsp_val)
dbg_rdata <= sysad_in;
end
// cpu interrupts;
// sum up all rcp interrupt sources;
// sum up all new device interrupts;
reg rcp_intr; // compatible rcp interupt;
reg dev_intr; // new device interrupts;
always @(posedge sysclk)
begin
rcp_intr <= (dp_mask & dp_intr)
| (pi_mask & pi_intr)
| (vi_mask & vi_intr)
| (ai_mask & ai_intr)
| (si_mask & si_intr)
| (sp_mask & sp_intr);
dev_intr <= (pi_flc_intr & pi_flc_mask)
| (pi_aes_intr & pi_aes_mask)
| (pi_ide_intr & (pi_ide_mask | en_ide_intr))
| (pi_err_intr & pi_err_mask)
| (usb_intr[0] & usb_mask[0])
| (usb_intr[1] & usb_mask[1])
| (md_intr & md_mask);
end
// synchronize button interrupt;
// pressing the button immediatedly asserts int[2];
// 0.5sec later, an nmi is issued to drop into secure kernel;
// timer ticks on jchan clocks from si;
// interrupt is cleared by clearing the mask;
// restart timer after secure mode trigger;
reg [2:0] but_sync; // metastability & edge detect flops;
reg but_clk; // buffered clock;
wire but_clr; // clear button timer;
reg [20:0] but_timer; // button pre-nmi timer;
assign but_clr = ~mi_reset_l | ~sec_but_en | but_timer[20];
assign but_sts = but_sync[2];
assign sec_trig_but = but_timer[20];
always @(posedge sysclk)
begin
but_sync <= { but_sync[1:0], button };
but_intr <= but_mask & (but_intr | but_sync[2]);
but_clk <= but_intr & jchan_clk;
if(but_clr)
but_timer <= 21'd0;
else if(but_clk)
but_timer <= but_timer + 1;
end
// wire cpu interrupts;
// int[0] is traditional rcp interrupt;
// int[1] was unused in N64, now is the new devices interrupt;
// int[2] was button interrupt from PIF, now from power/reset button;
// int[3] was unused in N64, now is the system error interrupt;
// int[4] was unused in N64, and stays unused;
assign int_l[0] = ~rcp_intr;
assign int_l[1] = ~dev_intr;
assign int_l[2] = ~but_intr;
assign int_l[3] = ~err_wei;
assign int_l[4] = 1'b1;
endmodule