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