1 /* Base class for devices that can generate hardware interrupts.
2    Copyright 2001, 2002 Brian R. Gaeke.
3    Copyright 2002, 2003 Paul Twohey.
4 
5 This file is part of VMIPS.
6 
7 VMIPS is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 2 of the License, or (at your
10 option) any later version.
11 
12 VMIPS is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 for more details.
16 
17 You should have received a copy of the GNU General Public License along
18 with VMIPS; if not, write to the Free Software Foundation, Inc.,
19 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
20 
21 #include "deviceint.h"
22 #include "options.h"
23 #include "vmips.h"
24 
25 extern vmips *machine;
26 
27 /* Given a value (LINE) representing one of the bits of the
28    Cause register (IRQ7 .. IRQ0 in deviceint.h), return
29    a string that describes the corresponding interrupt line.
30    The string is returned in a static buffer, so the next call
31    to strlineno will overwrite the result. */
strlineno(uint32 line)32 char *DeviceInt::strlineno(uint32 line)
33 {
34 	static char buff[50];
35 
36 	if (line == IRQ7) { sprintf(buff, "IRQ7"); }
37 	else if (line == IRQ6) { sprintf(buff, "IRQ6"); }
38 	else if (line == IRQ5) { sprintf(buff, "IRQ5"); }
39 	else if (line == IRQ4) { sprintf(buff, "IRQ4"); }
40 	else if (line == IRQ3) { sprintf(buff, "IRQ3"); }
41 	else if (line == IRQ2) { sprintf(buff, "IRQ2"); }
42 	else if (line == IRQ1) { sprintf(buff, "IRQ1"); }
43 	else if (line == IRQ0) { sprintf(buff, "IRQ0"); }
44 	else { sprintf(buff, "something strange (0x%08x)", line); }
45 	return buff;
46 }
47 
num2irq(uint32 num)48 uint32 DeviceInt::num2irq(uint32 num)
49 {
50 	switch (num) {
51 	case 0:
52 		return IRQ0;
53 	case 1:
54 		return IRQ1;
55 	case 2:
56 		return IRQ2;
57 	case 3:
58 		return IRQ3;
59 	case 4:
60 		return IRQ4;
61 	case 5:
62 		return IRQ5;
63 	case 6:
64 		return IRQ6;
65 	case 7:
66 		return IRQ7;
67 	default:
68 		return 0;
69 	}
70 }
71 
72 /* If the `reportirq' option is set, print a message to stderr
73    noting that LINE was asserted. */
reportAssert(uint32 line)74 void DeviceInt::reportAssert(uint32 line)
75 {
76 	if (opt_reportirq)
77 		fprintf(stderr, "%s asserted %s\n", descriptor_str(), strlineno(line));
78 }
79 
80 /* If the `reportirq' option is set, print a message to stderr
81    noting that LINE was asserted even though it was disconnected. */
reportAssertDisconnected(uint32 line)82 void DeviceInt::reportAssertDisconnected(uint32 line)
83 {
84 	if (opt_reportirq)
85 		fprintf(stderr, "%s asserted %s but it wasn't connected\n",
86 			descriptor_str(), strlineno(line));
87 }
88 
89 /* If the `reportirq' option is set, print a message to stderr
90    noting that LINE was deasserted. */
reportDeassert(uint32 line)91 void DeviceInt::reportDeassert(uint32 line)
92 {
93 	if (opt_reportirq)
94 		fprintf(stderr, "%s deasserted %s\n", descriptor_str(),
95 			strlineno(line));
96 }
97 
98 /* If the `reportirq' option is set, print a message to stderr
99    noting that LINE was deasserted even though it was disconnected. */
reportDeassertDisconnected(uint32 line)100 void DeviceInt::reportDeassertDisconnected(uint32 line)
101 {
102 	if (opt_reportirq)
103 		fprintf(stderr, "%s deasserted %s but it wasn't connected\n",
104 			descriptor_str(), strlineno(line));
105 }
106 
107 /* Assert an interrupt request on interrupt line LINE, which must be one
108    of the IRQ7 .. IRQ0 constants in deviceint.h. An interrupt thus asserted
109    remains asserted until it is explicitly deasserted. */
assertInt(uint32 line)110 void DeviceInt::assertInt(uint32 line)
111 {
112 	if (line & lines_connected) {
113 		if (! (line & lines_asserted)) reportAssert(line);
114 		lines_asserted |= line;
115 	} else {
116 		reportAssertDisconnected(line);
117 	}
118 }
119 
120 /* Deassert an interrupt request on interrupt line LINE, which must be one
121    of the IRQ7 .. IRQ0 constants in deviceint.h. Note that if one device
122    deasserts the interrupt request, that doesn't necessarily mean that
123    the interrupt line will go to zero; another device may be sharing the
124    same interrupt line. */
deassertInt(uint32 line)125 void DeviceInt::deassertInt(uint32 line)
126 {
127 	if (line & lines_connected) {
128 		if (line & lines_asserted) reportDeassert(line);
129 		lines_asserted &= ~line;
130 	} else {
131 		reportDeassertDisconnected(line);
132 	}
133 }
134 
135 /* Constructor. */
DeviceInt()136 DeviceInt::DeviceInt()
137 	: lines_connected(0), lines_asserted(0)
138 {
139 	opt_reportirq = machine->opt->option("reportirq")->flag;
140 }
141 
142