1 // license:BSD-3-Clause
2 // copyright-holders:David Haywood, Joakim Larsson Edstrom
3 /* 68340 SERIAL module */
4 
5 #include "emu.h"
6 #include "68340.h"
7 
8 //**************************************************************************
9 //  MACROS / CONSTANTS
10 //**************************************************************************
11 
12 //#define LOG_GENERAL (1U <<  0) // Already defined in logmacro.h
13 #define LOG_SETUP   (1U <<  1)
14 #define LOG_READ    (1U <<  2)
15 #define LOG_SERIAL  (1U <<  3)
16 #define LOG_INT     (1U <<  4)
17 
18 //#define VERBOSE  (LOG_SETUP|LOG_READ|LOG_SERIAL|LOG_INT)
19 #define LOG_OUTPUT_FUNC printf // Needs always to be enabled as the default value 'logerror' is not available here
20 
21 #include "logmacro.h"
22 
23 //#define LOG(...) LOGMASKED(LOG_GENERAL,   __VA_ARGS__) // Already defined in logmacro.h
24 #define LOGSETUP(...)  LOGMASKED(LOG_SETUP,  __VA_ARGS__)
25 #define LOGR(...)      LOGMASKED(LOG_READ,   __VA_ARGS__)
26 #define LOGSERIAL(...) LOGMASKED(LOG_SERIAL, __VA_ARGS__)
27 #define LOGINT(...)    LOGMASKED(LOG_INT,    __VA_ARGS__)
28 
29 #ifdef _MSC_VER
30 #define FUNCNAME __func__
31 #else
32 #define FUNCNAME __PRETTY_FUNCTION__
33 #endif
34 
device_start()35 void mc68340_serial_module_device::device_start()
36 {
37 	m_cpu = downcast<m68340_cpu_device *>(owner());
38 	mc68340_duart_device::device_start();
39 }
40 
read(offs_t offset)41 uint8_t mc68340_serial_module_device::read(offs_t offset)
42 {
43 	LOG("%s\n", FUNCNAME);
44 	int val = 0;
45 
46 	LOGR("%08x %s %08x\n", m_cpu->pcbase(), FUNCNAME, offset);
47 
48 	/*Setting the STP bit stops all clocks within the serial module (including the crystal
49 	  or external clock and SCLK), except for the clock from the IMB. The clock from the IMB
50 	  remains active to allow CPU32 access to the MCR. The clock stops on the low phase of the
51 	  clock and remains stopped until the STP bit is cleared by the CPU32 or a hardware reset.
52 	  Accesses to serial module registers while in stop mode produce a bus error.   */
53 	if ( (m_mcrh & REG_MCRH_STP) && offset != REG_MCRH && offset != REG_MCRL)
54 	{
55 		logerror("Attempt to access timer registers while timer clocks are stopped, STP bit in MCR is set!");
56 		return val; // TODO: Should cause BUSERROR
57 	}
58 
59 	switch (offset)
60 	{
61 	case REG_MCRH:
62 		val = m_mcrh;
63 		LOGSERIAL("- %08x %s %04x, %04x (MCRH - Module Configuration Register High byte)\n", m_cpu->pcbase(), FUNCNAME, offset, val);
64 		break;
65 	case REG_MCRL:
66 		val = m_mcrl;
67 		LOGSERIAL("- %08x %s %04x, %04x (MCRL - Module Configuration Register Low byte)\n", m_cpu->pcbase(), FUNCNAME, offset, val);
68 		break;
69 	case REG_ILR:
70 		val = m_ilr;
71 		LOGSERIAL("- %08x %s %04x, %04x (ILR - Interrupt Level Register)\n", m_cpu->pcbase(), FUNCNAME, offset, val);
72 		break;
73 	case REG_IVR:
74 		val = m_ivr;
75 		LOGSERIAL("- %08x %s %04x, %04x (IVR - Interrupt Vector Register)\n", m_cpu->pcbase(), FUNCNAME, offset, val);
76 		break;
77 	}
78 
79 
80 	LOGR(" * Reg %02x -> %02x - %s\n", offset, val,
81 		(offset > 0x21) ? "Error - should not happen" :
82 		 std::array<char const *, 0x22>
83 		 {{
84 		 "MCRH", "MCRL", "n/a",  "n/a",  "ILR",  "IVR",  "hole", "hole", // 0x00 - 0x07
85 		 "hole", "hole", "hole", "hole", "hole", "hole", "hole", "hole", // 0x08 - 0x0f
86 		 "MR1A", "SRA",  "n/a",  "RBA",  "IPCR", "ISR",  "n/a",  "n/a",  // 0x10 - 0x17
87 		 "MR1B", "SRB",  "n/a",  "RBB",  "n/a",  "IP",   "n/a",  "n/a",  // 0x18 - 0x1f
88 		 "MR2A", "MR2B" }}[offset]);                                     // 0x20 - 0x21
89 
90 	return offset >= 0x10 && offset < 0x22 ? mc68340_duart_device::read(offset - 0x10) : val;
91 }
92 
write(offs_t offset,uint8_t data)93 void mc68340_serial_module_device::write(offs_t offset, uint8_t data)
94 {
95 	LOG("\n%s\n", FUNCNAME);
96 	LOGSETUP(" * Reg %02x <- %02x - %s\n", offset, data,
97 		 (offset > 0x21) ? "Error - should not happen" :
98 		 std::array<char const *, 0x22>
99 		 {{
100 			 "MCRH", "MCRL", "n/a",  "n/a",  "ILR",  "IVR",  "hole", "hole", // 0x00 - 0x07
101 			 "hole", "hole", "hole", "hole", "hole", "hole", "hole", "hole", // 0x08 - 0x0f
102 			 "MR1A", "CSRA", "CRA",  "TBA",  "ACR",  "IER",  "n/a",  "n/a",  // 0x10 - 0x17
103 			 "MR1B", "CSRB", "CRB",  "TBB",  "n/a",  "OPCR", "OPS",  "OPR",  // 0x18 - 0x1f
104 			 "MR2A", "MR2B" }}[offset]);                                     // 0x20 - 0x21
105 
106 	/*Setting the STP bit stops all clocks within the serial module (including the crystal
107 	  or external clock and SCLK), except for the clock from the IMB. The clock from the IMB
108 	  remains active to allow CPU32 access to the MCR. The clock stops on the low phase of the
109 	  clock and remains stopped until the STP bit is cleared by the CPU32 or a hardware reset.
110 	  Accesses to serial module registers while in stop mode produce a bus error.   */
111 	if ( (m_mcrh & REG_MCRH_STP) && offset != REG_MCRH && offset != REG_MCRL)
112 	{
113 		logerror("Attempt to access timer registers while timer clocks are stopped, STP bit in MCR is set!");
114 		return; // TODO: Should cause BUSERROR
115 	}
116 
117 	switch (offset)
118 	{
119 	case REG_MCRH:
120 		m_mcrh = data;
121 		LOGSERIAL("PC: %08x %s %04x, %04x (MCRH - Module Configuration Register High byte)\n", m_cpu->pcbase(), FUNCNAME, offset, data);
122 		LOGSERIAL("- Clocks are %s\n", data & REG_MCRH_STP ? "stopped" : "running");
123 		LOGSERIAL("- Freeze signal %s - not implemented\n", data & REG_MCRH_FRZ1 ? "stops at character boundary" : "is ignored");
124 		LOGSERIAL("- CTS capture clock: %s - not implemented\n", data & REG_MCRH_ICCS ? "SCLK" : "Crystal");
125 		break;
126 	case REG_MCRL:
127 		m_mcrl = data;
128 		LOGSERIAL("PC: %08x %s %04x, %04x (MCRL - Module Configuration Register Low byte)\n", m_cpu->pcbase(), FUNCNAME, offset, data);
129 		LOGSERIAL("- Supervisor registers %s - not implemented\n", data & REG_MCRL_SUPV ? "requries supervisor privileges" : "can be accessed by user privileged software");
130 		LOGSERIAL("- Interrupt Arbitration level: %02x\n", data & REG_MCRL_ARBLV);
131 		break;
132 	case REG_ILR:
133 		m_ilr = data;
134 		LOGSERIAL("PC: %08x %s %04x, %04x (ILR - Interrupt Level Register)\n", m_cpu->pcbase(), FUNCNAME, offset, data);
135 		LOGSERIAL("- Interrupt Level: %02x\n", data & REG_ILR_MASK);
136 		m_cpu->update_ipl();
137 		break;
138 	case REG_IVR:
139 		m_ivr = data;
140 		LOGSERIAL("PC: %08x %s %04x, %04x (IVR - Interrupt Vector Register)\n", m_cpu->pcbase(), FUNCNAME, offset, data);
141 		LOGSERIAL("- Interrupt Vector: %02x\n", data);
142 		break;
143 	default:
144 		if (offset >= 0x10 && offset < 0x22) mc68340_duart_device::write(offset - 0x10, data);
145 	}
146 
147 }
148 
WRITE_LINE_MEMBER(mc68340_serial_module_device::irq_w)149 WRITE_LINE_MEMBER( mc68340_serial_module_device::irq_w )
150 {
151 	LOGINT("IRQ!\n%s\n", FUNCNAME);
152 	m_cpu->update_ipl();
153 }
154 
mc68340_serial_module_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)155 mc68340_serial_module_device::mc68340_serial_module_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
156   : mc68340_duart_device(mconfig, MC68340_SERIAL_MODULE, tag, owner, clock)
157 {
158 }
159 
module_reset()160 void mc68340_serial_module_device::module_reset()
161 {
162 	mc68340_duart_device::device_reset();
163 }
164 
165 DEFINE_DEVICE_TYPE(MC68340_SERIAL_MODULE, mc68340_serial_module_device, "mc68340sermod", "MC68340 Serial Module")
166