| Previous | 199869 Revisions | Next |
| r21685 Thursday 7th March, 2013 at 15:28:25 UTC by Curt Coder |
|---|
| Moved some files to where they belong. (nw) |
| [src/emu] | emu.mak |
| [src/emu/machine] | 74145.c* 74145.h* at29040a.c* at29040a.h* at45dbxx.c* at45dbxx.h* ay31015.c* ay31015.h* er59256.c* er59256.h* mc68328.c* mc68328.h* mc6843.c* mc6843.h* mc6846.c* mc6846.h* mc6854.c* mc6854.h* mm58274c.c* mm58274c.h* mos6530.c* mos6530.h* pcf8593.c* pcf8593.h* upd7002.c* upd7002.h* wd11c00_17.c* wd11c00_17.h* wd2010.c* wd2010.h* |
| [src/emu/video] | dl1416.c* dl1416.h* hd44352.c* hd44352.h* hd44780.c* hd44780.h* hd66421.c* hd66421.h* mc6847.c* mc6847.h* tms3556.c* tms3556.h* upd7220.c* upd7220.h* |
| [src/mess] | mess.mak |
| [src/mess/drivers] | c65.c |
| [src/mess/includes] | |
| [src/mess/machine] | |
| [src/mess/video] |
| r21684 | r21685 | |
|---|---|---|
| 151 | 151 | $(EMUMACHINE)/6840ptm.o \ |
| 152 | 152 | $(EMUMACHINE)/6850acia.o \ |
| 153 | 153 | $(EMUMACHINE)/68681.o \ |
| 154 | $(EMUMACHINE)/n68681.o \ | |
| 155 | 154 | $(EMUMACHINE)/74123.o \ |
| 155 | $(EMUMACHINE)/74145.o \ | |
| 156 | 156 | $(EMUMACHINE)/74148.o \ |
| 157 | 157 | $(EMUMACHINE)/74153.o \ |
| 158 | 158 | $(EMUMACHINE)/74181.o \ |
| r21684 | r21685 | |
| 169 | 169 | $(EMUMACHINE)/am9517a.o \ |
| 170 | 170 | $(EMUMACHINE)/amigafdc.o \ |
| 171 | 171 | $(EMUMACHINE)/at28c16.o \ |
| 172 | $(EMUMACHINE)/at29040a.o \ | |
| 173 | $(EMUMACHINE)/at45dbxx.o \ | |
| 174 | $(EMUMACHINE)/ay31015.o \ | |
| 172 | 175 | $(EMUMACHINE)/cdp1852.o \ |
| 173 | 176 | $(EMUMACHINE)/cdp1871.o \ |
| 174 | 177 | $(EMUMACHINE)/com8116.o \ |
| r21684 | r21685 | |
| 182 | 185 | $(EMUMACHINE)/e0516.o \ |
| 183 | 186 | $(EMUMACHINE)/eeprom.o \ |
| 184 | 187 | $(EMUMACHINE)/er2055.o \ |
| 188 | $(EMUMACHINE)/er59256.o \ | |
| 185 | 189 | $(EMUMACHINE)/f3853.o \ |
| 186 | 190 | $(EMUMACHINE)/fdc_pll.o \ |
| 187 | 191 | $(EMUMACHINE)/generic.o \ |
| r21684 | r21685 | |
| 204 | 208 | $(EMUMACHINE)/k033906.o \ |
| 205 | 209 | $(EMUMACHINE)/k053252.o \ |
| 206 | 210 | $(EMUMACHINE)/k056230.o \ |
| 211 | $(EMUMACHINE)/laserdsc.o \ | |
| 207 | 212 | $(EMUMACHINE)/latch8.o \ |
| 208 | $(EMUMACHINE)/laserdsc.o \ | |
| 209 | 213 | $(EMUMACHINE)/lc89510.o \ |
| 214 | $(EMUMACHINE)/ldpr8210.o \ | |
| 210 | 215 | $(EMUMACHINE)/ldstub.o \ |
| 211 | $(EMUMACHINE)/ldpr8210.o \ | |
| 212 | 216 | $(EMUMACHINE)/ldv1000.o \ |
| 213 | 217 | $(EMUMACHINE)/ldvp931.o \ |
| 214 | 218 | $(EMUMACHINE)/m6m80011ap.o \ |
| r21684 | r21685 | |
| 218 | 222 | $(EMUMACHINE)/mb87078.o \ |
| 219 | 223 | $(EMUMACHINE)/mc146818.o \ |
| 220 | 224 | $(EMUMACHINE)/mc2661.o \ |
| 225 | $(EMUMACHINE)/mc6843.o \ | |
| 226 | $(EMUMACHINE)/mc6846.o \ | |
| 221 | 227 | $(EMUMACHINE)/mc6852.o \ |
| 228 | $(EMUMACHINE)/mc6854.o \ | |
| 229 | $(EMUMACHINE)/mc68328.o \ | |
| 222 | 230 | $(EMUMACHINE)/mc68901.o \ |
| 223 | 231 | $(EMUMACHINE)/mccs1850.o \ |
| 232 | $(EMUMACHINE)/microtch.o \ | |
| 233 | $(EMUMACHINE)/mm58274c.o \ | |
| 224 | 234 | $(EMUMACHINE)/mm74c922.o \ |
| 225 | $(EMUMACHINE)/microtch.o \ | |
| 226 | 235 | $(EMUMACHINE)/mos6526.o \ |
| 227 | 236 | $(EMUMACHINE)/mos6529.o \ |
| 237 | $(EMUMACHINE)/mos6530.o \ | |
| 228 | 238 | $(EMUMACHINE)/mos6551.o \ |
| 229 | 239 | $(EMUMACHINE)/msm5832.o \ |
| 230 | 240 | $(EMUMACHINE)/msm58321.o \ |
| 231 | 241 | $(EMUMACHINE)/msm6242.o \ |
| 242 | $(EMUMACHINE)/n68681.o \ | |
| 232 | 243 | $(EMUMACHINE)/ncr539x.o \ |
| 244 | $(EMUMACHINE)/net_lib.o \ | |
| 233 | 245 | $(EMUMACHINE)/netlist.o \ |
| 234 | $(EMUMACHINE)/net_lib.o \ | |
| 235 | 246 | $(EMUMACHINE)/nmc9306.o \ |
| 236 | 247 | $(EMUMACHINE)/nscsi_bus.o \ |
| 237 | 248 | $(EMUMACHINE)/nscsi_cd.o \ |
| 238 | 249 | $(EMUMACHINE)/nscsi_hd.o \ |
| 239 | 250 | $(EMUMACHINE)/nvram.o \ |
| 240 | 251 | $(EMUMACHINE)/pc16552d.o \ |
| 252 | $(EMUMACHINE)/pcf8593.o \ | |
| 241 | 253 | $(EMUMACHINE)/pci.o \ |
| 242 | 254 | $(EMUMACHINE)/pd4990a.o \ |
| 243 | 255 | $(EMUMACHINE)/pic8259.o \ |
| r21684 | r21685 | |
| 251 | 263 | $(EMUMACHINE)/rtc4543.o \ |
| 252 | 264 | $(EMUMACHINE)/rtc65271.o \ |
| 253 | 265 | $(EMUMACHINE)/rtc9701.o \ |
| 266 | $(EMUMACHINE)/s3520cf.o \ | |
| 254 | 267 | $(EMUMACHINE)/s3c2400.o \ |
| 255 | 268 | $(EMUMACHINE)/s3c2410.o \ |
| 256 | 269 | $(EMUMACHINE)/s3c2440.o \ |
| 257 | $(EMUMACHINE)/s3520cf.o \ | |
| 258 | 270 | $(EMUMACHINE)/saturn.o \ |
| 259 | 271 | $(EMUMACHINE)/scsibus.o \ |
| 260 | 272 | $(EMUMACHINE)/scsicb.o \ |
| r21684 | r21685 | |
| 276 | 288 | $(EMUMACHINE)/tms9902.o \ |
| 277 | 289 | $(EMUMACHINE)/upd1990a.o \ |
| 278 | 290 | $(EMUMACHINE)/upd4701.o \ |
| 291 | $(EMUMACHINE)/upd7002.o \ | |
| 279 | 292 | $(EMUMACHINE)/upd7201.o \ |
| 280 | 293 | $(EMUMACHINE)/upd765.o \ |
| 281 | 294 | $(EMUMACHINE)/v3021.o \ |
| 295 | $(EMUMACHINE)/wd_fdc.o \ | |
| 296 | $(EMUMACHINE)/wd11c00_17.o \ | |
| 282 | 297 | $(EMUMACHINE)/wd17xx.o \ |
| 298 | $(EMUMACHINE)/wd2010.o \ | |
| 283 | 299 | $(EMUMACHINE)/wd33c93.o \ |
| 284 | $(EMUMACHINE)/wd_fdc.o \ | |
| 285 | 300 | $(EMUMACHINE)/x2212.o \ |
| 286 | 301 | $(EMUMACHINE)/x76f041.o \ |
| 287 | 302 | $(EMUMACHINE)/x76f100.o \ |
| r21684 | r21685 | |
| 298 | 313 | $(EMUVIDEO)/bufsprite.o \ |
| 299 | 314 | $(EMUVIDEO)/cdp1861.o \ |
| 300 | 315 | $(EMUVIDEO)/cdp1862.o \ |
| 316 | $(EMUVIDEO)/cgapal.o \ | |
| 301 | 317 | $(EMUVIDEO)/crt9007.o \ |
| 302 | 318 | $(EMUVIDEO)/crt9021.o \ |
| 303 | 319 | $(EMUVIDEO)/crt9212.o \ |
| 320 | $(EMUVIDEO)/dl1416.o \ | |
| 304 | 321 | $(EMUVIDEO)/dm9368.o \ |
| 305 | 322 | $(EMUVIDEO)/ef9340_1.o \ |
| 306 | 323 | $(EMUVIDEO)/generic.o \ |
| 307 | 324 | $(EMUVIDEO)/h63484.o \ |
| 308 | 325 | $(EMUVIDEO)/hd44102.o \ |
| 326 | $(EMUVIDEO)/hd44352.o \ | |
| 327 | $(EMUVIDEO)/hd44780.o \ | |
| 309 | 328 | $(EMUVIDEO)/hd61830.o \ |
| 310 | 329 | $(EMUVIDEO)/hd63484.o \ |
| 330 | $(EMUVIDEO)/hd66421.o \ | |
| 311 | 331 | $(EMUVIDEO)/huc6202.o \ |
| 312 | 332 | $(EMUVIDEO)/huc6260.o \ |
| 313 | 333 | $(EMUVIDEO)/huc6261.o \ |
| r21684 | r21685 | |
| 320 | 340 | $(EMUVIDEO)/m50458.o \ |
| 321 | 341 | $(EMUVIDEO)/mb90082.o \ |
| 322 | 342 | $(EMUVIDEO)/mc6845.o \ |
| 343 | $(EMUVIDEO)/mc6847.o \ | |
| 323 | 344 | $(EMUVIDEO)/msm6255.o \ |
| 324 | 345 | $(EMUVIDEO)/pc_cga.o \ |
| 325 | $(EMUVIDEO)/cgapal.o \ | |
| 326 | 346 | $(EMUVIDEO)/pc_vga.o \ |
| 327 | 347 | $(EMUVIDEO)/poly.o \ |
| 328 | 348 | $(EMUVIDEO)/psx.o \ |
| r21684 | r21685 | |
| 336 | 356 | $(EMUVIDEO)/stvvdp2.o \ |
| 337 | 357 | $(EMUVIDEO)/tlc34076.o \ |
| 338 | 358 | $(EMUVIDEO)/tms34061.o \ |
| 359 | $(EMUVIDEO)/tms3556.o \ | |
| 339 | 360 | $(EMUVIDEO)/tms9927.o \ |
| 340 | 361 | $(EMUVIDEO)/tms9928a.o \ |
| 341 | 362 | $(EMUVIDEO)/upd3301.o \ |
| 363 | $(EMUVIDEO)/upd7220.o \ | |
| 342 | 364 | $(EMUVIDEO)/v9938.o \ |
| 343 | 365 | $(EMUVIDEO)/vector.o \ |
| 344 | 366 | $(EMUVIDEO)/voodoo.o \ |
| r0 | r21685 | |
|---|---|---|
| 1 | /********************************************************************* | |
| 2 | ||
| 3 | Philips PCF8593 CMOS clock/calendar circuit | |
| 4 | ||
| 5 | (c) 2001-2007 Tim Schuerewegen | |
| 6 | ||
| 7 | *********************************************************************/ | |
| 8 | ||
| 9 | #include "pcf8593.h" | |
| 10 | ||
| 11 | ||
| 12 | /*************************************************************************** | |
| 13 | PARAMETERS/CONSTANTS/MACROS | |
| 14 | ***************************************************************************/ | |
| 15 | ||
| 16 | #define LOG_LEVEL 1 | |
| 17 | #define _logerror(level,x) do { if (LOG_LEVEL > level) logerror x; } while (0) | |
| 18 | ||
| 19 | // get/set date | |
| 20 | #define RTC_GET_DATE_YEAR ((m_data[5] >> 6) & 3) | |
| 21 | #define RTC_SET_DATE_YEAR(x) m_data[5] = (m_data[5] & 0x3F) | (((x) % 4) << 6) | |
| 22 | #define RTC_GET_DATE_MONTH bcd_to_integer( m_data[6]) | |
| 23 | #define RTC_SET_DATE_MONTH(x) m_data[6] = convert_to_bcd( x) | |
| 24 | #define RTC_GET_DATE_DAY (bcd_to_integer( m_data[5] & 0x3F)) | |
| 25 | #define RTC_SET_DATE_DAY(x) m_data[5] = (m_data[5] & 0xC0) | convert_to_bcd( x) | |
| 26 | ||
| 27 | // get/set time | |
| 28 | #define RTC_GET_TIME_HOUR bcd_to_integer( m_data[4]) | |
| 29 | #define RTC_SET_TIME_HOUR(x) m_data[4] = convert_to_bcd( x) | |
| 30 | #define RTC_GET_TIME_MINUTE bcd_to_integer( m_data[3]) | |
| 31 | #define RTC_SET_TIME_MINUTE(x) m_data[3] = convert_to_bcd( x) | |
| 32 | #define RTC_GET_TIME_SECOND bcd_to_integer( m_data[2]) | |
| 33 | #define RTC_SET_TIME_SECOND(x) m_data[2] = convert_to_bcd( x) | |
| 34 | ||
| 35 | ||
| 36 | //************************************************************************** | |
| 37 | // GLOBAL VARIABLES | |
| 38 | //************************************************************************** | |
| 39 | ||
| 40 | const device_type PCF8593 = &device_creator<pcf8593_device>; | |
| 41 | ||
| 42 | ||
| 43 | //------------------------------------------------- | |
| 44 | // pcf8593_device - constructor | |
| 45 | //------------------------------------------------- | |
| 46 | ||
| 47 | pcf8593_device::pcf8593_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) | |
| 48 | : device_t(mconfig, PCF8593, "PCF8593 RTC", tag, owner, clock), | |
| 49 | device_rtc_interface(mconfig, *this), | |
| 50 | device_nvram_interface(mconfig, *this) | |
| 51 | { | |
| 52 | } | |
| 53 | ||
| 54 | ||
| 55 | //------------------------------------------------- | |
| 56 | // device_start - device-specific startup | |
| 57 | //------------------------------------------------- | |
| 58 | ||
| 59 | void pcf8593_device::device_start() | |
| 60 | { | |
| 61 | _logerror( 0, ("pcf8593_init\n")); | |
| 62 | memset(m_register, 0, sizeof(m_register)); | |
| 63 | m_timer = timer_alloc(TIMER_UPDATE_COUNTER); | |
| 64 | m_timer->adjust(attotime::from_seconds(1), 0, attotime::from_seconds(1)); | |
| 65 | } | |
| 66 | ||
| 67 | //------------------------------------------------- | |
| 68 | // device_reset - device-specific reset | |
| 69 | //------------------------------------------------- | |
| 70 | ||
| 71 | void pcf8593_device::device_reset() | |
| 72 | { | |
| 73 | _logerror( 0, ("pcf8593_reset\n")); | |
| 74 | m_pin_scl = 1; | |
| 75 | m_pin_sda = 1; | |
| 76 | m_active = FALSE; | |
| 77 | m_inp = 0; | |
| 78 | m_mode = RTC_MODE_RECV; | |
| 79 | m_bits = 0; | |
| 80 | m_pos = 0; | |
| 81 | clear_buffer_rx(); | |
| 82 | set_time(true, RTC_GET_DATE_YEAR, RTC_GET_DATE_MONTH, RTC_GET_DATE_DAY, 0, RTC_GET_TIME_HOUR, RTC_GET_TIME_MINUTE, RTC_GET_TIME_SECOND); | |
| 83 | } | |
| 84 | ||
| 85 | ||
| 86 | //------------------------------------------------- | |
| 87 | // device_timer - handler timer events | |
| 88 | //------------------------------------------------- | |
| 89 | ||
| 90 | void pcf8593_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) | |
| 91 | { | |
| 92 | switch(id) | |
| 93 | { | |
| 94 | case TIMER_UPDATE_COUNTER: | |
| 95 | _logerror( 2, ("pcf8593_timer_callback (%d)\n", param)); | |
| 96 | // check if counting is enabled | |
| 97 | if (!(m_data[0] & 0x80)) | |
| 98 | advance_seconds(); | |
| 99 | break; | |
| 100 | } | |
| 101 | } | |
| 102 | ||
| 103 | ||
| 104 | //------------------------------------------------- | |
| 105 | // rtc_clock_updated - | |
| 106 | //------------------------------------------------- | |
| 107 | ||
| 108 | void pcf8593_device::rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second) | |
| 109 | { | |
| 110 | RTC_SET_TIME_SECOND(second); | |
| 111 | RTC_SET_TIME_MINUTE(minute); | |
| 112 | RTC_SET_TIME_HOUR(hour); | |
| 113 | RTC_SET_DATE_DAY(day); | |
| 114 | RTC_SET_DATE_MONTH(month); | |
| 115 | RTC_SET_DATE_YEAR(year); | |
| 116 | } | |
| 117 | ||
| 118 | ||
| 119 | //------------------------------------------------- | |
| 120 | // nvram_default - called to initialize NVRAM to | |
| 121 | // its default state | |
| 122 | //------------------------------------------------- | |
| 123 | ||
| 124 | void pcf8593_device::nvram_default() | |
| 125 | { | |
| 126 | memset(m_data, 0, sizeof(m_data)); | |
| 127 | } | |
| 128 | ||
| 129 | //------------------------------------------------- | |
| 130 | // nvram_read - called to read NVRAM from the | |
| 131 | // .nv file | |
| 132 | //------------------------------------------------- | |
| 133 | ||
| 134 | void pcf8593_device::nvram_read(emu_file &file) | |
| 135 | { | |
| 136 | file.read(m_data, sizeof(m_data)); | |
| 137 | } | |
| 138 | ||
| 139 | ||
| 140 | //------------------------------------------------- | |
| 141 | // nvram_write - called to write NVRAM to the | |
| 142 | // .nv file | |
| 143 | //------------------------------------------------- | |
| 144 | ||
| 145 | void pcf8593_device::nvram_write(emu_file &file) | |
| 146 | { | |
| 147 | file.write(m_data, sizeof(m_data)); | |
| 148 | } | |
| 149 | ||
| 150 | ||
| 151 | ||
| 152 | /*------------------------------------------------- | |
| 153 | pcf8593_pin_scl | |
| 154 | -------------------------------------------------*/ | |
| 155 | ||
| 156 | WRITE_LINE_MEMBER(pcf8593_device::scl_w) | |
| 157 | { | |
| 158 | // send bit | |
| 159 | if ((m_active) && (!m_pin_scl) && (state)) | |
| 160 | { | |
| 161 | switch (m_mode) | |
| 162 | { | |
| 163 | // HOST -> RTC | |
| 164 | case RTC_MODE_RECV : | |
| 165 | { | |
| 166 | // get bit | |
| 167 | if (m_pin_sda) m_data_recv[m_data_recv_index] = m_data_recv[m_data_recv_index] | (0x80 >> m_bits); | |
| 168 | m_bits++; | |
| 169 | // bit 9 = end | |
| 170 | if (m_bits > 8) | |
| 171 | { | |
| 172 | _logerror( 2, ("pcf8593_write_byte(%02X)\n", m_data_recv[m_data_recv_index])); | |
| 173 | // enter receive mode when 1st byte = 0xA3 | |
| 174 | if ((m_data_recv[0] == 0xA3) && (m_data_recv_index == 0)) | |
| 175 | { | |
| 176 | m_mode = RTC_MODE_SEND; | |
| 177 | } | |
| 178 | // A2 + xx = "read from pos xx" command | |
| 179 | if ((m_data_recv[0] == 0xA2) && (m_data_recv_index == 1)) | |
| 180 | { | |
| 181 | m_pos = m_data_recv[1]; | |
| 182 | } | |
| 183 | // A2 + xx + .. = write byte | |
| 184 | if ((m_data_recv[0] == 0xA2) && (m_data_recv_index >= 2)) | |
| 185 | { | |
| 186 | UINT8 rtc_pos, rtc_val; | |
| 187 | rtc_pos = m_data_recv[1] + (m_data_recv_index - 2); | |
| 188 | rtc_val = m_data_recv[m_data_recv_index]; | |
| 189 | //if (rtc_pos == 0) rtc_val = rtc_val & 3; // what is this doing here? | |
| 190 | m_data[rtc_pos] = rtc_val; | |
| 191 | set_time(false, RTC_GET_DATE_YEAR, RTC_GET_DATE_MONTH, RTC_GET_DATE_DAY, 0, RTC_GET_TIME_HOUR, RTC_GET_TIME_MINUTE, RTC_GET_TIME_SECOND); | |
| 192 | } | |
| 193 | // next byte | |
| 194 | m_bits = 0; | |
| 195 | m_data_recv_index++; | |
| 196 | } | |
| 197 | } | |
| 198 | break; | |
| 199 | // RTC -> HOST | |
| 200 | case RTC_MODE_SEND : | |
| 201 | { | |
| 202 | // set bit | |
| 203 | m_inp = (m_data[m_pos] >> (7 - m_bits)) & 1; | |
| 204 | m_bits++; | |
| 205 | // bit 9 = end | |
| 206 | if (m_bits > 8) | |
| 207 | { | |
| 208 | _logerror( 2, ("pcf8593_read_byte(%02X)\n", m_data[m_pos])); | |
| 209 | // end ? | |
| 210 | if (m_pin_sda) | |
| 211 | { | |
| 212 | _logerror( 2, ("pcf8593 end\n")); | |
| 213 | m_mode = RTC_MODE_RECV; | |
| 214 | clear_buffer_rx(); | |
| 215 | } | |
| 216 | // next byte | |
| 217 | m_bits = 0; | |
| 218 | m_pos++; | |
| 219 | } | |
| 220 | } | |
| 221 | break; | |
| 222 | } | |
| 223 | } | |
| 224 | // save scl | |
| 225 | m_pin_scl = state; | |
| 226 | } | |
| 227 | ||
| 228 | ||
| 229 | ||
| 230 | /*------------------------------------------------- | |
| 231 | pcf8593_pin_sda_w | |
| 232 | -------------------------------------------------*/ | |
| 233 | ||
| 234 | WRITE_LINE_MEMBER(pcf8593_device::sda_w) | |
| 235 | { | |
| 236 | // clock is high | |
| 237 | if (m_pin_scl) | |
| 238 | { | |
| 239 | // log init I2C | |
| 240 | if (state) _logerror( 1, ("pcf8593 init i2c\n")); | |
| 241 | // start condition (high to low when clock is high) | |
| 242 | if ((!state) && (m_pin_sda)) | |
| 243 | { | |
| 244 | _logerror( 1, ("pcf8593 start condition\n")); | |
| 245 | m_active = TRUE; | |
| 246 | m_bits = 0; | |
| 247 | m_data_recv_index = 0; | |
| 248 | clear_buffer_rx(); | |
| 249 | //m_pos = 0; | |
| 250 | } | |
| 251 | // stop condition (low to high when clock is high) | |
| 252 | if ((state) && (!m_pin_sda)) | |
| 253 | { | |
| 254 | _logerror( 1, ("pcf8593 stop condition\n")); | |
| 255 | m_active = FALSE; | |
| 256 | } | |
| 257 | } | |
| 258 | // save sda | |
| 259 | m_pin_sda = state; | |
| 260 | } | |
| 261 | ||
| 262 | ||
| 263 | ||
| 264 | /*------------------------------------------------- | |
| 265 | pcf8593_pin_sda_r | |
| 266 | -------------------------------------------------*/ | |
| 267 | ||
| 268 | READ_LINE_MEMBER(pcf8593_device::sda_r) | |
| 269 | { | |
| 270 | return m_inp; | |
| 271 | } | |
| 272 | ||
| 273 | ||
| 274 | ||
| 275 | /*------------------------------------------------- | |
| 276 | pcf8593_clear_buffer_rx | |
| 277 | -------------------------------------------------*/ | |
| 278 | ||
| 279 | void pcf8593_device::clear_buffer_rx() | |
| 280 | { | |
| 281 | memset(&m_data_recv[0], 0, sizeof( m_data_recv)); | |
| 282 | m_data_recv_index = 0; | |
| 283 | } |
| Added: svn:mime-type + text/plain Added: svn:eol-style + native |
| r0 | r21685 | |
|---|---|---|
| 1 | /********************************************************************* | |
| 2 | ||
| 3 | Philips PCF8593 CMOS clock/calendar circuit | |
| 4 | ||
| 5 | (c) 2001-2007 Tim Schuerewegen | |
| 6 | ||
| 7 | *********************************************************************/ | |
| 8 | ||
| 9 | #ifndef __PCF8593_H__ | |
| 10 | #define __PCF8593_H__ | |
| 11 | ||
| 12 | #include "emu.h" | |
| 13 | ||
| 14 | ||
| 15 | //************************************************************************** | |
| 16 | // INTERFACE CONFIGURATION MACROS | |
| 17 | //************************************************************************** | |
| 18 | ||
| 19 | #define MCFG_PCF8593_ADD(_tag) \ | |
| 20 | MCFG_DEVICE_ADD(_tag, PCF8593, 0) | |
| 21 | ||
| 22 | #define MCFG_PCF8593_REMOVE(_tag) \ | |
| 23 | MCFG_DEVICE_REMOVE(_tag) | |
| 24 | ||
| 25 | ||
| 26 | // ======================> pcf8593_device | |
| 27 | ||
| 28 | class pcf8593_device : public device_t, | |
| 29 | public device_rtc_interface, | |
| 30 | public device_nvram_interface | |
| 31 | { | |
| 32 | public: | |
| 33 | pcf8593_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); | |
| 34 | ||
| 35 | DECLARE_WRITE_LINE_MEMBER(scl_w); | |
| 36 | DECLARE_WRITE_LINE_MEMBER(sda_w); | |
| 37 | DECLARE_READ_LINE_MEMBER(sda_r); | |
| 38 | ||
| 39 | protected: | |
| 40 | // device-level overrides | |
| 41 | virtual void device_start(); | |
| 42 | virtual void device_reset(); | |
| 43 | virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); | |
| 44 | ||
| 45 | // device_rtc_interface overrides | |
| 46 | virtual bool rtc_feature_y2k() { return true; } | |
| 47 | virtual void rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second); | |
| 48 | ||
| 49 | // device_nvram_interface overrides | |
| 50 | virtual void nvram_default(); | |
| 51 | virtual void nvram_read(emu_file &file); | |
| 52 | virtual void nvram_write(emu_file &file); | |
| 53 | ||
| 54 | private: | |
| 55 | void clear_buffer_rx(); | |
| 56 | ||
| 57 | static const device_timer_id TIMER_UPDATE_COUNTER = 0; | |
| 58 | ||
| 59 | // internal state | |
| 60 | UINT8 m_data[16]; | |
| 61 | int m_pin_scl; | |
| 62 | int m_pin_sda; | |
| 63 | int m_inp; | |
| 64 | int m_active; | |
| 65 | int m_bits; | |
| 66 | UINT8 m_data_recv_index; | |
| 67 | UINT8 m_data_recv[50]; | |
| 68 | UINT8 m_mode; | |
| 69 | UINT8 m_pos; | |
| 70 | emu_timer * m_timer; | |
| 71 | enum { RTC_MODE_NONE, RTC_MODE_SEND, RTC_MODE_RECV }; | |
| 72 | }; | |
| 73 | ||
| 74 | // device type definition | |
| 75 | extern const device_type PCF8593; | |
| 76 | ||
| 77 | #endif /* __PCF8593_H__ */ |
| Added: svn:mime-type + text/plain Added: svn:eol-style + native |
| r0 | r21685 | |
|---|---|---|
| 1 | /********************************************************************** | |
| 2 | ||
| 3 | Copyright (C) Antoine Mine' 2007 | |
| 4 | ||
| 5 | Motorola 6843 Floppy Disk Controller emulation. | |
| 6 | ||
| 7 | **********************************************************************/ | |
| 8 | ||
| 9 | /* | |
| 10 | Main MC 6843 features are: | |
| 11 | - single density floppies | |
| 12 | - IBM 3740 compatible | |
| 13 | - DMA-able | |
| 14 | - high-level commands (including multi-sector read/write) | |
| 15 | ||
| 16 | CLONES: HD 46503S seems to be a clone of MC 6843 | |
| 17 | ||
| 18 | BUGS | |
| 19 | The driver was designed with Thomson computer emulation in mind | |
| 20 | (CD 90-015 5"1/4 floppy controller) and works in this context. | |
| 21 | It might work in other contexts but has currently shortcomings: | |
| 22 | - DMA is not emulated | |
| 23 | - Free-Format Read is not emulated | |
| 24 | - Free-Format Write only supports track formatting, in a specific | |
| 25 | format (FWF=1, Thomson-like sector formats) | |
| 26 | - very rough timing: basically, there is a fixed delay between | |
| 27 | a command request (CMR write) and its response (first byte | |
| 28 | available, seek complete, etc.); there is no delay between | |
| 29 | read / write | |
| 30 | */ | |
| 31 | ||
| 32 | ||
| 33 | #include "emu.h" | |
| 34 | #include "mc6843.h" | |
| 35 | #include "imagedev/flopdrv.h" | |
| 36 | ||
| 37 | ||
| 38 | /******************* parameters ******************/ | |
| 39 | ||
| 40 | #define VERBOSE 0 | |
| 41 | ||
| 42 | ||
| 43 | /******************* internal chip data structure ******************/ | |
| 44 | ||
| 45 | struct mc6843_t | |
| 46 | { | |
| 47 | /* interface */ | |
| 48 | const mc6843_interface* iface; | |
| 49 | ||
| 50 | /* registers */ | |
| 51 | UINT8 CTAR; /* current track */ | |
| 52 | UINT8 CMR; /* command */ | |
| 53 | UINT8 ISR; /* interrupt status */ | |
| 54 | UINT8 SUR; /* set-up */ | |
| 55 | UINT8 STRA; /* status */ | |
| 56 | UINT8 STRB; /* status */ | |
| 57 | UINT8 SAR; /* sector address */ | |
| 58 | UINT8 GCR; /* general count */ | |
| 59 | UINT8 CCR; /* CRC control */ | |
| 60 | UINT8 LTAR; /* logical address track (=track destination) */ | |
| 61 | ||
| 62 | /* internal state */ | |
| 63 | UINT8 drive; | |
| 64 | UINT8 side; | |
| 65 | UINT8 data[128]; /* sector buffer */ | |
| 66 | UINT32 data_size; /* size of data */ | |
| 67 | UINT32 data_idx; /* current read/write position in data */ | |
| 68 | UINT32 data_id; /* chrd_id for sector write */ | |
| 69 | UINT8 index_pulse; | |
| 70 | ||
| 71 | /* trigger delayed actions (bottom halves) */ | |
| 72 | emu_timer* timer_cont; | |
| 73 | ||
| 74 | }; | |
| 75 | ||
| 76 | ||
| 77 | ||
| 78 | /* macro-command numbers */ | |
| 79 | #define CMD_STZ 0x2 /* seek track zero */ | |
| 80 | #define CMD_SEK 0x3 /* seek */ | |
| 81 | #define CMD_SSR 0x4 /* single sector read */ | |
| 82 | #define CMD_SSW 0x5 /* single sector write */ | |
| 83 | #define CMD_RCR 0x6 /* read CRC */ | |
| 84 | #define CMD_SWD 0x7 /* single sector write with delete data mark */ | |
| 85 | #define CMD_MSW 0xd /* multiple sector write */ | |
| 86 | #define CMD_MSR 0xc /* multiple sector read */ | |
| 87 | #define CMD_FFW 0xb /* free format write */ | |
| 88 | #define CMD_FFR 0xa /* free format read */ | |
| 89 | ||
| 90 | /* coarse delays */ | |
| 91 | #define DELAY_SEEK attotime::from_usec( 100 ) /* track seek time */ | |
| 92 | #define DELAY_ADDR attotime::from_usec( 100 ) /* search-address time */ | |
| 93 | ||
| 94 | ||
| 95 | ||
| 96 | static const char *const mc6843_cmd[16] = | |
| 97 | { | |
| 98 | "---", "---", "STZ", "SEK", "SSR", "SSW", "RCR", "SWD", | |
| 99 | "---", "---", "FFR", "FFW", "MSR", "MSW", "---", "---", | |
| 100 | }; | |
| 101 | ||
| 102 | ||
| 103 | /******************* utility function and macros ********************/ | |
| 104 | ||
| 105 | #define LOG(x) do { if (VERBOSE) logerror x; } while (0) | |
| 106 | ||
| 107 | ||
| 108 | ||
| 109 | INLINE mc6843_t* get_safe_token( device_t *device ) | |
| 110 | { | |
| 111 | assert( device != NULL ); | |
| 112 | assert( device->type() == MC6843 ); | |
| 113 | return (mc6843_t*) downcast<mc6843_device *>(device)->token(); | |
| 114 | } | |
| 115 | ||
| 116 | ||
| 117 | /************************** floppy interface ****************************/ | |
| 118 | ||
| 119 | ||
| 120 | ||
| 121 | static device_t* mc6843_floppy_image ( device_t *device ) | |
| 122 | { | |
| 123 | mc6843_t* mc6843 = get_safe_token( device ); | |
| 124 | return floppy_get_device( device->machine(), mc6843->drive ); | |
| 125 | } | |
| 126 | ||
| 127 | ||
| 128 | ||
| 129 | void mc6843_set_drive( device_t *device, int drive ) | |
| 130 | { | |
| 131 | mc6843_t* mc6843 = get_safe_token( device ); | |
| 132 | mc6843->drive = drive; | |
| 133 | } | |
| 134 | ||
| 135 | ||
| 136 | ||
| 137 | void mc6843_set_side( device_t *device, int side ) | |
| 138 | { | |
| 139 | mc6843_t* mc6843 = get_safe_token( device ); | |
| 140 | mc6843->side = side; | |
| 141 | } | |
| 142 | ||
| 143 | ||
| 144 | ||
| 145 | /* called after ISR or STRB has changed */ | |
| 146 | static void mc6843_status_update( device_t *device ) | |
| 147 | { | |
| 148 | mc6843_t* mc6843 = get_safe_token( device ); | |
| 149 | int irq = 0; | |
| 150 | ||
| 151 | /* ISR3 */ | |
| 152 | if ( (mc6843->CMR & 0x40) || ! mc6843->STRB ) | |
| 153 | mc6843->ISR &= ~8; | |
| 154 | else | |
| 155 | mc6843->ISR |= 8; | |
| 156 | ||
| 157 | /* interrupts */ | |
| 158 | if ( mc6843->ISR & 4 ) | |
| 159 | irq = 1; /* unmaskable */ | |
| 160 | if ( ! (mc6843->CMR & 0x80) ) | |
| 161 | { | |
| 162 | /* maskable */ | |
| 163 | if ( mc6843->ISR & ~4 ) | |
| 164 | irq = 1; | |
| 165 | } | |
| 166 | ||
| 167 | if ( mc6843->iface->irq_func ) | |
| 168 | { | |
| 169 | mc6843->iface->irq_func( device, irq ); | |
| 170 | LOG(( "mc6843_status_update: irq=%i (CMR=%02X, ISR=%02X)\n", irq, mc6843->CMR, mc6843->ISR )); | |
| 171 | } | |
| 172 | } | |
| 173 | ||
| 174 | ||
| 175 | void mc6843_set_index_pulse ( device_t *device, int index_pulse ) | |
| 176 | { | |
| 177 | mc6843_t* mc6843 = get_safe_token( device ); | |
| 178 | mc6843->index_pulse = index_pulse; | |
| 179 | } | |
| 180 | ||
| 181 | ||
| 182 | /* called at end of command */ | |
| 183 | static void mc6843_cmd_end( device_t *device ) | |
| 184 | { | |
| 185 | mc6843_t* mc6843 = get_safe_token( device ); | |
| 186 | int cmd = mc6843->CMR & 0x0f; | |
| 187 | if ( ( cmd == CMD_STZ ) || ( cmd == CMD_SEK ) ) | |
| 188 | { | |
| 189 | mc6843->ISR |= 0x02; /* set Settling Time Complete */ | |
| 190 | } | |
| 191 | else | |
| 192 | { | |
| 193 | mc6843->ISR |= 0x01; /* set Macro Command Complete */ | |
| 194 | } | |
| 195 | mc6843->STRA &= ~0x80; /* clear Busy */ | |
| 196 | mc6843->CMR &= 0xf0; /* clear command */ | |
| 197 | mc6843_status_update( device ); | |
| 198 | } | |
| 199 | ||
| 200 | ||
| 201 | ||
| 202 | /* Seek Track Zero bottom half */ | |
| 203 | static void mc6843_finish_STZ( device_t *device ) | |
| 204 | { | |
| 205 | mc6843_t* mc6843 = get_safe_token( device ); | |
| 206 | device_t* img = mc6843_floppy_image( device ); | |
| 207 | int i; | |
| 208 | ||
| 209 | /* seek to track zero */ | |
| 210 | for ( i=0; i<83; i++ ) | |
| 211 | { | |
| 212 | if (floppy_tk00_r(img) == CLEAR_LINE) | |
| 213 | break; | |
| 214 | floppy_drive_seek( img, -1 ); | |
| 215 | } | |
| 216 | ||
| 217 | LOG(( "%f mc6843_finish_STZ: actual=%i\n", device->machine().time().as_double(), floppy_drive_get_current_track( img ) )); | |
| 218 | ||
| 219 | /* update state */ | |
| 220 | mc6843->CTAR = 0; | |
| 221 | mc6843->GCR = 0; | |
| 222 | mc6843->SAR = 0; | |
| 223 | mc6843->STRB |= floppy_tk00_r(img) << 4; | |
| 224 | ||
| 225 | mc6843_cmd_end( device ); | |
| 226 | } | |
| 227 | ||
| 228 | ||
| 229 | ||
| 230 | /* Seek bottom half */ | |
| 231 | static void mc6843_finish_SEK( device_t *device ) | |
| 232 | { | |
| 233 | mc6843_t* mc6843 = get_safe_token( device ); | |
| 234 | device_t* img = mc6843_floppy_image( device ); | |
| 235 | ||
| 236 | /* seek to track */ | |
| 237 | floppy_drive_seek( img, mc6843->GCR - mc6843->CTAR ); | |
| 238 | ||
| 239 | LOG(( "%f mc6843_finish_SEK: from %i to %i (actual=%i)\n", device->machine().time().as_double(), mc6843->CTAR, mc6843->GCR, floppy_drive_get_current_track( img ) )); | |
| 240 | ||
| 241 | /* update state */ | |
| 242 | mc6843->CTAR = mc6843->GCR; | |
| 243 | mc6843->SAR = 0; | |
| 244 | mc6843_cmd_end( device ); | |
| 245 | } | |
| 246 | ||
| 247 | ||
| 248 | ||
| 249 | /* preamble to all sector read / write commands, returns 1 if found */ | |
| 250 | static int mc6843_address_search( device_t *device, chrn_id* id ) | |
| 251 | { | |
| 252 | mc6843_t* mc6843 = get_safe_token( device ); | |
| 253 | device_t* img = mc6843_floppy_image( device ); | |
| 254 | int r = 0; | |
| 255 | ||
| 256 | while ( 1 ) | |
| 257 | { | |
| 258 | if ( ( ! floppy_drive_get_next_id( img, mc6843->side, id ) ) || ( id->flags & ID_FLAG_CRC_ERROR_IN_ID_FIELD ) || ( id->N != 0 ) ) | |
| 259 | { | |
| 260 | /* read address error */ | |
| 261 | LOG(( "%f mc6843_address_search: get_next_id failed\n", device->machine().time().as_double() )); | |
| 262 | mc6843->STRB |= 0x0a; /* set CRC error & Sector Address Undetected */ | |
| 263 | mc6843_cmd_end( device ); | |
| 264 | return 0; | |
| 265 | } | |
| 266 | ||
| 267 | if ( id->C != mc6843->LTAR ) | |
| 268 | { | |
| 269 | /* track mismatch */ | |
| 270 | LOG(( "%f mc6843_address_search: track mismatch: logical=%i real=%i\n", device->machine().time().as_double(), mc6843->LTAR, id->C )); | |
| 271 | mc6843->data[0] = id->C; /* make the track number available to the CPU */ | |
| 272 | mc6843->STRA |= 0x20; /* set Track Not Equal */ | |
| 273 | mc6843_cmd_end( device ); | |
| 274 | return 0; | |
| 275 | } | |
| 276 | ||
| 277 | if ( id->R == mc6843->SAR ) | |
| 278 | { | |
| 279 | /* found! */ | |
| 280 | LOG(( "%f mc6843_address_search: sector %i found on track %i\n", device->machine().time().as_double(), id->R, id->C )); | |
| 281 | if ( ! (mc6843->CMR & 0x20) ) | |
| 282 | { | |
| 283 | mc6843->ISR |= 0x04; /* if no DMA, set Status Sense */ | |
| 284 | } | |
| 285 | return 1; | |
| 286 | } | |
| 287 | ||
| 288 | if ( floppy_drive_get_flag_state( img, FLOPPY_DRIVE_INDEX ) ) | |
| 289 | { | |
| 290 | r++; | |
| 291 | if ( r >= 4 ) | |
| 292 | { | |
| 293 | /* time-out after 3 full revolutions */ | |
| 294 | LOG(( "%f mc6843_address_search: no sector %i found after 3 revolutions\n", device->machine().time().as_double(), mc6843->SAR )); | |
| 295 | mc6843->STRB |= 0x08; /* set Sector Address Undetected */ | |
| 296 | mc6843_cmd_end( device ); | |
| 297 | return 0; | |
| 298 | } | |
| 299 | } | |
| 300 | } | |
| 301 | ||
| 302 | return 0; /* unreachable */ | |
| 303 | } | |
| 304 | ||
| 305 | ||
| 306 | ||
| 307 | /* preamble specific to read commands (adds extra checks) */ | |
| 308 | static int mc6843_address_search_read( device_t *device, chrn_id* id ) | |
| 309 | { | |
| 310 | mc6843_t* mc6843 = get_safe_token( device ); | |
| 311 | if ( ! mc6843_address_search( device, id ) ) | |
| 312 | return 0; | |
| 313 | ||
| 314 | if ( id->flags & ID_FLAG_CRC_ERROR_IN_DATA_FIELD ) | |
| 315 | { | |
| 316 | LOG(( "%f mc6843_address_search_read: data CRC error\n", device->machine().time().as_double() )); | |
| 317 | mc6843->STRB |= 0x06; /* set CRC error & Data Mark Undetected */ | |
| 318 | mc6843_cmd_end( device ); | |
| 319 | return 0; | |
| 320 | } | |
| 321 | ||
| 322 | if ( id->flags & ID_FLAG_DELETED_DATA ) | |
| 323 | { | |
| 324 | LOG(( "%f mc6843_address_search_read: deleted data\n", device->machine().time().as_double() )); | |
| 325 | mc6843->STRA |= 0x02; /* set Delete Data Mark Detected */ | |
| 326 | } | |
| 327 | ||
| 328 | return 1; | |
| 329 | } | |
| 330 | ||
| 331 | ||
| 332 | ||
| 333 | ||
| 334 | /* Read CRC bottom half */ | |
| 335 | static void mc6843_finish_RCR( device_t *device ) | |
| 336 | { | |
| 337 | chrn_id id; | |
| 338 | if ( ! mc6843_address_search_read( device, &id ) ) | |
| 339 | return; | |
| 340 | mc6843_cmd_end( device ); | |
| 341 | } | |
| 342 | ||
| 343 | ||
| 344 | ||
| 345 | /* Single / Multiple Sector Read bottom half */ | |
| 346 | static void mc6843_cont_SR( device_t *device ) | |
| 347 | { | |
| 348 | mc6843_t* mc6843 = get_safe_token( device ); | |
| 349 | chrn_id id; | |
| 350 | device_t* img = mc6843_floppy_image( device ); | |
| 351 | ||
| 352 | /* sector seek */ | |
| 353 | if ( ! mc6843_address_search_read( device, &id ) ) | |
| 354 | return; | |
| 355 | ||
| 356 | /* sector read */ | |
| 357 | floppy_drive_read_sector_data( img, mc6843->side, id.data_id, mc6843->data, 128 ); | |
| 358 | mc6843->data_idx = 0; | |
| 359 | mc6843->data_size = 128; | |
| 360 | mc6843->STRA |= 0x01; /* set Data Transfer Request */ | |
| 361 | mc6843_status_update( device ); | |
| 362 | } | |
| 363 | ||
| 364 | ||
| 365 | ||
| 366 | /* Single / Multiple Sector Write bottom half */ | |
| 367 | static void mc6843_cont_SW( device_t *device ) | |
| 368 | { | |
| 369 | mc6843_t* mc6843 = get_safe_token( device ); | |
| 370 | chrn_id id; | |
| 371 | ||
| 372 | /* sector seek */ | |
| 373 | if ( ! mc6843_address_search( device, &id ) ) | |
| 374 | return; | |
| 375 | ||
| 376 | /* setup sector write buffer */ | |
| 377 | mc6843->data_idx = 0; | |
| 378 | mc6843->data_size = 128; | |
| 379 | mc6843->STRA |= 0x01; /* set Data Transfer Request */ | |
| 380 | mc6843->data_id = id.data_id; /* for subsequent write sector command */ | |
| 381 | mc6843_status_update( device ); | |
| 382 | } | |
| 383 | ||
| 384 | ||
| 385 | ||
| 386 | /* bottom halves, called to continue / finish a command after some delay */ | |
| 387 | static TIMER_CALLBACK( mc6843_cont ) | |
| 388 | { | |
| 389 | device_t* device = (device_t*) ptr; | |
| 390 | mc6843_t* mc6843 = get_safe_token( device ); | |
| 391 | int cmd = mc6843->CMR & 0x0f; | |
| 392 | ||
| 393 | LOG(( "%f mc6843_cont: timer called for cmd=%s(%i)\n", device->machine().time().as_double(), mc6843_cmd[cmd], cmd )); | |
| 394 | ||
| 395 | mc6843->timer_cont->adjust( attotime::never ); | |
| 396 | ||
| 397 | switch ( cmd ) | |
| 398 | { | |
| 399 | case CMD_STZ: mc6843_finish_STZ( device ); break; | |
| 400 | case CMD_SEK: mc6843_finish_SEK( device ); break; | |
| 401 | case CMD_SSR: mc6843_cont_SR( device ); break; | |
| 402 | case CMD_SSW: mc6843_cont_SW( device ); break; | |
| 403 | case CMD_RCR: mc6843_finish_RCR( device ); break; | |
| 404 | case CMD_SWD: mc6843_cont_SW( device ); break; | |
| 405 | case CMD_MSW: mc6843_cont_SW( device ); break; | |
| 406 | case CMD_MSR: mc6843_cont_SR( device ); break; | |
| 407 | } | |
| 408 | } | |
| 409 | ||
| 410 | ||
| 411 | ||
| 412 | /************************** CPU interface ****************************/ | |
| 413 | ||
| 414 | ||
| 415 | ||
| 416 | READ8_DEVICE_HANDLER ( mc6843_r ) | |
| 417 | { | |
| 418 | mc6843_t* mc6843 = get_safe_token( device ); | |
| 419 | UINT8 data = 0; | |
| 420 | ||
| 421 | switch ( offset ) { | |
| 422 | case 0: /* Data Input Register (DIR) */ | |
| 423 | { | |
| 424 | int cmd = mc6843->CMR & 0x0f; | |
| 425 | ||
| 426 | LOG(( "%f $%04x mc6843_r: data input cmd=%s(%i), pos=%i/%i, GCR=%i, ", | |
| 427 | space.machine().time().as_double(), space.machine().firstcpu->pcbase( ), | |
| 428 | mc6843_cmd[cmd], cmd, mc6843->data_idx, | |
| 429 | mc6843->data_size, mc6843->GCR )); | |
| 430 | ||
| 431 | if ( cmd == CMD_SSR || cmd == CMD_MSR ) | |
| 432 | { | |
| 433 | /* sector read */ | |
| 434 | assert( mc6843->data_size > 0 ); | |
| 435 | assert( mc6843->data_idx < mc6843->data_size ); | |
| 436 | assert( mc6843->data_idx < sizeof(mc6843->data) ); | |
| 437 | data = mc6843->data[ mc6843->data_idx ]; | |
| 438 | mc6843->data_idx++; | |
| 439 | ||
| 440 | if ( mc6843->data_idx >= mc6843->data_size ) | |
| 441 | { | |
| 442 | /* end of sector read */ | |
| 443 | ||
| 444 | mc6843->STRA &= ~0x01; /* clear Data Transfer Request */ | |
| 445 | ||
| 446 | if ( cmd == CMD_MSR ) | |
| 447 | { | |
| 448 | /* schedule next sector in multiple sector read */ | |
| 449 | mc6843->GCR--; | |
| 450 | mc6843->SAR++; | |
| 451 | if ( mc6843->GCR == 0xff ) | |
| 452 | { | |
| 453 | mc6843_cmd_end( device ); | |
| 454 | } | |
| 455 | else if ( mc6843->SAR > 26 ) | |
| 456 | ||
| 457 | { | |
| 458 | mc6843->STRB |= 0x08; /* set Sector Address Undetected */ | |
| 459 | mc6843_cmd_end( device ); | |
| 460 | } | |
| 461 | else | |
| 462 | { | |
| 463 | mc6843->timer_cont->adjust( DELAY_ADDR ); | |
| 464 | } | |
| 465 | } | |
| 466 | else | |
| 467 | { | |
| 468 | mc6843_cmd_end( device ); | |
| 469 | } | |
| 470 | } | |
| 471 | } | |
| 472 | else if ( cmd == 0 ) | |
| 473 | { | |
| 474 | data = mc6843->data[0]; | |
| 475 | } | |
| 476 | else | |
| 477 | { | |
| 478 | /* XXX TODO: other read modes */ | |
| 479 | data = mc6843->data[0]; | |
| 480 | logerror( "$%04x mc6843 read in unsupported command mode %i\n", space.machine().firstcpu->pcbase( ), cmd ); | |
| 481 | } | |
| 482 | ||
| 483 | LOG(( "data=%02X\n", data )); | |
| 484 | ||
| 485 | break; | |
| 486 | } | |
| 487 | ||
| 488 | case 1: /* Current-Track Address Register (CTAR) */ | |
| 489 | data = mc6843->CTAR; | |
| 490 | LOG(( "%f $%04x mc6843_r: read CTAR %i (actual=%i)\n", | |
| 491 | space.machine().time().as_double(), space.machine().firstcpu->pcbase( ), data, | |
| 492 | floppy_drive_get_current_track( mc6843_floppy_image( device ) ) )); | |
| 493 | break; | |
| 494 | ||
| 495 | case 2: /* Interrupt Status Register (ISR) */ | |
| 496 | data = mc6843->ISR; | |
| 497 | LOG(( "%f $%04x mc6843_r: read ISR %02X: cmd=%scomplete settle=%scomplete sense-rq=%i STRB=%i\n", | |
| 498 | space.machine().time().as_double(), space.machine().firstcpu->pcbase( ), data, | |
| 499 | (data & 1) ? "" : "not-" , (data & 2) ? "" : "not-", | |
| 500 | (data >> 2) & 1, (data >> 3) & 1 )); | |
| 501 | ||
| 502 | /* reset */ | |
| 503 | mc6843->ISR &= 8; /* keep STRB */ | |
| 504 | mc6843_status_update( device ); | |
| 505 | break; | |
| 506 | ||
| 507 | case 3: /* Status Register A (STRA) */ | |
| 508 | { | |
| 509 | /* update */ | |
| 510 | device_t* img = mc6843_floppy_image( device ); | |
| 511 | int flag = floppy_drive_get_flag_state( img, FLOPPY_DRIVE_READY); | |
| 512 | mc6843->STRA &= 0xa3; | |
| 513 | if ( flag & FLOPPY_DRIVE_READY ) | |
| 514 | mc6843->STRA |= 0x04; | |
| 515 | ||
| 516 | mc6843->STRA |= !floppy_tk00_r(img) << 3; | |
| 517 | mc6843->STRA |= !floppy_wpt_r(img) << 4; | |
| 518 | ||
| 519 | if ( mc6843->index_pulse ) | |
| 520 | mc6843->STRA |= 0x40; | |
| 521 | ||
| 522 | data = mc6843->STRA; | |
| 523 | LOG(( "%f $%04x mc6843_r: read STRA %02X: data-rq=%i del-dta=%i ready=%i t0=%i wp=%i trk-dif=%i idx=%i busy=%i\n", | |
| 524 | space.machine().time().as_double(), space.machine().firstcpu->pcbase( ), data, | |
| 525 | data & 1, (data >> 1) & 1, (data >> 2) & 1, (data >> 3) & 1, | |
| 526 | (data >> 4) & 1, (data >> 5) & 1, (data >> 6) & 1, (data >> 7) & 1 )); | |
| 527 | break; | |
| 528 | } | |
| 529 | ||
| 530 | case 4: /* Status Register B (STRB) */ | |
| 531 | data = mc6843->STRB; | |
| 532 | LOG(( "%f $%04x mc6843_r: read STRB %02X: data-err=%i CRC-err=%i dta--mrk-err=%i sect-mrk-err=%i seek-err=%i fi=%i wr-err=%i hard-err=%i\n", | |
| 533 | space.machine().time().as_double(), space.machine().firstcpu->pcbase( ), data, | |
| 534 | data & 1, (data >> 1) & 1, (data >> 2) & 1, (data >> 3) & 1, | |
| 535 | (data >> 4) & 1, (data >> 5) & 1, (data >> 6) & 1, (data >> 7) & 1 )); | |
| 536 | ||
| 537 | /* (partial) reset */ | |
| 538 | mc6843->STRB &= ~0xfb; | |
| 539 | mc6843_status_update( device ); | |
| 540 | break; | |
| 541 | ||
| 542 | case 7: /* Logical-Track Address Register (LTAR) */ | |
| 543 | data = mc6843->LTAR; | |
| 544 | LOG(( "%f $%04x mc6843_r: read LTAR %i (actual=%i)\n", | |
| 545 | space.machine().time().as_double(), space.machine().firstcpu->pcbase( ), data, | |
| 546 | floppy_drive_get_current_track( mc6843_floppy_image( device ) ) )); | |
| 547 | break; | |
| 548 | ||
| 549 | default: | |
| 550 | logerror( "$%04x mc6843 invalid read offset %i\n", space.machine().firstcpu->pcbase( ), offset ); | |
| 551 | } | |
| 552 | ||
| 553 | return data; | |
| 554 | } | |
| 555 | ||
| 556 | WRITE8_DEVICE_HANDLER ( mc6843_w ) | |
| 557 | { | |
| 558 | mc6843_t* mc6843 = get_safe_token( device ); | |
| 559 | switch ( offset ) { | |
| 560 | case 0: /* Data Output Register (DOR) */ | |
| 561 | { | |
| 562 | int cmd = mc6843->CMR & 0x0f; | |
| 563 | int FWF = (mc6843->CMR >> 4) & 1; | |
| 564 | ||
| 565 | LOG(( "%f $%04x mc6843_w: data output cmd=%s(%i), pos=%i/%i, GCR=%i, data=%02X\n", | |
| 566 | space.machine().time().as_double(), space.machine().firstcpu->pcbase( ), | |
| 567 | mc6843_cmd[cmd], cmd, mc6843->data_idx, | |
| 568 | mc6843->data_size, mc6843->GCR, data )); | |
| 569 | ||
| 570 | if ( cmd == CMD_SSW || cmd == CMD_MSW || cmd == CMD_SWD ) | |
| 571 | { | |
| 572 | /* sector write */ | |
| 573 | assert( mc6843->data_size > 0 ); | |
| 574 | assert( mc6843->data_idx < mc6843->data_size ); | |
| 575 | assert( mc6843->data_idx < sizeof(mc6843->data) ); | |
| 576 | mc6843->data[ mc6843->data_idx ] = data; | |
| 577 | mc6843->data_idx++; | |
| 578 | if ( mc6843->data_idx >= mc6843->data_size ) | |
| 579 | { | |
| 580 | /* end of sector write */ | |
| 581 | device_t* img = mc6843_floppy_image( device ); | |
| 582 | ||
| 583 | LOG(( "%f $%04x mc6843_w: write sector %i\n", space.machine().time().as_double(), space.machine().firstcpu->pcbase( ), mc6843->data_id )); | |
| 584 | ||
| 585 | floppy_drive_write_sector_data( | |
| 586 | img, mc6843->side, mc6843->data_id, | |
| 587 | mc6843->data, mc6843->data_size, | |
| 588 | (cmd == CMD_SWD) ? ID_FLAG_DELETED_DATA : 0 ); | |
| 589 | ||
| 590 | mc6843->STRA &= ~0x01; /* clear Data Transfer Request */ | |
| 591 | ||
| 592 | if ( cmd == CMD_MSW ) | |
| 593 | { | |
| 594 | mc6843->GCR--; | |
| 595 | mc6843->SAR++; | |
| 596 | if ( mc6843->GCR == 0xff ) | |
| 597 | { | |
| 598 | mc6843_cmd_end( device ); | |
| 599 | } | |
| 600 | else if ( mc6843->SAR > 26 ) | |
| 601 | ||
| 602 | { | |
| 603 | mc6843->STRB |= 0x08; /* set Sector Address Undetected */ | |
| 604 | mc6843_cmd_end( device ); | |
| 605 | } | |
| 606 | else | |
| 607 | { | |
| 608 | mc6843->timer_cont->adjust( DELAY_ADDR ); | |
| 609 | } | |
| 610 | } | |
| 611 | else | |
| 612 | { | |
| 613 | mc6843_cmd_end( device ); | |
| 614 | } | |
| 615 | } | |
| 616 | } | |
| 617 | else if ( (cmd == CMD_FFW) && FWF ) | |
| 618 | { | |
| 619 | /* assume we are formatting */ | |
| 620 | UINT8 nibble; | |
| 621 | nibble = | |
| 622 | (data & 0x01) | | |
| 623 | ((data & 0x04) >> 1 )| | |
| 624 | ((data & 0x10) >> 2 )| | |
| 625 | ((data & 0x40) >> 3 ); | |
| 626 | ||
| 627 | assert( mc6843->data_idx < sizeof(mc6843->data) ); | |
| 628 | ||
| 629 | mc6843->data[mc6843->data_idx / 2] = | |
| 630 | (mc6843->data[mc6843->data_idx / 2] << 4) | nibble; | |
| 631 | ||
| 632 | if ( (mc6843->data_idx == 0) && (mc6843->data[0] == 0xfe ) ) | |
| 633 | { | |
| 634 | /* address mark detected */ | |
| 635 | mc6843->data_idx = 2; | |
| 636 | } | |
| 637 | else if ( mc6843->data_idx == 9 ) | |
| 638 | { | |
| 639 | /* address id field complete */ | |
| 640 | if ( (mc6843->data[2] == 0) && (mc6843->data[4] == 0) ) | |
| 641 | { | |
| 642 | /* valid address id field */ | |
| 643 | device_t* img = mc6843_floppy_image( device ); | |
| 644 | UINT8 track = mc6843->data[1]; | |
| 645 | UINT8 sector = mc6843->data[3]; | |
| 646 | UINT8 filler = 0xe5; /* standard Thomson filler */ | |
| 647 | LOG(( "%f $%04x mc6843_w: address id detected track=%i sector=%i\n", space.machine().time().as_double(), space.machine().firstcpu->pcbase( ), track, sector)); | |
| 648 | floppy_drive_format_sector( img, mc6843->side, sector, track, 0, sector, 0, filler ); | |
| 649 | } | |
| 650 | else | |
| 651 | { | |
| 652 | /* abort */ | |
| 653 | mc6843->data_idx = 0; | |
| 654 | } | |
| 655 | } | |
| 656 | else if ( mc6843->data_idx > 0 ) | |
| 657 | { | |
| 658 | /* accumulate address id field */ | |
| 659 | mc6843->data_idx++; | |
| 660 | } | |
| 661 | } | |
| 662 | else if ( cmd == 0 ) | |
| 663 | { | |
| 664 | /* nothing */ | |
| 665 | } | |
| 666 | else | |
| 667 | { | |
| 668 | /* XXX TODO: other write modes */ | |
| 669 | logerror( "$%04x mc6843 write %02X in unsupported command mode %i (FWF=%i)\n", space.machine().firstcpu->pcbase( ), data, cmd, FWF ); | |
| 670 | } | |
| 671 | break; | |
| 672 | } | |
| 673 | ||
| 674 | case 1: /* Current-Track Address Register (CTAR) */ | |
| 675 | mc6843->CTAR = data & 0x7f; | |
| 676 | LOG(( "%f $%04x mc6843_w: set CTAR to %i %02X (actual=%i) \n", | |
| 677 | space.machine().time().as_double(), space.machine().firstcpu->pcbase( ), mc6843->CTAR, data, | |
| 678 | floppy_drive_get_current_track( mc6843_floppy_image( device ) ) )); | |
| 679 | break; | |
| 680 | ||
| 681 | case 2: /* Command Register (CMR) */ | |
| 682 | { | |
| 683 | int cmd = data & 15; | |
| 684 | ||
| 685 | LOG(( "%f $%04x mc6843_w: set CMR to $%02X: cmd=%s(%i) FWF=%i DMA=%i ISR3-intr=%i fun-intr=%i\n", | |
| 686 | space.machine().time().as_double(), space.machine().firstcpu->pcbase( ), | |
| 687 | data, mc6843_cmd[cmd], cmd, (data >> 4) & 1, (data >> 5) & 1, | |
| 688 | (data >> 6) & 1, (data >> 7) & 1 )); | |
| 689 | ||
| 690 | /* sanitize state */ | |
| 691 | mc6843->STRA &= ~0x81; /* clear Busy & Data Transfer Request */ | |
| 692 | mc6843->data_idx = 0; | |
| 693 | mc6843->data_size = 0; | |
| 694 | ||
| 695 | /* commands are initiated by updating some flags and scheduling | |
| 696 | a bottom-half (mc6843_cont) after some delay */ | |
| 697 | ||
| 698 | switch (cmd) | |
| 699 | { | |
| 700 | case CMD_SSW: | |
| 701 | case CMD_SSR: | |
| 702 | case CMD_SWD: | |
| 703 | case CMD_RCR: | |
| 704 | case CMD_MSR: | |
| 705 | case CMD_MSW: | |
| 706 | mc6843->STRA |= 0x80; /* set Busy */ | |
| 707 | mc6843->STRA &= ~0x22; /* clear Track Not Equal & Delete Data Mark Detected */ | |
| 708 | mc6843->STRB &= ~0x04; /* clear Data Mark Undetected */ | |
| 709 | mc6843->timer_cont->adjust( DELAY_ADDR ); | |
| 710 | break; | |
| 711 | case CMD_STZ: | |
| 712 | case CMD_SEK: | |
| 713 | mc6843->STRA |= 0x80; /* set Busy */ | |
| 714 | mc6843->timer_cont->adjust( DELAY_SEEK ); | |
| 715 | break; | |
| 716 | case CMD_FFW: | |
| 717 | case CMD_FFR: | |
| 718 | mc6843->data_idx = 0; | |
| 719 | mc6843->STRA |= 0x01; /* set Data Transfer Request */ | |
| 720 | break; | |
| 721 | } | |
| 722 | ||
| 723 | mc6843->CMR = data; | |
| 724 | mc6843_status_update( device ); | |
| 725 | break; | |
| 726 | } | |
| 727 | ||
| 728 | case 3: /* Set-Up Register (SUR) */ | |
| 729 | mc6843->SUR = data; | |
| 730 | ||
| 731 | /* assume CLK freq = 1MHz (IBM 3740 compatibility) */ | |
| 732 | LOG(( "%f $%04x mc6843_w: set SUR to $%02X: head settling time=%fms, track-to-track seek time=%f\n", | |
| 733 | space.machine().time().as_double(), space.machine().firstcpu->pcbase( ), | |
| 734 | data, 4.096 * (data & 15), 1.024 * ((data >> 4) & 15) )); | |
| 735 | break; | |
| 736 | ||
| 737 | case 4: /* Sector Address Register (SAR) */ | |
| 738 | mc6843->SAR = data & 0x1f; | |
| 739 | LOG(( "%f $%04x mc6843_w: set SAR to %i (%02X)\n", space.machine().time().as_double(), space.machine().firstcpu->pcbase( ), mc6843->SAR, data )); | |
| 740 | break; | |
| 741 | ||
| 742 | case 5: /* General Count Register (GCR) */ | |
| 743 | mc6843->GCR = data & 0x7f; | |
| 744 | LOG(( "%f $%04x mc6843_w: set GCR to %i (%02X)\n", space.machine().time().as_double(), space.machine().firstcpu->pcbase( ), mc6843->GCR, data )); | |
| 745 | break; | |
| 746 | ||
| 747 | case 6: /* CRC Control Register (CCR) */ | |
| 748 | mc6843->CCR = data & 3; | |
| 749 | LOG(( "%f $%04x mc6843_w: set CCR to %02X: CRC=%s shift=%i\n", | |
| 750 | space.machine().time().as_double(), space.machine().firstcpu->pcbase( ), data, | |
| 751 | (data & 1) ? "enabled" : "disabled", (data >> 1) & 1 )); | |
| 752 | break; | |
| 753 | ||
| 754 | case 7: /* Logical-Track Address Register (LTAR) */ | |
| 755 | mc6843->LTAR = data & 0x7f; | |
| 756 | LOG(( "%f $%04x mc6843_w: set LTAR to %i %02X (actual=%i)\n", | |
| 757 | space.machine().time().as_double(), space.machine().firstcpu->pcbase( ), mc6843->LTAR, data, | |
| 758 | floppy_drive_get_current_track( mc6843_floppy_image( device ) ) )); | |
| 759 | break; | |
| 760 | ||
| 761 | default: | |
| 762 | logerror( "$%04x mc6843 invalid write offset %i (data=$%02X)\n", space.machine().firstcpu->pcbase( ), offset, data ); | |
| 763 | } | |
| 764 | } | |
| 765 | ||
| 766 | ||
| 767 | ||
| 768 | /************************ reset *****************************/ | |
| 769 | ||
| 770 | static DEVICE_RESET( mc6843 ) | |
| 771 | { | |
| 772 | mc6843_t* mc6843 = get_safe_token( device ); | |
| 773 | int i; | |
| 774 | LOG (( "mc6843 reset\n" )); | |
| 775 | ||
| 776 | /* setup/reset floppy drive */ | |
| 777 | for ( i = 0; i < 4; i++ ) | |
| 778 | { | |
| 779 | device_t * img = floppy_get_device( device->machine(), i ); | |
| 780 | floppy_mon_w(img, CLEAR_LINE); | |
| 781 | floppy_drive_set_ready_state( img, FLOPPY_DRIVE_READY, 0 ); | |
| 782 | floppy_drive_set_rpm( img, 300. ); | |
| 783 | } | |
| 784 | ||
| 785 | /* reset registers */ | |
| 786 | mc6843->CMR &= 0xf0; /* zero only command */ | |
| 787 | mc6843->ISR = 0; | |
| 788 | mc6843->STRA &= 0x5c; | |
| 789 | mc6843->SAR = 0; | |
| 790 | mc6843->STRB &= 0x20; | |
| 791 | mc6843_status_update( device ); | |
| 792 | ||
| 793 | mc6843->data_size = 0; | |
| 794 | mc6843->data_idx = 0; | |
| 795 | mc6843->timer_cont->adjust( attotime::never ); | |
| 796 | } | |
| 797 | ||
| 798 | ||
| 799 | ||
| 800 | /************************ start *****************************/ | |
| 801 | ||
| 802 | static DEVICE_START( mc6843 ) | |
| 803 | { | |
| 804 | mc6843_t* mc6843 = get_safe_token( device ); | |
| 805 | ||
| 806 | mc6843->iface = (const mc6843_interface*)device->static_config(); | |
| 807 | ||
| 808 | mc6843->timer_cont = device->machine().scheduler().timer_alloc(FUNC(mc6843_cont), (void*) device) ; | |
| 809 | ||
| 810 | state_save_register_item( device->machine(),"mc6843", device->tag(), 0, mc6843->CTAR ); | |
| 811 | state_save_register_item( device->machine(),"mc6843", device->tag(), 0, mc6843->CMR ); | |
| 812 | state_save_register_item( device->machine(),"mc6843", device->tag(), 0, mc6843->ISR ); | |
| 813 | state_save_register_item( device->machine(),"mc6843", device->tag(), 0, mc6843->SUR ); | |
| 814 | state_save_register_item( device->machine(),"mc6843", device->tag(), 0, mc6843->STRA ); | |
| 815 | state_save_register_item( device->machine(),"mc6843", device->tag(), 0, mc6843->STRB ); | |
| 816 | state_save_register_item( device->machine(),"mc6843", device->tag(), 0, mc6843->SAR ); | |
| 817 | state_save_register_item( device->machine(),"mc6843", device->tag(), 0, mc6843->GCR ); | |
| 818 | state_save_register_item( device->machine(),"mc6843", device->tag(), 0, mc6843->CCR ); | |
| 819 | state_save_register_item( device->machine(),"mc6843", device->tag(), 0, mc6843->LTAR ); | |
| 820 | state_save_register_item( device->machine(),"mc6843", device->tag(), 0, mc6843->drive ); | |
| 821 | state_save_register_item( device->machine(),"mc6843", device->tag(), 0, mc6843->side ); | |
| 822 | state_save_register_item_array( device->machine(),"mc6843", device->tag(), 0, mc6843->data ); | |
| 823 | state_save_register_item( device->machine(),"mc6843", device->tag(), 0, mc6843->data_size ); | |
| 824 | state_save_register_item( device->machine(),"mc6843", device->tag(), 0, mc6843->data_idx ); | |
| 825 | state_save_register_item( device->machine(),"mc6843", device->tag(), 0, mc6843->data_id ); | |
| 826 | } | |
| 827 | ||
| 828 | ||
| 829 | const device_type MC6843 = &device_creator<mc6843_device>; | |
| 830 | ||
| 831 | mc6843_device::mc6843_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) | |
| 832 | : device_t(mconfig, MC6843, "Motorola MC6843 floppy controller", tag, owner, clock) | |
| 833 | { | |
| 834 | m_token = global_alloc_clear(mc6843_t); | |
| 835 | } | |
| 836 | ||
| 837 | //------------------------------------------------- | |
| 838 | // device_config_complete - perform any | |
| 839 | // operations now that the configuration is | |
| 840 | // complete | |
| 841 | //------------------------------------------------- | |
| 842 | ||
| 843 | void mc6843_device::device_config_complete() | |
| 844 | { | |
| 845 | } | |
| 846 | ||
| 847 | //------------------------------------------------- | |
| 848 | // device_start - device-specific startup | |
| 849 | //------------------------------------------------- | |
| 850 | ||
| 851 | void mc6843_device::device_start() | |
| 852 | { | |
| 853 | DEVICE_START_NAME( mc6843 )(this); | |
| 854 | } | |
| 855 | ||
| 856 | //------------------------------------------------- | |
| 857 | // device_reset - device-specific reset | |
| 858 | //------------------------------------------------- | |
| 859 | ||
| 860 | void mc6843_device::device_reset() | |
| 861 | { | |
| 862 | DEVICE_RESET_NAME( mc6843 )(this); | |
| 863 | } |
| Added: svn:eol-style + native Added: svn:mime-type + text/plain |
| r0 | r21685 | |
|---|---|---|
| 1 | /********************************************************************** | |
| 2 | ||
| 3 | Western Digital WD11C00-17 PC/XT Host Interface Logic Device | |
| 4 | ||
| 5 | Copyright MESS Team. | |
| 6 | Visit http://mamedev.org for licensing and usage restrictions. | |
| 7 | ||
| 8 | **********************************************************************/ | |
| 9 | ||
| 10 | #include "machine/wd11c00_17.h" | |
| 11 | ||
| 12 | ||
| 13 | ||
| 14 | //************************************************************************** | |
| 15 | // MACROS / CONSTANTS | |
| 16 | //************************************************************************** | |
| 17 | ||
| 18 | #define LOG 1 | |
| 19 | ||
| 20 | ||
| 21 | // status register | |
| 22 | #define STATUS_IRQ 0x20 | |
| 23 | #define STATUS_DRQ 0x10 | |
| 24 | #define STATUS_BUSY 0x08 | |
| 25 | #define STATUS_C_D 0x04 | |
| 26 | #define STATUS_I_O 0x02 | |
| 27 | #define STATUS_REQ 0x01 | |
| 28 | ||
| 29 | ||
| 30 | // mask register | |
| 31 | #define MASK_IRQ 0x02 | |
| 32 | #define MASK_DMA 0x01 | |
| 33 | ||
| 34 | ||
| 35 | ||
| 36 | //************************************************************************** | |
| 37 | // DEVICE DEFINITIONS | |
| 38 | //************************************************************************** | |
| 39 | ||
| 40 | const device_type WD11C00_17 = &device_creator<wd11c00_17_device>; | |
| 41 | ||
| 42 | ||
| 43 | //------------------------------------------------- | |
| 44 | // device_config_complete - perform any | |
| 45 | // operations now that the configuration is | |
| 46 | // complete | |
| 47 | //------------------------------------------------- | |
| 48 | ||
| 49 | void wd11c00_17_device::device_config_complete() | |
| 50 | { | |
| 51 | // inherit a copy of the static data | |
| 52 | const wd11c00_17_interface *intf = reinterpret_cast<const wd11c00_17_interface *>(static_config()); | |
| 53 | if (intf != NULL) | |
| 54 | *static_cast<wd11c00_17_interface *>(this) = *intf; | |
| 55 | ||
| 56 | // or initialize to defaults if none provided | |
| 57 | else | |
| 58 | { | |
| 59 | memset(&m_out_irq5_cb, 0, sizeof(m_out_irq5_cb)); | |
| 60 | memset(&m_out_drq3_cb, 0, sizeof(m_out_drq3_cb)); | |
| 61 | memset(&m_out_mr_cb, 0, sizeof(m_out_mr_cb)); | |
| 62 | memset(&m_out_busy_cb, 0, sizeof(m_out_busy_cb)); | |
| 63 | memset(&m_out_req_cb, 0, sizeof(m_out_req_cb)); | |
| 64 | memset(&m_out_ra3_cb, 0, sizeof(m_out_ra3_cb)); | |
| 65 | memset(&m_in_rd322_cb, 0, sizeof(m_in_rd322_cb)); | |
| 66 | memset(&m_in_ramcs_cb, 0, sizeof(m_in_ramcs_cb)); | |
| 67 | memset(&m_out_ramwr_cb, 0, sizeof(m_out_ramwr_cb)); | |
| 68 | memset(&m_in_cs1010_cb, 0, sizeof(m_in_cs1010_cb)); | |
| 69 | memset(&m_out_cs1010_cb, 0, sizeof(m_out_cs1010_cb)); | |
| 70 | } | |
| 71 | } | |
| 72 | ||
| 73 | ||
| 74 | ||
| 75 | //************************************************************************** | |
| 76 | // INLINE HELPERS | |
| 77 | //************************************************************************** | |
| 78 | ||
| 79 | //------------------------------------------------- | |
| 80 | // check_interrupt - | |
| 81 | //------------------------------------------------- | |
| 82 | ||
| 83 | inline void wd11c00_17_device::check_interrupt() | |
| 84 | { | |
| 85 | if (BIT(m_ra, 10)) | |
| 86 | { | |
| 87 | m_status &= ~STATUS_DRQ; | |
| 88 | } | |
| 89 | ||
| 90 | int ra3 = BIT(m_ra, 3); | |
| 91 | ||
| 92 | if (m_ra3 != ra3) | |
| 93 | { | |
| 94 | m_out_ra3_func(ra3 ? ASSERT_LINE : CLEAR_LINE); | |
| 95 | m_ra3 = ra3; | |
| 96 | } | |
| 97 | ||
| 98 | int irq5 = ((m_status & STATUS_IRQ) && (m_mask & MASK_IRQ)) ? ASSERT_LINE : CLEAR_LINE; | |
| 99 | ||
| 100 | if (m_irq5 != irq5) | |
| 101 | { | |
| 102 | m_out_irq5_func(irq5); | |
| 103 | m_irq5 = irq5; | |
| 104 | } | |
| 105 | ||
| 106 | int drq3 = ((m_status & STATUS_DRQ) && (m_mask & MASK_DMA)) ? ASSERT_LINE : CLEAR_LINE; | |
| 107 | ||
| 108 | if (m_drq3 != drq3) | |
| 109 | { | |
| 110 | m_out_drq3_func(drq3); | |
| 111 | m_drq3 = drq3; | |
| 112 | } | |
| 113 | ||
| 114 | int busy = (m_status & STATUS_BUSY) ? 0 : 1; | |
| 115 | ||
| 116 | if (m_busy != busy) | |
| 117 | { | |
| 118 | m_out_busy_func(busy); | |
| 119 | m_busy = busy; | |
| 120 | } | |
| 121 | ||
| 122 | int req = (m_status & STATUS_REQ) ? 1 : 0; | |
| 123 | ||
| 124 | if (m_req != req) | |
| 125 | { | |
| 126 | m_out_req_func(req); | |
| 127 | m_req = req; | |
| 128 | } | |
| 129 | } | |
| 130 | ||
| 131 | ||
| 132 | //------------------------------------------------- | |
| 133 | // increment_address - | |
| 134 | //------------------------------------------------- | |
| 135 | ||
| 136 | inline void wd11c00_17_device::increment_address() | |
| 137 | { | |
| 138 | m_ra++; | |
| 139 | check_interrupt(); | |
| 140 | } | |
| 141 | ||
| 142 | ||
| 143 | //------------------------------------------------- | |
| 144 | // read_data - | |
| 145 | //------------------------------------------------- | |
| 146 | ||
| 147 | inline UINT8 wd11c00_17_device::read_data() | |
| 148 | { | |
| 149 | UINT8 data = 0; | |
| 150 | ||
| 151 | if (m_status & STATUS_BUSY) | |
| 152 | { | |
| 153 | data = m_in_ramcs_func(m_ra & 0x7ff); | |
| 154 | ||
| 155 | increment_address(); | |
| 156 | } | |
| 157 | ||
| 158 | return data; | |
| 159 | } | |
| 160 | ||
| 161 | ||
| 162 | //------------------------------------------------- | |
| 163 | // write_data - | |
| 164 | //------------------------------------------------- | |
| 165 | ||
| 166 | inline void wd11c00_17_device::write_data(UINT8 data) | |
| 167 | { | |
| 168 | if (m_status & STATUS_BUSY) | |
| 169 | { | |
| 170 | m_out_ramwr_func(m_ra & 0x7ff, data); | |
| 171 | ||
| 172 | increment_address(); | |
| 173 | } | |
| 174 | } | |
| 175 | ||
| 176 | ||
| 177 | //------------------------------------------------- | |
| 178 | // software_reset - | |
| 179 | //------------------------------------------------- | |
| 180 | ||
| 181 | inline void wd11c00_17_device::software_reset() | |
| 182 | { | |
| 183 | m_out_mr_func(ASSERT_LINE); | |
| 184 | m_out_mr_func(CLEAR_LINE); | |
| 185 | ||
| 186 | device_reset(); | |
| 187 | } | |
| 188 | ||
| 189 | ||
| 190 | //------------------------------------------------- | |
| 191 | // select - | |
| 192 | //------------------------------------------------- | |
| 193 | ||
| 194 | inline void wd11c00_17_device::select() | |
| 195 | { | |
| 196 | m_status = STATUS_BUSY | STATUS_C_D | STATUS_REQ; | |
| 197 | ||
| 198 | check_interrupt(); | |
| 199 | } | |
| 200 | ||
| 201 | ||
| 202 | ||
| 203 | //************************************************************************** | |
| 204 | // LIVE DEVICE | |
| 205 | //************************************************************************** | |
| 206 | ||
| 207 | //------------------------------------------------- | |
| 208 | // wd11c00_17_device - constructor | |
| 209 | //------------------------------------------------- | |
| 210 | ||
| 211 | wd11c00_17_device::wd11c00_17_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) | |
| 212 | : device_t(mconfig, WD11C00_17, "Western Digital WD11C00-17", tag, owner, clock), | |
| 213 | m_status(0), | |
| 214 | m_ra(0), | |
| 215 | m_irq5(CLEAR_LINE), | |
| 216 | m_drq3(CLEAR_LINE), | |
| 217 | m_busy(1), | |
| 218 | m_req(0), | |
| 219 | m_ra3(0) | |
| 220 | { | |
| 221 | } | |
| 222 | ||
| 223 | ||
| 224 | //------------------------------------------------- | |
| 225 | // device_start - device-specific startup | |
| 226 | //------------------------------------------------- | |
| 227 | ||
| 228 | void wd11c00_17_device::device_start() | |
| 229 | { | |
| 230 | // resolve callbacks | |
| 231 | m_out_irq5_func.resolve(m_out_irq5_cb, *this); | |
| 232 | m_out_drq3_func.resolve(m_out_drq3_cb, *this); | |
| 233 | m_out_mr_func.resolve(m_out_mr_cb, *this); | |
| 234 | m_out_busy_func.resolve(m_out_busy_cb, *this); | |
| 235 | m_out_req_func.resolve(m_out_req_cb, *this); | |
| 236 | m_out_ra3_func.resolve(m_out_ra3_cb, *this); | |
| 237 | m_in_rd322_func.resolve(m_in_rd322_cb, *this); | |
| 238 | m_in_ramcs_func.resolve(m_in_ramcs_cb, *this); | |
| 239 | m_out_ramwr_func.resolve(m_out_ramwr_cb, *this); | |
| 240 | m_in_cs1010_func.resolve(m_in_cs1010_cb, *this); | |
| 241 | m_out_cs1010_func.resolve(m_out_cs1010_cb, *this); | |
| 242 | } | |
| 243 | ||
| 244 | ||
| 245 | //------------------------------------------------- | |
| 246 | // device_reset - device-specific reset | |
| 247 | //------------------------------------------------- | |
| 248 | ||
| 249 | void wd11c00_17_device::device_reset() | |
| 250 | { | |
| 251 | m_status &= ~(STATUS_IRQ | STATUS_DRQ | STATUS_BUSY); | |
| 252 | m_mask = 0; | |
| 253 | m_ra = 0; | |
| 254 | ||
| 255 | check_interrupt(); | |
| 256 | } | |
| 257 | ||
| 258 | ||
| 259 | //------------------------------------------------- | |
| 260 | // io_r - | |
| 261 | //------------------------------------------------- | |
| 262 | ||
| 263 | READ8_MEMBER( wd11c00_17_device::io_r ) | |
| 264 | { | |
| 265 | UINT8 data = 0xff; | |
| 266 | ||
| 267 | switch (offset) | |
| 268 | { | |
| 269 | case 0: // Read Data, Board to Host | |
| 270 | if (LOG) logerror("%s WD11C00-17 '%s' Read Data %03x:", machine().describe_context(), tag(), m_ra); | |
| 271 | data = read_data(); | |
| 272 | if (LOG) logerror("%02x\n", data); | |
| 273 | break; | |
| 274 | ||
| 275 | case 1: // Read Board Hardware Status | |
| 276 | data = m_status; | |
| 277 | check_interrupt(); | |
| 278 | break; | |
| 279 | ||
| 280 | case 2: // Read Drive Configuration Information | |
| 281 | data = m_in_rd322_func(0); | |
| 282 | break; | |
| 283 | ||
| 284 | case 3: // Not Used | |
| 285 | break; | |
| 286 | } | |
| 287 | ||
| 288 | return data; | |
| 289 | } | |
| 290 | ||
| 291 | ||
| 292 | //------------------------------------------------- | |
| 293 | // io_w - | |
| 294 | //------------------------------------------------- | |
| 295 | ||
| 296 | WRITE8_MEMBER( wd11c00_17_device::io_w ) | |
| 297 | { | |
| 298 | switch (offset) | |
| 299 | { | |
| 300 | case 0: // Write Data, Host to Board | |
| 301 | if (LOG) logerror("%s WD11C00-17 '%s' Write Data %03x:%02x\n", machine().describe_context(), tag(), m_ra, data); | |
| 302 | write_data(data); | |
| 303 | break; | |
| 304 | ||
| 305 | case 1: // Board Software Reset | |
| 306 | if (LOG) logerror("%s WD11C00-17 '%s' Software Reset\n", machine().describe_context(), tag()); | |
| 307 | software_reset(); | |
| 308 | break; | |
| 309 | ||
| 310 | case 2: // Board Select | |
| 311 | if (LOG) logerror("%s WD11C00-17 '%s' Select\n", machine().describe_context(), tag()); | |
| 312 | increment_address(); // HACK | |
| 313 | select(); | |
| 314 | break; | |
| 315 | ||
| 316 | case 3: // Set/Reset DMA, IRQ Masks | |
| 317 | if (LOG) logerror("%s WD11C00-17 '%s' Mask IRQ %u DMA %u\n", machine().describe_context(), tag(), BIT(data, 1), BIT(data, 0)); | |
| 318 | m_mask = data; | |
| 319 | check_interrupt(); | |
| 320 | break; | |
| 321 | } | |
| 322 | } | |
| 323 | ||
| 324 | ||
| 325 | //------------------------------------------------- | |
| 326 | // dack_r - | |
| 327 | //------------------------------------------------- | |
| 328 | ||
| 329 | UINT8 wd11c00_17_device::dack_r() | |
| 330 | { | |
| 331 | return read_data(); | |
| 332 | } | |
| 333 | ||
| 334 | ||
| 335 | //------------------------------------------------- | |
| 336 | // dack_w - | |
| 337 | //------------------------------------------------- | |
| 338 | ||
| 339 | void wd11c00_17_device::dack_w(UINT8 data) | |
| 340 | { | |
| 341 | write_data(data); | |
| 342 | } | |
| 343 | ||
| 344 | ||
| 345 | //------------------------------------------------- | |
| 346 | // read - | |
| 347 | //------------------------------------------------- | |
| 348 | ||
| 349 | READ8_MEMBER( wd11c00_17_device::read ) | |
| 350 | { | |
| 351 | UINT8 data = 0; | |
| 352 | ||
| 353 | switch (offset) | |
| 354 | { | |
| 355 | case 0x00: | |
| 356 | if (LOG) logerror("%s WD11C00-17 '%s' Read RAM %03x:", machine().describe_context(), tag(), m_ra); | |
| 357 | data = read_data(); | |
| 358 | if (LOG) logerror("%02x\n", data); | |
| 359 | break; | |
| 360 | ||
| 361 | case 0x20: | |
| 362 | data = m_in_cs1010_func(m_ra >> 8); | |
| 363 | break; | |
| 364 | } | |
| 365 | ||
| 366 | return data; | |
| 367 | } | |
| 368 | ||
| 369 | ||
| 370 | //------------------------------------------------- | |
| 371 | // write - | |
| 372 | //------------------------------------------------- | |
| 373 | ||
| 374 | WRITE8_MEMBER( wd11c00_17_device::write ) | |
| 375 | { | |
| 376 | switch (offset) | |
| 377 | { | |
| 378 | case 0x00: | |
| 379 | if (LOG) logerror("%s WD11C00-17 '%s' Write RAM %03x:%02x\n", machine().describe_context(), tag(), m_ra, data); | |
| 380 | write_data(data); | |
| 381 | if (m_ra > 0x400) m_ecc_not_0 = 0; // HACK | |
| 382 | break; | |
| 383 | ||
| 384 | case 0x20: | |
| 385 | m_out_cs1010_func(m_ra >> 8, data); | |
| 386 | break; | |
| 387 | ||
| 388 | case 0x60: | |
| 389 | m_ra = (data & 0x07) << 8; | |
| 390 | if (LOG) logerror("%s WD11C00-17 '%s' RA %03x\n", machine().describe_context(), tag(), m_ra); | |
| 391 | check_interrupt(); | |
| 392 | break; | |
| 393 | } | |
| 394 | } | |
| 395 | ||
| 396 | ||
| 397 | //------------------------------------------------- | |
| 398 | // ireq_w - | |
| 399 | //------------------------------------------------- | |
| 400 | ||
| 401 | WRITE_LINE_MEMBER( wd11c00_17_device::ireq_w ) | |
| 402 | { | |
| 403 | if (LOG) logerror("%s WD11C00-17 '%s' IREQ %u\n", machine().describe_context(), tag(), state); | |
| 404 | ||
| 405 | if (state) m_status |= STATUS_REQ; else m_status &= ~STATUS_REQ; | |
| 406 | ||
| 407 | if (m_status & STATUS_BUSY) | |
| 408 | { | |
| 409 | if (state) | |
| 410 | { | |
| 411 | m_status |= STATUS_IRQ | STATUS_I_O; | |
| 412 | } | |
| 413 | else | |
| 414 | { | |
| 415 | if (m_status & STATUS_I_O) | |
| 416 | { | |
| 417 | m_status &= ~(STATUS_BUSY | STATUS_I_O); | |
| 418 | } | |
| 419 | } | |
| 420 | } | |
| 421 | ||
| 422 | check_interrupt(); | |
| 423 | } | |
| 424 | ||
| 425 | ||
| 426 | //------------------------------------------------- | |
| 427 | // io_w - | |
| 428 | //------------------------------------------------- | |
| 429 | ||
| 430 | WRITE_LINE_MEMBER( wd11c00_17_device::io_w ) | |
| 431 | { | |
| 432 | if (LOG) logerror("%s WD11C00-17 '%s' I/O %u\n", machine().describe_context(), tag(), state); | |
| 433 | ||
| 434 | if (state) m_status |= STATUS_I_O; else m_status &= ~STATUS_I_O; | |
| 435 | } | |
| 436 | ||
| 437 | ||
| 438 | //------------------------------------------------- | |
| 439 | // cd_w - | |
| 440 | //------------------------------------------------- | |
| 441 | ||
| 442 | WRITE_LINE_MEMBER( wd11c00_17_device::cd_w ) | |
| 443 | { | |
| 444 | if (LOG) logerror("%s WD11C00-17 '%s' C/D %u\n", machine().describe_context(), tag(), state); | |
| 445 | ||
| 446 | if (state) m_status |= STATUS_C_D; else m_status &= ~STATUS_C_D; | |
| 447 | } | |
| 448 | ||
| 449 | ||
| 450 | //------------------------------------------------- | |
| 451 | // clct_w - | |
| 452 | //------------------------------------------------- | |
| 453 | ||
| 454 | WRITE_LINE_MEMBER( wd11c00_17_device::clct_w ) | |
| 455 | { | |
| 456 | if (LOG) logerror("%s WD11C00-17 '%s' CLCT %u\n", machine().describe_context(), tag(), state); | |
| 457 | ||
| 458 | if (state) | |
| 459 | { | |
| 460 | m_ra &= 0xff00; | |
| 461 | check_interrupt(); | |
| 462 | } | |
| 463 | } | |
| 464 | ||
| 465 | ||
| 466 | //------------------------------------------------- | |
| 467 | // mode_w - | |
| 468 | //------------------------------------------------- | |
| 469 | ||
| 470 | WRITE_LINE_MEMBER( wd11c00_17_device::mode_w ) | |
| 471 | { | |
| 472 | if (LOG) logerror("%s WD11C00-17 '%s' MODE %u\n", machine().describe_context(), tag(), state); | |
| 473 | ||
| 474 | m_mode = state; | |
| 475 | m_ecc_not_0 = state; // HACK | |
| 476 | } | |
| 477 | ||
| 478 | ||
| 479 | //------------------------------------------------- | |
| 480 | // busy_r - | |
| 481 | //------------------------------------------------- | |
| 482 | ||
| 483 | READ_LINE_MEMBER( wd11c00_17_device::busy_r ) | |
| 484 | { | |
| 485 | return (m_status & STATUS_BUSY) ? 0 : 1; | |
| 486 | } | |
| 487 | ||
| 488 | ||
| 489 | //------------------------------------------------- | |
| 490 | // ecc_not_0_r - | |
| 491 | //------------------------------------------------- | |
| 492 | ||
| 493 | READ_LINE_MEMBER( wd11c00_17_device::ecc_not_0_r ) | |
| 494 | { | |
| 495 | return m_ecc_not_0; | |
| 496 | } |
| Added: svn:eol-style + native Added: svn:mime-type + text/plain |
| r0 | r21685 | |
|---|---|---|
| 1 | /********************************************************************** | |
| 2 | ||
| 3 | Copyright (C) Antoine Mine' 2007 | |
| 4 | ||
| 5 | Motorola 6843 Floppy Disk Controller emulation. | |
| 6 | ||
| 7 | **********************************************************************/ | |
| 8 | ||
| 9 | #ifndef MC6843_H | |
| 10 | #define MC6843_H | |
| 11 | ||
| 12 | class mc6843_device : public device_t | |
| 13 | { | |
| 14 | public: | |
| 15 | mc6843_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); | |
| 16 | ~mc6843_device() { global_free(m_token); } | |
| 17 | ||
| 18 | // access to legacy token | |
| 19 | void *token() const { assert(m_token != NULL); return m_token; } | |
| 20 | protected: | |
| 21 | // device-level overrides | |
| 22 | virtual void device_config_complete(); | |
| 23 | virtual void device_start(); | |
| 24 | virtual void device_reset(); | |
| 25 | private: | |
| 26 | // internal state | |
| 27 | void *m_token; | |
| 28 | }; | |
| 29 | ||
| 30 | extern const device_type MC6843; | |
| 31 | ||
| 32 | ||
| 33 | ||
| 34 | /* ---------- configuration ------------ */ | |
| 35 | ||
| 36 | struct mc6843_interface | |
| 37 | { | |
| 38 | void ( * irq_func ) ( device_t *device, int state ); | |
| 39 | }; | |
| 40 | ||
| 41 | ||
| 42 | #define MCFG_MC6843_ADD(_tag, _intrf) \ | |
| 43 | MCFG_DEVICE_ADD(_tag, MC6843, 0) \ | |
| 44 | MCFG_DEVICE_CONFIG(_intrf) | |
| 45 | ||
| 46 | #define MCFG_MC6843_REMOVE(_tag) \ | |
| 47 | MCFG_DEVICE_REMOVE(_tag) | |
| 48 | ||
| 49 | ||
| 50 | /* ---------- functions ------------ */ | |
| 51 | ||
| 52 | extern DECLARE_READ8_DEVICE_HANDLER ( mc6843_r ); | |
| 53 | extern DECLARE_WRITE8_DEVICE_HANDLER ( mc6843_w ); | |
| 54 | ||
| 55 | extern void mc6843_set_drive ( device_t *device, int drive ); | |
| 56 | extern void mc6843_set_side ( device_t *device, int side ); | |
| 57 | extern void mc6843_set_index_pulse ( device_t *device, int index_pulse ); | |
| 58 | ||
| 59 | #endif |
| Added: svn:eol-style + native Added: svn:mime-type + text/plain |
| r0 | r21685 | |
|---|---|---|
| 1 | /********************************************************************** | |
| 2 | ||
| 3 | Western Digital WD11C00-17 PC/XT Host Interface Logic Device | |
| 4 | ||
| 5 | Copyright MESS Team. | |
| 6 | Visit http://mamedev.org for licensing and usage restrictions. | |
| 7 | ||
| 8 | **********************************************************************/ | |
| 9 | ||
| 10 | #pragma once | |
| 11 | ||
| 12 | #ifndef __WD11C00_17__ | |
| 13 | #define __WD11C00_17__ | |
| 14 | ||
| 15 | ||
| 16 | #include "emu.h" | |
| 17 | ||
| 18 | ||
| 19 | ||
| 20 | //************************************************************************** | |
| 21 | // INTERFACE CONFIGURATION MACROS | |
| 22 | //************************************************************************** | |
| 23 | ||
| 24 | #define MCFG_WD11C00_17_ADD(_tag, _clock, _config) \ | |
| 25 | MCFG_DEVICE_ADD(_tag, WD11C00_17, _clock) \ | |
| 26 | MCFG_DEVICE_CONFIG(_config) | |
| 27 | ||
| 28 | ||
| 29 | #define WD11C00_17_INTERFACE(_name) \ | |
| 30 | const wd11c00_17_interface (_name) = | |
| 31 | ||
| 32 | ||
| 33 | ||
| 34 | //************************************************************************** | |
| 35 | // TYPE DEFINITIONS | |
| 36 | //************************************************************************** | |
| 37 | ||
| 38 | // ======================> wd11c00_17_interface | |
| 39 | ||
| 40 | struct wd11c00_17_interface | |
| 41 | { | |
| 42 | devcb_write_line m_out_irq5_cb; | |
| 43 | devcb_write_line m_out_drq3_cb; | |
| 44 | devcb_write_line m_out_mr_cb; | |
| 45 | devcb_write_line m_out_busy_cb; | |
| 46 | devcb_write_line m_out_req_cb; | |
| 47 | devcb_write_line m_out_ra3_cb; | |
| 48 | devcb_read8 m_in_rd322_cb; | |
| 49 | devcb_read8 m_in_ramcs_cb; | |
| 50 | devcb_write8 m_out_ramwr_cb; | |
| 51 | devcb_read8 m_in_cs1010_cb; | |
| 52 | devcb_write8 m_out_cs1010_cb; | |
| 53 | }; | |
| 54 | ||
| 55 | ||
| 56 | // ======================> wd11c00_17_device | |
| 57 | ||
| 58 | class wd11c00_17_device : public device_t, | |
| 59 | public wd11c00_17_interface | |
| 60 | { | |
| 61 | public: | |
| 62 | // construction/destruction | |
| 63 | wd11c00_17_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); | |
| 64 | ||
| 65 | DECLARE_READ8_MEMBER( io_r ); | |
| 66 | DECLARE_WRITE8_MEMBER( io_w ); | |
| 67 | ||
| 68 | UINT8 dack_r(); | |
| 69 | void dack_w(UINT8 data); | |
| 70 | ||
| 71 | DECLARE_READ8_MEMBER( read ); | |
| 72 | DECLARE_WRITE8_MEMBER( write ); | |
| 73 | ||
| 74 | DECLARE_WRITE_LINE_MEMBER( ireq_w ); | |
| 75 | DECLARE_WRITE_LINE_MEMBER( io_w ); | |
| 76 | DECLARE_WRITE_LINE_MEMBER( cd_w ); | |
| 77 | DECLARE_WRITE_LINE_MEMBER( clct_w ); | |
| 78 | DECLARE_WRITE_LINE_MEMBER( mode_w ); | |
| 79 | ||
| 80 | DECLARE_READ_LINE_MEMBER( busy_r ); | |
| 81 | DECLARE_READ_LINE_MEMBER( ecc_not_0_r ); | |
| 82 | ||
| 83 | protected: | |
| 84 | // device-level overrides | |
| 85 | virtual void device_start(); | |
| 86 | virtual void device_reset(); | |
| 87 | virtual void device_config_complete(); | |
| 88 | ||
| 89 | private: | |
| 90 | inline void check_interrupt(); | |
| 91 | inline void increment_address(); | |
| 92 | inline UINT8 read_data(); | |
| 93 | inline void write_data(UINT8 data); | |
| 94 | inline void software_reset(); | |
| 95 | inline void select(); | |
| 96 | ||
| 97 | devcb_resolved_write_line m_out_irq5_func; | |
| 98 | devcb_resolved_write_line m_out_drq3_func; | |
| 99 | devcb_resolved_write_line m_out_mr_func; | |
| 100 | devcb_resolved_write_line m_out_busy_func; | |
| 101 | devcb_resolved_write_line m_out_req_func; | |
| 102 | devcb_resolved_write_line m_out_ra3_func; | |
| 103 | devcb_resolved_read8 m_in_rd322_func; | |
| 104 | devcb_resolved_read8 m_in_ramcs_func; | |
| 105 | devcb_resolved_write8 m_out_ramwr_func; | |
| 106 | devcb_resolved_read8 m_in_cs1010_func; | |
| 107 | devcb_resolved_write8 m_out_cs1010_func; | |
| 108 | ||
| 109 | UINT8 m_status; | |
| 110 | UINT8 m_mask; | |
| 111 | ||
| 112 | offs_t m_ra; | |
| 113 | ||
| 114 | int m_mode; | |
| 115 | int m_ecc_not_0; | |
| 116 | ||
| 117 | int m_irq5; | |
| 118 | int m_drq3; | |
| 119 | int m_busy; | |
| 120 | int m_req; | |
| 121 | int m_ra3; | |
| 122 | }; | |
| 123 | ||
| 124 | ||
| 125 | // device type definition | |
| 126 | extern const device_type WD11C00_17; | |
| 127 | ||
| 128 | #endif |
| Added: svn:mime-type + text/plain Added: svn:eol-style + native |
| r0 | r21685 | |
|---|---|---|
| 1 | /****************************************************************************** | |
| 2 | uPD7002 Analogue to Digital Converter | |
| 3 | ||
| 4 | MESS Driver By: | |
| 5 | ||
| 6 | Gordon Jefferyes | |
| 7 | mess_bbc@gjeffery.dircon.co.uk | |
| 8 | ||
| 9 | ******************************************************************************/ | |
| 10 | ||
| 11 | #include "emu.h" | |
| 12 | #include "upd7002.h" | |
| 13 | ||
| 14 | ||
| 15 | struct uPD7002_t | |
| 16 | { | |
| 17 | /* Pointer to our interface */ | |
| 18 | const uPD7002_interface *intf; | |
| 19 | ||
| 20 | /* Status Register | |
| 21 | D0 and D1 define the currently selected input channel | |
| 22 | D2 flag output | |
| 23 | D3 0 = 8 bit mode 1 = 12 bit mode | |
| 24 | D4 2nd MSB of conversion | |
| 25 | D5 MSB of conversion | |
| 26 | D6 0 = busy, 1 = not busy (~busy) | |
| 27 | D7 0 = conversion completed, 1 = conversion not completed (~EOC) | |
| 28 | */ | |
| 29 | int status; | |
| 30 | ||
| 31 | /* High data byte | |
| 32 | This byte contains the 8 most significant bits of the analogue to digital conversion. */ | |
| 33 | int data1; | |
| 34 | ||
| 35 | /* Low data byte | |
| 36 | In 12 bit mode: Bits 7 to 4 define the four low order bits of the conversion. | |
| 37 | In 8 bit mode. All bits 7 to 4 are inaccurate. | |
| 38 | Bits 3 to 0 are always set to low. */ | |
| 39 | int data0; | |
| 40 | ||
| 41 | ||
| 42 | /* temporary store of the next A to D conversion */ | |
| 43 | int digitalvalue; | |
| 44 | ||
| 45 | /* this counter is used to check a full end of conversion has been reached | |
| 46 | if the uPD7002 is half way through one conversion and a new conversion is requested | |
| 47 | the counter at the end of the first conversion will not match and not be processed | |
| 48 | only then at the end of the second conversion will the conversion complete function run */ | |
| 49 | int conversion_counter; | |
| 50 | }; | |
| 51 | ||
| 52 | ||
| 53 | /***************************************************************************** | |
| 54 | Implementation | |
| 55 | *****************************************************************************/ | |
| 56 | ||
| 57 | INLINE uPD7002_t *get_safe_token(device_t *device) | |
| 58 | { | |
| 59 | assert(device != NULL); | |
| 60 | assert(device->type() == UPD7002); | |
| 61 | ||
| 62 | return (uPD7002_t *)downcast<uPD7002_device *>(device)->token(); | |
| 63 | } | |
| 64 | ||
| 65 | READ8_DEVICE_HANDLER ( uPD7002_EOC_r ) | |
| 66 | { | |
| 67 | uPD7002_t *uPD7002 = get_safe_token(device); | |
| 68 | return (uPD7002->status>>7)&0x01; | |
| 69 | } | |
| 70 | ||
| 71 | ||
| 72 | static TIMER_CALLBACK(uPD7002_conversioncomplete) | |
| 73 | { | |
| 74 | device_t *device = (device_t *)ptr; | |
| 75 | uPD7002_t *uPD7002 = get_safe_token(device); | |
| 76 | ||
| 77 | int counter_value = param; | |
| 78 | if (counter_value==uPD7002->conversion_counter) | |
| 79 | { | |
| 80 | // this really always does a 12 bit conversion | |
| 81 | uPD7002->data1 = uPD7002->digitalvalue>>8; | |
| 82 | uPD7002->data0 = uPD7002->digitalvalue&0xf0; | |
| 83 | ||
| 84 | // set the status register with top 2 MSB, not busy and conversion complete | |
| 85 | uPD7002->status = (uPD7002->status & 0x0f)|((uPD7002->data1 & 0xc0)>>2)|0x40; | |
| 86 | ||
| 87 | // call the EOC function with EOC from status | |
| 88 | // uPD7002_EOC_r(0) this has just been set to 0 | |
| 89 | if (uPD7002->intf->EOC_func) (uPD7002->intf->EOC_func)(device,0); | |
| 90 | uPD7002->conversion_counter=0; | |
| 91 | } | |
| 92 | } | |
| 93 | ||
| 94 | ||
| 95 | READ8_DEVICE_HANDLER ( uPD7002_r ) | |
| 96 | { | |
| 97 | uPD7002_t *uPD7002 = get_safe_token(device); | |
| 98 | ||
| 99 | switch(offset&0x03) | |
| 100 | { | |
| 101 | case 0: | |
| 102 | return uPD7002->status; | |
| 103 | ||
| 104 | case 1: | |
| 105 | return uPD7002->data1; | |
| 106 | ||
| 107 | case 2: case 3: | |
| 108 | return uPD7002->data0; | |
| 109 | } | |
| 110 | return 0; | |
| 111 | } | |
| 112 | ||
| 113 | ||
| 114 | ||
| 115 | WRITE8_DEVICE_HANDLER ( uPD7002_w ) | |
| 116 | { | |
| 117 | uPD7002_t *uPD7002 = get_safe_token(device); | |
| 118 | /* logerror("write to uPD7002 $%02X = $%02X\n",offset,data); */ | |
| 119 | ||
| 120 | switch(offset&0x03) | |
| 121 | { | |
| 122 | case 0: | |
| 123 | /* | |
| 124 | Data Latch/AD start | |
| 125 | D0 and D1 together define which one of the four input channels is selected | |
| 126 | D2 flag input, normally set to 0???? | |
| 127 | D3 defines whether an 8 (0) or 12 (1) bit resolution conversion should occur | |
| 128 | D4 to D7 not used. | |
| 129 | ||
| 130 | an 8 bit conversion typically takes 4ms | |
| 131 | an 12 bit conversion typically takes 10ms | |
| 132 | ||
| 133 | writing to this register will initiate a conversion. | |
| 134 | */ | |
| 135 | ||
| 136 | /* set D6=0 busy ,D7=1 conversion not complete */ | |
| 137 | uPD7002->status=(data & 0x0f) | 0x80; | |
| 138 | ||
| 139 | // call the EOC function with EOC from status | |
| 140 | // uPD7002_EOC_r(0) this has just been set to 1 | |
| 141 | if (uPD7002->intf->EOC_func) uPD7002->intf->EOC_func(device, 1); | |
| 142 | ||
| 143 | /* the uPD7002 works by sampling the analogue value at the start of the conversion | |
| 144 | so it is read hear and stored until the end of the A to D conversion */ | |
| 145 | ||
| 146 | // this function should return a 16 bit value. | |
| 147 | uPD7002->digitalvalue = uPD7002->intf->get_analogue_func(device, uPD7002->status & 0x03); | |
| 148 | ||
| 149 | uPD7002->conversion_counter++; | |
| 150 | ||
| 151 | // call a timer to start the conversion | |
| 152 | if (uPD7002->status & 0x08) | |
| 153 | { | |
| 154 | // 12 bit conversion takes 10ms | |
| 155 | space.machine().scheduler().timer_set(attotime::from_msec(10), FUNC(uPD7002_conversioncomplete), uPD7002->conversion_counter, (void *)device); | |
| 156 | } else { | |
| 157 | // 8 bit conversion takes 4ms | |
| 158 | space.machine().scheduler().timer_set(attotime::from_msec(4), FUNC(uPD7002_conversioncomplete), uPD7002->conversion_counter, (void *)device); | |
| 159 | } | |
| 160 | break; | |
| 161 | ||
| 162 | case 1: case 2: | |
| 163 | /* Nothing */ | |
| 164 | break; | |
| 165 | ||
| 166 | case 3: | |
| 167 | /* Test Mode: Used for inspecting the device, The data input-output terminals assume an input | |
| 168 | state and are connected to the A/D counter. Therefore, the A/D conversion data | |
| 169 | read out after this is meaningless. | |
| 170 | */ | |
| 171 | break; | |
| 172 | } | |
| 173 | } | |
| 174 | ||
| 175 | /* Device Interface */ | |
| 176 | ||
| 177 | static DEVICE_START( uPD7002 ) | |
| 178 | { | |
| 179 | uPD7002_t *uPD7002 = get_safe_token(device); | |
| 180 | // validate arguments | |
| 181 | ||
| 182 | assert(device != NULL); | |
| 183 | assert(device->tag() != NULL); | |
| 184 | assert(device->static_config() != NULL); | |
| 185 | ||
| 186 | uPD7002->intf = (const uPD7002_interface*)device->static_config(); | |
| 187 | uPD7002->status = 0; | |
| 188 | uPD7002->data1 = 0; | |
| 189 | uPD7002->data0 = 0; | |
| 190 | uPD7002->digitalvalue = 0; | |
| 191 | uPD7002->conversion_counter = 0; | |
| 192 | ||
| 193 | // register for state saving | |
| 194 | state_save_register_item(device->machine(), "uPD7002", device->tag(), 0, uPD7002->status); | |
| 195 | state_save_register_item(device->machine(), "uPD7002", device->tag(), 0, uPD7002->data1); | |
| 196 | state_save_register_item(device->machine(), "uPD7002", device->tag(), 0, uPD7002->data0); | |
| 197 | state_save_register_item(device->machine(), "uPD7002", device->tag(), 0, uPD7002->digitalvalue); | |
| 198 | state_save_register_item(device->machine(), "uPD7002", device->tag(), 0, uPD7002->conversion_counter); | |
| 199 | } | |
| 200 | ||
| 201 | static DEVICE_RESET( uPD7002 ) | |
| 202 | { | |
| 203 | uPD7002_t *uPD7002 = get_safe_token(device); | |
| 204 | uPD7002->status = 0; | |
| 205 | uPD7002->data1 = 0; | |
| 206 | uPD7002->data0 = 0; | |
| 207 | uPD7002->digitalvalue = 0; | |
| 208 | uPD7002->conversion_counter = 0; | |
| 209 | } | |
| 210 | ||
| 211 | const device_type UPD7002 = &device_creator<uPD7002_device>; | |
| 212 | ||
| 213 | uPD7002_device::uPD7002_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) | |
| 214 | : device_t(mconfig, UPD7002, "uPD7002", tag, owner, clock) | |
| 215 | { | |
| 216 | m_token = global_alloc_clear(uPD7002_t); | |
| 217 | } | |
| 218 | ||
| 219 | //------------------------------------------------- | |
| 220 | // device_config_complete - perform any | |
| 221 | // operations now that the configuration is | |
| 222 | // complete | |
| 223 | //------------------------------------------------- | |
| 224 | ||
| 225 | void uPD7002_device::device_config_complete() | |
| 226 | { | |
| 227 | } | |
| 228 | ||
| 229 | //------------------------------------------------- | |
| 230 | // device_start - device-specific startup | |
| 231 | //------------------------------------------------- | |
| 232 | ||
| 233 | void uPD7002_device::device_start() | |
| 234 | { | |
| 235 | DEVICE_START_NAME( uPD7002 )(this); | |
| 236 | } | |
| 237 | ||
| 238 | //------------------------------------------------- | |
| 239 | // device_reset - device-specific reset | |
| 240 | //------------------------------------------------- | |
| 241 | ||
| 242 | void uPD7002_device::device_reset() | |
| 243 | { | |
| 244 | DEVICE_RESET_NAME( uPD7002 )(this); | |
| 245 | } |
| Added: svn:eol-style + native Added: svn:mime-type + text/plain |
| r0 | r21685 | |
|---|---|---|
| 1 | /***************************************************************************** | |
| 2 | * | |
| 3 | * machine/upd7002.h | |
| 4 | * | |
| 5 | * uPD7002 Analogue to Digital Converter | |
| 6 | * | |
| 7 | * Driver by Gordon Jefferyes <mess_bbc@gjeffery.dircon.co.uk> | |
| 8 | * | |
| 9 | ****************************************************************************/ | |
| 10 | ||
| 11 | #ifndef UPD7002_H_ | |
| 12 | #define UPD7002_H_ | |
| 13 | ||
| 14 | /*************************************************************************** | |
| 15 | MACROS | |
| 16 | ***************************************************************************/ | |
| 17 | ||
| 18 | class uPD7002_device : public device_t | |
| 19 | { | |
| 20 | public: | |
| 21 | uPD7002_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); | |
| 22 | ~uPD7002_device() { global_free(m_token); } | |
| 23 | ||
| 24 | // access to legacy token | |
| 25 | void *token() const { assert(m_token != NULL); return m_token; } | |
| 26 | protected: | |
| 27 | // device-level overrides | |
| 28 | virtual void device_config_complete(); | |
| 29 | virtual void device_start(); | |
| 30 | virtual void device_reset(); | |
| 31 | private: | |
| 32 | // internal state | |
| 33 | void *m_token; | |
| 34 | }; | |
| 35 | ||
| 36 | extern const device_type UPD7002; | |
| 37 | ||
| 38 | ||
| 39 | /*************************************************************************** | |
| 40 | TYPE DEFINITIONS | |
| 41 | ***************************************************************************/ | |
| 42 | ||
| 43 | typedef int (*uPD7002_get_analogue_func)(device_t *device, int channel_number); | |
| 44 | #define UPD7002_GET_ANALOGUE(name) int name(device_t *device, int channel_number ) | |
| 45 | ||
| 46 | typedef void (*uPD7002_eoc_func)(device_t *device, int data); | |
| 47 | #define UPD7002_EOC(name) void name(device_t *device, int data ) | |
| 48 | ||
| 49 | ||
| 50 | struct uPD7002_interface | |
| 51 | { | |
| 52 | uPD7002_get_analogue_func get_analogue_func; | |
| 53 | uPD7002_eoc_func EOC_func; | |
| 54 | }; | |
| 55 | ||
| 56 | /*************************************************************************** | |
| 57 | FUNCTION PROTOTYPES | |
| 58 | ***************************************************************************/ | |
| 59 | ||
| 60 | /* Standard handlers */ | |
| 61 | ||
| 62 | DECLARE_READ8_DEVICE_HANDLER ( uPD7002_EOC_r ); | |
| 63 | DECLARE_READ8_DEVICE_HANDLER ( uPD7002_r ); | |
| 64 | DECLARE_WRITE8_DEVICE_HANDLER ( uPD7002_w ); | |
| 65 | ||
| 66 | ||
| 67 | /*************************************************************************** | |
| 68 | DEVICE CONFIGURATION MACROS | |
| 69 | ***************************************************************************/ | |
| 70 | ||
| 71 | #define MCFG_UPD7002_ADD(_tag, _intrf) \ | |
| 72 | MCFG_DEVICE_ADD(_tag, UPD7002, 0) \ | |
| 73 | MCFG_DEVICE_CONFIG(_intrf) | |
| 74 | ||
| 75 | ||
| 76 | #endif /* UPD7002_H_ */ |
| Added: svn:mime-type + text/plain Added: svn:eol-style + native |
| r0 | r21685 | |
|---|---|---|
| 1 | /**************************************************************************** | |
| 2 | ||
| 3 | ay31015.c by Robbbert, May 2008. Bugs fixed by Judge. | |
| 4 | ||
| 5 | Code for the AY-3-1014A, AY-3-1015(D), AY-5-1013(A), and AY-6-1013 UARTs | |
| 6 | The HD6402 UART is compatible with the AY-3-1015 UART. | |
| 7 | ||
| 8 | This is cycle-accurate according to the specifications. | |
| 9 | ||
| 10 | It supports independent receive and transmit clocks, | |
| 11 | and transmission and reception can occur simultaneously if desired. | |
| 12 | ||
| 13 | ***************************************************************************** | |
| 14 | ||
| 15 | Differences between the chip types: | |
| 16 | - All units have pull-up resistors on the inputs, except for the AY-3-1014A which is CMOS-compatible. | |
| 17 | - AY-3-1014A and AY-3-1015 - 1.5 stop bits mode available. | |
| 18 | - Max baud rate of 30k, except AY-5-1013 which has 20k. | |
| 19 | - AY-5-1013 has extended temperature ratings. | |
| 20 | - AY-5-1013 and AY-6-1013 require a -12 volt supply on pin 2. Pin is not used otherwise. | |
| 21 | - AY-5-1013 and AY-6-1013 do not reset the received data register when XR pin is used. | |
| 22 | ||
| 23 | ****************************************************************************** | |
| 24 | ||
| 25 | It is not clear in the documentation as to which settings will reset the device. | |
| 26 | To be safe, we will always reset whenever the control register changes. | |
| 27 | ||
| 28 | Also, it not clear exactly what happens under various error conditions. | |
| 29 | ||
| 30 | ******************************************************************************** | |
| 31 | ||
| 32 | Device Data: | |
| 33 | ||
| 34 | * Common Controls: | |
| 35 | -- Pin 1 - Vcc - 5 volts | |
| 36 | -- Pin 2 - not used (on AY-5-1013 and AY-6-1013 this is Voo = -12 volts) | |
| 37 | -- Pin 3 - Gnd - 0 volts | |
| 38 | -- Pin 21 - XR - External Reset - resets all registers to initial state except for the control register | |
| 39 | -- Pin 35 - NP - No Parity - "1" will kill any parity processing | |
| 40 | -- Pin 36 - TSB - Number of Stop Bits - "0" = 1 stop bit; "1" = 2 stop bits. If "1", and 5 bits per character, then we have 1.5 stop bits | |
| 41 | -- pin 37 - NB1 | |
| 42 | -- pin 38 - NB2 - Number of bits per character = NB1 + (NB2 * 2) + 5 | |
| 43 | -- pin 39 - EPS - Odd or Even Parity Select - "0" = Odd parity; "1" = Even parity. Has no effect if NP is high. | |
| 44 | -- Pin 34 - CS - Control Strobe - Read NP, TSB, EPS, NB1, NB2 into the control register. | |
| 45 | ||
| 46 | Format of data stream: | |
| 47 | Start bit (low), Bit 0, Bit 1... highest bit, Parity bit (if enabled), 1-2 stop bits (high) | |
| 48 | ||
| 49 | ||
| 50 | * Receiver Controls: | |
| 51 | -- Pin 17 - RCP - Clock which is 16x the desired baud rate | |
| 52 | -- Pin 20 - SI - Serial input stream - "1" = Mark (waiting for input), "0" = Space (Start bit) initiates the transfer of a byte | |
| 53 | -- Pin 4 - RDE - "0" causes the received data to appear on RD1 to RD8. | |
| 54 | -- Pins 5 to 12 - RD8 to RD1 - These are the data lines (bits 7 to 0). Data is right-justified. | |
| 55 | -- Pin 16 - SWE - Status word enable - causes the status bits (PE, FE, OR, DAV, TBMT) to appear at the pins. | |
| 56 | -- Pin 19 - DAV - "1" indicates that a byte has been received by the UART, and should now be accepted by the computer | |
| 57 | -- Pin 18 - RDAV - "0" will force DAV low. | |
| 58 | -- Pin 13 - PE - Parity error - "1" indicates that a parity error occurred | |
| 59 | -- Pin 14 - FE - Framing error - "1" Indicates that the stop bit was missing | |
| 60 | -- Pin 15 - OR - overrun - "1" indicates that a new character has become available before the computer had accepted the previous character | |
| 61 | ||
| 62 | * Transmitter controls: | |
| 63 | -- Pin 40 - TCP - Clock which is 16x the desired baud rate | |
| 64 | -- Pin 25 - SO - Serial output stream - it will stay at "1" while no data is being transmitted | |
| 65 | -- Pins 26 to 33 - DB1 to DB8 - These are the data lines containing the byte to be sent | |
| 66 | -- Pin 23 - DS - Data Strobe - "0" will copy DB1 to DB8 into the transmit buffer | |
| 67 | -- Pin 22 - TBMT - Transmit buffer Empty - "1" indicates to the computer that another byte may be sent to the UART | |
| 68 | -- Pin 24 - EOC - End of Character - "0" means that a character is being sent. | |
| 69 | ||
| 70 | ******************************************* COMMON CONTROLS ********************************************************/ | |
| 71 | ||
| 72 | #include "emu.h" | |
| 73 | #include "ay31015.h" | |
| 74 | ||
| 75 | enum state_t | |
| 76 | { | |
| 77 | IDLE, | |
| 78 | START_BIT, | |
| 79 | PROCESSING, | |
| 80 | PARITY_BIT, | |
| 81 | FIRST_STOP_BIT, | |
| 82 | SECOND_STOP_BIT, | |
| 83 | PREP_TIME | |
| 84 | }; | |
| 85 | ||
| 86 | ||
| 87 | struct ay31015_t | |
| 88 | { | |
| 89 | const ay31015_config *config; | |
| 90 | ||
| 91 | int pins[41]; | |
| 92 | ||
| 93 | UINT8 control_reg; | |
| 94 | UINT8 status_reg; | |
| 95 | UINT16 second_stop_bit; // 0, 8, 16 | |
| 96 | UINT16 total_pulses; // bits * 16 | |
| 97 | UINT8 internal_sample; | |
| 98 | ||
| 99 | state_t rx_state; | |
| 100 | UINT8 rx_data; // byte being received | |
| 101 | UINT8 rx_buffer; // received byte waiting to be accepted by computer | |
| 102 | UINT8 rx_bit_count; | |
| 103 | UINT8 rx_parity; | |
| 104 | UINT16 rx_pulses; // total pulses left | |
| 105 | double rx_clock; | |
| 106 | emu_timer *rx_timer; | |
| 107 | ||
| 108 | state_t tx_state; | |
| 109 | UINT8 tx_data; // byte being sent | |
| 110 | UINT8 tx_buffer; // next byte to send | |
| 111 | UINT8 tx_parity; | |
| 112 | UINT16 tx_pulses; // total pulses left | |
| 113 | double tx_clock; | |
| 114 | emu_timer *tx_timer; | |
| 115 | ||
| 116 | devcb_resolved_read8 read_si; /* SI - pin 20 - This will be called whenever the SI pin is sampled. Optional */ | |
| 117 | devcb_resolved_write8 write_so; /* SO - pin 25 - This will be called whenever data is put on the SO pin. Optional */ | |
| 118 | devcb_resolved_write8 status_changed; /* This will be called whenever one of the status pins may have changed. Optional */ | |
| 119 | }; | |
| 120 | ||
| 121 | ||
| 122 | /* control reg */ | |
| 123 | #define CONTROL_NB1 0x01 | |
| 124 | #define CONTROL_NB2 0x02 | |
| 125 | #define CONTROL_TSB 0x04 | |
| 126 | #define CONTROL_EPS 0x08 | |
| 127 | #define CONTROL_NP 0x10 | |
| 128 | ||
| 129 | ||
| 130 | /* status reg */ | |
| 131 | #define STATUS_TBMT 0x01 | |
| 132 | #define STATUS_DAV 0x02 | |
| 133 | #define STATUS_OR 0x04 | |
| 134 | #define STATUS_FE 0x08 | |
| 135 | #define STATUS_PE 0x10 | |
| 136 | #define STATUS_EOC 0x20 | |
| 137 | ||
| 138 | ||
| 139 | /*------------------------------------------------- | |
| 140 | get_safe_token - safely gets the data | |
| 141 | -------------------------------------------------*/ | |
| 142 | ||
| 143 | INLINE ay31015_t *get_safe_token(device_t *device) | |
| 144 | { | |
| 145 | assert(device != NULL); | |
| 146 | assert(device->type() == AY31015); | |
| 147 | return (ay31015_t *) downcast<ay31015_device *>(device)->token(); | |
| 148 | } | |
| 149 | ||
| 150 | ||
| 151 | INLINE UINT8 ay31015_get_si( device_t *device ) | |
| 152 | { | |
| 153 | ay31015_t *ay31015 = get_safe_token( device ); | |
| 154 | ||
| 155 | if ( !ay31015->read_si.isnull() ) | |
| 156 | ay31015->pins[AY31015_SI] = ay31015->read_si( 0 ) ? 1 : 0; | |
| 157 | ||
| 158 | return ay31015->pins[AY31015_SI]; | |
| 159 | } | |
| 160 | ||
| 161 | ||
| 162 | INLINE void ay31015_set_so( device_t *device, int data ) | |
| 163 | { | |
| 164 | ay31015_t *ay31015 = get_safe_token( device ); | |
| 165 | ||
| 166 | ay31015->pins[AY31015_SO] = data ? 1 : 0; | |
| 167 | ||
| 168 | if ( !ay31015->write_so.isnull() ) | |
| 169 | ay31015->write_so( 0, ay31015->pins[AY31015_SO] ); | |
| 170 | } | |
| 171 | ||
| 172 | ||
| 173 | INLINE int ay31015_update_status_pin( ay31015_t *ay31015, UINT8 reg_bit, ay31015_output_pin_t pin ) | |
| 174 | { | |
| 175 | int new_value = ( ay31015->status_reg & reg_bit ) ? 1 : 0; | |
| 176 | ||
| 177 | if ( new_value == ay31015->pins[pin] ) | |
| 178 | return 0; | |
| 179 | ||
| 180 | ay31015->pins[pin] = new_value; | |
| 181 | return 1; | |
| 182 | } | |
| 183 | ||
| 184 | ||
| 185 | /*------------------------------------------------- | |
| 186 | ay31015_update_status_pins - Update the status pins | |
| 187 | -------------------------------------------------*/ | |
| 188 | static void ay31015_update_status_pins( device_t *device ) | |
| 189 | { | |
| 190 | ay31015_t *ay31015 = get_safe_token( device ); | |
| 191 | int status_pins_changed = 0; | |
| 192 | ||
| 193 | /* Should status pins be updated? */ | |
| 194 | if ( ! ay31015->pins[AY31015_SWE] ) | |
| 195 | { | |
| 196 | status_pins_changed += ay31015_update_status_pin( ay31015, STATUS_PE, AY31015_PE ); | |
| 197 | status_pins_changed += ay31015_update_status_pin( ay31015, STATUS_FE, AY31015_FE ); | |
| 198 | status_pins_changed += ay31015_update_status_pin( ay31015, STATUS_OR, AY31015_OR ); | |
| 199 | status_pins_changed += ay31015_update_status_pin( ay31015, STATUS_DAV, AY31015_DAV ); | |
| 200 | status_pins_changed += ay31015_update_status_pin( ay31015, STATUS_TBMT, AY31015_TBMT ); | |
| 201 | } | |
| 202 | status_pins_changed += ay31015_update_status_pin( ay31015, STATUS_EOC, AY31015_EOC ); | |
| 203 | ||
| 204 | if ( status_pins_changed && !ay31015->status_changed.isnull() ) | |
| 205 | { | |
| 206 | ay31015->status_changed( 0, status_pins_changed ); | |
| 207 | } | |
| 208 | } | |
| 209 | ||
| 210 | ||
| 211 | /*************************************************** RECEIVE CONTROLS *************************************************/ | |
| 212 | ||
| 213 | ||
| 214 | /*------------------------------------------------- | |
| 215 | ay31015_rx_process - convert serial to parallel | |
| 216 | -------------------------------------------------*/ | |
| 217 | static TIMER_CALLBACK( ay31015_rx_process ) | |
| 218 | { | |
| 219 | device_t *device = (device_t *)ptr; | |
| 220 | ay31015_t *ay31015 = get_safe_token( device ); | |
| 221 | ||
| 222 | switch (ay31015->rx_state) | |
| 223 | { | |
| 224 | case PREP_TIME: // assist sync by ensuring high bit occurs | |
| 225 | ay31015->rx_pulses--; | |
| 226 | if (ay31015_get_si( device )) | |
| 227 | ay31015->rx_state = IDLE; | |
| 228 | return; | |
| 229 | ||
| 230 | case IDLE: | |
| 231 | ay31015->rx_pulses--; | |
| 232 | if (!ay31015_get_si( device )) | |
| 233 | { | |
| 234 | ay31015->rx_state = START_BIT; | |
| 235 | ay31015->rx_pulses = 16; | |
| 236 | } | |
| 237 | return; | |
| 238 | ||
| 239 | case START_BIT: | |
| 240 | ay31015->rx_pulses--; | |
| 241 | if (ay31015->rx_pulses == 8) // start bit must be low at sample time | |
| 242 | { | |
| 243 | if ( ay31015_get_si( device ) ) | |
| 244 | ay31015->rx_state = IDLE; | |
| 245 | } | |
| 246 | else | |
| 247 | if (!ay31015->rx_pulses) // end of start bit | |
| 248 | { | |
| 249 | ay31015->rx_state = PROCESSING; | |
| 250 | ay31015->rx_pulses = ay31015->total_pulses; | |
| 251 | ay31015->rx_bit_count = 0; | |
| 252 | ay31015->rx_parity = 0; | |
| 253 | ay31015->rx_data = 0; | |
| 254 | } | |
| 255 | return; | |
| 256 | ||
| 257 | case PROCESSING: | |
| 258 | ay31015->rx_pulses--; | |
| 259 | if (!ay31015->rx_pulses) // end of a byte | |
| 260 | { | |
| 261 | ay31015->rx_pulses = 16; | |
| 262 | if (ay31015->control_reg & CONTROL_NP) // see if we need to get a parity bit | |
| 263 | ay31015->rx_state = FIRST_STOP_BIT; | |
| 264 | else | |
| 265 | ay31015->rx_state = PARITY_BIT; | |
| 266 | } | |
| 267 | else | |
| 268 | if (!(ay31015->rx_pulses & 15)) // end of a bit | |
| 269 | ay31015->rx_bit_count++; | |
| 270 | else | |
| 271 | if ((ay31015->rx_pulses & 15) == 8) // sample input stream | |
| 272 | { | |
| 273 | ay31015->internal_sample = ay31015_get_si( device ); | |
| 274 | ay31015->rx_parity ^= ay31015->internal_sample; // calculate cumulative parity | |
| 275 | ay31015->rx_data |= ay31015->internal_sample << ay31015->rx_bit_count; | |
| 276 | } | |
| 277 | return; | |
| 278 | ||
| 279 | case PARITY_BIT: | |
| 280 | ay31015->rx_pulses--; | |
| 281 | ||
| 282 | if (ay31015->rx_pulses == 8) // sample input stream | |
| 283 | { | |
| 284 | ay31015->rx_parity ^= ay31015_get_si( device ); // calculate cumulative parity | |
| 285 | } | |
| 286 | else | |
| 287 | if (!ay31015->rx_pulses) // end of a byte | |
| 288 | { | |
| 289 | ay31015->rx_pulses = 16; | |
| 290 | ay31015->rx_state = FIRST_STOP_BIT; | |
| 291 | ||
| 292 | if ((!(ay31015->control_reg & CONTROL_EPS)) && (ay31015->rx_parity)) | |
| 293 | ay31015->rx_parity = 0; // odd parity, ok | |
| 294 | else | |
| 295 | if ((ay31015->control_reg & CONTROL_EPS) && (!ay31015->rx_parity)) | |
| 296 | ay31015->rx_parity = 0; // even parity, ok | |
| 297 | else | |
| 298 | ay31015->rx_parity = 1; // parity error | |
| 299 | } | |
| 300 | return; | |
| 301 | ||
| 302 | case FIRST_STOP_BIT: | |
| 303 | ay31015->rx_pulses--; | |
| 304 | if (ay31015->rx_pulses == 8) // sample input stream | |
| 305 | ay31015->internal_sample = ay31015_get_si( device ); | |
| 306 | else | |
| 307 | if (ay31015->rx_pulses == 7) // set error flags | |
| 308 | { | |
| 309 | if (!ay31015->internal_sample) | |
| 310 | { | |
| 311 | ay31015->status_reg |= STATUS_FE; // framing error - the stop bit not high | |
| 312 | ay31015->rx_state = PREP_TIME; // lost sync - start over | |
| 313 | // return; | |
| 314 | } | |
| 315 | else | |
| 316 | ay31015->status_reg &= ~STATUS_FE; | |
| 317 | ||
| 318 | if ((ay31015->rx_parity) && (!(ay31015->control_reg & CONTROL_NP))) | |
| 319 | ay31015->status_reg |= STATUS_PE; // parity error | |
| 320 | else | |
| 321 | ay31015->status_reg &= ~STATUS_PE; | |
| 322 | ||
| 323 | if (ay31015->status_reg & STATUS_DAV) | |
| 324 | ay31015->status_reg |= STATUS_OR; // overrun error - previous byte still in buffer | |
| 325 | else | |
| 326 | ay31015->status_reg &= ~STATUS_OR; | |
| 327 | ||
| 328 | ay31015->rx_buffer = ay31015->rx_data; // bring received byte out for computer to read | |
| 329 | ||
| 330 | ay31015_update_status_pins( device ); | |
| 331 | } | |
| 332 | else | |
| 333 | if (ay31015->rx_pulses == 6) | |
| 334 | { | |
| 335 | ay31015->status_reg |= STATUS_DAV; // tell computer that new byte is ready | |
| 336 | ay31015_update_status_pins( device ); | |
| 337 | } | |
| 338 | else | |
| 339 | if (ay31015->rx_pulses == 4) | |
| 340 | { | |
| 341 | if (ay31015->second_stop_bit) | |
| 342 | { | |
| 343 | /* We should wait for the full first stop bit and | |
| 344 | the beginning of the second stop bit */ | |
| 345 | ay31015->rx_state = SECOND_STOP_BIT; | |
| 346 | ay31015->rx_pulses += ay31015->second_stop_bit - 7; | |
| 347 | } | |
| 348 | else | |
| 349 | { | |
| 350 | /* We have seen a STOP bit, go back to PREP_TIME */ | |
| 351 | ay31015->rx_state = PREP_TIME; | |
| 352 | } | |
| 353 | } | |
| 354 | return; | |
| 355 | ||
| 356 | case SECOND_STOP_BIT: | |
| 357 | ay31015->rx_pulses--; | |
| 358 | if (!ay31015->rx_pulses) | |
| 359 | ay31015->rx_state = PREP_TIME; | |
| 360 | return; | |
| 361 | ||
| 362 | } | |
| 363 | } | |
| 364 | ||
| 365 | ||
| 366 | /*************************************************** TRANSMIT CONTROLS *************************************************/ | |
| 367 | ||
| 368 | ||
| 369 | /*------------------------------------------------- | |
| 370 | ay31015_tx_process - convert parallel to serial | |
| 371 | -------------------------------------------------*/ | |
| 372 | static TIMER_CALLBACK( ay31015_tx_process ) | |
| 373 | { | |
| 374 | device_t *device = (device_t *)ptr; | |
| 375 | ay31015_t *ay31015 = get_safe_token( device ); | |
| 376 | ||
| 377 | UINT8 t1; | |
| 378 | switch (ay31015->tx_state) | |
| 379 | { | |
| 380 | case IDLE: | |
| 381 | if (!(ay31015->status_reg & STATUS_TBMT)) | |
| 382 | { | |
| 383 | ay31015->tx_state = PREP_TIME; // When idle, see if a byte has been sent to us | |
| 384 | ay31015->tx_pulses = 1; | |
| 385 | } | |
| 386 | return; | |
| 387 | ||
| 388 | case PREP_TIME: // This phase lets the transmitter regain sync after an idle period | |
| 389 | ay31015->tx_pulses--; | |
| 390 | if (!ay31015->tx_pulses) | |
| 391 | { | |
| 392 | ay31015->tx_state = START_BIT; | |
| 393 | ay31015->tx_pulses = 16; | |
| 394 | } | |
| 395 | return; | |
| 396 | ||
| 397 | case START_BIT: | |
| 398 | if (ay31015->tx_pulses == 16) // beginning of start bit | |
| 399 | { | |
| 400 | ay31015->tx_data = ay31015->tx_buffer; // load the shift register | |
| 401 | ay31015->status_reg |= STATUS_TBMT; // tell computer that another byte can be sent to uart | |
| 402 | ay31015_set_so( device, 0 ); /* start bit begins now (we are "spacing") */ | |
| 403 | ay31015->status_reg &= ~STATUS_EOC; // we are no longer idle | |
| 404 | ay31015->tx_parity = 0; | |
| 405 | ay31015_update_status_pins( device ); | |
| 406 | } | |
| 407 | ||
| 408 | ay31015->tx_pulses--; | |
| 409 | if (!ay31015->tx_pulses) // end of start bit | |
| 410 | { | |
| 411 | ay31015->tx_state = PROCESSING; | |
| 412 | ay31015->tx_pulses = ay31015->total_pulses; | |
| 413 | } | |
| 414 | return; | |
| 415 | ||
| 416 | case PROCESSING: | |
| 417 | if (!(ay31015->tx_pulses & 15)) // beginning of a data bit | |
| 418 | { | |
| 419 | if (ay31015->tx_data & 1) | |
| 420 | { | |
| 421 | ay31015_set_so( device, 1 ); | |
| 422 | ay31015->tx_parity++; // calculate cumulative parity | |
| 423 | } | |
| 424 | else | |
| 425 | ay31015_set_so( device, 0 ); | |
| 426 | ||
| 427 | ay31015->tx_data >>= 1; // adjust the shift register | |
| 428 | } | |
| 429 | ||
| 430 | ay31015->tx_pulses--; | |
| 431 | if (!ay31015->tx_pulses) // all data bits sent | |
| 432 | { | |
| 433 | ay31015->tx_pulses = 16; | |
| 434 | if (ay31015->control_reg & CONTROL_NP) // see if we need to make a parity bit | |
| 435 | ay31015->tx_state = FIRST_STOP_BIT; | |
| 436 | else | |
| 437 | ay31015->tx_state = PARITY_BIT; | |
| 438 | } | |
| 439 | ||
| 440 | return; | |
| 441 | ||
| 442 | case PARITY_BIT: | |
| 443 | if (ay31015->tx_pulses == 16) | |
| 444 | { | |
| 445 | t1 = (ay31015->control_reg & CONTROL_EPS) ? 0 : 1; | |
| 446 | t1 ^= (ay31015->tx_parity & 1); | |
| 447 | if (t1) | |
| 448 | ay31015_set_so( device, 1 ); /* extra bit to set the correct parity */ | |
| 449 | else | |
| 450 | ay31015_set_so( device, 0 ); /* it was already correct */ | |
| 451 | } | |
| 452 | ||
| 453 | ay31015->tx_pulses--; | |
| 454 | if (!ay31015->tx_pulses) | |
| 455 | { | |
| 456 | ay31015->tx_state = FIRST_STOP_BIT; | |
| 457 | ay31015->tx_pulses = 16; | |
| 458 | } | |
| 459 | return; | |
| 460 | ||
| 461 | case FIRST_STOP_BIT: | |
| 462 | if (ay31015->tx_pulses == 16) | |
| 463 | ay31015_set_so( device, 1 ); /* create a stop bit (marking and soon idle) */ | |
| 464 | ay31015->tx_pulses--; | |
| 465 | if (!ay31015->tx_pulses) | |
| 466 | { | |
| 467 | ay31015->status_reg |= STATUS_EOC; // character is completely sent | |
| 468 | if (ay31015->second_stop_bit) | |
| 469 | { | |
| 470 | ay31015->tx_state = SECOND_STOP_BIT; | |
| 471 | ay31015->tx_pulses = ay31015->second_stop_bit; | |
| 472 | } | |
| 473 | else | |
| 474 | if (ay31015->status_reg & STATUS_TBMT) | |
| 475 | ay31015->tx_state = IDLE; // if nothing to send, go idle | |
| 476 | else | |
| 477 | { | |
| 478 | ay31015->tx_pulses = 16; | |
| 479 | ay31015->tx_state = START_BIT; // otherwise immediately start next byte | |
| 480 | } | |
| 481 | ay31015_update_status_pins( device ); | |
| 482 | } | |
| 483 | return; | |
| 484 | ||
| 485 | case SECOND_STOP_BIT: | |
| 486 | ay31015->tx_pulses--; | |
| 487 | if (!ay31015->tx_pulses) | |
| 488 | { | |
| 489 | if (ay31015->status_reg & STATUS_TBMT) | |
| 490 | ay31015->tx_state = IDLE; // if nothing to send, go idle | |
| 491 | else | |
| 492 | { | |
| 493 | ay31015->tx_pulses = 16; | |
| 494 | ay31015->tx_state = START_BIT; // otherwise immediately start next byte | |
| 495 | } | |
| 496 | } | |
| 497 | return; | |
| 498 | ||
| 499 | } | |
| 500 | } | |
| 501 | ||
| 502 | ||
| 503 | /*------------------------------------------------- | |
| 504 | ay31015_reset - reset internal state | |
| 505 | -------------------------------------------------*/ | |
| 506 | static void ay31015_reset( device_t *device ) | |
| 507 | { | |
| 508 | ay31015_t *ay31015 = get_safe_token( device ); | |
| 509 | ||
| 510 | /* total pulses = 16 * data-bits */ | |
| 511 | UINT8 t1; | |
| 512 | ||
| 513 | if ( ay31015->control_reg & CONTROL_NB2 ) | |
| 514 | t1 = ( ay31015->control_reg & CONTROL_NB1 ) ? 8 : 7; | |
| 515 | else | |
| 516 | t1 = ( ay31015->control_reg & CONTROL_NB1 ) ? 6 : 5; | |
| 517 | ||
| 518 | ay31015->total_pulses = t1 << 4; /* total clock pulses to load a byte */ | |
| 519 | ay31015->second_stop_bit = ((ay31015->control_reg & CONTROL_TSB) ? 16 : 0); /* 2nd stop bit */ | |
| 520 | if ((t1 == 5) && (ay31015->second_stop_bit == 16)) | |
| 521 | ay31015->second_stop_bit = 8; /* 5 data bits and 2 stop bits = 1.5 stop bits */ | |
| 522 | ay31015->status_reg = STATUS_EOC | STATUS_TBMT; | |
| 523 | ay31015->tx_data = 0; | |
| 524 | ay31015->rx_state = PREP_TIME; | |
| 525 | ay31015->tx_state = IDLE; | |
| 526 | ay31015->pins[AY31015_SI] = 1; | |
| 527 | ay31015_set_so( device, 1 ); | |
| 528 | ||
| 529 | if ( ay31015->config->type == AY_3_1015 ) | |
| 530 | ay31015->rx_data = 0; | |
| 531 | ||
| 532 | } | |
| 533 | ||
| 534 | ||
| 535 | /*------------------------------------------------- | |
| 536 | ay31015_transfer_control_pins - transfers contents of controls pins to the control register | |
| 537 | -------------------------------------------------*/ | |
| 538 | static void ay31015_transfer_control_pins( device_t *device ) | |
| 539 | { | |
| 540 | ay31015_t *ay31015 = get_safe_token( device ); | |
| 541 | UINT8 control = 0; | |
| 542 | ||
| 543 | control |= ay31015->pins[AY31015_NP ] ? CONTROL_NP : 0; | |
| 544 | control |= ay31015->pins[AY31015_TSB] ? CONTROL_TSB : 0; | |
| 545 | control |= ay31015->pins[AY31015_NB1] ? CONTROL_NB1 : 0; | |
| 546 | control |= ay31015->pins[AY31015_NB2] ? CONTROL_NB2 : 0; | |
| 547 | control |= ay31015->pins[AY31015_EPS] ? CONTROL_EPS : 0; | |
| 548 | ||
| 549 | if ( ay31015->control_reg != control ) | |
| 550 | { | |
| 551 | ay31015->control_reg = control; | |
| 552 | ay31015_reset( device ); | |
| 553 | } | |
| 554 | } | |
| 555 | ||
| 556 | ||
| 557 | /*------------------------------------------------- | |
| 558 | ay31015_set_input_pin - set an input pin | |
| 559 | -------------------------------------------------*/ | |
| 560 | void ay31015_set_input_pin( device_t *device, ay31015_input_pin_t pin, int data ) | |
| 561 | { | |
| 562 | ay31015_t *ay31015 = get_safe_token(device); | |
| 563 | ||
| 564 | data = data ? 1 : 0; | |
| 565 | ||
| 566 | switch ( pin ) | |
| 567 | { | |
| 568 | case AY31015_SWE: | |
| 569 | ay31015->pins[pin] = data; | |
| 570 | ay31015_update_status_pins( device ); | |
| 571 | break; | |
| 572 | case AY31015_RDAV: | |
| 573 | ay31015->pins[pin] = data; | |
| 574 | if ( ! data ) | |
| 575 | { | |
| 576 | ay31015->status_reg &= ~STATUS_DAV; | |
| 577 | ay31015->pins[AY31015_DAV] = 0; | |
| 578 | } | |
| 579 | break; | |
| 580 | case AY31015_SI: | |
| 581 | ay31015->pins[pin] = data; | |
| 582 | break; | |
| 583 | case AY31015_XR: | |
| 584 | ay31015->pins[pin] = data; | |
| 585 | if ( data ) | |
| 586 | ay31015_reset( device ); | |
| 587 | break; | |
| 588 | case AY31015_CS: | |
| 589 | case AY31015_NP: | |
| 590 | case AY31015_TSB: | |
| 591 | case AY31015_NB1: | |
| 592 | case AY31015_NB2: | |
| 593 | case AY31015_EPS: | |
| 594 | ay31015->pins[pin] = data; | |
| 595 | if ( ay31015->pins[AY31015_CS] ) | |
| 596 | ay31015_transfer_control_pins( device ); | |
| 597 | break; | |
| 598 | } | |
| 599 | } | |
| 600 | ||
| 601 | ||
| 602 | /*------------------------------------------------- | |
| 603 | ay31015_get_output_pin - get the status of an output pin | |
| 604 | -------------------------------------------------*/ | |
| 605 | int ay31015_get_output_pin( device_t *device, ay31015_output_pin_t pin ) | |
| 606 | { | |
| 607 | ay31015_t *ay31015 = get_safe_token(device); | |
| 608 | ||
| 609 | return ay31015->pins[pin]; | |
| 610 | } | |
| 611 | ||
| 612 | ||
| 613 | INLINE void ay31015_update_rx_timer( device_t *device ) | |
| 614 | { | |
| 615 | ay31015_t *ay31015 = get_safe_token( device ); | |
| 616 | ||
| 617 | if ( ay31015->rx_clock > 0.0 ) | |
| 618 | { | |
| 619 | ay31015->rx_timer->adjust( attotime::from_hz( ay31015->rx_clock ), 0, attotime::from_hz( ay31015->rx_clock ) ); | |
| 620 | } | |
| 621 | else | |
| 622 | { | |
| 623 | ay31015->rx_timer->enable( 0 ); | |
| 624 | } | |
| 625 | } | |
| 626 | ||
| 627 | ||
| 628 | INLINE void ay31015_update_tx_timer( device_t *device ) | |
| 629 | { | |
| 630 | ay31015_t *ay31015 = get_safe_token( device ); | |
| 631 | ||
| 632 | if ( ay31015->tx_clock > 0.0 ) | |
| 633 | { | |
| 634 | ay31015->tx_timer->adjust( attotime::from_hz( ay31015->tx_clock ), 0, attotime::from_hz( ay31015->tx_clock ) ); | |
| 635 | } | |
| 636 | else | |
| 637 | { | |
| 638 | ay31015->tx_timer->enable( 0 ); | |
| 639 | } | |
| 640 | } | |
| 641 | ||
| 642 | ||
| 643 | /*------------------------------------------------- | |
| 644 | ay31015_set_receiver_clock - set receive clock | |
| 645 | -------------------------------------------------*/ | |
| 646 | void ay31015_set_receiver_clock( device_t *device, double new_clock ) | |
| 647 | { | |
| 648 | ay31015_t *ay31015 = get_safe_token(device); | |
| 649 | ||
| 650 | ay31015->rx_clock = new_clock; | |
| 651 | ay31015_update_rx_timer( device ); | |
| 652 | } | |
| 653 | ||
| 654 | ||
| 655 | /*------------------------------------------------- | |
| 656 | ay31015_set_transmitter_clock - set transmit clock | |
| 657 | -------------------------------------------------*/ | |
| 658 | void ay31015_set_transmitter_clock( device_t *device, double new_clock ) | |
| 659 | { | |
| 660 | ay31015_t *ay31015 = get_safe_token(device); | |
| 661 | ||
| 662 | ay31015->tx_clock = new_clock; | |
| 663 | ay31015_update_tx_timer( device ); | |
| 664 | } | |
| 665 | ||
| 666 | ||
| 667 | /*------------------------------------------------- | |
| 668 | ay31015_get_received_data - return a byte to the computer | |
| 669 | -------------------------------------------------*/ | |
| 670 | UINT8 ay31015_get_received_data( device_t *device ) | |
| 671 | { | |
| 672 | ay31015_t *ay31015 = get_safe_token(device); | |
| 673 | ||
| 674 | return ay31015->rx_buffer; | |
| 675 | } | |
| 676 | ||
| 677 | ||
| 678 | /*------------------------------------------------- | |
| 679 | ay31015_set_transmit_data - accept a byte to transmit, if able | |
| 680 | -------------------------------------------------*/ | |
| 681 | void ay31015_set_transmit_data( device_t *device, UINT8 data ) | |
| 682 | { | |
| 683 | ay31015_t *ay31015 = get_safe_token(device); | |
| 684 | ||
| 685 | if (ay31015->status_reg & STATUS_TBMT) | |
| 686 | { | |
| 687 | ay31015->tx_buffer = data; | |
| 688 | ay31015->status_reg &= ~STATUS_TBMT; | |
| 689 | ay31015_update_status_pins( device ); | |
| 690 | } | |
| 691 | } | |
| 692 | ||
| 693 | ||
| 694 | static DEVICE_START(ay31015) | |
| 695 | { | |
| 696 | ay31015_t *ay31015 = get_safe_token(device); | |
| 697 | ||
| 698 | ay31015->config = (const ay31015_config*)device->static_config(); | |
| 699 | ||
| 700 | ay31015->read_si.resolve(ay31015->config->read_si_cb, *device); | |
| 701 | ay31015->write_so.resolve(ay31015->config->write_so_cb, *device); | |
| 702 | ay31015->status_changed.resolve(ay31015->config->status_changed_cb, *device); | |
| 703 | ||
| 704 | ay31015->tx_clock = ay31015->config->transmitter_clock; | |
| 705 | ay31015->rx_clock = ay31015->config->receiver_clock; | |
| 706 | ||
| 707 | ay31015->rx_timer = device->machine().scheduler().timer_alloc(FUNC(ay31015_rx_process), (void *)device ); | |
| 708 | ay31015->tx_timer = device->machine().scheduler().timer_alloc(FUNC(ay31015_tx_process), (void *)device ); | |
| 709 | ||
| 710 | ay31015_update_rx_timer( device ); | |
| 711 | ay31015_update_tx_timer( device ); | |
| 712 | } | |
| 713 | ||
| 714 | ||
| 715 | static DEVICE_RESET( ay31015 ) | |
| 716 | { | |
| 717 | ay31015_t *ay31015 = get_safe_token(device); | |
| 718 | ||
| 719 | ay31015->control_reg = 0; | |
| 720 | ay31015->rx_data = 0; | |
| 721 | ||
| 722 | ay31015_reset( device ); | |
| 723 | } | |
| 724 | ||
| 725 | ||
| 726 | const device_type AY31015 = &device_creator<ay31015_device>; | |
| 727 | ||
| 728 | ay31015_device::ay31015_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) | |
| 729 | : device_t(mconfig, AY31015, "AY-3-1015", tag, owner, clock) | |
| 730 | { | |
| 731 | m_token = global_alloc_clear(ay31015_t); | |
| 732 | } | |
| 733 | ||
| 734 | //------------------------------------------------- | |
| 735 | // device_config_complete - perform any | |
| 736 | // operations now that the configuration is | |
| 737 | // complete | |
| 738 | //------------------------------------------------- | |
| 739 | ||
| 740 | void ay31015_device::device_config_complete() | |
| 741 | { | |
| 742 | } | |
| 743 | ||
| 744 | //------------------------------------------------- | |
| 745 | // device_start - device-specific startup | |
| 746 | //------------------------------------------------- | |
| 747 | ||
| 748 | void ay31015_device::device_start() | |
| 749 | { | |
| 750 | DEVICE_START_NAME( ay31015 )(this); | |
| 751 | } | |
| 752 | ||
| 753 | //------------------------------------------------- | |
| 754 | // device_reset - device-specific reset | |
| 755 | //------------------------------------------------- | |
| 756 | ||
| 757 | void ay31015_device::device_reset() | |
| 758 | { | |
| 759 | DEVICE_RESET_NAME( ay31015 )(this); | |
| 760 | } |
| Added: svn:eol-style + native Added: svn:mime-type + text/plain |
| r0 | r21685 | |
|---|---|---|
| 1 | /* ay31015.h | |
| 2 | ||
| 3 | Written for MESS by Robbbert on May 29th, 2008. | |
| 4 | ||
| 5 | */ | |
| 6 | ||
| 7 | #ifndef __AY31015_H_ | |
| 8 | #define __AY31015_H_ | |
| 9 | ||
| 10 | /*************************************************************************** | |
| 11 | TYPE DEFINITIONS | |
| 12 | ***************************************************************************/ | |
| 13 | ||
| 14 | ||
| 15 | enum ay31015_type_t | |
| 16 | { | |
| 17 | /* For AY-3-1014A, AY-3-1015(D) and HD6402 variants */ | |
| 18 | AY_3_1015, | |
| 19 | ||
| 20 | /* For AY-3-1014, AY-5-1013 and AY-6-1013 variants */ | |
| 21 | AY_5_1013 | |
| 22 | }; | |
| 23 | ||
| 24 | ||
| 25 | enum ay31015_input_pin_t | |
| 26 | { | |
| 27 | AY31015_SWE=16, /* -SWE - Pin 16 - Status word enable */ | |
| 28 | AY31015_RDAV=18, /* -RDAV - Pin 18 - Reset data available */ | |
| 29 | AY31015_SI=20, /* SI - Pin 20 - Serial input */ | |
| 30 | AY31015_XR=21, /* XR - Pin 21 - External reset */ | |
| 31 | AY31015_CS=34, /* CS - Pin 34 - Control strobe */ | |
| 32 | AY31015_NP=35, /* NP - Pin 35 - No parity */ | |
| 33 | AY31015_TSB=36, /* TSB - Pin 36 - Number of stop bits */ | |
| 34 | AY31015_NB1=37, /* NB1 - Pin 37 - Number of bits #1 */ | |
| 35 | AY31015_NB2=38, /* NB2 - Pin 38 - Number of bits #2 */ | |
| 36 | AY31015_EPS=39 /* EPS - Pin 39 - Odd/Even parity select */ | |
| 37 | }; | |
| 38 | ||
| 39 | ||
| 40 | enum ay31015_output_pin_t | |
| 41 | { | |
| 42 | AY31015_PE=13, /* PE - Pin 13 - Parity error */ | |
| 43 | AY31015_FE=14, /* FE - Pin 14 - Framing error */ | |
| 44 | AY31015_OR=15, /* OR - Pin 15 - Over-run */ | |
| 45 | AY31015_DAV=19, /* DAV - Pin 19 - Data available */ | |
| 46 | AY31015_TBMT=22, /* TBMT - Pin 22 - Transmit buffer empty */ | |
| 47 | AY31015_EOC=24, /* EOC - Pin 24 - End of character */ | |
| 48 | AY31015_SO=25 /* SO - Pin 25 - Serial output */ | |
| 49 | }; | |
| 50 | ||
| 51 | ||
| 52 | struct ay31015_config | |
| 53 | { | |
| 54 | ay31015_type_t type; /* Type of chip */ | |
| 55 | double transmitter_clock; /* TCP - pin 40 */ | |
| 56 | double receiver_clock; /* RCP - pin 17 */ | |
| 57 | devcb_read8 read_si_cb; /* SI - pin 20 - This will be called whenever the SI pin is sampled. Optional */ | |
| 58 | devcb_write8 write_so_cb; /* SO - pin 25 - This will be called whenever data is put on the SO pin. Optional */ | |
| 59 | devcb_write8 status_changed_cb; /* This will be called whenever one of the status pins may have changed. Optional */ | |
| 60 | }; | |
| 61 | ||
| 62 | ||
| 63 | /*************************************************************************** | |
| 64 | DEVICE CONFIGURATION MACROS | |
| 65 | ***************************************************************************/ | |
| 66 | ||
| 67 | #define MCFG_AY31015_ADD(_tag, _config) \ | |
| 68 | MCFG_DEVICE_ADD(_tag, AY31015, 0) \ | |
| 69 | MCFG_DEVICE_CONFIG(_config) | |
| 70 | ||
| 71 | ||
| 72 | /*************************************************************************** | |
| 73 | FUNCTION PROTOTYPES | |
| 74 | ***************************************************************************/ | |
| 75 | ||
| 76 | /* Set an input pin */ | |
| 77 | void ay31015_set_input_pin( device_t *device, ay31015_input_pin_t pin, int data ); | |
| 78 | ||
| 79 | ||
| 80 | /* Get an output pin */ | |
| 81 | int ay31015_get_output_pin( device_t *device, ay31015_output_pin_t pin ); | |
| 82 | ||
| 83 | ||
| 84 | /* Set a new transmitter clock (new_clock is in Hz) */ | |
| 85 | void ay31015_set_transmitter_clock( device_t *device, double new_clock ); | |
| 86 | ||
| 87 | ||
| 88 | /* Set a new receiver clock (new_clock is in Hz) */ | |
| 89 | void ay31015_set_receiver_clock( device_t *device, double new_clock ); | |
| 90 | ||
| 91 | ||
| 92 | /* Reead the received data */ | |
| 93 | /* The received data is available on RD8-RD1 (pins 5-12) */ | |
| 94 | UINT8 ay31015_get_received_data( device_t *device ); | |
| 95 | ||
| 96 | ||
| 97 | /* Set the transmitter buffer */ | |
| 98 | /* The data to transmit is set on DB1-DB8 (pins 26-33) */ | |
| 99 | void ay31015_set_transmit_data( device_t *device, UINT8 data ); | |
| 100 | ||
| 101 | ||
| 102 | /*************************************************************************** | |
| 103 | DEVICE INTERFACE | |
| 104 | ***************************************************************************/ | |
| 105 | ||
| 106 | class ay31015_device : public device_t | |
| 107 | { | |
| 108 | public: | |
| 109 | ay31015_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); | |
| 110 | ~ay31015_device() { global_free(m_token); } | |
| 111 | ||
| 112 | // access to legacy token | |
| 113 | void *token() const { assert(m_token != NULL); return m_token; } | |
| 114 | protected: | |
| 115 | // device-level overrides | |
| 116 | virtual void device_config_complete(); | |
| 117 | virtual void device_start(); | |
| 118 | virtual void device_reset(); | |
| 119 | private: | |
| 120 | // internal state | |
| 121 | void *m_token; | |
| 122 | }; | |
| 123 | ||
| 124 | extern const device_type AY31015; | |
| 125 | ||
| 126 | #endif |
| Added: svn:eol-style + native Added: svn:mime-type + text/plain |
| r0 | r21685 | |
|---|---|---|
| 1 | /********************************************************************** | |
| 2 | ||
| 3 | Motorola 68328 ("DragonBall") System-on-a-Chip implementation | |
| 4 | ||
| 5 | By MooglyGuy | |
| 6 | contact mooglyguy@gmail.com with licensing and usage questions. | |
| 7 | ||
| 8 | **********************************************************************/ | |
| 9 | ||
| 10 | #include "emu.h" | |
| 11 | #include "cpu/m68000/m68000.h" | |
| 12 | #include "includes/mc68328.h" | |
| 13 | #include "mc68328.h" | |
| 14 | ||
| 15 | #define VERBOSE_LEVEL (0) | |
| 16 | ||
| 17 | INLINE void verboselog(running_machine &machine, int n_level, const char *s_fmt, ...) | |
| 18 | { | |
| 19 | if( VERBOSE_LEVEL >= n_level ) | |
| 20 | { | |
| 21 | va_list v; | |
| 22 | char buf[ 32768 ]; | |
| 23 | va_start( v, s_fmt ); | |
| 24 | vsprintf( buf, s_fmt, v ); | |
| 25 | va_end( v ); | |
| 26 | logerror( "%s: %s", machine.describe_context(), buf ); | |
| 27 | } | |
| 28 | } | |
| 29 | ||
| 30 | static void mc68328_set_interrupt_line(device_t *device, UINT32 line, UINT32 active) | |
| 31 | { | |
| 32 | mc68328_t* mc68328 = mc68328_get_safe_token( device ); | |
| 33 | device_t *cpu = device->machine().device(mc68328->iface->m68k_cpu_tag); | |
| 34 | ||
| 35 | if(active) | |
| 36 | { | |
| 37 | mc68328->regs.ipr |= line; | |
| 38 | ||
| 39 | if(!(mc68328->regs.imr & line) && !(mc68328->regs.isr & line)) | |
| 40 | { | |
| 41 | mc68328->regs.isr |= line; | |
| 42 | ||
| 43 | if(mc68328->regs.isr & INT_M68K_LINE7) | |
| 44 | { | |
| 45 | cpu->execute().set_input_line_and_vector(M68K_IRQ_7, ASSERT_LINE, mc68328->regs.ivr | 0x07); | |
| 46 | } | |
| 47 | else if(mc68328->regs.isr & INT_M68K_LINE6) | |
| 48 | { | |
| 49 | cpu->execute().set_input_line_and_vector(M68K_IRQ_6, ASSERT_LINE, mc68328->regs.ivr | 0x06); | |
| 50 | } | |
| 51 | else if(mc68328->regs.isr & INT_M68K_LINE5) | |
| 52 | { | |
| 53 | cpu->execute().set_input_line_and_vector(M68K_IRQ_5, ASSERT_LINE, mc68328->regs.ivr | 0x05); | |
| 54 | } | |
| 55 | else if(mc68328->regs.isr & INT_M68K_LINE4) | |
| 56 | { | |
| 57 | cpu->execute().set_input_line_and_vector(M68K_IRQ_4, ASSERT_LINE, mc68328->regs.ivr | 0x04); | |
| 58 | } | |
| 59 | else if(mc68328->regs.isr & INT_M68K_LINE3) | |
| 60 | { | |
| 61 | cpu->execute().set_input_line_and_vector(M68K_IRQ_3, ASSERT_LINE, mc68328->regs.ivr | 0x03); | |
| 62 | } | |
| 63 | else if(mc68328->regs.isr & INT_M68K_LINE2) | |
| 64 | { | |
| 65 | cpu->execute().set_input_line_and_vector(M68K_IRQ_2, ASSERT_LINE, mc68328->regs.ivr | 0x02); | |
| 66 | } | |
| 67 | else if(mc68328->regs.isr & INT_M68K_LINE1) | |
| 68 | { | |
| 69 | cpu->execute().set_input_line_and_vector(M68K_IRQ_1, ASSERT_LINE, mc68328->regs.ivr | 0x01); | |
| 70 | } | |
| 71 | } | |
| 72 | } | |
| 73 | else | |
| 74 | { | |
| 75 | mc68328->regs.isr &= ~line; | |
| 76 | ||
| 77 | if((line & INT_M68K_LINE7) && !(mc68328->regs.isr & INT_M68K_LINE7)) | |
| 78 | { | |
| 79 | cpu->execute().set_input_line(M68K_IRQ_7, CLEAR_LINE); | |
| 80 | } | |
| 81 | if((line & INT_M68K_LINE6) && !(mc68328->regs.isr & INT_M68K_LINE6)) | |
| 82 | { | |
| 83 | cpu->execute().set_input_line(M68K_IRQ_6, CLEAR_LINE); | |
| 84 | } | |
| 85 | if((line & INT_M68K_LINE5) && !(mc68328->regs.isr & INT_M68K_LINE5)) | |
| 86 | { | |
| 87 | cpu->execute().set_input_line(M68K_IRQ_5, CLEAR_LINE); | |
| 88 | } | |
| 89 | if((line & INT_M68K_LINE4) && !(mc68328->regs.isr & INT_M68K_LINE4)) | |
| 90 | { | |
| 91 | cpu->execute().set_input_line(M68K_IRQ_4, CLEAR_LINE); | |
| 92 | } | |
| 93 | if((line & INT_M68K_LINE3) && !(mc68328->regs.isr & INT_M68K_LINE3)) | |
| 94 | { | |
| 95 | cpu->execute().set_input_line(M68K_IRQ_3, CLEAR_LINE); | |
| 96 | } | |
| 97 | if((line & INT_M68K_LINE2) && !(mc68328->regs.isr & INT_M68K_LINE2)) | |
| 98 | { | |
| 99 | cpu->execute().set_input_line(M68K_IRQ_2, CLEAR_LINE); | |
| 100 | } | |
| 101 | if((line & INT_M68K_LINE1) && !(mc68328->regs.isr & INT_M68K_LINE1)) | |
| 102 | { | |
| 103 | cpu->execute().set_input_line(M68K_IRQ_1, CLEAR_LINE); | |
| 104 | } | |
| 105 | } | |
| 106 | } | |
| 107 | ||
| 108 | static void mc68328_poll_port_d_interrupts(device_t *device) | |
| 109 | { | |
| 110 | mc68328_t* mc68328 = mc68328_get_safe_token( device ); | |
| 111 | UINT8 line_transitions = mc68328->regs.pddataedge & mc68328->regs.pdirqedge; | |
| 112 | UINT8 line_holds = mc68328->regs.pddata &~ mc68328->regs.pdirqedge; | |
| 113 | UINT8 line_interrupts = (line_transitions | line_holds) & mc68328->regs.pdirqen; | |
| 114 | ||
| 115 | if(line_interrupts) | |
| 116 | { | |
| 117 | mc68328_set_interrupt_line(device, line_interrupts << 8, 1); | |
| 118 | } | |
| 119 | else | |
| 120 | { | |
| 121 | mc68328_set_interrupt_line(device, INT_KBDINTS, 0); | |
| 122 | } | |
| 123 | } | |
| 124 | ||
| 125 | void mc68328_set_penirq_line(device_t *device, int state) | |
| 126 | { | |
| 127 | mc68328_t* mc68328 = mc68328_get_safe_token( device ); | |
| 128 | ||
| 129 | if(state) | |
| 130 | { | |
| 131 | mc68328_set_interrupt_line(device, INT_PEN, 1); | |
| 132 | } | |
| 133 | else | |
| 134 | { | |
| 135 | mc68328->regs.ipr &= ~INT_PEN; | |
| 136 | mc68328_set_interrupt_line(device, INT_PEN, 0); | |
| 137 | } | |
| 138 | } | |
| 139 | ||
| 140 | void mc68328_set_port_d_lines(device_t *device, UINT8 state, int bit) | |
| 141 | { | |
| 142 | mc68328_t* mc68328 = mc68328_get_safe_token( device ); | |
| 143 | UINT8 old_button_state = mc68328->regs.pddata; | |
| 144 | ||
| 145 | if(state & (1 << bit)) | |
| 146 | { | |
| 147 | mc68328->regs.pddata |= (1 << bit); | |
| 148 | } | |
| 149 | else | |
| 150 | { | |
| 151 | mc68328->regs.pddata &= ~(1 << bit); | |
| 152 | } | |
| 153 | ||
| 154 | mc68328->regs.pddataedge |= ~old_button_state & mc68328->regs.pddata; | |
| 155 | ||
| 156 | mc68328_poll_port_d_interrupts(device); | |
| 157 | } | |
| 158 | ||
| 159 | static UINT32 mc68328_get_timer_frequency(device_t *device, UINT32 index) | |
| 160 | { | |
| 161 | mc68328_t* mc68328 = mc68328_get_safe_token( device ); | |
| 162 | UINT32 frequency = 0; | |
| 163 | ||
| 164 | switch(mc68328->regs.tctl[index] & TCTL_CLKSOURCE) | |
| 165 | { | |
| 166 | case TCTL_CLKSOURCE_SYSCLK: | |
| 167 | frequency = 32768 * 506; | |
| 168 | break; | |
| 169 | ||
| 170 | case TCTL_CLKSOURCE_SYSCLK16: | |
| 171 | frequency = (32768 * 506) / 16; | |
| 172 | break; | |
| 173 | ||
| 174 | case TCTL_CLKSOURCE_32KHZ4: | |
| 175 | case TCTL_CLKSOURCE_32KHZ5: | |
| 176 | case TCTL_CLKSOURCE_32KHZ6: | |
| 177 | case TCTL_CLKSOURCE_32KHZ7: | |
| 178 | frequency = 32768; | |
| 179 | break; | |
| 180 | } | |
| 181 | frequency /= (mc68328->regs.tprer[index] + 1); | |
| 182 | ||
| 183 | return frequency; | |
| 184 | } | |
| 185 | ||
| 186 | static void mc68328_maybe_start_timer(device_t *device, UINT32 index, UINT32 new_enable) | |
| 187 | { | |
| 188 | mc68328_t* mc68328 = mc68328_get_safe_token( device ); | |
| 189 | ||
| 190 | if((mc68328->regs.tctl[index] & TCTL_TEN) == TCTL_TEN_ENABLE && (mc68328->regs.tctl[index] & TCTL_CLKSOURCE) > TCTL_CLKSOURCE_STOP) | |
| 191 | { | |
| 192 | if((mc68328->regs.tctl[index] & TCTL_CLKSOURCE) == TCTL_CLKSOURCE_TIN) | |
| 193 | { | |
| 194 | mc68328->gptimer[index]->adjust(attotime::never); | |
| 195 | } | |
| 196 | else if(mc68328->regs.tcmp[index] == 0) | |
| 197 | { | |
| 198 | mc68328->gptimer[index]->adjust(attotime::never); | |
| 199 | } | |
| 200 | else | |
| 201 | { | |
| 202 | UINT32 frequency = mc68328_get_timer_frequency(device, index); | |
| 203 | attotime period = (attotime::from_hz(frequency) * mc68328->regs.tcmp[index]); | |
| 204 | ||
| 205 | if(new_enable) | |
| 206 | { | |
| 207 | mc68328->regs.tcn[index] = 0x0000; | |
| 208 | } | |
| 209 | ||
| 210 | mc68328->gptimer[index]->adjust(period); | |
| 211 | } | |
| 212 | } | |
| 213 | else | |
| 214 | { | |
| 215 | mc68328->gptimer[index]->adjust(attotime::never); | |
| 216 | } | |
| 217 | } | |
| 218 | ||
| 219 | static void mc68328_timer_compare_event(device_t *device, UINT32 index) | |
| 220 | { | |
| 221 | mc68328_t* mc68328 = mc68328_get_safe_token( device ); | |
| 222 | ||
| 223 | mc68328->regs.tcn[index] = mc68328->regs.tcmp[index]; | |
| 224 | mc68328->regs.tstat[index] |= TSTAT_COMP; | |
| 225 | ||
| 226 | if((mc68328->regs.tctl[index] & TCTL_FRR) == TCTL_FRR_RESTART) | |
| 227 | { | |
| 228 | UINT32 frequency = mc68328_get_timer_frequency(device, index); | |
| 229 | ||
| 230 | if(frequency > 0) | |
| 231 | { | |
| 232 | attotime period = attotime::from_hz(frequency) * mc68328->regs.tcmp[index]; | |
| 233 | ||
| 234 | mc68328->regs.tcn[index] = 0x0000; | |
| 235 | ||
| 236 | mc68328->gptimer[index]->adjust(period); | |
| 237 | } | |
| 238 | else | |
| 239 | { | |
| 240 | mc68328->gptimer[index]->adjust(attotime::never); | |
| 241 | } | |
| 242 | } | |
| 243 | else | |
| 244 | { | |
| 245 | UINT32 frequency = mc68328_get_timer_frequency(device, index); | |
| 246 | ||
| 247 | if(frequency > 0) | |
| 248 | { | |
| 249 | attotime period = attotime::from_hz(frequency) * 0x10000; | |
| 250 | ||
| 251 | mc68328->gptimer[index]->adjust(period); | |
| 252 | } | |
| 253 | else | |
| 254 | { | |
| 255 | mc68328->gptimer[index]->adjust(attotime::never); | |
| 256 | } | |
| 257 | } | |
| 258 | if((mc68328->regs.tctl[index] & TCTL_IRQEN) == TCTL_IRQEN_ENABLE) | |
| 259 | { | |
| 260 | mc68328_set_interrupt_line(device, (index == 0) ? INT_TIMER1 : INT_TIMER2, 1); | |
| 261 | } | |
| 262 | } | |
| 263 | ||
| 264 | static TIMER_CALLBACK( mc68328_timer1_hit ) | |
| 265 | { | |
| 266 | device_t *device = machine.device(MC68328_TAG); | |
| 267 | ||
| 268 | mc68328_timer_compare_event(device, 0); | |
| 269 | } | |
| 270 | ||
| 271 | static TIMER_CALLBACK( mc68328_timer2_hit ) | |
| 272 | { | |
| 273 | device_t *device = machine.device(MC68328_TAG); | |
| 274 | ||
| 275 | mc68328_timer_compare_event(device, 1); | |
| 276 | } | |
| 277 | ||
| 278 | static TIMER_CALLBACK( mc68328_pwm_transition ) | |
| 279 | { | |
| 280 | device_t *device = machine.device(MC68328_TAG); | |
| 281 | mc68328_t* mc68328 = mc68328_get_safe_token( device ); | |
| 282 | ||
| 283 | if(mc68328->regs.pwmw >= mc68328->regs.pwmp || mc68328->regs.pwmw == 0 || mc68328->regs.pwmp == 0) | |
| 284 | { | |
| 285 | mc68328->pwm->adjust(attotime::never); | |
| 286 | return; | |
| 287 | } | |
| 288 | ||
| 289 | if(((mc68328->regs.pwmc & PWMC_POL) == 0 && (mc68328->regs.pwmc & PWMC_PIN) != 0) || | |
| 290 | ((mc68328->regs.pwmc & PWMC_POL) != 0 && (mc68328->regs.pwmc & PWMC_PIN) == 0)) | |
| 291 | { | |
| 292 | UINT32 frequency = 32768 * 506; | |
| 293 | UINT32 divisor = 4 << (mc68328->regs.pwmc & PWMC_CLKSEL); // ?? Datasheet says 2 <<, but then we're an octave higher than CoPilot. | |
| 294 | attotime period; | |
| 295 | ||
| 296 | frequency /= divisor; | |
| 297 | period = attotime::from_hz(frequency) * (mc68328->regs.pwmp - mc68328->regs.pwmw); | |
| 298 | ||
| 299 | mc68328->pwm->adjust(period); | |
| 300 | ||
| 301 | if(mc68328->regs.pwmc & PWMC_IRQEN) | |
| 302 | { | |
| 303 | mc68328_set_interrupt_line(device, INT_PWM, 1); | |
| 304 | } | |
| 305 | } | |
| 306 | else | |
| 307 | { | |
| 308 | UINT32 frequency = 32768 * 506; | |
| 309 | UINT32 divisor = 4 << (mc68328->regs.pwmc & PWMC_CLKSEL); // ?? Datasheet says 2 <<, but then we're an octave higher than CoPilot. | |
| 310 | attotime period; | |
| 311 | ||
| 312 | frequency /= divisor; | |
| 313 | period = attotime::from_hz(frequency) * mc68328->regs.pwmw; | |
| 314 | ||
| 315 | mc68328->pwm->adjust(period); | |
| 316 | } | |
| 317 | ||
| 318 | mc68328->regs.pwmc ^= PWMC_PIN; | |
| 319 | ||
| 320 | if( !mc68328->out_pwm.isnull() ) | |
| 321 | { | |
| 322 | mc68328->out_pwm( 0, (mc68328->regs.pwmc & PWMC_PIN) ? 1 : 0 ); | |
| 323 | } | |
| 324 | } | |
| 325 | ||
| 326 | static TIMER_CALLBACK( mc68328_rtc_tick ) | |
| 327 | { | |
| 328 | device_t *device = machine.device(MC68328_TAG); | |
| 329 | mc68328_t* mc68328 = mc68328_get_safe_token( device ); | |
| 330 | ||
| 331 | if(mc68328->regs.rtcctl & RTCCTL_ENABLE) | |
| 332 | { | |
| 333 | UINT32 set_int = 0; | |
| 334 | ||
| 335 | mc68328->regs.hmsr++; | |
| 336 | ||
| 337 | if(mc68328->regs.rtcienr & RTCINT_SECOND) | |
| 338 | { | |
| 339 | set_int = 1; | |
| 340 | mc68328->regs.rtcisr |= RTCINT_SECOND; | |
| 341 | } | |
| 342 | ||
| 343 | if((mc68328->regs.hmsr & 0x0000003f) == 0x0000003c) | |
| 344 | { | |
| 345 | mc68328->regs.hmsr &= 0xffffffc0; | |
| 346 | mc68328->regs.hmsr += 0x00010000; | |
| 347 | ||
| 348 | if(mc68328->regs.rtcienr & RTCINT_MINUTE) | |
| 349 | { | |
| 350 | set_int = 1; | |
| 351 | mc68328->regs.rtcisr |= RTCINT_MINUTE; | |
| 352 | } | |
| 353 | ||
| 354 | if((mc68328->regs.hmsr & 0x003f0000) == 0x003c0000) | |
| 355 | { | |
| 356 | mc68328->regs.hmsr &= 0xffc0ffff; | |
| 357 | mc68328->regs.hmsr += 0x0100000; | |
| 358 | ||
| 359 | if((mc68328->regs.hmsr & 0x1f000000) == 0x18000000) | |
| 360 | { | |
| 361 | mc68328->regs.hmsr &= 0xe0ffffff; | |
| 362 | ||
| 363 | if(mc68328->regs.rtcienr & RTCINT_DAY) | |
| 364 | { | |
| 365 | set_int = 1; | |
| 366 | mc68328->regs.rtcisr |= RTCINT_DAY; | |
| 367 | } | |
| 368 | } | |
| 369 | } | |
| 370 | ||
| 371 | if(mc68328->regs.stpwtch != 0x003f) | |
| 372 | { | |
| 373 | mc68328->regs.stpwtch--; | |
| 374 | mc68328->regs.stpwtch &= 0x003f; | |
| 375 | ||
| 376 | if(mc68328->regs.stpwtch == 0x003f) | |
| 377 | { | |
| 378 | if(mc68328->regs.rtcienr & RTCINT_STOPWATCH) | |
| 379 | { | |
| 380 | set_int = 1; | |
| 381 | mc68328->regs.rtcisr |= RTCINT_STOPWATCH; | |
| 382 | } | |
| 383 | } | |
| 384 | } | |
| 385 | } | |
| 386 | ||
| 387 | if(mc68328->regs.hmsr == mc68328->regs.alarm) | |
| 388 | { | |
| 389 | if(mc68328->regs.rtcienr & RTCINT_ALARM) | |
| 390 | { | |
| 391 | set_int = 1; | |
| 392 | mc68328->regs.rtcisr |= RTCINT_STOPWATCH; | |
| 393 | } | |
| 394 | } | |
| 395 | ||
| 396 | if(set_int) | |
| 397 | { | |
| 398 | mc68328_set_interrupt_line(device, INT_RTC, 1); | |
| 399 | } | |
| 400 | else | |
| 401 | { | |
| 402 | mc68328_set_interrupt_line(device, INT_RTC, 0); | |
| 403 | } | |
| 404 | } | |
| 405 | } | |
| 406 | ||
| 407 | WRITE16_DEVICE_HANDLER( mc68328_w ) | |
| 408 | { | |
| 409 | mc68328_t* mc68328 = mc68328_get_safe_token( device ); | |
| 410 | UINT32 address = offset << 1; | |
| 411 | UINT16 temp16[4] = { 0 }; | |
| 412 | UINT32 imr_old = mc68328->regs.imr, imr_diff; | |
| 413 | ||
| 414 | switch(address) | |
| 415 | { | |
| 416 | case 0x000: | |
| 417 | if( mem_mask & 0x00ff ) | |
| 418 | { | |
| 419 | verboselog(space.machine(), 2, "mc68328_w: Unknown address (0xfff001) = %02x\n", data & 0x00ff); | |
| 420 | } | |
| 421 | else | |
| 422 | { | |
| 423 | verboselog(space.machine(), 2, "mc68328_w: SCR = %02x\n", (data >> 8) & 0x00ff); | |
| 424 | } | |
| 425 | break; | |
| 426 | ||
| 427 | case 0x100: | |
| 428 | verboselog(space.machine(), 2, "mc68328_w: GRPBASEA = %04x\n", data); | |
| 429 | mc68328->regs.grpbasea = data; | |
| 430 | break; | |
| 431 | ||
| 432 | case 0x102: | |
| 433 | verboselog(space.machine(), 2, "mc68328_w: GRPBASEB = %04x\n", data); | |
| 434 | mc68328->regs.grpbaseb = data; | |
| 435 | break; | |
| 436 | ||
| 437 | case 0x104: | |
| 438 | verboselog(space.machine(), 2, "mc68328_w: GRPBASEC = %04x\n", data); | |
| 439 | mc68328->regs.grpbasec = data; | |
| 440 | break; | |
| 441 | ||
| 442 | case 0x106: | |
| 443 | verboselog(space.machine(), 2, "mc68328_w: GRPBASED = %04x\n", data); | |
| 444 | mc68328->regs.grpbased = data; | |
| 445 | break; | |
| 446 | ||
| 447 | case 0x108: | |
| 448 | verboselog(space.machine(), 2, "mc68328_w: GRPMASKA = %04x\n", data); | |
| 449 | mc68328->regs.grpmaska = data; | |
| 450 | break; | |
| 451 | ||
| 452 | case 0x10a: | |
| 453 | verboselog(space.machine(), 2, "mc68328_w: GRPMASKB = %04x\n", data); | |
| 454 | mc68328->regs.grpmaskb = data; | |
| 455 | break; | |
| 456 | ||
| 457 | case 0x10c: | |
| 458 | verboselog(space.machine(), 2, "mc68328_w: GRPMASKC = %04x\n", data); | |
| 459 | mc68328->regs.grpmaskc = data; | |
| 460 | break; | |
| 461 | ||
| 462 | case 0x10e: | |
| 463 | verboselog(space.machine(), 2, "mc68328_w: GRPMASKD = %04x\n", data); | |
| 464 | mc68328->regs.grpmaskd = data; | |
| 465 | break; | |
| 466 | ||
| 467 | case 0x110: | |
| 468 | verboselog(space.machine(), 5, "mc68328_w: CSA0(0) = %04x\n", data); | |
| 469 | mc68328->regs.csa0 &= 0xffff0000 | (~mem_mask); | |
| 470 | mc68328->regs.csa0 |= data & mem_mask; | |
| 471 | break; | |
| 472 | ||
| 473 | case 0x112: | |
| 474 | verboselog(space.machine(), 5, "mc68328_w: CSA0(16) = %04x\n", data); | |
| 475 | mc68328->regs.csa0 &= ~(mem_mask << 16); | |
| 476 | mc68328->regs.csa0 |= (data & mem_mask) << 16; | |
| 477 | break; | |
| 478 | ||
| 479 | case 0x114: | |
| 480 | verboselog(space.machine(), 5, "mc68328_w: CSA1(0) = %04x\n", data); | |
| 481 | mc68328->regs.csa1 &= 0xffff0000 | (~mem_mask); | |
| 482 | mc68328->regs.csa1 |= data & mem_mask; | |
| 483 | break; | |
| 484 | ||
| 485 | case 0x116: | |
| 486 | verboselog(space.machine(), 5, "mc68328_w: CSA1(16) = %04x\n", data); | |
| 487 | mc68328->regs.csa1 &= ~(mem_mask << 16); | |
| 488 | mc68328->regs.csa1 |= (data & mem_mask) << 16; | |
| 489 | break; | |
| 490 | ||
| 491 | case 0x118: | |
| 492 | verboselog(space.machine(), 5, "mc68328_w: CSA2(0) = %04x\n", data); | |
| 493 | mc68328->regs.csa2 &= 0xffff0000 | (~mem_mask); | |
| 494 | mc68328->regs.csa2 |= data & mem_mask; | |
| 495 | break; | |
| 496 | ||
| 497 | case 0x11a: | |
| 498 | verboselog(space.machine(), 5, "mc68328_w: CSA2(16) = %04x\n", data); | |
| 499 | mc68328->regs.csa2 &= ~(mem_mask << 16); | |
| 500 | mc68328->regs.csa2 |= (data & mem_mask) << 16; | |
| 501 | break; | |
| 502 | ||
| 503 | case 0x11c: | |
| 504 | verboselog(space.machine(), 5, "mc68328_w: CSA3(0) = %04x\n", data); | |
| 505 | mc68328->regs.csa3 &= 0xffff0000 | (~mem_mask); | |
| 506 | mc68328->regs.csa3 |= data & mem_mask; | |
| 507 | break; | |
| 508 | ||
| 509 | case 0x11e: | |
| 510 | verboselog(space.machine(), 5, "mc68328_w: CSA3(16) = %04x\n", data); | |
| 511 | mc68328->regs.csa3 &= ~(mem_mask << 16); | |
| 512 | mc68328->regs.csa3 |= (data & mem_mask) << 16; | |
| 513 | break; | |
| 514 | ||
| 515 | case 0x120: | |
| 516 | verboselog(space.machine(), 5, "mc68328_w: CSB0(0) = %04x\n", data); | |
| 517 | mc68328->regs.csb0 &= 0xffff0000 | (~mem_mask); | |
| 518 | mc68328->regs.csb0 |= data & mem_mask; | |
| 519 | break; | |
| 520 | ||
| 521 | case 0x122: | |
| 522 | verboselog(space.machine(), 5, "mc68328_w: CSB0(16) = %04x\n", data); | |
| 523 | mc68328->regs.csb0 &= ~(mem_mask << 16); | |
| 524 | mc68328->regs.csb0 |= (data & mem_mask) << 16; | |
| 525 | break; | |
| 526 | ||
| 527 | case 0x124: | |
| 528 | verboselog(space.machine(), 5, "mc68328_w: CSB1(0) = %04x\n", data); | |
| 529 | mc68328->regs.csb1 &= 0xffff0000 | (~mem_mask); | |
| 530 | mc68328->regs.csb1 |= data & mem_mask; | |
| 531 | break; | |
| 532 | ||
| 533 | case 0x126: | |
| 534 | verboselog(space.machine(), 5, "mc68328_w: CSB1(16) = %04x\n", data); | |
| 535 | mc68328->regs.csb1 &= ~(mem_mask << 16); | |
| 536 | mc68328->regs.csb1 |= (data & mem_mask) << 16; | |
| 537 | break; | |
| 538 | ||
| 539 | case 0x128: | |
| 540 | verboselog(space.machine(), 5, "mc68328_w: CSB2(0) = %04x\n", data); | |
| 541 | mc68328->regs.csb2 &= 0xffff0000 | (~mem_mask); | |
| 542 | mc68328->regs.csb2 |= data & mem_mask; | |
| 543 | break; | |
| 544 | ||
| 545 | case 0x12a: | |
| 546 | verboselog(space.machine(), 5, "mc68328_w: CSB2(16) = %04x\n", data); | |
| 547 | mc68328->regs.csb2 &= ~(mem_mask << 16); | |
| 548 | mc68328->regs.csb2 |= (data & mem_mask) << 16; | |
| 549 | break; | |
| 550 | ||
| 551 | case 0x12c: | |
| 552 | verboselog(space.machine(), 5, "mc68328_w: CSB3(0) = %04x\n", data); | |
| 553 | mc68328->regs.csb3 &= 0xffff0000 | (~mem_mask); | |
| 554 | mc68328->regs.csb3 |= data & mem_mask; | |
| 555 | break; | |
| 556 | ||
| 557 | case 0x12e: | |
| 558 | verboselog(space.machine(), 5, "mc68328_w: CSB3(16) = %04x\n", data); | |
| 559 | mc68328->regs.csb3 &= ~(mem_mask << 16); | |
| 560 | mc68328->regs.csb3 |= (data & mem_mask) << 16; | |
| 561 | break; | |
| 562 | ||
| 563 | case 0x130: | |
| 564 | verboselog(space.machine(), 5, "mc68328_w: CSC0(0) = %04x\n", data); | |
| 565 | mc68328->regs.csc0 &= 0xffff0000 | (~mem_mask); | |
| 566 | mc68328->regs.csc0 |= data & mem_mask; | |
| 567 | break; | |
| 568 | ||
| 569 | case 0x132: | |
| 570 | verboselog(space.machine(), 5, "mc68328_w: CSC0(16) = %04x\n", data); | |
| 571 | mc68328->regs.csc0 &= ~(mem_mask << 16); | |
| 572 | mc68328->regs.csc0 |= (data & mem_mask) << 16; | |
| 573 | break; | |
| 574 | ||
| 575 | case 0x134: | |
| 576 | verboselog(space.machine(), 5, "mc68328_w: CSC1(0) = %04x\n", data); | |
| 577 | mc68328->regs.csc1 &= 0xffff0000 | (~mem_mask); | |
| 578 | mc68328->regs.csc1 |= data & mem_mask; | |
| 579 | break; | |
| 580 | ||
| 581 | case 0x136: | |
| 582 | verboselog(space.machine(), 5, "mc68328_w: CSC1(16) = %04x\n", data); | |
| 583 | mc68328->regs.csc1 &= ~(mem_mask << 16); | |
| 584 | mc68328->regs.csc1 |= (data & mem_mask) << 16; | |
| 585 | break; | |
| 586 | ||
| 587 | case 0x138: | |
| 588 | verboselog(space.machine(), 5, "mc68328_w: CSC2(0) = %04x\n", data); | |
| 589 | mc68328->regs.csc2 &= 0xffff0000 | (~mem_mask); | |
| 590 | mc68328->regs.csc2 |= data & mem_mask; | |
| 591 | break; | |
| 592 | ||
| 593 | case 0x13a: | |
| 594 | verboselog(space.machine(), 5, "mc68328_w: CSC2(16) = %04x\n", data); | |
| 595 | mc68328->regs.csc2 &= ~(mem_mask << 16); | |
| 596 | mc68328->regs.csc2 |= (data & mem_mask) << 16; | |
| 597 | break; | |
| 598 | ||
| 599 | case 0x13c: | |
| 600 | verboselog(space.machine(), 5, "mc68328_w: CSC3(0) = %04x\n", data); | |
| 601 | mc68328->regs.csc3 &= 0xffff0000 | (~mem_mask); | |
| 602 | mc68328->regs.csc3 |= data & mem_mask; | |
| 603 | break; | |
| 604 | ||
| 605 | case 0x13e: | |
| 606 | verboselog(space.machine(), 5, "mc68328_w: CSC3(16) = %04x\n", data); | |
| 607 | mc68328->regs.csc3 &= ~(mem_mask << 16); | |
| 608 | mc68328->regs.csc3 |= (data & mem_mask) << 16; | |
| 609 | break; | |
| 610 | ||
| 611 | case 0x140: | |
| 612 | verboselog(space.machine(), 5, "mc68328_w: CSD0(0) = %04x\n", data); | |
| 613 | mc68328->regs.csd0 &= 0xffff0000 | (~mem_mask); | |
| 614 | mc68328->regs.csd0 |= data & mem_mask; | |
| 615 | break; | |
| 616 | ||
| 617 | case 0x142: | |
| 618 | verboselog(space.machine(), 5, "mc68328_w: CSD0(16) = %04x\n", data); | |
| 619 | mc68328->regs.csd0 &= ~(mem_mask << 16); | |
| 620 | mc68328->regs.csd0 |= (data & mem_mask) << 16; | |
| 621 | break; | |
| 622 | ||
| 623 | case 0x144: | |
| 624 | verboselog(space.machine(), 5, "mc68328_w: CSD1(0) = %04x\n", data); | |
| 625 | mc68328->regs.csd1 &= 0xffff0000 | (~mem_mask); | |
| 626 | mc68328->regs.csd1 |= data & mem_mask; | |
| 627 | break; | |
| 628 | ||
| 629 | case 0x146: | |
| 630 | verboselog(space.machine(), 5, "mc68328_w: CSD1(16) = %04x\n", data); | |
| 631 | mc68328->regs.csd1 &= ~(mem_mask << 16); | |
| 632 | mc68328->regs.csd1 |= (data & mem_mask) << 16; | |
| 633 | break; | |
| 634 | ||
| 635 | case 0x148: | |
| 636 | verboselog(space.machine(), 5, "mc68328_w: CSD2(0) = %04x\n", data); | |
| 637 | mc68328->regs.csd2 &= 0xffff0000 | (~mem_mask); | |
| 638 | mc68328->regs.csd2 |= data & mem_mask; | |
| 639 | break; | |
| 640 | ||
| 641 | case 0x14a: | |
| 642 | verboselog(space.machine(), 5, "mc68328_w: CSD2(16) = %04x\n", data); | |
| 643 | mc68328->regs.csd2 &= ~(mem_mask << 16); | |
| 644 | mc68328->regs.csd2 |= (data & mem_mask) << 16; | |
| 645 | break; | |
| 646 | ||
| 647 | case 0x14c: | |
| 648 | verboselog(space.machine(), 5, "mc68328_w: CSD3(0) = %04x\n", data); | |
| 649 | mc68328->regs.csd3 &= 0xffff0000 | (~mem_mask); | |
| 650 | mc68328->regs.csd3 |= data & mem_mask; | |
| 651 | break; | |
| 652 | ||
| 653 | case 0x14e: | |
| 654 | verboselog(space.machine(), 5, "mc68328_w: CSD3(16) = %04x\n", data); | |
| 655 | mc68328->regs.csd3 &= ~(mem_mask << 16); | |
| 656 | mc68328->regs.csd3 |= (data & mem_mask) << 16; | |
| 657 | break; | |
| 658 | ||
| 659 | case 0x200: | |
| 660 | verboselog(space.machine(), 2, "mc68328_w: PLLCR = %04x\n", data); | |
| 661 | mc68328->regs.pllcr = data; | |
| 662 | break; | |
| 663 | ||
| 664 | case 0x202: | |
| 665 | verboselog(space.machine(), 2, "mc68328_w: PLLFSR = %04x\n", data); | |
| 666 | mc68328->regs.pllfsr = data; | |
| 667 | break; | |
| 668 | ||
| 669 | case 0x206: | |
| 670 | if( mem_mask & 0x00ff ) | |
| 671 | { | |
| 672 | verboselog(space.machine(), 2, "mc68328_w: PCTLR = %02x\n", data & 0x00ff); | |
| 673 | mc68328->regs.pctlr = data & 0x00ff; | |
| 674 | } | |
| 675 | else | |
| 676 | { | |
| 677 | verboselog(space.machine(), 2, "mc68328_w: Unknown address (0xfff206) = %02x\n", (data >> 8) & 0x00ff); | |
| 678 | } | |
| 679 | break; | |
| 680 | ||
| 681 | case 0x300: | |
| 682 | if( mem_mask & 0x00ff ) | |
| 683 | { | |
| 684 | verboselog(space.machine(), 2, "mc68328_w: Unknown address (0xfff301) = %02x\n", data & 0x00ff); | |
| 685 | } | |
| 686 | else | |
| 687 | { | |
| 688 | verboselog(space.machine(), 2, "mc68328_w: IVR = %02x\n", (data >> 8) & 0x00ff); | |
| 689 | mc68328->regs.ivr = (data >> 8) & 0x00ff; | |
| 690 | } | |
| 691 | break; | |
| 692 | ||
| 693 | case 0x302: | |
| 694 | verboselog(space.machine(), 2, "mc68328_w: ICR = %04x\n", data); | |
| 695 | mc68328->regs.icr = data; | |
| 696 | break; | |
| 697 | ||
| 698 | case 0x304: | |
| 699 | verboselog(space.machine(), 2, "mc68328_w: IMR(16) = %04x\n", data); | |
| 700 | mc68328->regs.imr &= ~(mem_mask << 16); | |
| 701 | mc68328->regs.imr |= (data & mem_mask) << 16; | |
| 702 | mc68328->regs.isr &= ~((data & mem_mask) << 16); | |
| 703 | ||
| 704 | imr_diff = imr_old ^ mc68328->regs.imr; | |
| 705 | mc68328_set_interrupt_line(device, imr_diff, 0); | |
| 706 | break; | |
| 707 | ||
| 708 | case 0x306: | |
| 709 | verboselog(space.machine(), 2, "mc68328_w: IMR(0) = %04x\n", data); | |
| 710 | mc68328->regs.imr &= 0xffff0000 | (~mem_mask); | |
| 711 | mc68328->regs.imr |= data & mem_mask; | |
| 712 | mc68328->regs.isr &= ~(data & mem_mask); | |
| 713 | ||
| 714 | imr_diff = imr_old ^ mc68328->regs.imr; | |
| 715 | mc68328_set_interrupt_line(device, imr_diff, 0); | |
| 716 | break; | |
| 717 | ||
| 718 | case 0x308: | |
| 719 | { | |
| 720 | verboselog(space.machine(), 2, "mc68328_w: IWR(16) = %04x\n", data); | |
| 721 | mc68328->regs.iwr &= ~(mem_mask << 16); | |
| 722 | mc68328->regs.iwr |= (data & mem_mask) << 16; | |
| 723 | } | |
| 724 | break; | |
| 725 | ||
| 726 | case 0x30a: | |
| 727 | verboselog(space.machine(), 2, "mc68328_w: IWR(0) = %04x\n", data); | |
| 728 | mc68328->regs.iwr &= 0xffff0000 | (~mem_mask); | |
| 729 | mc68328->regs.iwr |= data & mem_mask; | |
| 730 | break; | |
| 731 | ||
| 732 | case 0x30c: | |
| 733 | verboselog(space.machine(), 2, "mc68328_w: ISR(16) = %04x\n", data); | |
| 734 | // Clear edge-triggered IRQ1 | |
| 735 | if((mc68328->regs.icr & ICR_ET1) == ICR_ET1 && (data & INT_IRQ1_SHIFT) == INT_IRQ1_SHIFT) | |
| 736 | { | |
| 737 | mc68328->regs.isr &= ~INT_IRQ1; | |
| 738 | } | |
| 739 | ||
| 740 | // Clear edge-triggered IRQ2 | |
| 741 | if((mc68328->regs.icr & ICR_ET2) == ICR_ET2 && (data & INT_IRQ2_SHIFT) == INT_IRQ2_SHIFT) | |
| 742 | { | |
| 743 | mc68328->regs.isr &= ~INT_IRQ2; | |
| 744 | } | |
| 745 | ||
| 746 | // Clear edge-triggered IRQ3 | |
| 747 | if((mc68328->regs.icr & ICR_ET3) == ICR_ET3 && (data & INT_IRQ3_SHIFT) == INT_IRQ3_SHIFT) | |
| 748 | { | |
| 749 | mc68328->regs.isr &= ~INT_IRQ3; | |
| 750 | } | |
| 751 | ||
| 752 | // Clear edge-triggered IRQ6 | |
| 753 | if((mc68328->regs.icr & ICR_ET6) == ICR_ET6 && (data & INT_IRQ6_SHIFT) == INT_IRQ6_SHIFT) | |
| 754 | { | |
| 755 | mc68328->regs.isr &= ~INT_IRQ6; | |
| 756 | } | |
| 757 | ||
| 758 | // Clear edge-triggered IRQ7 | |
| 759 | if((data & INT_IRQ7_SHIFT) == INT_IRQ7_SHIFT) | |
| 760 | { | |
| 761 | mc68328->regs.isr &= ~INT_IRQ7; | |
| 762 | } | |
| 763 | break; | |
| 764 | ||
| 765 | case 0x30e: | |
| 766 | verboselog(space.machine(), 2, "mc68328_w: ISR(0) = %04x (Ignored)\n", data); | |
| 767 | break; | |
| 768 | ||
| 769 | case 0x310: | |
| 770 | verboselog(space.machine(), 2, "mc68328_w: IPR(16) = %04x (Ignored)\n"); | |
| 771 | break; | |
| 772 | ||
| 773 | case 0x312: | |
| 774 | verboselog(space.machine(), 2, "mc68328_w: IPR(0) = %04x (Ignored)\n"); | |
| 775 | break; | |
| 776 | ||
| 777 | case 0x400: | |
| 778 | if( mem_mask & 0x00ff ) | |
| 779 | { | |
| 780 | verboselog(space.machine(), 2, "mc68328_w: PADATA = %02x\n", data & 0x00ff); | |
| 781 | mc68328->regs.padata = data & 0x00ff; | |
| 782 | if(!mc68328->out_port_a.isnull()) | |
| 783 | { | |
| 784 | mc68328->out_port_a( 0, data & 0x00ff ); | |
| 785 | } | |
| 786 | } | |
| 787 | else | |
| 788 | { | |
| 789 | verboselog(space.machine(), 2, "mc68328_w: PADIR = %02x\n", (data >> 8) & 0x00ff); | |
| 790 | mc68328->regs.padir = (data >> 8) & 0x00ff; | |
| 791 | } | |
| 792 | break; | |
| 793 | ||
| 794 | case 0x402: | |
| 795 | if( mem_mask & 0x00ff ) | |
| 796 | { | |
| 797 | verboselog(space.machine(), 2, "mc68328_w: PASEL = %02x\n", data & 0x00ff); | |
| 798 | mc68328->regs.pasel = data & 0x00ff; | |
| 799 | } | |
| 800 | else | |
| 801 | { | |
| 802 | verboselog(space.machine(), 2, "mc68328_w: Unknown address (0xfff402) = %02x\n", (data >> 8) & 0x00ff); | |
| 803 | } | |
| 804 | break; | |
| 805 | ||
| 806 | case 0x408: | |
| 807 | if( mem_mask & 0x00ff ) | |
| 808 | { | |
| 809 | verboselog(space.machine(), 2, "mc68328_w: PBDATA = %02x\n", data & 0x00ff); | |
| 810 | mc68328->regs.pbdata = data & 0x00ff; | |
| 811 | if(!mc68328->out_port_b.isnull()) | |
| 812 | { | |
| 813 | mc68328->out_port_b( 0, data & 0x00ff ); | |
| 814 | } | |
| 815 | } | |
| 816 | else | |
| 817 | { | |
| 818 | verboselog(space.machine(), 2, "mc68328_w: PBDIR = %02x\n", (data >> 8) & 0x00ff); | |
| 819 | mc68328->regs.pbdir = (data >> 8) & 0x00ff; | |
| 820 | } | |
| 821 | break; | |
| 822 | ||
| 823 | case 0x40a: | |
| 824 | if( mem_mask & 0x00ff ) | |
| 825 | { | |
| 826 | verboselog(space.machine(), 2, "mc68328_w: PBSEL = %02x\n", data & 0x00ff); | |
| 827 | mc68328->regs.pbsel = data & 0x00ff; | |
| 828 | } | |
| 829 | else | |
| 830 | { | |
| 831 | verboselog(space.machine(), 2, "mc68328_w: Unknown address (0xfff40a) = %02x\n", (data >> 8) & 0x00ff); | |
| 832 | } | |
| 833 | break; | |
| 834 | ||
| 835 | case 0x410: | |
| 836 | if( mem_mask & 0x00ff ) | |
| 837 | { | |
| 838 | verboselog(space.machine(), 2, "mc68328_w: PCDATA = %02x\n", data & 0x00ff); | |
| 839 | mc68328->regs.pcdata = data & 0x00ff; | |
| 840 | if(!mc68328->out_port_c.isnull()) | |
| 841 | { | |
| 842 | mc68328->out_port_c( 0, data & 0x00ff ); | |
| 843 | } | |
| 844 | } | |
| 845 | else | |
| 846 | { | |
| 847 | verboselog(space.machine(), 2, "mc68328_w: PCDIR = %02x\n", (data >> 8) & 0x00ff); | |
| 848 | mc68328->regs.pcdir = (data >> 8) & 0x00ff; | |
| 849 | } | |
| 850 | break; | |
| 851 | ||
| 852 | case 0x412: | |
| 853 | if( mem_mask & 0x00ff ) | |
| 854 | { | |
| 855 | verboselog(space.machine(), 2, "mc68328_w: PCSEL = %02x\n", data & 0x00ff); | |
| 856 | mc68328->regs.pcsel = data & 0x00ff; | |
| 857 | } | |
| 858 | else | |
| 859 | { | |
| 860 | verboselog(space.machine(), 2, "mc68328_w: Unknown address (0xfff412) = %02x\n", (data >> 8) & 0x00ff); | |
| 861 | } | |
| 862 | break; | |
| 863 | ||
| 864 | case 0x418: | |
| 865 | if( mem_mask & 0x00ff ) | |
| 866 | { | |
| 867 | verboselog(space.machine(), 2, "mc68328_w: PDDATA = %02x\n", data & 0x00ff); | |
| 868 | ||
| 869 | mc68328->regs.pddataedge &= ~(data & 0x00ff); | |
| 870 | mc68328_poll_port_d_interrupts(device); | |
| 871 | } | |
| 872 | else | |
| 873 | { | |
| 874 | verboselog(space.machine(), 2, "mc68328_w: PDDIR = %02x\n", (data >> 8) & 0x00ff); | |
| 875 | mc68328->regs.pddir = (data >> 8) & 0x00ff; | |
| 876 | } | |
| 877 | break; | |
| 878 | ||
| 879 | case 0x41a: | |
| 880 | if( mem_mask & 0x00ff ) | |
| 881 | { | |
| 882 | verboselog(space.machine(), 2, "mc68328_w: Unknown address (0xfff41b) = %02x\n", data & 0x00ff); | |
| 883 | } | |
| 884 | else | |
| 885 | { | |
| 886 | verboselog(space.machine(), 2, "mc68328_w: PDPUEN = %02x\n", (data >> 8) & 0x00ff); | |
| 887 | mc68328->regs.pdpuen = (data >> 8) & 0x00ff; | |
| 888 | } | |
| 889 | break; | |
| 890 | ||
| 891 | case 0x41c: | |
| 892 | if( mem_mask & 0x00ff ) | |
| 893 | { | |
| 894 | verboselog(space.machine(), 2, "mc68328_w: PDIRQEN = %02x\n", data & 0x00ff); | |
| 895 | mc68328->regs.pdirqen = data & 0x00ff; | |
| 896 | ||
| 897 | mc68328_poll_port_d_interrupts(device); | |
| 898 | } | |
| 899 | else | |
| 900 | { | |
| 901 | verboselog(space.machine(), 2, "mc68328_w: PDPOL = %02x\n", (data >> 8) & 0x00ff); | |
| 902 | mc68328->regs.pdpol = (data >> 8) & 0x00ff; | |
| 903 | } | |
| 904 | break; | |
| 905 | ||
| 906 | case 0x41e: | |
| 907 | if( mem_mask & 0x00ff ) | |
| 908 | { | |
| 909 | verboselog(space.machine(), 2, "mc68328_w: PDIRQEDGE = %02x\n", data & 0x00ff); | |
| 910 | mc68328->regs.pdirqedge = data & 0x00ff; | |
| 911 | } | |
| 912 | else | |
| 913 | { | |
| 914 | verboselog(space.machine(), 2, "mc68328_w: Unknown address (0xfff41e) = %02x\n", (data >> 8) & 0x00ff); | |
| 915 | } | |
| 916 | break; | |
| 917 | ||
| 918 | case 0x420: | |
| 919 | if( mem_mask & 0x00ff ) | |
| 920 | { | |
| 921 | verboselog(space.machine(), 2, "mc68328_w: PEDATA = %02x\n", data & 0x00ff); | |
| 922 | mc68328->regs.pedata = data & 0x00ff; | |
| 923 | if(!mc68328->out_port_e.isnull()) | |
| 924 | { | |
| 925 | mc68328->out_port_e( 0, data & 0x00ff ); | |
| 926 | } | |
| 927 | } | |
| 928 | else | |
| 929 | { | |
| 930 | verboselog(space.machine(), 2, "mc68328_w: PEDIR = %02x\n", (data >> 8) & 0x00ff); | |
| 931 | mc68328->regs.pedir = (data >> 8) & 0x00ff; | |
| 932 | } | |
| 933 | break; | |
| 934 | ||
| 935 | case 0x422: | |
| 936 | if( mem_mask & 0x00ff ) | |
| 937 | { | |
| 938 | verboselog(space.machine(), 2, "mc68328_w: PESEL = %02x\n", data & 0x00ff); | |
| 939 | mc68328->regs.pesel = data & 0x00ff; | |
| 940 | } | |
| 941 | else | |
| 942 | { | |
| 943 | verboselog(space.machine(), 2, "mc68328_w: PEPUEN = %02x\n", (data >> 8) & 0x00ff); | |
| 944 | mc68328->regs.pepuen = (data >> 8) & 0x00ff; | |
| 945 | mc68328->regs.pedata |= mc68328->regs.pepuen; | |
| 946 | } | |
| 947 | break; | |
| 948 | ||
| 949 | case 0x428: | |
| 950 | if( mem_mask & 0x00ff ) | |
| 951 | { | |
| 952 | verboselog(space.machine(), 2, "mc68328_w: PFDATA = %02x\n", data & 0x00ff); | |
| 953 | mc68328->regs.pfdata = data & 0x00ff; | |
| 954 | if(!mc68328->out_port_f.isnull()) | |
| 955 | { | |
| 956 | mc68328->out_port_f( 0, data & 0x00ff ); | |
| 957 | } | |
| 958 | } | |
| 959 | else | |
| 960 | { | |
| 961 | verboselog(space.machine(), 2, "mc68328_w: PFDIR = %02x\n", (data >> 8) & 0x00ff); | |
| 962 | mc68328->regs.pfdir = (data >> 8) & 0x00ff; | |
| 963 | } | |
| 964 | break; | |
| 965 | ||
| 966 | case 0x42a: | |
| 967 | if( mem_mask & 0x00ff ) | |
| 968 | { | |
| 969 | verboselog(space.machine(), 2, "mc68328_w: PFSEL = %02x\n", data & 0x00ff); | |
| 970 | mc68328->regs.pfsel = data & 0x00ff; | |
| 971 | } | |
| 972 | else | |
| 973 | { | |
| 974 | verboselog(space.machine(), 2, "mc68328_w: PFPUEN = %02x\n", (data >> 8) & 0x00ff); | |
| 975 | mc68328->regs.pfpuen = (data >> 8) & 0x00ff; | |
| 976 | } | |
| 977 | break; | |
| 978 | ||
| 979 | case 0x430: | |
| 980 | if( mem_mask & 0x00ff ) | |
| 981 | { | |
| 982 | verboselog(space.machine(), 2, "mc68328_w: PGDATA = %02x\n", data & 0x00ff); | |
| 983 | mc68328->regs.pgdata = data & 0x00ff; | |
| 984 | if(!mc68328->out_port_g.isnull()) | |
| 985 | { | |
| 986 | mc68328->out_port_g( 0, data & 0x00ff ); | |
| 987 | } | |
| 988 | } | |
| 989 | else | |
| 990 | { | |
| 991 | verboselog(space.machine(), 2, "mc68328_w: PGDIR = %02x\n", (data >> 8) & 0x00ff); | |
| 992 | mc68328->regs.pgdir = (data >> 8) & 0x00ff; | |
| 993 | } | |
| 994 | break; | |
| 995 | ||
| 996 | case 0x432: | |
| 997 | if( mem_mask & 0x00ff ) | |
| 998 | { | |
| 999 | verboselog(space.machine(), 2, "mc68328_w: PGSEL = %02x\n", data & 0x00ff); | |
| 1000 | mc68328->regs.pgsel = data & 0x00ff; | |
| 1001 | } | |
| 1002 | else | |
| 1003 | { | |
| 1004 | verboselog(space.machine(), 2, "mc68328_w: PGPUEN = %02x\n", (data >> 8) & 0x00ff); | |
| 1005 | mc68328->regs.pgpuen = (data >> 8) & 0x00ff; | |
| 1006 | } | |
| 1007 | break; | |
| 1008 | ||
| 1009 | case 0x438: | |
| 1010 | if( mem_mask & 0x00ff ) | |
| 1011 | { | |
| 1012 | verboselog(space.machine(), 2, "mc68328_w: PJDATA = %02x\n", data & 0x00ff); | |
| 1013 | mc68328->regs.pjdata = data & 0x00ff; | |
| 1014 | if(!mc68328->out_port_j.isnull()) | |
| 1015 | { | |
| 1016 | mc68328->out_port_j( 0, data & 0x00ff ); | |
| 1017 | } | |
| 1018 | } | |
| 1019 | else | |
| 1020 | { | |
| 1021 | verboselog(space.machine(), 2, "mc68328_w: PJDIR = %02x\n", (data >> 8) & 0x00ff); | |
| 1022 | mc68328->regs.pjdir = (data >> 8) & 0x00ff; | |
| 1023 | } | |
| 1024 | break; | |
| 1025 | ||
| 1026 | case 0x43a: | |
| 1027 | if( mem_mask & 0x00ff ) | |
| 1028 | { | |
| 1029 | verboselog(space.machine(), 2, "mc68328_w: PJSEL = %02x\n", data & 0x00ff); | |
| 1030 | mc68328->regs.pjsel = data & 0x00ff; | |
| 1031 | } | |
| 1032 | else | |
| 1033 | { | |
| 1034 | verboselog(space.machine(), 2, "mc68328_w: Unknown address (0xfff43a) = %02x\n", (data >> 8) & 0x00ff); | |
| 1035 | } | |
| 1036 | break; | |
| 1037 | ||
| 1038 | case 0x440: | |
| 1039 | if( mem_mask & 0x00ff ) | |
| 1040 | { | |
| 1041 | verboselog(space.machine(), 2, "mc68328_w: PKDATA = %02x\n", data & 0x00ff); | |
| 1042 | mc68328->regs.pkdata = data & 0x00ff; | |
| 1043 | if(!mc68328->out_port_k.isnull()) | |
| 1044 | { | |
| 1045 | mc68328->out_port_k( 0, data & 0x00ff ); | |
| 1046 | } | |
| 1047 | } | |
| 1048 | else | |
| 1049 | { | |
| 1050 | verboselog(space.machine(), 2, "mc68328_w: PKDIR = %02x\n", (data >> 8) & 0x00ff); | |
| 1051 | mc68328->regs.pkdir = (data >> 8) & 0x00ff; | |
| 1052 | } | |
| 1053 | break; | |
| 1054 | ||
| 1055 | case 0x442: | |
| 1056 | if( mem_mask & 0x00ff ) | |
| 1057 | { | |
| 1058 | verboselog(space.machine(), 2, "mc68328_w: PKSEL = %02x\n", data & 0x00ff); | |
| 1059 | mc68328->regs.pksel = data & 0x00ff; | |
| 1060 | } | |
| 1061 | else | |
| 1062 | { | |
| 1063 | verboselog(space.machine(), 2, "mc68328_w: PKPUEN = %02x\n", (data >> 8) & 0x00ff); | |
| 1064 | mc68328->regs.pgpuen = (data >> 8) & 0x00ff; | |
| 1065 | } | |
| 1066 | break; | |
| 1067 | ||
| 1068 | case 0x448: | |
| 1069 | if( mem_mask & 0x00ff ) | |
| 1070 | { | |
| 1071 | verboselog(space.machine(), 2, "mc68328_w: PMDATA = %02x\n", data & 0x00ff); | |
| 1072 | mc68328->regs.pmdata = data & 0x00ff; | |
| 1073 | if(!mc68328->out_port_m.isnull()) | |
| 1074 | { | |
| 1075 | mc68328->out_port_m( 0, data & 0x00ff ); | |
| 1076 | } | |
| 1077 | } | |
| 1078 | else | |
| 1079 | { | |
| 1080 | verboselog(space.machine(), 2, "mc68328_w: PMDIR = %02x\n", (data >> 8) & 0x00ff); | |
| 1081 | mc68328->regs.pmdir = (data >> 8) & 0x00ff; | |
| 1082 | } | |
| 1083 | break; | |
| 1084 | ||
| 1085 | case 0x44a: | |
| 1086 | if( mem_mask & 0x00ff ) | |
| 1087 | { | |
| 1088 | verboselog(space.machine(), 2, "mc68328_w: PMSEL = %02x\n", data & 0x00ff); | |
| 1089 | mc68328->regs.pmsel = data & 0x00ff; | |
| 1090 | } | |
| 1091 | else | |
| 1092 | { | |
| 1093 | verboselog(space.machine(), 2, "mc68328_w: PMPUEN = %02x\n", (data >> 8) & 0x00ff); | |
| 1094 | mc68328->regs.pmpuen = (data >> 8) & 0x00ff; | |
| 1095 | } | |
| 1096 | break; | |
| 1097 | ||
| 1098 | case 0x500: | |
| 1099 | verboselog(space.machine(), 2, "mc68328_w: PWMC = %04x\n", data); | |
| 1100 | ||
| 1101 | mc68328->regs.pwmc = data; | |
| 1102 | ||
| 1103 | if(mc68328->regs.pwmc & PWMC_PWMIRQ) | |
| 1104 | { | |
| 1105 | mc68328_set_interrupt_line(device, INT_PWM, 1); | |
| 1106 | } | |
| 1107 | ||
| 1108 | mc68328->regs.pwmc &= ~PWMC_LOAD; | |
| 1109 | ||
| 1110 | if((mc68328->regs.pwmc & PWMC_PWMEN) != 0 && mc68328->regs.pwmw != 0 && mc68328->regs.pwmp != 0) | |
| 1111 | { | |
| 1112 | UINT32 frequency = 32768 * 506; | |
| 1113 | UINT32 divisor = 4 << (mc68328->regs.pwmc & PWMC_CLKSEL); // ?? Datasheet says 2 <<, but then we're an octave higher than CoPilot. | |
| 1114 | attotime period; | |
| 1115 | frequency /= divisor; | |
| 1116 | period = attotime::from_hz(frequency) * mc68328->regs.pwmw; | |
| 1117 | mc68328->pwm->adjust(period); | |
| 1118 | if(mc68328->regs.pwmc & PWMC_IRQEN) | |
| 1119 | { | |
| 1120 | mc68328_set_interrupt_line(device, INT_PWM, 1); | |
| 1121 | } | |
| 1122 | mc68328->regs.pwmc ^= PWMC_PIN; | |
| 1123 | } | |
| 1124 | else | |
| 1125 | { | |
| 1126 | mc68328->pwm->adjust(attotime::never); | |
| 1127 | } | |
| 1128 | break; | |
| 1129 | ||
| 1130 | case 0x502: | |
| 1131 | verboselog(space.machine(), 2, "mc68328_w: PWMP = %04x\n", data); | |
| 1132 | mc68328->regs.pwmp = data; | |
| 1133 | break; | |
| 1134 | ||
| 1135 | case 0x504: | |
| 1136 | verboselog(space.machine(), 2, "mc68328_w: PWMW = %04x\n", data); | |
| 1137 | mc68328->regs.pwmw = data; | |
| 1138 | break; | |
| 1139 | ||
| 1140 | case 0x506: | |
| 1141 | verboselog(space.machine(), 2, "mc68328_w: PWMCNT = %04x\n", data); | |
| 1142 | mc68328->regs.pwmcnt = 0; | |
| 1143 | break; | |
| 1144 | ||
| 1145 | case 0x600: | |
| 1146 | verboselog(space.machine(), 2, "mc68328_w: TCTL1 = %04x\n", data); | |
| 1147 | temp16[0] = mc68328->regs.tctl[0]; | |
| 1148 | mc68328->regs.tctl[0] = data; | |
| 1149 | if((temp16[0] & TCTL_TEN) == (mc68328->regs.tctl[0] & TCTL_TEN)) | |
| 1150 | { | |
| 1151 | mc68328_maybe_start_timer(device, 0, 0); | |
| 1152 | } | |
| 1153 | else if((temp16[0] & TCTL_TEN) != TCTL_TEN_ENABLE && (mc68328->regs.tctl[0] & TCTL_TEN) == TCTL_TEN_ENABLE) | |
| 1154 | { | |
| 1155 | mc68328_maybe_start_timer(device, 0, 1); | |
| 1156 | } | |
| 1157 | break; | |
| 1158 | ||
| 1159 | case 0x602: | |
| 1160 | verboselog(space.machine(), 2, "mc68328_w: TPRER1 = %04x\n", data); | |
| 1161 | mc68328->regs.tprer[0] = data; | |
| 1162 | mc68328_maybe_start_timer(device, 0, 0); | |
| 1163 | break; | |
| 1164 | ||
| 1165 | case 0x604: | |
| 1166 | verboselog(space.machine(), 2, "mc68328_w: TCMP1 = %04x\n", data); | |
| 1167 | mc68328->regs.tcmp[0] = data; | |
| 1168 | mc68328_maybe_start_timer(device, 0, 0); | |
| 1169 | break; | |
| 1170 | ||
| 1171 | case 0x606: | |
| 1172 | verboselog(space.machine(), 2, "mc68328_w: TCR1 = %04x (Ignored)\n", data); | |
| 1173 | break; | |
| 1174 | ||
| 1175 | case 0x608: | |
| 1176 | verboselog(space.machine(), 2, "mc68328_w: TCN1 = %04x (Ignored)\n", data); | |
| 1177 | break; | |
| 1178 | ||
| 1179 | case 0x60a: | |
| 1180 | verboselog(space.machine(), 5, "mc68328_w: TSTAT1 = %04x\n", data); | |
| 1181 | mc68328->regs.tstat[0] &= ~mc68328->regs.tclear[0]; | |
| 1182 | if(!(mc68328->regs.tstat[0] & TSTAT_COMP)) | |
| 1183 | { | |
| 1184 | mc68328_set_interrupt_line(device, INT_TIMER1, 0); | |
| 1185 | } | |
| 1186 | break; | |
| 1187 | ||
| 1188 | case 0x60c: | |
| 1189 | verboselog(space.machine(), 2, "mc68328_w: TCTL2 = %04x\n", data); | |
| 1190 | temp16[0] = mc68328->regs.tctl[1]; | |
| 1191 | mc68328->regs.tctl[1] = data; | |
| 1192 | if((temp16[0] & TCTL_TEN) == (mc68328->regs.tctl[1] & TCTL_TEN)) | |
| 1193 | { | |
| 1194 | mc68328_maybe_start_timer(device, 1, 0); | |
| 1195 | } | |
| 1196 | else if((temp16[0] & TCTL_TEN) != TCTL_TEN_ENABLE && (mc68328->regs.tctl[1] & TCTL_TEN) == TCTL_TEN_ENABLE) | |
| 1197 | { | |
| 1198 | mc68328_maybe_start_timer(device, 1, 1); | |
| 1199 | } | |
| 1200 | break; | |
| 1201 | ||
| 1202 | case 0x60e: | |
| 1203 | verboselog(space.machine(), 2, "mc68328_w: TPRER2 = %04x\n", data); | |
| 1204 | mc68328->regs.tprer[1] = data; | |
| 1205 | mc68328_maybe_start_timer(device, 1, 0); | |
| 1206 | break; | |
| 1207 | ||
| 1208 | case 0x610: | |
| 1209 | verboselog(space.machine(), 2, "mc68328_w: TCMP2 = %04x\n", data); | |
| 1210 | mc68328->regs.tcmp[1] = data; | |
| 1211 | mc68328_maybe_start_timer(device, 1, 0); | |
| 1212 | break; | |
| 1213 | ||
| 1214 | case 0x612: | |
| 1215 | verboselog(space.machine(), 2, "mc68328_w: TCR2 = %04x (Ignored)\n", data); | |
| 1216 | break; | |
| 1217 | ||
| 1218 | case 0x614: | |
| 1219 | verboselog(space.machine(), 2, "mc68328_w: TCN2 = %04x (Ignored)\n", data); | |
| 1220 | break; | |
| 1221 | ||
| 1222 | case 0x616: | |
| 1223 | verboselog(space.machine(), 2, "mc68328_w: TSTAT2 = %04x\n", data); | |
| 1224 | mc68328->regs.tstat[1] &= ~mc68328->regs.tclear[1]; | |
| 1225 | if(!(mc68328->regs.tstat[1] & TSTAT_COMP)) | |
| 1226 | { | |
| 1227 | mc68328_set_interrupt_line(device, INT_TIMER2, 0); | |
| 1228 | } | |
| 1229 | break; | |
| 1230 | ||
| 1231 | case 0x618: | |
| 1232 | verboselog(space.machine(), 2, "mc68328_w: WCTLR = %04x\n", data); | |
| 1233 | mc68328->regs.wctlr = data; | |
| 1234 | break; | |
| 1235 | ||
| 1236 | case 0x61a: | |
| 1237 | verboselog(space.machine(), 2, "mc68328_w: WCMPR = %04x\n", data); | |
| 1238 | mc68328->regs.wcmpr = data; | |
| 1239 | break; | |
| 1240 | ||
| 1241 | case 0x61c: | |
| 1242 | verboselog(space.machine(), 2, "mc68328_w: WCN = %04x (Ignored)\n", data); | |
| 1243 | break; | |
| 1244 | ||
| 1245 | case 0x700: | |
| 1246 | verboselog(space.machine(), 2, "mc68328_w: SPISR = %04x\n", data); | |
| 1247 | mc68328->regs.spisr = data; | |
| 1248 | break; | |
| 1249 | ||
| 1250 | case 0x800: | |
| 1251 | verboselog(space.machine(), 2, "mc68328_w: SPIMDATA = %04x\n", data); | |
| 1252 | if(!mc68328->out_spim.isnull()) | |
| 1253 | { | |
| 1254 | mc68328->out_spim( 0, data, 0xffff ); | |
| 1255 | } | |
| 1256 | else | |
| 1257 | { | |
| 1258 | mc68328->regs.spimdata = data; | |
| 1259 | } | |
| 1260 | break; | |
| 1261 | ||
| 1262 | case 0x802: | |
| 1263 | verboselog(space.machine(), 2, "mc68328_w: SPIMCONT = %04x\n", data); | |
| 1264 | verboselog(space.machine(), 3, " Count = %d\n", data & SPIM_CLOCK_COUNT); | |
| 1265 | verboselog(space.machine(), 3, " Polarity = %s\n", (data & SPIM_POL) ? "Inverted" : "Active-high"); | |
| 1266 | verboselog(space.machine(), 3, " Phase = %s\n", (data & SPIM_PHA) ? "Opposite" : "Normal"); | |
| 1267 | verboselog(space.machine(), 3, " IRQ Enable = %s\n", (data & SPIM_IRQEN) ? "Enable" : "Disable"); | |
| 1268 | verboselog(space.machine(), 3, " IRQ Pending = %s\n", (data & SPIM_SPIMIRQ) ? "Yes" : "No"); | |
| 1269 | verboselog(space.machine(), 3, " Exchange = %s\n", (data & SPIM_XCH) ? "Initiate" : "Idle"); | |
| 1270 | verboselog(space.machine(), 3, " SPIM Enable = %s\n", (data & SPIM_SPMEN) ? "Enable" : "Disable"); | |
| 1271 | verboselog(space.machine(), 3, " Data Rate = Divide By %d\n", 1 << ((((data & SPIM_RATE) >> 13) & 0x0007) + 2) ); | |
| 1272 | mc68328->regs.spimcont = data; | |
| 1273 | // $$HACK$$ We should probably emulate the ADS7843 A/D device properly. | |
| 1274 | if(data & SPIM_XCH) | |
| 1275 | { | |
| 1276 | mc68328->regs.spimcont &= ~SPIM_XCH; | |
| 1277 | if(mc68328->iface->spim_xch_trigger) | |
| 1278 | { | |
| 1279 | (mc68328->iface->spim_xch_trigger)( device ); | |
| 1280 | } | |
| 1281 | if(data & SPIM_IRQEN) | |
| 1282 | { | |
| 1283 | mc68328->regs.spimcont |= SPIM_SPIMIRQ; | |
| 1284 | verboselog(space.machine(), 3, "Triggering SPIM Interrupt\n" ); | |
| 1285 | mc68328_set_interrupt_line(device, INT_SPIM, 1); | |
| 1286 | } | |
| 1287 | } | |
| 1288 | if(!(data & SPIM_IRQEN)) | |
| 1289 | { | |
| 1290 | mc68328_set_interrupt_line(device, INT_SPIM, 0); | |
| 1291 | } | |
| 1292 | break; | |
| 1293 | ||
| 1294 | case 0x900: | |
| 1295 | verboselog(space.machine(), 2, "mc68328_w: USTCNT = %04x\n", data); | |
| 1296 | mc68328->regs.ustcnt = data; | |
| 1297 | break; | |
| 1298 | ||
| 1299 | case 0x902: | |
| 1300 | verboselog(space.machine(), 2, "mc68328_w: UBAUD = %04x\n", data); | |
| 1301 | mc68328->regs.ubaud = data; | |
| 1302 | break; | |
| 1303 | ||
| 1304 | case 0x904: | |
| 1305 | verboselog(space.machine(), 2, "mc68328_w: URX = %04x\n", data); | |
| 1306 | break; | |
| 1307 | ||
| 1308 | case 0x906: | |
| 1309 | verboselog(space.machine(), 2, "mc68328_w: UTX = %04x\n", data); | |
| 1310 | break; | |
| 1311 | ||
| 1312 | case 0x908: | |
| 1313 | verboselog(space.machine(), 2, "mc68328_w: UMISC = %04x\n", data); | |
| 1314 | mc68328->regs.umisc = data; | |
| 1315 | break; | |
| 1316 | ||
| 1317 | case 0xa00: | |
| 1318 | verboselog(space.machine(), 2, "mc68328_w: LSSA(16) = %04x\n", data); | |
| 1319 | mc68328->regs.lssa &= ~(mem_mask << 16); | |
| 1320 | mc68328->regs.lssa |= (data & mem_mask) << 16; | |
| 1321 | verboselog(space.machine(), 3, " Address: %08x\n", mc68328->regs.lssa); | |
| 1322 | break; | |
| 1323 | ||
| 1324 | case 0xa02: | |
| 1325 | verboselog(space.machine(), 2, "mc68328_w: LSSA(0) = %04x\n", data); | |
| 1326 | mc68328->regs.lssa &= 0xffff0000 | (~mem_mask); | |
| 1327 | mc68328->regs.lssa |= data & mem_mask; | |
| 1328 | verboselog(space.machine(), 3, " Address: %08x\n", mc68328->regs.lssa); | |
| 1329 | break; | |
| 1330 | ||
| 1331 | case 0xa04: | |
| 1332 | if( mem_mask & 0x00ff ) | |
| 1333 | { | |
| 1334 | verboselog(space.machine(), 2, "mc68328_w: LVPW = %02x\n", data & 0x00ff); | |
| 1335 | mc68328->regs.lvpw = data & 0x00ff; | |
| 1336 | verboselog(space.machine(), 3, " Page Width: %d or %d\n", (mc68328->regs.lvpw + 1) * ((mc68328->regs.lpicf & 0x01) ? 8 : 16)); | |
| 1337 | } | |
| 1338 | else | |
| 1339 | { | |
| 1340 | verboselog(space.machine(), 2, "mc68328_w: Unknown address (0xfffa04) = %02x\n", (data >> 8) & 0x00ff); | |
| 1341 | } | |
| 1342 | break; | |
| 1343 | ||
| 1344 | case 0xa08: | |
| 1345 | verboselog(space.machine(), 2, "mc68328_w: LXMAX = %04x\n", data); | |
| 1346 | mc68328->regs.lxmax = data; | |
| 1347 | verboselog(space.machine(), 3, " Width: %d\n", (data & 0x03ff) + 1); | |
| 1348 | break; | |
| 1349 | ||
| 1350 | case 0xa0a: | |
| 1351 | verboselog(space.machine(), 2, "mc68328_w: LYMAX = %04x\n", data); | |
| 1352 | mc68328->regs.lymax = data; | |
| 1353 | verboselog(space.machine(), 3, " Height: %d\n", (data & 0x03ff) + 1); | |
| 1354 | break; | |
| 1355 | ||
| 1356 | case 0xa18: | |
| 1357 | verboselog(space.machine(), 2, "mc68328_w: LCXP = %04x\n", data); | |
| 1358 | mc68328->regs.lcxp = data; | |
| 1359 | verboselog(space.machine(), 3, " X Position: %d\n", data & 0x03ff); | |
| 1360 | switch(mc68328->regs.lcxp >> 14) | |
| 1361 | { | |
| 1362 | case 0: | |
| 1363 | verboselog(space.machine(), 3, " Cursor Control: Transparent\n"); | |
| 1364 | break; | |
| 1365 | ||
| 1366 | case 1: | |
| 1367 | verboselog(space.machine(), 3, " Cursor Control: Black\n"); | |
| 1368 | break; | |
| 1369 | ||
| 1370 | case 2: | |
| 1371 | verboselog(space.machine(), 3, " Cursor Control: Reverse\n"); | |
| 1372 | break; | |
| 1373 | ||
| 1374 | case 3: | |
| 1375 | verboselog(space.machine(), 3, " Cursor Control: Invalid\n"); | |
| 1376 | break; | |
| 1377 | } | |
| 1378 | break; | |
| 1379 | ||
| 1380 | case 0xa1a: | |
| 1381 | verboselog(space.machine(), 2, "mc68328_w: LCYP = %04x\n", data); | |
| 1382 | mc68328->regs.lcyp = data; | |
| 1383 | verboselog(space.machine(), 3, " Y Position: %d\n", data & 0x01ff); | |
| 1384 | break; | |
| 1385 | ||
| 1386 | case 0xa1c: | |
| 1387 | verboselog(space.machine(), 2, "mc68328_w: LCWCH = %04x\n", data); | |
| 1388 | mc68328->regs.lcwch = data; | |
| 1389 | verboselog(space.machine(), 3, " Width: %d\n", (data >> 8) & 0x1f); | |
| 1390 | verboselog(space.machine(), 3, " Height: %d\n", data & 0x1f); | |
| 1391 | break; | |
| 1392 | ||
| 1393 | case 0xa1e: | |
| 1394 | if( mem_mask & 0x00ff ) | |
| 1395 | { | |
| 1396 | verboselog(space.machine(), 2, "mc68328_w: LBLKC = %02x\n", data & 0x00ff); | |
| 1397 | mc68328->regs.lblkc = data & 0x00ff; | |
| 1398 | verboselog(space.machine(), 3, " Blink Enable: %d\n", mc68328->regs.lblkc >> 7); | |
| 1399 | verboselog(space.machine(), 3, " Blink Divisor: %d\n", mc68328->regs.lblkc & 0x7f); | |
| 1400 | } | |
| 1401 | else | |
| 1402 | { | |
| 1403 | verboselog(space.machine(), 2, "mc68328_w: Unknown address (0xfffa1e) = %02x\n", (data >> 8) & 0x00ff); | |
| 1404 | } | |
| 1405 | break; | |
| 1406 | ||
| 1407 | case 0xa20: | |
| 1408 | if( mem_mask & 0x00ff ) | |
| 1409 | { | |
| 1410 | verboselog(space.machine(), 2, "mc68328_w: LPOLCF = %02x\n", data & 0x00ff); | |
| 1411 | mc68328->regs.lpolcf = data & 0x00ff; | |
| 1412 | verboselog(space.machine(), 3, " LCD Shift Clock Polarity: %s\n", (mc68328->regs.lpicf & 0x08) ? "Active positive edge of LCLK" : "Active negative edge of LCLK"); | |
| 1413 | verboselog(space.machine(), 3, " First-line marker polarity: %s\n", (mc68328->regs.lpicf & 0x04) ? "Active Low" : "Active High"); | |
| 1414 | verboselog(space.machine(), 3, " Line-pulse polarity: %s\n", (mc68328->regs.lpicf & 0x02) ? "Active Low" : "Active High"); | |
| 1415 | verboselog(space.machine(), 3, " Pixel polarity: %s\n", (mc68328->regs.lpicf & 0x01) ? "Active Low" : "Active High"); | |
| 1416 | } | |
| 1417 | else | |
| 1418 | { | |
| 1419 | verboselog(space.machine(), 2, "mc68328_w: LPICF = %02x\n", (data >> 8) & 0x00ff); | |
| 1420 | mc68328->regs.lpicf = (data >> 8) & 0x00ff; | |
| 1421 | switch((mc68328->regs.lpicf >> 1) & 0x03) | |
| 1422 | { | |
| 1423 | case 0: | |
| 1424 | verboselog(space.machine(), 3, " Bus Size: 1-bit\n"); | |
| 1425 | break; | |
| 1426 | ||
| 1427 | case 1: | |
| 1428 | verboselog(space.machine(), 3, " Bus Size: 2-bit\n"); | |
| 1429 | break; | |
| 1430 | ||
| 1431 | case 2: | |
| 1432 | verboselog(space.machine(), 3, " Bus Size: 4-bit\n"); | |
| 1433 | break; | |
| 1434 | ||
| 1435 | case 3: | |
| 1436 | verboselog(space.machine(), 3, " Bus Size: unused\n"); | |
| 1437 | break; | |
| 1438 | } | |
| 1439 | verboselog(space.machine(), 3, " Gray scale enable: %d\n", mc68328->regs.lpicf & 0x01); | |
| 1440 | } | |
| 1441 | break; | |
| 1442 | ||
| 1443 | case 0xa22: | |
| 1444 | if( mem_mask & 0x00ff ) | |
| 1445 | { | |
| 1446 | verboselog(space.machine(), 2, "mc68328_w: LACDRC = %02x\n", data & 0x00ff); | |
| 1447 | mc68328->regs.lacdrc = data & 0x00ff; | |
| 1448 | } | |
| 1449 | else | |
| 1450 | { | |
| 1451 | verboselog(space.machine(), 2, "mc68328_w: Unknown address (0xfffa22) = %02x\n", (data >> 8) & 0x00ff); | |
| 1452 | } | |
| 1453 | break; | |
| 1454 | ||
| 1455 | case 0xa24: | |
| 1456 | if( mem_mask & 0x00ff ) | |
| 1457 | { | |
| 1458 | verboselog(space.machine(), 2, "mc68328_w: LPXCD = %02x\n", data & 0x00ff); | |
| 1459 | mc68328->regs.lpxcd = data & 0x00ff; | |
| 1460 | verboselog(space.machine(), 3, " Clock Divisor: %d\n", mc68328->regs.lpxcd + 1); | |
| 1461 | } | |
| 1462 | else | |
| 1463 | { | |
| 1464 | verboselog(space.machine(), 2, "mc68328_w: Unknown address (0xfffa24) = %02x\n", (data >> 8) & 0x00ff); | |
| 1465 | } | |
| 1466 | break; | |
| 1467 | ||
| 1468 | case 0xa26: | |
| 1469 | if( mem_mask & 0x00ff ) | |
| 1470 | { | |
| 1471 | verboselog(space.machine(), 2, "mc68328_w: LCKCON = %02x\n", data & 0x00ff); | |
| 1472 | mc68328->regs.lckcon = data & 0x00ff; | |
| 1473 | verboselog(space.machine(), 3, " LCDC Enable: %d\n", (mc68328->regs.lckcon >> 7) & 0x01); | |
| 1474 | verboselog(space.machine(), 3, " DMA Burst Length: %d\n", ((mc68328->regs.lckcon >> 6) & 0x01) ? 16 : 8); | |
| 1475 | verboselog(space.machine(), 3, " DMA Bursting Clock Control: %d\n", ((mc68328->regs.lckcon >> 4) & 0x03) + 1); | |
| 1476 | verboselog(space.machine(), 3, " Bus Width: %d\n", ((mc68328->regs.lckcon >> 1) & 0x01) ? 8 : 16); | |
| 1477 | verboselog(space.machine(), 3, " Pixel Clock Divider Source: %s\n", (mc68328->regs.lckcon & 0x01) ? "PIX" : "SYS"); | |
| 1478 | } | |
| 1479 | else | |
| 1480 | { | |
| 1481 | verboselog(space.machine(), 2, "mc68328_w: Unknown address (0xfffa26) = %02x\n", (data >> 8) & 0x00ff); | |
| 1482 | } | |
| 1483 | break; | |
| 1484 | ||
| 1485 | case 0xa28: | |
| 1486 | if( mem_mask & 0x00ff ) | |
| 1487 | { | |
| 1488 | verboselog(space.machine(), 2, "mc68328_w: LLBAR = %02x\n", data & 0x00ff); | |
| 1489 | mc68328->regs.llbar = data & 0x00ff; | |
| 1490 | verboselog(space.machine(), 3, " Address: %d\n", (mc68328->regs.llbar & 0x7f) * ((mc68328->regs.lpicf & 0x01) ? 8 : 16)); | |
| 1491 | } | |
| 1492 | else | |
| 1493 | { | |
| 1494 | verboselog(space.machine(), 2, "mc68328_w: Unknown address (0xfffa28) = %02x\n", (data >> 8) & 0x00ff); | |
| 1495 | } | |
| 1496 | break; | |
| 1497 | ||
| 1498 | case 0xa2a: | |
| 1499 | if( mem_mask & 0x00ff ) | |
| 1500 | { | |
| 1501 | verboselog(space.machine(), 2, "mc68328_w: LOTCR = %02x\n", data & 0x00ff); | |
| 1502 | } | |
| 1503 | else | |
| 1504 | { | |
| 1505 | verboselog(space.machine(), 2, "mc68328_w: Unknown address (0xfffa2a) = %02x\n", (data >> 8) & 0x00ff); | |
| 1506 | } | |
| 1507 | break; | |
| 1508 | ||
| 1509 | case 0xa2c: | |
| 1510 | if( mem_mask & 0x00ff ) | |
| 1511 | { | |
| 1512 | verboselog(space.machine(), 2, "mc68328_w: LPOSR = %02x\n", data & 0x00ff); | |
| 1513 | mc68328->regs.lposr = data & 0x00ff; | |
| 1514 | verboselog(space.machine(), 3, " Byte Offset: %d\n", (mc68328->regs.lposr >> 3) & 0x01); | |
| 1515 | verboselog(space.machine(), 3, " Pixel Offset: %d\n", mc68328->regs.lposr & 0x07); | |
| 1516 | } | |
| 1517 | else | |
| 1518 | { | |
| 1519 | verboselog(space.machine(), 2, "mc68328_w: Unknown address (0xfffa2c) = %02x\n", (data >> 8) & 0x00ff); | |
| 1520 | } | |
| 1521 | break; | |
| 1522 | ||
| 1523 | case 0xa30: | |
| 1524 | if( mem_mask & 0x00ff ) | |
| 1525 | { | |
| 1526 | verboselog(space.machine(), 2, "mc68328_w: LFRCM = %02x\n", data & 0x00ff); | |
| 1527 | mc68328->regs.lfrcm = data & 0x00ff; | |
| 1528 | verboselog(space.machine(), 3, " X Modulation: %d\n", (mc68328->regs.lfrcm >> 4) & 0x0f); | |
| 1529 | verboselog(space.machine(), 3, " Y Modulation: %d\n", mc68328->regs.lfrcm & 0x0f); | |
| 1530 | } | |
| 1531 | else | |
| 1532 | { | |
| 1533 | verboselog(space.machine(), 2, "mc68328_w: Unknown address (0xfffa30) = %02x\n", (data >> 8) & 0x00ff); | |
| 1534 | } | |
| 1535 | break; | |
| 1536 | ||
| 1537 | case 0xa32: | |
| 1538 | verboselog(space.machine(), 2, "mc68328_w: LGPMR = %04x\n", data); | |
| 1539 | mc68328->regs.lgpmr = data; | |
| 1540 | verboselog(space.machine(), 3, " Palette 0: %d\n", (mc68328->regs.lgpmr >> 8) & 0x07); | |
| 1541 | verboselog(space.machine(), 3, " Palette 1: %d\n", (mc68328->regs.lgpmr >> 12) & 0x07); | |
| 1542 | verboselog(space.machine(), 3, " Palette 2: %d\n", (mc68328->regs.lgpmr >> 0) & 0x07); | |
| 1543 | verboselog(space.machine(), 3, " Palette 3: %d\n", (mc68328->regs.lgpmr >> 4) & 0x07); | |
| 1544 | break; | |
| 1545 | ||
| 1546 | case 0xb00: | |
| 1547 | verboselog(space.machine(), 2, "mc68328_w: HMSR(0) = %04x\n", data); | |
| 1548 | mc68328->regs.hmsr &= ~(mem_mask << 16); | |
| 1549 | mc68328->regs.hmsr |= (data & mem_mask) << 16; | |
| 1550 | mc68328->regs.hmsr &= 0x1f3f003f; | |
| 1551 | break; | |
| 1552 | ||
| 1553 | case 0xb02: | |
| 1554 | verboselog(space.machine(), 2, "mc68328_w: HMSR(16) = %04x\n", data); | |
| 1555 | mc68328->regs.hmsr &= 0xffff0000 | (~mem_mask); | |
| 1556 | mc68328->regs.hmsr |= data & mem_mask; | |
| 1557 | mc68328->regs.hmsr &= 0x1f3f003f; | |
| 1558 | break; | |
| 1559 | ||
| 1560 | case 0xb04: | |
| 1561 | verboselog(space.machine(), 2, "mc68328_w: ALARM(0) = %04x\n", data); | |
| 1562 | mc68328->regs.alarm &= ~(mem_mask << 16); | |
| 1563 | mc68328->regs.alarm |= (data & mem_mask) << 16; | |
| 1564 | mc68328->regs.alarm &= 0x1f3f003f; | |
| 1565 | break; | |
| 1566 | ||
| 1567 | case 0xb06: | |
| 1568 | verboselog(space.machine(), 2, "mc68328_w: ALARM(16) = %04x\n", data); | |
| 1569 | mc68328->regs.alarm &= 0xffff0000 | (~mem_mask); | |
| 1570 | mc68328->regs.alarm |= data & mem_mask; | |
| 1571 | mc68328->regs.alarm &= 0x1f3f003f; | |
| 1572 | break; | |
| 1573 | ||
| 1574 | case 0xb0c: | |
| 1575 | verboselog(space.machine(), 2, "mc68328_w: RTCCTL = %04x\n", data); | |
| 1576 | mc68328->regs.rtcctl = data & 0x00a0; | |
| 1577 | break; | |
| 1578 | ||
| 1579 | case 0xb0e: | |
| 1580 | verboselog(space.machine(), 2, "mc68328_w: RTCISR = %04x\n", data); | |
| 1581 | mc68328->regs.rtcisr &= ~data; | |
| 1582 | if(mc68328->regs.rtcisr == 0) | |
| 1583 | { | |
| 1584 | mc68328_set_interrupt_line(device, INT_RTC, 0); | |
| 1585 | } | |
| 1586 | break; | |
| 1587 | ||
| 1588 | case 0xb10: | |
| 1589 | verboselog(space.machine(), 2, "mc68328_w: RTCIENR = %04x\n", data); | |
| 1590 | mc68328->regs.rtcienr = data & 0x001f; | |
| 1591 | break; | |
| 1592 | ||
| 1593 | case 0xb12: | |
| 1594 | verboselog(space.machine(), 2, "mc68328_w: STPWTCH = %04x\n", data); | |
| 1595 | mc68328->regs.stpwtch = data & 0x003f; | |
| 1596 | break; | |
| 1597 | ||
| 1598 | default: | |
| 1599 | verboselog(space.machine(), 0, "mc68328_w: Unknown address (0x%06x) = %04x (%04x)\n", 0xfff000 + address, data, mem_mask); | |
| 1600 | break; | |
| 1601 | } | |
| 1602 | } | |
| 1603 | ||
| 1604 | READ16_DEVICE_HANDLER( mc68328_r ) | |
| 1605 | { | |
| 1606 | mc68328_t* mc68328 = mc68328_get_safe_token( device ); | |
| 1607 | UINT16 temp16 = 0; | |
| 1608 | UINT32 address = offset << 1; | |
| 1609 | ||
| 1610 | switch(address) | |
| 1611 | { | |
| 1612 | case 0x000: | |
| 1613 | if( mem_mask & 0x00ff ) | |
| 1614 | { | |
| 1615 | verboselog(space.machine(), 2, "mc68328_r (%04x): Unknown address (0xfff001)\n", mem_mask); | |
| 1616 | } | |
| 1617 | else | |
| 1618 | { | |
| 1619 | verboselog(space.machine(), 2, "mc68328_r (%04x): SCR = %02x\n", mem_mask, mc68328->regs.scr); | |
| 1620 | return mc68328->regs.scr << 8; | |
| 1621 | } | |
| 1622 | break; | |
| 1623 | ||
| 1624 | case 0x100: | |
| 1625 | verboselog(space.machine(), 2, "mc68328_r (%04x): GRPBASEA = %04x\n", mem_mask, mc68328->regs.grpbasea); | |
| 1626 | return mc68328->regs.grpbasea; | |
| 1627 | ||
| 1628 | case 0x102: | |
| 1629 | verboselog(space.machine(), 2, "mc68328_r (%04x): GRPBASEB = %04x\n", mem_mask, mc68328->regs.grpbaseb); | |
| 1630 | return mc68328->regs.grpbaseb; | |
| 1631 | ||
| 1632 | case 0x104: | |
| 1633 | verboselog(space.machine(), 2, "mc68328_r (%04x): GRPBASEC = %04x\n", mem_mask, mc68328->regs.grpbasec); | |
| 1634 | return mc68328->regs.grpbasec; | |
| 1635 | ||
| 1636 | case 0x106: | |
| 1637 | verboselog(space.machine(), 2, "mc68328_r (%04x): GRPBASED = %04x\n", mem_mask, mc68328->regs.grpbased); | |
| 1638 | return mc68328->regs.grpbased; | |
| 1639 | ||
| 1640 | case 0x108: | |
| 1641 | verboselog(space.machine(), 2, "mc68328_r (%04x): GRPMASKA = %04x\n", mem_mask, mc68328->regs.grpmaska); | |
| 1642 | return mc68328->regs.grpmaska; | |
| 1643 | ||
| 1644 | case 0x10a: | |
| 1645 | verboselog(space.machine(), 2, "mc68328_r (%04x): GRPMASKB = %04x\n", mem_mask, mc68328->regs.grpmaskb); | |
| 1646 | return mc68328->regs.grpmaskb; | |
| 1647 | ||
| 1648 | case 0x10c: | |
| 1649 | verboselog(space.machine(), 2, "mc68328_r (%04x): GRPMASKC = %04x\n", mem_mask, mc68328->regs.grpmaskc); | |
| 1650 | return mc68328->regs.grpmaskc; | |
| 1651 | ||
| 1652 | case 0x10e: | |
| 1653 | verboselog(space.machine(), 2, "mc68328_r (%04x): GRPMASKD = %04x\n", mem_mask, mc68328->regs.grpmaskd); | |
| 1654 | return mc68328->regs.grpmaskd; | |
| 1655 | ||
| 1656 | case 0x110: | |
| 1657 | verboselog(space.machine(), 5, "mc68328_r (%04x): CSA0(0) = %04x\n", mem_mask, mc68328->regs.csa0 & 0x0000ffff); | |
| 1658 | return mc68328->regs.csa0 & 0x0000ffff; | |
| 1659 | ||
| 1660 | case 0x112: | |
| 1661 | verboselog(space.machine(), 5, "mc68328_r (%04x): CSA0(16) = %04x\n", mem_mask, mc68328->regs.csa0 >> 16); | |
| 1662 | return mc68328->regs.csa0 >> 16; | |
| 1663 | ||
| 1664 | case 0x114: | |
| 1665 | verboselog(space.machine(), 5, "mc68328_r (%04x): CSA1(0) = %04x\n", mem_mask, mc68328->regs.csa1 & 0x0000ffff); | |
| 1666 | return mc68328->regs.csa1 & 0x0000ffff; | |
| 1667 | ||
| 1668 | case 0x116: | |
| 1669 | verboselog(space.machine(), 5, "mc68328_r (%04x): CSA1(16) = %04x\n", mem_mask, mc68328->regs.csa1 >> 16); | |
| 1670 | return mc68328->regs.csa1 >> 16; | |
| 1671 | ||
| 1672 | case 0x118: | |
| 1673 | verboselog(space.machine(), 5, "mc68328_r (%04x): CSA2(0) = %04x\n", mem_mask, mc68328->regs.csa2 & 0x0000ffff); | |
| 1674 | return mc68328->regs.csa2 & 0x0000ffff; | |
| 1675 | ||
| 1676 | case 0x11a: | |
| 1677 | verboselog(space.machine(), 5, "mc68328_r (%04x): CSA2(16) = %04x\n", mem_mask, mc68328->regs.csa2 >> 16); | |
| 1678 | return mc68328->regs.csa2 >> 16; | |
| 1679 | ||
| 1680 | case 0x11c: | |
| 1681 | verboselog(space.machine(), 5, "mc68328_r (%04x): CSA3(0) = %04x\n", mem_mask, mc68328->regs.csa3 & 0x0000ffff); | |
| 1682 | return mc68328->regs.csa3 & 0x0000ffff; | |
| 1683 | ||
| 1684 | case 0x11e: | |
| 1685 | verboselog(space.machine(), 5, "mc68328_r (%04x): CSA3(16) = %04x\n", mem_mask, mc68328->regs.csa3 >> 16); | |
| 1686 | return mc68328->regs.csa3 >> 16; | |
| 1687 | ||
| 1688 | case 0x120: | |
| 1689 | verboselog(space.machine(), 5, "mc68328_r (%04x): CSB0(0) = %04x\n", mem_mask, mc68328->regs.csb0 & 0x0000ffff); | |
| 1690 | return mc68328->regs.csb0 & 0x0000ffff; | |
| 1691 | ||
| 1692 | case 0x122: | |
| 1693 | verboselog(space.machine(), 5, "mc68328_r (%04x): CSB0(16) = %04x\n", mem_mask, mc68328->regs.csb0 >> 16); | |
| 1694 | return mc68328->regs.csb0 >> 16; | |
| 1695 | ||
| 1696 | case 0x124: | |
| 1697 | verboselog(space.machine(), 5, "mc68328_r (%04x): CSB1(0) = %04x\n", mem_mask, mc68328->regs.csb1 & 0x0000ffff); | |
| 1698 | return mc68328->regs.csb1 & 0x0000ffff; | |
| 1699 | ||
| 1700 | case 0x126: | |
| 1701 | verboselog(space.machine(), 5, "mc68328_r (%04x): CSB1(16) = %04x\n", mem_mask, mc68328->regs.csb1 >> 16); | |
| 1702 | return mc68328->regs.csb1 >> 16; | |
| 1703 | ||
| 1704 | case 0x128: | |
| 1705 | verboselog(space.machine(), 5, "mc68328_r (%04x): CSB2(0) = %04x\n", mem_mask, mc68328->regs.csb2 & 0x0000ffff); | |
| 1706 | return mc68328->regs.csb2 & 0x0000ffff; | |
| 1707 | ||
| 1708 | case 0x12a: | |
| 1709 | verboselog(space.machine(), 5, "mc68328_r (%04x): CSB2(16) = %04x\n", mem_mask, mc68328->regs.csb2 >> 16); | |
| 1710 | return mc68328->regs.csb2 >> 16; | |
| 1711 | ||
| 1712 | case 0x12c: | |
| 1713 | verboselog(space.machine(), 5, "mc68328_r (%04x): CSB3(0) = %04x\n", mem_mask, mc68328->regs.csb3 & 0x0000ffff); | |
| 1714 | return mc68328->regs.csb3 & 0x0000ffff; | |
| 1715 | ||
| 1716 | case 0x12e: | |
| 1717 | verboselog(space.machine(), 5, "mc68328_r (%04x): CSB3(16) = %04x\n", mem_mask, mc68328->regs.csb3 >> 16); | |
| 1718 | return mc68328->regs.csb3 >> 16; | |
| 1719 | ||
| 1720 | case 0x130: | |
| 1721 | verboselog(space.machine(), 5, "mc68328_r (%04x): CSC0(0) = %04x\n", mem_mask, mc68328->regs.csc0 & 0x0000ffff); | |
| 1722 | return mc68328->regs.csc0 & 0x0000ffff; | |
| 1723 | ||
| 1724 | case 0x132: | |
| 1725 | verboselog(space.machine(), 5, "mc68328_r (%04x): CSC0(16) = %04x\n", mem_mask, mc68328->regs.csc0 >> 16); | |
| 1726 | return mc68328->regs.csc0 >> 16; | |
| 1727 | ||
| 1728 | case 0x134: | |
| 1729 | verboselog(space.machine(), 5, "mc68328_r (%04x): CSC1(0) = %04x\n", mem_mask, mc68328->regs.csc1 & 0x0000ffff); | |
| 1730 | return mc68328->regs.csc1 & 0x0000ffff; | |
| 1731 | ||
| 1732 | case 0x136: | |
| 1733 | verboselog(space.machine(), 5, "mc68328_r (%04x): CSC1(16) = %04x\n", mem_mask, mc68328->regs.csc1 >> 16); | |
| 1734 | return mc68328->regs.csc1 >> 16; | |
| 1735 | ||
| 1736 | case 0x138: | |
| 1737 | verboselog(space.machine(), 5, "mc68328_r (%04x): CSC2(0) = %04x\n", mem_mask, mc68328->regs.csc2 & 0x0000ffff); | |
| 1738 | return mc68328->regs.csc2 & 0x0000ffff; | |
| 1739 | ||
| 1740 | case 0x13a: | |
| 1741 | verboselog(space.machine(), 5, "mc68328_r (%04x): CSC2(16) = %04x\n", mem_mask, mc68328->regs.csc2 >> 16); | |
| 1742 | return mc68328->regs.csc2 >> 16; | |
| 1743 | ||
| 1744 | case 0x13c: | |
| 1745 | verboselog(space.machine(), 5, "mc68328_r (%04x): CSC3(0) = %04x\n", mem_mask, mc68328->regs.csc3 & 0x0000ffff); | |
| 1746 | return mc68328->regs.csc3 & 0x0000ffff; | |
| 1747 | ||
| 1748 | case 0x13e: | |
| 1749 | verboselog(space.machine(), 5, "mc68328_r (%04x): CSC3(16) = %04x\n", mem_mask, mc68328->regs.csc3 >> 16); | |
| 1750 | return mc68328->regs.csc3 >> 16; | |
| 1751 | ||
| 1752 | case 0x140: | |
| 1753 | verboselog(space.machine(), 5, "mc68328_r (%04x): CSD0(0) = %04x\n", mem_mask, mc68328->regs.csd0 & 0x0000ffff); | |
| 1754 | return mc68328->regs.csd0 & 0x0000ffff; | |
| 1755 | ||
| 1756 | case 0x142: | |
| 1757 | verboselog(space.machine(), 5, "mc68328_r (%04x): CSD0(16) = %04x\n", mem_mask, mc68328->regs.csd0 >> 16); | |
| 1758 | return mc68328->regs.csd0 >> 16; | |
| 1759 | ||
| 1760 | case 0x144: | |
| 1761 | verboselog(space.machine(), 5, "mc68328_r (%04x): CSD1(0) = %04x\n", mem_mask, mc68328->regs.csd1 & 0x0000ffff); | |
| 1762 | return mc68328->regs.csd1 & 0x0000ffff; | |
| 1763 | ||
| 1764 | case 0x146: | |
| 1765 | verboselog(space.machine(), 5, "mc68328_r (%04x): CSD1(16) = %04x\n", mem_mask, mc68328->regs.csd1 >> 16); | |
| 1766 | return mc68328->regs.csd1 >> 16; | |
| 1767 | ||
| 1768 | case 0x148: | |
| 1769 | verboselog(space.machine(), 5, "mc68328_r (%04x): CSD2(0) = %04x\n", mem_mask, mc68328->regs.csd2 & 0x0000ffff); | |
| 1770 | return mc68328->regs.csd2 & 0x0000ffff; | |
| 1771 | ||
| 1772 | case 0x14a: | |
| 1773 | verboselog(space.machine(), 5, "mc68328_r (%04x): CSD2(16) = %04x\n", mem_mask, mc68328->regs.csd2 >> 16); | |
| 1774 | return mc68328->regs.csd2 >> 16; | |
| 1775 | ||
| 1776 | case 0x14c: | |
| 1777 | verboselog(space.machine(), 5, "mc68328_r (%04x): CSD3(0) = %04x\n", mem_mask, mc68328->regs.csd3 & 0x0000ffff); | |
| 1778 | return mc68328->regs.csd3 & 0x0000ffff; | |
| 1779 | ||
| 1780 | case 0x14e: | |
| 1781 | verboselog(space.machine(), 5, "mc68328_r (%04x): CSD3(16) = %04x\n", mem_mask, mc68328->regs.csd3 >> 16); | |
| 1782 | return mc68328->regs.csd3 >> 16; | |
| 1783 | ||
| 1784 | case 0x200: | |
| 1785 | verboselog(space.machine(), 2, "mc68328_r (%04x): PLLCR = %04x\n", mem_mask, mc68328->regs.pllcr); | |
| 1786 | return mc68328->regs.pllcr; | |
| 1787 | ||
| 1788 | case 0x202: | |
| 1789 | verboselog(space.machine(), 2, "mc68328_r (%04x): PLLFSR = %04x\n", mem_mask, mc68328->regs.pllfsr); | |
| 1790 | mc68328->regs.pllfsr ^= 0x8000; | |
| 1791 | return mc68328->regs.pllfsr; | |
| 1792 | ||
| 1793 | case 0x206: | |
| 1794 | if( mem_mask & 0x00ff ) | |
| 1795 | { | |
| 1796 | verboselog(space.machine(), 2, "mc68328_r (%04x): Unknown address (0xfff206)\n", mem_mask); | |
| 1797 | } | |
| 1798 | else | |
| 1799 | { | |
| 1800 | verboselog(space.machine(), 2, "mc68328_r (%04x): PCTLR = %02x\n", mem_mask, mc68328->regs.pctlr); | |
| 1801 | return mc68328->regs.pctlr << 8; | |
| 1802 | } | |
| 1803 | break; | |
| 1804 | ||
| 1805 | case 0x300: | |
| 1806 | if( mem_mask & 0x00ff ) | |
| 1807 | { | |
| 1808 | verboselog(space.machine(), 2, "mc68328_r (%04x): Unknown address (0xfff301)\n", mem_mask); | |
| 1809 | } | |
| 1810 | else | |
| 1811 | { | |
| 1812 | verboselog(space.machine(), 2, "mc68328_r (%04x): IVR = %02x\n", mem_mask, mc68328->regs.ivr); | |
| 1813 | return mc68328->regs.ivr << 8; | |
| 1814 | } | |
| 1815 | break; | |
| 1816 | ||
| 1817 | case 0x302: | |
| 1818 | verboselog(space.machine(), 2, "mc68328_r (%04x): ICR = %04x\n", mem_mask, mc68328->regs.icr); | |
| 1819 | return mc68328->regs.icr; | |
| 1820 | ||
| 1821 | case 0x304: | |
| 1822 | verboselog(space.machine(), 2, "mc68328_r (%04x): IMR(16) = %04x\n", mem_mask, mc68328->regs.imr >> 16); | |
| 1823 | return mc68328->regs.imr >> 16; | |
| 1824 | ||
| 1825 | case 0x306: | |
| 1826 | verboselog(space.machine(), 2, "mc68328_r (%04x): IMR(0) = %04x\n", mem_mask, mc68328->regs.imr & 0x0000ffff); | |
| 1827 | return mc68328->regs.imr & 0x0000ffff; | |
| 1828 | ||
| 1829 | case 0x308: | |
| 1830 | verboselog(space.machine(), 2, "mc68328_r (%04x): IWR(16) = %04x\n", mem_mask, mc68328->regs.iwr >> 16); | |
| 1831 | return mc68328->regs.iwr >> 16; | |
| 1832 | ||
| 1833 | case 0x30a: | |
| 1834 | verboselog(space.machine(), 2, "mc68328_r (%04x): IWR(0) = %04x\n", mem_mask, mc68328->regs.iwr & 0x0000ffff); | |
| 1835 | return mc68328->regs.iwr & 0x0000ffff; | |
| 1836 | ||
| 1837 | case 0x30c: | |
| 1838 | verboselog(space.machine(), 2, "mc68328_r (%04x): ISR(16) = %04x\n", mem_mask, mc68328->regs.isr >> 16); | |
| 1839 | return mc68328->regs.isr >> 16; | |
| 1840 | ||
| 1841 | case 0x30e: | |
| 1842 | verboselog(space.machine(), 2, "mc68328_r (%04x): ISR(0) = %04x\n", mem_mask, mc68328->regs.isr & 0x0000ffff); | |
| 1843 | return mc68328->regs.isr & 0x0000ffff; | |
| 1844 | ||
| 1845 | case 0x310: | |
| 1846 | verboselog(space.machine(), 2, "mc68328_r (%04x): IPR(16) = %04x\n", mem_mask, mc68328->regs.ipr >> 16); | |
| 1847 | return mc68328->regs.ipr >> 16; | |
| 1848 | ||
| 1849 | case 0x312: | |
| 1850 | verboselog(space.machine(), 2, "mc68328_r (%04x): IPR(0) = %04x\n", mem_mask, mc68328->regs.ipr & 0x0000ffff); | |
| 1851 | return mc68328->regs.ipr & 0x0000ffff; | |
| 1852 | ||
| 1853 | case 0x400: | |
| 1854 | if( mem_mask & 0x00ff ) | |
| 1855 | { | |
| 1856 | verboselog(space.machine(), 2, "mc68328_r (%04x): PADATA = %02x\n", mem_mask, mc68328->regs.padata); | |
| 1857 | if(!mc68328->in_port_a.isnull()) | |
| 1858 | { | |
| 1859 | return mc68328->in_port_a( 0 ); | |
| 1860 | } | |
| 1861 | else | |
| 1862 | { | |
| 1863 | return mc68328->regs.padata; | |
| 1864 | } | |
| 1865 | } | |
| 1866 | else | |
| 1867 | { | |
| 1868 | verboselog(space.machine(), 2, "mc68328_r (%04x): PADIR = %02x\n", mem_mask, mc68328->regs.padir); | |
| 1869 | return mc68328->regs.padir << 8; | |
| 1870 | } | |
| 1871 | break; | |
| 1872 | ||
| 1873 | case 0x402: | |
| 1874 | if( mem_mask & 0x00ff ) | |
| 1875 | { | |
| 1876 | verboselog(space.machine(), 2, "mc68328_r (%04x): PASEL = %02x\n", mem_mask, mc68328->regs.pasel); | |
| 1877 | return mc68328->regs.pasel; | |
| 1878 | } | |
| 1879 | else | |
| 1880 | { | |
| 1881 | verboselog(space.machine(), 2, "mc68328_r (%04x): Unknown address (0xfff402)\n", mem_mask); | |
| 1882 | } | |
| 1883 | break; | |
| 1884 | ||
| 1885 | case 0x408: | |
| 1886 | if( mem_mask & 0x00ff ) | |
| 1887 | { | |
| 1888 | verboselog(space.machine(), 2, "mc68328_r (%04x): PBDATA = %02x\n", mem_mask, mc68328->regs.pbdata); | |
| 1889 | if(!mc68328->in_port_b.isnull()) | |
| 1890 | { | |
| 1891 | return mc68328->in_port_b( 0 ); | |
| 1892 | } | |
| 1893 | else | |
| 1894 | { | |
| 1895 | return mc68328->regs.pbdata; | |
| 1896 | } | |
| 1897 | } | |
| 1898 | else | |
| 1899 | { | |
| 1900 | verboselog(space.machine(), 2, "mc68328_r (%04x): PBDIR = %02x\n", mem_mask, mc68328->regs.pbdir); | |
| 1901 | return mc68328->regs.pbdir << 8; | |
| 1902 | } | |
| 1903 | break; | |
| 1904 | ||
| 1905 | case 0x40a: | |
| 1906 | if( mem_mask & 0x00ff ) | |
| 1907 | { | |
| 1908 | verboselog(space.machine(), 2, "mc68328_r (%04x): PBSEL = %02x\n", mem_mask, mc68328->regs.pbsel); | |
| 1909 | return mc68328->regs.pbsel; | |
| 1910 | } | |
| 1911 | else | |
| 1912 | { | |
| 1913 | verboselog(space.machine(), 2, "mc68328_r (%04x): Unknown address (0xfff40a)\n", mem_mask); | |
| 1914 | } | |
| 1915 | break; | |
| 1916 | ||
| 1917 | case 0x410: | |
| 1918 | if( mem_mask & 0x00ff ) | |
| 1919 | { | |
| 1920 | verboselog(space.machine(), 2, "mc68328_r (%04x): PCDATA = %02x\n", mem_mask, mc68328->regs.pcdata); | |
| 1921 | if(!mc68328->in_port_c.isnull()) | |
| 1922 | { | |
| 1923 | return mc68328->in_port_c( 0 ); | |
| 1924 | } | |
| 1925 | else | |
| 1926 | { | |
| 1927 | return mc68328->regs.pcdata; | |
| 1928 | } | |
| 1929 | } | |
| 1930 | else | |
| 1931 | { | |
| 1932 | verboselog(space.machine(), 2, "mc68328_r (%04x): PCDIR = %02x\n", mem_mask, mc68328->regs.pcdir); | |
| 1933 | return mc68328->regs.pcdir << 8; | |
| 1934 | } | |
| 1935 | break; | |
| 1936 | ||
| 1937 | case 0x412: | |
| 1938 | if( mem_mask & 0x00ff ) | |
| 1939 | { | |
| 1940 | verboselog(space.machine(), 2, "mc68328_r (%04x): PCSEL = %02x\n", mem_mask, mc68328->regs.pcsel); | |
| 1941 | return mc68328->regs.pcsel; | |
| 1942 | } | |
| 1943 | else | |
| 1944 | { | |
| 1945 | verboselog(space.machine(), 2, "mc68328_r (%04x): Unknown address (0xfff412)\n", mem_mask); | |
| 1946 | } | |
| 1947 | break; | |
| 1948 | ||
| 1949 | case 0x418: | |
| 1950 | if( mem_mask & 0x00ff ) | |
| 1951 | { | |
| 1952 | verboselog(space.machine(), 2, "mc68328_r (%04x): PDDATA = %02x\n", mem_mask, mc68328->regs.pddata); | |
| 1953 | if(!mc68328->in_port_d.isnull()) | |
| 1954 | { | |
| 1955 | return mc68328->in_port_d( 0 ); | |
| 1956 | } | |
| 1957 | else | |
| 1958 | { | |
| 1959 | return mc68328->regs.pddata; | |
| 1960 | } | |
| 1961 | } | |
| 1962 | else | |
| 1963 | { | |
| 1964 | verboselog(space.machine(), 2, "mc68328_r (%04x): PDDIR = %02x\n", mem_mask, mc68328->regs.pddir); | |
| 1965 | return mc68328->regs.pddir << 8; | |
| 1966 | } | |
| 1967 | break; | |
| 1968 | ||
| 1969 | case 0x41a: | |
| 1970 | if( mem_mask & 0x00ff ) | |
| 1971 | { | |
| 1972 | verboselog(space.machine(), 2, "mc68328_r (%04x): Unknown address (0xfff41b)\n", mem_mask); | |
| 1973 | } | |
| 1974 | else | |
| 1975 | { | |
| 1976 | verboselog(space.machine(), 2, "mc68328_r (%04x): PDPUEN = %02x\n", mem_mask, mc68328->regs.pdpuen); | |
| 1977 | return mc68328->regs.pdpuen << 8; | |
| 1978 | } | |
| 1979 | break; | |
| 1980 | ||
| 1981 | case 0x41c: | |
| 1982 | if( mem_mask & 0x00ff ) | |
| 1983 | { | |
| 1984 | verboselog(space.machine(), 2, "mc68328_r (%04x): PDIRQEN = %02x\n", mem_mask, mc68328->regs.pdirqen); | |
| 1985 | return mc68328->regs.pdirqen; | |
| 1986 | } | |
| 1987 | else | |
| 1988 | { | |
| 1989 | verboselog(space.machine(), 2, "mc68328_r (%04x): PDPOL = %02x\n", mem_mask, mc68328->regs.pdpol); | |
| 1990 | return mc68328->regs.pdpol << 8; | |
| 1991 | } | |
| 1992 | break; | |
| 1993 | ||
| 1994 | case 0x41e: | |
| 1995 | if( mem_mask & 0x00ff ) | |
| 1996 | { | |
| 1997 | verboselog(space.machine(), 2, "mc68328_r (%04x): PDIRQEDGE = %02x\n", mem_mask, mc68328->regs.pdirqedge); | |
| 1998 | return mc68328->regs.pdirqedge; | |
| 1999 | } | |
| 2000 | else | |
| 2001 | { | |
| 2002 | verboselog(space.machine(), 2, "mc68328_r (%04x): Unknown address (0xfff41e)\n", mem_mask); | |
| 2003 | } | |
| 2004 | break; | |
| 2005 | ||
| 2006 | case 0x420: | |
| 2007 | if( mem_mask & 0x00ff ) | |
| 2008 | { | |
| 2009 | verboselog(space.machine(), 2, "mc68328_r (%04x): PEDATA = %02x\n", mem_mask, mc68328->regs.pedata); | |
| 2010 | if(!mc68328->in_port_e.isnull()) | |
| 2011 | { | |
| 2012 | return mc68328->in_port_e( 0 ); | |
| 2013 | } | |
| 2014 | else | |
| 2015 | { | |
| 2016 | return mc68328->regs.pedata; | |
| 2017 | } | |
| 2018 | } | |
| 2019 | else | |
| 2020 | { | |
| 2021 | verboselog(space.machine(), 2, "mc68328_r (%04x): PEDIR = %02x\n", mem_mask, mc68328->regs.pedir); | |
| 2022 | return mc68328->regs.pedir << 8; | |
| 2023 | } | |
| 2024 | break; | |
| 2025 | ||
| 2026 | case 0x422: | |
| 2027 | if( mem_mask & 0x00ff ) | |
| 2028 | { | |
| 2029 | verboselog(space.machine(), 2, "mc68328_r (%04x): PESEL = %02x\n", mem_mask, mc68328->regs.pesel); | |
| 2030 | return mc68328->regs.pesel; | |
| 2031 | } | |
| 2032 | else | |
| 2033 | { | |
| 2034 | verboselog(space.machine(), 2, "mc68328_r (%04x): PEPUEN = %02x\n", mem_mask, mc68328->regs.pepuen); | |
| 2035 | return mc68328->regs.pepuen << 8; | |
| 2036 | } | |
| 2037 | break; | |
| 2038 | ||
| 2039 | case 0x428: | |
| 2040 | if( mem_mask & 0x00ff ) | |
| 2041 | { | |
| 2042 | verboselog(space.machine(), 2, "mc68328_r (%04x): PFDATA = %02x\n", mem_mask, mc68328->regs.pfdata); | |
| 2043 | if(!mc68328->in_port_f.isnull()) | |
| 2044 | { | |
| 2045 | return mc68328->in_port_f( 0 ); | |
| 2046 | } | |
| 2047 | else | |
| 2048 | { | |
| 2049 | return mc68328->regs.pfdata; | |
| 2050 | } | |
| 2051 | } | |
| 2052 | else | |
| 2053 | { | |
| 2054 | verboselog(space.machine(), 2, "mc68328_r (%04x): PFDIR = %02x\n", mem_mask, mc68328->regs.pfdir); | |
| 2055 | return mc68328->regs.pfdir << 8; | |
| 2056 | } | |
| 2057 | break; | |
| 2058 | ||
| 2059 | case 0x42a: | |
| 2060 | if( mem_mask & 0x00ff ) | |
| 2061 | { | |
| 2062 | verboselog(space.machine(), 2, "mc68328_r (%04x): PFSEL = %02x\n", mem_mask, mc68328->regs.pfsel); | |
| 2063 | return mc68328->regs.pfsel; | |
| 2064 | } | |
| 2065 | else | |
| 2066 | { | |
| 2067 | verboselog(space.machine(), 2, "mc68328_r (%04x): PFPUEN = %02x\n", mem_mask, mc68328->regs.pfpuen); | |
| 2068 | return mc68328->regs.pfpuen << 8; | |
| 2069 | } | |
| 2070 | break; | |
| 2071 | ||
| 2072 | case 0x430: | |
| 2073 | if( mem_mask & 0x00ff ) | |
| 2074 | { | |
| 2075 | verboselog(space.machine(), 2, "mc68328_r (%04x): PGDATA = %02x\n", mem_mask, mc68328->regs.pgdata); | |
| 2076 | if(!mc68328->in_port_g.isnull()) | |
| 2077 | { | |
| 2078 | return mc68328->in_port_g( 0 ); | |
| 2079 | } | |
| 2080 | else | |
| 2081 | { | |
| 2082 | return mc68328->regs.pgdata; | |
| 2083 | } | |
| 2084 | } | |
| 2085 | else | |
| 2086 | { | |
| 2087 | verboselog(space.machine(), 2, "mc68328_r (%04x): PGDIR = %02x\n", mem_mask, mc68328->regs.pgdir); | |
| 2088 | return mc68328->regs.pgdir << 8; | |
| 2089 | } | |
| 2090 | break; | |
| 2091 | ||
| 2092 | case 0x432: | |
| 2093 | if( mem_mask & 0x00ff ) | |
| 2094 | { | |
| 2095 | verboselog(space.machine(), 2, "mc68328_r (%04x): PGSEL = %02x\n", mem_mask, mc68328->regs.pgsel); | |
| 2096 | return mc68328->regs.pgsel; | |
| 2097 | } | |
| 2098 | else | |
| 2099 | { | |
| 2100 | verboselog(space.machine(), 2, "mc68328_r (%04x): PGPUEN = %02x\n", mem_mask, mc68328->regs.pgpuen); | |
| 2101 | return mc68328->regs.pgpuen << 8; | |
| 2102 | } | |
| 2103 | break; | |
| 2104 | ||
| 2105 | case 0x438: | |
| 2106 | if( mem_mask & 0x00ff ) | |
| 2107 | { | |
| 2108 | verboselog(space.machine(), 2, "mc68328_r (%04x): PJDATA = %02x\n", mem_mask, mc68328->regs.pjdata); | |
| 2109 | if(!mc68328->in_port_j.isnull()) | |
| 2110 | { | |
| 2111 | return mc68328->in_port_j( 0 ); | |
| 2112 | } | |
| 2113 | else | |
| 2114 | { | |
| 2115 | return mc68328->regs.pjdata; | |
| 2116 | } | |
| 2117 | } | |
| 2118 | else | |
| 2119 | { | |
| 2120 | verboselog(space.machine(), 2, "mc68328_r (%04x): PJDIR = %02x\n", mem_mask, mc68328->regs.pjdir); | |
| 2121 | return mc68328->regs.pjdir << 8; | |
| 2122 | } | |
| 2123 | break; | |
| 2124 | ||
| 2125 | case 0x43a: | |
| 2126 | if( mem_mask & 0x00ff ) | |
| 2127 | { | |
| 2128 | verboselog(space.machine(), 2, "mc68328_r (%04x): PJSEL = %02x\n", mem_mask, mc68328->regs.pjsel); | |
| 2129 | return mc68328->regs.pjsel; | |
| 2130 | } | |
| 2131 | else | |
| 2132 | { | |
| 2133 | verboselog(space.machine(), 2, "mc68328_r (%04x): Unknown address (0xfff43a)\n", mem_mask); | |
| 2134 | } | |
| 2135 | break; | |
| 2136 | ||
| 2137 | case 0x440: | |
| 2138 | if( mem_mask & 0x00ff ) | |
| 2139 | { | |
| 2140 | verboselog(space.machine(), 2, "mc68328_r (%04x): PKDATA = %02x\n", mem_mask, mc68328->regs.pkdata); | |
| 2141 | if(!mc68328->in_port_k.isnull()) | |
| 2142 | { | |
| 2143 | return mc68328->in_port_k( 0 ); | |
| 2144 | } | |
| 2145 | else | |
| 2146 | { | |
| 2147 | return mc68328->regs.pkdata; | |
| 2148 | } | |
| 2149 | } | |
| 2150 | else | |
| 2151 | { | |
| 2152 | verboselog(space.machine(), 2, "mc68328_r (%04x): PKDIR = %02x\n", mem_mask, mc68328->regs.pkdir); | |
| 2153 | return mc68328->regs.pkdir << 8; | |
| 2154 | } | |
| 2155 | break; | |
| 2156 | ||
| 2157 | case 0x442: | |
| 2158 | if( mem_mask & 0x00ff ) | |
| 2159 | { | |
| 2160 | verboselog(space.machine(), 2, "mc68328_r (%04x): PKSEL = %02x\n", mem_mask, mc68328->regs.pksel); | |
| 2161 | return mc68328->regs.pksel; | |
| 2162 | } | |
| 2163 | else | |
| 2164 | { | |
| 2165 | verboselog(space.machine(), 2, "mc68328_r (%04x): PKPUEN = %02x\n", mem_mask, mc68328->regs.pkpuen); | |
| 2166 | return mc68328->regs.pkpuen << 8; | |
| 2167 | } | |
| 2168 | break; | |
| 2169 | ||
| 2170 | case 0x448: | |
| 2171 | if( mem_mask & 0x00ff ) | |
| 2172 | { | |
| 2173 | verboselog(space.machine(), 2, "mc68328_r (%04x): PMDATA = %02x\n", mem_mask, mc68328->regs.pmdata); | |
| 2174 | if(!mc68328->in_port_m.isnull()) | |
| 2175 | { | |
| 2176 | return mc68328->in_port_m( 0 ); | |
| 2177 | } | |
| 2178 | else | |
| 2179 | { | |
| 2180 | return mc68328->regs.pmdata; | |
| 2181 | } | |
| 2182 | } | |
| 2183 | else | |
| 2184 | { | |
| 2185 | verboselog(space.machine(), 2, "mc68328_r (%04x): PMDIR = %02x\n", mem_mask, mc68328->regs.pmdir); | |
| 2186 | return mc68328->regs.pmdir << 8; | |
| 2187 | } | |
| 2188 | break; | |
| 2189 | ||
| 2190 | case 0x44a: | |
| 2191 | if( mem_mask & 0x00ff ) | |
| 2192 | { | |
| 2193 | verboselog(space.machine(), 2, "mc68328_r (%04x): PMSEL = %02x\n", mem_mask, mc68328->regs.pmsel); | |
| 2194 | return mc68328->regs.pmsel; | |
| 2195 | } | |
| 2196 | else | |
| 2197 | { | |
| 2198 | verboselog(space.machine(), 2, "mc68328_r (%04x): PMPUEN = %02x\n", mem_mask, mc68328->regs.pmpuen); | |
| 2199 | return mc68328->regs.pmpuen << 8; | |
| 2200 | } | |
| 2201 | break; | |
| 2202 | ||
| 2203 | case 0x500: | |
| 2204 | verboselog(space.machine(), 2, "mc68328_r (%04x): PWMC = %04x\n", mem_mask, mc68328->regs.pwmc); | |
| 2205 | temp16 = mc68328->regs.pwmc; | |
| 2206 | if(mc68328->regs.pwmc & PWMC_PWMIRQ) | |
| 2207 | { | |
| 2208 | mc68328->regs.pwmc &= ~PWMC_PWMIRQ; | |
| 2209 | mc68328_set_interrupt_line(device, INT_PWM, 0); | |
| 2210 | } | |
| 2211 | return temp16; | |
| 2212 | ||
| 2213 | case 0x502: | |
| 2214 | verboselog(space.machine(), 2, "mc68328_r (%04x): PWMP = %04x\n", mem_mask, mc68328->regs.pwmp); | |
| 2215 | return mc68328->regs.pwmp; | |
| 2216 | ||
| 2217 | case 0x504: | |
| 2218 | verboselog(space.machine(), 2, "mc68328_r (%04x): PWMW = %04x\n", mem_mask, mc68328->regs.pwmw); | |
| 2219 | return mc68328->regs.pwmw; | |
| 2220 | ||
| 2221 | case 0x506: | |
| 2222 | verboselog(space.machine(), 2, "mc68328_r (%04x): PWMCNT = %04x\n", mem_mask, mc68328->regs.pwmcnt); | |
| 2223 | return mc68328->regs.pwmcnt; | |
| 2224 | ||
| 2225 | case 0x600: | |
| 2226 | verboselog(space.machine(), 2, "mc68328_r (%04x): TCTL1 = %04x\n", mem_mask, mc68328->regs.tctl[0]); | |
| 2227 | return mc68328->regs.tctl[0]; | |
| 2228 | ||
| 2229 | case 0x602: | |
| 2230 | verboselog(space.machine(), 2, "mc68328_r (%04x): TPRER1 = %04x\n", mem_mask, mc68328->regs.tprer[0]); | |
| 2231 | return mc68328->regs.tprer[0]; | |
| 2232 | ||
| 2233 | case 0x604: | |
| 2234 | verboselog(space.machine(), 2, "mc68328_r (%04x): TCMP1 = %04x\n", mem_mask, mc68328->regs.tcmp[0]); | |
| 2235 | return mc68328->regs.tcmp[0]; | |
| 2236 | ||
| 2237 | case 0x606: | |
| 2238 | verboselog(space.machine(), 2, "mc68328_r (%04x): TCR1 = %04x\n", mem_mask, mc68328->regs.tcr[0]); | |
| 2239 | return mc68328->regs.tcr[0]; | |
| 2240 | ||
| 2241 | case 0x608: | |
| 2242 | verboselog(space.machine(), 2, "mc68328_r (%04x): TCN1 = %04x\n", mem_mask, mc68328->regs.tcn[0]); | |
| 2243 | return mc68328->regs.tcn[0]; | |
| 2244 | ||
| 2245 | case 0x60a: | |
| 2246 | verboselog(space.machine(), 5, "mc68328_r (%04x): TSTAT1 = %04x\n", mem_mask, mc68328->regs.tstat[0]); | |
| 2247 | mc68328->regs.tclear[0] |= mc68328->regs.tstat[0]; | |
| 2248 | return mc68328->regs.tstat[0]; | |
| 2249 | ||
| 2250 | case 0x60c: | |
| 2251 | verboselog(space.machine(), 2, "mc68328_r (%04x): TCTL2 = %04x\n", mem_mask, mc68328->regs.tctl[1]); | |
| 2252 | return mc68328->regs.tctl[1]; | |
| 2253 | ||
| 2254 | case 0x60e: | |
| 2255 | verboselog(space.machine(), 2, "mc68328_r (%04x): TPREP2 = %04x\n", mem_mask, mc68328->regs.tprer[1]); | |
| 2256 | return mc68328->regs.tprer[1]; | |
| 2257 | ||
| 2258 | case 0x610: | |
| 2259 | verboselog(space.machine(), 2, "mc68328_r (%04x): TCMP2 = %04x\n", mem_mask, mc68328->regs.tcmp[1]); | |
| 2260 | return mc68328->regs.tcmp[1]; | |
| 2261 | ||
| 2262 | case 0x612: | |
| 2263 | verboselog(space.machine(), 2, "mc68328_r (%04x): TCR2 = %04x\n", mem_mask, mc68328->regs.tcr[1]); | |
| 2264 | return mc68328->regs.tcr[1]; | |
| 2265 | ||
| 2266 | case 0x614: | |
| 2267 | verboselog(space.machine(), 2, "mc68328_r (%04x): TCN2 = %04x\n", mem_mask, mc68328->regs.tcn[1]); | |
| 2268 | return mc68328->regs.tcn[1]; | |
| 2269 | ||
| 2270 | case 0x616: | |
| 2271 | verboselog(space.machine(), 2, "mc68328_r (%04x): TSTAT2 = %04x\n", mem_mask, mc68328->regs.tstat[1]); | |
| 2272 | mc68328->regs.tclear[1] |= mc68328->regs.tstat[1]; | |
| 2273 | return mc68328->regs.tstat[1]; | |
| 2274 | ||
| 2275 | case 0x618: | |
| 2276 | verboselog(space.machine(), 2, "mc68328_r (%04x): WCTLR = %04x\n", mem_mask, mc68328->regs.wctlr); | |
| 2277 | return mc68328->regs.wctlr; | |
| 2278 | ||
| 2279 | case 0x61a: | |
| 2280 | verboselog(space.machine(), 2, "mc68328_r (%04x): WCMPR = %04x\n", mem_mask, mc68328->regs.wcmpr); | |
| 2281 | return mc68328->regs.wcmpr; | |
| 2282 | ||
| 2283 | case 0x61c: | |
| 2284 | verboselog(space.machine(), 2, "mc68328_r (%04x): WCN = %04x\n", mem_mask, mc68328->regs.wcn); | |
| 2285 | return mc68328->regs.wcn; | |
| 2286 | ||
| 2287 | case 0x700: | |
| 2288 | verboselog(space.machine(), 2, "mc68328_r (%04x): SPISR = %04x\n", mem_mask, mc68328->regs.spisr); | |
| 2289 | return mc68328->regs.spisr; | |
| 2290 | ||
| 2291 | case 0x800: | |
| 2292 | verboselog(space.machine(), 2, "mc68328_r (%04x): SPIMDATA = %04x\n", mem_mask, mc68328->regs.spimdata); | |
| 2293 | if(!mc68328->in_spim.isnull()) | |
| 2294 | { | |
| 2295 | return mc68328->in_spim( 0, 0xffff ); | |
| 2296 | } | |
| 2297 | return mc68328->regs.spimdata; | |
| 2298 | ||
| 2299 | case 0x802: | |
| 2300 | verboselog(space.machine(), 2, "mc68328_r (%04x): SPIMCONT = %04x\n", mem_mask, mc68328->regs.spimcont); | |
| 2301 | if(mc68328->regs.spimcont & SPIM_XCH) | |
| 2302 | { | |
| 2303 | mc68328->regs.spimcont &= ~SPIM_XCH; | |
| 2304 | mc68328->regs.spimcont |= SPIM_SPIMIRQ; | |
| 2305 | return ((mc68328->regs.spimcont | SPIM_XCH) &~ SPIM_SPIMIRQ); | |
| 2306 | } | |
| 2307 | return mc68328->regs.spimcont; | |
| 2308 | ||
| 2309 | case 0x900: | |
| 2310 | verboselog(space.machine(), 2, "mc68328_r (%04x): USTCNT = %04x\n", mem_mask, mc68328->regs.ustcnt); | |
| 2311 | return mc68328->regs.ustcnt; | |
| 2312 | ||
| 2313 | case 0x902: | |
| 2314 | verboselog(space.machine(), 2, "mc68328_r (%04x): UBAUD = %04x\n", mem_mask, mc68328->regs.ubaud); | |
| 2315 | return mc68328->regs.ubaud; | |
| 2316 | ||
| 2317 | case 0x904: | |
| 2318 | verboselog(space.machine(), 5, "mc68328_r (%04x): URX = %04x\n", mem_mask, mc68328->regs.urx); | |
| 2319 | return mc68328->regs.urx; | |
| 2320 | ||
| 2321 | case 0x906: | |
| 2322 | verboselog(space.machine(), 5, "mc68328_r (%04x): UTX = %04x\n", mem_mask, mc68328->regs.utx); | |
| 2323 | return mc68328->regs.utx | UTX_FIFO_EMPTY | UTX_FIFO_HALF | UTX_TX_AVAIL; | |
| 2324 | ||
| 2325 | case 0x908: | |
| 2326 | verboselog(space.machine(), 2, "mc68328_r (%04x): UMISC = %04x\n", mem_mask, mc68328->regs.umisc); | |
| 2327 | return mc68328->regs.umisc; | |
| 2328 | ||
| 2329 | case 0xa00: | |
| 2330 | verboselog(space.machine(), 2, "mc68328_r (%04x): LSSA(16) = %04x\n", mem_mask, mc68328->regs.lssa >> 16); | |
| 2331 | return mc68328->regs.lssa >> 16; | |
| 2332 | ||
| 2333 | case 0xa02: | |
| 2334 | verboselog(space.machine(), 2, "mc68328_r (%04x): LSSA(0) = %04x\n", mem_mask, mc68328->regs.lssa & 0x0000ffff); | |
| 2335 | return mc68328->regs.lssa & 0x0000ffff; | |
| 2336 | ||
| 2337 | case 0xa04: | |
| 2338 | if( mem_mask & 0x00ff ) | |
| 2339 | { | |
| 2340 | verboselog(space.machine(), 2, "mc68328_r (%04x): LVPW = %02x\n", mem_mask, mc68328->regs.lvpw); | |
| 2341 | return mc68328->regs.lvpw; | |
| 2342 | } | |
| 2343 | else | |
| 2344 | { | |
| 2345 | verboselog(space.machine(), 2, "mc68328_r (%04x): Unknown address (0xfffa04)\n", mem_mask); | |
| 2346 | } | |
| 2347 | break; | |
| 2348 | ||
| 2349 | case 0xa08: | |
| 2350 | verboselog(space.machine(), 2, "mc68328_r (%04x): LXMAX = %04x\n", mem_mask, mc68328->regs.lxmax); | |
| 2351 | return mc68328->regs.lxmax; | |
| 2352 | ||
| 2353 | case 0xa0a: | |
| 2354 | verboselog(space.machine(), 2, "mc68328_r (%04x): LYMAX = %04x\n", mem_mask, mc68328->regs.lymax); | |
| 2355 | return mc68328->regs.lymax; | |
| 2356 | ||
| 2357 | case 0xa18: | |
| 2358 | verboselog(space.machine(), 2, "mc68328_r (%04x): LCXP = %04x\n", mem_mask, mc68328->regs.lcxp); | |
| 2359 | return mc68328->regs.lcxp; | |
| 2360 | ||
| 2361 | case 0xa1a: | |
| 2362 | verboselog(space.machine(), 2, "mc68328_r (%04x): LCYP = %04x\n", mem_mask, mc68328->regs.lcyp); | |
| 2363 | return mc68328->regs.lcyp; | |
| 2364 | ||
| 2365 | case 0xa1c: | |
| 2366 | verboselog(space.machine(), 2, "mc68328_r (%04x): LCWCH = %04x\n", mem_mask, mc68328->regs.lcwch); | |
| 2367 | return mc68328->regs.lcwch; | |
| 2368 | ||
| 2369 | case 0xa1e: | |
| 2370 | if( mem_mask & 0x00ff ) | |
| 2371 | { | |
| 2372 | verboselog(space.machine(), 2, "mc68328_r (%04x): LBLKC = %02x\n", mem_mask, mc68328->regs.lblkc); | |
| 2373 | return mc68328->regs.lblkc; | |
| 2374 | } | |
| 2375 | else | |
| 2376 | { | |
| 2377 | verboselog(space.machine(), 2, "mc68328_r (%04x): Unknown address (0xfffa1e)\n", mem_mask); | |
| 2378 | } | |
| 2379 | break; | |
| 2380 | ||
| 2381 | case 0xa20: | |
| 2382 | if( mem_mask & 0x00ff ) | |
| 2383 | { | |
| 2384 | verboselog(space.machine(), 2, "mc68328_r (%04x): LPOLCF = %02x\n", mem_mask, mc68328->regs.lpolcf); | |
| 2385 | return mc68328->regs.lpolcf; | |
| 2386 | } | |
| 2387 | else | |
| 2388 | { | |
| 2389 | verboselog(space.machine(), 2, "mc68328_r (%04x): LPICF = %02x\n", mem_mask, mc68328->regs.lpicf); | |
| 2390 | return mc68328->regs.lpicf << 8; | |
| 2391 | } | |
| 2392 | break; | |
| 2393 | ||
| 2394 | case 0xa22: | |
| 2395 | if( mem_mask & 0x00ff ) | |
| 2396 | { | |
| 2397 | verboselog(space.machine(), 2, "mc68328_r (%04x): LACDRC = %02x\n", mem_mask, mc68328->regs.lacdrc); | |
| 2398 | return mc68328->regs.lacdrc; | |
| 2399 | } | |
| 2400 | else | |
| 2401 | { | |
| 2402 | verboselog(space.machine(), 2, "mc68328_r (%04x): Unknown address (0xfffa22)\n", mem_mask); | |
| 2403 | } | |
| 2404 | break; | |
| 2405 | ||
| 2406 | case 0xa24: | |
| 2407 | if( mem_mask & 0x00ff ) | |
| 2408 | { | |
| 2409 | verboselog(space.machine(), 2, "mc68328_r (%04x): LPXCD = %02x\n", mem_mask, mc68328->regs.lpxcd); | |
| 2410 | return mc68328->regs.lpxcd; | |
| 2411 | } | |
| 2412 | else | |
| 2413 | { | |
| 2414 | verboselog(space.machine(), 2, "mc68328_r (%04x): Unknown address (0xfffa24)\n", mem_mask); | |
| 2415 | } | |
| 2416 | break; | |
| 2417 | ||
| 2418 | case 0xa26: | |
| 2419 | if( mem_mask & 0x00ff ) | |
| 2420 | { | |
| 2421 | verboselog(space.machine(), 2, "mc68328_r (%04x): LCKCON = %02x\n", mem_mask, mc68328->regs.lckcon); | |
| 2422 | return mc68328->regs.lckcon; | |
| 2423 | } | |
| 2424 | else | |
| 2425 | { | |
| 2426 | verboselog(space.machine(), 2, "mc68328_r (%04x): Unknown address (0xfffa26)\n", mem_mask); | |
| 2427 | } | |
| 2428 | break; | |
| 2429 | ||
| 2430 | case 0xa28: | |
| 2431 | if( mem_mask & 0x00ff ) | |
| 2432 | { | |
| 2433 | verboselog(space.machine(), 2, "mc68328_r (%04x): LLBAR = %02x\n", mem_mask, mc68328->regs.llbar); | |
| 2434 | return mc68328->regs.llbar; | |
| 2435 | } | |
| 2436 | else | |
| 2437 | { | |
| 2438 | verboselog(space.machine(), 2, "mc68328_r (%04x): Unknown address (0xfffa28)\n", mem_mask); | |
| 2439 | } | |
| 2440 | break; | |
| 2441 | ||
| 2442 | case 0xa2a: | |
| 2443 | if( mem_mask & 0x00ff ) | |
| 2444 | { | |
| 2445 | verboselog(space.machine(), 2, "mc68328_r (%04x): LOTCR = %02x\n", mem_mask, mc68328->regs.lotcr); | |
| 2446 | return mc68328->regs.lotcr; | |
| 2447 | } | |
| 2448 | else | |
| 2449 | { | |
| 2450 | verboselog(space.machine(), 2, "mc68328_r (%04x): Unknown address (0xfffa2a)\n", mem_mask); | |
| 2451 | } | |
| 2452 | break; | |
| 2453 | ||
| 2454 | case 0xa2c: | |
| 2455 | if( mem_mask & 0x00ff ) | |
| 2456 | { | |
| 2457 | verboselog(space.machine(), 2, "mc68328_r (%04x): LPOSR = %02x\n", mem_mask, mc68328->regs.lposr); | |
| 2458 | return mc68328->regs.lposr; | |
| 2459 | } | |
| 2460 | else | |
| 2461 | { | |
| 2462 | verboselog(space.machine(), 2, "mc68328_r (%04x): Unknown address (0xfffa2c)\n", mem_mask); | |
| 2463 | } | |
| 2464 | break; | |
| 2465 | ||
| 2466 | case 0xa30: | |
| 2467 | if( mem_mask & 0x00ff ) | |
| 2468 | { | |
| 2469 | verboselog(space.machine(), 2, "mc68328_r (%04x): LFRCM = %02x\n", mem_mask, mc68328->regs.lfrcm); | |
| 2470 | return mc68328->regs.lfrcm; | |
| 2471 | } | |
| 2472 | else | |
| 2473 | { | |
| 2474 | verboselog(space.machine(), 2, "mc68328_r (%04x): Unknown address (0xfffa30)\n", mem_mask); | |
| 2475 | } | |
| 2476 | break; | |
| 2477 | ||
| 2478 | case 0xa32: | |
| 2479 | verboselog(space.machine(), 2, "mc68328_r (%04x): LGPMR = %04x\n", mem_mask, mc68328->regs.lgpmr); | |
| 2480 | return mc68328->regs.lgpmr; | |
| 2481 | ||
| 2482 | case 0xb00: | |
| 2483 | verboselog(space.machine(), 2, "mc68328_r (%04x): HMSR(0) = %04x\n", mem_mask, mc68328->regs.hmsr & 0x0000ffff); | |
| 2484 | return mc68328->regs.hmsr & 0x0000ffff; | |
| 2485 | ||
| 2486 | case 0xb02: | |
| 2487 | verboselog(space.machine(), 2, "mc68328_r (%04x): HMSR(16) = %04x\n", mem_mask, mc68328->regs.hmsr >> 16); | |
| 2488 | return mc68328->regs.hmsr >> 16; | |
| 2489 | ||
| 2490 | case 0xb04: | |
| 2491 | verboselog(space.machine(), 2, "mc68328_r (%04x): ALARM(0) = %04x\n", mem_mask, mc68328->regs.alarm & 0x0000ffff); | |
| 2492 | return mc68328->regs.alarm & 0x0000ffff; | |
| 2493 | ||
| 2494 | case 0xb06: | |
| 2495 | verboselog(space.machine(), 2, "mc68328_r (%04x): ALARM(16) = %04x\n", mem_mask, mc68328->regs.alarm >> 16); | |
| 2496 | return mc68328->regs.alarm >> 16; | |
| 2497 | ||
| 2498 | case 0xb0c: | |
| 2499 | verboselog(space.machine(), 2, "mc68328_r (%04x): RTCCTL = %04x\n", mem_mask, mc68328->regs.rtcctl); | |
| 2500 | return mc68328->regs.rtcctl; | |
| 2501 | ||
| 2502 | case 0xb0e: | |
| 2503 | verboselog(space.machine(), 2, "mc68328_r (%04x): RTCISR = %04x\n", mem_mask, mc68328->regs.rtcisr); | |
| 2504 | return mc68328->regs.rtcisr; | |
| 2505 | ||
| 2506 | case 0xb10: | |
| 2507 | verboselog(space.machine(), 2, "mc68328_r (%04x): RTCIENR = %04x\n", mem_mask, mc68328->regs.rtcienr); | |
| 2508 | return mc68328->regs.rtcienr; | |
| 2509 | ||
| 2510 | case 0xb12: | |
| 2511 | verboselog(space.machine(), 2, "mc68328_r (%04x): STPWTCH = %04x\n", mem_mask, mc68328->regs.stpwtch); | |
| 2512 | return mc68328->regs.stpwtch; | |
| 2513 | ||
| 2514 | default: | |
| 2515 | verboselog(space.machine(), 0, "mc68328_r (%04x): Unknown address (0x%06x)\n", mem_mask, 0xfff000 + address); | |
| 2516 | break; | |
| 2517 | } | |
| 2518 | return 0; | |
| 2519 | } | |
| 2520 | ||
| 2521 | static DEVICE_RESET( mc68328 ) | |
| 2522 | { | |
| 2523 | mc68328_t* mc68328 = mc68328_get_safe_token( device ); | |
| 2524 | ||
| 2525 | mc68328->regs.scr = 0x0c; | |
| 2526 | mc68328->regs.grpbasea = 0x0000; | |
| 2527 | mc68328->regs.grpbaseb = 0x0000; | |
| 2528 | mc68328->regs.grpbasec = 0x0000; | |
| 2529 | mc68328->regs.grpbased = 0x0000; | |
| 2530 | mc68328->regs.grpmaska = 0x0000; | |
| 2531 | mc68328->regs.grpmaskb = 0x0000; | |
| 2532 | mc68328->regs.grpmaskc = 0x0000; | |
| 2533 | mc68328->regs.grpmaskd = 0x0000; | |
| 2534 | mc68328->regs.csa0 = 0x00010006; | |
| 2535 | mc68328->regs.csa1 = 0x00010006; | |
| 2536 | mc68328->regs.csa2 = 0x00010006; | |
| 2537 | mc68328->regs.csa3 = 0x00010006; | |
| 2538 | mc68328->regs.csb0 = 0x00010006; | |
| 2539 | mc68328->regs.csb1 = 0x00010006; | |
| 2540 | mc68328->regs.csb2 = 0x00010006; | |
| 2541 | mc68328->regs.csb3 = 0x00010006; | |
| 2542 | mc68328->regs.csc0 = 0x00010006; | |
| 2543 | mc68328->regs.csc1 = 0x00010006; | |
| 2544 | mc68328->regs.csc2 = 0x00010006; | |
| 2545 | mc68328->regs.csc3 = 0x00010006; | |
| 2546 | mc68328->regs.csd0 = 0x00010006; | |
| 2547 | mc68328->regs.csd1 = 0x00010006; | |
| 2548 | mc68328->regs.csd2 = 0x00010006; | |
| 2549 | mc68328->regs.csd3 = 0x00010006; | |
| 2550 | ||
| 2551 | mc68328->regs.pllcr = 0x2400; | |
| 2552 | mc68328->regs.pllfsr = 0x0123; | |
| 2553 | mc68328->regs.pctlr = 0x1f; | |
| 2554 | ||
| 2555 | mc68328->regs.ivr = 0x00; | |
| 2556 | mc68328->regs.icr = 0x0000; | |
| 2557 | mc68328->regs.imr = 0x00ffffff; | |
| 2558 | mc68328->regs.iwr = 0x00ffffff; | |
| 2559 | mc68328->regs.isr = 0x00000000; | |
| 2560 | mc68328->regs.ipr = 0x00000000; | |
| 2561 | ||
| 2562 | mc68328->regs.padir = 0x00; | |
| 2563 | mc68328->regs.padata = 0x00; | |
| 2564 | mc68328->regs.pasel = 0x00; | |
| 2565 | mc68328->regs.pbdir = 0x00; | |
| 2566 | mc68328->regs.pbdata = 0x00; | |
| 2567 | mc68328->regs.pbsel = 0x00; | |
| 2568 | mc68328->regs.pcdir = 0x00; | |
| 2569 | mc68328->regs.pcdata = 0x00; | |
| 2570 | mc68328->regs.pcsel = 0x00; | |
| 2571 | mc68328->regs.pddir = 0x00; | |
| 2572 | mc68328->regs.pddata = 0x00; | |
| 2573 | mc68328->regs.pdpuen = 0xff; | |
| 2574 | mc68328->regs.pdpol = 0x00; | |
| 2575 | mc68328->regs.pdirqen = 0x00; | |
| 2576 | mc68328->regs.pddataedge = 0x00; | |
| 2577 | mc68328->regs.pdirqedge = 0x00; | |
| 2578 | mc68328->regs.pedir = 0x00; | |
| 2579 | mc68328->regs.pedata = 0x00; | |
| 2580 | mc68328->regs.pepuen = 0x80; | |
| 2581 | mc68328->regs.pesel = 0x80; | |
| 2582 | mc68328->regs.pfdir = 0x00; | |
| 2583 | mc68328->regs.pfdata = 0x00; | |
| 2584 | mc68328->regs.pfpuen = 0xff; | |
| 2585 | mc68328->regs.pfsel = 0xff; | |
| 2586 | mc68328->regs.pgdir = 0x00; | |
| 2587 | mc68328->regs.pgdata = 0x00; | |
| 2588 | mc68328->regs.pgpuen = 0xff; | |
| 2589 | mc68328->regs.pgsel = 0xff; | |
| 2590 | mc68328->regs.pjdir = 0x00; | |
| 2591 | mc68328->regs.pjdata = 0x00; | |
| 2592 | mc68328->regs.pjsel = 0x00; | |
| 2593 | mc68328->regs.pkdir = 0x00; | |
| 2594 | mc68328->regs.pkdata = 0x00; | |
| 2595 | mc68328->regs.pkpuen = 0xff; | |
| 2596 | mc68328->regs.pksel = 0xff; | |
| 2597 | mc68328->regs.pmdir = 0x00; | |
| 2598 | mc68328->regs.pmdata = 0x00; | |
| 2599 | mc68328->regs.pmpuen = 0xff; | |
| 2600 | mc68328->regs.pmsel = 0xff; | |
| 2601 | ||
| 2602 | mc68328->regs.pwmc = 0x0000; | |
| 2603 | mc68328->regs.pwmp = 0x0000; | |
| 2604 | mc68328->regs.pwmw = 0x0000; | |
| 2605 | mc68328->regs.pwmcnt = 0x0000; | |
| 2606 | ||
| 2607 | mc68328->regs.tctl[0] = mc68328->regs.tctl[1] = 0x0000; | |
| 2608 | mc68328->regs.tprer[0] = mc68328->regs.tprer[1] = 0x0000; | |
| 2609 | mc68328->regs.tcmp[0] = mc68328->regs.tcmp[1] = 0xffff; | |
| 2610 | mc68328->regs.tcr[0] = mc68328->regs.tcr[1] = 0x0000; | |
| 2611 | mc68328->regs.tcn[0] = mc68328->regs.tcn[1] = 0x0000; | |
| 2612 | mc68328->regs.tstat[0] = mc68328->regs.tstat[1] = 0x0000; | |
| 2613 | mc68328->regs.wctlr = 0x0000; | |
| 2614 | mc68328->regs.wcmpr = 0xffff; | |
| 2615 | mc68328->regs.wcn = 0x0000; | |
| 2616 | ||
| 2617 | mc68328->regs.spisr = 0x0000; | |
| 2618 | ||
| 2619 | mc68328->regs.spimdata = 0x0000; | |
| 2620 | mc68328->regs.spimcont = 0x0000; | |
| 2621 | ||
| 2622 | mc68328->regs.ustcnt = 0x0000; | |
| 2623 | mc68328->regs.ubaud = 0x003f; | |
| 2624 | mc68328->regs.urx = 0x0000; | |
| 2625 | mc68328->regs.utx = 0x0000; | |
| 2626 | mc68328->regs.umisc = 0x0000; | |
| 2627 | ||
| 2628 | mc68328->regs.lssa = 0x00000000; | |
| 2629 | mc68328->regs.lvpw = 0xff; | |
| 2630 | mc68328->regs.lxmax = 0x03ff; | |
| 2631 | mc68328->regs.lymax = 0x01ff; | |
| 2632 | mc68328->regs.lcxp = 0x0000; | |
| 2633 | mc68328->regs.lcyp = 0x0000; | |
| 2634 | mc68328->regs.lcwch = 0x0101; | |
| 2635 | mc68328->regs.lblkc = 0x7f; | |
| 2636 | mc68328->regs.lpicf = 0x00; | |
| 2637 | mc68328->regs.lpolcf = 0x00; | |
| 2638 | mc68328->regs.lacdrc = 0x00; | |
| 2639 | mc68328->regs.lpxcd = 0x00; | |
| 2640 | mc68328->regs.lckcon = 0x40; | |
| 2641 | mc68328->regs.llbar = 0x3e; | |
| 2642 | mc68328->regs.lotcr = 0x3f; | |
| 2643 | mc68328->regs.lposr = 0x00; | |
| 2644 | mc68328->regs.lfrcm = 0xb9; | |
| 2645 | mc68328->regs.lgpmr = 0x1073; | |
| 2646 | ||
| 2647 | mc68328->regs.hmsr = 0x00000000; | |
| 2648 | mc68328->regs.alarm = 0x00000000; | |
| 2649 | mc68328->regs.rtcctl = 0x00; | |
| 2650 | mc68328->regs.rtcisr = 0x00; | |
| 2651 | mc68328->regs.rtcienr = 0x00; | |
| 2652 | mc68328->regs.stpwtch = 0x00; | |
| 2653 | ||
| 2654 | mc68328->rtc->adjust(attotime::from_hz(1), 0, attotime::from_hz(1)); | |
| 2655 | } | |
| 2656 | ||
| 2657 | static void mc68328_register_state_save(device_t *device) | |
| 2658 | { | |
| 2659 | mc68328_t* mc68328 = mc68328_get_safe_token( device ); | |
| 2660 | ||
| 2661 | state_save_register_global(device->machine(), mc68328->regs.scr); | |
| 2662 | state_save_register_global(device->machine(), mc68328->regs.grpbasea); | |
| 2663 | state_save_register_global(device->machine(), mc68328->regs.grpbaseb); | |
| 2664 | state_save_register_global(device->machine(), mc68328->regs.grpbasec); | |
| 2665 | state_save_register_global(device->machine(), mc68328->regs.grpbased); | |
| 2666 | state_save_register_global(device->machine(), mc68328->regs.grpmaska); | |
| 2667 | state_save_register_global(device->machine(), mc68328->regs.grpmaskb); | |
| 2668 | state_save_register_global(device->machine(), mc68328->regs.grpmaskc); | |
| 2669 | state_save_register_global(device->machine(), mc68328->regs.grpmaskd); | |
| 2670 | state_save_register_global(device->machine(), mc68328->regs.csa0); | |
| 2671 | state_save_register_global(device->machine(), mc68328->regs.csa1); | |
| 2672 | state_save_register_global(device->machine(), mc68328->regs.csa2); | |
| 2673 | state_save_register_global(device->machine(), mc68328->regs.csa3); | |
| 2674 | state_save_register_global(device->machine(), mc68328->regs.csb0); | |
| 2675 | state_save_register_global(device->machine(), mc68328->regs.csb1); | |
| 2676 | state_save_register_global(device->machine(), mc68328->regs.csb2); | |
| 2677 | state_save_register_global(device->machine(), mc68328->regs.csb3); | |
| 2678 | state_save_register_global(device->machine(), mc68328->regs.csc0); | |
| 2679 | state_save_register_global(device->machine(), mc68328->regs.csc1); | |
| 2680 | state_save_register_global(device->machine(), mc68328->regs.csc2); | |
| 2681 | state_save_register_global(device->machine(), mc68328->regs.csc3); | |
| 2682 | state_save_register_global(device->machine(), mc68328->regs.csd0); | |
| 2683 | state_save_register_global(device->machine(), mc68328->regs.csd1); | |
| 2684 | state_save_register_global(device->machine(), mc68328->regs.csd2); | |
| 2685 | state_save_register_global(device->machine(), mc68328->regs.csd3); | |
| 2686 | ||
| 2687 | state_save_register_global(device->machine(), mc68328->regs.pllcr); | |
| 2688 | state_save_register_global(device->machine(), mc68328->regs.pllfsr); | |
| 2689 | state_save_register_global(device->machine(), mc68328->regs.pctlr); | |
| 2690 | ||
| 2691 | state_save_register_global(device->machine(), mc68328->regs.ivr); | |
| 2692 | state_save_register_global(device->machine(), mc68328->regs.icr); | |
| 2693 | state_save_register_global(device->machine(), mc68328->regs.imr); | |
| 2694 | state_save_register_global(device->machine(), mc68328->regs.iwr); | |
| 2695 | state_save_register_global(device->machine(), mc68328->regs.isr); | |
| 2696 | state_save_register_global(device->machine(), mc68328->regs.ipr); | |
| 2697 | ||
| 2698 | state_save_register_global(device->machine(), mc68328->regs.padir); | |
| 2699 | state_save_register_global(device->machine(), mc68328->regs.padata); | |
| 2700 | state_save_register_global(device->machine(), mc68328->regs.pasel); | |
| 2701 | state_save_register_global(device->machine(), mc68328->regs.pbdir); | |
| 2702 | state_save_register_global(device->machine(), mc68328->regs.pbdata); | |
| 2703 | state_save_register_global(device->machine(), mc68328->regs.pbsel); | |
| 2704 | state_save_register_global(device->machine(), mc68328->regs.pcdir); | |
| 2705 | state_save_register_global(device->machine(), mc68328->regs.pcdata); | |
| 2706 | state_save_register_global(device->machine(), mc68328->regs.pcsel); | |
| 2707 | state_save_register_global(device->machine(), mc68328->regs.pddir); | |
| 2708 | state_save_register_global(device->machine(), mc68328->regs.pddata); | |
| 2709 | state_save_register_global(device->machine(), mc68328->regs.pdpuen); | |
| 2710 | state_save_register_global(device->machine(), mc68328->regs.pdpol); | |
| 2711 | state_save_register_global(device->machine(), mc68328->regs.pdirqen); | |
| 2712 | state_save_register_global(device->machine(), mc68328->regs.pddataedge); | |
| 2713 | state_save_register_global(device->machine(), mc68328->regs.pdirqedge); | |
| 2714 | state_save_register_global(device->machine(), mc68328->regs.pedir); | |
| 2715 | state_save_register_global(device->machine(), mc68328->regs.pedata); | |
| 2716 | state_save_register_global(device->machine(), mc68328->regs.pepuen); | |
| 2717 | state_save_register_global(device->machine(), mc68328->regs.pesel); | |
| 2718 | state_save_register_global(device->machine(), mc68328->regs.pfdir); | |
| 2719 | state_save_register_global(device->machine(), mc68328->regs.pfdata); | |
| 2720 | state_save_register_global(device->machine(), mc68328->regs.pfpuen); | |
| 2721 | state_save_register_global(device->machine(), mc68328->regs.pfsel); | |
| 2722 | state_save_register_global(device->machine(), mc68328->regs.pgdir); | |
| 2723 | state_save_register_global(device->machine(), mc68328->regs.pgdata); | |
| 2724 | state_save_register_global(device->machine(), mc68328->regs.pgpuen); | |
| 2725 | state_save_register_global(device->machine(), mc68328->regs.pgsel); | |
| 2726 | state_save_register_global(device->machine(), mc68328->regs.pjdir); | |
| 2727 | state_save_register_global(device->machine(), mc68328->regs.pjdata); | |
| 2728 | state_save_register_global(device->machine(), mc68328->regs.pjsel); | |
| 2729 | state_save_register_global(device->machine(), mc68328->regs.pkdir); | |
| 2730 | state_save_register_global(device->machine(), mc68328->regs.pkdata); | |
| 2731 | state_save_register_global(device->machine(), mc68328->regs.pkpuen); | |
| 2732 | state_save_register_global(device->machine(), mc68328->regs.pksel); | |
| 2733 | state_save_register_global(device->machine(), mc68328->regs.pmdir); | |
| 2734 | state_save_register_global(device->machine(), mc68328->regs.pmdata); | |
| 2735 | state_save_register_global(device->machine(), mc68328->regs.pmpuen); | |
| 2736 | state_save_register_global(device->machine(), mc68328->regs.pmsel); | |
| 2737 | ||
| 2738 | state_save_register_global(device->machine(), mc68328->regs.pwmc); | |
| 2739 | state_save_register_global(device->machine(), mc68328->regs.pwmp); | |
| 2740 | state_save_register_global(device->machine(), mc68328->regs.pwmw); | |
| 2741 | state_save_register_global(device->machine(), mc68328->regs.pwmcnt); | |
| 2742 | ||
| 2743 | state_save_register_global(device->machine(), mc68328->regs.tctl[0]); | |
| 2744 | state_save_register_global(device->machine(), mc68328->regs.tctl[1]); | |
| 2745 | state_save_register_global(device->machine(), mc68328->regs.tprer[0]); | |
| 2746 | state_save_register_global(device->machine(), mc68328->regs.tprer[1]); | |
| 2747 | state_save_register_global(device->machine(), mc68328->regs.tcmp[0]); | |
| 2748 | state_save_register_global(device->machine(), mc68328->regs.tcmp[1]); | |
| 2749 | state_save_register_global(device->machine(), mc68328->regs.tcr[0]); | |
| 2750 | state_save_register_global(device->machine(), mc68328->regs.tcr[1]); | |
| 2751 | state_save_register_global(device->machine(), mc68328->regs.tcn[0]); | |
| 2752 | state_save_register_global(device->machine(), mc68328->regs.tcn[1]); | |
| 2753 | state_save_register_global(device->machine(), mc68328->regs.tstat[0]); | |
| 2754 | state_save_register_global(device->machine(), mc68328->regs.tstat[1]); | |
| 2755 | state_save_register_global(device->machine(), mc68328->regs.wctlr); | |
| 2756 | state_save_register_global(device->machine(), mc68328->regs.wcmpr); | |
| 2757 | state_save_register_global(device->machine(), mc68328->regs.wcn); | |
| 2758 | ||
| 2759 | state_save_register_global(device->machine(), mc68328->regs.spisr); | |
| 2760 | ||
| 2761 | state_save_register_global(device->machine(), mc68328->regs.spimdata); | |
| 2762 | state_save_register_global(device->machine(), mc68328->regs.spimcont); | |
| 2763 | ||
| 2764 | state_save_register_global(device->machine(), mc68328->regs.ustcnt); | |
| 2765 | state_save_register_global(device->machine(), mc68328->regs.ubaud); | |
| 2766 | state_save_register_global(device->machine(), mc68328->regs.urx); | |
| 2767 | state_save_register_global(device->machine(), mc68328->regs.utx); | |
| 2768 | state_save_register_global(device->machine(), mc68328->regs.umisc); | |
| 2769 | ||
| 2770 | state_save_register_global(device->machine(), mc68328->regs.lssa); | |
| 2771 | state_save_register_global(device->machine(), mc68328->regs.lvpw); | |
| 2772 | state_save_register_global(device->machine(), mc68328->regs.lxmax); | |
| 2773 | state_save_register_global(device->machine(), mc68328->regs.lymax); | |
| 2774 | state_save_register_global(device->machine(), mc68328->regs.lcxp); | |
| 2775 | state_save_register_global(device->machine(), mc68328->regs.lcyp); | |
| 2776 | state_save_register_global(device->machine(), mc68328->regs.lcwch); | |
| 2777 | state_save_register_global(device->machine(), mc68328->regs.lblkc); | |
| 2778 | state_save_register_global(device->machine(), mc68328->regs.lpicf); | |
| 2779 | state_save_register_global(device->machine(), mc68328->regs.lpolcf); | |
| 2780 | state_save_register_global(device->machine(), mc68328->regs.lacdrc); | |
| 2781 | state_save_register_global(device->machine(), mc68328->regs.lpxcd); | |
| 2782 | state_save_register_global(device->machine(), mc68328->regs.lckcon); | |
| 2783 | state_save_register_global(device->machine(), mc68328->regs.llbar); | |
| 2784 | state_save_register_global(device->machine(), mc68328->regs.lotcr); | |
| 2785 | state_save_register_global(device->machine(), mc68328->regs.lposr); | |
| 2786 | state_save_register_global(device->machine(), mc68328->regs.lfrcm); | |
| 2787 | state_save_register_global(device->machine(), mc68328->regs.lgpmr); | |
| 2788 | ||
| 2789 | state_save_register_global(device->machine(), mc68328->regs.hmsr); | |
| 2790 | state_save_register_global(device->machine(), mc68328->regs.alarm); | |
| 2791 | state_save_register_global(device->machine(), mc68328->regs.rtcctl); | |
| 2792 | state_save_register_global(device->machine(), mc68328->regs.rtcisr); | |
| 2793 | state_save_register_global(device->machine(), mc68328->regs.rtcienr); | |
| 2794 | state_save_register_global(device->machine(), mc68328->regs.stpwtch); | |
| 2795 | } | |
| 2796 | ||
| 2797 | static DEVICE_START( mc68328 ) | |
| 2798 | { | |
| 2799 | mc68328_t* mc68328 = mc68328_get_safe_token( device ); | |
| 2800 | ||
| 2801 | mc68328->iface = (const mc68328_interface*)device->static_config(); | |
| 2802 | ||
| 2803 | mc68328->out_port_a.resolve(mc68328->iface->out_port_a_func, *device); | |
| 2804 | mc68328->out_port_b.resolve(mc68328->iface->out_port_b_func, *device); | |
| 2805 | mc68328->out_port_c.resolve(mc68328->iface->out_port_c_func, *device); | |
| 2806 | mc68328->out_port_d.resolve(mc68328->iface->out_port_d_func, *device); | |
| 2807 | mc68328->out_port_e.resolve(mc68328->iface->out_port_e_func, *device); | |
| 2808 | mc68328->out_port_f.resolve(mc68328->iface->out_port_f_func, *device); | |
| 2809 | mc68328->out_port_g.resolve(mc68328->iface->out_port_g_func, *device); | |
| 2810 | mc68328->out_port_j.resolve(mc68328->iface->out_port_j_func, *device); | |
| 2811 | mc68328->out_port_k.resolve(mc68328->iface->out_port_k_func, *device); | |
| 2812 | mc68328->out_port_m.resolve(mc68328->iface->out_port_m_func, *device); | |
| 2813 | ||
| 2814 | mc68328->in_port_a.resolve(mc68328->iface->in_port_a_func, *device); | |
| 2815 | mc68328->in_port_b.resolve(mc68328->iface->in_port_b_func, *device); | |
| 2816 | mc68328->in_port_c.resolve(mc68328->iface->in_port_c_func, *device); | |
| 2817 | mc68328->in_port_d.resolve(mc68328->iface->in_port_d_func, *device); | |
| 2818 | mc68328->in_port_e.resolve(mc68328->iface->in_port_e_func, *device); | |
| 2819 | mc68328->in_port_f.resolve(mc68328->iface->in_port_f_func, *device); | |
| 2820 | mc68328->in_port_g.resolve(mc68328->iface->in_port_g_func, *device); | |
| 2821 | mc68328->in_port_j.resolve(mc68328->iface->in_port_j_func, *device); | |
| 2822 | mc68328->in_port_k.resolve(mc68328->iface->in_port_k_func, *device); | |
| 2823 | mc68328->in_port_m.resolve(mc68328->iface->in_port_m_func, *device); | |
| 2824 | ||
| 2825 | mc68328->out_pwm.resolve(mc68328->iface->out_pwm_func, *device); | |
| 2826 | ||
| 2827 | mc68328->out_spim.resolve(mc68328->iface->out_spim_func, *device); | |
| 2828 | mc68328->in_spim.resolve(mc68328->iface->in_spim_func, *device); | |
| 2829 | ||
| 2830 | mc68328->gptimer[0] = device->machine().scheduler().timer_alloc(FUNC(mc68328_timer1_hit)); | |
| 2831 | mc68328->gptimer[1] = device->machine().scheduler().timer_alloc(FUNC(mc68328_timer2_hit)); | |
| 2832 | mc68328->rtc = device->machine().scheduler().timer_alloc(FUNC(mc68328_rtc_tick)); | |
| 2833 | mc68328->pwm = device->machine().scheduler().timer_alloc(FUNC(mc68328_pwm_transition)); | |
| 2834 | ||
| 2835 | mc68328_register_state_save(device); | |
| 2836 | } | |
| 2837 | ||
| 2838 | const device_type MC68328 = &device_creator<mc68328_device>; | |
| 2839 | ||
| 2840 | mc68328_device::mc68328_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) | |
| 2841 | : device_t(mconfig, MC68328, "Motorola MC68328 (DragonBall) Integrated Processor", tag, owner, clock) | |
| 2842 | { | |
| 2843 | m_token = global_alloc_clear(mc68328_t); | |
| 2844 | } | |
| 2845 | ||
| 2846 | //------------------------------------------------- | |
| 2847 | // device_config_complete - perform any | |
| 2848 | // operations now that the configuration is | |
| 2849 | // complete | |
| 2850 | //------------------------------------------------- | |
| 2851 | ||
| 2852 | void mc68328_device::device_config_complete() | |
| 2853 | { | |
| 2854 | } | |
| 2855 | ||
| 2856 | //------------------------------------------------- | |
| 2857 | // device_start - device-specific startup | |
| 2858 | //------------------------------------------------- | |
| 2859 | ||
| 2860 | void mc68328_device::device_start() | |
| 2861 | { | |
| 2862 | DEVICE_START_NAME( mc68328 )(this); | |
| 2863 | } | |
| 2864 | ||
| 2865 | //------------------------------------------------- | |
| 2866 | // device_reset - device-specific reset | |
| 2867 | //------------------------------------------------- | |
| 2868 | ||
| 2869 | void mc68328_device::device_reset() | |
| 2870 | { | |
| 2871 | DEVICE_RESET_NAME( mc68328 )(this); | |
| 2872 | } |
| Added: svn:mime-type + text/plain Added: svn:eol-style + native |
| r0 | r21685 | |
|---|---|---|
| 1 | /********************************************************************** | |
| 2 | ||
| 3 | Motorola 68328 ("DragonBall") System-on-a-Chip private data | |
| 4 | ||
| 5 | By MooglyGuy | |
| 6 | contact mooglyguy@gmail.com with licensing and usage questions. | |
| 7 | ||
| 8 | **********************************************************************/ | |
| 9 | ||
| 10 | #ifndef __MC68328_PRIVATE_H_ | |
| 11 | #define __MC68328_PRIVATE_H_ | |
| 12 | ||
| 13 | struct mc68328_regs_t | |
| 14 | { | |
| 15 | // $(FF)FFF000 | |
| 16 | UINT8 scr; // System Control Register | |
| 17 | UINT8 unused0[255]; | |
| 18 | ||
| 19 | // $(FF)FFF100 | |
| 20 | UINT16 grpbasea; // Chip Select Group A Base Register | |
| 21 | UINT16 grpbaseb; // Chip Select Group B Base Register | |
| 22 | UINT16 grpbasec; // Chip Select Group C Base Register | |
| 23 | UINT16 grpbased; // Chip Select Group D Base Register | |
| 24 | UINT16 grpmaska; // Chip Select Group A Mask Register | |
| 25 | UINT16 grpmaskb; // Chip Select Group B Mask Register | |
| 26 | UINT16 grpmaskc; // Chip Select Group C Mask Register | |
| 27 | UINT16 grpmaskd; // Chip Select Group D Mask Register | |
| 28 | UINT32 csa0; // Group A Chip Select 0 Register | |
| 29 | UINT32 csa1; // Group A Chip Select 1 Register | |
| 30 | UINT32 csa2; // Group A Chip Select 2 Register | |
| 31 | UINT32 csa3; // Group A Chip Select 3 Register | |
| 32 | UINT32 csb0; // Group B Chip Select 0 Register | |
| 33 | UINT32 csb1; // Group B Chip Select 1 Register | |
| 34 | UINT32 csb2; // Group B Chip Select 2 Register | |
| 35 | UINT32 csb3; // Group B Chip Select 3 Register | |
| 36 | UINT32 csc0; // Group C Chip Select 0 Register | |
| 37 | UINT32 csc1; // Group C Chip Select 1 Register | |
| 38 | UINT32 csc2; // Group C Chip Select 2 Register | |
| 39 | UINT32 csc3; // Group C Chip Select 3 Register | |
| 40 | UINT32 csd0; // Group D Chip Select 0 Register | |
| 41 | UINT32 csd1; // Group D Chip Select 1 Register | |
| 42 | UINT32 csd2; // Group D Chip Select 2 Register | |
| 43 | UINT32 csd3; // Group D Chip Select 3 Register | |
| 44 | UINT8 unused1[176]; | |
| 45 | ||
| 46 | // $(FF)FFF200 | |
| 47 | UINT16 pllcr; // PLL Control Register | |
| 48 | UINT16 pllfsr; // PLL Frequency Select Register | |
| 49 | UINT8 pad2[3]; | |
| 50 | UINT8 pctlr; // Power Control Register | |
| 51 | UINT8 unused3[248]; | |
| 52 | ||
| 53 | // $(FF)FFF300 | |
| 54 | UINT8 ivr; // Interrupt Vector Register | |
| 55 | UINT8 unused4[1]; | |
| 56 | UINT16 icr; // Interrupt Control Register | |
| 57 | UINT32 imr; // Interrupt Mask Register | |
| 58 | UINT32 iwr; // Interrupt Wakeup Enable Register | |
| 59 | UINT32 isr; // Interrupt Status Register | |
| 60 | UINT32 ipr; // Interrupt Pending Register | |
| 61 | UINT8 unused5[236]; | |
| 62 | ||
| 63 | // $(FF)FFF400 | |
| 64 | UINT8 padir; // Port A Direction Register | |
| 65 | UINT8 padata; // Port A Data Register | |
| 66 | UINT8 unused6[1]; | |
| 67 | UINT8 pasel; // Port A Select Register | |
| 68 | UINT8 unused7[4]; | |
| 69 | ||
| 70 | UINT8 pbdir; // Port B Direction Register | |
| 71 | UINT8 pbdata; // Port B Data Register | |
| 72 | UINT8 unused8[1]; | |
| 73 | UINT8 pbsel; // Port B Select Register | |
| 74 | UINT8 unused9[4]; | |
| 75 | ||
| 76 | UINT8 pcdir; // Port C Direction Register | |
| 77 | UINT8 pcdata; // Port C Data Register | |
| 78 | UINT8 unused10[1]; | |
| 79 | UINT8 pcsel; // Port C Select Register | |
| 80 | UINT8 unused11[4]; | |
| 81 | ||
| 82 | UINT8 pddir; // Port D Direction Register | |
| 83 | UINT8 pddata; // Port D Data Register | |
| 84 | UINT8 pdpuen; // Port D Pullup Enable Register | |
| 85 | UINT8 unused12[1]; | |
| 86 | UINT8 pdpol; // Port D Polarity Register | |
| 87 | UINT8 pdirqen; // Port D IRQ Enable Register | |
| 88 | UINT8 pddataedge; // Port D Data Edge Level | |
| 89 | UINT8 pdirqedge; // Port D IRQ Edge Register | |
| 90 | ||
| 91 | UINT8 pedir; // Port E Direction Register | |
| 92 | UINT8 pedata; // Port E Data Register | |
| 93 | UINT8 pepuen; // Port E Pullup Enable Register | |
| 94 | UINT8 pesel; // Port E Select Register | |
| 95 | UINT8 unused14[4]; | |
| 96 | ||
| 97 | UINT8 pfdir; // Port F Direction Register | |
| 98 | UINT8 pfdata; // Port F Data Register | |
| 99 | UINT8 pfpuen; // Port F Pullup Enable Register | |
| 100 | UINT8 pfsel; // Port F Select Register | |
| 101 | UINT8 unused15[4]; | |
| 102 | ||
| 103 | UINT8 pgdir; // Port G Direction Register | |
| 104 | UINT8 pgdata; // Port G Data Register | |
| 105 | UINT8 pgpuen; // Port G Pullup Enable Register | |
| 106 | UINT8 pgsel; // Port G Select Register | |
| 107 | UINT8 unused16[4]; | |
| 108 | ||
| 109 | UINT8 pjdir; // Port J Direction Register | |
| 110 | UINT8 pjdata; // Port J Data Register | |
| 111 | UINT8 unused17[1]; | |
| 112 | UINT8 pjsel; // Port J Select Register | |
| 113 | UINT8 unused18[4]; | |
| 114 | UINT8 pkdir; // Port K Direction Register | |
| 115 | UINT8 pkdata; // Port K Data Register | |
| 116 | UINT8 pkpuen; // Port K Pullup Enable Register | |
| 117 | UINT8 pksel; // Port K Select Register | |
| 118 | UINT8 unused19[4]; | |
| 119 | ||
| 120 | UINT8 pmdir; // Port M Direction Register | |
| 121 | UINT8 pmdata; // Port M Data Register | |
| 122 | UINT8 pmpuen; // Port M Pullup Enable Register | |
| 123 | UINT8 pmsel; // Port M Select Register | |
| 124 | UINT8 unused20[180]; | |
| 125 | ||
| 126 | // $(FF)FFF500 | |
| 127 | UINT16 pwmc; // PWM Control Register | |
| 128 | UINT16 pwmp; // PWM Period Register | |
| 129 | UINT16 pwmw; // PWM Width Register | |
| 130 | UINT16 pwmcnt; // PWN Counter | |
| 131 | UINT8 unused21[248]; | |
| 132 | ||
| 133 | // $(FF)FFF600 | |
| 134 | UINT16 tctl[2]; // Timer Control Register | |
| 135 | UINT16 tprer[2]; // Timer Prescaler Register | |
| 136 | UINT16 tcmp[2]; // Timer Compare Register | |
| 137 | UINT16 tcr[2]; // Timer Capture Register | |
| 138 | UINT16 tcn[2]; // Timer Counter | |
| 139 | UINT16 tstat[2]; // Timer Status | |
| 140 | UINT16 wctlr; // Watchdog Control Register | |
| 141 | UINT16 wcmpr; // Watchdog Compare Register | |
| 142 | UINT16 wcn; // Watchdog Counter | |
| 143 | UINT8 tclear[2]; // Timer Clearable Status | |
| 144 | UINT8 unused22[224]; | |
| 145 | ||
| 146 | // $(FF)FFF700 | |
| 147 | UINT16 spisr; // SPIS Register | |
| 148 | UINT8 unused23[254]; | |
| 149 | ||
| 150 | // $(FF)FFF800 | |
| 151 | UINT16 spimdata; // SPIM Data Register | |
| 152 | UINT16 spimcont; // SPIM Control/Status Register | |
| 153 | UINT8 unused24[252]; | |
| 154 | ||
| 155 | // $(FF)FFF900 | |
| 156 | UINT16 ustcnt; // UART Status/Control Register | |
| 157 | UINT16 ubaud; // UART Baud Control Register | |
| 158 | UINT16 urx; // UART RX Register | |
| 159 | UINT16 utx; // UART TX Register | |
| 160 | UINT16 umisc; // UART Misc Register | |
| 161 | UINT8 unused25[246]; | |
| 162 | ||
| 163 | // $(FF)FFFA00 | |
| 164 | UINT32 lssa; // Screen Starting Address Register | |
| 165 | UINT8 unused26[1]; | |
| 166 | UINT8 lvpw; // Virtual Page Width Register | |
| 167 | UINT8 unused27[2]; | |
| 168 | UINT16 lxmax; // Screen Width Register | |
| 169 | UINT16 lymax; // Screen Height Register | |
| 170 | UINT8 unused28[12]; | |
| 171 | UINT16 lcxp; // Cursor X Position | |
| 172 | UINT16 lcyp; // Cursor Y Position | |
| 173 | UINT16 lcwch; // Cursor Width & Height Register | |
| 174 | UINT8 unused29[1]; | |
| 175 | UINT8 lblkc; // Blink Control Register | |
| 176 | UINT8 lpicf; // Panel Interface Config Register | |
| 177 | UINT8 lpolcf; // Polarity Config Register | |
| 178 | UINT8 unused30[1]; | |
| 179 | UINT8 lacdrc; // ACD (M) Rate Control Register | |
| 180 | UINT8 unused31[1]; | |
| 181 | UINT8 lpxcd; // Pixel Clock Divider Register | |
| 182 | UINT8 unused32[1]; | |
| 183 | UINT8 lckcon; // Clocking Control Register | |
| 184 | UINT8 unused33[1]; | |
| 185 | UINT8 llbar; // Last Buffer Address Register | |
| 186 | UINT8 unused34[1]; | |
| 187 | UINT8 lotcr; // Octet Terminal Count Register | |
| 188 | UINT8 unused35[1]; | |
| 189 | UINT8 lposr; // Panning Offset Register | |
| 190 | UINT8 unused36[3]; | |
| 191 | UINT8 lfrcm; // Frame Rate Control Modulation Register | |
| 192 | UINT16 lgpmr; // Gray Palette Mapping Register | |
| 193 | UINT8 unused37[204]; | |
| 194 | ||
| 195 | // $(FF)FFFB00 | |
| 196 | UINT32 hmsr; // RTC Hours Minutes Seconds Register | |
| 197 | UINT32 alarm; // RTC Alarm Register | |
| 198 | UINT8 unused38[4]; | |
| 199 | UINT16 rtcctl; // RTC Control Register | |
| 200 | UINT16 rtcisr; // RTC Interrupt Status Register | |
| 201 | UINT16 rtcienr; // RTC Interrupt Enable Register | |
| 202 | UINT16 stpwtch; // Stopwatch Minutes | |
| 203 | UINT8 unused42[1260]; | |
| 204 | }; | |
| 205 | ||
| 206 | struct mc68328_t | |
| 207 | { | |
| 208 | const mc68328_interface* iface; | |
| 209 | ||
| 210 | mc68328_regs_t regs; | |
| 211 | ||
| 212 | emu_timer *gptimer[2]; | |
| 213 | emu_timer *rtc; | |
| 214 | emu_timer *pwm; | |
| 215 | ||
| 216 | devcb_resolved_write8 out_port_a; /* 8-bit output */ | |
| 217 | devcb_resolved_write8 out_port_b; /* 8-bit output */ | |
| 218 | devcb_resolved_write8 out_port_c; /* 8-bit output */ | |
| 219 | devcb_resolved_write8 out_port_d; /* 8-bit output */ | |
| 220 | devcb_resolved_write8 out_port_e; /* 8-bit output */ | |
| 221 | devcb_resolved_write8 out_port_f; /* 8-bit output */ | |
| 222 | devcb_resolved_write8 out_port_g; /* 8-bit output */ | |
| 223 | devcb_resolved_write8 out_port_j; /* 8-bit output */ | |
| 224 | devcb_resolved_write8 out_port_k; /* 8-bit output */ | |
| 225 | devcb_resolved_write8 out_port_m; /* 8-bit output */ | |
| 226 | ||
| 227 | devcb_resolved_read8 in_port_a; /* 8-bit input */ | |
| 228 | devcb_resolved_read8 in_port_b; /* 8-bit input */ | |
| 229 | devcb_resolved_read8 in_port_c; /* 8-bit input */ | |
| 230 | devcb_resolved_read8 in_port_d; /* 8-bit input */ | |
| 231 | devcb_resolved_read8 in_port_e; /* 8-bit input */ | |
| 232 | devcb_resolved_read8 in_port_f; /* 8-bit input */ | |
| 233 | devcb_resolved_read8 in_port_g; /* 8-bit input */ | |
| 234 | devcb_resolved_read8 in_port_j; /* 8-bit input */ | |
| 235 | devcb_resolved_read8 in_port_k; /* 8-bit input */ | |
| 236 | devcb_resolved_read8 in_port_m; /* 8-bit input */ | |
| 237 | ||
| 238 | devcb_resolved_write8 out_pwm; /* 1-bit output */ | |
| 239 | ||
| 240 | devcb_resolved_write16 out_spim; /* 16-bit output */ | |
| 241 | devcb_resolved_read16 in_spim; /* 16-bit input */ | |
| 242 | }; | |
| 243 | ||
| 244 | #define SCR_BETO 0x80 | |
| 245 | #define SCR_WPV 0x40 | |
| 246 | #define SCR_PRV 0x20 | |
| 247 | #define SCR_BETEN 0x10 | |
| 248 | #define SCR_SO 0x08 | |
| 249 | #define SCR_DMAP 0x04 | |
| 250 | #define SCR_WDTH8 0x01 | |
| 251 | ||
| 252 | #define ICR_POL6 0x0100 | |
| 253 | #define ICR_POL3 0x0200 | |
| 254 | #define ICR_POL2 0x0400 | |
| 255 | #define ICR_POL1 0x0800 | |
| 256 | #define ICR_ET6 0x1000 | |
| 257 | #define ICR_ET3 0x2000 | |
| 258 | #define ICR_ET2 0x4000 | |
| 259 | #define ICR_ET1 0x8000 | |
| 260 | ||
| 261 | #define INT_SPIM 0x000001 | |
| 262 | #define INT_TIMER2 0x000002 | |
| 263 | #define INT_UART 0x000004 | |
| 264 | #define INT_WDT 0x000008 | |
| 265 | #define INT_RTC 0x000010 | |
| 266 | #define INT_RESERVED 0x000020 | |
| 267 | #define INT_KB 0x000040 | |
| 268 | #define INT_PWM 0x000080 | |
| 269 | #define INT_INT0 0x000100 | |
| 270 | #define INT_INT1 0x000200 | |
| 271 | #define INT_INT2 0x000400 | |
| 272 | #define INT_INT3 0x000800 | |
| 273 | #define INT_INT4 0x001000 | |
| 274 | #define INT_INT5 0x002000 | |
| 275 | #define INT_INT6 0x004000 | |
| 276 | #define INT_INT7 0x008000 | |
| 277 | #define INT_KBDINTS 0x00ff00 | |
| 278 | #define INT_IRQ1 0x010000 | |
| 279 | #define INT_IRQ2 0x020000 | |
| 280 | #define INT_IRQ3 0x040000 | |
| 281 | #define INT_IRQ6 0x080000 | |
| 282 | #define INT_PEN 0x100000 | |
| 283 | #define INT_SPIS 0x200000 | |
| 284 | #define INT_TIMER1 0x400000 | |
| 285 | #define INT_IRQ7 0x800000 | |
| 286 | ||
| 287 | #define INT_M68K_LINE1 (INT_IRQ1) | |
| 288 | #define INT_M68K_LINE2 (INT_IRQ2) | |
| 289 | #define INT_M68K_LINE3 (INT_IRQ3) | |
| 290 | #define INT_M68K_LINE4 (INT_INT0 | INT_INT1 | INT_INT2 | INT_INT3 | INT_INT4 | INT_INT5 | INT_INT6 | INT_INT7 | \ | |
| 291 | INT_PWM | INT_KB | INT_RTC | INT_WDT | INT_UART | INT_TIMER2 | INT_SPIM) | |
| 292 | #define INT_M68K_LINE5 (INT_PEN) | |
| 293 | #define INT_M68K_LINE6 (INT_IRQ6 | INT_TIMER1 | INT_SPIS) | |
| 294 | #define INT_M68K_LINE7 (INT_IRQ7) | |
| 295 | #define INT_M68K_LINE67 (INT_M68K_LINE6 | INT_M68K_LINE7) | |
| 296 | #define INT_M68K_LINE567 (INT_M68K_LINE5 | INT_M68K_LINE6 | INT_M68K_LINE7) | |
| 297 | #define INT_M68K_LINE4567 (INT_M68K_LINE4 | INT_M68K_LINE5 | INT_M68K_LINE6 | INT_M68K_LINE7) | |
| 298 | #define INT_M68K_LINE34567 (INT_M68K_LINE3 | INT_M68K_LINE4 | INT_M68K_LINE5 | INT_M68K_LINE6 | INT_M68K_LINE7) | |
| 299 | #define INT_M68K_LINE234567 (INT_M68K_LINE2 | INT_M68K_LINE3 | INT_M68K_LINE4 | INT_M68K_LINE5 | INT_M68K_LINE6 | INT_M68K_LINE7) | |
| 300 | ||
| 301 | #define INT_IRQ1_SHIFT 0x000001 | |
| 302 | #define INT_IRQ2_SHIFT 0x000002 | |
| 303 | #define INT_IRQ3_SHIFT 0x000004 | |
| 304 | #define INT_IRQ6_SHIFT 0x000008 | |
| 305 | #define INT_PEN_SHIFT 0x000010 | |
| 306 | #define INT_SPIS_SHIFT 0x000020 | |
| 307 | #define INT_TIMER1_SHIFT 0x000040 | |
| 308 | #define INT_IRQ7_SHIFT 0x000080 | |
| 309 | ||
| 310 | #define INT_ACTIVE 1 | |
| 311 | #define INT_INACTIVE 0 | |
| 312 | ||
| 313 | #define GRPBASE_BASE_ADDR 0xfff0 | |
| 314 | #define GRPBASE_VALID 0x0001 | |
| 315 | ||
| 316 | #define GRPMASK_BASE_MASK 0xfff0 | |
| 317 | ||
| 318 | #define CSAB_COMPARE 0xff000000 | |
| 319 | #define CSAB_BSW 0x00010000 | |
| 320 | #define CSAB_MASK 0x0000ff00 | |
| 321 | #define CSAB_RO 0x00000008 | |
| 322 | #define CSAB_WAIT 0x00000007 | |
| 323 | ||
| 324 | #define CSCD_COMPARE 0xfff00000 | |
| 325 | #define CSCD_BSW 0x00010000 | |
| 326 | #define CSCD_MASK 0x0000fff0 | |
| 327 | #define CSCD_RO 0x00000008 | |
| 328 | #define CSCD_WAIT 0x00000007 | |
| 329 | ||
| 330 | #define PLLCR_PIXCLK_SEL 0x3800 | |
| 331 | #define PLLCR_PIXCLK_SEL_DIV2 0x0000 | |
| 332 | #define PLLCR_PIXCLK_SEL_DIV4 0x0800 | |
| 333 | #define PLLCR_PIXCLK_SEL_DIV8 0x1000 | |
| 334 | #define PLLCR_PIXCLK_SEL_DIV16 0x1800 | |
| 335 | #define PLLCR_PIXCLK_SEL_DIV1_0 0x2000 | |
| 336 | #define PLLCR_PIXCLK_SEL_DIV1_1 0x2800 | |
| 337 | #define PLLCR_PIXCLK_SEL_DIV1_2 0x3000 | |
| 338 | #define PLLCR_PIXCLK_SEL_DIV1_3 0x3800 | |
| 339 | #define PLLCR_SYSCLK_SEL 0x0700 | |
| 340 | #define PLLCR_SYSCLK_SEL_DIV2 0x0000 | |
| 341 | #define PLLCR_SYSCLK_SEL_DIV4 0x0100 | |
| 342 | #define PLLCR_SYSCLK_SEL_DIV8 0x0200 | |
| 343 | #define PLLCR_SYSCLK_SEL_DIV16 0x0300 | |
| 344 | #define PLLCR_SYSCLK_SEL_DIV1_0 0x0400 | |
| 345 | #define PLLCR_SYSCLK_SEL_DIV1_1 0x0500 | |
| 346 | #define PLLCR_SYSCLK_SEL_DIV1_2 0x0600 | |
| 347 | #define PLLCR_SYSCLK_SEL_DIV1_3 0x0700 | |
| 348 | #define PLLCR_CLKEN 0x0010 | |
| 349 | #define PLLCR_DISPLL 0x0008 | |
| 350 | ||
| 351 | #define PLLFSR_CLK32 0x8000 | |
| 352 | #define PLLFSR_PROT 0x4000 | |
| 353 | #define PLLFSR_QCNT 0x0f00 | |
| 354 | #define PLLFSR_PCNT 0x00ff | |
| 355 | ||
| 356 | #define PCTLR_PC_EN 0x80 | |
| 357 | #define PCTLR_STOP 0x40 | |
| 358 | #define PCTLR_WIDTH 0x1f | |
| 359 | ||
| 360 | #define CXP_CC 0xc000 | |
| 361 | #define CXP_CC_XLU 0x0000 | |
| 362 | #define CXP_CC_BLACK 0x4000 | |
| 363 | #define CXP_CC_INVERSE 0x8000 | |
| 364 | #define CXP_CC_INVALID 0xc000 | |
| 365 | #define CXP_MASK 0x03ff | |
| 366 | ||
| 367 | #define CYP_MASK 0x01ff | |
| 368 | ||
| 369 | #define CWCH_CW 0x1f00 | |
| 370 | #define CWCH_CH 0x001f | |
| 371 | ||
| 372 | #define BLKC_BKEN 0x80 | |
| 373 | #define BLKC_BD 0x7f | |
| 374 | ||
| 375 | #define LPICF_PBSIZ 0x06 | |
| 376 | #define LPICF_PBSIZ_1 0x00 | |
| 377 | #define LPICF_PBSIZ_2 0x02 | |
| 378 | #define LPICF_PBSIZ_4 0x04 | |
| 379 | #define LPICF_PBSIZ_INVALID 0x06 | |
| 380 | ||
| 381 | #define LPOLCF_LCKPOL 0x08 | |
| 382 | #define LPOLCF_FLMPOL 0x04 | |
| 383 | #define LPOLCF_LPPOL 0x02 | |
| 384 | #define LPOLCF_PIXPOL 0x01 | |
| 385 | ||
| 386 | #define LACDRC_MASK 0x0f | |
| 387 | ||
| 388 | #define LPXCD_MASK 0x3f | |
| 389 | ||
| 390 | #define LCKCON_LCDC_EN 0x80 | |
| 391 | #define LCKCON_LCDON 0x80 | |
| 392 | #define LCKCON_DMA16 0x40 | |
| 393 | #define LCKCON_WS 0x30 | |
| 394 | #define LCKCON_WS_1 0x00 | |
| 395 | #define LCKCON_WS_2 0x10 | |
| 396 | #define LCKCON_WS_3 0x20 | |
| 397 | #define LCKCON_WS_4 0x30 | |
| 398 | #define LCKCON_DWIDTH 0x02 | |
| 399 | #define LCKCON_PCDS 0x01 | |
| 400 | ||
| 401 | #define LBAR_MASK 0x7f | |
| 402 | ||
| 403 | #define LPOSR_BOS 0x08 | |
| 404 | #define LPOSR_POS 0x07 | |
| 405 | ||
| 406 | #define LFRCM_XMOD 0xf0 | |
| 407 | #define LFRCM_YMOD 0x0f | |
| 408 | ||
| 409 | #define LGPMR_PAL1 0x7000 | |
| 410 | #define LGPMR_PAL0 0x0700 | |
| 411 | #define LGPMR_PAL3 0x0070 | |
| 412 | #define LGPMR_PAL2 0x0007 | |
| 413 | ||
| 414 | #define RTCHMSR_HOURS 0x1f000000 | |
| 415 | #define RTCHMSR_MINUTES 0x003f0000 | |
| 416 | #define RTCHMSR_SECONDS 0x0000003f | |
| 417 | ||
| 418 | #define RTCCTL_38_4 0x0020 | |
| 419 | #define RTCCTL_ENABLE 0x0080 | |
| 420 | ||
| 421 | #define RTCINT_STOPWATCH 0x0001 | |
| 422 | #define RTCINT_MINUTE 0x0002 | |
| 423 | #define RTCINT_ALARM 0x0004 | |
| 424 | #define RTCINT_DAY 0x0008 | |
| 425 | #define RTCINT_SECOND 0x0010 | |
| 426 | ||
| 427 | #define RTCSTPWTCH_MASK 0x003f | |
| 428 | ||
| 429 | #define TCTL_TEN 0x0001 | |
| 430 | #define TCTL_TEN_ENABLE 0x0001 | |
| 431 | #define TCTL_CLKSOURCE 0x000e | |
| 432 | #define TCTL_CLKSOURCE_STOP 0x0000 | |
| 433 | #define TCTL_CLKSOURCE_SYSCLK 0x0002 | |
| 434 | #define TCTL_CLKSOURCE_SYSCLK16 0x0004 | |
| 435 | #define TCTL_CLKSOURCE_TIN 0x0006 | |
| 436 | #define TCTL_CLKSOURCE_32KHZ4 0x0008 | |
| 437 | #define TCTL_CLKSOURCE_32KHZ5 0x000a | |
| 438 | #define TCTL_CLKSOURCE_32KHZ6 0x000c | |
| 439 | #define TCTL_CLKSOURCE_32KHZ7 0x000e | |
| 440 | #define TCTL_IRQEN 0x0010 | |
| 441 | #define TCTL_IRQEN_ENABLE 0x0010 | |
| 442 | #define TCTL_OM 0x0020 | |
| 443 | #define TCTL_OM_ACTIVELOW 0x0000 | |
| 444 | #define TCTL_OM_TOGGLE 0x0020 | |
| 445 | #define TCTL_CAPTURE 0x00c0 | |
| 446 | #define TCTL_CAPTURE_NOINT 0x0000 | |
| 447 | #define TCTL_CAPTURE_RISING 0x0040 | |
| 448 | #define TCTL_CAPTURE_FALLING 0x0080 | |
| 449 | #define TCTL_CAPTURE_BOTH 0x00c0 | |
| 450 | #define TCTL_FRR 0x0100 | |
| 451 | #define TCTL_FRR_RESTART 0x0000 | |
| 452 | #define TCTL_FRR_FREERUN 0x0100 | |
| 453 | ||
| 454 | #define TSTAT_COMP 0x0001 | |
| 455 | #define TSTAT_CAPT 0x0002 | |
| 456 | ||
| 457 | #define WCTLR_WDRST 0x0008 | |
| 458 | #define WCTLR_LOCK 0x0004 | |
| 459 | #define WCTLR_FI 0x0002 | |
| 460 | #define WCTLR_WDEN 0x0001 | |
| 461 | ||
| 462 | #define USTCNT_UART_EN 0x8000 | |
| 463 | #define USTCNT_RX_EN 0x4000 | |
| 464 | #define USTCNT_TX_EN 0x2000 | |
| 465 | #define USTCNT_RX_CLK_CONT 0x1000 | |
| 466 | #define USTCNT_PARITY_EN 0x0800 | |
| 467 | #define USTCNT_ODD_EVEN 0x0400 | |
| 468 | #define USTCNT_STOP_BITS 0x0200 | |
| 469 | #define USTCNT_8_7 0x0100 | |
| 470 | #define USTCNT_GPIO_DELTA_EN 0x0080 | |
| 471 | #define USTCNT_CTS_DELTA_EN 0x0040 | |
| 472 | #define USTCNT_RX_FULL_EN 0x0020 | |
| 473 | #define USTCNT_RX_HALF_EN 0x0010 | |
| 474 | #define USTCNT_RX_RDY_EN 0x0008 | |
| 475 | #define USTCNT_TX_EMPTY_EN 0x0004 | |
| 476 | #define USTCNT_TX_HALF_EN 0x0002 | |
| 477 | #define USTCNT_TX_AVAIL_EN 0x0001 | |
| 478 | ||
| 479 | #define UBAUD_GPIO_DELTA 0x8000 | |
| 480 | #define UBAUD_GPIO 0x4000 | |
| 481 | #define UBAUD_GPIO_DIR 0x2000 | |
| 482 | #define UBAUD_GPIO_SRC 0x1000 | |
| 483 | #define UBAUD_BAUD_SRC 0x0800 | |
| 484 | #define UBAUD_DIVIDE 0x0700 | |
| 485 | #define UBAUD_DIVIDE_1 0x0000 | |
| 486 | #define UBAUD_DIVIDE_2 0x0100 | |
| 487 | #define UBAUD_DIVIDE_4 0x0200 | |
| 488 | #define UBAUD_DIVIDE_8 0x0300 | |
| 489 | #define UBAUD_DIVIDE_16 0x0400 | |
| 490 | #define UBAUD_DIVIDE_32 0x0500 | |
| 491 | #define UBAUD_DIVIDE_64 0x0600 | |
| 492 | #define UBAUD_DIVIDE_128 0x0700 | |
| 493 | #define UBAUD_PRESCALER 0x00ff | |
| 494 | ||
| 495 | #define URX_FIFO_FULL 0x8000 | |
| 496 | #define URX_FIFO_HALF 0x4000 | |
| 497 | #define URX_DATA_READY 0x2000 | |
| 498 | #define URX_OVRUN 0x0800 | |
| 499 | #define URX_FRAME_ERROR 0x0400 | |
| 500 | #define URX_BREAK 0x0200 | |
| 501 | #define URX_PARITY_ERROR 0x0100 | |
| 502 | ||
| 503 | #define UTX_FIFO_EMPTY 0x8000 | |
| 504 | #define UTX_FIFO_HALF 0x4000 | |
| 505 | #define UTX_TX_AVAIL 0x2000 | |
| 506 | #define UTX_SEND_BREAK 0x1000 | |
| 507 | #define UTX_IGNORE_CTS 0x0800 | |
| 508 | #define UTX_CTS_STATUS 0x0200 | |
| 509 | #define UTX_CTS_DELTA 0x0100 | |
| 510 | ||
| 511 | #define UMISC_CLK_SRC 0x4000 | |
| 512 | #define UMISC_FORCE_PERR 0x2000 | |
| 513 | #define UMISC_LOOP 0x1000 | |
| 514 | #define UMISC_RTS_CONT 0x0080 | |
| 515 | #define UMISC_RTS 0x0040 | |
| 516 | #define UMISC_IRDA_ENABLE 0x0020 | |
| 517 | #define UMISC_IRDA_LOOP 0x0010 | |
| 518 | ||
| 519 | #define SPIS_SPIS_IRQ 0x8000 | |
| 520 | #define SPIS_IRQEN 0x4000 | |
| 521 | #define SPIS_ENPOL 0x2000 | |
| 522 | #define SPIS_DATA_RDY 0x1000 | |
| 523 | #define SPIS_OVRWR 0x0800 | |
| 524 | #define SPIS_PHA 0x0400 | |
| 525 | #define SPIS_POL 0x0200 | |
| 526 | #define SPIS_SPISEN 0x0100 | |
| 527 | ||
| 528 | #define SPIM_CLOCK_COUNT 0x000f | |
| 529 | #define SPIM_POL 0x0010 | |
| 530 | #define SPIM_POL_HIGH 0x0000 | |
| 531 | #define SPIM_POL_LOW 0x0010 | |
| 532 | #define SPIM_PHA 0x0020 | |
| 533 | #define SPIM_PHA_NORMAL 0x0000 | |
| 534 | #define SPIM_PHA_OPPOSITE 0x0020 | |
| 535 | #define SPIM_IRQEN 0x0040 | |
| 536 | #define SPIM_SPIMIRQ 0x0080 | |
| 537 | #define SPIM_XCH 0x0100 | |
| 538 | #define SPIM_XCH_IDLE 0x0000 | |
| 539 | #define SPIM_XCH_INIT 0x0100 | |
| 540 | #define SPIM_SPMEN 0x0200 | |
| 541 | #define SPIM_SPMEN_DISABLE 0x0000 | |
| 542 | #define SPIM_SPMEN_ENABLE 0x0200 | |
| 543 | #define SPIM_RATE 0xe000 | |
| 544 | #define SPIM_RATE_4 0x0000 | |
| 545 | #define SPIM_RATE_8 0x2000 | |
| 546 | #define SPIM_RATE_16 0x4000 | |
| 547 | #define SPIM_RATE_32 0x6000 | |
| 548 | #define SPIM_RATE_64 0x8000 | |
| 549 | #define SPIM_RATE_128 0xa000 | |
| 550 | #define SPIM_RATE_256 0xc000 | |
| 551 | #define SPIM_RATE_512 0xe000 | |
| 552 | ||
| 553 | #define PWMC_PWMIRQ 0x8000 | |
| 554 | #define PWMC_IRQEN 0x4000 | |
| 555 | #define PWMC_LOAD 0x0100 | |
| 556 | #define PWMC_PIN 0x0080 | |
| 557 | #define PWMC_POL 0x0040 | |
| 558 | #define PWMC_PWMEN 0x0010 | |
| 559 | #define PWMC_CLKSEL 0x0007 | |
| 560 | ||
| 561 | INLINE mc68328_t* mc68328_get_safe_token( device_t *device ) | |
| 562 | { | |
| 563 | assert( device != NULL ); | |
| 564 | assert( device->type() == MC68328 ); | |
| 565 | return (mc68328_t*) downcast<mc68328_device *>(device)->token(); | |
| 566 | } | |
| 567 | ||
| 568 | #endif // __MC68328_PRIVATE_H_ |
| Added: svn:eol-style + native Added: svn:mime-type + text/plain |
| r0 | r21685 | |
|---|---|---|
| 1 | /***************************************************************************** | |
| 2 | * | |
| 3 | * machine/74145.c | |
| 4 | * | |
| 5 | * BCD-to-Decimal decoder | |
| 6 | * | |
| 7 | * __ __ | |
| 8 | * 0-| v |-VCC | |
| 9 | * 1-| |-A | |
| 10 | * 2-| |-B | |
| 11 | * 3-| |-C | |
| 12 | * 4-| |-D | |
| 13 | * 5-| |-9 | |
| 14 | * 6-| |-8 | |
| 15 | * GND-|_____|-7 | |
| 16 | * | |
| 17 | * | |
| 18 | * Truth table | |
| 19 | * _______________________________ | |
| 20 | * | Inputs | Outputs | | |
| 21 | * | D C B A | 0 1 2 3 4 5 6 7 8 9 | | |
| 22 | * |-------------------------------| | |
| 23 | * | L L L L | L H H H H H H H H H | | |
| 24 | * | L L L H | H L H H H H H H H H | | |
| 25 | * | L L H L | H H L H H H H H H H | | |
| 26 | * | L L H H | H H H L H H H H H H | | |
| 27 | * | L H L L | H H H H L H H H H H | | |
| 28 | * |-------------------------------| | |
| 29 | * | L H L H | H H H H H L H H H H | | |
| 30 | * | L H H L | H H H H H H L H H H | | |
| 31 | * | L H H H | H H H H H H H L H H | | |
| 32 | * | H L L L | H H H H H H H H L H | | |
| 33 | * | H L L H | H H H H H H H H H L | | |
| 34 | * |-------------------------------| | |
| 35 | * | H L H L | H H H H H H H H H H | | |
| 36 | * | H L H H | H H H H H H H H H H | | |
| 37 | * | H H L L | H H H H H H H H H H | | |
| 38 | * | H H L H | H H H H H H H H H H | | |
| 39 | * | H H H L | H H H H H H H H H H | | |
| 40 | * | H H H H | H H H H H H H H H H | | |
| 41 | * ------------------------------- | |
| 42 | * | |
| 43 | ****************************************************************************/ | |
| 44 | ||
| 45 | #include "emu.h" | |
| 46 | #include "74145.h" | |
| 47 | #include "coreutil.h" | |
| 48 | ||
| 49 | /***************************************************************************** | |
| 50 | GLOBAL VARIABLES | |
| 51 | *****************************************************************************/ | |
| 52 | ||
| 53 | const ttl74145_interface default_ttl74145 = | |
| 54 | { | |
| 55 | DEVCB_NULL, | |
| 56 | DEVCB_NULL, | |
| 57 | DEVCB_NULL, | |
| 58 | DEVCB_NULL, | |
| 59 | DEVCB_NULL, | |
| 60 | DEVCB_NULL, | |
| 61 | DEVCB_NULL, | |
| 62 | DEVCB_NULL, | |
| 63 | DEVCB_NULL, | |
| 64 | DEVCB_NULL | |
| 65 | }; | |
| 66 | ||
| 67 | ||
| 68 | const device_type TTL74145 = &device_creator<ttl74145_device>; | |
| 69 | ||
| 70 | /*************************************************************************** | |
| 71 | DEVICE INTERFACE | |
| 72 | ***************************************************************************/ | |
| 73 | //------------------------------------------------- | |
| 74 | // ttl74145_device - constructor | |
| 75 | //------------------------------------------------- | |
| 76 | ||
| 77 | ttl74145_device::ttl74145_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) | |
| 78 | : device_t(mconfig, TTL74145, "TTL74145", tag, owner, clock) | |
| 79 | , m_number(0) | |
| 80 | { | |
| 81 | } | |
| 82 | ||
| 83 | ||
| 84 | //------------------------------------------------- | |
| 85 | // device_start - device-specific startup | |
| 86 | //------------------------------------------------- | |
| 87 | ||
| 88 | void ttl74145_device::device_start() | |
| 89 | { | |
| 90 | /* resolve callbacks */ | |
| 91 | m_output_line_0_func.resolve(m_output_line_0_cb, *this); | |
| 92 | m_output_line_1_func.resolve(m_output_line_1_cb, *this); | |
| 93 | m_output_line_2_func.resolve(m_output_line_2_cb, *this); | |
| 94 | m_output_line_3_func.resolve(m_output_line_3_cb, *this); | |
| 95 | m_output_line_4_func.resolve(m_output_line_4_cb, *this); | |
| 96 | m_output_line_5_func.resolve(m_output_line_5_cb, *this); | |
| 97 | m_output_line_6_func.resolve(m_output_line_6_cb, *this); | |
| 98 | m_output_line_7_func.resolve(m_output_line_7_cb, *this); | |
| 99 | m_output_line_8_func.resolve(m_output_line_8_cb, *this); | |
| 100 | m_output_line_9_func.resolve(m_output_line_9_cb, *this); | |
| 101 | ||
| 102 | // register for state saving | |
| 103 | save_item(NAME(m_number)); | |
| 104 | } | |
| 105 | ||
| 106 | //------------------------------------------------- | |
| 107 | // device_config_complete - perform any | |
| 108 | // operations now that the configuration is | |
| 109 | // complete | |
| 110 | //------------------------------------------------- | |
| 111 | ||
| 112 | void ttl74145_device::device_config_complete() | |
| 113 | { | |
| 114 | // inherit a copy of the static data | |
| 115 | const ttl74145_interface *intf = reinterpret_cast<const ttl74145_interface *>(static_config()); | |
| 116 | if (intf != NULL) | |
| 117 | *static_cast<ttl74145_interface *>(this) = *intf; | |
| 118 | ||
| 119 | // or initialize to defaults if none provided | |
| 120 | else | |
| 121 | { | |
| 122 | memset(&m_output_line_0_cb, 0, sizeof(m_output_line_0_cb)); | |
| 123 | memset(&m_output_line_1_cb, 0, sizeof(m_output_line_1_cb)); | |
| 124 | memset(&m_output_line_2_cb, 0, sizeof(m_output_line_2_cb)); | |
| 125 | memset(&m_output_line_3_cb, 0, sizeof(m_output_line_3_cb)); | |
| 126 | memset(&m_output_line_4_cb, 0, sizeof(m_output_line_4_cb)); | |
| 127 | memset(&m_output_line_5_cb, 0, sizeof(m_output_line_5_cb)); | |
| 128 | memset(&m_output_line_6_cb, 0, sizeof(m_output_line_6_cb)); | |
| 129 | memset(&m_output_line_7_cb, 0, sizeof(m_output_line_7_cb)); | |
| 130 | memset(&m_output_line_8_cb, 0, sizeof(m_output_line_8_cb)); | |
| 131 | memset(&m_output_line_9_cb, 0, sizeof(m_output_line_9_cb)); | |
| 132 | } | |
| 133 | } | |
| 134 | ||
| 135 | //------------------------------------------------- | |
| 136 | // device_start - device-specific reset | |
| 137 | //------------------------------------------------- | |
| 138 | ||
| 139 | void ttl74145_device::device_reset() | |
| 140 | { | |
| 141 | m_number = 0; | |
| 142 | } | |
| 143 | ||
| 144 | /*************************************************************************** | |
| 145 | IMPLEMENTATION | |
| 146 | ***************************************************************************/ | |
| 147 | ||
| 148 | void ttl74145_device::write(UINT8 data) | |
| 149 | { | |
| 150 | /* decode number */ | |
| 151 | UINT16 new_number = bcd_2_dec(data & 0x0f); | |
| 152 | ||
| 153 | /* call output callbacks if the number changed */ | |
| 154 | if (new_number != m_number) | |
| 155 | { | |
| 156 | m_output_line_0_func(new_number == 0); | |
| 157 | m_output_line_1_func(new_number == 1); | |
| 158 | m_output_line_2_func(new_number == 2); | |
| 159 | m_output_line_3_func(new_number == 3); | |
| 160 | m_output_line_4_func(new_number == 4); | |
| 161 | m_output_line_5_func(new_number == 5); | |
| 162 | m_output_line_6_func(new_number == 6); | |
| 163 | m_output_line_7_func(new_number == 7); | |
| 164 | m_output_line_8_func(new_number == 8); | |
| 165 | m_output_line_9_func(new_number == 9); | |
| 166 | } | |
| 167 | ||
| 168 | /* update state */ | |
| 169 | m_number = new_number; | |
| 170 | } | |
| 171 | ||
| 172 | ||
| 173 | UINT16 ttl74145_device::read() | |
| 174 | { | |
| 175 | return (1 << m_number) & 0x3ff; | |
| 176 | } |
| Added: svn:eol-style + native Added: svn:mime-type + text/plain |
| r0 | r21685 | |
|---|---|---|
| 1 | /*************************************************************************** | |
| 2 | ||
| 3 | TTL74145 | |
| 4 | ||
| 5 | BCD-to-Decimal decoder | |
| 6 | ||
| 7 | ***************************************************************************/ | |
| 8 | ||
| 9 | #ifndef __TTL74145_H__ | |
| 10 | #define __TTL74145_H__ | |
| 11 | ||
| 12 | //************************************************************************** | |
| 13 | // INTERFACE CONFIGURATION MACROS | |
| 14 | //************************************************************************** | |
| 15 | #define MCFG_TTL74145_ADD(_tag, _intf) \ | |
| 16 | MCFG_DEVICE_ADD(_tag, TTL74145, 0) \ | |
| 17 | MCFG_DEVICE_CONFIG(_intf) | |
| 18 | ||
| 19 | ||
| 20 | //************************************************************************** | |
| 21 | // TYPE DEFINITIONS | |
| 22 | //************************************************************************** | |
| 23 | ||
| 24 | // ======================> ttl74145_interface | |
| 25 | ||
| 26 | struct ttl74145_interface | |
| 27 | { | |
| 28 | devcb_write_line m_output_line_0_cb; | |
| 29 | devcb_write_line m_output_line_1_cb; | |
| 30 | devcb_write_line m_output_line_2_cb; | |
| 31 | devcb_write_line m_output_line_3_cb; | |
| 32 | devcb_write_line m_output_line_4_cb; | |
| 33 | devcb_write_line m_output_line_5_cb; | |
| 34 | devcb_write_line m_output_line_6_cb; | |
| 35 | devcb_write_line m_output_line_7_cb; | |
| 36 | devcb_write_line m_output_line_8_cb; | |
| 37 | devcb_write_line m_output_line_9_cb; | |
| 38 | }; | |
| 39 | ||
| 40 | // ======================> ttl74145_device | |
| 41 | ||
| 42 | class ttl74145_device : public device_t, | |
| 43 | public ttl74145_interface | |
| 44 | { | |
| 45 | public: | |
| 46 | // construction/destruction | |
| 47 | ttl74145_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); | |
| 48 | ||
| 49 | UINT16 read(); | |
| 50 | void write(UINT8 data); | |
| 51 | protected: | |
| 52 | // device-level overrides | |
| 53 | virtual void device_start(); | |
| 54 | virtual void device_reset(); | |
| 55 | virtual void device_config_complete(); | |
| 56 | ||
| 57 | private: | |
| 58 | devcb_resolved_write_line m_output_line_0_func; | |
| 59 | devcb_resolved_write_line m_output_line_1_func; | |
| 60 | devcb_resolved_write_line m_output_line_2_func; | |
| 61 | devcb_resolved_write_line m_output_line_3_func; | |
| 62 | devcb_resolved_write_line m_output_line_4_func; | |
| 63 | devcb_resolved_write_line m_output_line_5_func; | |
| 64 | devcb_resolved_write_line m_output_line_6_func; | |
| 65 | devcb_resolved_write_line m_output_line_7_func; | |
| 66 | devcb_resolved_write_line m_output_line_8_func; | |
| 67 | devcb_resolved_write_line m_output_line_9_func; | |
| 68 | ||
| 69 | /* decoded number */ | |
| 70 | UINT16 m_number; | |
| 71 | }; | |
| 72 | ||
| 73 | // device type definition | |
| 74 | extern const device_type TTL74145; | |
| 75 | ||
| 76 | //************************************************************************** | |
| 77 | // DEFAULT INTERFACES | |
| 78 | //************************************************************************** | |
| 79 | ||
| 80 | extern const ttl74145_interface default_ttl74145; | |
| 81 | ||
| 82 | ||
| 83 | #endif /* TTL74145 */ |
| Added: svn:mime-type + text/plain Added: svn:eol-style + native |
| r0 | r21685 | |
|---|---|---|
| 1 | /********************************************************************** | |
| 2 | ||
| 3 | Copyright (C) Antoine Mine' 2006 | |
| 4 | ||
| 5 | Motorola 6854 emulation. | |
| 6 | ||
| 7 | The MC6854 chip is an Advanced Data-Link Controller (ADLC). | |
| 8 | It provides a high-level network interface that can transimit frames with | |
| 9 | arbitrary data and address length, and is compatible with the following | |
| 10 | standards: | |
| 11 | - ADCCP (Advanced Data Communication Control Procedure) | |
| 12 | - HDLC (High-Level Data-Link Control) | |
| 13 | - SDLC (Synchronous Data-Link Control) | |
| 14 | It is designed to be interfaced with a M6800-family CPU. | |
| 15 | ||
| 16 | It is used in the "Nano-network" extension of the Thomson computers to | |
| 17 | link up to 32 computers at 500 Kbps. | |
| 18 | Many networks involving one PC server and several MO5 or TO7/70 computers | |
| 19 | were build in French schools in the 1980's to teach computer science. | |
| 20 | ||
| 21 | TODO: | |
| 22 | - CRC | |
| 23 | - DMA mode | |
| 24 | - loop mode | |
| 25 | - status prioritization | |
| 26 | - NRZI vs. NRZ coding | |
| 27 | - FD output | |
| 28 | ||
| 29 | **********************************************************************/ | |
| 30 | ||
| 31 | ||
| 32 | #include "emu.h" | |
| 33 | #include "mc6854.h" | |
| 34 | ||
| 35 | ||
| 36 | ||
| 37 | /******************* parameters ******************/ | |
| 38 | ||
| 39 | ||
| 40 | ||
| 41 | #define VERBOSE 0 | |
| 42 | ||
| 43 | ||
| 44 | #define MAX_FRAME_LENGTH 65536 | |
| 45 | /* arbitrary value, you may need to enlarge it if you get truncated frames */ | |
| 46 | ||
| 47 | #define FIFO_SIZE 3 | |
| 48 | /* hardcoded size of the 6854 FIFO (this is a hardware limit) */ | |
| 49 | ||
| 50 | #define FLAG 0x7e | |
| 51 | /* flag value, as defined by HDLC protocol: 01111110 */ | |
| 52 | ||
| 53 | #define BIT_LENGTH attotime::from_hz( 500000 ) | |
| 54 | ||
| 55 | ||
| 56 | ||
| 57 | /******************* internal chip data structure ******************/ | |
| 58 | ||
| 59 | ||
| 60 | struct mc6854_t | |
| 61 | { | |
| 62 | devcb_resolved_write_line out_irq_func; | |
| 63 | devcb_resolved_read_line in_rxd_func; | |
| 64 | devcb_resolved_write_line out_txd_func; | |
| 65 | devcb_resolved_write_line out_rts_func; | |
| 66 | devcb_resolved_write_line out_dtr_func; | |
| 67 | ||
| 68 | /* interface */ | |
| 69 | const mc6854_interface* iface; | |
| 70 | ||
| 71 | /* registers */ | |
| 72 | UINT8 cr1, cr2, cr3, cr4; /* control registers */ | |
| 73 | UINT8 sr1, sr2; /* status registers */ | |
| 74 | ||
| 75 | UINT8 cts, dcd; | |
| 76 | ||
| 77 | /* transmit state */ | |
| 78 | UINT8 tstate; | |
| 79 | UINT16 tfifo[FIFO_SIZE]; /* X x 8-bit FIFO + full & last marker bits */ | |
| 80 | UINT8 tones; /* counter for zero-insertion */ | |
| 81 | emu_timer *ttimer; /* when to ask for more data */ | |
| 82 | ||
| 83 | /* receive state */ | |
| 84 | UINT8 rstate; | |
| 85 | UINT32 rreg; /* shift register */ | |
| 86 | UINT8 rones; /* count '1 bits */ | |
| 87 | UINT8 rsize; /* bits in the shift register */ | |
| 88 | UINT16 rfifo[FIFO_SIZE]; /* X x 8-bit FIFO + full & addr marker bits */ | |
| 89 | ||
| 90 | /* frame-based interface*/ | |
| 91 | UINT8 frame[MAX_FRAME_LENGTH]; | |
| 92 | UINT32 flen, fpos; | |
| 93 | ||
| 94 | }; | |
| 95 | ||
| 96 | /* meaning of tstate / rtate: | |
| 97 | 0 = idle / waiting for frame flag | |
| 98 | 1 = flag sync | |
| 99 | 2 = 8-bit address field(s) | |
| 100 | 3-4 = 8-bit control field(s) | |
| 101 | 5 = 8-bit logical control field(s) | |
| 102 | 6 = variable-length data field(s) | |
| 103 | */ | |
| 104 | ||
| 105 | ||
| 106 | ||
| 107 | /******************* utility function and macros ********************/ | |
| 108 | ||
| 109 | ||
| 110 | ||
| 111 | #define LOG(x) do { if (VERBOSE) logerror x; } while (0) | |
| 112 | ||
| 113 | ||
| 114 | ||
| 115 | /* control register 1 */ | |
| 116 | ||
| 117 | #define AC ( mc6854->cr1 & 1 ) | |
| 118 | #define FCTDRA ( mc6854->cr2 & 8 ) | |
| 119 | /* extra register select bits */ | |
| 120 | ||
| 121 | #define RRESET ( mc6854->cr1 & 0x40 ) | |
| 122 | #define TRESET ( mc6854->cr1 & 0x80 ) | |
| 123 | /* transmit / reset condition */ | |
| 124 | ||
| 125 | #define RIE ( mc6854->cr1 & 2 ) | |
| 126 | #define TIE ( mc6854->cr1 & 4 ) | |
| 127 | /* interrupt enable */ | |
| 128 | ||
| 129 | #define DISCONTINUE ( mc6854->cr1 & 0x20 ) | |
| 130 | /* discontinue received frame */ | |
| 131 | ||
| 132 | ||
| 133 | ||
| 134 | /* control register 2 */ | |
| 135 | ||
| 136 | #define PSE ( mc6854->cr2 & 1 ) | |
| 137 | /* prioritize status bits (TODO) */ | |
| 138 | ||
| 139 | #define TWOBYTES ( mc6854->cr2 & 2 ) | |
| 140 | /* two-bytes mode */ | |
| 141 | ||
| 142 | #define FMIDLE ( mc6854->cr2 & 4 ) | |
| 143 | /* flag time fill (vs. mark idle) */ | |
| 144 | ||
| 145 | #define TLAST ( mc6854->cr2 & 0x10 ) | |
| 146 | /* transmit last byte of frame */ | |
| 147 | ||
| 148 | #define RTS ( mc6854->cr2 & 0x80 ) | |
| 149 | /* request-to-send */ | |
| 150 | ||
| 151 | ||
| 152 | ||
| 153 | /* control register 3 */ | |
| 154 | ||
| 155 | #define LCF ( mc6854->cr3 & 1 ) | |
| 156 | /* logical control field select */ | |
| 157 | ||
| 158 | #define CEX ( mc6854->cr3 & 2 ) | |
| 159 | /* control field is 16 bits instead of 8 */ | |
| 160 | ||
| 161 | #define AEX ( mc6854->cr3 & 4 ) | |
| 162 | /* extended address mode (vs normal 8-bit address mode) */ | |
| 163 | ||
| 164 | #define IDL0 ( mc6854->cr3 & 8 ) | |
| 165 | /* idle condition begins with a '0' instead of a '1" */ | |
| 166 | ||
| 167 | #define FDSE ( mc6854->cr3 & 0x10 ) | |
| 168 | /* enable the flag detect status in SR1 */ | |
| 169 | ||
| 170 | #define LOOP ( mc6854->cr3 & 0x20 ) | |
| 171 | /* loop mode */ | |
| 172 | ||
| 173 | #define TST ( mc6854->cr3 & 0x40 ) | |
| 174 | /* test mode (or go active on poll) */ | |
| 175 | ||
| 176 | #define DTR ( mc6854->cr3 & 0x80 ) | |
| 177 | /* data-transmit-ready (or loop on-line control) */ | |
| 178 | ||
| 179 | ||
| 180 | ||
| 181 | /* control register 4 */ | |
| 182 | ||
| 183 | #define TWOINTER ( mc6854->cr4 & 1 ) | |
| 184 | /* both an openning and a closing inter-frame are sent */ | |
| 185 | ||
| 186 | static const int word_length[4] = { 5, 6, 7, 8 }; | |
| 187 | #define TWL word_length[ ( mc6854->cr4 >> 1 ) & 3 ] | |
| 188 | #define RWL word_length[ ( mc6854->cr4 >> 3 ) & 3 ] | |
| 189 | /* transmit / receive word length */ | |
| 190 | ||
| 191 | #define ABT ( mc6854->cr4 & 0x20 ) | |
| 192 | /* aborts */ | |
| 193 | ||
| 194 | #define ABTEX ( mc6854->cr4 & 0x40 ) | |
| 195 | /* abort generates 16 '1' bits instead of 8 */ | |
| 196 | ||
| 197 | #define NRZ ( mc6854->cr4 & 0x80 ) | |
| 198 | /* zero complement / non-zero complement data format */ | |
| 199 | ||
| 200 | ||
| 201 | ||
| 202 | /* status register 1 */ | |
| 203 | #define RDA 0x01 /* receiver data available */ | |
| 204 | #define S2RQ 0x02 /* status register #2 read request */ | |
| 205 | #define FD 0x04 /* flag detect */ | |
| 206 | #define CTS 0x10 /* clear-to-send */ | |
| 207 | #define TU 0x20 /* transmitter underrun */ | |
| 208 | #define TDRA 0x40 /* transmitter data register available */ | |
| 209 | #define IRQ 0x80 /* interrupt request */ | |
| 210 | ||
| 211 | ||
| 212 | /* status register 2 */ | |
| 213 | #define AP 0x01 /* address present */ | |
| 214 | #define FV 0x02 /* frame valid */ | |
| 215 | #define RIDLE 0x04 /* receiver idle */ | |
| 216 | #define RABT 0x08 /* receiver abort */ | |
| 217 | #define ERR 0x10 /* invalid frame error */ | |
| 218 | #define DCD 0x20 /* data carrier detect (ignored) */ | |
| 219 | #define OVRN 0x40 /* receiver overrun */ | |
| 220 | #define RDA2 0x80 /* copy of RDA */ | |
| 221 | ||
| 222 | ||
| 223 | ||
| 224 | INLINE mc6854_t* get_safe_token( device_t *device ) | |
| 225 | { | |
| 226 | assert( device != NULL ); | |
| 227 | assert( device->type() == MC6854 ); | |
| 228 | return (mc6854_t*) downcast<mc6854_device *>(device)->token(); | |
| 229 | } | |
| 230 | ||
| 231 | ||
| 232 | /*********************** transmit ***********************/ | |
| 233 | ||
| 234 | ||
| 235 | ||
| 236 | /* MC6854 fills bit queue */ | |
| 237 | static void mc6854_send_bits( device_t *device, UINT32 data, int len, int zi ) | |
| 238 | { | |
| 239 | mc6854_t* mc6854 = get_safe_token( device ); | |
| 240 | attotime expire; | |
| 241 | int i; | |
| 242 | if ( zi ) | |
| 243 | { | |
| 244 | /* zero-insertion mode */ | |
| 245 | UINT32 d = 0; | |
| 246 | int l = 0; | |
| 247 | for ( i = 0; i < len; i++, data >>= 1, l++ ) | |
| 248 | { | |
| 249 | if ( data & 1 ) | |
| 250 | { | |
| 251 | d |= 1 << l; | |
| 252 | mc6854->tones++; | |
| 253 | if ( mc6854->tones == 5 ) | |
| 254 | { | |
| 255 | /* insert a '0' after 5 consecutive '1" */ | |
| 256 | mc6854->tones = 0; | |
| 257 | l++; | |
| 258 | } | |
| 259 | } | |
| 260 | else | |
| 261 | mc6854->tones = 0; | |
| 262 | } | |
| 263 | data = d; | |
| 264 | len = l; | |
| 265 | } | |
| 266 | else | |
| 267 | mc6854->tones = 0; | |
| 268 | ||
| 269 | /* send bits */ | |
| 270 | if ( !mc6854->out_txd_func.isnull() ) | |
| 271 | { | |
| 272 | for ( i = 0; i < len; i++, data >>= 1 ) | |
| 273 | mc6854->out_txd_func( data & 1 ); | |
| 274 | } | |
| 275 | ||
| 276 | /* schedule when to ask the MC6854 for more bits */ | |
| 277 | expire = mc6854->ttimer ->remaining( ); | |
| 278 | if ( expire== attotime::never ) | |
| 279 | expire = attotime::zero; | |
| 280 | mc6854->ttimer->reset( expire + (BIT_LENGTH * len)); | |
| 281 | } | |
| 282 | ||
| 283 | ||
| 284 | ||
| 285 | /* CPU push -> tfifo[0] -> ... -> tfifo[FIFO_SIZE-1] -> pop */ | |
| 286 | static void mc6854_tfifo_push( device_t *device, UINT8 data ) | |
| 287 | { | |
| 288 | mc6854_t* mc6854 = get_safe_token( device ); | |
| 289 | int i; | |
| 290 | ||
| 291 | if ( TRESET ) | |
| 292 | return; | |
| 293 | ||
| 294 | /* push towards the rightmost free entry */ | |
| 295 | for ( i = FIFO_SIZE - 1; i >= 0; i-- ) | |
| 296 | { | |
| 297 | if ( ! ( mc6854->tfifo[ i ] & 0x100 ) ) | |
| 298 | break; | |
| 299 | } | |
| 300 | ||
| 301 | if ( i >= 0 ) | |
| 302 | mc6854->tfifo[ i ] = data | 0x100; | |
| 303 | else | |
| 304 | logerror( "%f mc6854_tfifo_push: FIFO overrun\n", device->machine().time().as_double() ); | |
| 305 | ||
| 306 | /* start frame, if needed */ | |
| 307 | if ( ! mc6854->tstate ) | |
| 308 | { | |
| 309 | LOG(( "%f mc6854_tfifo_push: start frame\n", device->machine().time().as_double() )); | |
| 310 | mc6854->tstate = 2; | |
| 311 | mc6854_send_bits( device, FLAG, 8, 0 ); | |
| 312 | } | |
| 313 | } | |
| 314 | ||
| 315 | ||
| 316 | ||
| 317 | /* CPU asks for normal frame termination */ | |
| 318 | static void mc6854_tfifo_terminate( device_t *device ) | |
| 319 | { | |
| 320 | mc6854_t* mc6854 = get_safe_token( device ); | |
| 321 | ||
| 322 | /* mark most recently pushed byte as the last one of the frame */ | |
| 323 | int i; | |
| 324 | for ( i = 0; i < FIFO_SIZE; i++ ) | |
| 325 | { | |
| 326 | if ( mc6854->tfifo[ i ] & 0x100 ) | |
| 327 | { | |
| 328 | mc6854->tfifo[ i ] |= 0x200; | |
| 329 | break; | |
| 330 | } | |
| 331 | } | |
| 332 | } | |
| 333 | ||
| 334 | ||
| 335 | ||
| 336 | /* call-back to refill the bit-stream from the FIFO */ | |
| 337 | static TIMER_CALLBACK(mc6854_tfifo_cb) | |
| 338 | { | |
| 339 | device_t* device = (device_t*) ptr; | |
| 340 | mc6854_t* mc6854 = get_safe_token( device ); | |
| 341 | int i, data = mc6854->tfifo[ FIFO_SIZE - 1 ]; | |
| 342 | ||
| 343 | if ( ! mc6854->tstate ) | |
| 344 | return; | |
| 345 | ||
| 346 | /* shift FIFO to the right */ | |
| 347 | for ( i = FIFO_SIZE - 1; i > 0; i-- ) | |
| 348 | mc6854->tfifo[ i ] = mc6854->tfifo[ i - 1 ]; | |
| 349 | mc6854->tfifo[ 0 ] = 0; | |
| 350 | ||
| 351 | if ( data & 0x100 ) | |
| 352 | { | |
| 353 | /* got data */ | |
| 354 | ||
| 355 | int blen = 8; | |
| 356 | ||
| 357 | switch ( mc6854->tstate ) | |
| 358 | { | |
| 359 | case 2: /* 8-bit address field */ | |
| 360 | if ( ( data & 1 ) || ( ! AEX ) ) | |
| 361 | mc6854->tstate = 3; | |
| 362 | LOG(( "%f mc6854_tfifo_cb: address field $%02X\n", machine.time().as_double(), data & 0xff )); | |
| 363 | break; | |
| 364 | ||
| 365 | case 3: /* 8-bit control field */ | |
| 366 | if ( CEX ) | |
| 367 | mc6854->tstate = 4; | |
| 368 | else if ( LCF ) | |
| 369 | mc6854->tstate = 5; | |
| 370 | else | |
| 371 | mc6854->tstate = 6; | |
| 372 | LOG(( "%f mc6854_tfifo_cb: control field $%02X\n", machine.time().as_double(), data & 0xff )); | |
| 373 | break; | |
| 374 | ||
| 375 | case 4: /* 8-bit extended control field (optional) */ | |
| 376 | if ( LCF ) | |
| 377 | mc6854->tstate = 5; | |
| 378 | else | |
| 379 | mc6854->tstate = 6; | |
| 380 | LOG(( "%f mc6854_tfifo_cb: control field $%02X\n", machine.time().as_double(), data & 0xff )); | |
| 381 | break; | |
| 382 | ||
| 383 | case 5: /* 8-bit logical control (optional) */ | |
| 384 | if ( ! ( data & 0x80 ) ) | |
| 385 | mc6854->tstate = 6; | |
| 386 | LOG(( "%f mc6854_tfifo_cb: logical control field $%02X\n", machine.time().as_double(), data & 0xff )); | |
| 387 | break; | |
| 388 | ||
| 389 | case 6: /* variable-length data */ | |
| 390 | blen = TWL; | |
| 391 | LOG(( "%f mc6854_tfifo_cb: data field $%02X, %i bits\n", machine.time().as_double(), data & 0xff, blen )); | |
| 392 | break; | |
| 393 | ||
| 394 | default: | |
| 395 | LOG(( "%f mc6854_tfifo_cb: state=%i\n", machine.time().as_double(), mc6854->tstate)); | |
| 396 | } | |
| 397 | ||
| 398 | if ( mc6854->flen < MAX_FRAME_LENGTH ) | |
| 399 | mc6854->frame[ mc6854->flen++ ] = data; | |
| 400 | else | |
| 401 | logerror( "mc6854_tfifo_cb: truncated frame, max=%i\n", MAX_FRAME_LENGTH ); | |
| 402 | ||
| 403 | mc6854_send_bits( device, data, blen, 1 ); | |
| 404 | } | |
| 405 | else | |
| 406 | { | |
| 407 | /* data underrun => abort */ | |
| 408 | logerror( "%f mc6854_tfifo_cb: FIFO underrun\n", machine.time().as_double() ); | |
| 409 | mc6854->sr1 |= TU; | |
| 410 | mc6854->tstate = 0; | |
| 411 | mc6854_send_bits( device, 0xffff, ABTEX ? 16 : 8, 0 ); | |
| 412 | mc6854->flen = 0; | |
| 413 | } | |
| 414 | ||
| 415 | /* close frame, if needed */ | |
| 416 | if ( data & 0x200 ) | |
| 417 | { | |
| 418 | int len = mc6854->flen; | |
| 419 | ||
| 420 | LOG(( "%f mc6854_tfifo_cb: end frame\n", machine.time().as_double() )); | |
| 421 | mc6854_send_bits( device, 0xdeadbeef, 16, 1 ); /* send check-sum: TODO */ | |
| 422 | mc6854_send_bits( device, FLAG, 8, 0 ); /* send closing flag */ | |
| 423 | ||
| 424 | if ( mc6854->tfifo[ FIFO_SIZE - 1 ] & 0x100 ) | |
| 425 | { | |
| 426 | /* re-open frame asap */ | |
| 427 | LOG(( "%f mc6854_tfifo_cb: start frame\n", machine.time().as_double() )); | |
| 428 | if ( TWOINTER ) | |
| 429 | mc6854_send_bits( device, FLAG, 8, 0 ); | |
| 430 | } | |
| 431 | else | |
| 432 | mc6854->tstate = 0; | |
| 433 | ||
| 434 | mc6854->flen = 0; | |
| 435 | if ( mc6854->iface->out_frame ) | |
| 436 | mc6854->iface->out_frame( device, mc6854->frame, len ); | |
| 437 | } | |
| 438 | } | |
| 439 | ||
| 440 | ||
| 441 | ||
| 442 | static void mc6854_tfifo_clear( device_t *device ) | |
| 443 | { | |
| 444 | mc6854_t* mc6854 = get_safe_token( device ); | |
| 445 | memset( mc6854->tfifo, 0, sizeof( mc6854->tfifo ) ); | |
| 446 | mc6854->tstate = 0; | |
| 447 | mc6854->flen = 0; | |
| 448 | mc6854->ttimer->reset( ); | |
| 449 | } | |
| 450 | ||
| 451 | ||
| 452 | ||
| 453 | /*********************** receive ***********************/ | |
| 454 | ||
| 455 | ||
| 456 | ||
| 457 | /* MC6854 pushes a field in the FIFO */ | |
| 458 | static void mc6854_rfifo_push( device_t *device, UINT8 d ) | |
| 459 | { | |
| 460 | mc6854_t* mc6854 = get_safe_token( device ); | |
| 461 | int i, blen = 8; | |
| 462 | unsigned data = d; | |
| 463 | ||
| 464 | switch ( mc6854->rstate ) | |
| 465 | { | |
| 466 | case 0: | |
| 467 | case 1: | |
| 468 | case 2: /* 8-bit address field */ | |
| 469 | if ( ( data & 1 ) || ( ! AEX ) ) | |
| 470 | mc6854->rstate = 3; | |
| 471 | else | |
| 472 | mc6854->rstate = 2; | |
| 473 | LOG(( "%f mc6854_rfifo_push: address field $%02X\n", device->machine().time().as_double(), data )); | |
| 474 | data |= 0x400; /* address marker */ | |
| 475 | break; | |
| 476 | ||
| 477 | case 3: /* 8-bit control field */ | |
| 478 | if ( CEX ) | |
| 479 | mc6854->rstate = 4; | |
| 480 | else if ( LCF ) | |
| 481 | mc6854->rstate = 5; | |
| 482 | else | |
| 483 | mc6854->rstate = 6; | |
| 484 | LOG(( "%f mc6854_rfifo_push: control field $%02X\n", device->machine().time().as_double(), data )); | |
| 485 | break; | |
| 486 | ||
| 487 | case 4: /* 8-bit extended control field (optional) */ | |
| 488 | if ( LCF ) | |
| 489 | mc6854->rstate = 5; | |
| 490 | else | |
| 491 | mc6854->rstate = 6; | |
| 492 | LOG(( "%f mc6854_rfifo_push: control field $%02X\n", device->machine().time().as_double(), data )); | |
| 493 | break; | |
| 494 | ||
| 495 | case 5: /* 8-bit logical control (optional) */ | |
| 496 | if ( ! ( data & 0x80 ) ) | |
| 497 | mc6854->rstate = 6; | |
| 498 | LOG(( "%f mc6854_rfifo_push: logical control field $%02X\n", device->machine().time().as_double(), data )); | |
| 499 | break; | |
| 500 | ||
| 501 | case 6: /* variable-length data */ | |
| 502 | blen = RWL; | |
| 503 | data >>= 8 - blen; | |
| 504 | LOG(( "%f mc6854_rfifo_push: data field $%02X, %i bits\n", device->machine().time().as_double(), data, blen )); | |
| 505 | break; | |
| 506 | } | |
| 507 | ||
| 508 | /* no further FIFO fill until FV is cleared! */ | |
| 509 | if ( mc6854->sr2 & FV ) | |
| 510 | { | |
| 511 | LOG(( "%f mc6854_rfifo_push: field not pushed\n", device->machine().time().as_double() )); | |
| 512 | return; | |
| 513 | } | |
| 514 | ||
| 515 | data |= 0x100; /* entry full marker */ | |
| 516 | ||
| 517 | /* push towards the rightmost free entry */ | |
| 518 | for ( i = FIFO_SIZE - 1; i >= 0; i-- ) | |
| 519 | { | |
| 520 | if ( ! ( mc6854->rfifo[ i ] & 0x100 ) ) | |
| 521 | break; | |
| 522 | } | |
| 523 | ||
| 524 | if ( i >= 0 ) | |
| 525 | mc6854->rfifo[ i ] = data | 0x100; | |
| 526 | else | |
| 527 | { | |
| 528 | /* FIFO full */ | |
| 529 | mc6854->sr2 |= OVRN; | |
| 530 | mc6854->rfifo[ 0 ] = data; | |
| 531 | logerror( "%f mc6854_rfifo_push: FIFO overrun\n", device->machine().time().as_double() ); | |
| 532 | } | |
| 533 | ||
| 534 | mc6854->rsize -= blen; | |
| 535 | } | |
| 536 | ||
| 537 | ||
| 538 | ||
| 539 | static void mc6854_rfifo_terminate( device_t *device ) | |
| 540 | { | |
| 541 | mc6854_t* mc6854 = get_safe_token( device ); | |
| 542 | /* mark most recently pushed byte as the last one of the frame */ | |
| 543 | int i; | |
| 544 | for ( i = 0; i < FIFO_SIZE; i++ ) | |
| 545 | { | |
| 546 | if ( mc6854->rfifo[ i ] & 0x100 ) | |
| 547 | { | |
| 548 | mc6854->tfifo[ i ] |= 0x200; | |
| 549 | break; | |
| 550 | } | |
| 551 | ||
| 552 | } | |
| 553 | ||
| 554 | mc6854->flen = 0; | |
| 555 | mc6854->rstate = 1; | |
| 556 | } | |
| 557 | ||
| 558 | ||
| 559 | ||
| 560 | /* CPU pops the FIFO */ | |
| 561 | static UINT8 mc6854_rfifo_pop( device_t *device ) | |
| 562 | { | |
| 563 | mc6854_t* mc6854 = get_safe_token( device ); | |
| 564 | int i, data = mc6854->rfifo[ FIFO_SIZE - 1 ]; | |
| 565 | ||
| 566 | /* shift FIFO to the right */ | |
| 567 | for ( i = FIFO_SIZE - 1; i > 0; i -- ) | |
| 568 | mc6854->rfifo[ i ] = mc6854->rfifo[ i - 1 ]; | |
| 569 | mc6854->rfifo[ 0 ] = 0; | |
| 570 | ||
| 571 | if ( mc6854->rfifo[ FIFO_SIZE - 1 ] & 0x200 ) | |
| 572 | { | |
| 573 | /* last byte in frame */ | |
| 574 | mc6854->sr2 |= FV; /* TODO: check CRC & set ERR instead of FV if error*/ | |
| 575 | } | |
| 576 | ||
| 577 | /* auto-refill in frame mode */ | |
| 578 | if ( mc6854->flen > 0 ) | |
| 579 | { | |
| 580 | mc6854_rfifo_push( device, mc6854->frame[ mc6854->fpos++ ] ); | |
| 581 | if ( mc6854->fpos == mc6854->flen ) | |
| 582 | mc6854_rfifo_terminate( device ); | |
| 583 | } | |
| 584 | ||
| 585 | return data; | |
| 586 | } | |
| 587 | ||
| 588 | ||
| 589 | /* MC6854 makes fields from bits */ | |
| 590 | WRITE_LINE_DEVICE_HANDLER( mc6854_set_rx ) | |
| 591 | { | |
| 592 | mc6854_t* mc6854 = get_safe_token( device ); | |
| 593 | int fieldlen = ( mc6854->rstate < 6 ) ? 8 : RWL; | |
| 594 | ||
| 595 | if ( RRESET || (mc6854->sr2 & DCD) ) | |
| 596 | return; | |
| 597 | ||
| 598 | if ( state ) | |
| 599 | { | |
| 600 | mc6854->rones++; | |
| 601 | mc6854->rreg = (mc6854->rreg >> 1) | 0x80000000; | |
| 602 | if ( mc6854->rones >= 8 ) | |
| 603 | { | |
| 604 | /* abort */ | |
| 605 | mc6854->rstate = 0; | |
| 606 | mc6854->rsize = 0; | |
| 607 | if ( mc6854->rstate > 1 ) | |
| 608 | { | |
| 609 | /* only in-frame abort */ | |
| 610 | mc6854->sr2 |= RABT; | |
| 611 | LOG(( "%f mc6854_receive_bit: abort\n", device->machine().time().as_double() )); | |
| 612 | } | |
| 613 | } | |
| 614 | else | |
| 615 | { | |
| 616 | mc6854->rsize++; | |
| 617 | if ( mc6854->rstate && mc6854->rsize >= fieldlen + 24 ) | |
| 618 | mc6854_rfifo_push( device, mc6854->rreg ); | |
| 619 | } | |
| 620 | } | |
| 621 | else if ( mc6854->rones == 5 ) | |
| 622 | { | |
| 623 | /* discards '0' inserted after 5 '1' */ | |
| 624 | mc6854->rones = 0; | |
| 625 | return; | |
| 626 | } | |
| 627 | else if ( mc6854->rones == 6 ) | |
| 628 | { | |
| 629 | /* flag */ | |
| 630 | if ( FDSE ) | |
| 631 | mc6854->sr1 |= FD; | |
| 632 | ||
| 633 | if ( mc6854->rstate > 1 ) | |
| 634 | { | |
| 635 | /* end of frame */ | |
| 636 | mc6854->rreg >>= 1; | |
| 637 | mc6854->rsize++; | |
| 638 | if ( mc6854->rsize >= fieldlen + 24 ) /* last field */ | |
| 639 | mc6854_rfifo_push( device, mc6854->rreg ); | |
| 640 | mc6854_rfifo_terminate( device ); | |
| 641 | LOG(( "%f mc6854_receive_bit: end of frame\n", device->machine().time().as_double() )); | |
| 642 | } | |
| 643 | mc6854->rones = 0; | |
| 644 | mc6854->rstate = 1; | |
| 645 | mc6854->rsize = 0; | |
| 646 | } else | |
| 647 | { | |
| 648 | mc6854->rones = 0; | |
| 649 | mc6854->rreg >>= 1; | |
| 650 | mc6854->rsize++; | |
| 651 | if ( mc6854->rstate && mc6854->rsize >= fieldlen + 24 ) | |
| 652 | mc6854_rfifo_push( device, mc6854->rreg ); | |
| 653 | } | |
| 654 | } | |
| 655 | ||
| 656 | ||
| 657 | ||
| 658 | static void mc6854_rfifo_clear( device_t *device ) | |
| 659 | { | |
| 660 | mc6854_t* mc6854 = get_safe_token( device ); | |
| 661 | memset( mc6854->rfifo, 0, sizeof( mc6854->rfifo ) ); | |
| 662 | mc6854->rstate = 0; | |
| 663 | mc6854->rreg = 0; | |
| 664 | mc6854->rsize = 0; | |
| 665 | mc6854->rones = 0; | |
| 666 | mc6854->flen = 0; | |
| 667 | } | |
| 668 | ||
| 669 | ||
| 670 | ||
| 671 | int mc6854_send_frame( device_t *device, UINT8* data, int len ) | |
| 672 | { | |
| 673 | mc6854_t* mc6854 = get_safe_token( device ); | |
| 674 | if ( mc6854->rstate > 1 || mc6854->tstate > 1 || RTS ) | |
| 675 | return -1; /* busy */ | |
| 676 | ||
| 677 | if ( len > MAX_FRAME_LENGTH ) | |
| 678 | { | |
| 679 | logerror( "mc6854_send_frame: truncated frame, size=%i, max=%i\n", len, MAX_FRAME_LENGTH ); | |
| 680 | len = MAX_FRAME_LENGTH; | |
| 681 | } | |
| 682 | else if ( len < 2 ) | |
| 683 | { | |
| 684 | logerror( "mc6854_send_frame: frame too short, size=%i, min=2\n", len ); | |
| 685 | len = 2; | |
| 686 | } | |
| 687 | memcpy( mc6854->frame, data, len ); | |
| 688 | if ( FDSE ) | |
| 689 | mc6854->sr1 |= FD; | |
| 690 | mc6854->flen = len; | |
| 691 | mc6854->fpos = 0; | |
| 692 | mc6854_rfifo_push( device, mc6854->frame[ mc6854->fpos++ ] ); | |
| 693 | mc6854_rfifo_push( device, mc6854->frame[ mc6854->fpos++ ] ); | |
| 694 | if ( mc6854->fpos == mc6854->flen ) | |
| 695 | mc6854_rfifo_terminate( device ); | |
| 696 | return 0; | |
| 697 | } | |
| 698 | ||
| 699 | ||
| 700 | ||
| 701 | /************************** CPU interface ****************************/ | |
| 702 | ||
| 703 | ||
| 704 | ||
| 705 | WRITE_LINE_DEVICE_HANDLER( mc6854_set_cts ) | |
| 706 | { | |
| 707 | mc6854_t* mc6854 = get_safe_token( device ); | |
| 708 | if ( ! mc6854->cts && state ) | |
| 709 | mc6854->sr1 |= CTS; | |
| 710 | mc6854->cts = state; | |
| 711 | ||
| 712 | if ( mc6854->cts ) | |
| 713 | mc6854->sr1 |= CTS; | |
| 714 | else | |
| 715 | mc6854->sr1 &= ~CTS; | |
| 716 | } | |
| 717 | ||
| 718 | ||
| 719 | ||
| 720 | WRITE_LINE_DEVICE_HANDLER( mc6854_set_dcd ) | |
| 721 | { | |
| 722 | mc6854_t* mc6854 = get_safe_token( device ); | |
| 723 | if ( ! mc6854->dcd && state ) | |
| 724 | { | |
| 725 | mc6854->sr2 |= DCD; | |
| 726 | /* partial reset */ | |
| 727 | mc6854->rstate = 0; | |
| 728 | mc6854->rreg = 0; | |
| 729 | mc6854->rsize = 0; | |
| 730 | mc6854->rones = 0; | |
| 731 | } | |
| 732 | mc6854->dcd = state; | |
| 733 | } | |
| 734 | ||
| 735 | ||
| 736 | ||
| 737 | static void mc6854_update_sr2( mc6854_t* mc6854 ) | |
| 738 | { | |
| 739 | /* update RDA */ | |
| 740 | mc6854->sr2 |= RDA2; | |
| 741 | if ( ! (mc6854->rfifo[ FIFO_SIZE - 1 ] & 0x100) ) | |
| 742 | mc6854->sr2 &= ~RDA2; | |
| 743 | else if ( TWOBYTES && ! (mc6854->tfifo[ FIFO_SIZE - 2 ] & 0x100) ) | |
| 744 | mc6854->sr2 &= ~RDA2; | |
| 745 | ||
| 746 | /* update AP */ | |
| 747 | if ( mc6854->rfifo[ FIFO_SIZE - 1 ] & 0x400 ) | |
| 748 | mc6854->sr2 |= AP; | |
| 749 | else | |
| 750 | mc6854->sr2 &= ~AP; | |
| 751 | } | |
| 752 | ||
| 753 | ||
| 754 | ||
| 755 | static void mc6854_update_sr1( mc6854_t* mc6854 ) | |
| 756 | { | |
| 757 | mc6854_update_sr2( mc6854 ); | |
| 758 | ||
| 759 | /* update S2RQ */ | |
| 760 | if ( mc6854->sr2 & 0x7f ) | |
| 761 | mc6854->sr1 |= S2RQ; | |
| 762 | else | |
| 763 | mc6854->sr1 &= ~S2RQ; | |
| 764 | ||
| 765 | /* update TRDA (always prioritized by CTS) */ | |
| 766 | if ( TRESET || ( mc6854->sr1 & CTS ) ) | |
| 767 | mc6854->sr1 &= ~TDRA; | |
| 768 | else | |
| 769 | { | |
| 770 | mc6854->sr1 |= TDRA; | |
| 771 | if ( mc6854->tfifo[ 0 ] & 0x100 ) | |
| 772 | mc6854->sr1 &= ~TDRA; | |
| 773 | else if ( TWOBYTES && (mc6854->tfifo[ 1 ] & 0x100) ) | |
| 774 | mc6854->sr1 &= ~TDRA; | |
| 775 | } | |
| 776 | ||
| 777 | /* update RDA */ | |
| 778 | if ( mc6854->sr2 & RDA2 ) | |
| 779 | mc6854->sr1 |= RDA; | |
| 780 | else | |
| 781 | mc6854->sr1 &= ~RDA; | |
| 782 | ||
| 783 | /* update IRQ */ | |
| 784 | mc6854->sr1 &= ~IRQ; | |
| 785 | if ( RIE && (mc6854->sr1 & (TU | TDRA) ) ) | |
| 786 | mc6854->sr1 |= IRQ; | |
| 787 | if ( TIE ) | |
| 788 | { | |
| 789 | if ( mc6854->sr1 & (S2RQ | RDA | CTS) ) | |
| 790 | mc6854->sr1 |= IRQ; | |
| 791 | if ( mc6854->sr2 & (ERR | FV | DCD | OVRN | RABT | RIDLE | AP) ) | |
| 792 | mc6854->sr1 |= IRQ; | |
| 793 | } | |
| 794 | ||
| 795 | mc6854->out_irq_func((mc6854->sr1 & IRQ) ? ASSERT_LINE : CLEAR_LINE); | |
| 796 | } | |
| 797 | ||
| 798 | ||
| 799 | ||
| 800 | READ8_DEVICE_HANDLER ( mc6854_r ) | |
| 801 | { | |
| 802 | mc6854_t* mc6854 = get_safe_token( device ); | |
| 803 | switch ( offset ) | |
| 804 | { | |
| 805 | case 0: /* status register 1 */ | |
| 806 | mc6854_update_sr1( mc6854 ); | |
| 807 | LOG(( "%f $%04x mc6854_r: get SR1=$%02X (rda=%i,s2rq=%i,fd=%i,cts=%i,tu=%i,tdra=%i,irq=%i)\n", | |
| 808 | space.machine().time().as_double(), space.machine().firstcpu->pcbase( ), mc6854->sr1, | |
| 809 | ( mc6854->sr1 & RDA) ? 1 : 0, ( mc6854->sr1 & S2RQ) ? 1 : 0, | |
| 810 | ( mc6854->sr1 & FD ) ? 1 : 0, ( mc6854->sr1 & CTS ) ? 1 : 0, | |
| 811 | ( mc6854->sr1 & TU ) ? 1 : 0, ( mc6854->sr1 & TDRA) ? 1 : 0, | |
| 812 | ( mc6854->sr1 & IRQ) ? 1 : 0 )); | |
| 813 | return mc6854->sr1; | |
| 814 | ||
| 815 | case 1: /* status register 2 */ | |
| 816 | mc6854_update_sr2( mc6854 ); | |
| 817 | LOG(( "%f $%04x mc6854_r: get SR2=$%02X (ap=%i,fv=%i,ridle=%i,rabt=%i,err=%i,dcd=%i,ovrn=%i,rda2=%i)\n", | |
| 818 | space.machine().time().as_double(), space.machine().firstcpu->pcbase( ), mc6854->sr2, | |
| 819 | ( mc6854->sr2 & AP ) ? 1 : 0, ( mc6854->sr2 & FV ) ? 1 : 0, | |
| 820 | ( mc6854->sr2 & RIDLE) ? 1 : 0, ( mc6854->sr2 & RABT) ? 1 : 0, | |
| 821 | ( mc6854->sr2 & ERR ) ? 1 : 0, ( mc6854->sr2 & DCD ) ? 1 : 0, | |
| 822 | ( mc6854->sr2 & OVRN ) ? 1 : 0, ( mc6854->sr2 & RDA2) ? 1 : 0 )); | |
| 823 | return mc6854->sr2; | |
| 824 | ||
| 825 | case 2: /* receiver data register */ | |
| 826 | case 3: | |
| 827 | { | |
| 828 | UINT8 data = mc6854_rfifo_pop( device ); | |
| 829 | LOG(( "%f $%04x mc6854_r: get data $%02X\n", | |
| 830 | space.machine().time().as_double(), space.machine().firstcpu->pcbase( ), data )); | |
| 831 | return data; | |
| 832 | } | |
| 833 | ||
| 834 | default: | |
| 835 | logerror( "$%04x mc6854 invalid read offset %i\n", space.machine().firstcpu->pcbase( ), offset ); | |
| 836 | } | |
| 837 | return 0; | |
| 838 | } | |
| 839 | ||
| 840 | ||
| 841 | ||
| 842 | WRITE8_DEVICE_HANDLER ( mc6854_w ) | |
| 843 | { | |
| 844 | mc6854_t* mc6854 = get_safe_token( device ); | |
| 845 | switch ( offset ) | |
| 846 | { | |
| 847 | case 0: /* control register 1 */ | |
| 848 | mc6854->cr1 = data; | |
| 849 | LOG(( "%f $%04x mc6854_w: set CR1=$%02X (ac=%i,irq=%c%c,%sreset=%c%c)\n", | |
| 850 | space.machine().time().as_double(), space.machine().firstcpu->pcbase( ), mc6854->cr1, | |
| 851 | AC ? 1 : 0, | |
| 852 | RIE ? 'r' : '-', TIE ? 't' : '-', | |
| 853 | DISCONTINUE ? "discontinue," : "", | |
| 854 | RRESET ? 'r' : '-', TRESET ? 't' : '-' | |
| 855 | )); | |
| 856 | if ( mc6854->cr1 & 0xc ) | |
| 857 | logerror( "$%04x mc6854 DMA not handled (CR1=$%02X)\n", | |
| 858 | space.machine().firstcpu->pcbase( ), mc6854->cr1 ); | |
| 859 | if ( DISCONTINUE ) | |
| 860 | { | |
| 861 | /* abort receive FIFO but keeps shift register & synchro */ | |
| 862 | mc6854->rstate = 0; | |
| 863 | memset( mc6854->rfifo, 0, sizeof( mc6854->rfifo ) ); | |
| 864 | } | |
| 865 | if ( RRESET ) | |
| 866 | { | |
| 867 | /* abort FIFO & synchro */ | |
| 868 | mc6854_rfifo_clear( device ); | |
| 869 | mc6854->sr1 &= ~FD; | |
| 870 | mc6854->sr2 &= ~(AP | FV | RIDLE | RABT | ERR | OVRN | DCD); | |
| 871 | if ( mc6854->dcd ) mc6854->sr2 |= DCD; | |
| 872 | } | |
| 873 | if ( TRESET ) | |
| 874 | { | |
| 875 | mc6854_tfifo_clear( device ); | |
| 876 | mc6854->sr1 &= ~(TU | TDRA | CTS); | |
| 877 | if ( mc6854->cts ) mc6854->sr1 |= CTS; | |
| 878 | } | |
| 879 | break; | |
| 880 | ||
| 881 | case 1: | |
| 882 | if ( AC ) | |
| 883 | { | |
| 884 | /* control register 3 */ | |
| 885 | mc6854->cr3 = data; | |
| 886 | LOG(( "%f $%04x mc6854_w: set CR3=$%02X (lcf=%i,aex=%i,idl=%i,fdse=%i,loop=%i,tst=%i,dtr=%i)\n", | |
| 887 | space.machine().time().as_double(), space.machine().firstcpu->pcbase( ), mc6854->cr3, | |
| 888 | LCF ? (CEX ? 16 : 8) : 0, AEX ? 1 : 0, | |
| 889 | IDL0 ? 0 : 1, FDSE ? 1 : 0, LOOP ? 1 : 0, | |
| 890 | TST ? 1 : 0, DTR ? 1 : 0 | |
| 891 | )); | |
| 892 | if ( LOOP ) | |
| 893 | logerror( "$%04x mc6854 loop mode not handled (CR3=$%02X)\n", space.machine().firstcpu->pcbase( ), mc6854->cr3 ); | |
| 894 | if ( TST ) | |
| 895 | logerror( "$%04x mc6854 test mode not handled (CR3=$%02X)\n", space.machine().firstcpu->pcbase( ), mc6854->cr3 ); | |
| 896 | ||
| 897 | mc6854->out_dtr_func( DTR ? 1 : 0 ); | |
| 898 | ||
| 899 | } | |
| 900 | else | |
| 901 | { | |
| 902 | /* control register 2 */ | |
| 903 | mc6854->cr2 = data; | |
| 904 | LOG(( "%f $%04x mc6854_w: set CR2=$%02X (pse=%i,bytes=%i,fmidle=%i,%s,tlast=%i,clr=%c%c,rts=%i)\n", | |
| 905 | space.machine().time().as_double(), space.machine().firstcpu->pcbase( ), mc6854->cr2, | |
| 906 | PSE ? 1 : 0, TWOBYTES ? 2 : 1, FMIDLE ? 1 : 0, | |
| 907 | FCTDRA ? "fc" : "tdra", TLAST ? 1 : 0, | |
| 908 | data & 0x20 ? 'r' : '-', data & 0x40 ? 't' : '-', | |
| 909 | RTS ? 1 : 0 )); | |
| 910 | if ( PSE ) | |
| 911 | logerror( "$%04x mc6854 status prioritization not handled (CR2=$%02X)\n", space.machine().firstcpu->pcbase( ), mc6854->cr2 ); | |
| 912 | if ( TLAST ) | |
| 913 | mc6854_tfifo_terminate( device ); | |
| 914 | if ( data & 0x20 ) | |
| 915 | { | |
| 916 | /* clear receiver status */ | |
| 917 | mc6854->sr1 &= ~FD; | |
| 918 | mc6854->sr2 &= ~(AP | FV | RIDLE | RABT | ERR | OVRN | DCD); | |
| 919 | if ( mc6854->dcd ) | |
| 920 | mc6854->sr2 |= DCD; | |
| 921 | } | |
| 922 | if ( data & 0x40 ) | |
| 923 | { | |
| 924 | /* clear transmitter status */ | |
| 925 | mc6854->sr1 &= ~(TU | TDRA | CTS); | |
| 926 | if ( mc6854->cts ) | |
| 927 | mc6854->sr1 |= CTS; | |
| 928 | } | |
| 929 | ||
| 930 | mc6854->out_rts_func( RTS ? 1 : 0 ); | |
| 931 | } | |
| 932 | break; | |
| 933 | ||
| 934 | case 2: /* transmitter data: continue data */ | |
| 935 | LOG(( "%f $%04xmc6854_w: push data=$%02X\n", space.machine().time().as_double(), space.machine().firstcpu->pcbase( ), data )); | |
| 936 | mc6854_tfifo_push( device, data ); | |
| 937 | break; | |
| 938 | ||
| 939 | case 3: | |
| 940 | if ( AC ) | |
| 941 | { | |
| 942 | /* control register 4 */ | |
| 943 | mc6854->cr4 = data; | |
| 944 | LOG(( "%f $%04x mc6854_w: set CR4=$%02X (interframe=%i,tlen=%i,rlen=%i,%s%s)\n", space.machine().time().as_double(), space.machine().firstcpu->pcbase( ), mc6854->cr4, | |
| 945 | TWOINTER ? 2 : 1, | |
| 946 | TWL, RWL, | |
| 947 | ABT ? ( ABTEX ? "abort-ext," : "abort,") : "", | |
| 948 | NRZ ? "nrz" : "nrzi" )); | |
| 949 | if ( ABT ) | |
| 950 | { | |
| 951 | mc6854->tstate = 0; | |
| 952 | mc6854_send_bits( device, 0xffff, ABTEX ? 16 : 8, 0 ); | |
| 953 | mc6854->flen = 0; | |
| 954 | } | |
| 955 | } | |
| 956 | else | |
| 957 | { | |
| 958 | /* transmitter data: last data */ | |
| 959 | LOG(( "%f $%04x mc6854_w: push last-data=$%02X\n", space.machine().time().as_double(), space.machine().firstcpu->pcbase( ), data )); | |
| 960 | mc6854_tfifo_push( device, data ); | |
| 961 | mc6854_tfifo_terminate( device ); | |
| 962 | } | |
| 963 | break; | |
| 964 | ||
| 965 | default: | |
| 966 | logerror( "$%04x mc6854 invalid write offset %i (data=$%02X)\n", space.machine().firstcpu->pcbase( ), offset, data ); | |
| 967 | } | |
| 968 | } | |
| 969 | ||
| 970 | WRITE_LINE_DEVICE_HANDLER( mc6854_rxc_w ) | |
| 971 | { | |
| 972 | // TODO | |
| 973 | } | |
| 974 | ||
| 975 | WRITE_LINE_DEVICE_HANDLER( mc6854_txc_w ) | |
| 976 | { | |
| 977 | // TODO | |
| 978 | } | |
| 979 | ||
| 980 | /************************ reset *****************************/ | |
| 981 | ||
| 982 | static DEVICE_RESET( mc6854 ) | |
| 983 | { | |
| 984 | mc6854_t* mc6854 = get_safe_token( device ); | |
| 985 | LOG (( "mc6854 reset\n" )); | |
| 986 | mc6854->cr1 = 0xc0; /* reset condition */ | |
| 987 | mc6854->cr2 = 0; | |
| 988 | mc6854->cr3 = 0; | |
| 989 | mc6854->cr4 = 0; | |
| 990 | mc6854->sr1 = 0; | |
| 991 | mc6854->sr2 = 0; | |
| 992 | mc6854->cts = 0; | |
| 993 | mc6854->dcd = 0; | |
| 994 | mc6854_tfifo_clear( device ); | |
| 995 | mc6854_rfifo_clear( device ); | |
| 996 | } | |
| 997 | ||
| 998 | ||
| 999 | ||
| 1000 | /************************ start *****************************/ | |
| 1001 | ||
| 1002 | static DEVICE_START( mc6854 ) | |
| 1003 | { | |
| 1004 | mc6854_t* mc6854 = get_safe_token( device ); | |
| 1005 | ||
| 1006 | mc6854->iface = (const mc6854_interface*)device->static_config(); | |
| 1007 | mc6854->out_irq_func.resolve(mc6854->iface->out_irq_func, *device); | |
| 1008 | mc6854->in_rxd_func.resolve(mc6854->iface->in_rxd_func, *device); | |
| 1009 | mc6854->out_txd_func.resolve(mc6854->iface->out_txd_func, *device); | |
| 1010 | mc6854->out_rts_func.resolve(mc6854->iface->out_rts_func, *device); | |
| 1011 | mc6854->out_dtr_func.resolve(mc6854->iface->out_dtr_func, *device); | |
| 1012 | ||
| 1013 | mc6854->ttimer = device->machine().scheduler().timer_alloc(FUNC(mc6854_tfifo_cb), (void*) device ); | |
| 1014 | ||
| 1015 | state_save_register_item( device->machine(), "mc6854", device->tag(), 0, mc6854->cr1 ); | |
| 1016 | state_save_register_item( device->machine(), "mc6854", device->tag(), 0, mc6854->cr2 ); | |
| 1017 | state_save_register_item( device->machine(), "mc6854", device->tag(), 0, mc6854->cr3 ); | |
| 1018 | state_save_register_item( device->machine(), "mc6854", device->tag(), 0, mc6854->cr4 ); | |
| 1019 | state_save_register_item( device->machine(), "mc6854", device->tag(), 0, mc6854->sr1 ); | |
| 1020 | state_save_register_item( device->machine(), "mc6854", device->tag(), 0, mc6854->sr2 ); | |
| 1021 | state_save_register_item( device->machine(), "mc6854", device->tag(), 0, mc6854->cts ); | |
| 1022 | state_save_register_item( device->machine(), "mc6854", device->tag(), 0, mc6854->dcd ); | |
| 1023 | state_save_register_item( device->machine(), "mc6854", device->tag(), 0, mc6854->tstate ); | |
| 1024 | state_save_register_item_array( device->machine(), "mc6854", device->tag(), 0, mc6854->tfifo ); | |
| 1025 | state_save_register_item( device->machine(), "mc6854", device->tag(), 0, mc6854->tones ); | |
| 1026 | state_save_register_item( device->machine(), "mc6854", device->tag(), 0, mc6854->rstate ); | |
| 1027 | state_save_register_item( device->machine(), "mc6854", device->tag(), 0, mc6854->rreg ); | |
| 1028 | state_save_register_item( device->machine(), "mc6854", device->tag(), 0, mc6854->rones ); | |
| 1029 | state_save_register_item( device->machine(), "mc6854", device->tag(), 0, mc6854->rsize ); | |
| 1030 | state_save_register_item_array( device->machine(), "mc6854", device->tag(), 0, mc6854->rfifo ); | |
| 1031 | state_save_register_item_array( device->machine(), "mc6854", device->tag(), 0, mc6854->frame ); | |
| 1032 | state_save_register_item( device->machine(), "mc6854", device->tag(), 0, mc6854->flen ); | |
| 1033 | state_save_register_item( device->machine(), "mc6854", device->tag(), 0, mc6854->fpos ); | |
| 1034 | } | |
| 1035 | ||
| 1036 | ||
| 1037 | ||
| 1038 | const device_type MC6854 = &device_creator<mc6854_device>; | |
| 1039 | ||
| 1040 | mc6854_device::mc6854_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) | |
| 1041 | : device_t(mconfig, MC6854, "Motorola MC6854 ADLC", tag, owner, clock) | |
| 1042 | { | |
| 1043 | m_token = global_alloc_clear(mc6854_t); | |
| 1044 | } | |
| 1045 | ||
| 1046 | //------------------------------------------------- | |
| 1047 | // device_config_complete - perform any | |
| 1048 | // operations now that the configuration is | |
| 1049 | // complete | |
| 1050 | //------------------------------------------------- | |
| 1051 | ||
| 1052 | void mc6854_device::device_config_complete() | |
| 1053 | { | |
| 1054 | } | |
| 1055 | ||
| 1056 | //------------------------------------------------- | |
| 1057 | // device_start - device-specific startup | |
| 1058 | //------------------------------------------------- | |
| 1059 | ||
| 1060 | void mc6854_device::device_start() | |
| 1061 | { | |
| 1062 | DEVICE_START_NAME( mc6854 )(this); | |
| 1063 | } | |
| 1064 | ||
| 1065 | //------------------------------------------------- | |
| 1066 | // device_reset - device-specific reset | |
| 1067 | //------------------------------------------------- | |
| 1068 | ||
| 1069 | void mc6854_device::device_reset() | |
| 1070 | { | |
| 1071 | DEVICE_RESET_NAME( mc6854 )(this); | |
| 1072 | } |
| Added: svn:eol-style + native Added: svn:mime-type + text/plain |
| r0 | r21685 | |
|---|---|---|
| 1 | /********************************************************************** | |
| 2 | ||
| 3 | Copyright (C) Antoine Mine' 2006 | |
| 4 | ||
| 5 | Motorola 6854 emulation (network interface). | |
| 6 | ||
| 7 | **********************************************************************/ | |
| 8 | ||
| 9 | #ifndef MC6854_H | |
| 10 | #define MC6854_H | |
| 11 | ||
| 12 | class mc6854_device : public device_t | |
| 13 | { | |
| 14 | public: | |
| 15 | mc6854_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); | |
| 16 | ~mc6854_device() { global_free(m_token); } | |
| 17 | ||
| 18 | // access to legacy token | |
| 19 | void *token() const { assert(m_token != NULL); return m_token; } | |
| 20 | protected: | |
| 21 | // device-level overrides | |
| 22 | virtual void device_config_complete(); | |
| 23 | virtual void device_start(); | |
| 24 | virtual void device_reset(); | |
| 25 | private: | |
| 26 | // internal state | |
| 27 | void *m_token; | |
| 28 | }; | |
| 29 | ||
| 30 | extern const device_type MC6854; | |
| 31 | ||
| 32 | ||
| 33 | /* we provide two interfaces: | |
| 34 | - a bit-based interface: out_tx, set_rx | |
| 35 | - a frame-based interface: out_frame, send_frame | |
| 36 | ||
| 37 | The bit-based interface is low-level and slow. | |
| 38 | Use it to simulate the actual bits sent into the wires, e.g., to connect | |
| 39 | the emulator to another bit-based emulated network device, or an actual | |
| 40 | device. | |
| 41 | ||
| 42 | The frame-based interface is higher-level and faster. | |
| 43 | It passes bytes directly from one end to the other without bothering with | |
| 44 | the actual bit-encoding, synchronization, and CRC. | |
| 45 | Once completed, a frame is sent through out_frame. Aborted frames are not | |
| 46 | transmitted at all. No start flag, stop flag, or crc bits are trasmitted. | |
| 47 | send_frame makes a frame available to the CPU through the 6854 (it may | |
| 48 | fail and return -1 if the 6854 is not ready to accept the frame; even | |
| 49 | if the frame is accepted and 0 is returned, the CPU may abort it). Ony | |
| 50 | full frames are accepted. | |
| 51 | */ | |
| 52 | ||
| 53 | ||
| 54 | /* ---------- configuration ------------ */ | |
| 55 | ||
| 56 | struct mc6854_interface | |
| 57 | { | |
| 58 | devcb_write_line out_irq_func; /* interrupt request */ | |
| 59 | ||
| 60 | /* low-level, bit-based interface */ | |
| 61 | devcb_read_line in_rxd_func; /* receive bit */ | |
| 62 | devcb_write_line out_txd_func; /* transmit bit */ | |
| 63 | ||
| 64 | /* high-level, frame-based interface */ | |
| 65 | void ( * out_frame ) ( device_t *device, UINT8* data, int length ); | |
| 66 | ||
| 67 | /* control lines */ | |
| 68 | devcb_write_line out_rts_func; /* 1 = transmitting, 0 = idle */ | |
| 69 | devcb_write_line out_dtr_func; /* 1 = data transmit ready, 0 = busy */ | |
| 70 | }; | |
| 71 | ||
| 72 | ||
| 73 | #define MCFG_MC6854_ADD(_tag, _intrf) \ | |
| 74 | MCFG_DEVICE_ADD(_tag, MC6854, 0) \ | |
| 75 | MCFG_DEVICE_CONFIG(_intrf) | |
| 76 | ||
| 77 | #define MCFG_MC6854_REMOVE(_tag) \ | |
| 78 | MCFG_DEVICE_REMOVE(_tag) | |
| 79 | ||
| 80 | ||
| 81 | /* ---------- functions ------------ */ | |
| 82 | /* interface to CPU via address/data bus*/ | |
| 83 | extern DECLARE_READ8_DEVICE_HANDLER ( mc6854_r ); | |
| 84 | extern DECLARE_WRITE8_DEVICE_HANDLER ( mc6854_w ); | |
| 85 | ||
| 86 | /* low-level, bit-based interface */ | |
| 87 | WRITE_LINE_DEVICE_HANDLER( mc6854_set_rx ); | |
| 88 | ||
| 89 | /* high-level, frame-based interface */ | |
| 90 | extern int mc6854_send_frame( device_t *device, UINT8* data, int length ); /* ret -1 if busy */ | |
| 91 | ||
| 92 | /* control lines */ | |
| 93 | WRITE_LINE_DEVICE_HANDLER( mc6854_set_cts ); /* 1 = clear-to-send, 0 = busy */ | |
| 94 | WRITE_LINE_DEVICE_HANDLER( mc6854_set_dcd ); /* 1 = carrier, 0 = no carrier */ | |
| 95 | ||
| 96 | /* clock */ | |
| 97 | WRITE_LINE_DEVICE_HANDLER( mc6854_rxc_w ); | |
| 98 | WRITE_LINE_DEVICE_HANDLER( mc6854_txc_w ); | |
| 99 | ||
| 100 | #endif |
| Added: svn:mime-type + text/plain Added: svn:eol-style + native |
| r0 | r21685 | |
|---|---|---|
| 1 | /*************************************************************************** | |
| 2 | ||
| 3 | mm58274c.c | |
| 4 | ||
| 5 | mm58274c emulation | |
| 6 | ||
| 7 | Reference: | |
| 8 | * National Semiconductor MM58274C Microprocessor Compatible Real Time Clock | |
| 9 | <http://www.national.com/ds/MM/MM58274C.pdf> | |
| 10 | ||
| 11 | Todo: | |
| 12 | * Clock initialization will only work with the BwG: we need to provide | |
| 13 | a way to customize it. | |
| 14 | * Save the config to NVRAM? | |
| 15 | * Support interrupt pin output | |
| 16 | ||
| 17 | Raphael Nabet, 2002 | |
| 18 | ||
| 19 | ***************************************************************************/ | |
| 20 | ||
| 21 | #include "emu.h" | |
| 22 | #include "mm58274c.h" | |
| 23 | ||
| 24 | struct mm58274c_t | |
| 25 | { | |
| 26 | const mm58274c_interface *intf; | |
| 27 | ||
| 28 | int status; /* status register (*read* from address 0 = control register) */ | |
| 29 | int control; /* control register (*write* to address 0) */ | |
| 30 | ||
| 31 | int clk_set; /* clock setting register */ | |
| 32 | int int_ctl; /* interrupt control register */ | |
| 33 | ||
| 34 | ||
| 35 | int wday; /* day of the week (1-7 (1=day1 as set in init)) */ | |
| 36 | int years1; /* years (BCD: 0-99) */ | |
| 37 | int years2; | |
| 38 | int months1; /* months (BCD: 1-12) */ | |
| 39 | int months2; | |
| 40 | int days1; /* days (BCD: 1-31) */ | |
| 41 | int days2; | |
| 42 | int hours1; /* hours (BCD : 0-23) */ | |
| 43 | int hours2; | |
| 44 | int minutes1; /* minutes (BCD : 0-59) */ | |
| 45 | int minutes2; | |
| 46 | int seconds1; /* seconds (BCD : 0-59) */ | |
| 47 | int seconds2; | |
| 48 | int tenths; /* tenths of second (BCD : 0-9) */ | |
| 49 | ||
| 50 | emu_timer *increment_rtc; | |
| 51 | emu_timer *interrupt_timer; | |
| 52 | }; | |
| 53 | ||
| 54 | enum | |
| 55 | { | |
| 56 | st_dcf = 0x8, /* data-changed flag */ | |
| 57 | st_if = 0x1, /* interrupt flag */ | |
| 58 | ||
| 59 | ctl_test = 0x8, /* test mode (0=normal, 1=test) (not emulated) */ | |
| 60 | ctl_clkstop = 0x4, /* clock start/stop (0=run, 1=stop) */ | |
| 61 | ctl_intsel = 0x2, /* interrupt select (0=clock setting register, 1=interrupt register) */ | |
| 62 | ctl_intstop = 0x1, /* interrupt start stop (0=interrupt run, 1=interrupt stop) */ | |
| 63 | ||
| 64 | clk_set_leap = 0xc, /* leap year counter (0 indicates a leap year) */ | |
| 65 | clk_set_leap_inc = 0x4, /* leap year increment */ | |
| 66 | clk_set_pm = 0x2, /* am/pm indicator (0 = am, 1 = pm, 0 in 24-hour mode) */ | |
| 67 | clk_set_24 = 0x1, /* 12/24-hour select bit (1= 24-hour mode) */ | |
| 68 | ||
| 69 | int_ctl_rpt = 0x8, /* 1 for repeated interrupt */ | |
| 70 | int_ctl_dly = 0x7 /* 0 no interrupt, 1 = .1 second, 2=.5, 3=1, 4=5, 5=10, 6=30, 7=60 */ | |
| 71 | }; | |
| 72 | ||
| 73 | ||
| 74 | INLINE mm58274c_t *get_safe_token(device_t *device) | |
| 75 | { | |
| 76 | assert(device != NULL); | |
| 77 | assert(device->type() == MM58274C); | |
| 78 | ||
| 79 | return (mm58274c_t *)downcast<mm58274c_device *>(device)->token(); | |
| 80 | } | |
| 81 | ||
| 82 | static attotime interrupt_period_table(int val) | |
| 83 | { | |
| 84 | switch(val) | |
| 85 | { | |
| 86 | case 0: return attotime::from_msec(0); | |
| 87 | case 1: return attotime::from_msec(100); | |
| 88 | case 2: return attotime::from_msec(500); | |
| 89 | case 3: return attotime::from_seconds(1); | |
| 90 | case 4: return attotime::from_seconds(5); | |
| 91 | case 5: return attotime::from_seconds(10); | |
| 92 | case 6: return attotime::from_seconds(30); | |
| 93 | case 7: return attotime::from_seconds(60); | |
| 94 | default: fatalerror("out of range\n"); | |
| 95 | } | |
| 96 | }; | |
| 97 | ||
| 98 | READ8_DEVICE_HANDLER( mm58274c_r ) | |
| 99 | { | |
| 100 | mm58274c_t *mm58274c = get_safe_token(device); | |
| 101 | int reply; | |
| 102 | ||
| 103 | offset &= 0xf; | |
| 104 | ||
| 105 | switch (offset) | |
| 106 | { | |
| 107 | case 0x0: /* Control Register */ | |
| 108 | reply = mm58274c->status; | |
| 109 | mm58274c->status = 0; | |
| 110 | break; | |
| 111 | ||
| 112 | case 0x1: /* Tenths of Seconds */ | |
| 113 | reply = mm58274c->tenths; | |
| 114 | break; | |
| 115 | ||
| 116 | case 0x2: /* Units Seconds */ | |
| 117 | reply = mm58274c->seconds2; | |
| 118 | break; | |
| 119 | ||
| 120 | case 0x3: /* Tens Seconds */ | |
| 121 | reply = mm58274c->seconds1; | |
| 122 | break; | |
| 123 | ||
| 124 | case 0x04: /* Units Minutes */ | |
| 125 | reply = mm58274c->minutes2; | |
| 126 | break; | |
| 127 | ||
| 128 | case 0x5: /* Tens Minutes */ | |
| 129 | reply = mm58274c->minutes1; | |
| 130 | break; | |
| 131 | ||
| 132 | case 0x6: /* Units Hours */ | |
| 133 | reply = mm58274c->hours2; | |
| 134 | break; | |
| 135 | ||
| 136 | case 0x7: /* Tens Hours */ | |
| 137 | reply = mm58274c->hours1; | |
| 138 | break; | |
| 139 | ||
| 140 | case 0x8: /* Units Days */ | |
| 141 | reply = mm58274c->days2; | |
| 142 | break; | |
| 143 | ||
| 144 | case 0x9: /* Tens Days */ | |
| 145 | reply = mm58274c->days1; | |
| 146 | break; | |
| 147 | ||
| 148 | case 0xA: /* Units Months */ | |
| 149 | reply = mm58274c->months2; | |
| 150 | break; | |
| 151 | ||
| 152 | case 0xB: /* Tens Months */ | |
| 153 | reply = mm58274c->months1; | |
| 154 | break; | |
| 155 | ||
| 156 | case 0xC: /* Units Years */ | |
| 157 | reply = mm58274c->years2; | |
| 158 | break; | |
| 159 | ||
| 160 | case 0xD: /* Tens Years */ | |
| 161 | reply = mm58274c->years1; | |
| 162 | break; | |
| 163 | ||
| 164 | case 0xE: /* Day of Week */ | |
| 165 | reply = mm58274c->wday; | |
| 166 | break; | |
| 167 | ||
| 168 | case 0xF: /* Clock Setting & Interrupt Registers */ | |
| 169 | if (mm58274c->control & ctl_intsel) | |
| 170 | /* interrupt register */ | |
| 171 | reply = mm58274c->int_ctl; | |
| 172 | else | |
| 173 | { /* clock setting register */ | |
| 174 | if (mm58274c->clk_set & clk_set_24) | |
| 175 | /* 24-hour mode */ | |
| 176 | reply = mm58274c->clk_set & ~clk_set_pm; | |
| 177 | else | |
| 178 | /* 12-hour mode */ | |
| 179 | reply = mm58274c->clk_set; | |
| 180 | } | |
| 181 | break; | |
| 182 | ||
| 183 | default: | |
| 184 | reply = 0; | |
| 185 | break; | |
| 186 | } | |
| 187 | ||
| 188 | return reply; | |
| 189 | } | |
| 190 | ||
| 191 | ||
| 192 | WRITE8_DEVICE_HANDLER (mm58274c_w) | |
| 193 | { | |
| 194 | mm58274c_t *mm58274c = get_safe_token(device); | |
| 195 | ||
| 196 | offset &= 0xf; | |
| 197 | data &= 0xf; | |
| 198 | ||
| 199 | switch (offset) | |
| 200 | { | |
| 201 | case 0x0: /* Control Register (test mode and interrupt not emulated) */ | |
| 202 | if ((! (mm58274c->control & ctl_intstop)) && (data & ctl_intstop)) | |
| 203 | /* interrupt stop */ | |
| 204 | mm58274c->interrupt_timer->enable(0); | |
| 205 | else if ((mm58274c->control & ctl_intstop) && (! (data & ctl_intstop))) | |
| 206 | { | |
| 207 | /* interrupt run */ | |
| 208 | attotime period = interrupt_period_table(mm58274c->int_ctl & int_ctl_dly); | |
| 209 | ||
| 210 | mm58274c->interrupt_timer->adjust(period, 0, mm58274c->int_ctl & int_ctl_rpt ? period : attotime::zero); | |
| 211 | } | |
| 212 | if (data & ctl_clkstop) | |
| 213 | /* stopping the clock clears the tenth counter */ | |
| 214 | mm58274c->tenths = 0; | |
| 215 | mm58274c->control = data; | |
| 216 | break; | |
| 217 | ||
| 218 | case 0x1: /* Tenths of Seconds: cannot be written */ | |
| 219 | break; | |
| 220 | ||
| 221 | case 0x2: /* Units Seconds */ | |
| 222 | mm58274c->seconds2 = data; | |
| 223 | break; | |
| 224 | ||
| 225 | case 0x3: /* Tens Seconds */ | |
| 226 | mm58274c->seconds1 = data; | |
| 227 | break; | |
| 228 | ||
| 229 | case 0x4: /* Units Minutes */ | |
| 230 | mm58274c->minutes2 = data; | |
| 231 | break; | |
| 232 | ||
| 233 | case 0x5: /* Tens Minutes */ | |
| 234 | mm58274c->minutes1 = data; | |
| 235 | break; | |
| 236 | ||
| 237 | case 0x6: /* Units Hours */ | |
| 238 | mm58274c->hours2 = data; | |
| 239 | break; | |
| 240 | ||
| 241 | case 0x7: /* Tens Hours */ | |
| 242 | mm58274c->hours1 = data; | |
| 243 | break; | |
| 244 | ||
| 245 | case 0x8: /* Units Days */ | |
| 246 | mm58274c->days2 = data; | |
| 247 | break; | |
| 248 | ||
| 249 | case 0x9: /* Tens Days */ | |
| 250 | mm58274c->days1 = data; | |
| 251 | break; | |
| 252 | ||
| 253 | case 0xA: /* Units Months */ | |
| 254 | mm58274c->months2 = data; | |
| 255 | break; | |
| 256 | ||
| 257 | case 0xB: /* Tens Months */ | |
| 258 | mm58274c->months1 = data; | |
| 259 | break; | |
| 260 | ||
| 261 | case 0xC: /* Units Years */ | |
| 262 | mm58274c->years2 = data; | |
| 263 | break; | |
| 264 | ||
| 265 | case 0xD: /* Tens Years */ | |
| 266 | mm58274c->years1 = data; | |
| 267 | break; | |
| 268 | ||
| 269 | case 0xE: /* Day of Week */ | |
| 270 | mm58274c->wday = data; | |
| 271 | break; | |
| 272 | ||
| 273 | case 0xF: /* Clock Setting & Interrupt Registers */ | |
| 274 | if (mm58274c->control & ctl_intsel) | |
| 275 | { | |
| 276 | /* interrupt register (not emulated) */ | |
| 277 | mm58274c->int_ctl = data; | |
| 278 | if (! (mm58274c->control & ctl_intstop)) | |
| 279 | { | |
| 280 | /* interrupt run */ | |
| 281 | attotime period = interrupt_period_table(mm58274c->int_ctl & int_ctl_dly); | |
| 282 | ||
| 283 | mm58274c->interrupt_timer->adjust(period, 0, mm58274c->int_ctl & int_ctl_rpt ? period : attotime::zero); | |
| 284 | } | |
| 285 | } | |
| 286 | else | |
| 287 | { | |
| 288 | /* clock setting register */ | |
| 289 | mm58274c->clk_set = data; | |
| 290 | #if 0 | |
| 291 | if (mm58274c->clk_set & clk_set_24) | |
| 292 | /* 24-hour mode */ | |
| 293 | mm58274c->clk_set &= ~clk_set_pm; | |
| 294 | #endif | |
| 295 | } | |
| 296 | break; | |
| 297 | } | |
| 298 | } | |
| 299 | ||
| 300 | ||
| 301 | /* | |
| 302 | Set RTC interrupt flag | |
| 303 | */ | |
| 304 | static TIMER_CALLBACK(rtc_interrupt_callback) | |
| 305 | { | |
| 306 | device_t *device = (device_t *)ptr; | |
| 307 | mm58274c_t *mm58274c = get_safe_token(device); | |
| 308 | mm58274c->status |= st_if; | |
| 309 | } | |
| 310 | ||
| 311 | ||
| 312 | /* | |
| 313 | Increment RTC clock (timed interrupt every 1/10s) | |
| 314 | */ | |
| 315 | ||
| 316 | static TIMER_CALLBACK(increment_rtc) | |
| 317 | { | |
| 318 | device_t *device = (device_t *)ptr; | |
| 319 | mm58274c_t *mm58274c = get_safe_token(device); | |
| 320 | if (! (mm58274c->control & ctl_clkstop)) | |
| 321 | { | |
| 322 | mm58274c->status |= st_dcf; | |
| 323 | ||
| 324 | if ((++mm58274c->tenths) == 10) | |
| 325 | { | |
| 326 | mm58274c->tenths = 0; | |
| 327 | ||
| 328 | if ((++mm58274c->seconds2) == 10) | |
| 329 | { | |
| 330 | mm58274c->seconds2 = 0; | |
| 331 | ||
| 332 | if ((++mm58274c->seconds1) == 6) | |
| 333 | { | |
| 334 | mm58274c->seconds1 = 0; | |
| 335 | ||
| 336 | if ((++mm58274c->minutes2) == 10) | |
| 337 | { | |
| 338 | mm58274c->minutes2 = 0; | |
| 339 | ||
| 340 | if ((++mm58274c->minutes1) == 6) | |
| 341 | { | |
| 342 | mm58274c->minutes1 = 0; | |
| 343 | ||
| 344 | if ((++mm58274c->hours2) == 10) | |
| 345 | { | |
| 346 | mm58274c->hours2 = 0; | |
| 347 | ||
| 348 | mm58274c->hours1++; | |
| 349 | } | |
| 350 | ||
| 351 | /* handle wrap-around */ | |
| 352 | if ((! (mm58274c->clk_set & clk_set_24)) | |
| 353 | && ((mm58274c->hours1*10 + mm58274c->hours2) == 12)) | |
| 354 | { | |
| 355 | mm58274c->clk_set ^= clk_set_pm; | |
| 356 | } | |
| 357 | if ((! (mm58274c->clk_set & clk_set_24)) | |
| 358 | && ((mm58274c->hours1*10 + mm58274c->hours2) == 13)) | |
| 359 | { | |
| 360 | mm58274c->hours1 = 0; | |
| 361 | mm58274c->hours2 = 1; | |
| 362 | } | |
| 363 | ||
| 364 | if ((mm58274c->clk_set & clk_set_24) | |
| 365 | && ((mm58274c->hours1*10 + mm58274c->hours2) == 24)) | |
| 366 | { | |
| 367 | mm58274c->hours1 = mm58274c->hours2 = 0; | |
| 368 | } | |
| 369 | ||
| 370 | /* increment day if needed */ | |
| 371 | if ((mm58274c->clk_set & clk_set_24) | |
| 372 | ? ((mm58274c->hours1*10 + mm58274c->hours2) == 0) | |
| 373 | : (((mm58274c->hours1*10 + mm58274c->hours2) == 12) | |
| 374 | && (! (mm58274c->clk_set & clk_set_pm)))) | |
| 375 | { | |
| 376 | int days_in_month; | |
| 377 | ||
| 378 | if ((++mm58274c->days2) == 10) | |
| 379 | { | |
| 380 | mm58274c->days2 = 0; | |
| 381 | ||
| 382 | mm58274c->days1++; | |
| 383 | } | |
| 384 | ||
| 385 | if ((++mm58274c->wday) == 8) | |
| 386 | mm58274c->wday = 1; | |
| 387 | ||
| 388 | { | |
| 389 | static const int days_in_month_array[] = | |
| 390 | { | |
| 391 | 31,28,31, 30,31,30, | |
| 392 | 31,31,30, 31,30,31 | |
| 393 | }; | |
| 394 | ||
| 395 | if (((mm58274c->months1*10 + mm58274c->months2) != 2) || (mm58274c->clk_set & clk_set_leap)) | |
| 396 | days_in_month = days_in_month_array[mm58274c->months1*10 + mm58274c->months2 - 1]; | |
| 397 | else | |
| 398 | days_in_month = 29; | |
| 399 | } | |
| 400 | ||
| 401 | ||
| 402 | if ((mm58274c->days1*10 + mm58274c->days2) == days_in_month+1) | |
| 403 | { | |
| 404 | mm58274c->days1 = 0; | |
| 405 | mm58274c->days2 = 1; | |
| 406 | ||
| 407 | if ((++mm58274c->months2) == 10) | |
| 408 | { | |
| 409 | mm58274c->months2 = 0; | |
| 410 | ||
| 411 | mm58274c->months1++; | |
| 412 | } | |
| 413 | ||
| 414 | if ((mm58274c->months1*10 + mm58274c->months2) == 13) | |
| 415 | { | |
| 416 | mm58274c->months1 = 0; | |
| 417 | mm58274c->months2 = 1; | |
| 418 | ||
| 419 | mm58274c->clk_set = (mm58274c->clk_set & ~clk_set_leap) | |
| 420 | | ((mm58274c->clk_set + clk_set_leap_inc) & clk_set_leap); | |
| 421 | ||
| 422 | if ((++mm58274c->years2) == 10) | |
| 423 | { | |
| 424 | mm58274c->years2 = 0; | |
| 425 | ||
| 426 | if ((++mm58274c->years1) == 10) | |
| 427 | mm58274c->years1 = 0; | |
| 428 | } | |
| 429 | } | |
| 430 | } | |
| 431 | } | |
| 432 | } | |
| 433 | } | |
| 434 | } | |
| 435 | } | |
| 436 | } | |
| 437 | } | |
| 438 | } | |
| 439 | ||
| 440 | /* Device Interface */ | |
| 441 | ||
| 442 | static DEVICE_START( mm58274c ) | |
| 443 | { | |
| 444 | mm58274c_t *mm58274c = get_safe_token(device); | |
| 445 | ||
| 446 | // validate arguments | |
| 447 | assert(device != NULL); | |
| 448 | assert(device->tag() != NULL); | |
| 449 | assert(device->static_config() != NULL); | |
| 450 | ||
| 451 | mm58274c->intf = (const mm58274c_interface*)device->static_config(); | |
| 452 | // register for state saving | |
| 453 | state_save_register_item(device->machine(), "mm58274c", device->tag(), 0, mm58274c->status); | |
| 454 | state_save_register_item(device->machine(), "mm58274c", device->tag(), 0, mm58274c->control); | |
| 455 | state_save_register_item(device->machine(), "mm58274c", device->tag(), 0, mm58274c->clk_set); | |
| 456 | state_save_register_item(device->machine(), "mm58274c", device->tag(), 0, mm58274c->int_ctl); | |
| 457 | state_save_register_item(device->machine(), "mm58274c", device->tag(), 0, mm58274c->wday); | |
| 458 | state_save_register_item(device->machine(), "mm58274c", device->tag(), 0, mm58274c->years1); | |
| 459 | state_save_register_item(device->machine(), "mm58274c", device->tag(), 0, mm58274c->years2); | |
| 460 | state_save_register_item(device->machine(), "mm58274c", device->tag(), 0, mm58274c->months1); | |
| 461 | state_save_register_item(device->machine(), "mm58274c", device->tag(), 0, mm58274c->months2); | |
| 462 | state_save_register_item(device->machine(), "mm58274c", device->tag(), 0, mm58274c->days1); | |
| 463 | state_save_register_item(device->machine(), "mm58274c", device->tag(), 0, mm58274c->days2); | |
| 464 | state_save_register_item(device->machine(), "mm58274c", device->tag(), 0, mm58274c->hours1); | |
| 465 | state_save_register_item(device->machine(), "mm58274c", device->tag(), 0, mm58274c->hours2); | |
| 466 | state_save_register_item(device->machine(), "mm58274c", device->tag(), 0, mm58274c->minutes1); | |
| 467 | state_save_register_item(device->machine(), "mm58274c", device->tag(), 0, mm58274c->minutes2); | |
| 468 | state_save_register_item(device->machine(), "mm58274c", device->tag(), 0, mm58274c->seconds1); | |
| 469 | state_save_register_item(device->machine(), "mm58274c", device->tag(), 0, mm58274c->seconds2); | |
| 470 | state_save_register_item(device->machine(), "mm58274c", device->tag(), 0, mm58274c->tenths); | |
| 471 | ||
| 472 | mm58274c->increment_rtc = device->machine().scheduler().timer_alloc(FUNC(increment_rtc), ((void*)device)); | |
| 473 | mm58274c->increment_rtc->adjust(attotime::zero, 0, attotime::from_msec(100)); | |
| 474 | mm58274c->interrupt_timer = device->machine().scheduler().timer_alloc(FUNC(rtc_interrupt_callback), ((void*)device)); | |
| 475 | } | |
| 476 | ||
| 477 | ||
| 478 | static DEVICE_RESET( mm58274c ) | |
| 479 | { | |
| 480 | mm58274c_t *mm58274c = get_safe_token(device); | |
| 481 | system_time systime; | |
| 482 | ||
| 483 | /* get the current date/time from the core */ | |
| 484 | device->machine().current_datetime(systime); | |
| 485 | ||
| 486 | mm58274c->clk_set = systime.local_time.year & 3 << 2; | |
| 487 | if (mm58274c->intf->mode24) | |
| 488 | mm58274c->clk_set |= clk_set_24; | |
| 489 | ||
| 490 | /* The clock count starts on 1st January 1900 */ | |
| 491 | mm58274c->wday = 1 + ((systime.local_time.weekday - mm58274c->intf->day1)%7); | |
| 492 | mm58274c->years1 = (systime.local_time.year / 10) % 10; | |
| 493 | mm58274c->years2 = systime.local_time.year % 10; | |
| 494 | mm58274c->months1 = (systime.local_time.month + 1) / 10; | |
| 495 | mm58274c->months2 = (systime.local_time.month + 1) % 10; | |
| 496 | mm58274c->days1 = systime.local_time.mday / 10; | |
| 497 | mm58274c->days2 = systime.local_time.mday % 10; | |
| 498 | if (!mm58274c->intf->mode24) | |
| 499 | { | |
| 500 | /* 12-hour mode */ | |
| 501 | if (systime.local_time.hour > 12) | |
| 502 | { | |
| 503 | systime.local_time.hour -= 12; | |
| 504 | mm58274c->clk_set |= clk_set_pm; | |
| 505 | } | |
| 506 | if (systime.local_time.hour == 0) | |
| 507 | systime.local_time.hour = 12; | |
| 508 | } | |
| 509 | mm58274c->hours1 = systime.local_time.hour / 10; | |
| 510 | mm58274c->hours2 = systime.local_time.hour % 10; | |
| 511 | mm58274c->minutes1 = systime.local_time.minute / 10; | |
| 512 | mm58274c->minutes2 = systime.local_time.minute % 10; | |
| 513 | mm58274c->seconds1 = systime.local_time.second / 10; | |
| 514 | mm58274c->seconds2 = systime.local_time.second % 10; | |
| 515 | mm58274c->tenths = 0; | |
| 516 | } | |
| 517 | ||
| 518 | const device_type MM58274C = &device_creator<mm58274c_device>; | |
| 519 | ||
| 520 | mm58274c_device::mm58274c_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) | |
| 521 | : device_t(mconfig, MM58274C, "National Semiconductor MM58274C", tag, owner, clock) | |
| 522 | { | |
| 523 | m_token = global_alloc_clear(mm58274c_t); | |
| 524 | } | |
| 525 | ||
| 526 | //------------------------------------------------- | |
| 527 | // device_config_complete - perform any | |
| 528 | // operations now that the configuration is | |
| 529 | // complete | |
| 530 | //------------------------------------------------- | |
| 531 | ||
| 532 | void mm58274c_device::device_config_complete() | |
| 533 | { | |
| 534 | } | |
| 535 | ||
| 536 | //------------------------------------------------- | |
| 537 | // device_start - device-specific startup | |
| 538 | //------------------------------------------------- | |
| 539 | ||
| 540 | void mm58274c_device::device_start() | |
| 541 | { | |
| 542 | DEVICE_START_NAME( mm58274c )(this); | |
| 543 | } | |
| 544 | ||
| 545 | //------------------------------------------------- | |
| 546 | // device_reset - device-specific reset | |
| 547 | //------------------------------------------------- | |
| 548 | ||
| 549 | void mm58274c_device::device_reset() | |
| 550 | { | |
| 551 | DEVICE_RESET_NAME( mm58274c )(this); | |
| 552 | } |
| Added: svn:eol-style + native Added: svn:mime-type + text/plain |
| r0 | r21685 | |
|---|---|---|
| 1 | /********************************************************************** | |
| 2 | ||
| 3 | Copyright (C) Antoine Mine' 2006 | |
| 4 | ||
| 5 | Motorola 6846 emulation. | |
| 6 | ||
| 7 | The MC6846 chip provides ROM (2048 bytes), I/O (8-bit directional data port + | |
| 8 | 2 control lines) and a programmable timer. | |
| 9 | It may be interfaced with a M6809 cpu. | |
| 10 | It is used in some Thomson computers. | |
| 11 | ||
| 12 | Not yet implemented: | |
| 13 | - external clock (CTC) | |
| 14 | - latching of port on CP1 | |
| 15 | - gate input (CTG) | |
| 16 | - timer comparison modes (frequency and pulse width) | |
| 17 | - CP2 acknowledge modes | |
| 18 | ||
| 19 | **********************************************************************/ | |
| 20 | ||
| 21 | #include "emu.h" | |
| 22 | #include "mc6846.h" | |
| 23 | ||
| 24 | #define VERBOSE 0 | |
| 25 | ||
| 26 | ||
| 27 | ||
| 28 | /******************* internal chip data structure ******************/ | |
| 29 | ||
| 30 | ||
| 31 | struct mc6846_t | |
| 32 | { | |
| 33 | const mc6846_interface* iface; | |
| 34 | ||
| 35 | /* registers */ | |
| 36 | UINT8 csr; /* 0,4: combination status register */ | |
| 37 | UINT8 pcr; /* 1: peripheral control register */ | |
| 38 | UINT8 ddr; /* 2: data direction register */ | |
| 39 | UINT8 pdr; /* 3: peripheral data register (last cpu write) */ | |
| 40 | UINT8 tcr; /* 5: timer control register */ | |
| 41 | ||
| 42 | /* lines */ | |
| 43 | UINT8 cp1; /* 1-bit input */ | |
| 44 | UINT8 cp2; /* 1-bit input/output: last external write */ | |
| 45 | UINT8 cp2_cpu; /* last cpu write */ | |
| 46 | UINT8 cto; /* 1-bit timer output (unmasked) */ | |
| 47 | ||
| 48 | /* internal state */ | |
| 49 | UINT8 time_MSB; /* MSB buffer register */ | |
| 50 | UINT8 csr0_to_be_cleared; | |
| 51 | UINT8 csr1_to_be_cleared; | |
| 52 | UINT8 csr2_to_be_cleared; | |
| 53 | UINT16 latch; /* timer latch */ | |
| 54 | UINT16 preset; /* preset value */ | |
| 55 | UINT8 timer_started; | |
| 56 | ||
| 57 | /* timers */ | |
| 58 | emu_timer *interval; /* interval programmable timer */ | |
| 59 | emu_timer *one_shot; /* 1-us x factor one-shot timer */ | |
| 60 | ||
| 61 | /* CPU write to the outside through chip */ | |
| 62 | devcb_resolved_write8 out_port; /* 8-bit output */ | |
| 63 | devcb_resolved_write8 out_cp1; /* 1-bit output */ | |
| 64 | devcb_resolved_write8 out_cp2; /* 1-bit output */ | |
| 65 | ||
| 66 | /* CPU read from the outside through chip */ | |
| 67 | devcb_resolved_read8 in_port; /* 8-bit input */ | |
| 68 | ||
| 69 | /* asynchronous timer output to outside world */ | |
| 70 | devcb_resolved_write8 out_cto; /* 1-bit output */ | |
| 71 | ||
| 72 | /* timer interrupt */ | |
| 73 | devcb_resolved_write_line irq; | |
| 74 | ||
| 75 | int old_cif; | |
| 76 | int old_cto; | |
| 77 | }; | |
| 78 | ||
| 79 | ||
| 80 | ||
| 81 | /******************* utility function and macros ********************/ | |
| 82 | ||
| 83 | #define LOG(x) do { if (VERBOSE) logerror x; } while (0) | |
| 84 | ||
| 85 | #define PORT \ | |
| 86 | ((mc6846->pdr & mc6846->ddr) | \ | |
| 87 | ((!mc6846->in_port.isnull() ? mc6846->in_port( 0 ) : 0) & \ | |
| 88 | ~mc6846->ddr)) | |
| 89 | ||
| 90 | #define CTO \ | |
| 91 | ((MODE == 0x30 || (mc6846->tcr & 0x80)) ? mc6846->cto : 0) | |
| 92 | ||
| 93 | #define MODE (mc6846->tcr & 0x38) | |
| 94 | ||
| 95 | #define FACTOR ((mc6846->tcr & 4) ? 8 : 1) | |
| 96 | ||
| 97 | ||
| 98 | ||
| 99 | INLINE mc6846_t* get_safe_token( device_t *device ) | |
| 100 | { | |
| 101 | assert( device != NULL ); | |
| 102 | assert( device->type() == MC6846 ); | |
| 103 | return (mc6846_t*) downcast<mc6846_device *>(device)->token(); | |
| 104 | } | |
| 105 | ||
| 106 | ||
| 107 | INLINE UINT16 mc6846_counter( device_t *device ) | |
| 108 | { | |
| 109 | mc6846_t* mc6846 = get_safe_token( device ); | |
| 110 | if ( mc6846->timer_started ) | |
| 111 | { | |
| 112 | attotime delay = mc6846->interval ->remaining( ); | |
| 113 | return delay.as_ticks(1000000) / FACTOR; | |
| 114 | } | |
| 115 | else | |
| 116 | return mc6846->preset; | |
| 117 | } | |
| 118 | ||
| 119 | ||
| 120 | ||
| 121 | INLINE void mc6846_update_irq( device_t *device ) | |
| 122 | { | |
| 123 | mc6846_t* mc6846 = get_safe_token( device ); | |
| 124 | int cif = 0; | |
| 125 | /* composite interrupt flag */ | |
| 126 | if ( ( (mc6846->csr & 1) && (mc6846->tcr & 0x40) ) || | |
| 127 | ( (mc6846->csr & 2) && (mc6846->pcr & 1) ) || | |
| 128 | ( (mc6846->csr & 4) && (mc6846->pcr & 8) && ! (mc6846->pcr & 0x20) ) ) | |
| 129 | cif = 1; | |
| 130 | if ( mc6846->old_cif != cif ) | |
| 131 | { | |
| 132 | LOG (( "%f: mc6846 interrupt %i (time=%i cp1=%i cp2=%i)\n", | |
| 133 | device->machine().time().as_double(), cif, | |
| 134 | mc6846->csr & 1, (mc6846->csr >> 1 ) & 1, (mc6846->csr >> 2 ) & 1 )); | |
| 135 | mc6846->old_cif = cif; | |
| 136 | } | |
| 137 | if ( cif ) | |
| 138 | { | |
| 139 | mc6846->csr |= 0x80; | |
| 140 | if ( !mc6846->irq.isnull() ) | |
| 141 | mc6846->irq( 1 ); | |
| 142 | } | |
| 143 | else | |
| 144 | { | |
| 145 | mc6846->csr &= ~0x80; | |
| 146 | if ( !mc6846->irq.isnull() ) | |
| 147 | mc6846->irq( 0 ); | |
| 148 | } | |
| 149 | } | |
| 150 | ||
| 151 | ||
| 152 | ||
| 153 | INLINE void mc6846_update_cto ( device_t *device ) | |
| 154 | { | |
| 155 | mc6846_t* mc6846 = get_safe_token( device ); | |
| 156 | int cto = CTO; | |
| 157 | if ( cto != mc6846->old_cto ) | |
| 158 | { | |
| 159 | LOG (( "%f: mc6846 CTO set to %i\n", device->machine().time().as_double(), cto )); | |
| 160 | mc6846->old_cto = cto; | |
| 161 | } | |
| 162 | if ( !mc6846->out_cto.isnull() ) | |
| 163 | mc6846->out_cto( 0, cto ); | |
| 164 | } | |
| 165 | ||
| 166 | ||
| 167 | ||
| 168 | INLINE void mc6846_timer_launch ( device_t *device ) | |
| 169 | { | |
| 170 | mc6846_t* mc6846 = get_safe_token( device ); | |
| 171 | int delay = FACTOR * (mc6846->preset+1); | |
| 172 | LOG (( "%f: mc6846 timer launch called, mode=%i, preset=%i (x%i)\n", device->machine().time().as_double(), MODE, mc6846->preset, FACTOR )); | |
| 173 | ||
| 174 | if ( ! (mc6846->tcr & 2) ) | |
| 175 | { | |
| 176 | logerror( "mc6846 external clock CTC not implemented\n" ); | |
| 177 | } | |
| 178 | ||
| 179 | switch( MODE ) | |
| 180 | { | |
| 181 | case 0x00: | |
| 182 | case 0x10: /* continuous */ | |
| 183 | mc6846->cto = 0; | |
| 184 | break; | |
| 185 | ||
| 186 | case 0x20: /* single-shot */ | |
| 187 | mc6846->cto = 0; | |
| 188 | mc6846->one_shot->reset( attotime::from_usec(FACTOR) ); | |
| 189 | break; | |
| 190 | ||
| 191 | case 0x30: /* cascaded single-shot */ | |
| 192 | break; | |
| 193 | ||
| 194 | default: | |
| 195 | logerror( "mc6846 timer mode %i not implemented\n", MODE ); | |
| 196 | mc6846->interval->reset( ); | |
| 197 | mc6846->timer_started = 0; | |
| 198 | return; | |
| 199 | } | |
| 200 | ||
| 201 | mc6846->interval->reset( attotime::from_usec(delay) ); | |
| 202 | mc6846->timer_started = 1; | |
| 203 | ||
| 204 | mc6846->csr &= ~1; | |
| 205 | mc6846_update_cto( device ); | |
| 206 | mc6846_update_irq( device ); | |
| 207 | } | |
| 208 | ||
| 209 | ||
| 210 | ||
| 211 | /******************* timer callbacks *********************************/ | |
| 212 | ||
| 213 | static TIMER_CALLBACK( mc6846_timer_expire ) | |
| 214 | { | |
| 215 | device_t* device = (device_t*) ptr; | |
| 216 | mc6846_t* mc6846 = get_safe_token( device ); | |
| 217 | int delay = FACTOR * (mc6846->latch+1); | |
| 218 | ||
| 219 | LOG (( "%f: mc6846 timer expire called, mode=%i, latch=%i (x%i)\n", device->machine().time().as_double(), MODE, mc6846->latch, FACTOR )); | |
| 220 | ||
| 221 | /* latch => counter */ | |
| 222 | mc6846->preset = mc6846->latch; | |
| 223 | ||
| 224 | if ( ! (mc6846->tcr & 2) ) | |
| 225 | logerror( "mc6846 external clock CTC not implemented\n" ); | |
| 226 | ||
| 227 | switch ( MODE ) | |
| 228 | { | |
| 229 | case 0x00: | |
| 230 | case 0x10: /* continuous */ | |
| 231 | mc6846->cto = 1 ^ mc6846->cto; | |
| 232 | break; | |
| 233 | ||
| 234 | case 0x20: /* single-shot */ | |
| 235 | mc6846->cto = 0; | |
| 236 | break; | |
| 237 | ||
| 238 | case 0x30: /* cascaded single-shot */ | |
| 239 | mc6846->cto = ( mc6846->tcr & 0x80 ) ? 1 : 0; | |
| 240 | break; | |
| 241 | ||
| 242 | default: | |
| 243 | logerror( "mc6846 timer mode %i not implemented\n", MODE ); | |
| 244 | mc6846->interval->reset( ); | |
| 245 | mc6846->timer_started = 0; | |
| 246 | return; | |
| 247 | } | |
| 248 | ||
| 249 | mc6846->interval->reset( attotime::from_usec(delay) ); | |
| 250 | ||
| 251 | mc6846->csr |= 1; | |
| 252 | mc6846_update_cto( device ); | |
| 253 | mc6846_update_irq( device ); | |
| 254 | } | |
| 255 | ||
| 256 | ||
| 257 | ||
| 258 | static TIMER_CALLBACK( mc6846_timer_one_shot ) | |
| 259 | { | |
| 260 | device_t* device = (device_t*) ptr; | |
| 261 | mc6846_t* mc6846 = get_safe_token( device ); | |
| 262 | LOG (( "%f: mc6846 timer one shot called\n", device->machine().time().as_double() )); | |
| 263 | ||
| 264 | /* 1 micro second after one-shot launch, we put cto to high */ | |
| 265 | mc6846->cto = 1; | |
| 266 | mc6846_update_cto( device ); | |
| 267 | } | |
| 268 | ||
| 269 | ||
| 270 | ||
| 271 | /************************** CPU interface ****************************/ | |
| 272 | ||
| 273 | ||
| 274 | READ8_DEVICE_HANDLER ( mc6846_r ) | |
| 275 | { | |
| 276 | mc6846_t* mc6846 = get_safe_token( device ); | |
| 277 | switch ( offset ) | |
| 278 | { | |
| 279 | case 0: | |
| 280 | case 4: | |
| 281 | LOG (( "$%04x %f: mc6846 CSR read $%02X intr=%i (timer=%i, cp1=%i, cp2=%i)\n", | |
| 282 | space.machine().firstcpu->pcbase( ), space.machine().time().as_double(), | |
| 283 | mc6846->csr, (mc6846->csr >> 7) & 1, | |
| 284 | mc6846->csr & 1, (mc6846->csr >> 1) & 1, (mc6846->csr >> 2) & 1 )); | |
| 285 | mc6846->csr0_to_be_cleared = mc6846->csr & 1; | |
| 286 | mc6846->csr1_to_be_cleared = mc6846->csr & 2; | |
| 287 | mc6846->csr2_to_be_cleared = mc6846->csr & 4; | |
| 288 | return mc6846->csr; | |
| 289 | ||
| 290 | case 1: | |
| 291 | LOG (( "$%04x %f: mc6846 PCR read $%02X\n", space.machine().firstcpu->pcbase( ), space.machine().time().as_double(), mc6846->pcr )); | |
| 292 | return mc6846->pcr; | |
| 293 | ||
| 294 | case 2: | |
| 295 | LOG (( "$%04x %f: mc6846 DDR read $%02X\n", space.machine().firstcpu->pcbase( ), space.machine().time().as_double(), mc6846->ddr )); | |
| 296 | return mc6846->ddr; | |
| 297 | ||
| 298 | case 3: | |
| 299 | LOG (( "$%04x %f: mc6846 PORT read $%02X\n", space.machine().firstcpu->pcbase( ), space.machine().time().as_double(), PORT )); | |
| 300 | if ( ! (mc6846->pcr & 0x80) ) | |
| 301 | { | |
| 302 | if ( mc6846->csr1_to_be_cleared ) | |
| 303 | mc6846->csr &= ~2; | |
| 304 | if ( mc6846->csr2_to_be_cleared ) | |
| 305 | mc6846->csr &= ~4; | |
| 306 | mc6846_update_irq( device ); | |
| 307 | mc6846->csr1_to_be_cleared = 0; | |
| 308 | mc6846->csr2_to_be_cleared = 0; | |
| 309 | } | |
| 310 | return PORT; | |
| 311 | ||
| 312 | case 5: | |
| 313 | LOG (( "$%04x %f: mc6846 TCR read $%02X\n",space.machine().firstcpu->pcbase( ), space.machine().time().as_double(), mc6846->tcr )); | |
| 314 | return mc6846->tcr; | |
| 315 | ||
| 316 | case 6: | |
| 317 | LOG (( "$%04x %f: mc6846 COUNTER hi read $%02X\n", space.machine().firstcpu->pcbase( ), space.machine().time().as_double(), mc6846_counter( device ) >> 8 )); | |
| 318 | if ( mc6846->csr0_to_be_cleared ) | |
| 319 | { | |
| 320 | mc6846->csr &= ~1; | |
| 321 | mc6846_update_irq( device ); | |
| 322 | } | |
| 323 | mc6846->csr0_to_be_cleared = 0; | |
| 324 | return mc6846_counter( device ) >> 8; | |
| 325 | ||
| 326 | case 7: | |
| 327 | LOG (( "$%04x %f: mc6846 COUNTER low read $%02X\n", space.machine().firstcpu->pcbase( ), space.machine().time().as_double(), mc6846_counter( device ) & 0xff )); | |
| 328 | if ( mc6846->csr0_to_be_cleared ) | |
| 329 | { | |
| 330 | mc6846->csr &= ~1; | |
| 331 | mc6846_update_irq( device ); | |
| 332 | } | |
| 333 | mc6846->csr0_to_be_cleared = 0; | |
| 334 | return mc6846_counter( device ) & 0xff; | |
| 335 | ||
| 336 | default: | |
| 337 | logerror( "$%04x mc6846 invalid read offset %i\n", space.machine().firstcpu->pcbase( ), offset ); | |
| 338 | } | |
| 339 | return 0; | |
| 340 | } | |
| 341 | ||
| 342 | ||
| 343 | ||
| 344 | WRITE8_DEVICE_HANDLER ( mc6846_w ) | |
| 345 | { | |
| 346 | mc6846_t* mc6846 = get_safe_token( device ); | |
| 347 | switch ( offset ) | |
| 348 | { | |
| 349 | case 0: | |
| 350 | case 4: | |
| 351 | /* CSR is read-only */ | |
| 352 | break; | |
| 353 | ||
| 354 | case 1: | |
| 355 | { | |
| 356 | static const char *const cp2[8] = | |
| 357 | { | |
| 358 | "in,neg-edge", "in,neg-edge,intr", "in,pos-edge", "in,pos-edge,intr", | |
| 359 | "out,intr-ack", "out,i/o-ack", "out,0", "out,1" | |
| 360 | }; | |
| 361 | static const char *const cp1[8] = | |
| 362 | { | |
| 363 | "neg-edge", "neg-edge,intr", "pos-edge", "pos-edge,intr", | |
| 364 | "latched,neg-edge", "latched,neg-edge,intr", | |
| 365 | "latcged,pos-edge", "latcged,pos-edge,intr" | |
| 366 | }; | |
| 367 | LOG (( "$%04x %f: mc6846 PCR write $%02X reset=%i cp2=%s cp1=%s\n", | |
| 368 | space.machine().firstcpu->pcbase( ), space.machine().time().as_double(), data, | |
| 369 | (data >> 7) & 1, cp2[ (data >> 3) & 7 ], cp1[ data & 7 ] )); | |
| 370 | ||
| 371 | } | |
| 372 | mc6846->pcr = data; | |
| 373 | if ( data & 0x80 ) | |
| 374 | { /* data reset */ | |
| 375 | mc6846->pdr = 0; | |
| 376 | mc6846->ddr = 0; | |
| 377 | mc6846->csr &= ~6; | |
| 378 | mc6846_update_irq( device ); | |
| 379 | } | |
| 380 | if ( data & 4 ) | |
| 381 | logerror( "$%04x mc6846 CP1 latching not implemented\n", space.machine().firstcpu->pcbase( ) ); | |
| 382 | if (data & 0x20) | |
| 383 | { | |
| 384 | if (data & 0x10) | |
| 385 | { | |
| 386 | mc6846->cp2_cpu = (data >> 3) & 1; | |
| 387 | if ( !mc6846->out_cp2.isnull() ) | |
| 388 | mc6846->out_cp2( 0, mc6846->cp2_cpu ); | |
| 389 | } | |
| 390 | else | |
| 391 | logerror( "$%04x mc6846 acknowledge not implemented\n", space.machine().firstcpu->pcbase( ) ); | |
| 392 | } | |
| 393 | break; | |
| 394 | ||
| 395 | case 2: | |
| 396 | LOG (( "$%04x %f: mc6846 DDR write $%02X\n", space.machine().firstcpu->pcbase( ), space.machine().time().as_double(), data )); | |
| 397 | if ( ! (mc6846->pcr & 0x80) ) | |
| 398 | { | |
| 399 | mc6846->ddr = data; | |
| 400 | if ( !mc6846->out_port.isnull() ) | |
| 401 | mc6846->out_port( 0, mc6846->pdr & mc6846->ddr ); | |
| 402 | } | |
| 403 | break; | |
| 404 | ||
| 405 | case 3: | |
| 406 | LOG (( "$%04x %f: mc6846 PORT write $%02X (mask=$%02X)\n", space.machine().firstcpu->pcbase( ), space.machine().time().as_double(), data,mc6846->ddr )); | |
| 407 | if ( ! (mc6846->pcr & 0x80) ) | |
| 408 | { | |
| 409 | mc6846->pdr = data; | |
| 410 | if ( !mc6846->out_port.isnull() ) | |
| 411 | mc6846->out_port( 0, mc6846->pdr & mc6846->ddr ); | |
| 412 | if ( mc6846->csr1_to_be_cleared && (mc6846->csr & 2) ) | |
| 413 | { | |
| 414 | mc6846->csr &= ~2; | |
| 415 | LOG (( "$%04x %f: mc6846 CP1 intr reset\n", space.machine().firstcpu->pcbase( ), space.machine().time().as_double() )); | |
| 416 | } | |
| 417 | if ( mc6846->csr2_to_be_cleared && (mc6846->csr & 4) ) | |
| 418 | { | |
| 419 | mc6846->csr &= ~4; | |
| 420 | LOG (( "$%04x %f: mc6846 CP2 intr reset\n", space.machine().firstcpu->pcbase( ), space.machine().time().as_double() )); | |
| 421 | } | |
| 422 | mc6846->csr1_to_be_cleared = 0; | |
| 423 | mc6846->csr2_to_be_cleared = 0; | |
| 424 | mc6846_update_irq( device ); | |
| 425 | } | |
| 426 | break; | |
| 427 | ||
| 428 | case 5: | |
| 429 | { | |
| 430 | static const char *const mode[8] = | |
| 431 | { | |
| 432 | "continuous", "cascaded", "continuous", "one-shot", | |
| 433 | "freq-cmp", "freq-cmp", "pulse-cmp", "pulse-cmp" | |
| 434 | }; | |
| 435 | LOG (( "$%04x %f: mc6846 TCR write $%02X reset=%i clock=%s scale=%i mode=%s out=%s\n", | |
| 436 | space.machine().firstcpu->pcbase( ), space.machine().time().as_double(), data, | |
| 437 | (data >> 7) & 1, (data & 0x40) ? "extern" : "sys", | |
| 438 | (data & 0x40) ? 1 : 8, mode[ (data >> 1) & 7 ], | |
| 439 | (data & 1) ? "enabled" : "0" )); | |
| 440 | ||
| 441 | mc6846->tcr = data; | |
| 442 | if ( mc6846->tcr & 1 ) | |
| 443 | { | |
| 444 | /* timer preset = initialization without launch */ | |
| 445 | mc6846->preset = mc6846->latch; | |
| 446 | mc6846->csr &= ~1; | |
| 447 | if ( MODE != 0x30 ) | |
| 448 | mc6846->cto = 0; | |
| 449 | mc6846_update_cto( device ); | |
| 450 | mc6846->interval->reset( ); | |
| 451 | mc6846->one_shot->reset( ); | |
| 452 | mc6846->timer_started = 0; | |
| 453 | } | |
| 454 | else | |
| 455 | { | |
| 456 | /* timer launch */ | |
| 457 | if ( ! mc6846->timer_started ) | |
| 458 | mc6846_timer_launch( device ); | |
| 459 | } | |
| 460 | mc6846_update_irq( device ); | |
| 461 | } | |
| 462 | break; | |
| 463 | ||
| 464 | case 6: | |
| 465 | mc6846->time_MSB = data; | |
| 466 | break; | |
| 467 | ||
| 468 | case 7: | |
| 469 | mc6846->latch = ( ((UINT16) mc6846->time_MSB) << 8 ) + data; | |
| 470 | LOG (( "$%04x %f: mc6846 COUNT write %i\n", space.machine().firstcpu->pcbase( ), space.machine().time().as_double(), mc6846->latch )); | |
| 471 | if (!(mc6846->tcr & 0x38)) | |
| 472 | { | |
| 473 | /* timer initialization */ | |
| 474 | mc6846->preset = mc6846->latch; | |
| 475 | mc6846->csr &= ~1; | |
| 476 | mc6846_update_irq( device ); | |
| 477 | mc6846->cto = 0; | |
| 478 | mc6846_update_cto( device ); | |
| 479 | /* launch only if started */ | |
| 480 | if (!(mc6846->tcr & 1)) | |
| 481 | mc6846_timer_launch( device ); | |
| 482 | } | |
| 483 | break; | |
| 484 | ||
| 485 | default: | |
| 486 | logerror( "$%04x mc6846 invalid write offset %i\n", space.machine().firstcpu->pcbase( ), offset ); | |
| 487 | } | |
| 488 | } | |
| 489 | ||
| 490 | ||
| 491 | ||
| 492 | /******************** outside world interface ************************/ | |
| 493 | ||
| 494 | ||
| 495 | ||
| 496 | void mc6846_set_input_cp1 ( device_t *device, int data ) | |
| 497 | { | |
| 498 | mc6846_t* mc6846 = get_safe_token( device ); | |
| 499 | data = (data != 0 ); | |
| 500 | if ( data == mc6846->cp1 ) | |
| 501 | return; | |
| 502 | mc6846->cp1 = data; | |
| 503 | LOG (( "%f: mc6846 input CP1 set to %i\n", device->machine().time().as_double(), data )); | |
| 504 | if (( data && (mc6846->pcr & 2)) || (!data && !(mc6846->pcr & 2))) | |
| 505 | { | |
| 506 | mc6846->csr |= 2; | |
| 507 | mc6846_update_irq( device ); | |
| 508 | } | |
| 509 | } | |
| 510 | ||
| 511 | void mc6846_set_input_cp2 ( device_t *device, int data ) | |
| 512 | { | |
| 513 | mc6846_t* mc6846 = get_safe_token( device ); | |
| 514 | data = (data != 0 ); | |
| 515 | if ( data == mc6846->cp2 ) | |
| 516 | return; | |
| 517 | mc6846->cp2 = data; | |
| 518 | LOG (( "%f: mc6846 input CP2 set to %i\n", device->machine().time().as_double(), data )); | |
| 519 | if (mc6846->pcr & 0x20) | |
| 520 | { | |
| 521 | if (( data && (mc6846->pcr & 0x10)) || (!data && !(mc6846->pcr & 0x10))) | |
| 522 | { | |
| 523 | mc6846->csr |= 4; | |
| 524 | mc6846_update_irq( device ); | |
| 525 | } | |
| 526 | } | |
| 527 | } | |
| 528 | ||
| 529 | ||
| 530 | ||
| 531 | /************************ accessors **********************************/ | |
| 532 | ||
| 533 | ||
| 534 | ||
| 535 | UINT8 mc6846_get_output_port ( device_t *device ) | |
| 536 | { | |
| 537 | mc6846_t* mc6846 = get_safe_token( device ); | |
| 538 | return PORT; | |
| 539 | } | |
| 540 | ||
| 541 | ||
| 542 | ||
| 543 | UINT8 mc6846_get_output_cto ( device_t *device ) | |
| 544 | { | |
| 545 | mc6846_t* mc6846 = get_safe_token( device ); | |
| 546 | return CTO; | |
| 547 | } | |
| 548 | ||
| 549 | ||
| 550 | ||
| 551 | UINT8 mc6846_get_output_cp2 ( device_t *device ) | |
| 552 | { | |
| 553 | mc6846_t* mc6846 = get_safe_token( device ); | |
| 554 | return mc6846->cp2_cpu; | |
| 555 | } | |
| 556 | ||
| 557 | ||
| 558 | ||
| 559 | UINT16 mc6846_get_preset ( device_t *device ) | |
| 560 | { | |
| 561 | mc6846_t* mc6846 = get_safe_token( device ); | |
| 562 | return mc6846->preset; | |
| 563 | } | |
| 564 | ||
| 565 | ||
| 566 | ||
| 567 | /************************ reset *****************************/ | |
| 568 | ||
| 569 | ||
| 570 | static DEVICE_RESET( mc6846 ) | |
| 571 | { | |
| 572 | mc6846_t* mc6846 = get_safe_token( device ); | |
| 573 | LOG (( "mc6846_reset\n" )); | |
| 574 | mc6846->cto = 0; | |
| 575 | mc6846->csr = 0; | |
| 576 | mc6846->pcr = 0x80; | |
| 577 | mc6846->ddr = 0; | |
| 578 | mc6846->pdr = 0; | |
| 579 | mc6846->tcr = 1; | |
| 580 | mc6846->cp1 = 0; | |
| 581 | mc6846->cp2 = 0; | |
| 582 | mc6846->cp2_cpu = 0; | |
| 583 | mc6846->latch = 0xffff; | |
| 584 | mc6846->preset = 0xffff; | |
| 585 | mc6846->time_MSB = 0; | |
| 586 | mc6846->csr0_to_be_cleared = 0; | |
| 587 | mc6846->csr1_to_be_cleared = 0; | |
| 588 | mc6846->csr2_to_be_cleared = 0; | |
| 589 | mc6846->timer_started = 0; | |
| 590 | mc6846->interval->reset( ); | |
| 591 | mc6846->one_shot->reset( ); | |
| 592 | } | |
| 593 | ||
| 594 | ||
| 595 | /************************ start *****************************/ | |
| 596 | ||
| 597 | static DEVICE_START( mc6846 ) | |
| 598 | { | |
| 599 | mc6846_t* mc6846 = get_safe_token( device ); | |
| 600 | ||
| 601 | mc6846->iface = (const mc6846_interface*)device->static_config(); | |
| 602 | mc6846->interval = device->machine().scheduler().timer_alloc(FUNC(mc6846_timer_expire), (void*) device ); | |
| 603 | mc6846->one_shot = device->machine().scheduler().timer_alloc(FUNC(mc6846_timer_one_shot), (void*) device ); | |
| 604 | ||
| 605 | mc6846->out_port.resolve(mc6846->iface->out_port_func, *device); /* 8-bit output */ | |
| 606 | mc6846->out_cp1.resolve(mc6846->iface->out_cp1_func, *device); /* 1-bit output */ | |
| 607 | mc6846->out_cp2.resolve(mc6846->iface->out_cp2_func, *device); /* 1-bit output */ | |
| 608 | ||
| 609 | /* CPU read from the outside through chip */ | |
| 610 | mc6846->in_port.resolve(mc6846->iface->in_port_func, *device); /* 8-bit input */ | |
| 611 | ||
| 612 | /* asynchronous timer output to outside world */ | |
| 613 | mc6846->out_cto.resolve(mc6846->iface->out_cto_func, *device); /* 1-bit output */ | |
| 614 | ||
| 615 | /* timer interrupt */ | |
| 616 | mc6846->irq.resolve(mc6846->iface->irq_func, *device); | |
| 617 | ||
| 618 | state_save_register_item( device->machine(), "mc6846", device->tag(), 0, mc6846->csr ); | |
| 619 | state_save_register_item( device->machine(), "mc6846", device->tag(), 0, mc6846->pcr ); | |
| 620 | state_save_register_item( device->machine(), "mc6846", device->tag(), 0, mc6846->ddr ); | |
| 621 | state_save_register_item( device->machine(), "mc6846", device->tag(), 0, mc6846->pdr ); | |
| 622 | state_save_register_item( device->machine(), "mc6846", device->tag(), 0, mc6846->tcr ); | |
| 623 | state_save_register_item( device->machine(), "mc6846", device->tag(), 0, mc6846->cp1 ); | |
| 624 | state_save_register_item( device->machine(), "mc6846", device->tag(), 0, mc6846->cp2 ); | |
| 625 | state_save_register_item( device->machine(), "mc6846", device->tag(), 0, mc6846->cp2_cpu ); | |
| 626 | state_save_register_item( device->machine(), "mc6846", device->tag(), 0, mc6846->cto ); | |
| 627 | state_save_register_item( device->machine(), "mc6846", device->tag(), 0, mc6846->time_MSB ); | |
| 628 | state_save_register_item( device->machine(), "mc6846", device->tag(), 0, mc6846->csr0_to_be_cleared ); | |
| 629 | state_save_register_item( device->machine(), "mc6846", device->tag(), 0, mc6846->csr1_to_be_cleared ); | |
| 630 | state_save_register_item( device->machine(), "mc6846", device->tag(), 0, mc6846->csr2_to_be_cleared ); | |
| 631 | state_save_register_item( device->machine(), "mc6846", device->tag(), 0, mc6846->latch ); | |
| 632 | state_save_register_item( device->machine(), "mc6846", device->tag(), 0, mc6846->preset ); | |
| 633 | state_save_register_item( device->machine(), "mc6846", device->tag(), 0, mc6846->timer_started ); | |
| 634 | } | |
| 635 | ||
| 636 | ||
| 637 | const device_type MC6846 = &device_creator<mc6846_device>; | |
| 638 | ||
| 639 | mc6846_device::mc6846_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) | |
| 640 | : device_t(mconfig, MC6846, "Motorola MC6846 programmable timer", tag, owner, clock) | |
| 641 | { | |
| 642 | m_token = global_alloc_clear(mc6846_t); | |
| 643 | } | |
| 644 | ||
| 645 | //------------------------------------------------- | |
| 646 | // device_config_complete - perform any | |
| 647 | // operations now that the configuration is | |
| 648 | // complete | |
| 649 | //------------------------------------------------- | |
| 650 | ||
| 651 | void mc6846_device::device_config_complete() | |
| 652 | { | |
| 653 | } | |
| 654 | ||
| 655 | //------------------------------------------------- | |
| 656 | // device_start - device-specific startup | |
| 657 | //------------------------------------------------- | |
| 658 | ||
| 659 | void mc6846_device::device_start() | |
| 660 | { | |
| 661 | DEVICE_START_NAME( mc6846 )(this); | |
| 662 | } | |
| 663 | ||
| 664 | //------------------------------------------------- | |
| 665 | // device_reset - device-specific reset | |
| 666 | //------------------------------------------------- | |
| 667 | ||
| 668 | void mc6846_device::device_reset() | |
| 669 | { | |
| 670 | DEVICE_RESET_NAME( mc6846 )(this); | |
| 671 | } |
| Added: svn:mime-type + text/plain Added: svn:eol-style + native |
| r0 | r21685 | |
|---|---|---|
| 1 | #ifndef MM58274C_H | |
| 2 | #define MM58274C_H | |
| 3 | ||
| 4 | /*************************************************************************** | |
| 5 | MACROS | |
| 6 | ***************************************************************************/ | |
| 7 | ||
| 8 | class mm58274c_device : public device_t | |
| 9 | { | |
| 10 | public: | |
| 11 | mm58274c_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); | |
| 12 | ~mm58274c_device() { global_free(m_token); } | |
| 13 | ||
| 14 | // access to legacy token | |
| 15 | void *token() const { assert(m_token != NULL); return m_token; } | |
| 16 | protected: | |
| 17 | // device-level overrides | |
| 18 | virtual void device_config_complete(); | |
| 19 | virtual void device_start(); | |
| 20 | virtual void device_reset(); | |
| 21 | private: | |
| 22 | // internal state | |
| 23 | void *m_token; | |
| 24 | }; | |
| 25 | ||
| 26 | extern const device_type MM58274C; | |
| 27 | ||
| 28 | ||
| 29 | /*************************************************************************** | |
| 30 | FUNCTION PROTOTYPES | |
| 31 | ***************************************************************************/ | |
| 32 | /* interface */ | |
| 33 | /* | |
| 34 | Initializes the clock chip. | |
| 35 | day1 must be set to a value from 0 (sunday), 1 (monday) ... | |
| 36 | to 6 (saturday) and is needed to correctly retrieve the day-of-week | |
| 37 | from the host system clock. | |
| 38 | */ | |
| 39 | struct mm58274c_interface | |
| 40 | { | |
| 41 | int mode24; /* 24/12 mode */ | |
| 42 | int day1; /* first day of week */ | |
| 43 | }; | |
| 44 | ||
| 45 | DECLARE_READ8_DEVICE_HANDLER ( mm58274c_r ); | |
| 46 | DECLARE_WRITE8_DEVICE_HANDLER( mm58274c_w ); | |
| 47 | ||
| 48 | /*************************************************************************** | |
| 49 | DEVICE CONFIGURATION MACROS | |
| 50 | ***************************************************************************/ | |
| 51 | ||
| 52 | #define MCFG_MM58274C_ADD(_tag, _intrf) \ | |
| 53 | MCFG_DEVICE_ADD(_tag, MM58274C, 0) \ | |
| 54 | MCFG_DEVICE_CONFIG(_intrf) | |
| 55 | ||
| 56 | #endif /* MM58274C_H */ |
| Added: svn:eol-style + native Added: svn:mime-type + text/plain |
| r0 | r21685 | |
|---|---|---|
| 1 | /********************************************************************** | |
| 2 | ||
| 3 | Copyright (C) Antoine Mine' 2006 | |
| 4 | ||
| 5 | Motorola 6846 timer emulation. | |
| 6 | ||
| 7 | **********************************************************************/ | |
| 8 | ||
| 9 | #ifndef MC6846_H | |
| 10 | #define MC6846_H | |
| 11 | ||
| 12 | class mc6846_device : public device_t | |
| 13 | { | |
| 14 | public: | |
| 15 | mc6846_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); | |
| 16 | ~mc6846_device() { global_free(m_token); } | |
| 17 | ||
| 18 | // access to legacy token | |
| 19 | void *token() const { assert(m_token != NULL); return m_token; } | |
| 20 | protected: | |
| 21 | // device-level overrides | |
| 22 | virtual void device_config_complete(); | |
| 23 | virtual void device_start(); | |
| 24 | virtual void device_reset(); | |
| 25 | private: | |
| 26 | // internal state | |
| 27 | void *m_token; | |
| 28 | }; | |
| 29 | ||
| 30 | extern const device_type MC6846; | |
| 31 | ||
| 32 | ||
| 33 | /* ---------- configuration ------------ */ | |
| 34 | ||
| 35 | struct mc6846_interface | |
| 36 | { | |
| 37 | /* CPU write to the outside through chip */ | |
| 38 | devcb_write8 out_port_func; /* 8-bit output */ | |
| 39 | devcb_write8 out_cp1_func; /* 1-bit output */ | |
| 40 | devcb_write8 out_cp2_func; /* 1-bit output */ | |
| 41 | ||
| 42 | /* CPU read from the outside through chip */ | |
| 43 | devcb_read8 in_port_func; /* 8-bit input */ | |
| 44 | ||
| 45 | /* asynchronous timer output to outside world */ | |
| 46 | devcb_write8 out_cto_func; /* 1-bit output */ | |
| 47 | ||
| 48 | /* timer interrupt */ | |
| 49 | devcb_write_line irq_func; | |
| 50 | }; | |
| 51 | ||
| 52 | ||
| 53 | #define MCFG_MC6846_ADD(_tag, _intrf) \ | |
| 54 | MCFG_DEVICE_ADD(_tag, MC6846, 0) \ | |
| 55 | MCFG_DEVICE_CONFIG(_intrf) | |
| 56 | ||
| 57 | #define MCFG_MC6846_MODIFY(_tag, _intrf) \ | |
| 58 | MCFG_DEVICE_MODIFY(_tag) \ | |
| 59 | MCFG_DEVICE_CONFIG(_intrf) | |
| 60 | ||
| 61 | #define MCFG_MC6846_REMOVE(_tag) \ | |
| 62 | MCFG_DEVICE_REMOVE(_tag) | |
| 63 | ||
| 64 | ||
| 65 | /* ---------- functions ------------ */ | |
| 66 | /* interface to CPU via address/data bus*/ | |
| 67 | extern DECLARE_READ8_DEVICE_HANDLER ( mc6846_r ); | |
| 68 | extern DECLARE_WRITE8_DEVICE_HANDLER ( mc6846_w ); | |
| 69 | ||
| 70 | /* asynchronous write from outside world into interrupt-generating pins */ | |
| 71 | extern void mc6846_set_input_cp1 ( device_t *device, int data ); | |
| 72 | extern void mc6846_set_input_cp2 ( device_t *device, int data ); | |
| 73 | ||
| 74 | /* polling from outside world */ | |
| 75 | extern UINT8 mc6846_get_output_port ( device_t *device ); | |
| 76 | extern UINT8 mc6846_get_output_cto ( device_t *device ); | |
| 77 | extern UINT8 mc6846_get_output_cp2 ( device_t *device ); | |
| 78 | ||
| 79 | /* partial access to internal state */ | |
| 80 | extern UINT16 mc6846_get_preset ( device_t *device ); /* timer interval - 1 in us */ | |
| 81 | ||
| 82 | #endif |
| Added: svn:mime-type + text/plain Added: svn:eol-style + native |
| r0 | r21685 | |
|---|---|---|
| 1 | /*************************************************************************** | |
| 2 | ||
| 3 | MIOT 6530 emulation | |
| 4 | ||
| 5 | The timer seems to follow these rules: | |
| 6 | - When the timer flag changes from 0 to 1 the timer continues to count | |
| 7 | down at a 1 cycle rate. | |
| 8 | - When the timer is being read or written the timer flag is reset. | |
| 9 | - When the timer flag is set and the timer contents are 0, the counting | |
| 10 | stops. | |
| 11 | ||
| 12 | From the operation of the KIM1 it expects the irqflag to be set whenever | |
| 13 | the unit is reset. This is something that is not clear from the datasheet | |
| 14 | and should be verified against real hardware. | |
| 15 | ||
| 16 | ***************************************************************************/ | |
| 17 | ||
| 18 | #include "emu.h" | |
| 19 | #include "mos6530.h" | |
| 20 | ||
| 21 | ||
| 22 | /*************************************************************************** | |
| 23 | CONSTANTS | |
| 24 | ***************************************************************************/ | |
| 25 | ||
| 26 | enum | |
| 27 | { | |
| 28 | TIMER_IDLE, | |
| 29 | TIMER_COUNTING, | |
| 30 | TIMER_FINISHING | |
| 31 | }; | |
| 32 | ||
| 33 | #define TIMER_FLAG 0x80 | |
| 34 | ||
| 35 | ||
| 36 | ||
| 37 | /*************************************************************************** | |
| 38 | TYPE DEFINITIONS | |
| 39 | ***************************************************************************/ | |
| 40 | ||
| 41 | struct mos6530_port | |
| 42 | { | |
| 43 | devcb_resolved_read8 in_port_func; | |
| 44 | devcb_resolved_write8 out_port_func; | |
| 45 | ||
| 46 | UINT8 in; | |
| 47 | UINT8 out; | |
| 48 | UINT8 ddr; | |
| 49 | }; | |
| 50 | ||
| 51 | ||
| 52 | struct mos6530_state | |
| 53 | { | |
| 54 | devcb_resolved_write_line out_irq_func; | |
| 55 | ||
| 56 | mos6530_port port[2]; | |
| 57 | ||
| 58 | UINT8 irqstate; | |
| 59 | UINT8 irqenable; | |
| 60 | ||
| 61 | UINT8 timershift; | |
| 62 | UINT8 timerstate; | |
| 63 | emu_timer * timer; | |
| 64 | ||
| 65 | UINT32 clock; | |
| 66 | }; | |
| 67 | ||
| 68 | ||
| 69 | ||
| 70 | /*************************************************************************** | |
| 71 | INLINE FUNCTIONS | |
| 72 | ***************************************************************************/ | |
| 73 | ||
| 74 | /*------------------------------------------------- | |
| 75 | get_safe_token - convert a device's token | |
| 76 | into a mos6530_state | |
| 77 | -------------------------------------------------*/ | |
| 78 | ||
| 79 | INLINE mos6530_state *get_safe_token(device_t *device) | |
| 80 | { | |
| 81 | assert(device != NULL); | |
| 82 | assert(device->type() == MOS6530); | |
| 83 | return (mos6530_state *)downcast<mos6530_device *>(device)->token(); | |
| 84 | } | |
| 85 | ||
| 86 | ||
| 87 | /*------------------------------------------------- | |
| 88 | update_irqstate - update the IRQ state | |
| 89 | based on interrupt enables | |
| 90 | -------------------------------------------------*/ | |
| 91 | ||
| 92 | INLINE void update_irqstate(device_t *device) | |
| 93 | { | |
| 94 | mos6530_state *miot = get_safe_token(device); | |
| 95 | UINT8 out = miot->port[1].out; | |
| 96 | ||
| 97 | if ( miot->irqenable ) | |
| 98 | out = ( ( miot->irqstate & TIMER_FLAG ) ? 0x00 : 0x80 ) | ( out & 0x7F ); | |
| 99 | ||
| 100 | if (!miot->port[1].out_port_func.isnull()) | |
| 101 | miot->port[1].out_port_func(0, out); | |
| 102 | else | |
| 103 | logerror("6530MIOT chip %s: Port B is being written to but has no handler.\n", device->tag()); | |
| 104 | } | |
| 105 | ||
| 106 | ||
| 107 | /*------------------------------------------------- | |
| 108 | get_timer - return the current timer value | |
| 109 | -------------------------------------------------*/ | |
| 110 | ||
| 111 | INLINE UINT8 get_timer(mos6530_state *miot) | |
| 112 | { | |
| 113 | /* if idle, return 0 */ | |
| 114 | if (miot->timerstate == TIMER_IDLE) | |
| 115 | return 0; | |
| 116 | ||
| 117 | /* if counting, return the number of ticks remaining */ | |
| 118 | else if (miot->timerstate == TIMER_COUNTING) | |
| 119 | return miot->timer->remaining().as_ticks(miot->clock) >> miot->timershift; | |
| 120 | ||
| 121 | /* if finishing, return the number of ticks without the shift */ | |
| 122 | else | |
| 123 | return miot->timer->remaining().as_ticks(miot->clock); | |
| 124 | } | |
| 125 | ||
| 126 | ||
| 127 | /*************************************************************************** | |
| 128 | INTERNAL FUNCTIONS | |
| 129 | ***************************************************************************/ | |
| 130 | ||
| 131 | /*------------------------------------------------- | |
| 132 | timer_end_callback - callback to process the | |
| 133 | timer | |
| 134 | -------------------------------------------------*/ | |
| 135 | ||
| 136 | static TIMER_CALLBACK( timer_end_callback ) | |
| 137 | { | |
| 138 | device_t *device = (device_t *)ptr; | |
| 139 | mos6530_state *miot = get_safe_token(device); | |
| 140 | ||
| 141 | assert(miot->timerstate != TIMER_IDLE); | |
| 142 | ||
| 143 | /* if we finished counting, switch to the finishing state */ | |
| 144 | if (miot->timerstate == TIMER_COUNTING) | |
| 145 | { | |
| 146 | miot->timerstate = TIMER_FINISHING; | |
| 147 | miot->timer->adjust(attotime::from_ticks(256, miot->clock)); | |
| 148 | ||
| 149 | /* signal timer IRQ as well */ | |
| 150 | miot->irqstate |= TIMER_FLAG; | |
| 151 | update_irqstate(device); | |
| 152 | } | |
| 153 | ||
| 154 | /* if we finished finishing, switch to the idle state */ | |
| 155 | else if (miot->timerstate == TIMER_FINISHING) | |
| 156 | { | |
| 157 | miot->timerstate = TIMER_IDLE; | |
| 158 | miot->timer->adjust(attotime::never); | |
| 159 | } | |
| 160 | } | |
| 161 | ||
| 162 | ||
| 163 | ||
| 164 | /*************************************************************************** | |
| 165 | I/O ACCESS | |
| 166 | ***************************************************************************/ | |
| 167 | ||
| 168 | /*------------------------------------------------- | |
| 169 | mos6530_w - master I/O write access | |
| 170 | -------------------------------------------------*/ | |
| 171 | ||
| 172 | WRITE8_DEVICE_HANDLER( mos6530_w ) | |
| 173 | { | |
| 174 | mos6530_state *miot = get_safe_token(device); | |
| 175 | ||
| 176 | /* if A2 == 1, we are writing to the timer */ | |
| 177 | if (offset & 0x04) | |
| 178 | { | |
| 179 | static const UINT8 timershift[4] = { 0, 3, 6, 10 }; | |
| 180 | attotime curtime = space.machine().time(); | |
| 181 | INT64 target; | |
| 182 | ||
| 183 | /* A0-A1 contain the timer divisor */ | |
| 184 | miot->timershift = timershift[offset & 3]; | |
| 185 | ||
| 186 | /* A3 contains the timer IRQ enable */ | |
| 187 | if (offset & 8) | |
| 188 | miot->irqenable |= TIMER_FLAG; | |
| 189 | else | |
| 190 | miot->irqenable &= ~TIMER_FLAG; | |
| 191 | ||
| 192 | /* writes here clear the timer flag */ | |
| 193 | if (miot->timerstate != TIMER_FINISHING || get_timer(miot) != 0xff) | |
| 194 | miot->irqstate &= ~TIMER_FLAG; | |
| 195 | update_irqstate(device); | |
| 196 | ||
| 197 | /* update the timer */ | |
| 198 | miot->timerstate = TIMER_COUNTING; | |
| 199 | target = curtime.as_ticks(miot->clock) + 1 + (data << miot->timershift); | |
| 200 | miot->timer->adjust(attotime::from_ticks(target, miot->clock) - curtime); | |
| 201 | } | |
| 202 | ||
| 203 | /* if A2 == 0, we are writing to the I/O section */ | |
| 204 | else | |
| 205 | { | |
| 206 | /* A1 selects the port */ | |
| 207 | mos6530_port *port = &miot->port[(offset >> 1) & 1]; | |
| 208 | ||
| 209 | /* if A0 == 1, we are writing to the port's DDR */ | |
| 210 | if (offset & 1) | |
| 211 | port->ddr = data; | |
| 212 | ||
| 213 | /* if A0 == 0, we are writing to the port's output */ | |
| 214 | else | |
| 215 | { | |
| 216 | UINT8 olddata = port->out; | |
| 217 | port->out = data; | |
| 218 | ||
| 219 | if ( ( offset & 2 ) && miot->irqenable ) | |
| 220 | { | |
| 221 | olddata = ( ( miot->irqstate & TIMER_FLAG ) ? 0x00 : 0x80 ) | ( olddata & 0x7F ); | |
| 222 | data = ( ( miot->irqstate & TIMER_FLAG ) ? 0x00 : 0x80 ) | ( data & 0x7F ); | |
| 223 | } | |
| 224 | ||
| 225 | if (!port->out_port_func.isnull()) | |
| 226 | port->out_port_func(0, data); | |
| 227 | else | |
| 228 | logerror("6530MIOT chip %s: Port %c is being written to but has no handler. PC: %08X - %02X\n", device->tag(), 'A' + (offset & 1), space.machine().firstcpu->pc(), data); | |
| 229 | } | |
| 230 | } | |
| 231 | } | |
| 232 | ||
| 233 | ||
| 234 | /*------------------------------------------------- | |
| 235 | mos6530_r - master I/O read access | |
| 236 | -------------------------------------------------*/ | |
| 237 | ||
| 238 | READ8_DEVICE_HANDLER( mos6530_r ) | |
| 239 | { | |
| 240 | mos6530_state *miot = get_safe_token(device); | |
| 241 | UINT8 val = 0; | |
| 242 | ||
| 243 | /* if A2 == 1 and A0 == 1, we are reading interrupt flags */ | |
| 244 | if ((offset & 0x05) == 0x05) | |
| 245 | { | |
| 246 | val = miot->irqstate; | |
| 247 | } | |
| 248 | ||
| 249 | /* if A2 == 1 and A0 == 0, we are reading the timer */ | |
| 250 | else if ((offset & 0x05) == 0x04) | |
| 251 | { | |
| 252 | val = get_timer(miot); | |
| 253 | ||
| 254 | /* A3 contains the timer IRQ enable */ | |
| 255 | if (offset & 8) | |
| 256 | miot->irqenable |= TIMER_FLAG; | |
| 257 | else | |
| 258 | miot->irqenable &= ~TIMER_FLAG; | |
| 259 | ||
| 260 | /* implicitly clears the timer flag */ | |
| 261 | if (miot->timerstate != TIMER_FINISHING || val != 0xff) | |
| 262 | miot->irqstate &= ~TIMER_FLAG; | |
| 263 | update_irqstate(device); | |
| 264 | } | |
| 265 | ||
| 266 | /* if A2 == 0 and A0 == anything, we are reading from ports */ | |
| 267 | else | |
| 268 | { | |
| 269 | /* A1 selects the port */ | |
| 270 | mos6530_port *port = &miot->port[(offset >> 1) & 1]; | |
| 271 | ||
| 272 | /* if A0 == 1, we are reading the port's DDR */ | |
| 273 | if (offset & 1) | |
| 274 | val = port->ddr; | |
| 275 | ||
| 276 | /* if A0 == 0, we are reading the port as an input */ | |
| 277 | else | |
| 278 | { | |
| 279 | UINT8 out = port->out; | |
| 280 | ||
| 281 | if ( ( offset & 2 ) && miot->irqenable ) | |
| 282 | out = ( ( miot->irqstate & TIMER_FLAG ) ? 0x00 : 0x80 ) | ( out & 0x7F ); | |
| 283 | ||
| 284 | /* call the input callback if it exists */ | |
| 285 | if (!port->in_port_func.isnull()) | |
| 286 | { | |
| 287 | port->in = port->in_port_func(0); | |
| 288 | } | |
| 289 | else | |
| 290 | logerror("6530MIOT chip %s: Port %c is being read but has no handler. PC: %08X\n", device->tag(), 'A' + (offset & 1), space.machine().firstcpu->pc()); | |
| 291 | ||
| 292 | /* apply the DDR to the result */ | |
| 293 | val = (out & port->ddr) | (port->in & ~port->ddr); | |
| 294 | } | |
| 295 | } | |
| 296 | return val; | |
| 297 | } | |
| 298 | ||
| 299 | ||
| 300 | /*------------------------------------------------- | |
| 301 | mos6530_porta_in_set - set port A input | |
| 302 | value | |
| 303 | -------------------------------------------------*/ | |
| 304 | ||
| 305 | void mos6530_porta_in_set(device_t *device, UINT8 data, UINT8 mask) | |
| 306 | { | |
| 307 | mos6530_state *miot = get_safe_token(device); | |
| 308 | miot->port[0].in = (miot->port[0].in & ~mask) | (data & mask); | |
| 309 | } | |
| 310 | ||
| 311 | ||
| 312 | /*------------------------------------------------- | |
| 313 | mos6530_portb_in_set - set port B input | |
| 314 | value | |
| 315 | -------------------------------------------------*/ | |
| 316 | ||
| 317 | void mos6530_portb_in_set(device_t *device, UINT8 data, UINT8 mask) | |
| 318 | { | |
| 319 | mos6530_state *miot = get_safe_token(device); | |
| 320 | miot->port[1].in = (miot->port[1].in & ~mask) | (data & mask); | |
| 321 | } | |
| 322 | ||
| 323 | ||
| 324 | /*------------------------------------------------- | |
| 325 | mos6530_porta_in_get - return port A input | |
| 326 | value | |
| 327 | -------------------------------------------------*/ | |
| 328 | ||
| 329 | UINT8 mos6530_porta_in_get(device_t *device) | |
| 330 | { | |
| 331 | mos6530_state *miot = get_safe_token(device); | |
| 332 | return miot->port[0].in; | |
| 333 | } | |
| 334 | ||
| 335 | ||
| 336 | /*------------------------------------------------- | |
| 337 | mos6530_portb_in_get - return port B input | |
| 338 | value | |
| 339 | -------------------------------------------------*/ | |
| 340 | ||
| 341 | UINT8 mos6530_portb_in_get(device_t *device) | |
| 342 | { | |
| 343 | mos6530_state *miot = get_safe_token(device); | |
| 344 | return miot->port[1].in; | |
| 345 | } | |
| 346 | ||
| 347 | ||
| 348 | /*------------------------------------------------- | |
| 349 | mos6530_porta_in_get - return port A output | |
| 350 | value | |
| 351 | -------------------------------------------------*/ | |
| 352 | ||
| 353 | UINT8 mos6530_porta_out_get(device_t *device) | |
| 354 | { | |
| 355 | mos6530_state *miot = get_safe_token(device); | |
| 356 | return miot->port[0].out; | |
| 357 | } | |
| 358 | ||
| 359 | ||
| 360 | /*------------------------------------------------- | |
| 361 | mos6530_portb_in_get - return port B output | |
| 362 | value | |
| 363 | -------------------------------------------------*/ | |
| 364 | ||
| 365 | UINT8 mos6530_portb_out_get(device_t *device) | |
| 366 | { | |
| 367 | mos6530_state *miot = get_safe_token(device); | |
| 368 | return miot->port[1].out; | |
| 369 | } | |
| 370 | ||
| 371 | ||
| 372 | /*************************************************************************** | |
| 373 | DEVICE INTERFACE | |
| 374 | ***************************************************************************/ | |
| 375 | ||
| 376 | static DEVICE_START( mos6530 ) | |
| 377 | { | |
| 378 | mos6530_state *miot = get_safe_token(device); | |
| 379 | const mos6530_interface *intf = (const mos6530_interface*)device->static_config(); | |
| 380 | ||
| 381 | /* validate arguments */ | |
| 382 | assert(device != NULL); | |
| 383 | assert(device->tag() != NULL); | |
| 384 | ||
| 385 | /* set static values */ | |
| 386 | miot->clock = device->clock(); | |
| 387 | ||
| 388 | /* resolve callbacks */ | |
| 389 | miot->port[0].in_port_func.resolve(intf->in_pa_func, *device); | |
| 390 | miot->port[1].in_port_func.resolve(intf->in_pb_func, *device); | |
| 391 | miot->port[0].out_port_func.resolve(intf->out_pa_func, *device); | |
| 392 | miot->port[1].out_port_func.resolve(intf->out_pb_func, *device); | |
| 393 | ||
| 394 | /* allocate timers */ | |
| 395 | miot->timer = device->machine().scheduler().timer_alloc(FUNC(timer_end_callback), (void *)device); | |
| 396 | ||
| 397 | /* register for save states */ | |
| 398 | device->save_item(NAME(miot->port[0].in)); | |
| 399 | device->save_item(NAME(miot->port[0].out)); | |
| 400 | device->save_item(NAME(miot->port[0].ddr)); | |
| 401 | device->save_item(NAME(miot->port[1].in)); | |
| 402 | device->save_item(NAME(miot->port[1].out)); | |
| 403 | device->save_item(NAME(miot->port[1].ddr)); | |
| 404 | ||
| 405 | device->save_item(NAME(miot->irqstate)); | |
| 406 | device->save_item(NAME(miot->irqenable)); | |
| 407 | ||
| 408 | device->save_item(NAME(miot->timershift)); | |
| 409 | device->save_item(NAME(miot->timerstate)); | |
| 410 | } | |
| 411 | ||
| 412 | ||
| 413 | static DEVICE_RESET( mos6530 ) | |
| 414 | { | |
| 415 | mos6530_state *miot = get_safe_token(device); | |
| 416 | ||
| 417 | /* reset I/O states */ | |
| 418 | miot->port[0].out = 0; | |
| 419 | miot->port[0].ddr = 0; | |
| 420 | miot->port[1].out = 0; | |
| 421 | miot->port[1].ddr = 0; | |
| 422 | ||
| 423 | /* reset IRQ states */ | |
| 424 | miot->irqenable = 0; | |
| 425 | miot->irqstate = TIMER_FLAG; | |
| 426 | update_irqstate(device); | |
| 427 | ||
| 428 | /* reset timer states */ | |
| 429 | miot->timershift = 0; | |
| 430 | miot->timerstate = TIMER_IDLE; | |
| 431 | miot->timer->adjust(attotime::never); | |
| 432 | } | |
| 433 | ||
| 434 | ||
| 435 | const device_type MOS6530 = &device_creator<mos6530_device>; | |
| 436 | ||
| 437 | mos6530_device::mos6530_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) | |
| 438 | : device_t(mconfig, MOS6530, "MOS6530", tag, owner, clock) | |
| 439 | { | |
| 440 | m_token = global_alloc_clear(mos6530_state); | |
| 441 | } | |
| 442 | ||
| 443 | //------------------------------------------------- | |
| 444 | // device_config_complete - perform any | |
| 445 | // operations now that the configuration is | |
| 446 | // complete | |
| 447 | //------------------------------------------------- | |
| 448 | ||
| 449 | void mos6530_device::device_config_complete() | |
| 450 | { | |
| 451 | } | |
| 452 | ||
| 453 | //------------------------------------------------- | |
| 454 | // device_start - device-specific startup | |
| 455 | //------------------------------------------------- | |
| 456 | ||
| 457 | void mos6530_device::device_start() | |
| 458 | { | |
| 459 | DEVICE_START_NAME( mos6530 )(this); | |
| 460 | } | |
| 461 | ||
| 462 | //------------------------------------------------- | |
| 463 | // device_reset - device-specific reset | |
| 464 | //------------------------------------------------- | |
| 465 | ||
| 466 | void mos6530_device::device_reset() | |
| 467 | { | |
| 468 | DEVICE_RESET_NAME( mos6530 )(this); | |
| 469 | } |
| Added: svn:eol-style + native Added: svn:mime-type + text/plain |
| r0 | r21685 | |
|---|---|---|
| 1 | /********************************************************************** | |
| 2 | ||
| 3 | MOS Technology 6530 Memory, I/O, Timer Array emulation | |
| 4 | ||
| 5 | Copyright MESS Team. | |
| 6 | Visit http://mamedev.org for licensing and usage restrictions. | |
| 7 | ||
| 8 | ********************************************************************** | |
| 9 | _____ _____ | |
| 10 | Vss 1 |* \_/ | 40 PA1 | |
| 11 | PA0 2 | | 39 PA2 | |
| 12 | phi2 3 | | 38 PA3 | |
| 13 | RS0 4 | | 37 PA4 | |
| 14 | A9 5 | | 36 PA5 | |
| 15 | A8 6 | | 35 PA6 | |
| 16 | A7 7 | | 34 PA7 | |
| 17 | A6 8 | | 33 DB0 | |
| 18 | R/W 9 | | 32 DB1 | |
| 19 | A5 10 | MCS6530 | 31 DB2 | |
| 20 | A4 11 | | 30 DB3 | |
| 21 | A3 12 | | 29 DB4 | |
| 22 | A2 13 | | 28 DB5 | |
| 23 | A1 14 | | 27 DB6 | |
| 24 | A0 15 | | 26 DB7 | |
| 25 | _RES 16 | | 25 PB0 | |
| 26 | IRQ/PB7 17 | | 24 PB1 | |
| 27 | CS1/PB6 18 | | 23 PB2 | |
| 28 | CS2/PB5 19 | | 22 PB3 | |
| 29 | Vcc 20 |_____________| 21 PB4 | |
| 30 | ||
| 31 | **********************************************************************/ | |
| 32 | ||
| 33 | #ifndef __MIOT6530_H__ | |
| 34 | #define __MIOT6530_H__ | |
| 35 | ||
| 36 | /*************************************************************************** | |
| 37 | MACROS / CONSTANTS | |
| 38 | ***************************************************************************/ | |
| 39 | ||
| 40 | class mos6530_device : public device_t | |
| 41 | { | |
| 42 | public: | |
| 43 | mos6530_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); | |
| 44 | ~mos6530_device() { global_free(m_token); } | |
| 45 | ||
| 46 | // access to legacy token | |
| 47 | void *token() const { assert(m_token != NULL); return m_token; } | |
| 48 | protected: | |
| 49 | // device-level overrides | |
| 50 | virtual void device_config_complete(); | |
| 51 | virtual void device_start(); | |
| 52 | virtual void device_reset(); | |
| 53 | private: | |
| 54 | // internal state | |
| 55 | void *m_token; | |
| 56 | }; | |
| 57 | ||
| 58 | extern const device_type MOS6530; | |
| 59 | ||
| 60 | ||
| 61 | #define MCFG_MOS6530_ADD(_tag, _clock, _config) \ | |
| 62 | MCFG_DEVICE_ADD((_tag), MOS6530, _clock) \ | |
| 63 | MCFG_DEVICE_CONFIG(_config) | |
| 64 | ||
| 65 | #define MOS6530_INTERFACE(name) \ | |
| 66 | const mos6530_interface (name) = | |
| 67 | ||
| 68 | /*************************************************************************** | |
| 69 | TYPE DEFINITIONS | |
| 70 | ***************************************************************************/ | |
| 71 | ||
| 72 | struct mos6530_interface | |
| 73 | { | |
| 74 | devcb_read8 in_pa_func; | |
| 75 | devcb_write8 out_pa_func; | |
| 76 | ||
| 77 | devcb_read8 in_pb_func; | |
| 78 | devcb_write8 out_pb_func; | |
| 79 | }; | |
| 80 | ||
| 81 | /*************************************************************************** | |
| 82 | PROTOTYPES | |
| 83 | ***************************************************************************/ | |
| 84 | ||
| 85 | DECLARE_READ8_DEVICE_HANDLER( mos6530_r ); | |
| 86 | DECLARE_WRITE8_DEVICE_HANDLER( mos6530_w ); | |
| 87 | ||
| 88 | void mos6530_porta_in_set(device_t *device, UINT8 data, UINT8 mask); | |
| 89 | void mos6530_portb_in_set(device_t *device, UINT8 data, UINT8 mask); | |
| 90 | ||
| 91 | UINT8 mos6530_porta_in_get(device_t *device); | |
| 92 | UINT8 mos6530_portb_in_get(device_t *device); | |
| 93 | ||
| 94 | UINT8 mos6530_porta_out_get(device_t *device); | |
| 95 | UINT8 mos6530_portb_out_get(device_t *device); | |
| 96 | ||
| 97 | #endif |
| Added: svn:eol-style + native Added: svn:mime-type + text/plain |
| r0 | r21685 | |
|---|---|---|
| 1 | /********************************************************************** | |
| 2 | ||
| 3 | Western Digital WD2010 Winchester Disk Controller | |
| 4 | ||
| 5 | Copyright MESS Team. | |
| 6 | Visit http://mamedev.org for licensing and usage restrictions. | |
| 7 | ||
| 8 | **********************************************************************/ | |
| 9 | ||
| 10 | #include "machine/wd2010.h" | |
| 11 | ||
| 12 | ||
| 13 | ||
| 14 | //************************************************************************** | |
| 15 | // MACROS / CONSTANTS | |
| 16 | //************************************************************************** | |
| 17 | ||
| 18 | #define LOG 1 | |
| 19 | ||
| 20 | ||
| 21 | // task file | |
| 22 | enum | |
| 23 | { | |
| 24 | TASK_FILE_ERROR = 1, | |
| 25 | TASK_FILE_WRITE_PRECOMP_CYLINDER = TASK_FILE_ERROR, | |
| 26 | TASK_FILE_SECTOR_COUNT, | |
| 27 | TASK_FILE_SECTOR_NUMBER, | |
| 28 | TASK_FILE_CYLINDER_LOW, | |
| 29 | TASK_FILE_CYLINDER_HIGH, | |
| 30 | TASK_FILE_SDH_REGISTER, | |
| 31 | TASK_FILE_STATUS, | |
| 32 | TASK_FILE_COMMAND = TASK_FILE_STATUS | |
| 33 | }; | |
| 34 | ||
| 35 | #define WRITE_PRECOMP_CYLINDER \ | |
| 36 | (m_task_file[TASK_FILE_WRITE_PRECOMP_CYLINDER] * 4) | |
| 37 | ||
| 38 | #define SECTOR_COUNT \ | |
| 39 | ((m_task_file[TASK_FILE_SECTOR_COUNT] + 1) * 256) | |
| 40 | ||
| 41 | #define SECTOR_NUMBER \ | |
| 42 | (m_task_file[TASK_FILE_SECTOR_NUMBER]) | |
| 43 | ||
| 44 | #define CYLINDER \ | |
| 45 | (((m_task_file[TASK_FILE_CYLINDER_HIGH] & 0x07) << 8) | m_task_file[TASK_FILE_CYLINDER_LOW]) | |
| 46 | ||
| 47 | #define HEAD \ | |
| 48 | (m_task_file[TASK_FILE_SDH_REGISTER] & 0x07) | |
| 49 | ||
| 50 | #define DRIVE \ | |
| 51 | ((m_task_file[TASK_FILE_SDH_REGISTER] >> 3) & 0x03) | |
| 52 | ||
| 53 | static const int SECTOR_SIZES[4] = { 256, 512, 1024, 128 }; | |
| 54 | ||
| 55 | #define SECTOR_SIZE \ | |
| 56 | SECTOR_SIZES[(m_task_file[TASK_FILE_SDH_REGISTER] >> 5) & 0x03] | |
| 57 | ||
| 58 | ||
| 59 | // status register | |
| 60 | #define STATUS_BSY 0x80 | |
| 61 | #define STATUS_RDY 0x40 | |
| 62 | #define STATUS_WF 0x20 | |
| 63 | #define STATUS_SC 0x10 | |
| 64 | #define STATUS_DRQ 0x08 | |
| 65 | #define STATUS_DWC 0x04 | |
| 66 | #define STATUS_CIP 0x02 | |
| 67 | #define STATUS_ERR 0x01 | |
| 68 | ||
| 69 | ||
| 70 | // error register | |
| 71 | #define ERROR_BB 0x80 | |
| 72 | #define ERROR_CRC_ECC 0x40 | |
| 73 | #define ERROR_ID 0x10 | |
| 74 | #define ERROR_AC 0x04 | |
| 75 | #define ERROR_TK 0x02 | |
| 76 | #define ERROR_DM 0x01 | |
| 77 | ||
| 78 | ||
| 79 | // command register | |
| 80 | #define COMMAND_MASK 0xf0 | |
| 81 | #define COMMAND_RESTORE 0x10 | |
| 82 | #define COMMAND_SEEK 0x70 | |
| 83 | #define COMMAND_READ_SECTOR 0x20 | |
| 84 | #define COMMAND_WRITE_SECTOR 0x30 | |
| 85 | #define COMMAND_SCAN_ID 0x40 | |
| 86 | #define COMMAND_WRITE_FORMAT 0x50 | |
| 87 | #define COMMAND_COMPUTE_CORRECTION 0x08 | |
| 88 | #define COMMAND_SET_PARAMETER_MASK 0xfe | |
| 89 | #define COMMAND_SET_PARAMETER 0x00 | |
| 90 | ||
| 91 | ||
| 92 | ||
| 93 | //************************************************************************** | |
| 94 | // DEVICE DEFINITIONS | |
| 95 | //************************************************************************** | |
| 96 | ||
| 97 | const device_type WD2010 = &device_creator<wd2010_device>; | |
| 98 | ||
| 99 | ||
| 100 | //------------------------------------------------- | |
| 101 | // device_config_complete - perform any | |
| 102 | // operations now that the configuration is | |
| 103 | // complete | |
| 104 | //------------------------------------------------- | |
| 105 | ||
| 106 | void wd2010_device::device_config_complete() | |
| 107 | { | |
| 108 | // inherit a copy of the static data | |
| 109 | const wd2010_interface *intf = reinterpret_cast<const wd2010_interface *>(static_config()); | |
| 110 | if (intf != NULL) | |
| 111 | *static_cast<wd2010_interface *>(this) = *intf; | |
| 112 | ||
| 113 | // or initialize to defaults if none provided | |
| 114 | else | |
| 115 | { | |
| 116 | memset(&m_out_intrq_cb, 0, sizeof(m_out_intrq_cb)); | |
| 117 | memset(&m_out_bdrq_cb, 0, sizeof(m_out_bdrq_cb)); | |
| 118 | memset(&m_out_bcr_cb, 0, sizeof(m_out_bcr_cb)); | |
| 119 | memset(&m_in_bcs_cb, 0, sizeof(m_in_bcs_cb)); | |
| 120 | memset(&m_out_bcs_cb, 0, sizeof(m_out_bcs_cb)); | |
| 121 | memset(&m_out_dirin_cb, 0, sizeof(m_out_dirin_cb)); | |
| 122 | memset(&m_out_step_cb, 0, sizeof(m_out_step_cb)); | |
| 123 | memset(&m_out_rwc_cb, 0, sizeof(m_out_rwc_cb)); | |
| 124 | memset(&m_in_drdy_cb, 0, sizeof(m_in_drdy_cb)); | |
| 125 | memset(&m_in_index_cb, 0, sizeof(m_in_index_cb)); | |
| 126 | memset(&m_in_wf_cb, 0, sizeof(m_in_wf_cb)); | |
| 127 | memset(&m_in_tk000_cb, 0, sizeof(m_in_tk000_cb)); | |
| 128 | memset(&m_in_sc_cb, 0, sizeof(m_in_sc_cb)); | |
| 129 | } | |
| 130 | } | |
| 131 | ||
| 132 | ||
| 133 | ||
| 134 | //************************************************************************** | |
| 135 | // LIVE DEVICE | |
| 136 | //************************************************************************** | |
| 137 | ||
| 138 | //------------------------------------------------- | |
| 139 | // wd2010_device - constructor | |
| 140 | //------------------------------------------------- | |
| 141 | ||
| 142 | wd2010_device::wd2010_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) | |
| 143 | : device_t(mconfig, WD2010, "Western Digital WD2010", tag, owner, clock), | |
| 144 | m_status(0), | |
| 145 | m_error(0) | |
| 146 | { | |
| 147 | } | |
| 148 | ||
| 149 | ||
| 150 | //------------------------------------------------- | |
| 151 | // device_start - device-specific startup | |
| 152 | //------------------------------------------------- | |
| 153 | ||
| 154 | void wd2010_device::device_start() | |
| 155 | { | |
| 156 | // resolve callbacks | |
| 157 | m_out_intrq_func.resolve(m_out_intrq_cb, *this); | |
| 158 | m_out_bdrq_func.resolve(m_out_bdrq_cb, *this); | |
| 159 | m_out_bcr_func.resolve(m_out_bcr_cb, *this); | |
| 160 | m_in_bcs_func.resolve(m_in_bcs_cb, *this); | |
| 161 | m_out_bcs_func.resolve(m_out_bcs_cb, *this); | |
| 162 | m_out_dirin_func.resolve(m_out_dirin_cb, *this); | |
| 163 | m_out_step_func.resolve(m_out_step_cb, *this); | |
| 164 | m_out_rwc_func.resolve(m_out_rwc_cb, *this); | |
| 165 | m_in_drdy_func.resolve(m_in_drdy_cb, *this); | |
| 166 | m_in_index_func.resolve(m_in_index_cb, *this); | |
| 167 | m_in_wf_func.resolve(m_in_wf_cb, *this); | |
| 168 | m_in_tk000_func.resolve(m_in_tk000_cb, *this); | |
| 169 | m_in_sc_func.resolve(m_in_sc_cb, *this); | |
| 170 | } | |
| 171 | ||
| 172 | ||
| 173 | //------------------------------------------------- | |
| 174 | // device_reset - device-specific reset | |
| 175 | //------------------------------------------------- | |
| 176 | ||
| 177 | void wd2010_device::device_reset() | |
| 178 | { | |
| 179 | } | |
| 180 | ||
| 181 | ||
| 182 | //------------------------------------------------- | |
| 183 | // read - | |
| 184 | //------------------------------------------------- | |
| 185 | ||
| 186 | READ8_MEMBER( wd2010_device::read ) | |
| 187 | { | |
| 188 | UINT8 data = 0; | |
| 189 | ||
| 190 | switch (offset) | |
| 191 | { | |
| 192 | case TASK_FILE_ERROR: | |
| 193 | data = m_error; | |
| 194 | break; | |
| 195 | ||
| 196 | case TASK_FILE_STATUS: | |
| 197 | m_out_intrq_func(CLEAR_LINE); | |
| 198 | data = m_status | STATUS_RDY | STATUS_SC; | |
| 199 | break; | |
| 200 | ||
| 201 | default: | |
| 202 | data = m_task_file[offset]; | |
| 203 | break; | |
| 204 | } | |
| 205 | ||
| 206 | return data; | |
| 207 | } | |
| 208 | ||
| 209 | ||
| 210 | //------------------------------------------------- | |
| 211 | // write - | |
| 212 | //------------------------------------------------- | |
| 213 | ||
| 214 | WRITE8_MEMBER( wd2010_device::write ) | |
| 215 | { | |
| 216 | m_task_file[offset] = data; | |
| 217 | ||
| 218 | switch (offset) | |
| 219 | { | |
| 220 | case TASK_FILE_WRITE_PRECOMP_CYLINDER: | |
| 221 | if (LOG) logerror("%s WD2010 '%s' Write Precomp Cylinder: %u\n", machine().describe_context(), tag(), WRITE_PRECOMP_CYLINDER); | |
| 222 | break; | |
| 223 | ||
| 224 | case TASK_FILE_SECTOR_COUNT: | |
| 225 | if (LOG) logerror("%s WD2010 '%s' Sector Count: %u\n", machine().describe_context(), tag(), SECTOR_COUNT); | |
| 226 | break; | |
| 227 | ||
| 228 | case TASK_FILE_SECTOR_NUMBER: | |
| 229 | if (LOG) logerror("%s WD2010 '%s' Sector Number: %u\n", machine().describe_context(), tag(), SECTOR_NUMBER); | |
| 230 | break; | |
| 231 | ||
| 232 | case TASK_FILE_CYLINDER_LOW: | |
| 233 | if (LOG) logerror("%s WD2010 '%s' Cylinder Low: %u\n", machine().describe_context(), tag(), CYLINDER); | |
| 234 | break; | |
| 235 | ||
| 236 | case TASK_FILE_CYLINDER_HIGH: | |
| 237 | if (LOG) logerror("%s WD2010 '%s' Cylinder Low: %u\n", machine().describe_context(), tag(), CYLINDER); | |
| 238 | break; | |
| 239 | ||
| 240 | case TASK_FILE_SDH_REGISTER: | |
| 241 | if (LOG) | |
| 242 | { | |
| 243 | logerror("%s WD2010 '%s' Head: %u\n", machine().describe_context(), tag(), HEAD); | |
| 244 | logerror("%s WD2010 '%s' Drive: %u\n", machine().describe_context(), tag(), DRIVE); | |
| 245 | logerror("%s WD2010 '%s' Sector Size: %u\n", machine().describe_context(), tag(), SECTOR_SIZE); | |
| 246 | } | |
| 247 | break; | |
| 248 | ||
| 249 | case TASK_FILE_COMMAND: | |
| 250 | if (data == COMMAND_COMPUTE_CORRECTION) | |
| 251 | { | |
| 252 | if (LOG) logerror("%s WD2010 '%s' COMPUTE CORRECTION\n", machine().describe_context(), tag()); | |
| 253 | compute_correction(data); | |
| 254 | } | |
| 255 | else if ((data & COMMAND_SET_PARAMETER_MASK) == COMMAND_SET_PARAMETER) | |
| 256 | { | |
| 257 | if (LOG) logerror("%s WD2010 '%s' SET PARAMETER\n", machine().describe_context(), tag()); | |
| 258 | set_parameter(data); | |
| 259 | } | |
| 260 | else | |
| 261 | { | |
| 262 | switch (data & COMMAND_MASK) | |
| 263 | { | |
| 264 | case COMMAND_RESTORE: | |
| 265 | if (LOG) logerror("%s WD2010 '%s' RESTORE\n", machine().describe_context(), tag()); | |
| 266 | restore(data); | |
| 267 | break; | |
| 268 | ||
| 269 | case COMMAND_SEEK: | |
| 270 | if (LOG) logerror("%s WD2010 '%s' SEEK\n", machine().describe_context(), tag()); | |
| 271 | seek(data); | |
| 272 | break; | |
| 273 | ||
| 274 | case COMMAND_READ_SECTOR: | |
| 275 | if (LOG) logerror("%s WD2010 '%s' READ SECTOR\n", machine().describe_context(), tag()); | |
| 276 | read_sector(data); | |
| 277 | break; | |
| 278 | ||
| 279 | case COMMAND_WRITE_SECTOR: | |
| 280 | if (LOG) logerror("%s WD2010 '%s' WRITE SECTOR\n", machine().describe_context(), tag()); | |
| 281 | write_sector(data); | |
| 282 | break; | |
| 283 | ||
| 284 | case COMMAND_SCAN_ID: | |
| 285 | if (LOG) logerror("%s WD2010 '%s' SCAN ID\n", machine().describe_context(), tag()); | |
| 286 | scan_id(data); | |
| 287 | break; | |
| 288 | ||
| 289 | case COMMAND_WRITE_FORMAT: | |
| 290 | if (LOG) logerror("%s WD2010 '%s' WRITE FORMAT\n", machine().describe_context(), tag()); | |
| 291 | format(data); | |
| 292 | break; | |
| 293 | } | |
| 294 | } | |
| 295 | break; | |
| 296 | } | |
| 297 | } | |
| 298 | ||
| 299 | ||
| 300 | //------------------------------------------------- | |
| 301 | // compute_correction - | |
| 302 | //------------------------------------------------- | |
| 303 | ||
| 304 | void wd2010_device::compute_correction(UINT8 data) | |
| 305 | { | |
| 306 | } | |
| 307 | ||
| 308 | ||
| 309 | //------------------------------------------------- | |
| 310 | // set_parameter - | |
| 311 | //------------------------------------------------- | |
| 312 | ||
| 313 | void wd2010_device::set_parameter(UINT8 data) | |
| 314 | { | |
| 315 | } | |
| 316 | ||
| 317 | ||
| 318 | //------------------------------------------------- | |
| 319 | // restore - | |
| 320 | //------------------------------------------------- | |
| 321 | ||
| 322 | void wd2010_device::restore(UINT8 data) | |
| 323 | { | |
| 324 | // reset INTRQ, errors, set BUSY, CIP | |
| 325 | m_out_intrq_func(CLEAR_LINE); | |
| 326 | m_error = 0; | |
| 327 | m_status = STATUS_BSY | STATUS_CIP; | |
| 328 | ||
| 329 | // reset RWC, set direction=OUT, store step rate | |
| 330 | m_out_rwc_func(0); | |
| 331 | m_out_dirin_func(0); | |
| 332 | ||
| 333 | int step_pulses = 0; | |
| 334 | ||
| 335 | while (step_pulses < 2048) | |
| 336 | { | |
| 337 | while (!m_in_sc_func()) | |
| 338 | { | |
| 339 | // drive not ready or write fault? | |
| 340 | if (!m_in_drdy_func() || m_in_wf_func()) | |
| 341 | { | |
| 342 | // pulse BCR, set AC, INTRQ, reset BSY, CIP | |
| 343 | m_out_bcr_func(0); | |
| 344 | m_out_bcr_func(1); | |
| 345 | m_error = ERROR_AC; | |
| 346 | m_status = (m_in_drdy_func() << 6) | (m_in_wf_func() << 5) | STATUS_ERR; | |
| 347 | m_out_intrq_func(ASSERT_LINE); | |
| 348 | return; | |
| 349 | } | |
| 350 | } | |
| 351 | ||
| 352 | if (m_in_tk000_func()) | |
| 353 | { | |
| 354 | // pulse BCR, set INTRQ, reset BSY, CIP | |
| 355 | m_out_bcr_func(0); | |
| 356 | m_out_bcr_func(1); | |
| 357 | m_status &= ~(STATUS_BSY | STATUS_CIP); | |
| 358 | m_out_intrq_func(ASSERT_LINE); | |
| 359 | return; | |
| 360 | } | |
| 361 | ||
| 362 | if (step_pulses == 2047) | |
| 363 | { | |
| 364 | // set TK000 error | |
| 365 | m_error = ERROR_TK; | |
| 366 | m_status |= STATUS_ERR; | |
| 367 | ||
| 368 | // pulse BCR, set INTRQ, reset BSY, CIP | |
| 369 | m_out_bcr_func(0); | |
| 370 | m_out_bcr_func(1); | |
| 371 | m_status &= ~(STATUS_BSY | STATUS_CIP); | |
| 372 | m_out_intrq_func(ASSERT_LINE); | |
| 373 | return; | |
| 374 | } | |
| 375 | ||
| 376 | // issue a step pulse | |
| 377 | m_out_step_func(1); | |
| 378 | m_out_step_func(0); | |
| 379 | step_pulses++; | |
| 380 | } | |
| 381 | } | |
| 382 | ||
| 383 | ||
| 384 | //------------------------------------------------- | |
| 385 | // seek - | |
| 386 | //------------------------------------------------- | |
| 387 | ||
| 388 | void wd2010_device::seek(UINT8 data) | |
| 389 | { | |
| 390 | } | |
| 391 | ||
| 392 | ||
| 393 | //------------------------------------------------- | |
| 394 | // read_sector - | |
| 395 | //------------------------------------------------- | |
| 396 | ||
| 397 | void wd2010_device::read_sector(UINT8 data) | |
| 398 | { | |
| 399 | } | |
| 400 | ||
| 401 | ||
| 402 | //------------------------------------------------- | |
| 403 | // write_sector - | |
| 404 | //------------------------------------------------- | |
| 405 | ||
| 406 | void wd2010_device::write_sector(UINT8 data) | |
| 407 | { | |
| 408 | } | |
| 409 | ||
| 410 | ||
| 411 | //------------------------------------------------- | |
| 412 | // scan_id - | |
| 413 | //------------------------------------------------- | |
| 414 | ||
| 415 | void wd2010_device::scan_id(UINT8 data) | |
| 416 | { | |
| 417 | } | |
| 418 | ||
| 419 | ||
| 420 | //------------------------------------------------- | |
| 421 | // format - | |
| 422 | //------------------------------------------------- | |
| 423 | ||
| 424 | void wd2010_device::format(UINT8 data) | |
| 425 | { | |
| 426 | } |
| Added: svn:eol-style + native Added: svn:mime-type + text/plain |
| r0 | r21685 | |
|---|---|---|
| 1 | /********************************************************************** | |
| 2 | ||
| 3 | Western Digital WD2010 Winchester Disk Controller | |
| 4 | ||
| 5 | Copyright MESS Team. | |
| 6 | Visit http://mamedev.org for licensing and usage restrictions. | |
| 7 | ||
| 8 | **********************************************************************/ | |
| 9 | ||
| 10 | #pragma once | |
| 11 | ||
| 12 | #ifndef __WD2010__ | |
| 13 | #define __WD2010__ | |
| 14 | ||
| 15 | ||
| 16 | #include "emu.h" | |
| 17 | ||
| 18 | ||
| 19 | ||
| 20 | //************************************************************************** | |
| 21 | // INTERFACE CONFIGURATION MACROS | |
| 22 | //************************************************************************** | |
| 23 | ||
| 24 | #define MCFG_WD2010_ADD(_tag, _clock, _config) \ | |
| 25 | MCFG_DEVICE_ADD(_tag, WD2010, _clock) \ | |
| 26 | MCFG_DEVICE_CONFIG(_config) | |
| 27 | ||
| 28 | ||
| 29 | #define WD2010_INTERFACE(_name) \ | |
| 30 | const wd2010_interface (_name) = | |
| 31 | ||
| 32 | ||
| 33 | ||
| 34 | //************************************************************************** | |
| 35 | // TYPE DEFINITIONS | |
| 36 | //************************************************************************** | |
| 37 | ||
| 38 | // ======================> wd2010_interface | |
| 39 | ||
| 40 | struct wd2010_interface | |
| 41 | { | |
| 42 | devcb_write_line m_out_intrq_cb; | |
| 43 | devcb_write_line m_out_bdrq_cb; | |
| 44 | devcb_write_line m_out_bcr_cb; | |
| 45 | devcb_read8 m_in_bcs_cb; | |
| 46 | devcb_write8 m_out_bcs_cb; | |
| 47 | devcb_write_line m_out_dirin_cb; | |
| 48 | devcb_write_line m_out_step_cb; | |
| 49 | devcb_write_line m_out_rwc_cb; | |
| 50 | devcb_read_line m_in_drdy_cb; | |
| 51 | devcb_read_line m_in_index_cb; | |
| 52 | devcb_read_line m_in_wf_cb; | |
| 53 | devcb_read_line m_in_tk000_cb; | |
| 54 | devcb_read_line m_in_sc_cb; | |
| 55 | }; | |
| 56 | ||
| 57 | ||
| 58 | // ======================> wd2010_device | |
| 59 | ||
| 60 | class wd2010_device : public device_t, | |
| 61 | public wd2010_interface | |
| 62 | { | |
| 63 | public: | |
| 64 | // construction/destruction | |
| 65 | wd2010_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); | |
| 66 | ||
| 67 | DECLARE_READ8_MEMBER( read ); | |
| 68 | DECLARE_WRITE8_MEMBER( write ); | |
| 69 | ||
| 70 | protected: | |
| 71 | // device-level overrides | |
| 72 | virtual void device_start(); | |
| 73 | virtual void device_reset(); | |
| 74 | virtual void device_config_complete(); | |
| 75 | ||
| 76 | private: | |
| 77 | void compute_correction(UINT8 data); | |
| 78 | void set_parameter(UINT8 data); | |
| 79 | void restore(UINT8 data); | |
| 80 | void seek(UINT8 data); | |
| 81 | void read_sector(UINT8 data); | |
| 82 | void write_sector(UINT8 data); | |
| 83 | void scan_id(UINT8 data); | |
| 84 | void format(UINT8 data); | |
| 85 | ||
| 86 | devcb_resolved_write_line m_out_intrq_func; | |
| 87 | devcb_resolved_write_line m_out_bdrq_func; | |
| 88 | devcb_resolved_write_line m_out_bcr_func; | |
| 89 | devcb_resolved_read8 m_in_bcs_func; | |
| 90 | devcb_resolved_write8 m_out_bcs_func; | |
| 91 | devcb_resolved_write_line m_out_dirin_func; | |
| 92 | devcb_resolved_write_line m_out_step_func; | |
| 93 | devcb_resolved_write_line m_out_rwc_func; | |
| 94 | devcb_resolved_read_line m_in_drdy_func; | |
| 95 | devcb_resolved_read_line m_in_index_func; | |
| 96 | devcb_resolved_read_line m_in_wf_func; | |
| 97 | devcb_resolved_read_line m_in_tk000_func; | |
| 98 | devcb_resolved_read_line m_in_sc_func; | |
| 99 | ||
| 100 | UINT8 m_status; | |
| 101 | UINT8 m_error; | |
| 102 | UINT8 m_task_file[8]; | |
| 103 | }; | |
| 104 | ||
| 105 | ||
| 106 | // device type definition | |
| 107 | extern const device_type WD2010; | |
| 108 | ||
| 109 | #endif |
| Added: svn:eol-style + native Added: svn:mime-type + text/plain |
| r0 | r21685 | |
|---|---|---|
| 1 | /* | |
| 2 | ||
| 3 | Atmel Serial DataFlash | |
| 4 | ||
| 5 | (c) 2001-2007 Tim Schuerewegen | |
| 6 | ||
| 7 | AT45DB041 - 528 KByte | |
| 8 | AT45DB081 - 1056 KByte | |
| 9 | AT45DB161 - 2112 KByte | |
| 10 | ||
| 11 | */ | |
| 12 | ||
| 13 | #include "at45dbxx.h" | |
| 14 | ||
| 15 | #define LOG_LEVEL 1 | |
| 16 | #define _logerror(level,x) do { if (LOG_LEVEL > level) logerror x; } while (0) | |
| 17 | ||
| 18 | #define FLASH_CMD_52 0x52 | |
| 19 | #define FLASH_CMD_57 0x57 | |
| 20 | #define FLASH_CMD_60 0x60 | |
| 21 | #define FLASH_CMD_82 0x82 | |
| 22 | ||
| 23 | #define FLASH_MODE_XX 0 // unknown | |
| 24 | #define FLASH_MODE_SI 1 // input | |
| 25 | #define FLASH_MODE_SO 2 // output | |
| 26 | ||
| 27 | ||
| 28 | //************************************************************************** | |
| 29 | // GLOBAL VARIABLES | |
| 30 | //************************************************************************** | |
| 31 | ||
| 32 | // device type definition | |
| 33 | const device_type AT45DB041 = &device_creator<at45db041_device>; | |
| 34 | const device_type AT45DB081 = &device_creator<at45db081_device>; | |
| 35 | const device_type AT45DB161 = &device_creator<at45db161_device>; | |
| 36 | ||
| 37 | ||
| 38 | //************************************************************************** | |
| 39 | // LIVE DEVICE | |
| 40 | //************************************************************************** | |
| 41 | ||
| 42 | //------------------------------------------------- | |
| 43 | // at45db041_device - constructor | |
| 44 | //------------------------------------------------- | |
| 45 | ||
| 46 | at45db041_device::at45db041_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) | |
| 47 | : device_t(mconfig, AT45DB041, "AT45DB041", tag, owner, clock), | |
| 48 | device_nvram_interface(mconfig, *this) | |
| 49 | { | |
| 50 | } | |
| 51 | ||
| 52 | ||
| 53 | at45db041_device::at45db041_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock) | |
| 54 | : device_t(mconfig, type, name, tag, owner, clock), | |
| 55 | device_nvram_interface(mconfig, *this) | |
| 56 | { | |
| 57 | } | |
| 58 | ||
| 59 | ||
| 60 | at45db081_device::at45db081_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) | |
| 61 | : at45db041_device(mconfig, AT45DB081, "AT45DB081", tag, owner, clock) | |
| 62 | { | |
| 63 | } | |
| 64 | ||
| 65 | ||
| 66 | at45db161_device::at45db161_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) | |
| 67 | : at45db041_device(mconfig, AT45DB161, "AT45DB161", tag, owner, clock) | |
| 68 | { | |
| 69 | } | |
| 70 | ||
| 71 | ||
| 72 | //------------------------------------------------- | |
| 73 | // device_start - device-specific startup | |
| 74 | //------------------------------------------------- | |
| 75 | ||
| 76 | void at45db041_device::device_start() | |
| 77 | { | |
| 78 | m_size = num_pages() * page_size(); | |
| 79 | m_data = auto_alloc_array(machine(), UINT8, m_size); | |
| 80 | m_buffer1 = auto_alloc_array(machine(), UINT8, page_size()); | |
| 81 | m_buffer2 = auto_alloc_array(machine(), UINT8, page_size()); | |
| 82 | ||
| 83 | // data | |
| 84 | save_pointer(NAME(m_data), m_size); | |
| 85 | // pins | |
| 86 | save_item(NAME(m_pin.cs)); | |
| 87 | save_item(NAME(m_pin.sck)); | |
| 88 | save_item(NAME(m_pin.si)); | |
| 89 | save_item(NAME(m_pin.so)); | |
| 90 | save_item(NAME(m_pin.wp)); | |
| 91 | save_item(NAME(m_pin.reset)); | |
| 92 | save_item(NAME(m_pin.busy)); | |
| 93 | } | |
| 94 | ||
| 95 | ||
| 96 | //------------------------------------------------- | |
| 97 | // device_reset - device-specific reset | |
| 98 | //------------------------------------------------- | |
| 99 | ||
| 100 | void at45db041_device::device_reset() | |
| 101 | { | |
| 102 | _logerror( 1, ("at45dbxx_reset\n")); | |
| 103 | // mode | |
| 104 | m_mode = FLASH_MODE_SI; | |
| 105 | // command | |
| 106 | memset(&m_cmd.data[0], 0, sizeof(m_cmd.data)); | |
| 107 | m_cmd.size = 0; | |
| 108 | // input/output | |
| 109 | m_io.data = NULL; | |
| 110 | m_io.size = 0; | |
| 111 | m_io.pos = 0; | |
| 112 | // pins | |
| 113 | m_pin.cs = 0; | |
| 114 | m_pin.sck = 0; | |
| 115 | m_pin.si = 0; | |
| 116 | m_pin.so = 0; | |
| 117 | m_pin.wp = 0; | |
| 118 | m_pin.reset = 0; | |
| 119 | m_pin.busy = 0; | |
| 120 | // output | |
| 121 | m_so_byte = 0; | |
| 122 | m_so_bits = 0; | |
| 123 | // input | |
| 124 | m_si_byte = 0; | |
| 125 | m_si_bits = 0; | |
| 126 | } | |
| 127 | ||
| 128 | ||
| 129 | //------------------------------------------------- | |
| 130 | // nvram_default - called to initialize NVRAM to | |
| 131 | // its default state | |
| 132 | //------------------------------------------------- | |
| 133 | ||
| 134 | void at45db041_device::nvram_default() | |
| 135 | { | |
| 136 | memset(m_data, 0xff, m_size); | |
| 137 | ||
| 138 | if (region() != NULL) | |
| 139 | { | |
| 140 | UINT32 bytes = region()->bytes(); | |
| 141 | if (bytes > m_size) | |
| 142 | bytes = m_size; | |
| 143 | ||
| 144 | memcpy(m_data, region()->base(), bytes); | |
| 145 | } | |
| 146 | } | |
| 147 | ||
| 148 | //------------------------------------------------- | |
| 149 | // nvram_read - called to read NVRAM from the | |
| 150 | // .nv file | |
| 151 | //------------------------------------------------- | |
| 152 | ||
| 153 | void at45db041_device::nvram_read(emu_file &file) | |
| 154 | { | |
| 155 | file.read(m_data, m_size); | |
| 156 | } | |
| 157 | ||
| 158 | //------------------------------------------------- | |
| 159 | // nvram_write - called to write NVRAM to the | |
| 160 | // .nv file | |
| 161 | //------------------------------------------------- | |
| 162 | ||
| 163 | void at45db041_device::nvram_write(emu_file &file) | |
| 164 | { | |
| 165 | file.write(m_data, m_size); | |
| 166 | } | |
| 167 | ||
| 168 | UINT8 at45db041_device::read_byte() | |
| 169 | { | |
| 170 | UINT8 data; | |
| 171 | // check mode | |
| 172 | if ((m_mode != FLASH_MODE_SO) || (!m_io.data)) return 0; | |
| 173 | // read byte | |
| 174 | data = m_io.data[m_io.pos++]; | |
| 175 | _logerror( 2, ("at45dbxx_read_byte (%02X) (%03d/%03d)\n", data, m_io.pos, m_io.size)); | |
| 176 | if (m_io.pos == m_io.size) m_io.pos = 0; | |
| 177 | return data; | |
| 178 | } | |
| 179 | ||
| 180 | void at45db041_device::flash_set_io(UINT8* data, UINT32 size, UINT32 pos) | |
| 181 | { | |
| 182 | m_io.data = data; | |
| 183 | m_io.size = size; | |
| 184 | m_io.pos = pos; | |
| 185 | } | |
| 186 | ||
| 187 | UINT32 at45db041_device::flash_get_page_addr() | |
| 188 | { | |
| 189 | return ((m_cmd.data[1] & 0x0F) << 7) | ((m_cmd.data[2] & 0xFE) >> 1); | |
| 190 | } | |
| 191 | ||
| 192 | UINT32 at45db041_device::flash_get_byte_addr() | |
| 193 | { | |
| 194 | return ((m_cmd.data[2] & 0x01) << 8) | ((m_cmd.data[3] & 0xFF) >> 0); | |
| 195 | } | |
| 196 | ||
| 197 | UINT32 at45db081_device::flash_get_page_addr() | |
| 198 | { | |
| 199 | return ((m_cmd.data[1] & 0x1F) << 7) | ((m_cmd.data[2] & 0xFE) >> 1); | |
| 200 | } | |
| 201 | ||
| 202 | UINT32 at45db161_device::flash_get_page_addr() | |
| 203 | { | |
| 204 | return ((m_cmd.data[1] & 0x3F) << 6) | ((m_cmd.data[2] & 0xFC) >> 2); | |
| 205 | } | |
| 206 | ||
| 207 | UINT32 at45db161_device::flash_get_byte_addr() | |
| 208 | { | |
| 209 | return ((m_cmd.data[2] & 0x03) << 8) | ((m_cmd.data[3] & 0xFF) >> 0); | |
| 210 | } | |
| 211 | ||
| 212 | void at45db041_device::write_byte(UINT8 data) | |
| 213 | { | |
| 214 | // check mode | |
| 215 | if (m_mode != FLASH_MODE_SI) return; | |
| 216 | // process byte | |
| 217 | if (m_cmd.size < 8) | |
| 218 | { | |
| 219 | UINT8 opcode; | |
| 220 | _logerror( 2, ("at45dbxx_write_byte (%02X)\n", data)); | |
| 221 | // add to command buffer | |
| 222 | m_cmd.data[m_cmd.size++] = data; | |
| 223 | // check opcode | |
| 224 | opcode = m_cmd.data[0]; | |
| 225 | switch (opcode) | |
| 226 | { | |
| 227 | // status register read | |
| 228 | case FLASH_CMD_57 : | |
| 229 | { | |
| 230 | // 8 bits command | |
| 231 | if (m_cmd.size == 1) | |
| 232 | { | |
| 233 | _logerror( 1, ("at45dbxx opcode %02X - status register read\n", opcode)); | |
| 234 | m_status = (m_status & 0xC7) | device_id(); // 80 = busy / 40 = compare fail | |
| 235 | flash_set_io(&m_status, 1, 0); | |
| 236 | m_mode = FLASH_MODE_SO; | |
| 237 | m_cmd.size = 8; | |
| 238 | } | |
| 239 | } | |
| 240 | break; | |
| 241 | // main memory page to buffer 1 compare | |
| 242 | case FLASH_CMD_60 : | |
| 243 | { | |
| 244 | // 8 bits command + 4 bits reserved + 11 bits page address + 9 bits don't care | |
| 245 | if (m_cmd.size == 4) | |
| 246 | { | |
| 247 | UINT32 page; | |
| 248 | UINT8 comp; | |
| 249 | page = flash_get_page_addr(); | |
| 250 | _logerror( 1, ("at45dbxx opcode %02X - main memory page to buffer 1 compare [%04X]\n", opcode, page)); | |
| 251 | comp = memcmp( m_data + page * page_size(), m_buffer1, page_size()) == 0 ? 0 : 1; | |
| 252 | if (comp) m_status |= 0x40; else m_status &= ~0x40; | |
| 253 | _logerror( 1, ("at45dbxx page compare %s\n", comp ? "failure" : "success")); | |
| 254 | m_mode = FLASH_MODE_SI; | |
| 255 | m_cmd.size = 8; | |
| 256 | } | |
| 257 | } | |
| 258 | break; | |
| 259 | // main memory page read | |
| 260 | case FLASH_CMD_52 : | |
| 261 | { | |
| 262 | // 8 bits command + 4 bits reserved + 11 bits page address + 9 bits buffer address + 32 bits don't care | |
| 263 | if (m_cmd.size == 8) | |
| 264 | { | |
| 265 | UINT32 page, byte; | |
| 266 | page = flash_get_page_addr(); | |
| 267 | byte = flash_get_byte_addr(); | |
| 268 | _logerror( 1, ("at45dbxx opcode %02X - main memory page read [%04X/%04X]\n", opcode, page, byte)); | |
| 269 | flash_set_io(m_data + page * page_size(), page_size(), byte); | |
| 270 | m_mode = FLASH_MODE_SO; | |
| 271 | m_cmd.size = 8; | |
| 272 | } | |
| 273 | } | |
| 274 | break; | |
| 275 | // main memory page program through buffer 1 | |
| 276 | case FLASH_CMD_82 : | |
| 277 | { | |
| 278 | // 8 bits command + 4 bits reserved + 11 bits page address + 9 bits buffer address | |
| 279 | if (m_cmd.size == 4) | |
| 280 | { | |
| 281 | UINT32 page, byte; | |
| 282 | page = flash_get_page_addr(); | |
| 283 | byte = flash_get_byte_addr(); | |
| 284 | _logerror( 1, ("at45dbxx opcode %02X - main memory page program through buffer 1 [%04X/%04X]\n",opcode, page, byte)); | |
| 285 | flash_set_io(m_buffer1, page_size(), byte); | |
| 286 | memset( m_buffer1, 0xFF, page_size()); | |
| 287 | m_mode = FLASH_MODE_SI; | |
| 288 | m_cmd.size = 8; | |
| 289 | } | |
| 290 | } | |
| 291 | break; | |
| 292 | // other | |
| 293 | default : | |
| 294 | { | |
| 295 | _logerror( 1, ("at45dbxx opcode %02X - unknown\n", opcode)); | |
| 296 | m_cmd.data[0] = 0; | |
| 297 | m_cmd.size = 0; | |
| 298 | } | |
| 299 | break; | |
| 300 | } | |
| 301 | } | |
| 302 | else | |
| 303 | { | |
| 304 | _logerror( 2, ("at45dbxx_write_byte (%02X) (%03d/%03d)\n", data, m_io.pos + 1, m_io.size)); | |
| 305 | // store byte | |
| 306 | m_io.data[m_io.pos] = data; | |
| 307 | m_io.pos++; | |
| 308 | if (m_io.pos == m_io.size) m_io.pos = 0; | |
| 309 | } | |
| 310 | } | |
| 311 | ||
| 312 | READ_LINE_MEMBER(at45db041_device::so_r) | |
| 313 | { | |
| 314 | if (m_pin.cs == 0) return 0; | |
| 315 | return m_pin.so; | |
| 316 | } | |
| 317 | ||
| 318 | WRITE_LINE_MEMBER(at45db041_device::si_w) | |
| 319 | { | |
| 320 | if (m_pin.cs == 0) return; | |
| 321 | m_pin.si = state; | |
| 322 | } | |
| 323 | ||
| 324 | WRITE_LINE_MEMBER(at45db041_device::cs_w) | |
| 325 | { | |
| 326 | // check if changed | |
| 327 | if (m_pin.cs == state) return; | |
| 328 | // cs low-to-high | |
| 329 | if (state != 0) | |
| 330 | { | |
| 331 | // complete program command | |
| 332 | if ((m_cmd.size >= 4) && (m_cmd.data[0] == FLASH_CMD_82)) | |
| 333 | { | |
| 334 | UINT32 page, byte; | |
| 335 | page = flash_get_page_addr(); | |
| 336 | byte = flash_get_byte_addr(); | |
| 337 | _logerror( 1, ("at45dbxx - program data stored in buffer 1 into selected page in main memory [%04X/%04X]\n", page, byte)); | |
| 338 | memcpy( m_data + page * page_size(), m_buffer1, page_size()); | |
| 339 | } | |
| 340 | // reset | |
| 341 | at45db041_device::device_reset(); | |
| 342 | } | |
| 343 | // save cs | |
| 344 | m_pin.cs = state; | |
| 345 | } | |
| 346 | ||
| 347 | WRITE_LINE_MEMBER(at45db041_device::sck_w) | |
| 348 | { | |
| 349 | // check if changed | |
| 350 | if (m_pin.sck == state) return; | |
| 351 | // sck high-to-low | |
| 352 | if (state == 0) | |
| 353 | { | |
| 354 | // output (part 1) | |
| 355 | if (m_so_bits == 8) | |
| 356 | { | |
| 357 | m_so_bits = 0; | |
| 358 | m_so_byte = read_byte(); | |
| 359 | } | |
| 360 | // input | |
| 361 | if (m_pin.si) m_si_byte = m_si_byte | (1 << m_si_bits); | |
| 362 | m_si_bits++; | |
| 363 | if (m_si_bits == 8) | |
| 364 | { | |
| 365 | m_si_bits = 0; | |
| 366 | write_byte(m_si_byte); | |
| 367 | m_si_byte = 0; | |
| 368 | } | |
| 369 | // output (part 2) | |
| 370 | m_pin.so = (m_so_byte >> m_so_bits) & 1; | |
| 371 | m_so_bits++; | |
| 372 | } | |
| 373 | // save sck | |
| 374 | m_pin.sck = state; | |
| 375 | } |
| Added: svn:mime-type + text/plain Added: svn:eol-style + native |
| r0 | r21685 | |
|---|---|---|
| 1 | /* | |
| 2 | ||
| 3 | Atmel Serial DataFlash | |
| 4 | ||
| 5 | (c) 2001-2007 Tim Schuerewegen | |
| 6 | ||
| 7 | AT45DB041 - 528 KByte | |
| 8 | AT45DB081 - 1056 KByte | |
| 9 | AT45DB161 - 2112 KByte | |
| 10 | ||
| 11 | */ | |
| 12 | ||
| 13 | #ifndef _AT45DBXX_H_ | |
| 14 | #define _AT45DBXX_H_ | |
| 15 | ||
| 16 | #include "emu.h" | |
| 17 | ||
| 18 | ||
| 19 | //************************************************************************** | |
| 20 | // INTERFACE CONFIGURATION MACROS | |
| 21 | //************************************************************************** | |
| 22 | ||
| 23 | #define MCFG_AT45DB041_ADD(_tag) \ | |
| 24 | MCFG_DEVICE_ADD(_tag, AT45DB041, 0) | |
| 25 | ||
| 26 | #define MCFG_AT45DB081_ADD(_tag) \ | |
| 27 | MCFG_DEVICE_ADD(_tag, AT45DB081, 0) | |
| 28 | ||
| 29 | #define MCFG_AT45DB161_ADD(_tag) \ | |
| 30 | MCFG_DEVICE_ADD(_tag, AT45DB161, 0) | |
| 31 | ||
| 32 | ||
| 33 | // ======================> at45db041_device | |
| 34 | ||
| 35 | class at45db041_device : public device_t, | |
| 36 | public device_nvram_interface | |
| 37 | { | |
| 38 | public: | |
| 39 | at45db041_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); | |
| 40 | at45db041_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock); | |
| 41 | ||
| 42 | DECLARE_WRITE_LINE_MEMBER(cs_w); | |
| 43 | DECLARE_WRITE_LINE_MEMBER(sck_w); | |
| 44 | DECLARE_WRITE_LINE_MEMBER(si_w); | |
| 45 | DECLARE_READ_LINE_MEMBER(so_r); | |
| 46 | ||
| 47 | UINT8 *get_ptr() { return m_data; } | |
| 48 | ||
| 49 | protected: | |
| 50 | // device-level overrides | |
| 51 | virtual void device_start(); | |
| 52 | virtual void device_reset(); | |
| 53 | ||
| 54 | // device_nvram_interface overrides | |
| 55 | virtual void nvram_default(); | |
| 56 | virtual void nvram_read(emu_file &file); | |
| 57 | virtual void nvram_write(emu_file &file); | |
| 58 | ||
| 59 | protected: | |
| 60 | virtual int num_pages() const { return 2048; } | |
| 61 | virtual int page_size() const { return 264; } | |
| 62 | virtual UINT8 device_id() const { return 0x18; } | |
| 63 | ||
| 64 | UINT8 read_byte(); | |
| 65 | void flash_set_io(UINT8* data, UINT32 size, UINT32 pos); | |
| 66 | virtual UINT32 flash_get_page_addr(); | |
| 67 | virtual UINT32 flash_get_byte_addr(); | |
| 68 | void write_byte(UINT8 data); | |
| 69 | ||
| 70 | // internal state | |
| 71 | UINT8 * m_data; | |
| 72 | UINT32 m_size; | |
| 73 | UINT8 m_mode; | |
| 74 | UINT8 m_status; | |
| 75 | UINT8 * m_buffer1; | |
| 76 | UINT8 * m_buffer2; | |
| 77 | UINT8 m_si_byte; | |
| 78 | UINT8 m_si_bits; | |
| 79 | UINT8 m_so_byte; | |
| 80 | UINT8 m_so_bits; | |
| 81 | ||
| 82 | struct AT45DBXX_PINS | |
| 83 | { | |
| 84 | int cs; // chip select | |
| 85 | int sck; // serial clock | |
| 86 | int si; // serial input | |
| 87 | int so; // serial output | |
| 88 | int wp; // write protect | |
| 89 | int reset; // reset | |
| 90 | int busy; // busy | |
| 91 | } m_pin; | |
| 92 | ||
| 93 | struct AT45DBXX_IO | |
| 94 | { | |
| 95 | UINT8 *data; | |
| 96 | UINT32 size; | |
| 97 | UINT32 pos; | |
| 98 | } m_io; | |
| 99 | ||
| 100 | struct AT45DBXX_CMD | |
| 101 | { | |
| 102 | UINT8 data[8]; | |
| 103 | UINT8 size; | |
| 104 | } m_cmd; | |
| 105 | }; | |
| 106 | ||
| 107 | // ======================> at45db081_device | |
| 108 | ||
| 109 | class at45db081_device : public at45db041_device | |
| 110 | { | |
| 111 | public: | |
| 112 | at45db081_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); | |
| 113 | ||
| 114 | protected: | |
| 115 | virtual int num_pages() const { return 4096; } | |
| 116 | virtual int page_size() const { return 264; } | |
| 117 | virtual UINT8 device_id() const { return 0x20; } | |
| 118 | ||
| 119 | virtual UINT32 flash_get_page_addr(); | |
| 120 | }; | |
| 121 | ||
| 122 | // ======================> at45db161_device | |
| 123 | ||
| 124 | class at45db161_device : public at45db041_device | |
| 125 | { | |
| 126 | public: | |
| 127 | at45db161_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); | |
| 128 | ||
| 129 | protected: | |
| 130 | virtual int num_pages() const { return 4096; } | |
| 131 | virtual int page_size() const { return 528; } | |
| 132 | virtual UINT8 device_id() const { return 0x28; } | |
| 133 | ||
| 134 | virtual UINT32 flash_get_page_addr(); | |
| 135 | virtual UINT32 flash_get_byte_addr(); | |
| 136 | }; | |
| 137 | ||
| 138 | ||
| 139 | // device type definition | |
| 140 | extern const device_type AT45DB041; | |
| 141 | extern const device_type AT45DB081; | |
| 142 | extern const device_type AT45DB161; | |
| 143 | ||
| 144 | #endif |
| Added: svn:eol-style + native Added: svn:mime-type + text/plain |
| r0 | r21685 | |
|---|---|---|
| 1 | /********************************************************************* | |
| 2 | ||
| 3 | er59256.c | |
| 4 | ||
| 5 | Microchip ER59256 serial eeprom. | |
| 6 | ||
| 7 | ||
| 8 | *********************************************************************/ | |
| 9 | ||
| 10 | #include "emu.h" | |
| 11 | #include "er59256.h" | |
| 12 | ||
| 13 | /* LOGLEVEL 0=no logging, 1=just commands and data, 2=everything ! */ | |
| 14 | ||
| 15 | #define LOGLEVEL 0 | |
| 16 | ||
| 17 | #define LOG(level,...) if(LOGLEVEL>=level) logerror(__VA_ARGS__) | |
| 18 | #define LOG_BITS(bits) logerror("CS=%d CK=%d DI=%d DO=%d", (bits&CS_MASK) ? 1 : 0, (bits&CK_MASK) ? 1 : 0, (bits&DI_MASK) ? 1 : 0, (bits&DO_MASK) ? 1 : 0) | |
| 19 | ||
| 20 | /*************************************************************************** | |
| 21 | TYPE DEFINITIONS | |
| 22 | ***************************************************************************/ | |
| 23 | ||
| 24 | struct er59256_t | |
| 25 | { | |
| 26 | /* The actual memory */ | |
| 27 | UINT16 eerom[EEROM_WORDS]; | |
| 28 | ||
| 29 | /* Bits as they appear on the io pins, current state */ | |
| 30 | UINT8 io_bits; | |
| 31 | ||
| 32 | /* Bits as they appear on the io pins, previous state */ | |
| 33 | UINT8 old_io_bits; | |
| 34 | ||
| 35 | ||
| 36 | /* the 16 bit shift in/out reg */ | |
| 37 | UINT16 in_shifter; | |
| 38 | UINT32 out_shifter; | |
| 39 | ||
| 40 | /* Count of bits received since last CS low->high */ | |
| 41 | UINT8 bitcount; | |
| 42 | ||
| 43 | /* Command & addresss */ | |
| 44 | UINT8 command; | |
| 45 | ||
| 46 | /* Write enable and write in progress flags */ | |
| 47 | UINT8 flags; | |
| 48 | }; | |
| 49 | ||
| 50 | /*************************************************************************** | |
| 51 | FUNCTION PROTOTYPES | |
| 52 | ************************************************************************/ | |
| 53 | ||
| 54 | static void decode_command(er59256_t *er59256); | |
| 55 | ||
| 56 | /*************************************************************************** | |
| 57 | INLINE FUNCTIONS | |
| 58 | ***************************************************************************/ | |
| 59 | ||
| 60 | INLINE er59256_t *get_token(device_t *device) | |
| 61 | { | |
| 62 | assert(device->type() == ER59256); | |
| 63 | return (er59256_t *) downcast<er59256_device *>(device)->token(); | |
| 64 | } | |
| 65 | ||
| 66 | ||
| 67 | /*************************************************************************** | |
| 68 | IMPLEMENTATION | |
| 69 | ***************************************************************************/ | |
| 70 | ||
| 71 | void er59256_preload_rom(device_t *device, const UINT16 *rom_data, int count) | |
| 72 | { | |
| 73 | er59256_t *er59256 = get_token(device); | |
| 74 | int WordNo; | |
| 75 | ||
| 76 | logerror("Preloading %d words of data\n",count); | |
| 77 | ||
| 78 | if(count>EEROM_WORDS) | |
| 79 | memcpy(&er59256->eerom,rom_data,count*2); | |
| 80 | else | |
| 81 | memcpy(&er59256->eerom,rom_data,EEROM_WORDS*2); | |
| 82 | ||
| 83 | for(WordNo=0;WordNo<EEROM_WORDS;WordNo++) | |
| 84 | logerror("%04X ",er59256->eerom[WordNo]); | |
| 85 | ||
| 86 | logerror("\n"); | |
| 87 | } | |
| 88 | ||
| 89 | UINT8 er59256_data_loaded(device_t *device) | |
| 90 | { | |
| 91 | er59256_t *er59256 = get_token(device); | |
| 92 | ||
| 93 | return (er59256->flags & FLAG_DATA_LOADED) ? 1 : 0; | |
| 94 | } | |
| 95 | ||
| 96 | /*------------------------------------------------- | |
| 97 | DEVICE_START( er59256 ) | |
| 98 | -------------------------------------------------*/ | |
| 99 | ||
| 100 | static DEVICE_START( er59256 ) | |
| 101 | { | |
| 102 | er59256_t *er59256 = get_token(device); | |
| 103 | ||
| 104 | memset(er59256, 0x00, sizeof(er59256_t)); | |
| 105 | ||
| 106 | // Start with rom defaulted to erased | |
| 107 | memset(&er59256->eerom, 0xFF, EEROM_WORDS*2); | |
| 108 | ||
| 109 | er59256->command=CMD_INVALID; | |
| 110 | ||
| 111 | er59256->flags&= ~FLAG_DATA_LOADED; | |
| 112 | } | |
| 113 | ||
| 114 | static DEVICE_STOP( er59256 ) | |
| 115 | { | |
| 116 | /* Save contents of eerom */ | |
| 117 | } | |
| 118 | ||
| 119 | void er59256_set_iobits(device_t *device, UINT8 newbits) | |
| 120 | { | |
| 121 | er59256_t *er59256 = get_token(device); | |
| 122 | //UINT32 bit; | |
| 123 | ||
| 124 | // Make sure we only apply valid bits | |
| 125 | newbits&=ALL_MASK; | |
| 126 | ||
| 127 | if(LOGLEVEL>1) | |
| 128 | { | |
| 129 | logerror("er59256:newbits=%02X : ",newbits); | |
| 130 | LOG_BITS(newbits); | |
| 131 | logerror(" io_bits=%02X : ",er59256->io_bits); | |
| 132 | LOG_BITS(er59256->io_bits); | |
| 133 | logerror(" old_io_bits=%02X : ",er59256->old_io_bits); | |
| 134 | LOG_BITS(er59256->old_io_bits); | |
| 135 | logerror(" bitcount=%d, in_shifter=%04X, out_shifter=%05X, flags=%02X\n",er59256->bitcount,er59256->in_shifter,er59256->out_shifter,er59256->flags); | |
| 136 | } | |
| 137 | // Only do anything if the inputs have changed | |
| 138 | if((newbits&IN_MASK)!=(er59256->io_bits&IN_MASK)) | |
| 139 | { | |
| 140 | // save the current state, then set the new one, remembering to preserve data out | |
| 141 | er59256->old_io_bits=er59256->io_bits; | |
| 142 | er59256->io_bits=(newbits & ~DO_MASK) | (er59256->old_io_bits&DO_MASK); | |
| 143 | ||
| 144 | if(CS_RISE(er59256)) | |
| 145 | { | |
| 146 | er59256->flags&=~FLAG_START_BIT; | |
| 147 | er59256->command=CMD_INVALID; | |
| 148 | } | |
| 149 | ||
| 150 | if(LOGLEVEL>1) | |
| 151 | { | |
| 152 | if(CK_RISE(er59256)) logerror("er59256:CK rise\n"); | |
| 153 | if(CS_RISE(er59256)) logerror("er59256:CS rise\n"); | |
| 154 | if(CK_FALL(er59256)) logerror("er59256:CK fall\n"); | |
| 155 | if(CS_FALL(er59256)) logerror("er59256:CS fall\n"); | |
| 156 | } | |
| 157 | ||
| 158 | if(CK_RISE(er59256) && CS_VALID(er59256)) | |
| 159 | { | |
| 160 | if((STARTED(er59256)==0) && (GET_DI(er59256)==1)) | |
| 161 | { | |
| 162 | er59256->bitcount=0; | |
| 163 | er59256->flags|=FLAG_START_BIT; | |
| 164 | } | |
| 165 | else | |
| 166 | { | |
| 167 | SHIFT_IN(er59256); | |
| 168 | er59256->bitcount++; | |
| 169 | ||
| 170 | if(er59256->bitcount==CMD_BITLEN) | |
| 171 | decode_command(er59256); | |
| 172 | ||
| 173 | if((er59256->bitcount==WRITE_BITLEN) && ((er59256->command & CMD_MASK)==CMD_WRITE)) | |
| 174 | { | |
| 175 | er59256->eerom[er59256->command & ADDR_MASK]=er59256->in_shifter; | |
| 176 | LOG(1,"er59256:write[%02X]=%04X\n",(er59256->command & ADDR_MASK),er59256->in_shifter); | |
| 177 | er59256->command=CMD_INVALID; | |
| 178 | } | |
| 179 | LOG(1,"out_shifter=%05X, io_bits=%02X\n",er59256->out_shifter,er59256->io_bits); | |
| 180 | SHIFT_OUT(er59256); | |
| 181 | } | |
| 182 | ||
| 183 | LOG(2,"io_bits:out=%02X\n",er59256->io_bits); | |
| 184 | } | |
| 185 | } | |
| 186 | } | |
| 187 | ||
| 188 | UINT8 er59256_get_iobits(device_t *device) | |
| 189 | { | |
| 190 | er59256_t *er59256 = get_token(device); | |
| 191 | ||
| 192 | return er59256->io_bits; | |
| 193 | } | |
| 194 | ||
| 195 | ||
| 196 | static void decode_command(er59256_t *er59256) | |
| 197 | { | |
| 198 | er59256->out_shifter=0x0000; | |
| 199 | er59256->command=(er59256->in_shifter & (CMD_MASK | ADDR_MASK)); | |
| 200 | ||
| 201 | switch(er59256->command & CMD_MASK) | |
| 202 | { | |
| 203 | case CMD_READ : er59256->out_shifter=er59256->eerom[er59256->command & ADDR_MASK]; | |
| 204 | LOG(1,"er59256:read[%02X]=%04X\n",(er59256->command&ADDR_MASK),er59256->eerom[er59256->command & ADDR_MASK]); | |
| 205 | break; | |
| 206 | case CMD_WRITE : break; | |
| 207 | case CMD_ERASE : if (WRITE_ENABLED(er59256)) er59256->eerom[er59256->command & ADDR_MASK]=0xFF; | |
| 208 | LOG(1,"er59256:erase[%02X]\n",(er59256->command&ADDR_MASK)); | |
| 209 | break; | |
| 210 | case CMD_EWEN : er59256->flags|=FLAG_WRITE_EN; | |
| 211 | LOG(1,"er59256:erase/write enabled\n"); | |
| 212 | break; | |
| 213 | case CMD_EWDS : er59256->flags&=~FLAG_WRITE_EN; | |
| 214 | LOG(1,"er59256:erase/write disabled\n"); | |
| 215 | break; | |
| 216 | case CMD_ERAL : if (WRITE_ENABLED(er59256)) memset(&er59256->eerom, 0xFF, EEROM_WORDS*2); | |
| 217 | LOG(1,"er59256:erase all\n"); | |
| 218 | break; | |
| 219 | } | |
| 220 | ||
| 221 | if ((er59256->command & CMD_MASK)!=CMD_WRITE) | |
| 222 | er59256->command=CMD_INVALID; | |
| 223 | } | |
| 224 | ||
| 225 | const device_type ER59256 = &device_creator<er59256_device>; | |
| 226 | ||
| 227 | er59256_device::er59256_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) | |
| 228 | : device_t(mconfig, ER59256, "Microchip ER59256 serial eeprom.", tag, owner, clock) | |
| 229 | { | |
| 230 | m_token = global_alloc_clear(er59256_t); | |
| 231 | } | |
| 232 | ||
| 233 | //------------------------------------------------- | |
| 234 | // device_config_complete - perform any | |
| 235 | // operations now that the configuration is | |
| 236 | // complete | |
| 237 | //------------------------------------------------- | |
| 238 | ||
| 239 | void er59256_device::device_config_complete() | |
| 240 | { | |
| 241 | } | |
| 242 | ||
| 243 | //------------------------------------------------- | |
| 244 | // device_start - device-specific startup | |
| 245 | //------------------------------------------------- | |
| 246 | ||
| 247 | void er59256_device::device_start() | |
| 248 | { | |
| 249 | DEVICE_START_NAME( er59256 )(this); | |
| 250 | } | |
| 251 | ||
| 252 | //------------------------------------------------- | |
| 253 | // device_stop - device-specific stop | |
| 254 | //------------------------------------------------- | |
| 255 | ||
| 256 | void er59256_device::device_stop() | |
| 257 | { | |
| 258 | DEVICE_STOP_NAME( er59256 )(this); | |
| 259 | } |
| Added: svn:mime-type + text/plain Added: svn:eol-style + native |
| r0 | r21685 | |
|---|---|---|
| 1 | /********************************************************************* | |
| 2 | ||
| 3 | er59256.h | |
| 4 | ||
| 5 | Microchip ER59256 serial eeprom. | |
| 6 | ||
| 7 | ||
| 8 | *********************************************************************/ | |
| 9 | ||
| 10 | #ifndef _ER59256_H_ | |
| 11 | #define _ER59256_H_ | |
| 12 | ||
| 13 | /*************************************************************************** | |
| 14 | MACROS | |
| 15 | ***************************************************************************/ | |
| 16 | ||
| 17 | class er59256_device : public device_t | |
| 18 | { | |
| 19 | public: | |
| 20 | er59256_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); | |
| 21 | ~er59256_device() { global_free(m_token); } | |
| 22 | ||
| 23 | // access to legacy token | |
| 24 | void *token() const { assert(m_token != NULL); return m_token; } | |
| 25 | protected: | |
| 26 | // device-level overrides | |
| 27 | virtual void device_config_complete(); | |
| 28 | virtual void device_start(); | |
| 29 | virtual void device_stop(); | |
| 30 | private: | |
| 31 | // internal state | |
| 32 | void *m_token; | |
| 33 | }; | |
| 34 | ||
| 35 | extern const device_type ER59256; | |
| 36 | ||
| 37 | ||
| 38 | #define MCFG_ER59256_ADD(_tag) \ | |
| 39 | MCFG_DEVICE_ADD((_tag), ER59256, 0) | |
| 40 | ||
| 41 | /*************************************************************************** | |
| 42 | CONSTANTS | |
| 43 | ***************************************************************************/ | |
| 44 | ||
| 45 | #define EEROM_WORDS 0x10 | |
| 46 | ||
| 47 | #define CK_SHIFT 0x00 | |
| 48 | #define DI_SHIFT 0x01 | |
| 49 | #define DO_SHIFT 0x02 | |
| 50 | #define CS_SHIFT 0x03 | |
| 51 | ||
| 52 | #define CK_MASK (1<<CK_SHIFT) | |
| 53 | #define DI_MASK (1<<DI_SHIFT) | |
| 54 | #define DO_MASK (1<<DO_SHIFT) | |
| 55 | #define CS_MASK (1<<CS_SHIFT) | |
| 56 | ||
| 57 | #define ALL_MASK (CK_MASK | DI_MASK | DO_MASK | CS_MASK) | |
| 58 | #define IN_MASK (CK_MASK | DI_MASK | CS_MASK) | |
| 59 | ||
| 60 | #define GET_CK(eep) ((eep->io_bits & CK_MASK) >> CK_SHIFT) | |
| 61 | #define GET_DI(eep) ((eep->io_bits & DI_MASK) >> DI_SHIFT) | |
| 62 | #define GET_DO(eep) ((eep->io_bits & DO_MASK) >> DO_SHIFT) | |
| 63 | #define GET_CS(eep) ((eep->io_bits & CS_MASK) >> CS_SHIFT) | |
| 64 | ||
| 65 | #define SET_CK(eep,data) eep->io_bits=((eep->io_bits & ~CK_MASK) | ((data & 0x01) << CK_SHIFT)) | |
| 66 | #define SET_DI(eep,data) eep->io_bits=((eep->io_bits & ~DI_MASK) | ((data & 0x01) << DI_SHIFT)) | |
| 67 | #define SET_DO(eep,data) eep->io_bits=((eep->io_bits & ~DO_MASK) | ((data & 0x01) << DO_SHIFT)) | |
| 68 | #define SET_CS(eep,data) eep->io_bits=((eep->io_bits & ~CS_MASK) | ((data & 0x01) << CS_SHIFT)) | |
| 69 | ||
| 70 | #define CK_RISE(eep) ((eep->io_bits & CK_MASK) & ~(eep->old_io_bits & CK_MASK)) | |
| 71 | #define CS_RISE(eep) ((eep->io_bits & CS_MASK) & ~(eep->old_io_bits & CS_MASK)) | |
| 72 | #define CS_VALID(eep) ((eep->io_bits & CS_MASK) & (eep->old_io_bits & CS_MASK)) | |
| 73 | ||
| 74 | #define CK_FALL(eep) (~(eep->io_bits & CK_MASK) & (eep->old_io_bits & CK_MASK)) | |
| 75 | #define CS_FALL(eep) (~(eep->io_bits & CS_MASK) & (eep->old_io_bits & CS_MASK)) | |
| 76 | ||
| 77 | ||
| 78 | #define SHIFT_IN(eep) eep->in_shifter=(eep->in_shifter<<1) | GET_DI(eep) | |
| 79 | #define SHIFT_OUT(eep) SET_DO(eep,(eep->out_shifter & 0x10000)>>16); eep->out_shifter=(eep->out_shifter<<1) | |
| 80 | ||
| 81 | #define CMD_READ 0x80 | |
| 82 | #define CMD_WRITE 0x40 | |
| 83 | #define CMD_ERASE 0xC0 | |
| 84 | #define CMD_EWEN 0x30 | |
| 85 | #define CMD_EWDS 0x00 | |
| 86 | #define CMD_ERAL 0x20 | |
| 87 | #define CMD_INVALID 0xF0 | |
| 88 | ||
| 89 | #define CMD_MASK 0xF0 | |
| 90 | #define ADDR_MASK 0x0F | |
| 91 | ||
| 92 | // CMD_BITLEN is 1 start bit plus 4 command bits plus 4 address bits | |
| 93 | #define CMD_BITLEN 8 | |
| 94 | #define DATA_BITLEN 16 | |
| 95 | #define WRITE_BITLEN CMD_BITLEN+DATA_BITLEN | |
| 96 | ||
| 97 | #define FLAG_WRITE_EN 0x01 | |
| 98 | #define FLAG_START_BIT 0x02 | |
| 99 | #define FLAG_DATA_LOADED 0x04 | |
| 100 | ||
| 101 | #define WRITE_ENABLED(eep) ((eep->flags & FLAG_WRITE_EN) ? 1 : 0) | |
| 102 | #define STARTED(eep) ((eep->flags & FLAG_START_BIT) ? 1 : 0) | |
| 103 | ||
| 104 | /*************************************************************************** | |
| 105 | FUNCTION PROTOTYPES | |
| 106 | ***************************************************************************/ | |
| 107 | ||
| 108 | void er59256_set_iobits(device_t *device, UINT8 newbits); | |
| 109 | UINT8 er59256_get_iobits(device_t *device); | |
| 110 | void er59256_preload_rom(device_t *device, const UINT16 *rom_data, int count); | |
| 111 | UINT8 er59256_data_loaded(device_t *device); | |
| 112 | #endif |
| Added: svn:mime-type + text/plain Added: svn:eol-style + native |
| r0 | r21685 | |
|---|---|---|
| 1 | /* | |
| 2 | Atmel at29c040a flash EEPROM | |
| 3 | ||
| 4 | 512k*8 FEEPROM, organized in pages of 256 bytes. | |
| 5 | ||
| 6 | References: | |
| 7 | Datasheets were found on Atmel's site (www.atmel.com) | |
| 8 | ||
| 9 | Raphael Nabet 2003 | |
| 10 | ||
| 11 | September 2010: Rewritten as device | |
| 12 | February 2012: Rewritten as class | |
| 13 | */ | |
| 14 | ||
| 15 | #include "at29040a.h" | |
| 16 | ||
| 17 | #define VERBOSE 2 | |
| 18 | #define LOG logerror | |
| 19 | ||
| 20 | #define FEEPROM_SIZE 0x80000 | |
| 21 | #define SECTOR_SIZE 0x00100 | |
| 22 | #define BOOT_BLOCK_SIZE 0x04000 | |
| 23 | ||
| 24 | #define ADDRESS_MASK 0x7ffff | |
| 25 | #define SECTOR_ADDRESS_MASK 0x7ff00 | |
| 26 | #define BYTE_ADDRESS_MASK 0x000ff | |
| 27 | ||
| 28 | #define PRG_TIMER 1 | |
| 29 | ||
| 30 | #define VERSION 0 | |
| 31 | ||
| 32 | /* | |
| 33 | Constructor. | |
| 34 | */ | |
| 35 | at29040a_device::at29040a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) | |
| 36 | : device_t(mconfig, AT29040A, "ATMEL 29040A 512K*8 FEEPROM", tag, owner, clock), | |
| 37 | device_nvram_interface(mconfig, *this) | |
| 38 | { | |
| 39 | } | |
| 40 | ||
| 41 | //------------------------------------------------- | |
| 42 | // nvram_default - called to initialize NVRAM to | |
| 43 | // its default state | |
| 44 | //------------------------------------------------- | |
| 45 | ||
| 46 | void at29040a_device::nvram_default() | |
| 47 | { | |
| 48 | memset(m_eememory, 0, FEEPROM_SIZE+2); | |
| 49 | } | |
| 50 | ||
| 51 | //------------------------------------------------- | |
| 52 | // nvram_read - called to read NVRAM from the | |
| 53 | // .nv file | |
| 54 | //------------------------------------------------- | |
| 55 | ||
| 56 | void at29040a_device::nvram_read(emu_file &file) | |
| 57 | { | |
| 58 | file.read(m_eememory, FEEPROM_SIZE+2); | |
| 59 | } | |
| 60 | ||
| 61 | //------------------------------------------------- | |
| 62 | // nvram_write - called to write NVRAM to the | |
| 63 | // .nv file | |
| 64 | //------------------------------------------------- | |
| 65 | ||
| 66 | void at29040a_device::nvram_write(emu_file &file) | |
| 67 | { | |
| 68 | m_eememory[0] = VERSION; | |
| 69 | file.write(m_eememory, FEEPROM_SIZE+2); | |
| 70 | } | |
| 71 | ||
| 72 | /* | |
| 73 | programming timer callback | |
| 74 | */ | |
| 75 | void at29040a_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) | |
| 76 | { | |
| 77 | switch (m_pgm) | |
| 78 | { | |
| 79 | case PGM_1: | |
| 80 | /* programming cycle timeout */ | |
| 81 | if (VERBOSE>7) LOG("at29040a: Programming cycle timeout\n"); | |
| 82 | m_pgm = PGM_0; | |
| 83 | break; | |
| 84 | ||
| 85 | case PGM_2: | |
| 86 | /* programming cycle start */ | |
| 87 | if (VERBOSE>7) LOG("at29040a: Sector write start\n"); | |
| 88 | m_pgm = PGM_3; | |
| 89 | /* max delay 10ms, typical delay 5 to 7 ms */ | |
| 90 | m_programming_timer->adjust(attotime::from_msec(5)); | |
| 91 | break; | |
| 92 | ||
| 93 | case PGM_3: | |
| 94 | /* programming cycle end */ | |
| 95 | memcpy(m_eememory + 2 + (m_programming_last_offset & ~0xff), m_programming_buffer, SECTOR_SIZE); | |
| 96 | if (VERBOSE>7) LOG("at29040a: Sector write completed at location %04x + 2\n", (m_programming_last_offset & ~0xff)); | |
| 97 | if (m_enabling_sdb) | |
| 98 | { | |
| 99 | m_sdp = true; | |
| 100 | } | |
| 101 | if (m_disabling_sdb) | |
| 102 | { | |
| 103 | m_sdp = false; | |
| 104 | } | |
| 105 | if (VERBOSE>7) LOG("at29040a: Software data protection = %d\n", m_sdp); | |
| 106 | ||
| 107 | m_pgm = PGM_0; | |
| 108 | m_enabling_sdb = false; | |
| 109 | m_disabling_sdb = false; | |
| 110 | ||
| 111 | break; | |
| 112 | ||
| 113 | default: | |
| 114 | if (VERBOSE>1) LOG("internal error in %s %d\n", __FILE__, __LINE__); | |
| 115 | break; | |
| 116 | } | |
| 117 | } | |
| 118 | ||
| 119 | void at29040a_device::sync_flags() | |
| 120 | { | |
| 121 | if (m_lower_bbl) m_eememory[1] |= 0x04; | |
| 122 | else m_eememory[1] &= ~0x04; | |
| 123 | ||
| 124 | if (m_higher_bbl) m_eememory[1] |= 0x02; | |
| 125 | else m_eememory[1] &= ~0x02; | |
| 126 | ||
| 127 | if (m_sdp) m_eememory[1] |= 0x01; | |
| 128 | else m_eememory[1] &= ~0x01; | |
| 129 | } | |
| 130 | ||
| 131 | /* | |
| 132 | read a byte from FEEPROM | |
| 133 | */ | |
| 134 | READ8_MEMBER( at29040a_device::read ) | |
| 135 | { | |
| 136 | int reply; | |
| 137 | ||
| 138 | offset &= ADDRESS_MASK; | |
| 139 | ||
| 140 | /* reading in the midst of any command sequence cancels it (right???) */ | |
| 141 | m_cmd = CMD_0; | |
| 142 | m_long_sequence = false; | |
| 143 | // m_higher_bbl = true; // who says that? | |
| 144 | ||
| 145 | sync_flags(); | |
| 146 | ||
| 147 | /* reading before the start of a programming cycle cancels it (right???) */ | |
| 148 | if (m_pgm == PGM_1) | |
| 149 | { | |
| 150 | // attempt to access a locked out boot block: cancel programming | |
| 151 | // command if necessary | |
| 152 | m_pgm = PGM_0; | |
| 153 | m_enabling_sdb = false; | |
| 154 | m_disabling_sdb = false; | |
| 155 | m_programming_timer->adjust(attotime::never); | |
| 156 | } | |
| 157 | ||
| 158 | if (m_id_mode) | |
| 159 | { | |
| 160 | switch (offset) | |
| 161 | { | |
| 162 | case 0x00000: | |
| 163 | reply = 0x1f; // Manufacturer code | |
| 164 | break; | |
| 165 | ||
| 166 | case 0x00001: | |
| 167 | reply = 0xa4; // Device code | |
| 168 | break; | |
| 169 | ||
| 170 | case 0x00002: | |
| 171 | reply = m_lower_bbl? 0xff : 0xfe; | |
| 172 | break; | |
| 173 | ||
| 174 | case 0x7fff2: | |
| 175 | reply = m_higher_bbl? 0xff : 0xfe; | |
| 176 | break; | |
| 177 | ||
| 178 | default: | |
| 179 | reply = 0; | |
| 180 | break; | |
| 181 | } | |
| 182 | } | |
| 183 | else if ((m_pgm == PGM_2) || (m_pgm == PGM_3)) | |
| 184 | { | |
| 185 | if (m_pgm == PGM_2) | |
| 186 | { // DATA* polling starts the programming cycle (right???) | |
| 187 | m_pgm = PGM_3; | |
| 188 | /* max delay 10ms, typical delay 5 to 7 ms */ | |
| 189 | m_programming_timer->adjust(attotime::from_msec(5)); | |
| 190 | } | |
| 191 | ||
| 192 | reply = m_toggle_bit? 0x02 : 0x00; | |
| 193 | m_toggle_bit = !m_toggle_bit; | |
| 194 | ||
| 195 | if ((offset == m_programming_last_offset) && (! (m_programming_buffer[m_programming_last_offset & 0xff] & 0x01))) | |
| 196 | reply |= 0x01; | |
| 197 | } | |
| 198 | else | |
| 199 | reply = m_eememory[offset+2]; | |
| 200 | ||
| 201 | if (VERBOSE>7) LOG("at29040a: %05x -> %02x\n", offset, reply); | |
| 202 | ||
| 203 | return reply; | |
| 204 | } | |
| 205 | ||
| 206 | /* | |
| 207 | Write a byte to FEEPROM | |
| 208 | */ | |
| 209 | WRITE8_MEMBER( at29040a_device::write ) | |
| 210 | { | |
| 211 | offset &= ADDRESS_MASK; | |
| 212 | if (VERBOSE>7) LOG("at29040a: %05x <- %02x\n", offset, data); | |
| 213 | ||
| 214 | /* The special CFI commands assume a smaller address space according */ | |
| 215 | /* to the specification ("address format A14-A0") */ | |
| 216 | offs_t cfi_offset = offset & 0x7fff; | |
| 217 | ||
| 218 | if (m_enabling_bbl) | |
| 219 | { | |
| 220 | if (VERBOSE>7) LOG("at29040a: Enabling boot block lockout\n"); | |
| 221 | m_enabling_bbl = false; | |
| 222 | ||
| 223 | if ((offset == 0x00000) && (data == 0x00)) | |
| 224 | { | |
| 225 | if (VERBOSE>7) LOG("at29040a: Enabling lower boot block lockout\n"); | |
| 226 | m_lower_bbl = true; | |
| 227 | sync_flags(); | |
| 228 | return; | |
| 229 | } | |
| 230 | else | |
| 231 | { | |
| 232 | if ((offset == 0x7ffff) && (data == 0xff)) | |
| 233 | { | |
| 234 | if (VERBOSE>7) LOG("at29040a: Enabling higher boot block lockout\n"); | |
| 235 | m_higher_bbl = true; | |
| 236 | sync_flags(); | |
| 237 | return; | |
| 238 | } | |
| 239 | else | |
| 240 | { | |
| 241 | if (VERBOSE>1) LOG("at29040a: Invalid boot block specification: %05x/%02x\n", offset, data); | |
| 242 | } | |
| 243 | } | |
| 244 | } | |
| 245 | ||
| 246 | switch (m_cmd) | |
| 247 | { | |
| 248 | case CMD_0: | |
| 249 | if ((cfi_offset == 0x5555) && (data == 0xaa)) | |
| 250 | { | |
| 251 | if (VERBOSE>7) LOG("at29040a: Command sequence started\n"); | |
| 252 | m_cmd = CMD_1; | |
| 253 | } | |
| 254 | else | |
| 255 | { | |
| 256 | m_cmd = CMD_0; | |
| 257 | m_long_sequence = false; | |
| 258 | } | |
| 259 | break; | |
| 260 | ||
| 261 | case CMD_1: | |
| 262 | if ((cfi_offset == 0x2aaa) && (data == 0x55)) | |
| 263 | { | |
| 264 | m_cmd = CMD_2; | |
| 265 | } | |
| 266 | else | |
| 267 | { | |
| 268 | m_cmd = CMD_0; | |
| 269 | m_long_sequence = false; | |
| 270 | if (VERBOSE>7) LOG("at29040a: Command sequence aborted\n"); | |
| 271 | } | |
| 272 | break; | |
| 273 | ||
| 274 | case CMD_2: | |
| 275 | if (cfi_offset == 0x5555) | |
| 276 | { | |
| 277 | if (!m_long_sequence) | |
| 278 | if (VERBOSE>7) LOG("at29040a: Command sequence completed\n"); | |
| 279 | ||
| 280 | m_pgm = PGM_0; | |
| 281 | m_enabling_sdb = false; | |
| 282 | m_disabling_sdb = false; | |
| 283 | m_programming_timer->adjust(attotime::never); | |
| 284 | ||
| 285 | /* process command */ | |
| 286 | switch (data) | |
| 287 | { | |
| 288 | case 0x10: | |
| 289 | /* Software chip erase */ | |
| 290 | if (m_long_sequence) | |
| 291 | { | |
| 292 | if (m_lower_bbl || m_higher_bbl) | |
| 293 | { | |
| 294 | if (VERBOSE>1) LOG("at29040a: Chip erase sequence deactivated due to previous boot block lockout.\n"); | |
| 295 | } | |
| 296 | else | |
| 297 | { | |
| 298 | if (VERBOSE>7) LOG("at29040a: Erase chip\n"); | |
| 299 | memset(m_eememory+2, 0xff, FEEPROM_SIZE); | |
| 300 | } | |
| 301 | } | |
| 302 | break; | |
| 303 | ||
| 304 | case 0x20: | |
| 305 | /* Software data protection disable */ | |
| 306 | if (VERBOSE>7) LOG("at29040a: Software data protection disable\n"); | |
| 307 | // The complete sequence is aa-55-80-aa-55-20 | |
| 308 | // so we need a 80 before, else the sequence is invalid | |
| 309 | if (m_long_sequence) | |
| 310 | { | |
| 311 | m_pgm = PGM_1; | |
| 312 | m_disabling_sdb = true; | |
| 313 | /* set command timeout (right???) */ | |
| 314 | //m_programming_timer->adjust(attotime::from_usec(150), id, 0.); | |
| 315 | } | |
| 316 | break; | |
| 317 | ||
| 318 | case 0x40: | |
| 319 | /* Boot block lockout enable */ | |
| 320 | // Complete sequence is aa-55-80-aa-55-40 | |
| 321 | if (VERBOSE>7) LOG("at29040a: Boot block lockout enable\n"); | |
| 322 | if (m_long_sequence) m_enabling_bbl = true; | |
| 323 | break; | |
| 324 | ||
| 325 | case 0x80: | |
| 326 | m_long_sequence = true; | |
| 327 | break; | |
| 328 | ||
| 329 | case 0x90: | |
| 330 | /* Software product identification entry */ | |
| 331 | if (VERBOSE>7) LOG("at29040a: Identification mode (start)\n"); | |
| 332 | m_id_mode = true; | |
| 333 | break; | |
| 334 | ||
| 335 | case 0xa0: | |
| 336 | /* Software data protection enable */ | |
| 337 | if (VERBOSE>7) LOG("at29040a: Software data protection enable\n"); | |
| 338 | m_pgm = PGM_1; | |
| 339 | m_enabling_sdb = true; | |
| 340 | /* set command timeout (right???) */ | |
| 341 | //m_programming_timer->adjust(attotime::from_usec(150), id, 0.); | |
| 342 | break; | |
| 343 | ||
| 344 | case 0xf0: | |
| 345 | /* Software product identification exit */ | |
| 346 | if (VERBOSE>7) LOG("at29040a: Identification mode (end)\n"); | |
| 347 | m_id_mode = false; | |
| 348 | break; | |
| 349 | } | |
| 350 | m_cmd = CMD_0; | |
| 351 | if (data != 0x80) m_long_sequence = false; | |
| 352 | ||
| 353 | /* return, because we don't want to write the EEPROM with the command byte */ | |
| 354 | return; | |
| 355 | } | |
| 356 | else | |
| 357 | { | |
| 358 | m_cmd = CMD_0; | |
| 359 | m_long_sequence = false; | |
| 360 | } | |
| 361 | } | |
| 362 | if ((m_pgm == PGM_2) | |
| 363 | && ((offset & ~0xff) != (m_programming_last_offset & ~0xff))) | |
| 364 | { | |
| 365 | /* cancel current programming cycle */ | |
| 366 | if (VERBOSE>7) LOG("at29040a: invalid sector change (from %05x to %05x); cancel programming cycle\n",(offset & ~0xff), (m_programming_last_offset & ~0xff)); | |
| 367 | m_pgm = PGM_0; | |
| 368 | m_enabling_sdb = false; | |
| 369 | m_disabling_sdb = false; | |
| 370 | m_programming_timer->adjust(attotime::never); | |
| 371 | } | |
| 372 | ||
| 373 | if (((m_pgm == PGM_0) && !m_sdp) // write directly | |
| 374 | || (m_pgm == PGM_1)) // write after unlocking | |
| 375 | { | |
| 376 | if (((offset < BOOT_BLOCK_SIZE) && m_lower_bbl) | |
| 377 | || ((offset >= FEEPROM_SIZE-BOOT_BLOCK_SIZE) && m_higher_bbl)) | |
| 378 | { | |
| 379 | // attempt to access a locked out boot block: cancel programming | |
| 380 | // command if necessary | |
| 381 | if (VERBOSE>7) LOG("at29040a: attempt to access a locked out boot block: offset = %05x, lowblock=%d, highblock=%d\n", offset, m_lower_bbl, m_higher_bbl); | |
| 382 | ||
| 383 | m_pgm = PGM_0; | |
| 384 | m_enabling_sdb = false; | |
| 385 | m_disabling_sdb = false; | |
| 386 | } | |
| 387 | else | |
| 388 | { /* enter programming mode */ | |
| 389 | if (VERBOSE>7) LOG("at29040a: enter programming mode (m_pgm=%d)\n", m_pgm); | |
| 390 | memset(m_programming_buffer, 0xff, SECTOR_SIZE); | |
| 391 | m_pgm = PGM_2; | |
| 392 | } | |
| 393 | } | |
| 394 | if (m_pgm == PGM_2) | |
| 395 | { | |
| 396 | /* write data to programming buffer */ | |
| 397 | if (VERBOSE>7) LOG("at29040a: Write data to programming buffer\n"); | |
| 398 | m_programming_buffer[offset & 0xff] = data; | |
| 399 | m_programming_last_offset = offset; | |
| 400 | m_programming_timer->adjust(attotime::from_usec(150)); // next byte must be written before the timer expires | |
| 401 | } | |
| 402 | } | |
| 403 | ||
| 404 | void at29040a_device::device_start(void) | |
| 405 | { | |
| 406 | m_programming_buffer = (UINT8*)malloc(SECTOR_SIZE); | |
| 407 | m_programming_timer = timer_alloc(PRG_TIMER); | |
| 408 | ||
| 409 | m_eememory = (UINT8*)malloc(FEEPROM_SIZE+2); | |
| 410 | } | |
| 411 | ||
| 412 | void at29040a_device::device_stop(void) | |
| 413 | { | |
| 414 | free(m_programming_buffer); | |
| 415 | free(m_eememory); | |
| 416 | } | |
| 417 | ||
| 418 | void at29040a_device::device_reset(void) | |
| 419 | { | |
| 420 | if (m_eememory[0] != VERSION) | |
| 421 | { | |
| 422 | if (VERBOSE>1) LOG("AT29040A: Warning: Version mismatch; expected %d but found %d for %s. Resetting.\n", VERSION, m_eememory[0], tag()); | |
| 423 | m_eememory[0] = 0; | |
| 424 | m_eememory[1] = 0; | |
| 425 | } | |
| 426 | ||
| 427 | m_lower_bbl = ((m_eememory[1] & 0x04)!=0); | |
| 428 | m_higher_bbl = ((m_eememory[1] & 0x02)!=0); | |
| 429 | m_sdp = ((m_eememory[1] & 0x01)!=0); | |
| 430 | ||
| 431 | if (VERBOSE>7) LOG("at29040a (%s): LowerBBL = %d, HigherBBL = %d, SoftDataProt = %d\n", tag(), m_lower_bbl, m_higher_bbl, m_sdp); | |
| 432 | ||
| 433 | m_id_mode = false; | |
| 434 | m_cmd = CMD_0; | |
| 435 | m_enabling_bbl = false; | |
| 436 | m_long_sequence = false; | |
| 437 | m_pgm = PGM_0; | |
| 438 | m_enabling_sdb = false; | |
| 439 | m_disabling_sdb = false; | |
| 440 | m_toggle_bit = false; | |
| 441 | m_programming_last_offset = 0; | |
| 442 | } | |
| 443 | ||
| 444 | const device_type AT29040A = &device_creator<at29040a_device>; |
| Added: svn:mime-type + text/plain Added: svn:eol-style + native |
| r0 | r21685 | |
|---|---|---|
| 1 | /* | |
| 2 | ATMEL 29040a | |
| 3 | ||
| 4 | Michael Zapf | |
| 5 | September 2010: Rewritten as device | |
| 6 | February 2012: Rewritten as class | |
| 7 | */ | |
| 8 | ||
| 9 | #ifndef __AT29040__ | |
| 10 | #define __AT29040__ | |
| 11 | ||
| 12 | #include "emu.h" | |
| 13 | ||
| 14 | extern const device_type AT29040A; | |
| 15 | ||
| 16 | /* | |
| 17 | at29c40a state | |
| 18 | ||
| 19 | Command states (CMD_0 is the initial state): | |
| 20 | CMD_0: default state | |
| 21 | CMD_1: state after writing aa to 5555 | |
| 22 | CMD_2: state after writing 55 to 2aaa | |
| 23 | ||
| 24 | Programming states (s_programming_0 is the initial state): | |
| 25 | PGM_0: default state | |
| 26 | PGM_1: a program and enable/disable lock command has been executed, but programming has not actually started. | |
| 27 | PGM_2: the programming buffer is being written to | |
| 28 | PGM_3: the programming buffer is being burnt to flash ROM | |
| 29 | */ | |
| 30 | enum s_cmd_t | |
| 31 | { | |
| 32 | CMD_0 = 0x0, | |
| 33 | CMD_1 = 0x1, | |
| 34 | CMD_2 = 0x2 | |
| 35 | }; | |
| 36 | ||
| 37 | enum s_pgm_t | |
| 38 | { | |
| 39 | PGM_0 = 0x0, | |
| 40 | PGM_1 = 0x1, | |
| 41 | PGM_2 = 0x2, | |
| 42 | PGM_3 = 0x3 | |
| 43 | }; | |
| 44 | ||
| 45 | class at29040a_device : public device_t, public device_nvram_interface | |
| 46 | { | |
| 47 | public: | |
| 48 | at29040a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); | |
| 49 | DECLARE_READ8_MEMBER( read ); | |
| 50 | DECLARE_WRITE8_MEMBER( write ); | |
| 51 | ||
| 52 | protected: | |
| 53 | virtual void device_start(void); | |
| 54 | virtual void device_reset(void); | |
| 55 | virtual void device_stop(void); | |
| 56 | virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); | |
| 57 | ||
| 58 | void nvram_default(); | |
| 59 | void nvram_read(emu_file &file); | |
| 60 | void nvram_write(emu_file &file); | |
| 61 | ||
| 62 | private: | |
| 63 | void sync_flags(void); | |
| 64 | ||
| 65 | UINT8* m_eememory; | |
| 66 | ||
| 67 | bool m_lower_bbl; /* set when lower boot block lockout is enabled */ | |
| 68 | bool m_higher_bbl; /* set when upper boot block lockout is enabled */ | |
| 69 | bool m_sdp; /* set when in software data protect mode */ | |
| 70 | ||
| 71 | bool m_id_mode; /* set when in chip id mode */ | |
| 72 | s_cmd_t m_cmd; /* command state */ | |
| 73 | bool m_enabling_bbl; /* set when a boot block lockout command is expecting its parameter */ | |
| 74 | bool m_long_sequence; /* set if 0x80 command has just been executed (some command require this prefix) */ | |
| 75 | s_pgm_t m_pgm; /* programming state */ | |
| 76 | bool m_enabling_sdb; /* set when a sdp enable command is in progress */ | |
| 77 | bool m_disabling_sdb; /* set when a sdp disable command is in progress */ | |
| 78 | bool m_dirty; /* set when the memory contents should be set */ | |
| 79 | bool m_toggle_bit; // indicates flashing in progress (toggles for each query) | |
| 80 | UINT8* m_programming_buffer; | |
| 81 | int m_programming_last_offset; | |
| 82 | emu_timer* m_programming_timer; | |
| 83 | }; | |
| 84 | ||
| 85 | #define MCFG_AT29040A_ADD(_tag ) \ | |
| 86 | MCFG_DEVICE_ADD(_tag, AT29040A, 0) | |
| 87 | ||
| 88 | #endif |
| Added: svn:eol-style + native Added: svn:mime-type + text/plain |
| r0 | r21685 | |
|---|---|---|
| 1 | /***************************************************************************** | |
| 2 | * | |
| 3 | * video/dl1416.c | |
| 4 | * | |
| 5 | * DL1416 | |
| 6 | * | |
| 7 | * 4-Digit 16-Segment Alphanumeric Intelligent Display | |
| 8 | * with Memory/Decoder/Driver | |
| 9 | * | |
| 10 | * Notes: | |
| 11 | * - Currently supports the DL1416T and by virtue of it being nearly the same, the DL1414. | |
| 12 | * - Partial support for DL1416B is available, it just needs the right | |
| 13 | * character set and MAME core support for its display. | |
| 14 | * - Cursor support is implemented but not tested, as the AIM65 does not | |
| 15 | * seem to use it. | |
| 16 | * | |
| 17 | * Todo: | |
| 18 | * - Is the DL1416A identical to the DL1416T? If not, we need to add | |
| 19 | * support for it. | |
| 20 | * - Add proper support for DL1414 (pretty much DL1416T without the cursor) | |
| 21 | * | |
| 22 | * Changes: | |
| 23 | * - 2007-07-30: Initial version. [Dirk Best] | |
| 24 | * - 2008-02-25: Converted to the new device interface. [Dirk Best] | |
| 25 | * - 2008-12-18: Cleanups. [Dirk Best] | |
| 26 | * - 2011-10-08: Changed the ram to store character rather than segment data. [Lord Nightmare] | |
| 27 | * | |
| 28 | * | |
| 29 | * We use the following order for the segments: | |
| 30 | * | |
| 31 | * 000 111 | |
| 32 | * 7D A E2 | |
| 33 | * 7 D A E 2 | |
| 34 | * 7 DAE 2 | |
| 35 | * 888 999 | |
| 36 | * 6 CBF 3 | |
| 37 | * 6 C B F 3 | |
| 38 | * 6C B F3 | |
| 39 | * 555 444 | |
| 40 | * | |
| 41 | ****************************************************************************/ | |
| 42 | ||
| 43 | #include "emu.h" | |
| 44 | #include "dl1416.h" | |
| 45 | ||
| 46 | ||
| 47 | /*************************************************************************** | |
| 48 | CONSTANTS | |
| 49 | ***************************************************************************/ | |
| 50 | ||
| 51 | #define SEG_UNDEF (-2) | |
| 52 | #define SEG_BLANK (0) | |
| 53 | #define SEG_CURSOR (0xffff) | |
| 54 | #define CURSOR_ON (1) | |
| 55 | #define CURSOR_OFF (0) | |
| 56 | ||
| 57 | /* character set DL1416T */ | |
| 58 | static const int dl1416t_segments[128] = { | |
| 59 | SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, /* undefined */ | |
| 60 | SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, /* undefined */ | |
| 61 | SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, /* undefined */ | |
| 62 | SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, /* undefined */ | |
| 63 | SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, /* undefined */ | |
| 64 | SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, /* undefined */ | |
| 65 | SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, /* undefined */ | |
| 66 | SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, /* undefined */ | |
| 67 | 0x0000, 0x2421, 0x0480, 0x0f3c, /* ! " # */ | |
| 68 | 0x0fbb, 0x5f99, 0xa579, 0x4000, /* $ % & ' */ | |
| 69 | 0xc000, 0x3000, 0xff00, 0x0f00, /* ( ) * + */ | |
| 70 | 0x1000, 0x0300, 0x0020, 0x5000, /* , - . / */ | |
| 71 | 0x0ce1, 0x0c00, 0x0561, 0x0d21, /* 0 1 2 3 */ | |
| 72 | 0x0d80, 0x09a1, 0x09e1, 0x0c01, /* 4 5 6 7 */ | |
| 73 | 0x0de1, 0x0da1, 0x0021, 0x1001, /* 8 9 : ; */ | |
| 74 | 0x5030, 0x0330, 0xa030, 0x0a07, /* < = > ? */ | |
| 75 | 0x097f, 0x03cf, 0x0e3f, 0x00f3, /* @ A B C */ | |
| 76 | 0x0c3f, 0x01f3, 0x01c3, 0x02fb, /* D E F G */ | |
| 77 | 0x03cc, 0x0c33, 0x0c63, 0xc1c0, /* H I J K */ | |
| 78 | 0x00f0, 0x60cc, 0xa0cc, 0x00ff, /* L M N O */ | |
| 79 | 0x03c7, 0x80ff, 0x83c7, 0x03bb, /* P Q R S */ | |
| 80 | 0x0c03, 0x00fc, 0x50c0, 0x90cc, /* T U V W */ | |
| 81 | 0xf000, 0x6800, 0x5033, 0x00e1, /* X Y Z [ */ | |
| 82 | 0xa000, 0x001e, 0x9000, 0x0030, /* \ ] ^ _ */ | |
| 83 | SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, /* undefined */ | |
| 84 | SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, /* undefined */ | |
| 85 | SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, /* undefined */ | |
| 86 | SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, /* undefined */ | |
| 87 | SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, /* undefined */ | |
| 88 | SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, /* undefined */ | |
| 89 | SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, /* undefined */ | |
| 90 | SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF /* undefined */ | |
| 91 | }; | |
| 92 | ||
| 93 | ||
| 94 | /*************************************************************************** | |
| 95 | TYPE DEFINITIONS | |
| 96 | ***************************************************************************/ | |
| 97 | ||
| 98 | struct dl1416_state | |
| 99 | { | |
| 100 | int write_enable; | |
| 101 | int chip_enable; | |
| 102 | int cursor_enable; | |
| 103 | ||
| 104 | UINT16 digit_ram[4]; // holds the digit code for each position | |
| 105 | UINT8 cursor_state[4]; // holds the cursor state for each position, 0=off, 1=on | |
| 106 | }; | |
| 107 | ||
| 108 | ||
| 109 | /***************************************************************************** | |
| 110 | INLINE FUNCTIONS | |
| 111 | *****************************************************************************/ | |
| 112 | ||
| 113 | INLINE dl1416_state *get_safe_token(device_t *device) | |
| 114 | { | |
| 115 | assert(device != NULL); | |
| 116 | assert(device->type() == DL1416B || device->type() == DL1416T); | |
| 117 | ||
| 118 | return (dl1416_state *)downcast<dl1416_device *>(device)->token(); | |
| 119 | } | |
| 120 | ||
| 121 | ||
| 122 | /***************************************************************************** | |
| 123 | DEVICE INTERFACE | |
| 124 | *****************************************************************************/ | |
| 125 | ||
| 126 | static DEVICE_START( dl1416 ) | |
| 127 | { | |
| 128 | dl1416_state *dl1416 = get_safe_token(device); | |
| 129 | ||
| 130 | /* register for state saving */ | |
| 131 | state_save_register_item(device->machine(), "dl1416", device->tag(), 0, dl1416->chip_enable); | |
| 132 | state_save_register_item(device->machine(), "dl1416", device->tag(), 0, dl1416->cursor_enable); | |
| 133 | state_save_register_item(device->machine(), "dl1416", device->tag(), 0, dl1416->write_enable); | |
| 134 | state_save_register_item_array(device->machine(), "dl1416", device->tag(), 0, dl1416->digit_ram); | |
| 135 | } | |
| 136 | ||
| 137 | ||
| 138 | static DEVICE_RESET( dl1416 ) | |
| 139 | { | |
| 140 | int i, pattern; | |
| 141 | dl1416_state *chip = get_safe_token(device); | |
| 142 | const dl1416_interface *intf = (const dl1416_interface *)device->static_config(); | |
| 143 | /* disable all lines */ | |
| 144 | chip->chip_enable = FALSE; | |
| 145 | chip->write_enable = FALSE; | |
| 146 | chip->cursor_enable = FALSE; | |
| 147 | ||
| 148 | /* randomize digit and cursor memory */ | |
| 149 | for (i = 0; i < 4; i++) | |
| 150 | { | |
| 151 | chip->digit_ram[i] = device->machine().rand()&0x3F; | |
| 152 | // TODO: only enable the following line if the device actually has a cursor (DL1416T and DL1416B), if DL1414 then cursor is always 0! | |
| 153 | //chip->cursor_state[i] = ((device->machine().rand()&0xFF) >= 0x80) ? CURSOR_ON : CURSOR_OFF; | |
| 154 | chip->cursor_state[i] = CURSOR_OFF; | |
| 155 | pattern = dl1416t_segments[chip->digit_ram[i]]; | |
| 156 | ||
| 157 | /* If cursor for this digit position is enabled and segment is not */ | |
| 158 | /* undefined, replace digit with cursor */ | |
| 159 | if ((chip->cursor_state[i] == CURSOR_ON) && (pattern != SEG_UNDEF)) | |
| 160 | pattern = SEG_CURSOR; | |
| 161 | ||
| 162 | /* Undefined characters are replaced by blanks */ | |
| 163 | if (pattern == SEG_UNDEF) | |
| 164 | pattern = SEG_BLANK; | |
| 165 | ||
| 166 | /* Call update function */ | |
| 167 | if (intf->update) | |
| 168 | intf->update(device, i, pattern); | |
| 169 | } | |
| 170 | } | |
| 171 | ||
| 172 | ||
| 173 | /***************************************************************************** | |
| 174 | IMPLEMENTATION | |
| 175 | *****************************************************************************/ | |
| 176 | ||
| 177 | /* write enable, active low */ | |
| 178 | WRITE_LINE_DEVICE_HANDLER( dl1416_wr_w ) | |
| 179 | { | |
| 180 | dl1416_state *chip = get_safe_token(device); | |
| 181 | chip->write_enable = !state; | |
| 182 | } | |
| 183 | ||
| 184 | /* chip enable, active low */ | |
| 185 | WRITE_LINE_DEVICE_HANDLER( dl1416_ce_w ) | |
| 186 | { | |
| 187 | dl1416_state *chip = get_safe_token(device); | |
| 188 | chip->chip_enable = !state; | |
| 189 | } | |
| 190 | ||
| 191 | /* cursor enable, active low */ | |
| 192 | WRITE_LINE_DEVICE_HANDLER( dl1416_cu_w ) | |
| 193 | { | |
| 194 | dl1416_state *chip = get_safe_token(device); | |
| 195 | chip->cursor_enable = !state; | |
| 196 | } | |
| 197 | ||
| 198 | /* data */ | |
| 199 | WRITE8_DEVICE_HANDLER( dl1416_data_w ) | |
| 200 | { | |
| 201 | dl1416_state *chip = get_safe_token(device); | |
| 202 | const dl1416_interface *intf = (const dl1416_interface *)device->static_config(); | |
| 203 | ||
| 204 | offset &= 0x03; /* A0-A1 */ | |
| 205 | data &= 0x7f; /* D0-D6 */ | |
| 206 | ||
| 207 | /* Only try to update the data if we are enabled and write is enabled */ | |
| 208 | if (chip->chip_enable && chip->write_enable) | |
| 209 | { | |
| 210 | /* fprintf(stderr,"DL1416 Write: Cursor: %d, Offset: %d, Data: %02X\n (%c)", chip->cursor_enable, offset, data, data); */ | |
| 211 | int i, pattern, previous_state; | |
| 212 | ||
| 213 | if (chip->cursor_enable) /* cursor enable is set */ | |
| 214 | { | |
| 215 | if (device->type() == DL1416B) | |
| 216 | { | |
| 217 | /* DL1416B uses offset to decide cursor pos to change and D0 to hold new state */ | |
| 218 | ||
| 219 | /* The cursor will be set if D0 is high and the original */ | |
| 220 | /* character restored otherwise */ | |
| 221 | previous_state = chip->cursor_state[offset]; | |
| 222 | chip->cursor_state[offset] = data & 1 ? CURSOR_ON : CURSOR_OFF; | |
| 223 | ||
| 224 | if (previous_state != chip->cursor_state[offset]) | |
| 225 | { | |
| 226 | pattern = dl1416t_segments[chip->digit_ram[offset]]; | |
| 227 | ||
| 228 | /* If cursor for this digit position is enabled and segment is not */ | |
| 229 | /* undefined, replace digit with cursor */ | |
| 230 | if ((chip->cursor_state[offset] == CURSOR_ON) && (pattern != SEG_UNDEF)) | |
| 231 | pattern = SEG_CURSOR; | |
| 232 | ||
| 233 | /* Undefined characters are replaced by blanks */ | |
| 234 | if (pattern == SEG_UNDEF) | |
| 235 | pattern = SEG_BLANK; | |
| 236 | ||
| 237 | /* Call update function */ | |
| 238 | if (intf->update) | |
| 239 | intf->update(device, offset, pattern); | |
| 240 | } | |
| 241 | } | |
| 242 | else { | |
| 243 | /* DL1416T uses a bitmap of 4 data bits D0,D1,D2,D3 to decide cursor pos to change and new state */ | |
| 244 | ||
| 245 | for (i = 0; i < 4; i++) | |
| 246 | { | |
| 247 | /* The cursor will be set if D0-D3 is high and the original */ | |
| 248 | /* character at the appropriate position restored otherwise */ | |
| 249 | previous_state = chip->cursor_state[i]; | |
| 250 | chip->cursor_state[i] = data & (1<<i) ? CURSOR_ON : CURSOR_OFF; | |
| 251 | ||
| 252 | if (previous_state != chip->cursor_state[i]) | |
| 253 | { | |
| 254 | pattern = dl1416t_segments[chip->digit_ram[i]]; | |
| 255 | ||
| 256 | /* If cursor for this digit position is enabled and segment is not */ | |
| 257 | /* undefined, replace digit with cursor */ | |
| 258 | if ((chip->cursor_state[i] == CURSOR_ON) && (pattern != SEG_UNDEF)) | |
| 259 | pattern = SEG_CURSOR; | |
| 260 | ||
| 261 | /* Undefined characters are replaced by blanks */ | |
| 262 | if (pattern == SEG_UNDEF) | |
| 263 | pattern = SEG_BLANK; | |
| 264 | ||
| 265 | /* Call update function */ | |
| 266 | if (intf->update) | |
| 267 | intf->update(device, i, pattern); | |
| 268 | } | |
| 269 | } | |
| 270 | } | |
| 271 | } | |
| 272 | else /* cursor enable is not set, so standard write */ | |
| 273 | { | |
| 274 | /* Save written value */ | |
| 275 | chip->digit_ram[offset] = data&0x3f; | |
| 276 | ||
| 277 | /* Load segment pattern from ROM */ | |
| 278 | pattern = dl1416t_segments[data]; /** TODO: handle DL1416T vs DL1416B vs DL1414 here */ | |
| 279 | ||
| 280 | /* If cursor for this digit position is enabled and segment is not */ | |
| 281 | /* undefined, replace digit with cursor */ | |
| 282 | if ((chip->cursor_state[offset] == CURSOR_ON) && (pattern != SEG_UNDEF)) | |
| 283 | pattern = SEG_CURSOR; | |
| 284 | ||
| 285 | /* Undefined characters are replaced by blanks */ | |
| 286 | if (pattern == SEG_UNDEF) | |
| 287 | pattern = SEG_BLANK; | |
| 288 | ||
| 289 | /* Call update function */ | |
| 290 | if (intf->update) | |
| 291 | intf->update(device, offset, pattern); | |
| 292 | } | |
| 293 | } | |
| 294 | } | |
| 295 | ||
| 296 | dl1416_device::dl1416_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock) | |
| 297 | : device_t(mconfig, type, name, tag, owner, clock) | |
| 298 | { | |
| 299 | m_token = global_alloc_clear(dl1416_state); | |
| 300 | } | |
| 301 | ||
| 302 | //------------------------------------------------- | |
| 303 | // device_config_complete - perform any | |
| 304 | // operations now that the configuration is | |
| 305 | // complete | |
| 306 | //------------------------------------------------- | |
| 307 | ||
| 308 | void dl1416_device::device_config_complete() | |
| 309 | { | |
| 310 | } | |
| 311 | ||
| 312 | //------------------------------------------------- | |
| 313 | // device_start - device-specific startup | |
| 314 | //------------------------------------------------- | |
| 315 | ||
| 316 | void dl1416_device::device_start() | |
| 317 | { | |
| 318 | DEVICE_START_NAME( dl1416 )(this); | |
| 319 | } | |
| 320 | ||
| 321 | //------------------------------------------------- | |
| 322 | // device_reset - device-specific reset | |
| 323 | //------------------------------------------------- | |
| 324 | ||
| 325 | void dl1416_device::device_reset() | |
| 326 | { | |
| 327 | DEVICE_RESET_NAME( dl1416 )(this); | |
| 328 | } | |
| 329 | ||
| 330 | ||
| 331 | const device_type DL1416B = &device_creator<dl1416b_device>; | |
| 332 | ||
| 333 | dl1416b_device::dl1416b_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) | |
| 334 | : dl1416_device(mconfig, DL1416B, "DL1416B", tag, owner, clock) | |
| 335 | { | |
| 336 | } | |
| 337 | ||
| 338 | ||
| 339 | const device_type DL1416T = &device_creator<dl1416t_device>; | |
| 340 | ||
| 341 | dl1416t_device::dl1416t_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) | |
| 342 | : dl1416_device(mconfig, DL1416T, "DL1416T", tag, owner, clock) | |
| 343 | { | |
| 344 | } |
| Added: svn:eol-style + native Added: svn:mime-type + text/plain |
| r0 | r21685 | |
|---|---|---|
| 1 | /***************************************************************************** | |
| 2 | * | |
| 3 | * video/dl1416.h | |
| 4 | * | |
| 5 | * DL1416 | |
| 6 | * | |
| 7 | * 4-Digit 16-Segment Alphanumeric Intelligent Display | |
| 8 | * with Memory/Decoder/Driver | |
| 9 | * | |
| 10 | * See video/dl1416.c for more info | |
| 11 | * | |
| 12 | ****************************************************************************/ | |
| 13 | ||
| 14 | #ifndef DL1416_H_ | |
| 15 | #define DL1416_H_ | |
| 16 | ||
| 17 | #include "devcb.h" | |
| 18 | ||
| 19 | /*************************************************************************** | |
| 20 | TYPE DEFINITIONS | |
| 21 | ***************************************************************************/ | |
| 22 | ||
| 23 | typedef void (*dl1416_update_func)(device_t *device, int digit, int data); | |
| 24 | ||
| 25 | struct dl1416_interface | |
| 26 | { | |
| 27 | dl1416_update_func update; | |
| 28 | }; | |
| 29 | ||
| 30 | ||
| 31 | /*************************************************************************** | |
| 32 | DEVICE CONFIGURATION MACROS | |
| 33 | ***************************************************************************/ | |
| 34 | ||
| 35 | #define MCFG_DL1416B_ADD(_tag, _config) \ | |
| 36 | MCFG_DEVICE_ADD(_tag, DL1416B, 0) \ | |
| 37 | MCFG_DEVICE_CONFIG(_config) | |
| 38 | ||
| 39 | #define MCFG_DL1416T_ADD(_tag, _config) \ | |
| 40 | MCFG_DEVICE_ADD(_tag, DL1416T, 0) \ | |
| 41 | MCFG_DEVICE_CONFIG(_config) | |
| 42 | ||
| 43 | ||
| 44 | /*************************************************************************** | |
| 45 | FUNCTION PROTOTYPES | |
| 46 | ***************************************************************************/ | |
| 47 | ||
| 48 | /* inputs */ | |
| 49 | WRITE_LINE_DEVICE_HANDLER( dl1416_wr_w ); /* write enable */ | |
| 50 | WRITE_LINE_DEVICE_HANDLER( dl1416_ce_w ); /* chip enable */ | |
| 51 | WRITE_LINE_DEVICE_HANDLER( dl1416_cu_w ); /* cursor enable */ | |
| 52 | DECLARE_WRITE8_DEVICE_HANDLER( dl1416_data_w ); | |
| 53 | ||
| 54 | /* device get info callback */ | |
| 55 | class dl1416_device : public device_t | |
| 56 | { | |
| 57 | public: | |
| 58 | dl1416_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock); | |
| 59 | ~dl1416_device() { global_free(m_token); } | |
| 60 | ||
| 61 | // access to legacy token | |
| 62 | void *token() const { assert(m_token != NULL); return m_token; } | |
| 63 | protected: | |
| 64 | // device-level overrides | |
| 65 | virtual void device_config_complete(); | |
| 66 | virtual void device_start(); | |
| 67 | virtual void device_reset(); | |
| 68 | private: | |
| 69 | // internal state | |
| 70 | void *m_token; | |
| 71 | }; | |
| 72 | ||
| 73 | class dl1416b_device : public dl1416_device | |
| 74 | { | |
| 75 | public: | |
| 76 | dl1416b_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); | |
| 77 | }; | |
| 78 | ||
| 79 | extern const device_type DL1416B; | |
| 80 | ||
| 81 | class dl1416t_device : public dl1416_device | |
| 82 | { | |
| 83 | public: | |
| 84 | dl1416t_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); | |
| 85 | }; | |
| 86 | ||
| 87 | extern const device_type DL1416T; | |
| 88 | ||
| 89 | ||
| 90 | #endif /* DL1416_H_ */ |
| Added: svn:eol-style + native Added: svn:mime-type + text/plain |
| r0 | r21685 | |
|---|---|---|
| 1 | /* | |
| 2 | tms3556 emulation | |
| 3 | ||
| 4 | TODO: | |
| 5 | * implement remaining flags in control registers | |
| 6 | * test the whole thing | |
| 7 | * find the bloody tms3556 manual. I mean the register and VRAM interfaces | |
| 8 | are mostly guesswork full of hacks, and I'd like to compare it with | |
| 9 | documentation. | |
| 10 | ||
| 11 | Raphael Nabet, 2004 | |
| 12 | */ | |
| 13 | ||
| 14 | #include "emu.h" | |
| 15 | #include "tms3556.h" | |
| 16 | ||
| 17 | //************************************************************************** | |
| 18 | // MACROS / CONSTANTS | |
| 19 | //************************************************************************** | |
| 20 | ||
| 21 | #define LOG 0 | |
| 22 | ||
| 23 | //************************************************************************** | |
| 24 | // GLOBAL VARIABLES | |
| 25 | //************************************************************************** | |
| 26 | ||
| 27 | // devices | |
| 28 | const device_type TMS3556 = &device_creator<tms3556_device>; | |
| 29 | ||
| 30 | ||
| 31 | // default address map | |
| 32 | static ADDRESS_MAP_START( tms3556, AS_0, 8, tms3556_device ) | |
| 33 | AM_RANGE(0x0000, 0xffff) AM_RAM | |
| 34 | ADDRESS_MAP_END | |
| 35 | ||
| 36 | //------------------------------------------------- | |
| 37 | // memory_space_config - return a description of | |
| 38 | // any address spaces owned by this device | |
| 39 | //------------------------------------------------- | |
| 40 | ||
| 41 | const address_space_config *tms3556_device::memory_space_config(address_spacenum spacenum) const | |
| 42 | { | |
| 43 | return (spacenum == AS_0) ? &m_space_config : NULL; | |
| 44 | } | |
| 45 | ||
| 46 | ||
| 47 | //************************************************************************** | |
| 48 | // INLINE HELPERS | |
| 49 | //************************************************************************** | |
| 50 | ||
| 51 | //------------------------------------------------- | |
| 52 | // readbyte - read a byte at the given address | |
| 53 | //------------------------------------------------- | |
| 54 | ||
| 55 | inline UINT8 tms3556_device::readbyte(offs_t address) | |
| 56 | { | |
| 57 | return space().read_byte(address); | |
| 58 | } | |
| 59 | ||
| 60 | ||
| 61 | //------------------------------------------------- | |
| 62 | // writebyte - write a byte at the given address | |
| 63 | //------------------------------------------------- | |
| 64 | ||
| 65 | inline void tms3556_device::writebyte(offs_t address, UINT8 data) | |
| 66 | { | |
| 67 | space().write_byte(address, data); | |
| 68 | } | |
| 69 | ||
| 70 | ||
| 71 | //************************************************************************** | |
| 72 | // LIVE DEVICE | |
| 73 | //************************************************************************** | |
| 74 | ||
| 75 | //------------------------------------------------- | |
| 76 | // tms3556_device - constructor | |
| 77 | //------------------------------------------------- | |
| 78 | ||
| 79 | tms3556_device::tms3556_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) | |
| 80 | : device_t(mconfig, TMS3556, "Texas Instruments VDP TMS3556", tag, owner, clock), | |
| 81 | device_memory_interface(mconfig, *this), | |
| 82 | m_space_config("videoram", ENDIANNESS_LITTLE, 8, 17, 0, NULL, *ADDRESS_MAP_NAME(tms3556)), | |
| 83 | m_write_ptr(0), | |
| 84 | m_reg_ptr(0), | |
| 85 | m_reg_access_phase(0), | |
| 86 | m_magical_mystery_flag(0), | |
| 87 | m_scanline(0), | |
| 88 | m_blink(0), | |
| 89 | m_blink_count(0) | |
| 90 | { | |
| 91 | for (int i = 0; i < 8; i++) | |
| 92 | { | |
| 93 | m_control_regs[i] = 0; | |
| 94 | m_address_regs[i] = 0; | |
| 95 | } | |
| 96 | } | |
| 97 | ||
| 98 | ||
| 99 | //------------------------------------------------- | |
| 100 | // device_start - device-specific startup | |
| 101 | //------------------------------------------------- | |
| 102 | ||
| 103 | void tms3556_device::device_start() | |
| 104 | { | |
| 105 | // register for state saving | |
| 106 | save_item(NAME(m_control_regs)); | |
| 107 | save_item(NAME(m_address_regs)); | |
| 108 | save_item(NAME(m_write_ptr)); | |
| 109 | save_item(NAME(m_reg_ptr)); | |
| 110 | save_item(NAME(m_reg_access_phase)); | |
| 111 | save_item(NAME(m_magical_mystery_flag)); | |
| 112 | save_item(NAME(m_scanline)); | |
| 113 | save_item(NAME(m_blink)); | |
| 114 | save_item(NAME(m_blink_count)); | |
| 115 | save_item(NAME(m_bg_color)); | |
| 116 | save_item(NAME(m_name_offset)); | |
| 117 | save_item(NAME(m_cg_flag)); | |
| 118 | save_item(NAME(m_char_line_counter)); | |
| 119 | save_item(NAME(m_dbl_h_phase)); | |
| 120 | ||
| 121 | machine().primary_screen->register_screen_bitmap(m_bitmap); | |
| 122 | } | |
| 123 | ||
| 124 | ||
| 125 | /*static const char *const tms3556_mode_names[] = { "DISPLAY OFF", "TEXT", "GRAPHIC", "MIXED" };*/ | |
| 126 | ||
| 127 | ||
| 128 | UINT32 tms3556_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) | |
| 129 | { | |
| 130 | copybitmap(bitmap, m_bitmap, 0, 0, 0, 0, cliprect); | |
| 131 | return 0; | |
| 132 | } | |
| 133 | ||
| 134 | ||
| 135 | //------------------------------------------------- | |
| 136 | // vram_r - VRAM read | |
| 137 | //------------------------------------------------- | |
| 138 | ||
| 139 | READ8_MEMBER( tms3556_device::vram_r ) | |
| 140 | { | |
| 141 | if (LOG) logerror("TMS3556 VRAM Read: %06x\n", offset); | |
| 142 | ||
| 143 | if (m_magical_mystery_flag) | |
| 144 | { | |
| 145 | m_write_ptr = ((m_control_regs[2] << 8) | m_control_regs[1]) + 1; | |
| 146 | m_magical_mystery_flag = 0; | |
| 147 | } | |
| 148 | ||
| 149 | return readbyte(m_address_regs[1]++); | |
| 150 | } | |
| 151 | ||
| 152 | //------------------------------------------------- | |
| 153 | // vram_w - VRAM write | |
| 154 | //------------------------------------------------- | |
| 155 | ||
| 156 | WRITE8_MEMBER( tms3556_device::vram_w ) | |
| 157 | { | |
| 158 | if (LOG) logerror("TMS3556 VRAM Write: %06x = %02x\n", offset, data); | |
| 159 | ||
| 160 | if (m_magical_mystery_flag) | |
| 161 | { | |
| 162 | m_write_ptr = (m_control_regs[2] << 8) | m_control_regs[1]; | |
| 163 | m_magical_mystery_flag = 0; | |
| 164 | } | |
| 165 | ||
| 166 | writebyte(m_write_ptr++, data); | |
| 167 | } | |
| 168 | ||
| 169 | ||
| 170 | //------------------------------------------------- | |
| 171 | // reg_r - read from register port | |
| 172 | //------------------------------------------------- | |
| 173 | ||
| 174 | READ8_MEMBER( tms3556_device::reg_r ) | |
| 175 | { | |
| 176 | if (LOG) logerror("TMS3556 Reg Read: %06x\n", offset); | |
| 177 | ||
| 178 | int reply = 0; | |
| 179 | ||
| 180 | if (m_reg_ptr < 8) | |
| 181 | { | |
| 182 | reply = m_control_regs[m_reg_ptr]; | |
| 183 | m_reg_access_phase = 0; | |
| 184 | } | |
| 185 | else | |
| 186 | { | |
| 187 | // ??? | |
| 188 | } | |
| 189 | ||
| 190 | return reply; | |
| 191 | } | |
| 192 | ||
| 193 | //------------------------------------------------- | |
| 194 | // reg_w - write to register port | |
| 195 | //------------------------------------------------- | |
| 196 | ||
| 197 | WRITE8_MEMBER( tms3556_device::reg_w ) | |
| 198 | { | |
| 199 | if (LOG) logerror("TMS3556 Reg Write: %06x = %02x\n", offset, data); | |
| 200 | ||
| 201 | if ((m_reg_access_phase == 3) && (data)) | |
| 202 | m_reg_access_phase = 0; /* ???????????? */ | |
| 203 | ||
| 204 | switch (m_reg_access_phase) | |
| 205 | { | |
| 206 | case 0: | |
| 207 | m_reg_ptr = data & 0x0f; | |
| 208 | m_reg_access_phase = 1; | |
| 209 | break; | |
| 210 | ||
| 211 | case 1: | |
| 212 | if (m_reg_ptr < 8) | |
| 213 | { | |
| 214 | m_control_regs[m_reg_ptr] = data; | |
| 215 | m_reg_access_phase = 0; | |
| 216 | if (m_reg_ptr == 2) | |
| 217 | m_magical_mystery_flag = 1; | |
| 218 | } | |
| 219 | else if (m_reg_ptr == 9) | |
| 220 | { /* I don't understand what is going on, but it is the only way to | |
| 221 | get this to work */ | |
| 222 | m_address_regs[m_reg_ptr - 8] = ((m_control_regs[2] << 8) | m_control_regs[1]) + 1; | |
| 223 | m_reg_access_phase = 0; | |
| 224 | m_magical_mystery_flag = 0; | |
| 225 | } | |
| 226 | else | |
| 227 | { | |
| 228 | m_address_regs[m_reg_ptr - 8] = (m_control_regs[m_reg_ptr - 8] & 0xff00) | m_control_regs[1]; | |
| 229 | m_reg_access_phase = 2; | |
| 230 | m_magical_mystery_flag = 0; | |
| 231 | } | |
| 232 | break; | |
| 233 | ||
| 234 | case 2: | |
| 235 | m_address_regs[m_reg_ptr - 8] = (m_control_regs[m_reg_ptr - 8] & 0x00ff) | (m_control_regs[2] << 8); | |
| 236 | if ((m_reg_ptr <= 10) || (m_reg_ptr == 15)) | |
| 237 | m_address_regs[m_reg_ptr - 8]++; | |
| 238 | else | |
| 239 | m_address_regs[m_reg_ptr - 8] += 2; | |
| 240 | m_reg_access_phase = 3; | |
| 241 | break; | |
| 242 | ||
| 243 | case 3: | |
| 244 | m_reg_access_phase = 0; | |
| 245 | break; | |
| 246 | } | |
| 247 | } | |
| 248 | ||
| 249 | ||
| 250 | //------------------------------------------------- | |
| 251 | // redraw code | |
| 252 | //------------------------------------------------- | |
| 253 | ||
| 254 | ||
| 255 | //------------------------------------------------- | |
| 256 | // draw_line_empty - draw an empty line (used for | |
| 257 | // top and bottom borders, and screen off mode) | |
| 258 | //------------------------------------------------- | |
| 259 | ||
| 260 | void tms3556_device::draw_line_empty(UINT16 *ln) | |
| 261 | { | |
| 262 | int i; | |
| 263 | ||
| 264 | for (i = 0; i < TMS3556_TOTAL_WIDTH; i++) | |
| 265 | #if TMS3556_DOUBLE_WIDTH | |
| 266 | *ln++ = m_bg_color; | |
| 267 | #endif | |
| 268 | *ln++ = m_bg_color; | |
| 269 | } | |
| 270 | ||
| 271 | ||
| 272 | //------------------------------------------------- | |
| 273 | // draw_line_text_common - draw a line of text | |
| 274 | // (called by draw_line_text and draw_line_mixed) | |
| 275 | //------------------------------------------------- | |
| 276 | ||
| 277 | void tms3556_device::draw_line_text_common(UINT16 *ln) | |
| 278 | { | |
| 279 | int pattern, x, xx, i, name_offset; | |
| 280 | UINT16 fg, bg; | |
| 281 | offs_t nametbl_base; | |
| 282 | offs_t patterntbl_base[4]; | |
| 283 | int name_hi, name_lo; | |
| 284 | int pattern_ix; | |
| 285 | int alphanumeric_mode, dbl_w, dbl_h, dbl_w_phase = 0; | |
| 286 | ||
| 287 | nametbl_base = m_address_regs[2]; | |
| 288 | for (i = 0; i < 4; i++) | |
| 289 | patterntbl_base[i] = m_address_regs[i + 3]; | |
| 290 | ||
| 291 | for (xx = 0; xx < TMS3556_LEFT_BORDER; xx++) | |
| 292 | #if TMS3556_DOUBLE_WIDTH | |
| 293 | *ln++ = m_bg_color; | |
| 294 | #endif | |
| 295 | *ln++ = m_bg_color; | |
| 296 | ||
| 297 | name_offset = m_name_offset; | |
| 298 | ||
| 299 | for (x = 0; x < 40; x++) | |
| 300 | { | |
| 301 | name_hi = readbyte(nametbl_base + name_offset); | |
| 302 | name_lo = readbyte(nametbl_base + name_offset + 1); | |
| 303 | pattern_ix = ((name_hi >> 2) & 2) | ((name_hi >> 4) & 1); | |
| 304 | alphanumeric_mode = (pattern_ix < 2) || ((pattern_ix == 3) && !(m_control_regs[7] & 0x08)); | |
| 305 | fg = (name_hi >> 5) & 0x7; | |
| 306 | if (alphanumeric_mode) | |
| 307 | { | |
| 308 | if (name_hi & 4) | |
| 309 | { /* inverted color */ | |
| 310 | bg = fg; | |
| 311 | fg = m_bg_color; | |
| 312 | } | |
| 313 | else | |
| 314 | bg = m_bg_color; | |
| 315 | dbl_w = name_hi & 0x2; | |
| 316 | dbl_h = name_hi & 0x1; | |
| 317 | } | |
| 318 | else | |
| 319 | { | |
| 320 | bg = name_hi & 0x7; | |
| 321 | dbl_w = 0; | |
| 322 | dbl_h = 0; | |
| 323 | } | |
| 324 | if ((name_lo & 0x80) && m_blink) | |
| 325 | fg = bg; /* blink off time */ | |
| 326 | if (! dbl_h) | |
| 327 | { /* single height */ | |
| 328 | pattern = readbyte(patterntbl_base[pattern_ix] + (name_lo & 0x7f) + 128 * m_char_line_counter); | |
| 329 | if (m_char_line_counter == 0) | |
| 330 | m_dbl_h_phase[x] = 0; | |
| 331 | } | |
| 332 | else | |
| 333 | { /* double height */ | |
| 334 | if (! m_dbl_h_phase[x]) | |
| 335 | /* first phase: pattern from upper half */ | |
| 336 | pattern = readbyte(patterntbl_base[pattern_ix] + (name_lo & 0x7f) + 128 * (5 + (m_char_line_counter >> 1))); | |
| 337 | else | |
| 338 | /* second phase: pattern from lower half */ | |
| 339 | pattern = readbyte(patterntbl_base[pattern_ix] + (name_lo & 0x7f) + 128 * (m_char_line_counter >> 1)); | |
| 340 | if (m_char_line_counter == 0) | |
| 341 | m_dbl_h_phase[x] = !m_dbl_h_phase[x]; | |
| 342 | } | |
| 343 | if (!dbl_w) | |
| 344 | { /* single width */ | |
| 345 | for (xx = 0; xx < 8; xx++) | |
| 346 | { | |
| 347 | UINT16 color = (pattern & 0x80) ? fg : bg; | |
| 348 | #if TMS3556_DOUBLE_WIDTH | |
| 349 | *ln++ = color; | |
| 350 | #endif | |
| 351 | *ln++ = color; | |
| 352 | pattern <<= 1; | |
| 353 | } | |
| 354 | dbl_w_phase = 0; | |
| 355 | } | |
| 356 | else | |
| 357 | { /* double width */ | |
| 358 | if (dbl_w_phase) | |
| 359 | /* second phase: display right half */ | |
| 360 | pattern <<= 4; | |
| 361 | for (xx = 0; xx < 4; xx++) | |
| 362 | { | |
| 363 | UINT16 color = (pattern & 0x80) ? fg : bg; | |
| 364 | #if TMS3556_DOUBLE_WIDTH | |
| 365 | *ln++ = color; *ln++ = color; | |
| 366 | #endif | |
| 367 | *ln++ = color; *ln++ = color; | |
| 368 | pattern <<= 1; | |
| 369 | } | |
| 370 | dbl_w_phase = !dbl_w_phase; | |
| 371 | } | |
| 372 | name_offset += 2; | |
| 373 | } | |
| 374 | ||
| 375 | for (xx = 0; xx < TMS3556_RIGHT_BORDER; xx++) | |
| 376 | #if TMS3556_DOUBLE_WIDTH | |
| 377 | *ln++ = m_bg_color; | |
| 378 | #endif | |
| 379 | *ln++ = m_bg_color; | |
| 380 | ||
| 381 | if (m_char_line_counter == 0) | |
| 382 | m_name_offset = name_offset; | |
| 383 | } | |
| 384 | ||
| 385 | ||
| 386 | //------------------------------------------------- | |
| 387 | // draw_line_bitmap_common - draw a line of bitmap | |
| 388 | // (called by draw_line_bitmap and draw_line_mixed) | |
| 389 | //------------------------------------------------- | |
| 390 | ||
| 391 | void tms3556_device::draw_line_bitmap_common(UINT16 *ln) | |
| 392 | { | |
| 393 | int x, xx; | |
| 394 | offs_t nametbl_base; | |
| 395 | int name_b, name_g, name_r; | |
| 396 | ||
| 397 | nametbl_base = m_address_regs[2]; | |
| 398 | ||
| 399 | for (xx = 0; xx < TMS3556_LEFT_BORDER; xx++) | |
| 400 | #if TMS3556_DOUBLE_WIDTH | |
| 401 | *ln++ = m_bg_color; | |
| 402 | #endif | |
| 403 | *ln++ = m_bg_color; | |
| 404 | ||
| 405 | for (x = 0; x < 40; x++) | |
| 406 | { | |
| 407 | name_b = readbyte(nametbl_base + m_name_offset); | |
| 408 | name_g = readbyte(nametbl_base + m_name_offset + 1); | |
| 409 | name_r = readbyte(nametbl_base + m_name_offset + 2); | |
| 410 | for (xx = 0; xx < 8; xx++) | |
| 411 | { | |
| 412 | UINT16 color = ((name_b >> 5) & 0x4) | ((name_g >> 6) & 0x2) | ((name_r >> 7) & 0x1); | |
| 413 | #if TMS3556_DOUBLE_WIDTH | |
| 414 | *ln++ = color; | |
| 415 | #endif | |
| 416 | *ln++ = color; | |
| 417 | name_b <<= 1; | |
| 418 | name_g <<= 1; | |
| 419 | name_r <<= 1; | |
| 420 | } | |
| 421 | m_name_offset += 3; | |
| 422 | } | |
| 423 | ||
| 424 | for (xx = 0; xx < TMS3556_RIGHT_BORDER; xx++) | |
| 425 | #if TMS3556_DOUBLE_WIDTH | |
| 426 | *ln++ = m_bg_color; | |
| 427 | #endif | |
| 428 | *ln++ = m_bg_color; | |
| 429 | } | |
| 430 | ||
| 431 | ||
| 432 | //------------------------------------------------- | |
| 433 | // draw_line_text - draw a line in text mode | |
| 434 | //------------------------------------------------- | |
| 435 | ||
| 436 | void tms3556_device::draw_line_text(UINT16 *ln) | |
| 437 | { | |
| 438 | if (m_char_line_counter == 0) | |
| 439 | m_char_line_counter = 10; | |
| 440 | m_char_line_counter--; | |
| 441 | draw_line_text_common(ln); | |
| 442 | } | |
| 443 | ||
| 444 | ||
| 445 | //------------------------------------------------- | |
| 446 | // draw_line_bitmap - draw a line in bitmap mode | |
| 447 | //------------------------------------------------- | |
| 448 | ||
| 449 | void tms3556_device::draw_line_bitmap(UINT16 *ln) | |
| 450 | { | |
| 451 | draw_line_bitmap_common(ln); | |
| 452 | m_bg_color = (readbyte(m_address_regs[2] + m_name_offset) >> 5) & 0x7; | |
| 453 | m_name_offset += 2; | |
| 454 | } | |
| 455 | ||
| 456 | ||
| 457 | //------------------------------------------------- | |
| 458 | // draw_line_mixed - draw a line in mixed mode | |
| 459 | //------------------------------------------------- | |
| 460 | ||
| 461 | void tms3556_device::draw_line_mixed(UINT16 *ln) | |
| 462 | { | |
| 463 | if (m_cg_flag) | |
| 464 | { /* bitmap line */ | |
| 465 | draw_line_bitmap_common(ln); | |
| 466 | m_bg_color = (readbyte(m_address_regs[2] + m_name_offset) >> 5) & 0x7; | |
| 467 | m_cg_flag = (readbyte(m_address_regs[2] + m_name_offset) >> 4) & 0x1; | |
| 468 | m_name_offset += 2; | |
| 469 | } | |
| 470 | else | |
| 471 | { /* text line */ | |
| 472 | if (m_char_line_counter == 0) | |
| 473 | m_char_line_counter = 10; | |
| 474 | m_char_line_counter--; | |
| 475 | draw_line_text_common(ln); | |
| 476 | if (m_char_line_counter == 0) | |
| 477 | { | |
| 478 | m_bg_color = (readbyte(m_address_regs[2] + m_name_offset) >> 5) & 0x7; | |
| 479 | m_cg_flag = (readbyte(m_address_regs[2] + m_name_offset) >> 4) & 0x1; | |
| 480 | m_name_offset += 2; | |
| 481 | } | |
| 482 | } | |
| 483 | } | |
| 484 | ||
| 485 | ||
| 486 | //------------------------------------------------- | |
| 487 | // draw_line - draw a line. If non-interlaced mode, | |
| 488 | // duplicate the line. | |
| 489 | //------------------------------------------------- | |
| 490 | ||
| 491 | void tms3556_device::draw_line(bitmap_ind16 &bmp, int line) | |
| 492 | { | |
| 493 | int double_lines = 0; | |
| 494 | UINT16 *ln, *ln2 = NULL; | |
| 495 | ||
| 496 | // if (m_control_regs[4] & 0x??) | |
| 497 | // { // interlaced mode | |
| 498 | // ln = &bmp->pix16(line, m_field); | |
| 499 | // } | |
| 500 | // else | |
| 501 | { /* non-interlaced mode */ | |
| 502 | ln = &bmp.pix16(line); | |
| 503 | ln2 = &bmp.pix16(line, 1); | |
| 504 | double_lines = 1; | |
| 505 | } | |
| 506 | ||
| 507 | if ((line < TMS3556_TOP_BORDER) || (line >= (TMS3556_TOP_BORDER + 250))) | |
| 508 | { | |
| 509 | /* draw top and bottom borders */ | |
| 510 | draw_line_empty(ln); | |
| 511 | } | |
| 512 | else | |
| 513 | { | |
| 514 | /* draw useful area */ | |
| 515 | switch (m_control_regs[6] >> 6) | |
| 516 | { | |
| 517 | case TMS3556_MODE_OFF: | |
| 518 | draw_line_empty(ln); | |
| 519 | break; | |
| 520 | case TMS3556_MODE_TEXT: | |
| 521 | draw_line_text(ln); | |
| 522 | break; | |
| 523 | case TMS3556_MODE_BITMAP: | |
| 524 | draw_line_bitmap(ln); | |
| 525 | break; | |
| 526 | case TMS3556_MODE_MIXED: | |
| 527 | draw_line_mixed(ln); | |
| 528 | break; | |
| 529 | } | |
| 530 | } | |
| 531 | ||
| 532 | if (double_lines) | |
| 533 | { | |
| 534 | memcpy (ln2, ln, TMS3556_TOTAL_WIDTH * (TMS3556_DOUBLE_WIDTH ? 2 : 1)); | |
| 535 | } | |
| 536 | } | |
| 537 | ||
| 538 | ||
| 539 | //------------------------------------------------- | |
| 540 | // interrupt_start_vblank - Do vblank-time tasks | |
| 541 | //------------------------------------------------- | |
| 542 | ||
| 543 | void tms3556_device::interrupt_start_vblank(void) | |
| 544 | { | |
| 545 | /* at every frame, vdp switches fields */ | |
| 546 | //m_field = !m_field; | |
| 547 | ||
| 548 | /* color blinking */ | |
| 549 | if (m_blink_count) | |
| 550 | m_blink_count--; | |
| 551 | if (!m_blink_count) | |
| 552 | { | |
| 553 | m_blink = !m_blink; | |
| 554 | m_blink_count = 60; /*no idea what the real value is*/ | |
| 555 | } | |
| 556 | /* reset background color */ | |
| 557 | m_bg_color = (m_control_regs[7] >> 5) & 0x7; | |
| 558 | /* reset name offset */ | |
| 559 | m_name_offset = 0; | |
| 560 | /* reset character line counter */ | |
| 561 | m_char_line_counter = 0; | |
| 562 | /* reset c/g flag */ | |
| 563 | m_cg_flag = 0; | |
| 564 | /* reset double height phase flags */ | |
| 565 | memset(m_dbl_h_phase, 0, sizeof(m_dbl_h_phase)); | |
| 566 | } | |
| 567 | ||
| 568 | ||
| 569 | //------------------------------------------------- | |
| 570 | // interrupt - scanline handler | |
| 571 | //------------------------------------------------- | |
| 572 | ||
| 573 | void tms3556_device::interrupt(running_machine &machine) | |
| 574 | { | |
| 575 | /* check for start of vblank */ | |
| 576 | if (m_scanline == 310) /*no idea what the real value is*/ | |
| 577 | interrupt_start_vblank(); | |
| 578 | ||
| 579 | /* render the current line */ | |
| 580 | if ((m_scanline >= 0) && (m_scanline < TMS3556_TOTAL_HEIGHT)) | |
| 581 | { | |
| 582 | //if (!video_skip_this_frame()) | |
| 583 | draw_line(m_bitmap, m_scanline); | |
| 584 | } | |
| 585 | ||
| 586 | if (++m_scanline == 313) | |
| 587 | m_scanline = 0; | |
| 588 | } |
| Added: svn:eol-style + native Added: svn:mime-type + text/plain |
| r0 | r21685 | |
|---|---|---|
| 1 | /*************************************************************************** | |
| 2 | ||
| 3 | Texas Instruments TMS3556 Video Display Processor | |
| 4 | ||
| 5 | ***************************************************************************/ | |
| 6 | ||
| 7 | ||
| 8 | #pragma once | |
| 9 | ||
| 10 | #ifndef __TMS3556_H__ | |
| 11 | #define __TMS3556_H__ | |
| 12 | ||
| 13 | ///************************************************************************* | |
| 14 | // MACROS / CONSTANTS | |
| 15 | ///************************************************************************* | |
| 16 | ||
| 17 | #define TMS3556_TOP_BORDER 1 | |
| 18 | #define TMS3556_BOTTOM_BORDER 1 | |
| 19 | #define TMS3556_LEFT_BORDER 8 | |
| 20 | #define TMS3556_RIGHT_BORDER 8 | |
| 21 | #define TMS3556_TOTAL_WIDTH (320 + TMS3556_LEFT_BORDER + TMS3556_RIGHT_BORDER) | |
| 22 | #define TMS3556_TOTAL_HEIGHT (250 + TMS3556_TOP_BORDER + TMS3556_BOTTOM_BORDER) | |
| 23 | ||
| 24 | /* if DOUBLE_WIDTH set, the horizontal resolution is doubled */ | |
| 25 | #define TMS3556_DOUBLE_WIDTH 1 | |
| 26 | ||
| 27 | #define TMS3556_MODE_OFF 0 | |
| 28 | #define TMS3556_MODE_TEXT 1 | |
| 29 | #define TMS3556_MODE_BITMAP 2 | |
| 30 | #define TMS3556_MODE_MIXED 3 | |
| 31 | ||
| 32 | ||
| 33 | ///************************************************************************* | |
| 34 | // INTERFACE CONFIGURATION MACROS | |
| 35 | ///************************************************************************* | |
| 36 | ||
| 37 | #define MCFG_TMS3556_ADD(_tag) \ | |
| 38 | MCFG_DEVICE_ADD(_tag, TMS3556, 0) | |
| 39 | ||
| 40 | ///************************************************************************* | |
| 41 | // TYPE DEFINITIONS | |
| 42 | ///************************************************************************* | |
| 43 | ||
| 44 | // ======================> tms3556_device | |
| 45 | ||
| 46 | class tms3556_device : public device_t, | |
| 47 | public device_memory_interface | |
| 48 | { | |
| 49 | public: | |
| 50 | // construction/destruction | |
| 51 | tms3556_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); | |
| 52 | ||
| 53 | DECLARE_READ8_MEMBER( vram_r ); | |
| 54 | DECLARE_WRITE8_MEMBER( vram_w ); | |
| 55 | DECLARE_READ8_MEMBER( reg_r ); | |
| 56 | DECLARE_WRITE8_MEMBER( reg_w ); | |
| 57 | ||
| 58 | void interrupt(running_machine &machine); | |
| 59 | ||
| 60 | UINT32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); | |
| 61 | ||
| 62 | protected: | |
| 63 | // device-level overrides | |
| 64 | virtual void device_start(); | |
| 65 | ||
| 66 | // device_config_memory_interface overrides | |
| 67 | virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; | |
| 68 | ||
| 69 | // address space configurations | |
| 70 | const address_space_config m_space_config; | |
| 71 | ||
| 72 | inline UINT8 readbyte(offs_t address); | |
| 73 | inline void writebyte(offs_t address, UINT8 data); | |
| 74 | ||
| 75 | void draw_line_empty(UINT16 *ln); | |
| 76 | void draw_line_text_common(UINT16 *ln); | |
| 77 | void draw_line_bitmap_common(UINT16 *ln); | |
| 78 | void draw_line_text(UINT16 *ln); | |
| 79 | void draw_line_bitmap(UINT16 *ln); | |
| 80 | void draw_line_mixed(UINT16 *ln); | |
| 81 | void draw_line(bitmap_ind16 &bmp, int line); | |
| 82 | void interrupt_start_vblank(void); | |
| 83 | ||
| 84 | private: | |
| 85 | // registers | |
| 86 | UINT8 m_control_regs[8]; | |
| 87 | UINT16 m_address_regs[8]; | |
| 88 | UINT16 m_write_ptr; | |
| 89 | ||
| 90 | // register interface | |
| 91 | int m_reg_ptr; | |
| 92 | int m_reg_access_phase; | |
| 93 | int m_magical_mystery_flag; | |
| 94 | ||
| 95 | int m_scanline; // scanline counter | |
| 96 | int m_blink, m_blink_count; // blinking | |
| 97 | int m_bg_color; // background color for current line | |
| 98 | int m_name_offset; // current offset in name table | |
| 99 | int m_cg_flag; // c/g flag (mixed mode only) | |
| 100 | int m_char_line_counter; // character line counter (decrements from 10, 0 when we have reached | |
| 101 | // last line of character row) | |
| 102 | int m_dbl_h_phase[40]; // double height phase flags (one per horizontal character position) | |
| 103 | ||
| 104 | bitmap_ind16 m_bitmap; | |
| 105 | }; | |
| 106 | ||
| 107 | ||
| 108 | // device type definition | |
| 109 | extern const device_type TMS3556; | |
| 110 | ||
| 111 | ||
| 112 | #endif |
| Added: svn:mime-type + text/plain Added: svn:eol-style + native |
| r0 | r21685 | |
|---|---|---|
| 1 | /* | |
| 2 | ||
| 3 | Hitachi HD66421 LCD Controller/Driver | |
| 4 | ||
| 5 | (c) 2001-2007 Tim Schuerewegen | |
| 6 | ||
| 7 | */ | |
| 8 | ||
| 9 | #include "emu.h" | |
| 10 | #include "hd66421.h" | |
| 11 | ||
| 12 | //************************************************************************** | |
| 13 | // MACROS / CONSTANTS | |
| 14 | //************************************************************************** | |
| 15 | ||
| 16 | #define LOG_LEVEL 1 | |
| 17 | #define _logerror(level,x) do { if (LOG_LEVEL > level) logerror x; } while (0) | |
| 18 | ||
| 19 | #define HD66421_RAM_SIZE (HD66421_WIDTH * HD66421_HEIGHT / 4) // 2-bits per pixel | |
| 20 | ||
| 21 | // R0 - control register 1 | |
| 22 | #define LCD_R0_RMW 0x80 // read-modify-write mode | |
| 23 | #define LCD_R0_DISP 0x40 // display on/off | |
| 24 | #define LCD_R0_STBY 0x20 // standby (internal operation and power circuit halt) | |
| 25 | #define LCD_R0_PWR 0x10 | |
| 26 | #define LCD_R0_AMP 0x08 | |
| 27 | #define LCD_R0_REV 0x04 // reverse | |
| 28 | #define LCD_R0_HOLT 0x02 | |
| 29 | #define LCD_R0_ADC 0x01 | |
| 30 | ||
| 31 | // R1 - control register 2 | |
| 32 | #define LCD_R1_BIS1 0x80 // bias ratio (bit 1) | |
| 33 | #define LCD_R1_BIS0 0x40 // bias ratio (bit 0) | |
| 34 | #define LCD_R1_WLS 0x20 | |
| 35 | #define LCD_R1_GRAY 0x10 // grayscale palette 4/32 | |
| 36 | #define LCD_R1_DTY1 0x08 // display duty cycle (bit 1) | |
| 37 | #define LCD_R1_DTY0 0x04 // display duty cycle (bit 0) | |
| 38 | #define LCD_R1_INC 0x02 | |
| 39 | #define LCD_R1_BLK 0x01 // blink function | |
| 40 | ||
| 41 | // register 0 to 16 | |
| 42 | #define LCD_REG_CONTROL_1 0x00 // control register 1 | |
| 43 | #define LCD_REG_CONTROL_2 0x01 // control register 2 | |
| 44 | #define LCD_REG_ADDR_X 0x02 // x address register | |
| 45 | #define LCD_REG_ADDR_Y 0x03 // y address register | |
| 46 | #define LCD_REG_RAM 0x04 // display ram access register | |
| 47 | #define LCD_REG_START_Y 0x05 // display start line register | |
| 48 | #define LCD_REG_BLINK_START 0x06 // blink start line register | |
| 49 | #define LCD_REG_BLINK_END 0x07 // blink end line register | |
| 50 | #define LCD_REG_BLINK_1 0x08 // blink register 1 | |
| 51 | #define LCD_REG_BLINK_2 0x09 // blink register 2 | |
| 52 | #define LCD_REG_BLINK_3 0x0A // blink register 3 | |
| 53 | #define LCD_REG_PARTIAL 0x0B // partial display block register | |
| 54 | #define LCD_REG_COLOR_1 0x0C // gray scale palette 1 (0,0) | |
| 55 | #define LCD_REG_COLOR_2 0x0D // gray scale palette 2 (0,1) | |
| 56 | #define LCD_REG_COLOR_3 0x0E // gray scale palette 3 (1,0) | |
| 57 | #define LCD_REG_COLOR_4 0x0F // gray scale palette 4 (1,1) | |
| 58 | #define LCD_REG_CONTRAST 0x10 // contrast control register | |
| 59 | #define LCD_REG_PLANE 0x11 // plane selection register | |
| 60 | ||
| 61 | //************************************************************************** | |
| 62 | // GLOBAL VARIABLES | |
| 63 | //************************************************************************** | |
| 64 | ||
| 65 | // devices | |
| 66 | const device_type HD66421 = &device_creator<hd66421_device>; | |
| 67 | ||
| 68 | ||
| 69 | // default address map | |
| 70 | static ADDRESS_MAP_START( hd66421, AS_0, 8, hd66421_device ) | |
| 71 | AM_RANGE(0x0000, HD66421_RAM_SIZE) AM_RAM | |
| 72 | ADDRESS_MAP_END | |
| 73 | ||
| 74 | //------------------------------------------------- | |
| 75 | // memory_space_config - return a description of | |
| 76 | // any address spaces owned by this device | |
| 77 | //------------------------------------------------- | |
| 78 | ||
| 79 | const address_space_config *hd66421_device::memory_space_config(address_spacenum spacenum) const | |
| 80 | { | |
| 81 | return (spacenum == AS_0) ? &m_space_config : NULL; | |
| 82 | } | |
| 83 | ||
| 84 | ||
| 85 | //************************************************************************** | |
| 86 | // INLINE HELPERS | |
| 87 | //************************************************************************** | |
| 88 | ||
| 89 | //------------------------------------------------- | |
| 90 | // readbyte - read a byte at the given address | |
| 91 | //------------------------------------------------- | |
| 92 | ||
| 93 | inline UINT8 hd66421_device::readbyte(offs_t address) | |
| 94 | { | |
| 95 | return space().read_byte(address); | |
| 96 | } | |
| 97 | ||
| 98 | ||
| 99 | //------------------------------------------------- | |
| 100 | // writebyte - write a byte at the given address | |
| 101 | //------------------------------------------------- | |
| 102 | ||
| 103 | inline void hd66421_device::writebyte(offs_t address, UINT8 data) | |
| 104 | { | |
| 105 | space().write_byte(address, data); | |
| 106 | } | |
| 107 | ||
| 108 | ||
| 109 | //************************************************************************** | |
| 110 | // LIVE DEVICE | |
| 111 | //************************************************************************** | |
| 112 | ||
| 113 | //------------------------------------------------- | |
| 114 | // hd66421_device - constructor | |
| 115 | //------------------------------------------------- | |
| 116 | ||
| 117 | hd66421_device::hd66421_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) | |
| 118 | : device_t(mconfig, HD66421, "Hitachi HD66421 LCD Controller", tag, owner, clock), | |
| 119 | device_memory_interface(mconfig, *this), | |
| 120 | m_space_config("videoram", ENDIANNESS_LITTLE, 8, 17, 0, NULL, *ADDRESS_MAP_NAME(hd66421)), | |
| 121 | m_cmd(0), | |
| 122 | m_x(0), | |
| 123 | m_y(0) | |
| 124 | { | |
| 125 | for (int i = 0; i < 32; i++) | |
| 126 | { | |
| 127 | m_reg[i] = 0; | |
| 128 | } | |
| 129 | } | |
| 130 | ||
| 131 | ||
| 132 | //------------------------------------------------- | |
| 133 | // device_start - device-specific startup | |
| 134 | //------------------------------------------------- | |
| 135 | ||
| 136 | void hd66421_device::device_start() | |
| 137 | { | |
| 138 | // register for state saving | |
| 139 | save_item(NAME(m_cmd)); | |
| 140 | save_item(NAME(m_reg)); | |
| 141 | save_item(NAME(m_x)); | |
| 142 | save_item(NAME(m_y)); | |
| 143 | } | |
| 144 | ||
| 145 | READ8_MEMBER( hd66421_device::reg_idx_r ) | |
| 146 | { | |
| 147 | _logerror( 2, ("reg_idx_r\n")); | |
| 148 | return m_cmd; | |
| 149 | } | |
| 150 | ||
| 151 | WRITE8_MEMBER( hd66421_device::reg_idx_w ) | |
| 152 | { | |
| 153 | _logerror( 2, ("reg_idx_w (%02X)\n", data)); | |
| 154 | m_cmd = data; | |
| 155 | } | |
| 156 | ||
| 157 | READ8_MEMBER( hd66421_device::reg_dat_r ) | |
| 158 | { | |
| 159 | _logerror( 2, ("reg_dat_r\n")); | |
| 160 | return m_reg[m_cmd]; | |
| 161 | } | |
| 162 | ||
| 163 | WRITE8_MEMBER( hd66421_device::reg_dat_w ) | |
| 164 | { | |
| 165 | _logerror( 2, ("reg_dat_w (%02X)\n", data)); | |
| 166 | m_reg[m_cmd] = data; | |
| 167 | ||
| 168 | switch (m_cmd) | |
| 169 | { | |
| 170 | case LCD_REG_ADDR_X : | |
| 171 | m_x = data; | |
| 172 | break; | |
| 173 | ||
| 174 | case LCD_REG_ADDR_Y : | |
| 175 | m_y = data; | |
| 176 | break; | |
| 177 | ||
| 178 | case LCD_REG_RAM : | |
| 179 | { | |
| 180 | UINT8 r1; | |
| 181 | writebyte(m_y * (HD66421_WIDTH / 4) + m_x, data); | |
| 182 | r1 = m_reg[LCD_REG_CONTROL_2]; | |
| 183 | if (r1 & 0x02) | |
| 184 | m_x++; | |
| 185 | else | |
| 186 | m_y++; | |
| 187 | ||
| 188 | if (m_x >= (HD66421_WIDTH / 4)) | |
| 189 | { | |
| 190 | m_x = 0; | |
| 191 | m_y++; | |
| 192 | } | |
| 193 | ||
| 194 | if (m_y >= HD66421_HEIGHT) | |
| 195 | m_y = 0; | |
| 196 | } | |
| 197 | break; | |
| 198 | } | |
| 199 | } | |
| 200 | ||
| 201 | void hd66421_device::plot_pixel(bitmap_ind16 &bitmap, int x, int y, UINT32 color) | |
| 202 | { | |
| 203 | bitmap.pix16(y, x) = (UINT16)color; | |
| 204 | } | |
| 205 | ||
| 206 | UINT32 hd66421_device::update_screen(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) | |
| 207 | { | |
| 208 | pen_t pen[4]; | |
| 209 | ||
| 210 | _logerror( 1, ("video_update_hd66421\n")); | |
| 211 | ||
| 212 | // update palette | |
| 213 | for (int i = 0; i < 4; i++) | |
| 214 | { | |
| 215 | double bright; | |
| 216 | int temp; | |
| 217 | temp = 31 - (m_reg[LCD_REG_COLOR_1 + i] - m_reg[LCD_REG_CONTRAST] + 0x03); | |
| 218 | if (temp < 0) temp = 0; | |
| 219 | if (temp > 31) temp = 31; | |
| 220 | bright = 1.0 * temp / 31; | |
| 221 | pen[i] = i; | |
| 222 | #ifdef HD66421_BRIGHTNESS_DOES_NOT_WORK | |
| 223 | palette_set_color(machine(), pen[i], 255 * bright, 255 * bright, 255 * bright); | |
| 224 | #else | |
| 225 | palette_set_pen_contrast(machine(), pen[i], bright); | |
| 226 | #endif | |
| 227 | } | |
| 228 | ||
| 229 | // draw bitmap (bottom to top) | |
| 230 | if (m_reg[0] & LCD_R0_DISP) | |
| 231 | { | |
| 232 | int x, y; | |
| 233 | x = 0; | |
| 234 | y = HD66421_HEIGHT - 1; | |
| 235 | ||
| 236 | for (int i = 0; i < HD66421_RAM_SIZE; i++) | |
| 237 | { | |
| 238 | plot_pixel(bitmap, x++, y, pen[(readbyte(i) >> 6) & 3]); | |
| 239 | plot_pixel(bitmap, x++, y, pen[(readbyte(i) >> 4) & 3]); | |
| 240 | plot_pixel(bitmap, x++, y, pen[(readbyte(i) >> 2) & 3]); | |
| 241 | plot_pixel(bitmap, x++, y, pen[(readbyte(i) >> 0) & 3]); | |
| 242 | if (x >= HD66421_WIDTH) | |
| 243 | { | |
| 244 | x = 0; | |
| 245 | y = y - 1; | |
| 246 | } | |
| 247 | } | |
| 248 | } | |
| 249 | else | |
| 250 | { | |
| 251 | rectangle rect(0, HD66421_WIDTH - 1, 0, HD66421_HEIGHT - 1); | |
| 252 | bitmap.fill(get_white_pen(machine()), rect); | |
| 253 | } | |
| 254 | ||
| 255 | return 0; | |
| 256 | } |
| Added: svn:eol-style + native Added: svn:mime-type + text/plain |
| r0 | r21685 | |
|---|---|---|
| 1 | /*************************************************************************** | |
| 2 | ||
| 3 | Hitachi HD66421 LCD Controller | |
| 4 | ||
| 5 | (c) 2001-2007 Tim Schuerewegen | |
| 6 | ||
| 7 | ***************************************************************************/ | |
| 8 | ||
| 9 | #pragma once | |
| 10 | ||
| 11 | #ifndef __HD66421_H__ | |
| 12 | #define __HD66421_H__ | |
| 13 | ||
| 14 | ||
| 15 | ///************************************************************************* | |
| 16 | // MACROS / CONSTANTS | |
| 17 | ///************************************************************************* | |
| 18 | ||
| 19 | //#define HD66421_BRIGHTNESS_DOES_NOT_WORK | |
| 20 | ||
| 21 | #define HD66421_WIDTH 160 | |
| 22 | #define HD66421_HEIGHT 100 | |
| 23 | ||
| 24 | ||
| 25 | /*----------- defined in video/hd66421.c -----------*/ | |
| 26 | ||
| 27 | ///************************************************************************* | |
| 28 | // INTERFACE CONFIGURATION MACROS | |
| 29 | ///************************************************************************* | |
| 30 | ||
| 31 | #define MCFG_HD66421_ADD(_tag) \ | |
| 32 | MCFG_DEVICE_ADD(_tag, HD66421, 0) | |
| 33 | ||
| 34 | ///************************************************************************* | |
| 35 | // TYPE DEFINITIONS | |
| 36 | ///************************************************************************* | |
| 37 | ||
| 38 | // ======================> hd66421_device | |
| 39 | ||
| 40 | class hd66421_device : public device_t, | |
| 41 | public device_memory_interface | |
| 42 | { | |
| 43 | public: | |
| 44 | // construction/destruction | |
| 45 | hd66421_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); | |
| 46 | ||
| 47 | DECLARE_READ8_MEMBER( reg_idx_r ); | |
| 48 | DECLARE_WRITE8_MEMBER( reg_idx_w ); | |
| 49 | DECLARE_READ8_MEMBER( reg_dat_r ); | |
| 50 | DECLARE_WRITE8_MEMBER( reg_dat_w ); | |
| 51 | ||
| 52 | UINT32 update_screen(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); | |
| 53 | ||
| 54 | protected: | |
| 55 | // device-level overrides | |
| 56 | virtual void device_start(); | |
| 57 | ||
| 58 | // device_config_memory_interface overrides | |
| 59 | virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; | |
| 60 | ||
| 61 | // address space configurations | |
| 62 | const address_space_config m_space_config; | |
| 63 | ||
| 64 | inline UINT8 readbyte(offs_t address); | |
| 65 | inline void writebyte(offs_t address, UINT8 data); | |
| 66 | ||
| 67 | void plot_pixel(bitmap_ind16 &bitmap, int x, int y, UINT32 color); | |
| 68 | ||
| 69 | private: | |
| 70 | UINT8 m_cmd, m_reg[32]; | |
| 71 | int m_x, m_y; | |
| 72 | }; | |
| 73 | ||
| 74 | ||
| 75 | // device type definition | |
| 76 | extern const device_type HD66421; | |
| 77 | ||
| 78 | ||
| 79 | #endif |
| Added: svn:eol-style + native Added: svn:mime-type + text/plain |
| r0 | r21685 | |
|---|---|---|
| 1 | /********************************************************************* | |
| 2 | ||
| 3 | mc6847.c | |
| 4 | ||
| 5 | Implementation of Motorola 6847 video hardware chip | |
| 6 | ||
| 7 | Sources: | |
| 8 | M6847 data sheet | |
| 9 | M6847T1 info from Rainbow magazine (10/1986-12/1986) | |
| 10 | ||
| 11 | ||
| 12 | AG AS INTEXT INV GM2 GM1 GM0 | |
| 13 | -- -- ------ --- --- --- --- | |
| 14 | 0 0 0 0 X X X Internal Alphanumerics | |
| 15 | 0 0 0 1 X X X Internal Alphanumerics Inverted | |
| 16 | 0 0 1 0 X X X External Alphanumerics | |
| 17 | 0 0 1 1 X X X External Alphanumerics Inverted | |
| 18 | 0 1 0 X X X X Semigraphics 4 | |
| 19 | 0 1 1 X X X X Semigraphics 6 | |
| 20 | 1 X X X 0 0 0 Graphics CG1 (64x64x4) (16 bpr) | |
| 21 | 1 X X X 0 0 1 Graphics RG1 (128x64x2) (16 bpr) | |
| 22 | 1 X X X 0 1 0 Graphics CG2 (128x64x4) (32 bpr) | |
| 23 | 1 X X X 0 1 1 Graphics RG2 (128x96x2) (16 bpr) | |
| 24 | 1 X X X 1 0 0 Graphics CG3 (128x96x4) (32 bpr) | |
| 25 | 1 X X X 1 0 1 Graphics RG3 (128x192x2) (16 bpr) | |
| 26 | 1 X X X 1 1 0 Graphics CG6 (128x192x4) (32 bpr) | |
| 27 | 1 X X X 1 1 1 Graphics RG6 (256x192x2) (32 bpr) | |
| 28 | ||
| 29 | Note: The M6847 relies on an external source (typically a 6883 SAM chip) | |
| 30 | to feed it bytes; so the BPR (bytes per row) figures are effectively | |
| 31 | suggestions. Mismatching modes is responsible for the semigraphic modes | |
| 32 | on the CoCo. | |
| 33 | ||
| 34 | Timing: (source Motorola M6847 Manual, experimentation, SockMaster) | |
| 35 | ||
| 36 | Horizontal Sync: Total Period: 228 clock cycles | |
| 37 | @ CLK(0) + DHS_F - falling edge (high to low) | |
| 38 | @ CLK(16.5) + DHS_R - rising edge (low to high) | |
| 39 | @ CLK(42) - left border start | |
| 40 | @ CLK(71.5) - body start | |
| 41 | @ CLK(199.5) - right border start | |
| 42 | @ CLK(228) + DHS_F - falling edge (high to low) | |
| 43 | ... | |
| 44 | ||
| 45 | Field Sync: Total Period 262*228 clock cycles | |
| 46 | @ CLK(0) + DFS_F - falling edge (high to low) | |
| 47 | @ CLK(32*228) + DFS_R - rising edge (low to high) | |
| 48 | @ CLK(262*228) + DFS_F - falling edge (high to low) (262.5 for the M6847Y) | |
| 49 | ||
| 50 | DHS_F: 550ns | |
| 51 | DHS_R: 740ns | |
| 52 | DFS_F: 520ns | |
| 53 | DFS_R: 500ns | |
| 54 | ||
| 55 | The M6847T1 is a later variant of the M6847 chip that implements lower | |
| 56 | case support and some other nifty features. This chip is in the CoCo 2B. | |
| 57 | I have not been able to find a pinout diagram for this chip so I am | |
| 58 | assuming that the extra text modes on the CoCo 2B are activated by the | |
| 59 | GM2-0 pins. This needs to be confirmed. | |
| 60 | ||
| 61 | The MC6847 datasheet states that a scanline is 227.5 clock cycles, | |
| 62 | but experimentation suggests that it is 228. The game "Dragon Fire" | |
| 63 | has a fine tuned loop that runs in 57 clock cycles by the CPU's | |
| 64 | reckoning (228 actual clock cycles) and would not function correctly | |
| 65 | if skew existed. SockMaster has confirmed that scanlines are in | |
| 66 | fact 228 clock cycles. | |
| 67 | ||
| 68 | **********************************************************************/ | |
| 69 | ||
| 70 | ||
| 71 | #include "emu.h" | |
| 72 | #include "video/mc6847.h" | |
| 73 | ||
| 74 | ||
| 75 | //************************************************************************** | |
| 76 | // CONSTANTS | |
| 77 | //************************************************************************** | |
| 78 | ||
| 79 | #define TOP_BORDER 25 | |
| 80 | #define USE_HORIZONTAL_CLIP false | |
| 81 | ||
| 82 | #define TIMER_HSYNC_PERIOD (228) | |
| 83 | #define TIMER_HSYNC_OFF_TIME (10.0) | |
| 84 | #define TIMER_HSYNC_ON_TIME (TIMER_HSYNC_OFF_TIME + 16.5) | |
| 85 | #define TIMER_FSYNC_OFF_TIME (TIMER_HSYNC_PERIOD * TOP_BORDER + TIMER_HSYNC_ON_TIME) | |
| 86 | #define TIMER_FSYNC_ON_TIME (TIMER_HSYNC_PERIOD * (TOP_BORDER + 192) + TIMER_HSYNC_ON_TIME) | |
| 87 | ||
| 88 | #define LOG_SCANLINE 0 | |
| 89 | #define LOG_HSYNC 0 | |
| 90 | #define LOG_FSYNC 1 | |
| 91 | #define LOG_FLUSH 1 | |
| 92 | #define LOG_INPUT 0 | |
| 93 | ||
| 94 | ||
| 95 | const UINT32 mc6847_base_device::s_palette[mc6847_base_device::PALETTE_LENGTH] = | |
| 96 | { | |
| 97 | MAKE_RGB(0x07, 0xff, 0x00), /* GREEN */ | |
| 98 | MAKE_RGB(0xff, 0xff, 0x00), /* YELLOW */ | |
| 99 | MAKE_RGB(0x3b, 0x08, 0xff), /* BLUE */ | |
| 100 | MAKE_RGB(0xcc, 0x00, 0x3b), /* RED */ | |
| 101 | MAKE_RGB(0xff, 0xff, 0xff), /* BUFF */ | |
| 102 | MAKE_RGB(0x07, 0xe3, 0x99), /* CYAN */ | |
| 103 | MAKE_RGB(0xff, 0x1c, 0xff), /* MAGENTA */ | |
| 104 | MAKE_RGB(0xff, 0x81, 0x00), /* ORANGE */ | |
| 105 | ||
| 106 | MAKE_RGB(0x00, 0x00, 0x00), /* BLACK */ | |
| 107 | MAKE_RGB(0x07, 0xff, 0x00), /* GREEN */ | |
| 108 | MAKE_RGB(0x00, 0x00, 0x00), /* BLACK */ | |
| 109 | MAKE_RGB(0xff, 0xff, 0xff), /* BUFF */ | |
| 110 | ||
| 111 | MAKE_RGB(0x00, 0x7c, 0x00), /* ALPHANUMERIC DARK GREEN */ | |
| 112 | MAKE_RGB(0x07, 0xff, 0x00), /* ALPHANUMERIC BRIGHT GREEN */ | |
| 113 | MAKE_RGB(0x91, 0x00, 0x00), /* ALPHANUMERIC DARK ORANGE */ | |
| 114 | MAKE_RGB(0xff, 0x81, 0x00) /* ALPHANUMERIC BRIGHT ORANGE */ | |
| 115 | }; | |
| 116 | ||
| 117 | ||
| 118 | ||
| 119 | //************************************************************************** | |
| 120 | // FRIEND DEVICE | |
| 121 | //************************************************************************** | |
| 122 | ||
| 123 | //------------------------------------------------- | |
| 124 | // ctor | |
| 125 | //------------------------------------------------- | |
| 126 | ||
| 127 | mc6847_friend_device::mc6847_friend_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, | |
| 128 | const UINT8 *fontdata, bool is_mc6847t1, double tpfs, int field_sync_falling_edge_scanline, bool supports_partial_body_scanlines) | |
| 129 | : device_t(mconfig, type, name, tag, owner, clock), | |
| 130 | m_character_map(fontdata, is_mc6847t1) | |
| 131 | { | |
| 132 | m_tpfs = tpfs; | |
| 133 | m_supports_partial_body_scanlines = supports_partial_body_scanlines; | |
| 134 | ||
| 135 | // The MC6847 and the GIME apply field sync on different scanlines | |
| 136 | m_field_sync_falling_edge_scanline = field_sync_falling_edge_scanline; | |
| 137 | } | |
| 138 | ||
| 139 | ||
| 140 | ||
| 141 | //------------------------------------------------- | |
| 142 | // setup_timer - sets up a single timer relative | |
| 143 | // to the clock | |
| 144 | //------------------------------------------------- | |
| 145 | ||
| 146 | ATTR_FORCE_INLINE emu_timer *mc6847_friend_device::setup_timer(device_timer_id id, double offset, double period) | |
| 147 | { | |
| 148 | emu_timer *timer = timer_alloc(id); | |
| 149 | timer->adjust( | |
| 150 | attotime::from_ticks(offset * 4, m_clock * 4), | |
| 151 | 0, | |
| 152 | attotime::from_ticks(period * 4, m_clock * 4)); | |
| 153 | return timer; | |
| 154 | } | |
| 155 | ||
| 156 | ||
| 157 | ||
| 158 | //------------------------------------------------- | |
| 159 | // device_start - device-specific startup | |
| 160 | //------------------------------------------------- | |
| 161 | ||
| 162 | void mc6847_friend_device::device_start(void) | |
| 163 | { | |
| 164 | /* create the timers */ | |
| 165 | m_frame_timer = setup_timer( TIMER_FRAME, 0, m_tpfs * TIMER_HSYNC_PERIOD); | |
| 166 | m_hsync_on_timer = setup_timer( TIMER_HSYNC_ON, TIMER_HSYNC_ON_TIME, TIMER_HSYNC_PERIOD); | |
| 167 | m_hsync_off_timer = setup_timer(TIMER_HSYNC_OFF, TIMER_HSYNC_OFF_TIME, TIMER_HSYNC_PERIOD); | |
| 168 | m_fsync_timer = timer_alloc(TIMER_FSYNC); | |
| 169 | ||
| 170 | m_top_border_scanlines = 0; | |
| 171 | m_body_scanlines = 0; | |
| 172 | m_wide = false; | |
| 173 | m_recording_scanline = false; | |
| 174 | m_physical_scanline = 0; | |
| 175 | m_logical_scanline_zone = 0; | |
| 176 | m_field_sync = false; | |
| 177 | m_horizontal_sync = false; | |
| 178 | set_geometry(25, 192, false); | |
| 179 | ||
| 180 | /* save states */ | |
| 181 | save_item(NAME(m_physical_scanline)); | |
| 182 | save_item(NAME(m_logical_scanline)); | |
| 183 | save_item(NAME(m_logical_scanline_zone)); | |
| 184 | save_item(NAME(m_horizontal_sync)); | |
| 185 | save_item(NAME(m_field_sync)); | |
| 186 | ||
| 187 | /* artifacting */ | |
| 188 | m_artifacter.setup_config(this); | |
| 189 | } | |
| 190 | ||
| 191 | ||
| 192 | ||
| 193 | //------------------------------------------------- | |
| 194 | // device_start - device-specific reset | |
| 195 | //------------------------------------------------- | |
| 196 | ||
| 197 | void mc6847_friend_device::device_reset(void) | |
| 198 | { | |
| 199 | device_t::device_reset(); | |
| 200 | m_video_changed = true; | |
| 201 | } | |
| 202 | ||
| 203 | ||
| 204 | ||
| 205 | //------------------------------------------------- | |
| 206 | // device_post_load - device-specific post load | |
| 207 | //------------------------------------------------- | |
| 208 | ||
| 209 | void mc6847_friend_device::device_post_load(void) | |
| 210 | { | |
| 211 | device_t::device_post_load(); | |
| 212 | m_video_changed = true; | |
| 213 | } | |
| 214 | ||
| 215 | ||
| 216 | ||
| 217 | //------------------------------------------------- | |
| 218 | // update_field_sync_timer | |
| 219 | //------------------------------------------------- | |
| 220 | ||
| 221 | void mc6847_friend_device::update_field_sync_timer(void) | |
| 222 | { | |
| 223 | /* are we expecting field sync? */ | |
| 224 | bool expected_field_sync = (m_physical_scanline < m_field_sync_falling_edge_scanline) | |
| 225 | || (m_logical_scanline_zone == SCANLINE_ZONE_VBLANK); | |
| 226 | ||
| 227 | /* determine the duration */ | |
| 228 | attotime duration = (expected_field_sync != m_field_sync) ? attotime::from_ticks(160, m_clock) : attotime::never; | |
| 229 | ||
| 230 | /* and reset the timer */ | |
| 231 | m_fsync_timer->adjust(duration, expected_field_sync ? 1 : 0); | |
| 232 | } | |
| 233 | ||
| 234 | ||
| 235 | ||
| 236 | //------------------------------------------------- | |
| 237 | // device_timer | |
| 238 | //------------------------------------------------- | |
| 239 | ||
| 240 | void mc6847_friend_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) | |
| 241 | { | |
| 242 | switch(id) | |
| 243 | { | |
| 244 | case TIMER_FRAME: new_frame(); break; | |
| 245 | case TIMER_HSYNC_ON: change_horizontal_sync(true); break; | |
| 246 | case TIMER_HSYNC_OFF: change_horizontal_sync(false); break; | |
| 247 | case TIMER_FSYNC: change_field_sync(param != 0); break; | |
| 248 | } | |
| 249 | } | |
| 250 | ||
| 251 | ||
| 252 | ||
| 253 | //------------------------------------------------- | |
| 254 | // new_frame | |
| 255 | //------------------------------------------------- | |
| 256 | ||
| 257 | ATTR_FORCE_INLINE void mc6847_friend_device::new_frame(void) | |
| 258 | { | |
| 259 | m_physical_scanline = 0; | |
| 260 | m_logical_scanline = 0; | |
| 261 | m_logical_scanline_zone = SCANLINE_ZONE_FRAME_END; | |
| 262 | } | |
| 263 | ||
| 264 | ||
| 265 | ||
| 266 | //------------------------------------------------- | |
| 267 | // scanline_zone_string | |
| 268 | //------------------------------------------------- | |
| 269 | ||
| 270 | const char *mc6847_friend_device::scanline_zone_string(scanline_zone zone) | |
| 271 | { | |
| 272 | const char *result; | |
| 273 | switch(zone) | |
| 274 | { | |
| 275 | case SCANLINE_ZONE_TOP_BORDER: result = "SCANLINE_ZONE_TOP_BORDER"; break; | |
| 276 | case SCANLINE_ZONE_BODY: result = "SCANLINE_ZONE_BODY"; break; | |
| 277 | case SCANLINE_ZONE_BOTTOM_BORDER: result = "SCANLINE_ZONE_BOTTOM_BORDER"; break; | |
| 278 | case SCANLINE_ZONE_RETRACE: result = "SCANLINE_ZONE_RETRACE"; break; | |
| 279 | case SCANLINE_ZONE_VBLANK: result = "SCANLINE_ZONE_VBLANK"; break; | |
| 280 | case SCANLINE_ZONE_FRAME_END: result = "SCANLINE_ZONE_FRAME_END"; break; | |
| 281 | default: | |
| 282 | fatalerror("Should not get here\n"); | |
| 283 | break; | |
| 284 | } | |
| 285 | return result; | |
| 286 | } | |
| 287 | ||
| 288 | ||
| 289 | ||
| 290 | //------------------------------------------------- | |
| 291 | // change_horizontal_sync | |
| 292 | //------------------------------------------------- | |
| 293 | ||
| 294 | ATTR_FORCE_INLINE void mc6847_friend_device::change_horizontal_sync(bool line) | |
| 295 | { | |
| 296 | g_profiler.start(PROFILER_USER1); | |
| 297 | if (line && !m_horizontal_sync) | |
| 298 | { | |
| 299 | if (LOG_SCANLINE) | |
| 300 | logerror("%s: change_horizontal_sync(): Recording scanline\n", describe_context()); | |
| 301 | ||
| 302 | /* first store the scanline */ | |
| 303 | g_profiler.start(PROFILER_USER2); | |
| 304 | switch((scanline_zone) m_logical_scanline_zone) | |
| 305 | { | |
| 306 | case SCANLINE_ZONE_TOP_BORDER: | |
| 307 | case SCANLINE_ZONE_BOTTOM_BORDER: | |
| 308 | record_border_scanline(m_physical_scanline); | |
| 309 | break; | |
| 310 | ||
| 311 | case SCANLINE_ZONE_BODY: | |
| 312 | m_recording_scanline = true; | |
| 313 | if (m_partial_scanline_clocks > 0) | |
| 314 | record_partial_body_scanline(m_physical_scanline, m_logical_scanline, m_partial_scanline_clocks, 228); | |
| 315 | else | |
| 316 | record_body_scanline(m_physical_scanline, m_logical_scanline); | |
| 317 | m_recording_scanline = false; | |
| 318 | break; | |
| 319 | ||
| 320 | case SCANLINE_ZONE_RETRACE: | |
| 321 | case SCANLINE_ZONE_VBLANK: | |
| 322 | case SCANLINE_ZONE_FRAME_END: | |
| 323 | /* do nothing */ | |
| 324 | break; | |
| 325 | } | |
| 326 | g_profiler.stop(); | |
| 327 | ||
| 328 | /* advance to next scanline */ | |
| 329 | next_scanline(); | |
| 330 | } | |
| 331 | ||
| 332 | /* finally output horizontal sync */ | |
| 333 | if (line != m_horizontal_sync) | |
| 334 | { | |
| 335 | m_horizontal_sync = line; | |
| 336 | ||
| 337 | /* log if apprpriate */ | |
| 338 | if (LOG_HSYNC) | |
| 339 | logerror("%s: change_horizontal_sync(): line=%d\n", describe_context(), line ? 1 : 0); | |
| 340 | ||
| 341 | /* invoke callback */ | |
| 342 | if (!m_res_out_hsync_func.isnull()) | |
| 343 | m_res_out_hsync_func(line); | |
| 344 | ||
| 345 | /* call virtual function */ | |
| 346 | horizontal_sync_changed(m_horizontal_sync); | |
| 347 | } | |
| 348 | ||
| 349 | /* and update the field sync timer */ | |
| 350 | update_field_sync_timer(); | |
| 351 | g_profiler.stop(); | |
| 352 | } | |
| 353 | ||
| 354 | ||
| 355 | ||
| 356 | //------------------------------------------------- | |
| 357 | // change_field_sync | |
| 358 | //------------------------------------------------- | |
| 359 | ||
| 360 | ATTR_FORCE_INLINE void mc6847_friend_device::change_field_sync(bool line) | |
| 361 | { | |
| 362 | /* output field sync */ | |
| 363 | if (line != m_field_sync) | |
| 364 | { | |
| 365 | m_field_sync = line; | |
| 366 | ||
| 367 | /* log if apprpriate */ | |
| 368 | if (LOG_FSYNC) | |
| 369 | logerror("%s: change_field_sync(): line=%d\n", describe_context(), line ? 1 : 0); | |
| 370 | ||
| 371 | /* invoke callback */ | |
| 372 | if (!m_res_out_fsync_func.isnull()) | |
| 373 | m_res_out_fsync_func(line); | |
| 374 | ||
| 375 | /* call virtual function */ | |
| 376 | field_sync_changed(m_field_sync); | |
| 377 | } | |
| 378 | } | |
| 379 | ||
| 380 | ||
| 381 | ||
| 382 | //------------------------------------------------- | |
| 383 | // next_scanline | |
| 384 | //------------------------------------------------- | |
| 385 | ||
| 386 | ATTR_FORCE_INLINE void mc6847_friend_device::next_scanline(void) | |
| 387 | { | |
| 388 | /* advance to next scanline */ | |
| 389 | m_physical_scanline++; | |
| 390 | m_logical_scanline++; | |
| 391 | m_partial_scanline_clocks = 0; | |
| 392 | ||
| 393 | /* check for movement into the next "zone" */ | |
| 394 | if (m_logical_scanline_zone == SCANLINE_ZONE_FRAME_END) | |
| 395 | { | |
| 396 | /* we're now in the top border */ | |
| 397 | m_logical_scanline = 0; | |
| 398 | m_logical_scanline_zone = SCANLINE_ZONE_TOP_BORDER; | |
| 399 | } | |
| 400 | else if ((m_logical_scanline_zone < SCANLINE_ZONE_VBLANK) && (m_physical_scanline >= 25+192+26+6)) | |
| 401 | { | |
| 402 | /* we're now into vblank */ | |
| 403 | m_logical_scanline = 0; | |
| 404 | m_logical_scanline_zone = SCANLINE_ZONE_VBLANK; | |
| 405 | } | |
| 406 | else if ((m_logical_scanline_zone < SCANLINE_ZONE_RETRACE) && (m_physical_scanline >= 25+192+26)) | |
| 407 | { | |
| 408 | /* we're now into retrace */ | |
| 409 | m_logical_scanline = 0; | |
| 410 | m_logical_scanline_zone = SCANLINE_ZONE_RETRACE; | |
| 411 | } | |
| 412 | else if ((m_logical_scanline_zone == SCANLINE_ZONE_TOP_BORDER) && (m_logical_scanline >= m_top_border_scanlines)) | |
| 413 | { | |
| 414 | /* we're now into the body */ | |
| 415 | m_logical_scanline = 0; | |
| 416 | m_logical_scanline_zone = SCANLINE_ZONE_BODY; | |
| 417 | } | |
| 418 | else if ((m_logical_scanline_zone == SCANLINE_ZONE_BODY) && (m_logical_scanline >= m_body_scanlines)) | |
| 419 | { | |
| 420 | /* we're now into the bottom border */ | |
| 421 | m_logical_scanline = 0; | |
| 422 | m_logical_scanline_zone = SCANLINE_ZONE_BOTTOM_BORDER; | |
| 423 | enter_bottom_border(); | |
| 424 | } | |
| 425 | } | |
| 426 | ||
| 427 | ||
| 428 | ||
| 429 | //------------------------------------------------- | |
| 430 | // horizontal_sync_changed | |
| 431 | //------------------------------------------------- | |
| 432 | ||
| 433 | void mc6847_friend_device::horizontal_sync_changed(bool line) | |
| 434 | { | |
| 435 | } | |
| 436 | ||
| 437 | ||
| 438 | ||
| 439 | //------------------------------------------------- | |
| 440 | // field_sync_changed | |
| 441 | //------------------------------------------------- | |
| 442 | ||
| 443 | void mc6847_friend_device::field_sync_changed(bool line) | |
| 444 | { | |
| 445 | } | |
| 446 | ||
| 447 | ||
| 448 | ||
| 449 | //------------------------------------------------- | |
| 450 | // enter_bottom_border | |
| 451 | //------------------------------------------------- | |
| 452 | ||
| 453 | void mc6847_friend_device::enter_bottom_border(void) | |
| 454 | { | |
| 455 | } | |
| 456 | ||
| 457 | ||
| 458 | ||
| 459 | //------------------------------------------------- | |
| 460 | // record_border_scanline | |
| 461 | //------------------------------------------------- | |
| 462 | ||
| 463 | void mc6847_friend_device::record_border_scanline(UINT16 physical_scanline) | |
| 464 | { | |
| 465 | } | |
| 466 | ||
| 467 | ||
| 468 | ||
| 469 | //------------------------------------------------- | |
| 470 | // get_clocks_since_hsync | |
| 471 | //------------------------------------------------- | |
| 472 | ||
| 473 | INT32 mc6847_friend_device::get_clocks_since_hsync() | |
| 474 | { | |
| 475 | UINT64 hsync_on_clocks = attotime_to_clocks(m_hsync_on_timer->start()); | |
| 476 | UINT64 current_clocks = attotime_to_clocks(machine().time()); | |
| 477 | return (INT32) (current_clocks - hsync_on_clocks); | |
| 478 | } | |
| 479 | ||
| 480 | ||
| 481 | ||
| 482 | //------------------------------------------------- | |
| 483 | // video_flush | |
| 484 | //------------------------------------------------- | |
| 485 | ||
| 486 | void mc6847_friend_device::video_flush() | |
| 487 | { | |
| 488 | // first, only flush if... | |
| 489 | // 1. We support partial scanlines | |
| 490 | // 2. We're not already recording | |
| 491 | // 3. We're in the body | |
| 492 | if (m_supports_partial_body_scanlines && !m_recording_scanline && (m_logical_scanline_zone == SCANLINE_ZONE_BODY)) | |
| 493 | { | |
| 494 | UINT32 new_partial_scanline_clocks = get_clocks_since_hsync(); | |
| 495 | if (m_partial_scanline_clocks < new_partial_scanline_clocks) | |
| 496 | { | |
| 497 | if (LOG_FLUSH) | |
| 498 | logerror("%s: new_partial_scanline_clocks=%u\n", describe_context(), new_partial_scanline_clocks); | |
| 499 | ||
| 500 | m_recording_scanline = true; | |
| 501 | record_partial_body_scanline(m_physical_scanline, m_logical_scanline, m_partial_scanline_clocks, new_partial_scanline_clocks); | |
| 502 | m_recording_scanline = false; | |
| 503 | ||
| 504 | m_partial_scanline_clocks = new_partial_scanline_clocks; | |
| 505 | } | |
| 506 | } | |
| 507 | } | |
| 508 | ||
| 509 | ||
| 510 | ||
| 511 | //------------------------------------------------- | |
| 512 | // describe_context | |
| 513 | //------------------------------------------------- | |
| 514 | ||
| 515 | const char *mc6847_friend_device::describe_context(void) | |
| 516 | { | |
| 517 | static char buffer[128]; | |
| 518 | snprintf(buffer, ARRAY_LENGTH(buffer), "%s (scanline %s:%d)", | |
| 519 | machine().describe_context(), | |
| 520 | scanline_zone_string((scanline_zone) m_logical_scanline_zone), | |
| 521 | m_logical_scanline); | |
| 522 | return buffer; | |
| 523 | } | |
| 524 | ||
| 525 | ||
| 526 | ||
| 527 | //************************************************************************** | |
| 528 | // BASE DEVICE | |
| 529 | //************************************************************************** | |
| 530 | ||
| 531 | //------------------------------------------------- | |
| 532 | // ctor | |
| 533 | //------------------------------------------------- | |
| 534 | ||
| 535 | mc6847_base_device::mc6847_base_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const UINT8 *fontdata, double tpfs) | |
| 536 | : mc6847_friend_device(mconfig, type, name, tag, owner, clock, fontdata, (type == MC6847T1_NTSC) || (type == MC6847T1_PAL), tpfs, 25+191, true) | |
| 537 | { | |
| 538 | m_palette = s_palette; | |
| 539 | ||
| 540 | for (int i = 0; i < ARRAY_LENGTH(s_palette); i++) | |
| 541 | { | |
| 542 | m_bw_palette[i] = black_and_white(s_palette[i]); | |
| 543 | } | |
| 544 | } | |
| 545 | ||
| 546 | ||
| 547 | ||
| 548 | //------------------------------------------------- | |
| 549 | // setup_fixed_mode - sets up a particular video | |
| 550 | // mode bit with a decb callback | |
| 551 | //------------------------------------------------- | |
| 552 | ||
| 553 | void mc6847_base_device::setup_fixed_mode(struct devcb_read_line callback, UINT8 mode) | |
| 554 | { | |
| 555 | if (callback.type == DEVCB_TYPE_NULL) | |
| 556 | { | |
| 557 | // do nothing | |
| 558 | } | |
| 559 | else if (callback.type == DEVCB_TYPE_CONSTANT && (callback.index == 0 || callback.index == 1)) | |
| 560 | { | |
| 561 | // this mode is fixed | |
| 562 | m_fixed_mode |= (callback.index ? mode : 0x00); | |
| 563 | m_fixed_mode_mask |= mode; | |
| 564 | } | |
| 565 | else | |
| 566 | { | |
| 567 | // for reasons of performance, we currently only support DEVCB_NULL, | |
| 568 | // DEVCB_LINE_GND and DEVCB_LINE_VCC | |
| 569 | emu_fatalerror("mc6847 does not support this callback type for mode bits\n"); | |
| 570 | } | |
| 571 | } | |
| 572 | ||
| 573 | ||
| 574 | ||
| 575 | //------------------------------------------------- | |
| 576 | // device_start - device-specific startup | |
| 577 | //------------------------------------------------- | |
| 578 | ||
| 579 | void mc6847_base_device::device_start() | |
| 580 | { | |
| 581 | const mc6847_interface *config = (const mc6847_interface *) static_config(); | |
| 582 | assert(config); | |
| 583 | ||
| 584 | /* inherited function */ | |
| 585 | mc6847_friend_device::device_start(); | |
| 586 | ||
| 587 | /* setup */ | |
| 588 | memset(m_data, 0, sizeof(m_data)); | |
| 589 | ||
| 590 | /* resolve callbacks */ | |
| 591 | m_res_input_func.resolve(config->m_input_func, *this); | |
| 592 | m_res_out_hsync_func.resolve(config->m_out_hsync_func, *this); | |
| 593 | m_res_out_fsync_func.resolve(config->m_out_fsync_func, *this); | |
| 594 | m_get_char_rom = config->m_get_char_rom; | |
| 595 | ||
| 596 | /* set up fixed mode */ | |
| 597 | m_fixed_mode = 0x00; | |
| 598 | m_fixed_mode_mask = 0x00; | |
| 599 | setup_fixed_mode(config->m_in_gm2_func, MODE_GM2); | |
| 600 | setup_fixed_mode(config->m_in_gm1_func, MODE_GM1); | |
| 601 | setup_fixed_mode(config->m_in_gm0_func, MODE_GM0); | |
| 602 | setup_fixed_mode(config->m_in_intext_func, MODE_INTEXT); | |
| 603 | setup_fixed_mode(config->m_in_inv_func, MODE_INV); | |
| 604 | setup_fixed_mode(config->m_in_as_func, MODE_AS); | |
| 605 | setup_fixed_mode(config->m_in_ag_func, MODE_AG); | |
| 606 | setup_fixed_mode(config->m_in_css_func, MODE_CSS); | |
| 607 | ||
| 608 | m_dirty = false; | |
| 609 | ||
| 610 | /* state save */ | |
| 611 | save_item(NAME(m_dirty)); | |
| 612 | save_item(NAME(m_mode)); | |
| 613 | ||
| 614 | /* colors */ | |
| 615 | m_palette = config->m_black_and_white ? m_bw_palette : s_palette; | |
| 616 | } | |
| 617 | ||
| 618 | ||
| 619 | ||
| 620 | //------------------------------------------------- | |
| 621 | // device_reset - device-specific reset | |
| 622 | //------------------------------------------------- | |
| 623 | ||
| 624 | void mc6847_base_device::device_reset() | |
| 625 | { | |
| 626 | mc6847_friend_device::device_reset(); | |
| 627 | m_mode = m_fixed_mode; | |
| 628 | } | |
| 629 | ||
| 630 | ||
| 631 | ||
| 632 | //------------------------------------------------- | |
| 633 | // input | |
| 634 | //------------------------------------------------- | |
| 635 | ||
| 636 | UINT8 mc6847_base_device::input(UINT16 address) | |
| 637 | { | |
| 638 | UINT8 data = m_res_input_func(address); | |
| 639 | if (LOG_INPUT) | |
| 640 | logerror("%s: input: address=0x%04X data=0x%02X\n", describe_context(), address, data); | |
| 641 | return data; | |
| 642 | } | |
| 643 | ||
| 644 | ||
| 645 | ||
| 646 | //------------------------------------------------- | |
| 647 | // record_scanline_res | |
| 648 | //------------------------------------------------- | |
| 649 | ||
| 650 | template<int sample_count, int yres> | |
| 651 | void mc6847_base_device::record_scanline_res(int scanline, INT32 start_pos, INT32 end_pos) | |
| 652 | { | |
| 653 | UINT8 current_sample_count = (start_pos > 0) ? m_data[scanline].m_sample_count : 0; | |
| 654 | ||
| 655 | // main loop | |
| 656 | for (INT32 pos = start_pos; pos < end_pos; pos++) | |
| 657 | { | |
| 658 | // set address at beginning of line | |
| 659 | if (pos == 0) | |
| 660 | m_video_address = scanline / (192 / yres) * sample_count; | |
| 661 | ||
| 662 | if ((sample_count == 32) || ((pos % 1) == 0)) | |
| 663 | { | |
| 664 | // input data | |
| 665 | UINT8 data = input(m_video_address++); | |
| 666 | ||
| 667 | if (pos < 32) | |
| 668 | { | |
| 669 | // update values | |
| 670 | //assert(current_sample_count >= 0); | |
| 671 | assert(current_sample_count < ARRAY_LENGTH(m_data[scanline].m_mode)); | |
| 672 | update_value(&m_data[scanline].m_mode[current_sample_count], simplify_mode(data, m_mode)); | |
| 673 | update_value(&m_data[scanline].m_data[current_sample_count], data); | |
| 674 | current_sample_count++; | |
| 675 | } | |
| 676 | } | |
| 677 | } | |
| 678 | ||
| 679 | // update sample count | |
| 680 | update_value(&m_data[scanline].m_sample_count, current_sample_count); | |
| 681 | } | |
| 682 | ||
| 683 | ||
| 684 | ||
| 685 | //------------------------------------------------- | |
| 686 | // record_body_scanline | |
| 687 | //------------------------------------------------- | |
| 688 | ||
| 689 | ATTR_FORCE_INLINE void mc6847_base_device::record_body_scanline(UINT16 physical_scanline, UINT16 scanline, INT32 start_pos, INT32 end_pos) | |
| 690 | { | |
| 691 | // sanity checks | |
| 692 | assert(scanline < 192); | |
| 693 | ||
| 694 | if (m_mode & MODE_AG) | |
| 695 | { | |
| 696 | switch(m_mode & (MODE_GM2|MODE_GM1|MODE_GM0)) | |
| 697 | { | |
| 698 | case 0: | |
| 699 | case MODE_GM0: | |
| 700 | record_scanline_res<16, 64>(scanline, start_pos, end_pos); | |
| 701 | break; | |
| 702 | ||
| 703 | case MODE_GM1: | |
| 704 | record_scanline_res<32, 64>(scanline, start_pos, end_pos); | |
| 705 | break; | |
| 706 | ||
| 707 | case MODE_GM1|MODE_GM0: | |
| 708 | record_scanline_res<16, 96>(scanline, start_pos, end_pos); | |
| 709 | break; | |
| 710 | ||
| 711 | case MODE_GM2: | |
| 712 | record_scanline_res<32, 96>(scanline, start_pos, end_pos); | |
| 713 | break; | |
| 714 | ||
| 715 | case MODE_GM2|MODE_GM0: | |
| 716 | record_scanline_res<16, 192>(scanline, start_pos, end_pos); | |
| 717 | break; | |
| 718 | ||
| 719 | case MODE_GM2|MODE_GM1: | |
| 720 | case MODE_GM2|MODE_GM1|MODE_GM0: | |
| 721 | record_scanline_res<32, 192>(scanline, start_pos, end_pos); | |
| 722 | break; | |
| 723 | ||
| 724 | default: | |
| 725 | /* should not get here */ | |
| 726 | fatalerror("should not get here\n"); | |
| 727 | break; | |
| 728 | } | |
| 729 | } | |
| 730 | else | |
| 731 | { | |
| 732 | record_scanline_res<32, 16>(scanline, start_pos, end_pos); | |
| 733 | } | |
| 734 | } | |
| 735 | ||
| 736 | ||
| 737 | ||
| 738 | //------------------------------------------------- | |
| 739 | // record_body_scanline | |
| 740 | //------------------------------------------------- | |
| 741 | ||
| 742 | void mc6847_base_device::record_body_scanline(UINT16 physical_scanline, UINT16 scanline) | |
| 743 | { | |
| 744 | record_body_scanline(physical_scanline, scanline, 0, 32); | |
| 745 | } | |
| 746 | ||
| 747 | ||
| 748 | ||
| 749 | //------------------------------------------------- | |
| 750 | // record_partial_body_scanline | |
| 751 | //------------------------------------------------- | |
| 752 | ||
| 753 | void mc6847_base_device::record_partial_body_scanline(UINT16 physical_scanline, UINT16 scanline, INT32 start_clock, INT32 end_clock) | |
| 754 | { | |
| 755 | INT32 start_pos = MAX(scanline_position_from_clock(start_clock), 0); | |
| 756 | INT32 end_pos = MIN(scanline_position_from_clock(end_clock), 42); | |
| 757 | ||
| 758 | if (start_pos < end_pos) | |
| 759 | record_body_scanline(physical_scanline, scanline, start_pos, end_pos); | |
| 760 | } | |
| 761 | ||
| 762 | ||
| 763 | ||
| 764 | //------------------------------------------------- | |
| 765 | // scanline_position_from_clock | |
| 766 | //------------------------------------------------- | |
| 767 | ||
| 768 | INT32 mc6847_base_device::scanline_position_from_clock(INT32 clocks_since_hsync) | |
| 769 | { | |
| 770 | return (clocks_since_hsync - 20) / 4; | |
| 771 | } | |
| 772 | ||
| 773 | ||
| 774 | ||
| 775 | //------------------------------------------------- | |
| 776 | // field_sync_changed | |
| 777 | //------------------------------------------------- | |
| 778 | ||
| 779 | void mc6847_base_device::field_sync_changed(bool line) | |
| 780 | { | |
| 781 | /* when field sync is on, the DA* enter the Hi-Z state */ | |
| 782 | if (line && !m_res_input_func.isnull()) | |
| 783 | m_res_input_func(~0); | |
| 784 | } | |
| 785 | ||
| 786 | ||
| 787 | ||
| 788 | //------------------------------------------------- | |
| 789 | // border_value | |
| 790 | //------------------------------------------------- | |
| 791 | ||
| 792 | ATTR_FORCE_INLINE mc6847_base_device::pixel_t mc6847_base_device::border_value(UINT8 mode, const pixel_t *palette, bool is_mc6847t1) | |
| 793 | { | |
| 794 | pixel_t result; | |
| 795 | switch(mc6847_friend_device::border_value(mode, is_mc6847t1)) | |
| 796 | { | |
| 797 | case BORDER_COLOR_BLACK: | |
| 798 | result = palette[8]; | |
| 799 | break; | |
| 800 | case BORDER_COLOR_GREEN: | |
| 801 | result = palette[0]; | |
| 802 | break; | |
| 803 | case BORDER_COLOR_WHITE: | |
| 804 | result = palette[4]; | |
| 805 | break; | |
| 806 | case BORDER_COLOR_ORANGE: | |
| 807 | result = palette[7]; | |
| 808 | break; | |
| 809 | default: | |
| 810 | fatalerror("Should not get here\n"); | |
| 811 | break; | |
| 812 | } | |
| 813 | return result; | |
| 814 | } | |
| 815 | ||
| 816 | ||
| 817 | ||
| 818 | //------------------------------------------------- | |
| 819 | // update | |
| 820 | //------------------------------------------------- | |
| 821 | ||
| 822 | UINT32 mc6847_base_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) | |
| 823 | { | |
| 824 | int base_x = 32; | |
| 825 | int base_y = 25; | |
| 826 | int x, x2, y; | |
| 827 | bool is_mc6847t1 = (type() == MC6847T1_NTSC) || (type() == MC6847T1_PAL); | |
| 828 | int min_x = USE_HORIZONTAL_CLIP ? cliprect.min_x : 0; | |
| 829 | int max_x = USE_HORIZONTAL_CLIP ? cliprect.max_x : (base_x * 2 + 256 - 1); | |
| 830 | int min_y = cliprect.min_y; | |
| 831 | int max_y = cliprect.max_y; | |
| 832 | const pixel_t *palette = m_palette; | |
| 833 | ||
| 834 | /* if the video didn't change, indicate as much */ | |
| 835 | if (!has_video_changed()) | |
| 836 | return UPDATE_HAS_NOT_CHANGED; | |
| 837 | ||
| 838 | /* top border */ | |
| 839 | for (y = min_y; y < base_y; y++) | |
| 840 | { | |
| 841 | for (x = min_x; x <= max_x; x++) | |
| 842 | { | |
| 843 | *bitmap_addr(bitmap, y, x) = border_value(m_data[0].m_mode[0], palette, is_mc6847t1); | |
| 844 | } | |
| 845 | } | |
| 846 | ||
| 847 | for (y = MAX(0, min_y - base_y); y <= MIN(192, max_y - base_y); y++) | |
| 848 | { | |
| 849 | /* left border */ | |
| 850 | for (x = min_x; x < base_x; x++) | |
| 851 | { | |
| 852 | *bitmap_addr(bitmap, y + base_y, x) = border_value(m_data[y].m_mode[0], palette, is_mc6847t1); | |
| 853 | } | |
| 854 | ||
| 855 | /* body */ | |
| 856 | x = 0; | |
| 857 | int width = m_data[y].m_sample_count; | |
| 858 | pixel_t *RESTRICT pixels = bitmap_addr(bitmap, base_y + y, base_x); | |
| 859 | while(x < width) | |
| 860 | { | |
| 861 | /* determine how many bytes exist for which the mode is identical */ | |
| 862 | for (x2 = x + 1; (x2 < width) && (m_data[y].m_mode[x] == m_data[y].m_mode[x2]); x2++) | |
| 863 | ; | |
| 864 | ||
| 865 | /* emit the samples */ | |
| 866 | pixels += emit_mc6847_samples<1>( | |
| 867 | m_data[y].m_mode[x], | |
| 868 | &m_data[y].m_data[x], | |
| 869 | x2 - x, | |
| 870 | pixels, | |
| 871 | m_palette, | |
| 872 | m_get_char_rom, | |
| 873 | x, | |
| 874 | y); | |
| 875 | ||
| 876 | /* update x */ | |
| 877 | x = x2; | |
| 878 | } | |
| 879 | ||
| 880 | /* right border */ | |
| 881 | for (x = base_x + 256; x <= max_x; x++) | |
| 882 | { | |
| 883 | *bitmap_addr(bitmap, y + base_y, x) = border_value(m_data[y].m_mode[width - 1], palette, is_mc6847t1); | |
| 884 | } | |
| 885 | ||
| 886 | /* artifacting */ | |
| 887 | m_artifacter.process_artifacts<1>(bitmap_addr(bitmap, y + base_y, base_x), m_data[y].m_mode[0], palette); | |
| 888 | } | |
| 889 | ||
| 890 | /* bottom border */ | |
| 891 | for (y = base_y + 192; y <= max_y; y++) | |
| 892 | { | |
| 893 | for (x = min_x; x <= max_x; x++) | |
| 894 | { | |
| 895 | int width = m_data[191].m_sample_count; | |
| 896 | *bitmap_addr(bitmap, y, x) = border_value(m_data[191].m_mode[width - 1], palette, is_mc6847t1); | |
| 897 | } | |
| 898 | } | |
| 899 | return 0; | |
| 900 | } | |
| 901 | ||
| 902 | ||
| 903 | ||
| 904 | //************************************************************************** | |
| 905 | // CHARACTER MAP | |
| 906 | //************************************************************************** | |
| 907 | ||
| 908 | mc6847_friend_device::character_map::character_map(const UINT8 *text_fontdata, bool is_mc6847t1) | |
| 909 | { | |
| 910 | int mode, i; | |
| 911 | ||
| 912 | // set up font data | |
| 913 | for (i = 0; i < 64*12; i++) | |
| 914 | { | |
| 915 | m_text_fontdata_inverse[i] = text_fontdata[i] ^ 0xFF; | |
| 916 | m_text_fontdata_lower_case[i] = text_fontdata[i + (i < 32*12 ? 64*12 : 0)] ^ (i < 32*12 ? 0xFF : 0x00); | |
| 917 | m_text_fontdata_lower_case_inverse[i] = m_text_fontdata_lower_case[i] ^ 0xFF; | |
| 918 | } | |
| 919 | ||
| 920 | // loop through all modes | |
| 921 | for (mode = 0; mode < sizeof(m_entries) / sizeof(m_entries[0]); mode++) | |
| 922 | { | |
| 923 | const UINT8 *fontdata; | |
| 924 | UINT8 character_mask; | |
| 925 | UINT8 color_shift_0 = 0; | |
| 926 | UINT8 color_shift_1 = 0; | |
| 927 | UINT8 color_mask_0 = 0x00; | |
| 928 | UINT8 color_mask_1 = 0x00; | |
| 929 | UINT16 color_base_0; | |
| 930 | UINT16 color_base_1; | |
| 931 | ||
| 932 | if ((mode & MODE_INTEXT) && !is_mc6847t1) | |
| 933 | { | |
| 934 | // semigraphics 6 | |
| 935 | fontdata = semigraphics6_fontdata8x12; | |
| 936 | character_mask = 0x3F; | |
| 937 | color_base_0 = 8; | |
| 938 | color_base_1 = mode & MODE_CSS ? 4 : 0; | |
| 939 | color_shift_1 = 6; | |
| 940 | color_mask_1 = 0x03; | |
| 941 | } | |
| 942 | else if (mode & MODE_AS) | |
| 943 | { | |
| 944 | // semigraphics 4 | |
| 945 | fontdata = semigraphics4_fontdata8x12; | |
| 946 | character_mask = 0x0F; | |
| 947 | color_base_0 = 8; | |
| 948 | color_base_1 = 0; | |
| 949 | color_shift_1 = 4; | |
| 950 | color_mask_1 = 0x07; | |
| 951 | } | |
| 952 | else | |
| 953 | { | |
| 954 | // text | |
| 955 | bool is_lower_case = is_mc6847t1 && ((mode & MODE_INV) == 0) && (mode & MODE_GM0); | |
| 956 | bool is_inverse1 = (mode & MODE_INV) ? true : false; | |
| 957 | bool is_inverse2 = is_mc6847t1 && (mode & MODE_GM1); | |
| 958 | bool is_inverse = (is_inverse1 && !is_inverse2) || (!is_inverse1 && is_inverse2); | |
| 959 | fontdata = is_inverse | |
| 960 | ? (is_lower_case ? m_text_fontdata_lower_case_inverse : m_text_fontdata_inverse) | |
| 961 | : (is_lower_case ? m_text_fontdata_lower_case : text_fontdata); | |
| 962 | character_mask = 0x3F; | |
| 963 | color_base_0 = (mode & MODE_CSS ? 14 : 12); | |
| 964 | color_base_1 = (mode & MODE_CSS ? 15 : 13); | |
| 965 | } | |
| 966 | ||
| 967 | // populate the entry | |
| 968 | memset(&m_entries[mode], 0, sizeof(m_entries[mode])); | |
| 969 | m_entries[mode].m_fontdata = fontdata; | |
| 970 | m_entries[mode].m_character_mask = character_mask; | |
| 971 | m_entries[mode].m_color_shift_0 = color_shift_0; | |
| 972 | m_entries[mode].m_color_shift_1 = color_shift_1; | |
| 973 | m_entries[mode].m_color_mask_0 = color_mask_0; | |
| 974 | m_entries[mode].m_color_mask_1 = color_mask_1; | |
| 975 | m_entries[mode].m_color_base_0 = color_base_0; | |
| 976 | m_entries[mode].m_color_base_1 = color_base_1; | |
| 977 | } | |
| 978 | } | |
| 979 | ||
| 980 | ||
| 981 | ||
| 982 | //------------------------------------------------- | |
| 983 | // pal_round_fontdata8x12 | |
| 984 | //------------------------------------------------- | |
| 985 | ||
| 986 | const UINT8 mc6847_friend_device::pal_round_fontdata8x12[] = | |
| 987 | { | |
| 988 | 0x00, 0x00, 0x38, 0x44, 0x04, 0x34, 0x4C, 0x4C, 0x38, 0x00, 0x00, 0x00, | |
| 989 | 0x00, 0x00, 0x10, 0x28, 0x44, 0x44, 0x7C, 0x44, 0x44, 0x00, 0x00, 0x00, | |
| 990 | 0x00, 0x00, 0x78, 0x24, 0x24, 0x38, 0x24, 0x24, 0x78, 0x00, 0x00, 0x00, | |
| 991 | 0x00, 0x00, 0x38, 0x44, 0x40, 0x40, 0x40, 0x44, 0x38, 0x00, 0x00, 0x00, | |
| 992 | 0x00, 0x00, 0x78, 0x24, 0x24, 0x24, 0x24, 0x24, 0x78, 0x00, 0x00, 0x00, | |
| 993 | 0x00, 0x00, 0x7C, 0x40, 0x40, 0x70, 0x40, 0x40, 0x7C, 0x00, 0x00, 0x00, | |
| 994 | 0x00, 0x00, 0x7C, 0x40, 0x40, 0x70, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, | |
| 995 | 0x00, 0x00, 0x38, 0x44, 0x40, 0x40, 0x4C, 0x44, 0x38, 0x00, 0x00, 0x00, | |
| 996 | 0x00, 0x00, 0x44, 0x44, 0x44, 0x7C, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00, | |
| 997 | 0x00, 0x00, 0x38, 0x10, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00, 0x00, 0x00, | |
| 998 | 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x44, 0x38, 0x00, 0x00, 0x00, | |
| 999 | 0x00, 0x00, 0x44, 0x48, 0x50, 0x60, 0x50, 0x48, 0x44, 0x00, 0x00, 0x00, | |
| 1000 | 0x00, 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x7C, 0x00, 0x00, 0x00, | |
| 1001 | 0x00, 0x00, 0x44, 0x6C, 0x54, 0x54, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00, | |
| 1002 | 0x00, 0x00, 0x44, 0x44, 0x64, 0x54, 0x4C, 0x44, 0x44, 0x00, 0x00, 0x00, | |
| 1003 | 0x00, 0x00, 0x38, 0x44, 0x44, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, | |
| 1004 | 0x00, 0x00, 0x78, 0x44, 0x44, 0x78, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, | |
| 1005 | 0x00, 0x00, 0x38, 0x44, 0x44, 0x44, 0x54, 0x48, 0x34, 0x00, 0x00, 0x00, | |
| 1006 | 0x00, 0x00, 0x78, 0x44, 0x44, 0x78, 0x50, 0x48, 0x44, 0x00, 0x00, 0x00, | |
| 1007 | 0x00, 0x00, 0x38, 0x44, 0x40, 0x38, 0x04, 0x44, 0x38, 0x00, 0x00, 0x00, | |
| 1008 | 0x00, 0x00, 0x7C, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, | |
| 1009 | 0x00, 0x00, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, | |
| 1010 | 0x00, 0x00, 0x44, 0x44, 0x44, 0x28, 0x28, 0x10, 0x10, 0x00, 0x00, 0x00, | |
| 1011 | 0x00, 0x00, 0x44, 0x44, 0x44, 0x44, 0x54, 0x6C, 0x44, 0x00, 0x00, 0x00, | |
| 1012 | 0x00, 0x00, 0x44, 0x44, 0x28, 0x10, 0x28, 0x44, 0x44, 0x00, 0x00, 0x00, | |
| 1013 | 0x00, 0x00, 0x44, 0x44, 0x28, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, | |
| 1014 | 0x00, 0x00, 0x7C, 0x04, 0x08, 0x10, 0x20, 0x40, 0x7C, 0x00, 0x00, 0x00, | |
| 1015 | 0x00, 0x00, 0x38, 0x20, 0x20, 0x20, 0x20, 0x20, 0x38, 0x00, 0x00, 0x00, | |
| 1016 | 0x00, 0x00, 0x00, 0x40, 0x20, 0x10, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, | |
| 1017 | 0x00, 0x00, 0x38, 0x08, 0x08, 0x08, 0x08, 0x08, 0x38, 0x00, 0x00, 0x00, | |
| 1018 | 0x00, 0x00, 0x10, 0x38, 0x54, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, | |
| 1019 | 0x00, 0x00, 0x00, 0x10, 0x20, 0x7C, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, | |
| 1020 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 1021 | 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00, | |
| 1022 | 0x00, 0x00, 0x28, 0x28, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 1023 | 0x00, 0x00, 0x28, 0x28, 0x7C, 0x28, 0x7C, 0x28, 0x28, 0x00, 0x00, 0x00, | |
| 1024 | 0x00, 0x00, 0x10, 0x3C, 0x50, 0x38, 0x14, 0x78, 0x10, 0x00, 0x00, 0x00, | |
| 1025 | 0x00, 0x00, 0x60, 0x64, 0x08, 0x10, 0x20, 0x4C, 0x0C, 0x00, 0x00, 0x00, | |
| 1026 | 0x00, 0x00, 0x20, 0x50, 0x50, 0x20, 0x54, 0x48, 0x34, 0x00, 0x00, 0x00, | |
| 1027 | 0x00, 0x00, 0x10, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 1028 | 0x00, 0x00, 0x08, 0x10, 0x20, 0x20, 0x20, 0x10, 0x08, 0x00, 0x00, 0x00, | |
| 1029 | 0x00, 0x00, 0x20, 0x10, 0x08, 0x08, 0x08, 0x10, 0x20, 0x00, 0x00, 0x00, | |
| 1030 | 0x00, 0x00, 0x00, 0x10, 0x54, 0x38, 0x38, 0x54, 0x10, 0x00, 0x00, 0x00, | |
| 1031 | 0x00, 0x00, 0x00, 0x10, 0x10, 0x7C, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, | |
| 1032 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x40, 0x00, 0x00, | |
| 1033 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 1034 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, | |
| 1035 | 0x00, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x40, 0x00, 0x00, 0x00, 0x00, | |
| 1036 | 0x00, 0x00, 0x38, 0x44, 0x4C, 0x54, 0x64, 0x44, 0x38, 0x00, 0x00, 0x00, | |
| 1037 | 0x00, 0x00, 0x10, 0x30, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00, 0x00, 0x00, | |
| 1038 | 0x00, 0x00, 0x38, 0x44, 0x04, 0x38, 0x40, 0x40, 0x7C, 0x00, 0x00, 0x00, | |
| 1039 | 0x00, 0x00, 0x38, 0x44, 0x04, 0x08, 0x04, 0x44, 0x38, 0x00, 0x00, 0x00, | |
| 1040 | 0x00, 0x00, 0x08, 0x18, 0x28, 0x48, 0x7C, 0x08, 0x08, 0x00, 0x00, 0x00, | |
| 1041 | 0x00, 0x00, 0x7C, 0x40, 0x78, 0x04, 0x04, 0x44, 0x38, 0x00, 0x00, 0x00, | |
| 1042 | 0x00, 0x00, 0x38, 0x40, 0x40, 0x78, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, | |
| 1043 | 0x00, 0x00, 0x7C, 0x04, 0x08, 0x10, 0x20, 0x40, 0x40, 0x00, 0x00, 0x00, | |
| 1044 | 0x00, 0x00, 0x38, 0x44, 0x44, 0x38, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, | |
| 1045 | 0x00, 0x00, 0x38, 0x44, 0x44, 0x3C, 0x04, 0x04, 0x38, 0x00, 0x00, 0x00, | |
| 1046 | 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, | |
| 1047 | 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x10, 0x20, 0x00, 0x00, | |
| 1048 | 0x00, 0x00, 0x08, 0x10, 0x20, 0x40, 0x20, 0x10, 0x08, 0x00, 0x00, 0x00, | |
| 1049 | 0x00, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 1050 | 0x00, 0x00, 0x20, 0x10, 0x08, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x00, | |
| 1051 | 0x00, 0x00, 0x38, 0x44, 0x04, 0x08, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00, | |
| 1052 | ||
| 1053 | /* Lower case */ | |
| 1054 | 0x00, 0x00, 0x18, 0x24, 0x20, 0x70, 0x20, 0x24, 0x78, 0x00, 0x00, 0x00, | |
| 1055 | 0x00, 0x00, 0x00, 0x00, 0x38, 0x04, 0x3C, 0x44, 0x3C, 0x00, 0x00, 0x00, | |
| 1056 | 0x00, 0x00, 0x40, 0x40, 0x58, 0x64, 0x44, 0x64, 0x58, 0x00, 0x00, 0x00, | |
| 1057 | 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, 0x40, 0x44, 0x38, 0x00, 0x00, 0x00, | |
| 1058 | 0x00, 0x00, 0x04, 0x04, 0x34, 0x4C, 0x44, 0x4C, 0x34, 0x00, 0x00, 0x00, | |
| 1059 | 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, 0x7C, 0x40, 0x38, 0x00, 0x00, 0x00, | |
| 1060 | 0x00, 0x00, 0x08, 0x14, 0x10, 0x38, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, | |
| 1061 | 0x00, 0x00, 0x00, 0x00, 0x34, 0x4C, 0x44, 0x4C, 0x34, 0x04, 0x38, 0x00, | |
| 1062 | 0x00, 0x00, 0x40, 0x40, 0x58, 0x64, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00, | |
| 1063 | 0x00, 0x00, 0x10, 0x00, 0x30, 0x10, 0x10, 0x10, 0x38, 0x00, 0x00, 0x00, | |
| 1064 | 0x00, 0x00, 0x04, 0x00, 0x04, 0x04, 0x04, 0x04, 0x44, 0x38, 0x00, 0x00, | |
| 1065 | 0x00, 0x00, 0x40, 0x40, 0x48, 0x50, 0x60, 0x50, 0x48, 0x00, 0x00, 0x00, | |
| 1066 | 0x00, 0x00, 0x30, 0x10, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00, 0x00, 0x00, | |
| 1067 | 0x00, 0x00, 0x00, 0x00, 0x78, 0x54, 0x54, 0x54, 0x54, 0x00, 0x00, 0x00, | |
| 1068 | 0x00, 0x00, 0x00, 0x00, 0x58, 0x64, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00, | |
| 1069 | 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, | |
| 1070 | 0x00, 0x00, 0x00, 0x00, 0x78, 0x44, 0x44, 0x44, 0x78, 0x40, 0x40, 0x00, | |
| 1071 | 0x00, 0x00, 0x00, 0x00, 0x3C, 0x44, 0x44, 0x44, 0x3C, 0x04, 0x04, 0x00, | |
| 1072 | 0x00, 0x00, 0x00, 0x00, 0x58, 0x64, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, | |
| 1073 | 0x00, 0x00, 0x00, 0x00, 0x3C, 0x40, 0x38, 0x04, 0x78, 0x00, 0x00, 0x00, | |
| 1074 | 0x00, 0x00, 0x20, 0x20, 0x70, 0x20, 0x20, 0x24, 0x18, 0x00, 0x00, 0x00, | |
| 1075 | 0x00, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x4C, 0x34, 0x00, 0x00, 0x00, | |
| 1076 | 0x00, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x28, 0x10, 0x00, 0x00, 0x00, | |
| 1077 | 0x00, 0x00, 0x00, 0x00, 0x44, 0x54, 0x54, 0x28, 0x28, 0x00, 0x00, 0x00, | |
| 1078 | 0x00, 0x00, 0x00, 0x00, 0x44, 0x28, 0x10, 0x28, 0x44, 0x00, 0x00, 0x00, | |
| 1079 | 0x00, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x3C, 0x04, 0x38, 0x00, 0x00, | |
| 1080 | 0x00, 0x00, 0x00, 0x00, 0x7C, 0x08, 0x10, 0x20, 0x7C, 0x00, 0x00, 0x00, | |
| 1081 | 0x00, 0x00, 0x08, 0x10, 0x10, 0x20, 0x10, 0x10, 0x08, 0x00, 0x00, 0x00, | |
| 1082 | 0x00, 0x00, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, | |
| 1083 | 0x00, 0x00, 0x20, 0x10, 0x10, 0x08, 0x10, 0x10, 0x20, 0x00, 0x00, 0x00, | |
| 1084 | 0x00, 0x00, 0x20, 0x54, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 1085 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00 | |
| 1086 | }; | |
| 1087 | ||
| 1088 | ||
| 1089 | ||
| 1090 | //------------------------------------------------- | |
| 1091 | // pal_square_fontdata8x12 | |
| 1092 | //------------------------------------------------- | |
| 1093 | ||
| 1094 | const UINT8 mc6847_friend_device::pal_square_fontdata8x12[] = | |
| 1095 | { | |
| 1096 | 0x00, 0x00, 0x00, 0x1C, 0x22, 0x02, 0x1A, 0x2A, 0x2A, 0x1C, 0x00, 0x00, | |
| 1097 | 0x00, 0x00, 0x00, 0x08, 0x14, 0x22, 0x22, 0x3E, 0x22, 0x22, 0x00, 0x00, | |
| 1098 | 0x00, 0x00, 0x00, 0x3C, 0x12, 0x12, 0x1C, 0x12, 0x12, 0x3C, 0x00, 0x00, | |
| 1099 | 0x00, 0x00, 0x00, 0x1C, 0x22, 0x20, 0x20, 0x20, 0x22, 0x1C, 0x00, 0x00, | |
| 1100 | 0x00, 0x00, 0x00, 0x3C, 0x12, 0x12, 0x12, 0x12, 0x12, 0x3C, 0x00, 0x00, | |
| 1101 | 0x00, 0x00, 0x00, 0x3E, 0x20, 0x20, 0x3C, 0x20, 0x20, 0x3E, 0x00, 0x00, | |
| 1102 | 0x00, 0x00, 0x00, 0x3E, 0x20, 0x20, 0x3C, 0x20, 0x20, 0x20, 0x00, 0x00, | |
| 1103 | 0x00, 0x00, 0x00, 0x1E, 0x20, 0x20, 0x26, 0x22, 0x22, 0x1E, 0x00, 0x00, | |
| 1104 | 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x3E, 0x22, 0x22, 0x22, 0x00, 0x00, | |
| 1105 | 0x00, 0x00, 0x00, 0x1C, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1C, 0x00, 0x00, | |
| 1106 | 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x22, 0x22, 0x1C, 0x00, 0x00, | |
| 1107 | 0x00, 0x00, 0x00, 0x22, 0x24, 0x28, 0x30, 0x28, 0x24, 0x22, 0x00, 0x00, | |
| 1108 | 0x00, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3E, 0x00, 0x00, | |
| 1109 | 0x00, 0x00, 0x00, 0x22, 0x36, 0x2A, 0x2A, 0x22, 0x22, 0x22, 0x00, 0x00, | |
| 1110 | 0x00, 0x00, 0x00, 0x22, 0x32, 0x2A, 0x26, 0x22, 0x22, 0x22, 0x00, 0x00, | |
| 1111 | 0x00, 0x00, 0x00, 0x3E, 0x22, 0x22, 0x22, 0x22, 0x22, 0x3E, 0x00, 0x00, | |
| 1112 | 0x00, 0x00, 0x00, 0x3C, 0x22, 0x22, 0x3C, 0x20, 0x20, 0x20, 0x00, 0x00, | |
| 1113 | 0x00, 0x00, 0x00, 0x1C, 0x22, 0x22, 0x22, 0x2A, 0x24, 0x1A, 0x00, 0x00, | |
| 1114 | 0x00, 0x00, 0x00, 0x3C, 0x22, 0x22, 0x3C, 0x28, 0x24, 0x22, 0x00, 0x00, | |
| 1115 | 0x00, 0x00, 0x00, 0x1C, 0x22, 0x10, 0x08, 0x04, 0x22, 0x1C, 0x00, 0x00, | |
| 1116 | 0x00, 0x00, 0x00, 0x3E, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, | |
| 1117 | 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x1C, 0x00, 0x00, | |
| 1118 | 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x14, 0x14, 0x08, 0x08, 0x00, 0x00, | |
| 1119 | 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x2A, 0x2A, 0x36, 0x22, 0x00, 0x00, | |
| 1120 | 0x00, 0x00, 0x00, 0x22, 0x22, 0x14, 0x08, 0x14, 0x22, 0x22, 0x00, 0x00, | |
| 1121 | 0x00, 0x00, 0x00, 0x22, 0x22, 0x14, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, | |
| 1122 | 0x00, 0x00, 0x00, 0x3E, 0x02, 0x04, 0x08, 0x10, 0x20, 0x3E, 0x00, 0x00, | |
| 1123 | 0x00, 0x00, 0x00, 0x38, 0x20, 0x20, 0x20, 0x20, 0x20, 0x38, 0x00, 0x00, | |
| 1124 | 0x00, 0x00, 0x00, 0x20, 0x20, 0x10, 0x08, 0x04, 0x02, 0x02, 0x00, 0x00, | |
| 1125 | 0x00, 0x00, 0x00, 0x0E, 0x02, 0x02, 0x02, 0x02, 0x02, 0x0E, 0x00, 0x00, | |
| 1126 | 0x00, 0x00, 0x00, 0x08, 0x1C, 0x2A, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, | |
| 1127 | 0x00, 0x00, 0x00, 0x00, 0x08, 0x10, 0x3E, 0x10, 0x08, 0x00, 0x00, 0x00, | |
| 1128 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 1129 | 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x08, 0x00, 0x00, | |
| 1130 | 0x00, 0x00, 0x00, 0x14, 0x14, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 1131 | 0x00, 0x00, 0x00, 0x14, 0x14, 0x36, 0x00, 0x36, 0x14, 0x14, 0x00, 0x00, | |
| 1132 | 0x00, 0x00, 0x00, 0x08, 0x1E, 0x20, 0x1C, 0x02, 0x3C, 0x08, 0x00, 0x00, | |
| 1133 | 0x00, 0x00, 0x00, 0x32, 0x32, 0x04, 0x08, 0x10, 0x26, 0x26, 0x00, 0x00, | |
| 1134 | 0x00, 0x00, 0x00, 0x10, 0x28, 0x28, 0x10, 0x2A, 0x24, 0x1A, 0x00, 0x00, | |
| 1135 | 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 1136 | 0x00, 0x00, 0x00, 0x08, 0x10, 0x20, 0x20, 0x20, 0x10, 0x08, 0x00, 0x00, | |
| 1137 | 0x00, 0x00, 0x00, 0x08, 0x04, 0x02, 0x02, 0x02, 0x04, 0x08, 0x00, 0x00, | |
| 1138 | 0x00, 0x00, 0x00, 0x00, 0x08, 0x1C, 0x3E, 0x1C, 0x08, 0x00, 0x00, 0x00, | |
| 1139 | 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x3E, 0x08, 0x08, 0x00, 0x00, 0x00, | |
| 1140 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x10, 0x20, 0x00, 0x00, | |
| 1141 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 1142 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, | |
| 1143 | 0x00, 0x00, 0x00, 0x02, 0x02, 0x04, 0x08, 0x10, 0x20, 0x20, 0x00, 0x00, | |
| 1144 | 0x00, 0x00, 0x00, 0x18, 0x24, 0x24, 0x24, 0x24, 0x24, 0x18, 0x00, 0x00, | |
| 1145 | 0x00, 0x00, 0x00, 0x08, 0x18, 0x08, 0x08, 0x08, 0x08, 0x1C, 0x00, 0x00, | |
| 1146 | 0x00, 0x00, 0x00, 0x1C, 0x22, 0x02, 0x1C, 0x20, 0x20, 0x3E, 0x00, 0x00, | |
| 1147 | 0x00, 0x00, 0x00, 0x1C, 0x22, 0x02, 0x0C, 0x02, 0x22, 0x1C, 0x00, 0x00, | |
| 1148 | 0x00, 0x00, 0x00, 0x04, 0x0C, 0x14, 0x3E, 0x04, 0x04, 0x04, 0x00, 0x00, | |
| 1149 | 0x00, 0x00, 0x00, 0x3E, 0x20, 0x3C, 0x02, 0x02, 0x22, 0x1C, 0x00, 0x00, | |
| 1150 | 0x00, 0x00, 0x00, 0x1C, 0x20, 0x20, 0x3C, 0x22, 0x22, 0x1C, 0x00, 0x00, | |
| 1151 | 0x00, 0x00, 0x00, 0x3E, 0x02, 0x04, 0x08, 0x10, 0x20, 0x20, 0x00, 0x00, | |
| 1152 | 0x00, 0x00, 0x00, 0x1C, 0x22, 0x22, 0x1C, 0x22, 0x22, 0x1C, 0x00, 0x00, | |
| 1153 | 0x00, 0x00, 0x00, 0x1C, 0x22, 0x22, 0x1E, 0x02, 0x02, 0x1C, 0x00, 0x00, | |
| 1154 | 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, | |
| 1155 | 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x08, 0x10, 0x00, 0x00, | |
| 1156 | 0x00, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x10, 0x08, 0x04, 0x00, 0x00, | |
| 1157 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, | |
| 1158 | 0x00, 0x00, 0x00, 0x10, 0x08, 0x04, 0x02, 0x04, 0x08, 0x10, 0x00, 0x00, | |
| 1159 | 0x00, 0x00, 0x00, 0x18, 0x24, 0x04, 0x08, 0x08, 0x00, 0x08, 0x00, 0x00, | |
| 1160 | ||
| 1161 | /* Lower case */ | |
| 1162 | 0x00, 0x00, 0x00, 0x0C, 0x12, 0x10, 0x38, 0x10, 0x12, 0x3C, 0x00, 0x00, | |
| 1163 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x02, 0x1E, 0x22, 0x1E, 0x00, 0x00, | |
| 1164 | 0x00, 0x00, 0x00, 0x20, 0x20, 0x3C, 0x22, 0x22, 0x22, 0x3C, 0x00, 0x00, | |
| 1165 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x20, 0x20, 0x20, 0x1C, 0x00, 0x00, | |
| 1166 | 0x00, 0x00, 0x00, 0x02, 0x02, 0x1E, 0x22, 0x22, 0x22, 0x1E, 0x00, 0x00, | |
| 1167 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x22, 0x3E, 0x20, 0x1C, 0x00, 0x00, | |
| 1168 | 0x00, 0x00, 0x00, 0x0C, 0x12, 0x10, 0x38, 0x10, 0x10, 0x10, 0x00, 0x00, | |
| 1169 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x22, 0x22, 0x22, 0x1E, 0x02, 0x1C, | |
| 1170 | 0x00, 0x00, 0x00, 0x20, 0x20, 0x3C, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, | |
| 1171 | 0x00, 0x00, 0x00, 0x08, 0x00, 0x18, 0x08, 0x08, 0x08, 0x1C, 0x00, 0x00, | |
| 1172 | 0x00, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x04, 0x04, 0x04, 0x04, 0x24, 0x18, | |
| 1173 | 0x00, 0x00, 0x00, 0x20, 0x20, 0x24, 0x28, 0x38, 0x24, 0x22, 0x00, 0x00, | |
| 1174 | 0x00, 0x00, 0x00, 0x18, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1C, 0x00, 0x00, | |
| 1175 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x2A, 0x2A, 0x2A, 0x2A, 0x00, 0x00, | |
| 1176 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x2C, 0x32, 0x22, 0x22, 0x22, 0x00, 0x00, | |
| 1177 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x22, 0x22, 0x22, 0x1C, 0x00, 0x00, | |
| 1178 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x22, 0x22, 0x22, 0x3C, 0x20, 0x20, | |
| 1179 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x22, 0x22, 0x22, 0x1E, 0x02, 0x03, | |
| 1180 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x2C, 0x32, 0x20, 0x20, 0x20, 0x00, 0x00, | |
| 1181 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x20, 0x1C, 0x02, 0x3C, 0x00, 0x00, | |
| 1182 | 0x00, 0x00, 0x00, 0x10, 0x3C, 0x10, 0x10, 0x10, 0x12, 0x0C, 0x00, 0x00, | |
| 1183 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x26, 0x1A, 0x00, 0x00, | |
| 1184 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x14, 0x14, 0x08, 0x00, 0x00, | |
| 1185 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x2A, 0x2A, 0x1C, 0x14, 0x00, 0x00, | |
| 1186 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x14, 0x08, 0x14, 0x22, 0x00, 0x00, | |
| 1187 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x1E, 0x02, 0x1C, | |
| 1188 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x04, 0x08, 0x10, 0x3E, 0x00, 0x00, | |
| 1189 | 0x00, 0x00, 0x00, 0x08, 0x10, 0x10, 0x20, 0x10, 0x10, 0x08, 0x00, 0x00, | |
| 1190 | 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x00, 0x08, 0x08, 0x08, 0x00, 0x00, | |
| 1191 | 0x00, 0x00, 0x00, 0x08, 0x04, 0x04, 0x02, 0x04, 0x04, 0x08, 0x00, 0x00, | |
| 1192 | 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x2A, 0x1C, 0x08, 0x00, 0x00, | |
| 1193 | 0x00, 0x00, 0x00, 0x08, 0x04, 0x3E, 0x04, 0x08, 0x00, 0x00, 0x00, 0x00, | |
| 1194 | }; | |
| 1195 | ||
| 1196 | ||
| 1197 | ||
| 1198 | //------------------------------------------------- | |
| 1199 | // ntsc_round_fontdata8x12 | |
| 1200 | //------------------------------------------------- | |
| 1201 | ||
| 1202 | const UINT8 mc6847_friend_device::ntsc_round_fontdata8x12[] = | |
| 1203 | { | |
| 1204 | 0x00, 0x00, 0x38, 0x44, 0x04, 0x34, 0x4C, 0x4C, 0x38, 0x00, 0x00, 0x00, | |
| 1205 | 0x00, 0x00, 0x10, 0x28, 0x44, 0x44, 0x7C, 0x44, 0x44, 0x00, 0x00, 0x00, | |
| 1206 | 0x00, 0x00, 0x78, 0x24, 0x24, 0x38, 0x24, 0x24, 0x78, 0x00, 0x00, 0x00, | |
| 1207 | 0x00, 0x00, 0x38, 0x44, 0x40, 0x40, 0x40, 0x44, 0x38, 0x00, 0x00, 0x00, | |
| 1208 | 0x00, 0x00, 0x78, 0x24, 0x24, 0x24, 0x24, 0x24, 0x78, 0x00, 0x00, 0x00, | |
| 1209 | 0x00, 0x00, 0x7C, 0x40, 0x40, 0x70, 0x40, 0x40, 0x7C, 0x00, 0x00, 0x00, | |
| 1210 | 0x00, 0x00, 0x7C, 0x40, 0x40, 0x70, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, | |
| 1211 | 0x00, 0x00, 0x38, 0x44, 0x40, 0x40, 0x4C, 0x44, 0x38, 0x00, 0x00, 0x00, | |
| 1212 | 0x00, 0x00, 0x44, 0x44, 0x44, 0x7C, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00, | |
| 1213 | 0x00, 0x00, 0x38, 0x10, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00, 0x00, 0x00, | |
| 1214 | 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x44, 0x38, 0x00, 0x00, 0x00, | |
| 1215 | 0x00, 0x00, 0x44, 0x48, 0x50, 0x60, 0x50, 0x48, 0x44, 0x00, 0x00, 0x00, | |
| 1216 | 0x00, 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x7C, 0x00, 0x00, 0x00, | |
| 1217 | 0x00, 0x00, 0x44, 0x6C, 0x54, 0x54, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00, | |
| 1218 | 0x00, 0x00, 0x44, 0x44, 0x64, 0x54, 0x4C, 0x44, 0x44, 0x00, 0x00, 0x00, | |
| 1219 | 0x00, 0x00, 0x38, 0x44, 0x44, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, | |
| 1220 | 0x00, 0x00, 0x78, 0x44, 0x44, 0x78, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, | |
| 1221 | 0x00, 0x00, 0x38, 0x44, 0x44, 0x44, 0x54, 0x48, 0x34, 0x00, 0x00, 0x00, | |
| 1222 | 0x00, 0x00, 0x78, 0x44, 0x44, 0x78, 0x50, 0x48, 0x44, 0x00, 0x00, 0x00, | |
| 1223 | 0x00, 0x00, 0x38, 0x44, 0x40, 0x38, 0x04, 0x44, 0x38, 0x00, 0x00, 0x00, | |
| 1224 | 0x00, 0x00, 0x7C, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, | |
| 1225 | 0x00, 0x00, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, | |
| 1226 | 0x00, 0x00, 0x44, 0x44, 0x44, 0x28, 0x28, 0x10, 0x10, 0x00, 0x00, 0x00, | |
| 1227 | 0x00, 0x00, 0x44, 0x44, 0x44, 0x44, 0x54, 0x6C, 0x44, 0x00, 0x00, 0x00, | |
| 1228 | 0x00, 0x00, 0x44, 0x44, 0x28, 0x10, 0x28, 0x44, 0x44, 0x00, 0x00, 0x00, | |
| 1229 | 0x00, 0x00, 0x44, 0x44, 0x28, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, | |
| 1230 | 0x00, 0x00, 0x7C, 0x04, 0x08, 0x10, 0x20, 0x40, 0x7C, 0x00, 0x00, 0x00, | |
| 1231 | 0x00, 0x00, 0x38, 0x20, 0x20, 0x20, 0x20, 0x20, 0x38, 0x00, 0x00, 0x00, | |
| 1232 | 0x00, 0x00, 0x00, 0x40, 0x20, 0x10, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, | |
| 1233 | 0x00, 0x00, 0x38, 0x08, 0x08, 0x08, 0x08, 0x08, 0x38, 0x00, 0x00, 0x00, | |
| 1234 | 0x00, 0x00, 0x10, 0x38, 0x54, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, | |
| 1235 | 0x00, 0x00, 0x00, 0x10, 0x20, 0x7C, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, | |
| 1236 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 1237 | 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00, | |
| 1238 | 0x00, 0x00, 0x28, 0x28, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 1239 | 0x00, 0x00, 0x28, 0x28, 0x7C, 0x28, 0x7C, 0x28, 0x28, 0x00, 0x00, 0x00, | |
| 1240 | 0x00, 0x00, 0x10, 0x3C, 0x50, 0x38, 0x14, 0x78, 0x10, 0x00, 0x00, 0x00, | |
| 1241 | 0x00, 0x00, 0x60, 0x64, 0x08, 0x10, 0x20, 0x4C, 0x0C, 0x00, 0x00, 0x00, | |
| 1242 | 0x00, 0x00, 0x20, 0x50, 0x50, 0x20, 0x54, 0x48, 0x34, 0x00, 0x00, 0x00, | |
| 1243 | 0x00, 0x00, 0x10, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 1244 | 0x00, 0x00, 0x08, 0x10, 0x20, 0x20, 0x20, 0x10, 0x08, 0x00, 0x00, 0x00, | |
| 1245 | 0x00, 0x00, 0x20, 0x10, 0x08, 0x08, 0x08, 0x10, 0x20, 0x00, 0x00, 0x00, | |
| 1246 | 0x00, 0x00, 0x00, 0x10, 0x54, 0x38, 0x38, 0x54, 0x10, 0x00, 0x00, 0x00, | |
| 1247 | 0x00, 0x00, 0x00, 0x10, 0x10, 0x7C, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, | |
| 1248 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x40, 0x00, 0x00, | |
| 1249 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 1250 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, | |
| 1251 | 0x00, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x40, 0x00, 0x00, 0x00, 0x00, | |
| 1252 | 0x00, 0x00, 0x38, 0x44, 0x4C, 0x54, 0x64, 0x44, 0x38, 0x00, 0x00, 0x00, | |
| 1253 | 0x00, 0x00, 0x10, 0x30, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00, 0x00, 0x00, | |
| 1254 | 0x00, 0x00, 0x38, 0x44, 0x04, 0x38, 0x40, 0x40, 0x7C, 0x00, 0x00, 0x00, | |
| 1255 | 0x00, 0x00, 0x38, 0x44, 0x04, 0x08, 0x04, 0x44, 0x38, 0x00, 0x00, 0x00, | |
| 1256 | 0x00, 0x00, 0x08, 0x18, 0x28, 0x48, 0x7C, 0x08, 0x08, 0x00, 0x00, 0x00, | |
| 1257 | 0x00, 0x00, 0x7C, 0x40, 0x78, 0x04, 0x04, 0x44, 0x38, 0x00, 0x00, 0x00, | |
| 1258 | 0x00, 0x00, 0x38, 0x40, 0x40, 0x78, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, | |
| 1259 | 0x00, 0x00, 0x7C, 0x04, 0x08, 0x10, 0x20, 0x40, 0x40, 0x00, 0x00, 0x00, | |
| 1260 | 0x00, 0x00, 0x38, 0x44, 0x44, 0x38, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, | |
| 1261 | 0x00, 0x00, 0x38, 0x44, 0x44, 0x3C, 0x04, 0x04, 0x38, 0x00, 0x00, 0x00, | |
| 1262 | 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, | |
| 1263 | 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x10, 0x20, 0x00, 0x00, | |
| 1264 | 0x00, 0x00, 0x08, 0x10, 0x20, 0x40, 0x20, 0x10, 0x08, 0x00, 0x00, 0x00, | |
| 1265 | 0x00, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 1266 | 0x00, 0x00, 0x20, 0x10, 0x08, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x00, | |
| 1267 | 0x00, 0x00, 0x38, 0x44, 0x04, 0x08, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00, | |
| 1268 | ||
| 1269 | /* Lower case */ | |
| 1270 | 0x00, 0x00, 0x10, 0x28, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 1271 | 0x00, 0x00, 0x00, 0x00, 0x38, 0x04, 0x3C, 0x44, 0x3C, 0x00, 0x00, 0x00, | |
| 1272 | 0x00, 0x00, 0x40, 0x40, 0x58, 0x64, 0x44, 0x64, 0x58, 0x00, 0x00, 0x00, | |
| 1273 | 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, 0x40, 0x44, 0x38, 0x00, 0x00, 0x00, | |
| 1274 | 0x00, 0x00, 0x04, 0x04, 0x34, 0x4C, 0x44, 0x4C, 0x34, 0x00, 0x00, 0x00, | |
| 1275 | 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, 0x7C, 0x40, 0x38, 0x00, 0x00, 0x00, | |
| 1276 | 0x00, 0x00, 0x08, 0x14, 0x10, 0x38, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, | |
| 1277 | 0x00, 0x00, 0x00, 0x00, 0x34, 0x4C, 0x44, 0x4C, 0x34, 0x04, 0x38, 0x00, | |
| 1278 | 0x00, 0x00, 0x40, 0x40, 0x58, 0x64, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00, | |
| 1279 | 0x00, 0x00, 0x10, 0x00, 0x30, 0x10, 0x10, 0x10, 0x38, 0x00, 0x00, 0x00, | |
| 1280 | 0x00, 0x00, 0x04, 0x00, 0x04, 0x04, 0x04, 0x04, 0x44, 0x38, 0x00, 0x00, | |
| 1281 | 0x00, 0x00, 0x40, 0x40, 0x48, 0x50, 0x60, 0x50, 0x48, 0x00, 0x00, 0x00, | |
| 1282 | 0x00, 0x00, 0x30, 0x10, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00, 0x00, 0x00, | |
| 1283 | 0x00, 0x00, 0x00, 0x00, 0x78, 0x54, 0x54, 0x54, 0x54, 0x00, 0x00, 0x00, | |
| 1284 | 0x00, 0x00, 0x00, 0x00, 0x58, 0x64, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00, | |
| 1285 | 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, | |
| 1286 | 0x00, 0x00, 0x00, 0x00, 0x78, 0x44, 0x44, 0x44, 0x78, 0x40, 0x40, 0x00, | |
| 1287 | 0x00, 0x00, 0x00, 0x00, 0x3C, 0x44, 0x44, 0x44, 0x3C, 0x04, 0x04, 0x00, | |
| 1288 | 0x00, 0x00, 0x00, 0x00, 0x58, 0x64, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, | |
| 1289 | 0x00, 0x00, 0x00, 0x00, 0x3C, 0x40, 0x38, 0x04, 0x78, 0x00, 0x00, 0x00, | |
| 1290 | 0x00, 0x00, 0x20, 0x20, 0x70, 0x20, 0x20, 0x24, 0x18, 0x00, 0x00, 0x00, | |
| 1291 | 0x00, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x4C, 0x34, 0x00, 0x00, 0x00, | |
| 1292 | 0x00, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x28, 0x10, 0x00, 0x00, 0x00, | |
| 1293 | 0x00, 0x00, 0x00, 0x00, 0x44, 0x54, 0x54, 0x28, 0x28, 0x00, 0x00, 0x00, | |
| 1294 | 0x00, 0x00, 0x00, 0x00, 0x44, 0x28, 0x10, 0x28, 0x44, 0x00, 0x00, 0x00, | |
| 1295 | 0x00, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x3C, 0x04, 0x38, 0x00, 0x00, | |
| 1296 | 0x00, 0x00, 0x00, 0x00, 0x7C, 0x08, 0x10, 0x20, 0x7C, 0x00, 0x00, 0x00, | |
| 1297 | 0x00, 0x00, 0x08, 0x10, 0x10, 0x20, 0x10, 0x10, 0x08, 0x00, 0x00, 0x00, | |
| 1298 | 0x00, 0x00, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, | |
| 1299 | 0x00, 0x00, 0x20, 0x10, 0x10, 0x08, 0x10, 0x10, 0x20, 0x00, 0x00, 0x00, | |
| 1300 | 0x00, 0x00, 0x20, 0x54, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 1301 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00, | |
| 1302 | }; | |
| 1303 | ||
| 1304 | ||
| 1305 | ||
| 1306 | //------------------------------------------------- | |
| 1307 | // ntsc_square_fontdata8x12 | |
| 1308 | //------------------------------------------------- | |
| 1309 | ||
| 1310 | const UINT8 mc6847_friend_device::ntsc_square_fontdata8x12[] = | |
| 1311 | { | |
| 1312 | 0x00, 0x00, 0x00, 0x1C, 0x22, 0x02, 0x1A, 0x2A, 0x2A, 0x1C, 0x00, 0x00, | |
| 1313 | 0x00, 0x00, 0x00, 0x08, 0x14, 0x22, 0x22, 0x3E, 0x22, 0x22, 0x00, 0x00, | |
| 1314 | 0x00, 0x00, 0x00, 0x3C, 0x12, 0x12, 0x1C, 0x12, 0x12, 0x3C, 0x00, 0x00, | |
| 1315 | 0x00, 0x00, 0x00, 0x1C, 0x22, 0x20, 0x20, 0x20, 0x22, 0x1C, 0x00, 0x00, | |
| 1316 | 0x00, 0x00, 0x00, 0x3C, 0x12, 0x12, 0x12, 0x12, 0x12, 0x3C, 0x00, 0x00, | |
| 1317 | 0x00, 0x00, 0x00, 0x3E, 0x20, 0x20, 0x38, 0x20, 0x20, 0x3E, 0x00, 0x00, | |
| 1318 | 0x00, 0x00, 0x00, 0x3E, 0x20, 0x20, 0x38, 0x20, 0x20, 0x20, 0x00, 0x00, | |
| 1319 | 0x00, 0x00, 0x00, 0x1E, 0x20, 0x20, 0x26, 0x22, 0x22, 0x1E, 0x00, 0x00, | |
| 1320 | 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x3E, 0x22, 0x22, 0x22, 0x00, 0x00, | |
| 1321 | 0x00, 0x00, 0x00, 0x1C, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1C, 0x00, 0x00, | |
| 1322 | 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x22, 0x22, 0x1C, 0x00, 0x00, | |
| 1323 | 0x00, 0x00, 0x00, 0x22, 0x24, 0x28, 0x30, 0x28, 0x24, 0x22, 0x00, 0x00, | |
| 1324 | 0x00, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3E, 0x00, 0x00, | |
| 1325 | 0x00, 0x00, 0x00, 0x22, 0x36, 0x2A, 0x2A, 0x22, 0x22, 0x22, 0x00, 0x00, | |
| 1326 | 0x00, 0x00, 0x00, 0x22, 0x32, 0x2A, 0x26, 0x22, 0x22, 0x22, 0x00, 0x00, | |
| 1327 | 0x00, 0x00, 0x00, 0x3E, 0x22, 0x22, 0x22, 0x22, 0x22, 0x3E, 0x00, 0x00, | |
| 1328 | 0x00, 0x00, 0x00, 0x3C, 0x22, 0x22, 0x3C, 0x20, 0x20, 0x20, 0x00, 0x00, | |
| 1329 | 0x00, 0x00, 0x00, 0x1C, 0x22, 0x22, 0x22, 0x2A, 0x24, 0x1A, 0x00, 0x00, | |
| 1330 | 0x00, 0x00, 0x00, 0x3C, 0x22, 0x22, 0x3C, 0x28, 0x24, 0x22, 0x00, 0x00, | |
| 1331 | 0x00, 0x00, 0x00, 0x1C, 0x22, 0x10, 0x08, 0x04, 0x22, 0x1C, 0x00, 0x00, | |
| 1332 | 0x00, 0x00, 0x00, 0x3E, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, | |
| 1333 | 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x1C, 0x00, 0x00, | |
| 1334 | 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x14, 0x14, 0x08, 0x08, 0x00, 0x00, | |
| 1335 | 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x2A, 0x2A, 0x36, 0x22, 0x00, 0x00, | |
| 1336 | 0x00, 0x00, 0x00, 0x22, 0x22, 0x14, 0x08, 0x14, 0x22, 0x22, 0x00, 0x00, | |
| 1337 | 0x00, 0x00, 0x00, 0x22, 0x22, 0x14, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, | |
| 1338 | 0x00, 0x00, 0x00, 0x3E, 0x02, 0x04, 0x08, 0x10, 0x20, 0x3E, 0x00, 0x00, | |
| 1339 | 0x00, 0x00, 0x00, 0x38, 0x20, 0x20, 0x20, 0x20, 0x20, 0x38, 0x00, 0x00, | |
| 1340 | 0x00, 0x00, 0x00, 0x20, 0x20, 0x10, 0x08, 0x04, 0x02, 0x02, 0x00, 0x00, | |
| 1341 | 0x00, 0x00, 0x00, 0x0E, 0x02, 0x02, 0x02, 0x02, 0x02, 0x0E, 0x00, 0x00, | |
| 1342 | 0x00, 0x00, 0x00, 0x08, 0x1C, 0x2A, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, | |
| 1343 | 0x00, 0x00, 0x00, 0x00, 0x08, 0x10, 0x3E, 0x10, 0x08, 0x00, 0x00, 0x00, | |
| 1344 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 1345 | 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x08, 0x00, 0x00, | |
| 1346 | 0x00, 0x00, 0x00, 0x14, 0x14, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 1347 | 0x00, 0x00, 0x00, 0x14, 0x14, 0x36, 0x00, 0x36, 0x14, 0x14, 0x00, 0x00, | |
| 1348 | 0x00, 0x00, 0x00, 0x08, 0x1E, 0x20, 0x1C, 0x02, 0x3C, 0x08, 0x00, 0x00, | |
| 1349 | 0x00, 0x00, 0x00, 0x32, 0x32, 0x04, 0x08, 0x10, 0x26, 0x26, 0x00, 0x00, | |
| 1350 | 0x00, 0x00, 0x00, 0x10, 0x28, 0x28, 0x10, 0x2A, 0x24, 0x1A, 0x00, 0x00, | |
| 1351 | 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 1352 | 0x00, 0x00, 0x00, 0x08, 0x10, 0x20, 0x20, 0x20, 0x10, 0x08, 0x00, 0x00, | |
| 1353 | 0x00, 0x00, 0x00, 0x08, 0x04, 0x02, 0x02, 0x02, 0x04, 0x08, 0x00, 0x00, | |
| 1354 | 0x00, 0x00, 0x00, 0x00, 0x08, 0x1C, 0x3E, 0x1C, 0x08, 0x00, 0x00, 0x00, | |
| 1355 | 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x3E, 0x08, 0x08, 0x00, 0x00, 0x00, | |
| 1356 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x10, 0x20, 0x00, 0x00, | |
| 1357 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 1358 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, | |
| 1359 | 0x00, 0x00, 0x00, 0x02, 0x02, 0x04, 0x08, 0x10, 0x20, 0x20, 0x00, 0x00, | |
| 1360 | 0x00, 0x00, 0x00, 0x18, 0x24, 0x24, 0x24, 0x24, 0x24, 0x18, 0x00, 0x00, | |
| 1361 | 0x00, 0x00, 0x00, 0x08, 0x18, 0x08, 0x08, 0x08, 0x08, 0x1C, 0x00, 0x00, | |
| 1362 | 0x00, 0x00, 0x00, 0x1C, 0x22, 0x02, 0x1C, 0x20, 0x20, 0x3E, 0x00, 0x00, | |
| 1363 | 0x00, 0x00, 0x00, 0x1C, 0x22, 0x02, 0x04, 0x02, 0x22, 0x1C, 0x00, 0x00, | |
| 1364 | 0x00, 0x00, 0x00, 0x04, 0x0C, 0x14, 0x3E, 0x04, 0x04, 0x04, 0x00, 0x00, | |
| 1365 | 0x00, 0x00, 0x00, 0x3E, 0x20, 0x3C, 0x02, 0x02, 0x22, 0x1C, 0x00, 0x00, | |
| 1366 | 0x00, 0x00, 0x00, 0x1C, 0x20, 0x20, 0x3C, 0x22, 0x22, 0x1C, 0x00, 0x00, | |
| 1367 | 0x00, 0x00, 0x00, 0x3E, 0x02, 0x04, 0x08, 0x10, 0x20, 0x20, 0x00, 0x00, | |
| 1368 | 0x00, 0x00, 0x00, 0x1C, 0x22, 0x22, 0x1C, 0x22, 0x22, 0x1C, 0x00, 0x00, | |
| 1369 | 0x00, 0x00, 0x00, 0x1C, 0x22, 0x22, 0x1E, 0x02, 0x02, 0x1C, 0x00, 0x00, | |
| 1370 | 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, | |
| 1371 | 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x08, 0x10, 0x00, 0x00, | |
| 1372 | 0x00, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x10, 0x08, 0x04, 0x00, 0x00, | |
| 1373 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, | |
| 1374 | 0x00, 0x00, 0x00, 0x10, 0x08, 0x04, 0x02, 0x04, 0x08, 0x10, 0x00, 0x00, | |
| 1375 | 0x00, 0x00, 0x00, 0x18, 0x24, 0x04, 0x08, 0x08, 0x00, 0x08, 0x00, 0x00, | |
| 1376 | ||
| 1377 | /* Lower case */ | |
| 1378 | 0x00, 0x00, 0x00, 0x0C, 0x12, 0x10, 0x38, 0x10, 0x12, 0x3C, 0x00, 0x00, | |
| 1379 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x02, 0x1E, 0x22, 0x1E, 0x00, 0x00, | |
| 1380 | 0x00, 0x00, 0x00, 0x20, 0x20, 0x3C, 0x22, 0x22, 0x22, 0x3C, 0x00, 0x00, | |
| 1381 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x20, 0x20, 0x20, 0x1C, 0x00, 0x00, | |
| 1382 | 0x00, 0x00, 0x00, 0x02, 0x02, 0x1E, 0x22, 0x22, 0x22, 0x1E, 0x00, 0x00, | |
| 1383 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x22, 0x3E, 0x20, 0x1C, 0x00, 0x00, | |
| 1384 | 0x00, 0x00, 0x00, 0x0C, 0x12, 0x10, 0x38, 0x10, 0x10, 0x10, 0x00, 0x00, | |
| 1385 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x22, 0x22, 0x22, 0x1E, 0x02, 0x1C, | |
| 1386 | 0x00, 0x00, 0x00, 0x20, 0x20, 0x3C, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, | |
| 1387 | 0x00, 0x00, 0x00, 0x08, 0x00, 0x18, 0x08, 0x08, 0x08, 0x1C, 0x00, 0x00, | |
| 1388 | 0x00, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x04, 0x04, 0x04, 0x04, 0x24, 0x18, | |
| 1389 | 0x00, 0x00, 0x00, 0x20, 0x20, 0x24, 0x28, 0x38, 0x24, 0x22, 0x00, 0x00, | |
| 1390 | 0x00, 0x00, 0x00, 0x18, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1C, 0x00, 0x00, | |
| 1391 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x2A, 0x2A, 0x2A, 0x2A, 0x00, 0x00, | |
| 1392 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x2C, 0x32, 0x22, 0x22, 0x22, 0x00, 0x00, | |
| 1393 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x22, 0x22, 0x22, 0x1C, 0x00, 0x00, | |
| 1394 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x22, 0x22, 0x22, 0x3C, 0x20, 0x20, | |
| 1395 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x22, 0x22, 0x22, 0x1E, 0x02, 0x03, | |
| 1396 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x2C, 0x32, 0x20, 0x20, 0x20, 0x00, 0x00, | |
| 1397 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x20, 0x1C, 0x02, 0x3C, 0x00, 0x00, | |
| 1398 | 0x00, 0x00, 0x00, 0x10, 0x3C, 0x10, 0x10, 0x10, 0x12, 0x0C, 0x00, 0x00, | |
| 1399 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x26, 0x1A, 0x00, 0x00, | |
| 1400 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x14, 0x14, 0x08, 0x00, 0x00, | |
| 1401 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x2A, 0x2A, 0x1C, 0x14, 0x00, 0x00, | |
| 1402 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x14, 0x08, 0x14, 0x22, 0x00, 0x00, | |
| 1403 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x1E, 0x02, 0x1C, | |
| 1404 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x04, 0x08, 0x10, 0x3E, 0x00, 0x00, | |
| 1405 | 0x00, 0x00, 0x00, 0x08, 0x10, 0x10, 0x20, 0x10, 0x10, 0x08, 0x00, 0x00, | |
| 1406 | 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x00, 0x08, 0x08, 0x08, 0x00, 0x00, | |
| 1407 | 0x00, 0x00, 0x00, 0x08, 0x04, 0x04, 0x02, 0x04, 0x04, 0x08, 0x00, 0x00, | |
| 1408 | 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x2A, 0x1C, 0x08, 0x00, 0x00, | |
| 1409 | 0x00, 0x00, 0x00, 0x08, 0x04, 0x3E, 0x04, 0x08, 0x00, 0x00, 0x00, 0x00 | |
| 1410 | }; | |
| 1411 | ||
| 1412 | ||
| 1413 | ||
| 1414 | //------------------------------------------------- | |
| 1415 | // semigraphics4_fontdata8x12 | |
| 1416 | //------------------------------------------------- | |
| 1417 | ||
| 1418 | const UINT8 mc6847_friend_device::semigraphics4_fontdata8x12[] = | |
| 1419 | { | |
| 1420 | /* Block Graphics (Semigraphics 4 Graphics ) */ | |
| 1421 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 1422 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, | |
| 1423 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, | |
| 1424 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, | |
| 1425 | 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 1426 | 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, | |
| 1427 | 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, | |
| 1428 | 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, | |
| 1429 | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 1430 | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, | |
| 1431 | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, | |
| 1432 | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, | |
| 1433 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 1434 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, | |
| 1435 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, | |
| 1436 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF | |
| 1437 | }; | |
| 1438 | ||
| 1439 | ||
| 1440 | ||
| 1441 | //------------------------------------------------- | |
| 1442 | // semigraphics6_fontdata8x12 | |
| 1443 | //------------------------------------------------- | |
| 1444 | ||
| 1445 | const UINT8 mc6847_friend_device::semigraphics6_fontdata8x12[] = | |
| 1446 | { | |
| 1447 | /* Semigraphics 6 */ | |
| 1448 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 1449 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, | |
| 1450 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, | |
| 1451 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, | |
| 1452 | 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, | |
| 1453 | 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, | |
| 1454 | 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, 0xF0, 0xF0, 0xF0, 0xF0, | |
| 1455 | 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, | |
| 1456 | 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00, | |
| 1457 | 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F, | |
| 1458 | 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, | |
| 1459 | 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, | |
| 1460 | 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, | |
| 1461 | 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, | |
| 1462 | 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0, | |
| 1463 | 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, | |
| 1464 | 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 1465 | 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, | |
| 1466 | 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, | |
| 1467 | 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, | |
| 1468 | 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, | |
| 1469 | 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, | |
| 1470 | 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0xF0, 0xF0, 0xF0, 0xF0, | |
| 1471 | 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, | |
| 1472 | 0x0F, 0x0F, 0x0F, 0x0F, 0xF0, 0xF0, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00, | |
| 1473 | 0x0F, 0x0F, 0x0F, 0x0F, 0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F, | |
| 1474 | 0x0F, 0x0F, 0x0F, 0x0F, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, | |
| 1475 | 0x0F, 0x0F, 0x0F, 0x0F, 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, | |
| 1476 | 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, | |
| 1477 | 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, | |
| 1478 | 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0, | |
| 1479 | 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, | |
| 1480 | 0xF0, 0xF0, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 1481 | 0xF0, 0xF0, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, | |
| 1482 | 0xF0, 0xF0, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, | |
| 1483 | 0xF0, 0xF0, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, | |
| 1484 | 0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, | |
| 1485 | 0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, | |
| 1486 | 0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F, 0xF0, 0xF0, 0xF0, 0xF0, | |
| 1487 | 0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, | |
| 1488 | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00, | |
| 1489 | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F, | |
| 1490 | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, | |
| 1491 | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, | |
| 1492 | 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, | |
| 1493 | 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, | |
| 1494 | 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0, | |
| 1495 | 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, | |
| 1496 | 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 1497 | 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, | |
| 1498 | 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, | |
| 1499 | 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, | |
| 1500 | 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, | |
| 1501 | 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, | |
| 1502 | 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, 0xF0, 0xF0, 0xF0, 0xF0, | |
| 1503 | 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, | |
| 1504 | 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00, | |
| 1505 | 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F, | |
| 1506 | 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, | |
| 1507 | 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, | |
| 1508 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, | |
| 1509 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, | |
| 1510 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0, | |
| 1511 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF | |
| 1512 | }; | |
| 1513 | ||
| 1514 | ||
| 1515 | ||
| 1516 | //************************************************************************** | |
| 1517 | // ARTIFACTING | |
| 1518 | //************************************************************************** | |
| 1519 | ||
| 1520 | INPUT_PORTS_START(mc6847_artifacting) | |
| 1521 | PORT_START(ARTIFACTING_TAG) | |
| 1522 | PORT_CONFNAME( 0x03, 0x01, "Artifacting" ) | |
| 1523 | PORT_CONFSETTING( 0x00, DEF_STR( Off ) ) | |
| 1524 | PORT_CONFSETTING( 0x01, DEF_STR( Standard ) ) | |
| 1525 | PORT_CONFSETTING( 0x02, DEF_STR( Reverse ) ) | |
| 1526 | INPUT_PORTS_END | |
| 1527 | ||
| 1528 | ioport_constructor mc6847_base_device::device_input_ports() const | |
| 1529 | { | |
| 1530 | return INPUT_PORTS_NAME(mc6847_artifacting); | |
| 1531 | } | |
| 1532 | ||
| 1533 | ||
| 1534 | ||
| 1535 | //------------------------------------------------- | |
| 1536 | // ctor | |
| 1537 | //------------------------------------------------- | |
| 1538 | ||
| 1539 | mc6847_base_device::artifacter::artifacter() | |
| 1540 | { | |
| 1541 | m_config = NULL; | |
| 1542 | m_artifacting = 0; | |
| 1543 | m_saved_artifacting = 0; | |
| 1544 | m_saved_c0 = 0; | |
| 1545 | m_saved_c1 = 0; | |
| 1546 | memset(m_expanded_colors, 0, sizeof(m_expanded_colors)); | |
| 1547 | } | |
| 1548 | ||
| 1549 | ||
| 1550 | ||
| 1551 | //------------------------------------------------- | |
| 1552 | // artifacter::setup_config | |
| 1553 | //------------------------------------------------- | |
| 1554 | ||
| 1555 | void mc6847_base_device::artifacter::setup_config(device_t *device) | |
| 1556 | { | |
| 1557 | char port_name[32]; | |
| 1558 | snprintf(port_name, ARRAY_LENGTH(port_name), "%s:%s", device->tag(), ARTIFACTING_TAG); | |
| 1559 | m_config = device->ioport(port_name); | |
| 1560 | } | |
| 1561 | ||
| 1562 | ||
| 1563 | ||
| 1564 | //------------------------------------------------- | |
| 1565 | // artifacter::update_colors | |
| 1566 | //------------------------------------------------- | |
| 1567 | ||
| 1568 | void mc6847_base_device::artifacter::update_colors(pixel_t c0, pixel_t c1) | |
| 1569 | { | |
| 1570 | /* Boy this code sucks; this code was adapted from the old M6847 | |
| 1571 | * artifacting implmentation. The only reason that it didn't look as | |
| 1572 | * horrible was because the code around it sucked as well. Now that I | |
| 1573 | * have cleaned everything up, the ugliness is much more prominent. | |
| 1574 | * | |
| 1575 | * Hopefully we will have a generic artifacting algorithm that plugs into | |
| 1576 | * the MESS/MAME core directly so we can chuck this hack */ | |
| 1577 | static const double artifact_colors[14*3] = | |
| 1578 | { | |
| 1579 | 0.157, 0.000, 0.157, /* [ 1] - dk purple (reverse 2) */ | |
| 1580 | 0.000, 0.157, 0.000, /* [ 2] - dk green (reverse 1) */ | |
| 1581 | 1.000, 0.824, 1.000, /* [ 3] - lt purple (reverse 4) */ | |
| 1582 | 0.824, 1.000, 0.824, /* [ 4] - lt green (reverse 3) */ | |
| 1583 | 0.706, 0.236, 0.118, /* [ 5] - dk blue (reverse 6) */ | |
| 1584 | 0.000, 0.197, 0.471, /* [ 6] - dk red (reverse 5) */ | |
| 1585 | 1.000, 0.550, 0.393, /* [ 7] - lt blue (reverse 8) */ | |
| 1586 | 0.275, 0.785, 1.000, /* [ 8] - lt red (reverse 7) */ | |
| 1587 | 0.000, 0.500, 1.000, /* [ 9] - red (reverse 10) */ | |
| 1588 | 1.000, 0.500, 0.000, /* [10] - blue (reverse 9) */ | |
| 1589 | 1.000, 0.942, 0.785, /* [11] - cyan (reverse 12) */ | |
| 1590 | 0.393, 0.942, 1.000, /* [12] - yellow (reverse 11) */ | |
| 1591 | 0.236, 0.000, 0.000, /* [13] - black-blue (reverse 14) */ | |
| 1592 | 0.000, 0.000, 0.236 /* [14] - black-red (reverse 13) */ | |
| 1593 | }; | |
| 1594 | ||
| 1595 | static const UINT8 artifact_correction[128] = | |
| 1596 | { | |
| 1597 | 0, 0, 0, 0, 0, 6, 0, 2, | |
| 1598 | 5, 7, 5, 7, 1, 3, 1, 11, | |
| 1599 | 8, 6, 8, 14, 8, 9, 8, 9, | |
| 1600 | 4, 4, 4, 15, 12, 12, 12, 15, | |
| 1601 | ||
| 1602 | 5, 13, 5, 13, 13, 0, 13, 2, | |
| 1603 | 10, 10, 10, 10, 10, 15, 10, 11, | |
| 1604 | 3, 1, 3, 1, 15, 9, 15, 9, | |
| 1605 | 11, 11, 11, 11, 15, 15, 15, 15, | |
| 1606 | ||
| 1607 | 14, 0, 14, 0, 14, 6, 14, 2, | |
| 1608 | 0, 7, 0, 7, 1, 3, 1, 11, | |
| 1609 | 9, 6, 9, 14, 9, 9, 9, 9, | |
| 1610 | 15, 4, 15, 15, 12, 12, 12, 15, | |
| 1611 | ||
| 1612 | 2, 13, 2, 13, 2, 0, 2, 2, | |
| 1613 | 10, 10, 10, 10, 10, 15, 10, 11, | |
| 1614 | 12, 1, 12, 1, 12, 9, 12, 9, | |
| 1615 | 15, 11, 15, 11, 15, 15, 15, 15 | |
| 1616 | }; | |
| 1617 | ||
| 1618 | pixel_t colors[16]; | |
| 1619 | int i; | |
| 1620 | ||
| 1621 | /* do we need to update our artifact colors table? */ | |
| 1622 | if ((m_artifacting != m_saved_artifacting) || (c0 != m_saved_c0) || (c1 != m_saved_c1)) | |
| 1623 | { | |
| 1624 | m_saved_artifacting = m_artifacting; | |
| 1625 | m_saved_c0 = colors[0] = c0; | |
| 1626 | m_saved_c1 = colors[15] = c1; | |
| 1627 | ||
| 1628 | /* mix the other colors */ | |
| 1629 | for (i = 1; i <= 14; i++) | |
| 1630 | { | |
| 1631 | const double *factors = &artifact_colors[((i - 1) ^ (m_artifacting & 0x01)) * 3]; | |
| 1632 | ||
| 1633 | colors[i] = (mix_color(factors[0], c0 >> 16, c1 >> 16) << 16) | |
| 1634 | | (mix_color(factors[1], c0 >> 8, c1 >> 8) << 8) | |
| 1635 | | (mix_color(factors[2], c0 >> 0, c1 >> 0) << 0); | |
| 1636 | } | |
| 1637 | for (i = 0; i < 128; i++) | |
| 1638 | { | |
| 1639 | m_expanded_colors[i] = colors[artifact_correction[i]]; | |
| 1640 | } | |
| 1641 | } | |
| 1642 | } | |
| 1643 | ||
| 1644 | ||
| 1645 | ||
| 1646 | //------------------------------------------------- | |
| 1647 | // artifacter::update | |
| 1648 | //------------------------------------------------- | |
| 1649 | ||
| 1650 | mc6847_base_device::pixel_t mc6847_base_device::artifacter::mix_color(double factor, UINT8 c0, UINT8 c1) | |
| 1651 | { | |
| 1652 | return (UINT32) (UINT8) ((c0 * (1.0 - factor)) + (c1 * (0.0 + factor)) + 0.5); | |
| 1653 | } | |
| 1654 | ||
| 1655 | ||
| 1656 | ||
| 1657 | //************************************************************************** | |
| 1658 | // VARIATIONS | |
| 1659 | //************************************************************************** | |
| 1660 | ||
| 1661 | const device_type MC6847_NTSC = &device_creator<mc6847_ntsc_device>; | |
| 1662 | const device_type MC6847_PAL = &device_creator<mc6847_pal_device>; | |
| 1663 | const device_type MC6847Y_NTSC = &device_creator<mc6847y_ntsc_device>; | |
| 1664 | const device_type MC6847Y_PAL = &device_creator<mc6847y_pal_device>; | |
| 1665 | const device_type MC6847T1_NTSC = &device_creator<mc6847t1_ntsc_device>; | |
| 1666 | const device_type MC6847T1_PAL = &device_creator<mc6847t1_pal_device>; | |
| 1667 | ||
| 1668 | ||
| 1669 | ||
| 1670 | //------------------------------------------------- | |
| 1671 | // mc6847_ntsc_device | |
| 1672 | //------------------------------------------------- | |
| 1673 | ||
| 1674 | mc6847_ntsc_device::mc6847_ntsc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) | |
| 1675 | : mc6847_base_device(mconfig, MC6847_NTSC, "MC6847_NTSC", tag, owner, clock, ntsc_square_fontdata8x12, 262.0) | |
| 1676 | { | |
| 1677 | } | |
| 1678 | ||
| 1679 | ||
| 1680 | ||
| 1681 | //------------------------------------------------- | |
| 1682 | // mc6847_pal_device | |
| 1683 | //------------------------------------------------- | |
| 1684 | ||
| 1685 | mc6847_pal_device::mc6847_pal_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) | |
| 1686 | : mc6847_base_device(mconfig, MC6847_PAL, "MC6847_PAL", tag, owner, clock, pal_square_fontdata8x12, 262.0) | |
| 1687 | { | |
| 1688 | } | |
| 1689 | ||
| 1690 | ||
| 1691 | ||
| 1692 | //------------------------------------------------- | |
| 1693 | // mc6847y_ntsc_device | |
| 1694 | //------------------------------------------------- | |
| 1695 | ||
| 1696 | mc6847y_ntsc_device::mc6847y_ntsc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) | |
| 1697 | : mc6847_base_device(mconfig, MC6847Y_NTSC, "MC6847Y_NTSC", tag, owner, clock, ntsc_square_fontdata8x12, 262.5) | |
| 1698 | { | |
| 1699 | } | |
| 1700 | ||
| 1701 | ||
| 1702 | ||
| 1703 | //------------------------------------------------- | |
| 1704 | // mc6847y_pal_device | |
| 1705 | //------------------------------------------------- | |
| 1706 | ||
| 1707 | mc6847y_pal_device::mc6847y_pal_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) | |
| 1708 | : mc6847_base_device(mconfig, MC6847Y_PAL, "MC6847Y_PAL", tag, owner, clock, pal_square_fontdata8x12, 262.5) | |
| 1709 | { | |
| 1710 | } | |
| 1711 | ||
| 1712 | ||
| 1713 | ||
| 1714 | //------------------------------------------------- | |
| 1715 | // mc6847t1_ntsc_device | |
| 1716 | //------------------------------------------------- | |
| 1717 | ||
| 1718 | mc6847t1_ntsc_device::mc6847t1_ntsc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) | |
| 1719 | : mc6847_base_device(mconfig, MC6847T1_NTSC, "MC6847T1_NTSC", tag, owner, clock, ntsc_round_fontdata8x12, 262.0) | |
| 1720 | { | |
| 1721 | } | |
| 1722 | ||
| 1723 | ||
| 1724 | ||
| 1725 | //------------------------------------------------- | |
| 1726 | // mc6847t1_pal_device | |
| 1727 | //------------------------------------------------- | |
| 1728 | ||
| 1729 | mc6847t1_pal_device::mc6847t1_pal_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) | |
| 1730 | : mc6847_base_device(mconfig, MC6847T1_PAL, "MC6847T1_PAL", tag, owner, clock, pal_round_fontdata8x12, 262.0) | |
| 1731 | { | |
| 1732 | } |
| Added: svn:eol-style + native Added: svn:mime-type + text/plain |
| r0 | r21685 | |
|---|---|---|
| 1 | /*************************************************************************** | |
| 2 | ||
| 3 | Hitachi HD44352 LCD controller | |
| 4 | ||
| 5 | ***************************************************************************/ | |
| 6 | ||
| 7 | #include "emu.h" | |
| 8 | #include "video/hd44352.h" | |
| 9 | ||
| 10 | #define LCD_BYTE_INPUT 0x01 | |
| 11 | #define LCD_BYTE_OUTPUT 0x02 | |
| 12 | #define LCD_CHAR_OUTPUT 0x03 | |
| 13 | #define LCD_ON_OFF 0x04 | |
| 14 | #define LCD_CURSOR_GRAPHIC 0x06 | |
| 15 | #define LCD_CURSOR_CHAR 0x07 | |
| 16 | #define LCD_SCROLL_CHAR_WIDTH 0x08 | |
| 17 | #define LCD_CURSOR_STATUS 0x09 | |
| 18 | #define LCD_USER_CHARACTER 0x0b | |
| 19 | #define LCD_CONTRAST 0x0c | |
| 20 | #define LCD_IRQ_FREQUENCY 0x0d | |
| 21 | #define LCD_CURSOR_POSITION 0x0e | |
| 22 | ||
| 23 | ||
| 24 | // devices | |
| 25 | const device_type HD44352 = &device_creator<hd44352_device>; | |
| 26 | ||
| 27 | //************************************************************************** | |
| 28 | // live device | |
| 29 | //************************************************************************** | |
| 30 | ||
| 31 | //------------------------------------------------- | |
| 32 | // hd44352_device - constructor | |
| 33 | //------------------------------------------------- | |
| 34 | ||
| 35 | hd44352_device::hd44352_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock): | |
| 36 | device_t(mconfig, HD44352, "hd44352", tag, owner, clock) | |
| 37 | { | |
| 38 | } | |
| 39 | ||
| 40 | //------------------------------------------------- | |
| 41 | // device_config_complete - perform any | |
| 42 | // operations now that the configuration is | |
| 43 | // complete | |
| 44 | //------------------------------------------------- | |
| 45 | ||
| 46 | void hd44352_device::device_config_complete() | |
| 47 | { | |
| 48 | // inherit a copy of the static data | |
| 49 | const hd44352_interface *intf = reinterpret_cast<const hd44352_interface *>(static_config()); | |
| 50 | if (intf != NULL) | |
| 51 | *static_cast<hd44352_interface *>(this) = *intf; | |
| 52 | ||
| 53 | // or initialize to defaults if none provided | |
| 54 | else | |
| 55 | { | |
| 56 | memset(&m_on, 0, sizeof(m_on)); | |
| 57 | } | |
| 58 | } | |
| 59 | ||
| 60 | //------------------------------------------------- | |
| 61 | // device_validity_check - perform validity checks | |
| 62 | // on this device | |
| 63 | //------------------------------------------------- | |
| 64 | ||
| 65 | void hd44352_device::device_validity_check(validity_checker &valid) const | |
| 66 | { | |
| 67 | } | |
| 68 | //------------------------------------------------- | |
| 69 | // device_start - device-specific startup | |
| 70 | //------------------------------------------------- | |
| 71 | ||
| 72 | void hd44352_device::device_start() | |
| 73 | { | |
| 74 | m_on.resolve(m_on_cb, *this); | |
| 75 | ||
| 76 | m_on_timer = timer_alloc(ON_TIMER); | |
| 77 | m_on_timer->adjust(attotime::from_hz(m_clock/16384), 0, attotime::from_hz(m_clock/16384)); | |
| 78 | ||
| 79 | save_item( NAME(m_control_lines)); | |
| 80 | save_item( NAME(m_data_bus)); | |
| 81 | save_item( NAME(m_state)); | |
| 82 | save_item( NAME(m_offset)); | |
| 83 | save_item( NAME(m_char_width)); | |
| 84 | save_item( NAME(m_bank)); | |
| 85 | save_item( NAME(m_lcd_on)); | |
| 86 | save_item( NAME(m_scroll)); | |
| 87 | save_item( NAME(m_contrast)); | |
| 88 | save_item( NAME(m_byte_count)); | |
| 89 | save_item( NAME(m_cursor_status)); | |
| 90 | save_item( NAME(m_cursor_x)); | |
| 91 | save_item( NAME(m_cursor_y)); | |
| 92 | save_item( NAME(m_cursor_lcd)); | |
| 93 | save_item( NAME(m_video_ram[0])); | |
| 94 | save_item( NAME(m_video_ram[1])); | |
| 95 | save_item( NAME(m_par)); | |
| 96 | save_item( NAME(m_cursor)); | |
| 97 | save_item( NAME(m_custom_char[0])); | |
| 98 | save_item( NAME(m_custom_char[1])); | |
| 99 | save_item( NAME(m_custom_char[2])); | |
| 100 | save_item( NAME(m_custom_char[3])); | |
| 101 | } | |
| 102 | ||
| 103 | ||
| 104 | //------------------------------------------------- | |
| 105 | // device_reset - device-specific reset | |
| 106 | //------------------------------------------------- | |
| 107 | ||
| 108 | void hd44352_device::device_reset() | |
| 109 | { | |
| 110 | memset(m_video_ram, 0x00, sizeof(m_video_ram)); | |
| 111 | memset(m_par, 0x00, sizeof(m_par)); | |
| 112 | memset(m_custom_char, 0x00, sizeof(m_custom_char)); | |
| 113 | memset(m_cursor, 0x00, sizeof(m_cursor)); | |
| 114 | m_control_lines = 0; | |
| 115 | m_data_bus = 0xff; | |
| 116 | m_state = 0; | |
| 117 | m_bank = 0; | |
| 118 | m_offset = 0; | |
| 119 | m_char_width = 6; | |
| 120 | m_lcd_on = 0; | |
| 121 | m_scroll = 0; | |
| 122 | m_byte_count = 0; | |
| 123 | m_cursor_status = 0; | |
| 124 | m_cursor_x = 0; | |
| 125 | m_cursor_y = 0; | |
| 126 | m_cursor_lcd = 0; | |
| 127 | m_contrast = 0; | |
| 128 | } | |
| 129 | ||
| 130 | ||
| 131 | //------------------------------------------------- | |
| 132 | // device_timer - handler timer events | |
| 133 | //------------------------------------------------- | |
| 134 | void hd44352_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) | |
| 135 | { | |
| 136 | switch(id) | |
| 137 | { | |
| 138 | case ON_TIMER: | |
| 139 | if (m_control_lines & 0x40) | |
| 140 | { | |
| 141 | m_on(ASSERT_LINE); | |
| 142 | m_on(CLEAR_LINE); | |
| 143 | } | |
| 144 | break; | |
| 145 | } | |
| 146 | } | |
| 147 | ||
| 148 | //************************************************************************** | |
| 149 | // device interface | |
| 150 | //************************************************************************** | |
| 151 | ||
| 152 | UINT32 hd44352_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) | |
| 153 | { | |
| 154 | UINT8 cw = m_char_width; | |
| 155 | ||
| 156 | bitmap.fill(0, cliprect); | |
| 157 | ||
| 158 | if (m_control_lines&0x80 && m_lcd_on) | |
| 159 | { | |
| 160 | for (int a=0; a<2; a++) | |
| 161 | for (int py=0; py<4; py++) | |
| 162 | for (int px=0; px<16; px++) | |
| 163 | if (BIT(m_cursor_status, 4) && px == m_cursor_x && py == m_cursor_y && a == m_cursor_lcd) | |
| 164 | { | |
| 165 | //draw the cursor | |
| 166 | for (int c=0; c<cw; c++) | |
| 167 | { | |
| 168 | UINT8 d = compute_newval((m_cursor_status>>5) & 0x07, m_video_ram[a][py*16*cw + px*cw + c + m_scroll * 48], m_cursor[c]); | |
| 169 | for (int b=0; b<8; b++) | |
| 170 | { | |
| 171 | bitmap.pix16(py*8 + b, a*cw*16 + px*cw + c) = BIT(d, 7-b); | |
| 172 | } | |
| 173 | } | |
| 174 | } | |
| 175 | else | |
| 176 | { | |
| 177 | for (int c=0; c<cw; c++) | |
| 178 | { | |
| 179 | UINT8 d = m_video_ram[a][py*16*cw + px*cw + c + m_scroll * 48]; | |
| 180 | for (int b=0; b<8; b++) | |
| 181 | { | |
| 182 | bitmap.pix16(py*8 + b, a*cw*16 + px*cw + c) = BIT(d, 7-b); | |
| 183 | } | |
| 184 | } | |
| 185 | } | |
| 186 | } | |
| 187 | ||
| 188 | return 0; | |
| 189 | } | |
| 190 | ||
| 191 | ||
| 192 | void hd44352_device::control_write(UINT8 data) | |
| 193 | { | |
| 194 | if(m_control_lines == data) | |
| 195 | m_state = 0; | |
| 196 | ||
| 197 | m_control_lines = data; | |
| 198 | } | |
| 199 | ||
| 200 | UINT8 hd44352_device::compute_newval(UINT8 type, UINT8 oldval, UINT8 newval) | |
| 201 | { | |
| 202 | switch(type & 0x07) | |
| 203 | { | |
| 204 | case 0x00: | |
| 205 | return (~oldval) & newval; | |
| 206 | case 0x01: | |
| 207 | return oldval ^ newval; | |
| 208 | case 0x03: | |
| 209 | return oldval & (~newval); | |
| 210 | case 0x04: | |
| 211 | return newval; | |
| 212 | case 0x05: | |
| 213 | return oldval | newval; | |
| 214 | case 0x07: | |
| 215 | return oldval; | |
| 216 | case 0x02: | |
| 217 | case 0x06: | |
| 218 | default: | |
| 219 | return 0; | |
| 220 | } | |
| 221 | } | |
| 222 | ||
| 223 | UINT8 hd44352_device::get_char(UINT16 pos) | |
| 224 | { | |
| 225 | switch ((UINT8)pos/8) | |
| 226 | { | |
| 227 | case 0xcf: | |
| 228 | return m_custom_char[0][pos%8]; | |
| 229 | case 0xdf: | |
| 230 | return m_custom_char[1][pos%8]; | |
| 231 | case 0xef: | |
| 232 | return m_custom_char[2][pos%8]; | |
| 233 | case 0xff: | |
| 234 | return m_custom_char[3][pos%8]; | |
| 235 | default: | |
| 236 | return region()->u8(pos); | |
| 237 | } | |
| 238 | } | |
| 239 | ||
| 240 | void hd44352_device::data_write(UINT8 data) | |
| 241 | { | |
| 242 | // verify that controller is active | |
| 243 | if (!(m_control_lines&0x80)) | |
| 244 | return; | |
| 245 | ||
| 246 | if (m_control_lines & 0x01) | |
| 247 | { | |
| 248 | if (!(m_control_lines&0x02) && !(m_control_lines&0x04)) | |
| 249 | return; | |
| 250 | ||
| 251 | switch (m_state) | |
| 252 | { | |
| 253 | case 0: //parameter 0 | |
| 254 | m_par[m_state++] = data; | |
| 255 | break; | |
| 256 | case 1: //parameter 1 | |
| 257 | m_par[m_state++] = data; | |
| 258 | break; | |
| 259 | case 2: //parameter 2 | |
| 260 | m_par[m_state++] = data; | |
| 261 | break; | |
| 262 | } | |
| 263 | ||
| 264 | switch (m_par[0] & 0x0f) | |
| 265 | { | |
| 266 | case LCD_BYTE_INPUT: | |
| 267 | case LCD_CHAR_OUTPUT: | |
| 268 | { | |
| 269 | if (m_state == 1) | |
| 270 | m_bank = BIT(data, 4); | |
| 271 | else if (m_state == 2) | |
| 272 | m_offset = ((data>>1)&0x3f) % 48 + (BIT(data,7) * 48); | |
| 273 | else if (m_state == 3) | |
| 274 | m_offset += ((data & 0x03) * 96); | |
| 275 | } | |
| 276 | break; | |
| 277 | case LCD_BYTE_OUTPUT: | |
| 278 | { | |
| 279 | if (m_state == 1) | |
| 280 | m_bank = BIT(data, 4); | |
| 281 | else if (m_state == 2) | |
| 282 | m_offset = ((data>>1)&0x3f) % 48 + (BIT(data,7) * 48); | |
| 283 | else if (m_state == 3) | |
| 284 | m_offset += ((data & 0x03) * 96); | |
| 285 | } | |
| 286 | break; | |
| 287 | case LCD_ON_OFF: | |
| 288 | { | |
| 289 | if (m_state == 1) | |
| 290 | m_lcd_on = BIT(data, 4); | |
| 291 | m_data_bus = 0xff; | |
| 292 | m_state = 0; | |
| 293 | } | |
| 294 | break; | |
| 295 | case LCD_SCROLL_CHAR_WIDTH: | |
| 296 | { | |
| 297 | if (m_state == 1) | |
| 298 | { | |
| 299 | m_char_width = 8-((data>>4)&3); | |
| 300 | m_scroll = ((data>>6)&3); | |
| 301 | } | |
| 302 | ||
| 303 | m_data_bus = 0xff; | |
| 304 | m_state = 0; | |
| 305 | } | |
| 306 | break; | |
| 307 | case LCD_CURSOR_STATUS: | |
| 308 | { | |
| 309 | if (m_state == 1) | |
| 310 | m_cursor_status = data; | |
| 311 | m_data_bus = 0xff; | |
| 312 | m_state = 0; | |
| 313 | } | |
| 314 | break; | |
| 315 | case LCD_CONTRAST: | |
| 316 | { | |
| 317 | if (m_state == 1) | |
| 318 | m_contrast = (m_contrast & 0x00ffff) | (data<<16); | |
| 319 | else if (m_state == 2) | |
| 320 | m_contrast = (m_contrast & 0xff00ff) | (data<<8); | |
| 321 | else if (m_state == 3) | |
| 322 | { | |
| 323 | m_contrast = (m_contrast & 0xffff00) | (data<<0); | |
| 324 | m_state = 0; | |
| 325 | } | |
| 326 | ||
| 327 | m_data_bus = 0xff; | |
| 328 | } | |
| 329 | break; | |
| 330 | case LCD_IRQ_FREQUENCY: | |
| 331 | { | |
| 332 | if (m_state == 1) | |
| 333 | { | |
| 334 | UINT32 on_timer_rate; | |
| 335 | ||
| 336 | switch((data>>4) & 0x0f) | |
| 337 | { | |
| 338 | case 0x00: on_timer_rate = 16384; break; | |
| 339 | case 0x01: on_timer_rate = 8; break; | |
| 340 | case 0x02: on_timer_rate = 16; break; | |
| 341 | case 0x03: on_timer_rate = 32; break; | |
| 342 | case 0x04: on_timer_rate = 64; break; | |
| 343 | case 0x05: on_timer_rate = 128; break; | |
| 344 | case 0x06: on_timer_rate = 256; break; | |
| 345 | case 0x07: on_timer_rate = 512; break; | |
| 346 | case 0x08: on_timer_rate = 1024; break; | |
| 347 | case 0x09: on_timer_rate = 2048; break; | |
| 348 | case 0x0a: on_timer_rate = 4096; break; | |
| 349 | case 0x0b: on_timer_rate = 4096; break; | |
| 350 | default: on_timer_rate = 8192; break; | |
| 351 | } | |
| 352 | ||
| 353 | m_on_timer->adjust(attotime::from_hz(m_clock/on_timer_rate), 0, attotime::from_hz(m_clock/on_timer_rate)); | |
| 354 | } | |
| 355 | m_data_bus = 0xff; | |
| 356 | m_state = 0; | |
| 357 | } | |
| 358 | break; | |
| 359 | case LCD_CURSOR_POSITION: | |
| 360 | { | |
| 361 | if (m_state == 1) | |
| 362 | m_cursor_lcd = BIT(data, 4); //0:left lcd 1:right lcd; | |
| 363 | else if (m_state == 2) | |
| 364 | m_cursor_x = ((data>>1)&0x3f) % 48 + (BIT(data,7) * 48); | |
| 365 | else if (m_state == 3) | |
| 366 | { | |
| 367 | m_cursor_y = data & 0x03; | |
| 368 | m_state = 0; | |
| 369 | } | |
| 370 | ||
| 371 | m_data_bus = 0xff; | |
| 372 | } | |
| 373 | break; | |
| 374 | } | |
| 375 | ||
| 376 | m_byte_count = 0; | |
| 377 | m_data_bus = 0xff; | |
| 378 | } | |
| 379 | else | |
| 380 | { | |
| 381 | switch (m_par[0] & 0x0f) | |
| 382 | { | |
| 383 | case LCD_BYTE_INPUT: | |
| 384 | { | |
| 385 | if (((m_par[0]>>5) & 0x07) != 0x03) | |
| 386 | break; | |
| 387 | ||
| 388 | m_offset %= 0x180; | |
| 389 | m_data_bus = ((m_video_ram[m_bank][m_offset]<<4)&0xf0) | ((m_video_ram[m_bank][m_offset]>>4)&0x0f); | |
| 390 | m_offset++; m_byte_count++; | |
| 391 | } | |
| 392 | break; | |
| 393 | case LCD_BYTE_OUTPUT: | |
| 394 | { | |
| 395 | m_offset %= 0x180; | |
| 396 | m_video_ram[m_bank][m_offset] = compute_newval((m_par[0]>>5) & 0x07, m_video_ram[m_bank][m_offset], data); | |
| 397 | m_offset++; m_byte_count++; | |
| 398 | ||
| 399 | m_data_bus = 0xff; | |
| 400 | } | |
| 401 | break; | |
| 402 | case LCD_CHAR_OUTPUT: | |
| 403 | { | |
| 404 | int char_pos = data*8; | |
| 405 | ||
| 406 | for (int i=0; i<m_char_width; i++) | |
| 407 | { | |
| 408 | m_offset %= 0x180; | |
| 409 | m_video_ram[m_bank][m_offset] = compute_newval((m_par[0]>>5) & 0x07, m_video_ram[m_bank][m_offset], get_char(char_pos)); | |
| 410 | m_offset++; char_pos++; | |
| 411 | } | |
| 412 | ||
| 413 | m_byte_count++; | |
| 414 | m_data_bus = 0xff; | |
| 415 | } | |
| 416 | break; | |
| 417 | case LCD_CURSOR_GRAPHIC: | |
| 418 | if (m_byte_count<8) | |
| 419 | { | |
| 420 | m_cursor[m_byte_count] = data; | |
| 421 | m_byte_count++; | |
| 422 | m_data_bus = 0xff; | |
| 423 | } | |
| 424 | break; | |
| 425 | case LCD_CURSOR_CHAR: | |
| 426 | if (m_byte_count<1) | |
| 427 | { | |
| 428 | UINT8 char_code = ((data<<4)&0xf0) | ((data>>4)&0x0f); | |
| 429 | ||
| 430 | for (int i=0; i<8; i++) | |
| 431 | m_cursor[i] = get_char(char_code*8 + i); | |
| 432 | ||
| 433 | m_byte_count++; | |
| 434 | m_data_bus = 0xff; | |
| 435 | } | |
| 436 | break; | |
| 437 | case LCD_USER_CHARACTER: | |
| 438 | if (m_byte_count<8) | |
| 439 | { | |
| 440 | m_custom_char[(m_par[1]&0x03)][m_byte_count] = data; | |
| 441 | m_byte_count++; | |
| 442 | m_data_bus = 0xff; | |
| 443 | } | |
| 444 | break; | |
| 445 | default: | |
| 446 | m_data_bus = 0xff; | |
| 447 | } | |
| 448 | ||
| 449 | m_state=0; | |
| 450 | } | |
| 451 | } | |
| 452 | ||
| 453 | UINT8 hd44352_device::data_read() | |
| 454 | { | |
| 455 | return m_data_bus; | |
| 456 | } |
| Added: svn:mime-type + text/plain Added: svn:eol-style + native |
| r0 | r21685 | |
|---|---|---|
| 1 | /********************************************************************* | |
| 2 | ||
| 3 | mc6847.h | |
| 4 | ||
| 5 | Implementation of Motorola 6847 video hardware chip | |
| 6 | ||
| 7 | ***************************************************************************/ | |
| 8 | ||
| 9 | #pragma once | |
| 10 | ||
| 11 | #ifndef __MC6847__ | |
| 12 | #define __MC6847__ | |
| 13 | ||
| 14 | ||
| 15 | //************************************************************************** | |
| 16 | // MC6847 CONFIGURATION / INTERFACE | |
| 17 | //************************************************************************** | |
| 18 | ||
| 19 | #define MCFG_MC6847_REMOVE(_tag) \ | |
| 20 | MCFG_DEVICE_REMOVE(_tag) | |
| 21 | ||
| 22 | #define MCFG_MC6847_ADD(_tag, _variant, _clock, _config) \ | |
| 23 | MCFG_DEVICE_ADD(_tag, _variant, _clock) \ | |
| 24 | MCFG_DEVICE_CONFIG(_config) | |
| 25 | ||
| 26 | #define MCFG_SCREEN_MC6847_NTSC_ADD(_tag, _mctag) \ | |
| 27 | MCFG_SCREEN_ADD(_tag, RASTER) \ | |
| 28 | MCFG_SCREEN_UPDATE_DEVICE(_mctag, mc6847_base_device, screen_update) \ | |
| 29 | MCFG_SCREEN_REFRESH_RATE(60) \ | |
| 30 | MCFG_SCREEN_SIZE(320, 243) \ | |
| 31 | MCFG_SCREEN_VISIBLE_AREA(0, 320-1, 1, 241-1) \ | |
| 32 | MCFG_SCREEN_VBLANK_TIME(0) | |
| 33 | #define MCFG_SCREEN_MC6847_PAL_ADD(_tag, _mctag) \ | |
| 34 | MCFG_SCREEN_ADD(_tag, RASTER) \ | |
| 35 | MCFG_SCREEN_UPDATE_DEVICE(_mctag, mc6847_base_device, screen_update) \ | |
| 36 | MCFG_SCREEN_REFRESH_RATE(50) \ | |
| 37 | MCFG_SCREEN_SIZE(320, 243) \ | |
| 38 | MCFG_SCREEN_VISIBLE_AREA(0, 320-1, 1, 241-1) \ | |
| 39 | MCFG_SCREEN_VBLANK_TIME(0) | |
| 40 | /* interface */ | |
| 41 | struct mc6847_interface | |
| 42 | { | |
| 43 | /* screen we are acting on */ | |
| 44 | const char *m_screen_tag; | |
| 45 | ||
| 46 | /* if specified, this gets called whenever reading a byte (offs_t ~0 specifies DA* entering the tristate mode) */ | |
| 47 | devcb_read8 m_input_func; | |
| 48 | ||
| 49 | /* if specified, this gets called for every change of the HS pin (pin 38) */ | |
| 50 | devcb_write_line m_out_hsync_func; | |
| 51 | ||
| 52 | /* if specified, this gets called for every change of the FS pin (pin 37) */ | |
| 53 | devcb_write_line m_out_fsync_func; | |
| 54 | ||
| 55 | /* mode control lines input */ | |
| 56 | devcb_read_line m_in_ag_func; | |
| 57 | devcb_read_line m_in_gm2_func; | |
| 58 | devcb_read_line m_in_gm1_func; | |
| 59 | devcb_read_line m_in_gm0_func; | |
| 60 | devcb_read_line m_in_css_func; | |
| 61 | devcb_read_line m_in_as_func; | |
| 62 | devcb_read_line m_in_intext_func; | |
| 63 | devcb_read_line m_in_inv_func; | |
| 64 | ||
| 65 | /* if specified, this reads the external char rom off of the driver state */ | |
| 66 | UINT8 (*m_get_char_rom)(running_machine &machine, UINT8 ch, int line); | |
| 67 | ||
| 68 | /* if true, this is black and white */ | |
| 69 | bool m_black_and_white; | |
| 70 | }; | |
| 71 | ||
| 72 | #define ARTIFACTING_TAG "artifacting" | |
| 73 | ||
| 74 | INPUT_PORTS_EXTERN(mc6847_artifacting); | |
| 75 | ||
| 76 | ||
| 77 | //************************************************************************** | |
| 78 | // MC6847 CORE | |
| 79 | //************************************************************************** | |
| 80 | ||
| 81 | PALETTE_INIT( mc6847 ); | |
| 82 | PALETTE_INIT( mc6847_bw ); | |
| 83 | ||
| 84 | // base class so that the GIME emulation can access mc6847 stuff | |
| 85 | class mc6847_friend_device : public device_t | |
| 86 | { | |
| 87 | public: | |
| 88 | // inlines | |
| 89 | bool hs_r(void) { return m_horizontal_sync; } | |
| 90 | bool fs_r(void) { return m_field_sync; } | |
| 91 | ||
| 92 | protected: | |
| 93 | mc6847_friend_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, | |
| 94 | const UINT8 *fontdata, bool is_mc6847t1, double tpfs, int field_sync_falling_edge_scanline, bool supports_partial_body_scanlines); | |
| 95 | ||
| 96 | // video mode constants | |
| 97 | static const UINT8 MODE_AG = 0x80; | |
| 98 | static const UINT8 MODE_GM2 = 0x40; | |
| 99 | static const UINT8 MODE_GM1 = 0x20; | |
| 100 | static const UINT8 MODE_GM0 = 0x10; | |
| 101 | static const UINT8 MODE_CSS = 0x08; | |
| 102 | static const UINT8 MODE_AS = 0x04; | |
| 103 | static const UINT8 MODE_INTEXT = 0x02; | |
| 104 | static const UINT8 MODE_INV = 0x01; | |
| 105 | ||
| 106 | // timer constants | |
| 107 | static const device_timer_id TIMER_FRAME = 0; | |
| 108 | static const device_timer_id TIMER_HSYNC_OFF = 1; | |
| 109 | static const device_timer_id TIMER_HSYNC_ON = 2; | |
| 110 | static const device_timer_id TIMER_FSYNC = 3; | |
| 111 | ||
| 112 | // fonts | |
| 113 | static const UINT8 pal_round_fontdata8x12[]; | |
| 114 | static const UINT8 pal_square_fontdata8x12[]; | |
| 115 | static const UINT8 ntsc_round_fontdata8x12[]; | |
| 116 | static const UINT8 ntsc_square_fontdata8x12[]; | |
| 117 | static const UINT8 semigraphics4_fontdata8x12[]; | |
| 118 | static const UINT8 semigraphics6_fontdata8x12[]; | |
| 119 | ||
| 120 | // pixel definitions | |
| 121 | typedef UINT32 pixel_t; | |
| 122 | ||
| 123 | pixel_t *bitmap_addr(bitmap_rgb32 &bitmap, int y, int x) | |
| 124 | { | |
| 125 | return &bitmap.pix32(y, x); | |
| 126 | } | |
| 127 | ||
| 128 | static UINT8 simplify_mode(UINT8 data, UINT8 mode) | |
| 129 | { | |
| 130 | // simplifies MC6847 modes to drop mode flags that are not significant | |
| 131 | return mode & ~((mode & MODE_AG) ? (MODE_AS | MODE_INV) : 0); | |
| 132 | } | |
| 133 | ||
| 134 | // internal class that represents a MC6847 character map | |
| 135 | class character_map | |
| 136 | { | |
| 137 | public: | |
| 138 | // constructor that sets up the font data | |
| 139 | character_map(const UINT8 *fontdata, bool is_mc6847t1); | |
| 140 | ||
| 141 | // optimized template function that emits a single character | |
| 142 | template<int xscale> | |
| 143 | ATTR_FORCE_INLINE void emit_character(UINT8 mode, const UINT8 *data, int length, pixel_t *RESTRICT pixels, int y, const pixel_t *palette) | |
| 144 | { | |
| 145 | for (int i = 0; i < length; i++) | |
| 146 | { | |
| 147 | // get the character | |
| 148 | UINT8 character = data[i]; | |
| 149 | ||
| 150 | // based on the mode, determine which entry to use | |
| 151 | const entry *e = &m_entries[mode % (sizeof(m_entries) / sizeof(m_entries[0]))]; | |
| 152 | ||
| 153 | // identify the character in the font data | |
| 154 | const UINT8 *font_character = e->m_fontdata + (character & e->m_character_mask) * 12; | |
| 155 | ||
| 156 | // get the particular slice out | |
| 157 | UINT8 font_character_slice = font_character[y % 12]; | |
| 158 | ||
| 159 | // get the two colors | |
| 160 | UINT16 color_base_0 = e->m_color_base_0 + ((character >> e->m_color_shift_0) & e->m_color_mask_0); | |
| 161 | UINT16 color_base_1 = e->m_color_base_1 + ((character >> e->m_color_shift_1) & e->m_color_mask_1); | |
| 162 | pixel_t color_0 = palette[color_base_0]; | |
| 163 | pixel_t color_1 = palette[color_base_1]; | |
| 164 | ||
| 165 | // emit the bits | |
| 166 | for (int j = 0; j < 8; j++) | |
| 167 | { | |
| 168 | for (int k = 0; k < xscale; k++) | |
| 169 | { | |
| 170 | pixels[(i * 8 + j) * xscale + k] = bit_test(font_character_slice, j, color_0, color_1); | |
| 171 | } | |
| 172 | } | |
| 173 | } | |
| 174 | }; | |
| 175 | ||
| 176 | private: | |
| 177 | struct entry | |
| 178 | { | |
| 179 | const UINT8 *m_fontdata; | |
| 180 | UINT8 m_character_mask; | |
| 181 | UINT8 m_color_shift_0; | |
| 182 | UINT8 m_color_shift_1; | |
| 183 | UINT8 m_color_mask_0; | |
| 184 | UINT8 m_color_mask_1; | |
| 185 | UINT16 m_color_base_0; | |
| 186 | UINT16 m_color_base_1; | |
| 187 | }; | |
| 188 | ||
| 189 | // lookup table for MC6847 modes to determine font data and color | |
| 190 | entry m_entries[128]; | |
| 191 | ||
| 192 | // text font data calculated on startup | |
| 193 | UINT8 m_text_fontdata_inverse[64*12]; | |
| 194 | UINT8 m_text_fontdata_lower_case[64*12]; | |
| 195 | UINT8 m_text_fontdata_lower_case_inverse[64*12]; | |
| 196 | ||
| 197 | // optimized function that tests a single bit | |
| 198 | ATTR_FORCE_INLINE pixel_t bit_test(UINT8 data, int shift, pixel_t color_0, pixel_t color_1) | |
| 199 | { | |
| 200 | return data & (0x80 >> shift) ? color_1 : color_0; | |
| 201 | } | |
| 202 | }; | |
| 203 | ||
| 204 | // artficater internal class | |
| 205 | class artifacter | |
| 206 | { | |
| 207 | public: | |
| 208 | artifacter(); | |
| 209 | ||
| 210 | // artifacting config | |
| 211 | void setup_config(device_t *device); | |
| 212 | void poll_config(void) { m_artifacting = (m_config!=NULL) ? m_config->read() : 0; } | |
| 213 | ||
| 214 | // artifacting application | |
| 215 | template<int xscale> | |
| 216 | ATTR_FORCE_INLINE void process_artifacts(pixel_t *pixels, UINT8 mode, const pixel_t *palette) | |
| 217 | { | |
| 218 | if (((mode & (MODE_AG|MODE_GM2|MODE_GM1|MODE_GM0)) == (MODE_AG|MODE_GM2|MODE_GM1|MODE_GM0)) | |
| 219 | && (m_artifacting != 0)) | |
| 220 | { | |
| 221 | // identify the new colors and update | |
| 222 | pixel_t c0 = palette[(mode & MODE_CSS) ? 10 : 8]; | |
| 223 | pixel_t c1 = palette[(mode & MODE_CSS) ? 11 : 9]; | |
| 224 | update_colors(c0, c1); | |
| 225 | ||
| 226 | // generate the new line | |
| 227 | pixel_t new_line[256]; | |
| 228 | int x, i; | |
| 229 | for (x = 0; x < 256; x += 2) | |
| 230 | { | |
| 231 | UINT8 val = ((pixels[(x - 2) * xscale] == c1) ? 0x20 : 0x00) | |
| 232 | | ((pixels[(x - 1) * xscale] == c1) ? 0x10 : 0x00) | |
| 233 | | ((pixels[(x + 0) * xscale] == c1) ? 0x08 : 0x00) | |
| 234 | | ((pixels[(x + 1) * xscale] == c1) ? 0x04 : 0x00) | |
| 235 | | ((pixels[(x + 2) * xscale] == c1) ? 0x02 : 0x00) | |
| 236 | | ((pixels[(x + 3) * xscale] == c1) ? 0x01 : 0x00); | |
| 237 | ||
| 238 | new_line[x + 0] = m_expanded_colors[val * 2 + 0]; | |
| 239 | new_line[x + 1] = m_expanded_colors[val * 2 + 1]; | |
| 240 | } | |
| 241 | ||
| 242 | // and copy it in | |
| 243 | for (x = 0; x < 256; x++) | |
| 244 | { | |
| 245 | for (i = 0; i < xscale; i++) | |
| 246 | pixels[x * xscale + i] = new_line[x]; | |
| 247 | } | |
| 248 | } | |
| 249 | } | |
| 250 | ||
| 251 | private: | |
| 252 | ioport_port *m_config; | |
| 253 | ioport_value m_artifacting; | |
| 254 | ioport_value m_saved_artifacting; | |
| 255 | pixel_t m_saved_c0, m_saved_c1; | |
| 256 | pixel_t m_expanded_colors[128]; | |
| 257 | ||
| 258 | void update_colors(pixel_t c0, pixel_t c1); | |
| 259 | static pixel_t mix_color(double factor, UINT8 c0, UINT8 c1); | |
| 260 | }; | |
| 261 | ||
| 262 | enum border_color_t | |
| 263 | { | |
| 264 | BORDER_COLOR_BLACK, | |
| 265 | BORDER_COLOR_GREEN, | |
| 266 | BORDER_COLOR_WHITE, | |
| 267 | BORDER_COLOR_ORANGE | |
| 268 | }; | |
| 269 | ||
| 270 | // callbacks | |
| 271 | devcb_resolved_write_line m_res_out_hsync_func; | |
| 272 | devcb_resolved_write_line m_res_out_fsync_func; | |
| 273 | ||
| 274 | // incidentals | |
| 275 | character_map m_character_map; | |
| 276 | artifacter m_artifacter; | |
| 277 | ||
| 278 | // device-level overrides | |
| 279 | virtual void device_start(void); | |
| 280 | virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); | |
| 281 | virtual void device_reset(void); | |
| 282 | virtual void device_post_load(void); | |
| 283 | ||
| 284 | // other overridables | |
| 285 | virtual void new_frame(void); | |
| 286 | virtual void horizontal_sync_changed(bool line); | |
| 287 | virtual void field_sync_changed(bool line); | |
| 288 | virtual void enter_bottom_border(void); | |
| 289 | virtual void record_border_scanline(UINT16 physical_scanline); | |
| 290 | virtual void record_body_scanline(UINT16 physical_scanline, UINT16 logical_scanline) = 0; | |
| 291 | virtual void record_partial_body_scanline(UINT16 physical_scanline, UINT16 logical_scanline, INT32 start_clock, INT32 end_clock) = 0; | |
| 292 | ||
| 293 | // miscellaneous | |
| 294 | void video_flush(void); | |
| 295 | const char *describe_context(void); | |
| 296 | ||
| 297 | // setup functions | |
| 298 | emu_timer *setup_timer(device_timer_id id, double offset, double period); | |
| 299 | ||
| 300 | // converts to B&W | |
| 301 | static pixel_t black_and_white(pixel_t color) | |
| 302 | { | |
| 303 | UINT8 average_color = (RGB_RED(color) + RGB_GREEN(color) + RGB_BLUE(color)) / 3; | |
| 304 | return MAKE_RGB(average_color, average_color, average_color); | |
| 305 | } | |
| 306 | ||
| 307 | // changes the geometry | |
| 308 | ATTR_FORCE_INLINE void set_geometry(UINT16 top_border_scanlines, UINT16 body_scanlines, bool wide) | |
| 309 | { | |
| 310 | if (UNEXPECTED((m_top_border_scanlines != top_border_scanlines) | |
| 311 | || (m_body_scanlines != body_scanlines) | |
| 312 | || (m_wide != wide))) | |
| 313 | { | |
| 314 | m_top_border_scanlines = top_border_scanlines; | |
| 315 | m_body_scanlines = body_scanlines; | |
| 316 | m_wide = wide; | |
| 317 | update_field_sync_timer(); | |
| 318 | } | |
| 319 | } | |
| 320 | ||
| 321 | // calculates the border color | |
| 322 | static ATTR_FORCE_INLINE border_color_t border_value(UINT8 mode, bool is_mc6847t1) | |
| 323 | { | |
| 324 | border_color_t result; | |
| 325 | ||
| 326 | if (mode & MODE_AG) | |
| 327 | { | |
| 328 | // graphics | |
| 329 | result = mode & MODE_CSS ? BORDER_COLOR_WHITE : BORDER_COLOR_GREEN; | |
| 330 | } | |
| 331 | else if (!is_mc6847t1 || ((mode & MODE_GM2) == 0)) | |
| 332 | { | |
| 333 | // text, black border | |
| 334 | result = BORDER_COLOR_BLACK; | |
| 335 | } | |
| 336 | else | |
| 337 | { | |
| 338 | // text, green or orange border | |
| 339 | result = mode & MODE_CSS ? BORDER_COLOR_ORANGE : BORDER_COLOR_GREEN; | |
| 340 | } | |
| 341 | return result; | |
| 342 | } | |
| 343 | ||
| 344 | // checks to see if the video has changed | |
| 345 | ATTR_FORCE_INLINE bool has_video_changed(void) | |
| 346 | { | |
| 347 | /* poll the artifacting config */ | |
| 348 | m_artifacter.poll_config(); | |
| 349 | ||
| 350 | /* if the video didn't change, indicate as much */ | |
| 351 | bool video_changed = m_video_changed; | |
| 352 | m_video_changed = false; | |
| 353 | return video_changed; | |
| 354 | } | |
| 355 | ||
| 356 | // updates a byte in the video state | |
| 357 | template<class T> | |
| 358 | ATTR_FORCE_INLINE bool update_value(T *ptr, T byte) | |
| 359 | { | |
| 360 | bool result = false; | |
| 361 | if (*ptr != byte) | |
| 362 | { | |
| 363 | *ptr = byte; | |
| 364 | m_video_changed = true; | |
| 365 | result = true; | |
| 366 | } | |
| 367 | return result; | |
| 368 | }; | |
| 369 | ||
| 370 | // template function for emitting graphics bytes | |
| 371 | template<int bits_per_pixel, int xscale> | |
| 372 | ATTR_FORCE_INLINE void emit_graphics(const UINT8 *data, int length, pixel_t *RESTRICT pixels, UINT16 color_base, const pixel_t *RESTRICT palette) | |
| 373 | { | |
| 374 | for (int i = 0; i < length; i++) | |
| 375 | { | |
| 376 | for (int j = 0; j < (8 / bits_per_pixel); j++) | |
| 377 | { | |
| 378 | for (int k = 0; k < xscale; k++) | |
| 379 | { | |
| 380 | UINT16 color = color_base + ((data[i] >> (8 - (j + 1) * bits_per_pixel)) & ((1 << bits_per_pixel) - 1)); | |
| 381 | pixels[(i * (8 / bits_per_pixel) + j) * xscale + k] = palette[color]; | |
| 382 | } | |
| 383 | } | |
| 384 | } | |
| 385 | } | |
| 386 | ||
| 387 | // template function for emitting samples | |
| 388 | template<int xscale> | |
| 389 | UINT32 emit_mc6847_samples(UINT8 mode, const UINT8 *data, int length, pixel_t *RESTRICT pixels, const pixel_t *RESTRICT palette, | |
| 390 | UINT8 (*get_char_rom)(running_machine &machine, UINT8 ch, int line), int x, int y) | |
| 391 | { | |
| 392 | UINT32 result = 0; | |
| 393 | if (mode & MODE_AG) | |
| 394 | { | |
| 395 | /* graphics */ | |
| 396 | switch(mode & (MODE_GM2|MODE_GM1|MODE_GM0)) | |
| 397 | { | |
| 398 | case 0: | |
| 399 | emit_graphics<2, xscale * 4>(data, length, pixels, (mode & MODE_CSS) ? 4 : 0, palette); | |
| 400 | result = length * 8 * xscale * 2; | |
| 401 | break; | |
| 402 | ||
| 403 | case MODE_GM0: | |
| 404 | case MODE_GM1|MODE_GM0: | |
| 405 | case MODE_GM2|MODE_GM0: | |
| 406 | emit_graphics<1, xscale * 2>(data, length, pixels, (mode & MODE_CSS) ? 10 : 8, palette); | |
| 407 | result = length * 8 * xscale * 2; | |
| 408 | break; | |
| 409 | ||
| 410 | case MODE_GM1: | |
| 411 | case MODE_GM2: | |
| 412 | case MODE_GM2|MODE_GM1: | |
| 413 | emit_graphics<2, xscale * 2>(data, length, pixels, (mode & MODE_CSS) ? 4 : 0, palette); | |
| 414 | result = length * 8 * xscale; | |
| 415 | break; | |
| 416 | ||
| 417 | case MODE_GM2|MODE_GM1|MODE_GM0: | |
| 418 | emit_graphics<1, xscale * 1>(data, length, pixels, (mode & MODE_CSS) ? 10 : 8, palette); | |
| 419 | result = length * 8 * xscale; | |
| 420 | break; | |
| 421 | ||
| 422 | default: | |
| 423 | /* should not get here */ | |
| 424 | fatalerror("Should not get here\n"); | |
| 425 | break; | |
| 426 | } | |
| 427 | } | |
| 428 | else if ((get_char_rom != NULL) && ((mode & (MODE_AG|MODE_AS|MODE_INTEXT)) == MODE_INTEXT)) | |
| 429 | { | |
| 430 | /* external ROM */ | |
| 431 | for (int i = 0; i < length; i++) | |
| 432 | { | |
| 433 | UINT8 byte = get_char_rom(machine(), data[i], y % 12) ^ (mode & MODE_INV ? 0xFF : 0x00); | |
| 434 | emit_graphics<2, xscale * 2>(&byte, 1, &pixels[i * 8], (mode & MODE_CSS) ? 14 : 12, palette); | |
| 435 | } | |
| 436 | result = length * 8 * xscale; | |
| 437 | } | |
| 438 | else | |
| 439 | { | |
| 440 | /* text/semigraphics */ | |
| 441 | m_character_map.emit_character<xscale>(mode, data, length, pixels, y, palette); | |
| 442 | result = length * 8 * xscale; | |
| 443 | } | |
| 444 | return result; | |
| 445 | } | |
| 446 | ||
| 447 | private: | |
| 448 | enum scanline_zone | |
| 449 | { | |
| 450 | SCANLINE_ZONE_TOP_BORDER, | |
| 451 | SCANLINE_ZONE_BODY, | |
| 452 | SCANLINE_ZONE_BOTTOM_BORDER, | |
| 453 | SCANLINE_ZONE_RETRACE, | |
| 454 | SCANLINE_ZONE_VBLANK, | |
| 455 | SCANLINE_ZONE_FRAME_END | |
| 456 | }; | |
| 457 | ||
| 458 | // timers | |
| 459 | emu_timer *m_frame_timer; | |
| 460 | emu_timer *m_hsync_on_timer; | |
| 461 | emu_timer *m_hsync_off_timer; | |
| 462 | emu_timer *m_fsync_timer; | |
| 463 | ||
| 464 | // incidentals | |
| 465 | double m_tpfs; | |
| 466 | int m_field_sync_falling_edge_scanline; | |
| 467 | bool m_wide; | |
| 468 | bool m_video_changed; | |
| 469 | UINT16 m_top_border_scanlines; | |
| 470 | UINT16 m_body_scanlines; | |
| 471 | bool m_recording_scanline; | |
| 472 | bool m_supports_partial_body_scanlines; | |
| 473 | ||
| 474 | // video state | |
| 475 | UINT16 m_physical_scanline; | |
| 476 | UINT16 m_logical_scanline; | |
| 477 | UINT16 m_logical_scanline_zone; | |
| 478 | bool m_horizontal_sync; | |
| 479 | bool m_field_sync; | |
| 480 | UINT32 m_partial_scanline_clocks; | |
| 481 | ||
| 482 | // functions | |
| 483 | void change_horizontal_sync(bool line); | |
| 484 | void change_field_sync(bool line); | |
| 485 | void update_field_sync_timer(void); | |
| 486 | void next_scanline(void); | |
| 487 | INT32 get_clocks_since_hsync(); | |
| 488 | ||
| 489 | // debugging | |
| 490 | const char *scanline_zone_string(scanline_zone zone); | |
| 491 | }; | |
| 492 | ||
| 493 | // actual base class for MC6847 family of devices | |
| 494 | class mc6847_base_device : public mc6847_friend_device | |
| 495 | { | |
| 496 | public: | |
| 497 | /* updates the screen -- this will call begin_update(), | |
| 498 | followed by update_row() reapeatedly and after all row | |
| 499 | updating is complete, end_update() */ | |
| 500 | UINT32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); | |
| 501 | ||
| 502 | // mode changing operations | |
| 503 | DECLARE_WRITE_LINE_MEMBER( ag_w ) { change_mode(MODE_AG, state); } | |
| 504 | DECLARE_WRITE_LINE_MEMBER( gm2_w ) { change_mode(MODE_GM2, state); } | |
| 505 | DECLARE_WRITE_LINE_MEMBER( gm1_w ) { change_mode(MODE_GM1, state); } | |
| 506 | DECLARE_WRITE_LINE_MEMBER( gm0_w ) { change_mode(MODE_GM0, state); } | |
| 507 | DECLARE_WRITE_LINE_MEMBER( as_w ) { change_mode(MODE_AS, state); } | |
| 508 | DECLARE_WRITE_LINE_MEMBER( css_w ) { change_mode(MODE_CSS, state); } | |
| 509 | DECLARE_WRITE_LINE_MEMBER( intext_w ) { change_mode(MODE_INTEXT, state); } | |
| 510 | DECLARE_WRITE_LINE_MEMBER( inv_w ) { change_mode(MODE_INV, state); } | |
| 511 | ||
| 512 | protected: | |
| 513 | mc6847_base_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const UINT8 *fontdata, double tpfs); | |
| 514 | ||
| 515 | // device-level overrides | |
| 516 | virtual void device_start(); | |
| 517 | virtual void device_reset(); | |
| 518 | virtual ioport_constructor device_input_ports() const; | |
| 519 | ||
| 520 | // other overrides | |
| 521 | virtual void field_sync_changed(bool line); | |
| 522 | virtual void record_body_scanline(UINT16 physical_scanline, UINT16 scanline); | |
| 523 | virtual void record_partial_body_scanline(UINT16 physical_scanline, UINT16 logical_scanline, INT32 start_clock, INT32 end_clock); | |
| 524 | ||
| 525 | private: | |
| 526 | struct video_scanline | |
| 527 | { | |
| 528 | UINT8 m_sample_count; | |
| 529 | UINT8 m_mode[32]; | |
| 530 | UINT8 m_data[32]; | |
| 531 | }; | |
| 532 | ||
| 533 | // palette | |
| 534 | static const int PALETTE_LENGTH = 16; | |
| 535 | static const UINT32 s_palette[PALETTE_LENGTH]; | |
| 536 | ||
| 537 | // callbacks | |
| 538 | devcb_resolved_read8 m_res_input_func; | |
| 539 | UINT8 (*m_get_char_rom)(running_machine &machine, UINT8 ch, int line); | |
| 540 | ||
| 541 | // incidentals | |
| 542 | UINT8 m_fixed_mode; | |
| 543 | UINT8 m_fixed_mode_mask; | |
| 544 | const pixel_t *m_palette; | |
| 545 | pixel_t m_bw_palette[PALETTE_LENGTH]; | |
| 546 | ||
| 547 | // state | |
| 548 | UINT8 m_mode; | |
| 549 | UINT16 m_video_address; | |
| 550 | bool m_dirty; | |
| 551 | video_scanline m_data[192]; | |
| 552 | ||
| 553 | void change_mode(UINT8 mode, int state) | |
| 554 | { | |
| 555 | // sanity check, to ensure that we're not changing fixed modes | |
| 556 | assert((mode & m_fixed_mode_mask) == 0); | |
| 557 | ||
| 558 | // calculate new mode | |
| 559 | UINT8 new_mode; | |
| 560 | if (state) | |
| 561 | new_mode = m_mode | mode; | |
| 562 | else | |
| 563 | new_mode = m_mode & ~mode; | |
| 564 | ||
| 565 | // has the mode changed? | |
| 566 | if (new_mode != m_mode) | |
| 567 | { | |
| 568 | // it has! check dirty flag | |
| 569 | video_flush(); | |
| 570 | if (!m_dirty) | |
| 571 | { | |
| 572 | m_dirty = true; | |
| 573 | } | |
| 574 | ||
| 575 | // and set the new mode | |
| 576 | m_mode = new_mode; | |
| 577 | } | |
| 578 | } | |
| 579 | ||
| 580 | // setup functions | |
| 581 | void setup_fixed_mode(struct devcb_read_line callback, UINT8 mode); | |
| 582 | ||
| 583 | // runtime functions | |
| 584 | void record_body_scanline(UINT16 physical_scanline, UINT16 scanline, INT32 start_pos, INT32 end_pos); | |
| 585 | pixel_t border_value(UINT8 mode, const pixel_t *palette, bool is_mc6847t1); | |
| 586 | ||
| 587 | template<int xscale> | |
| 588 | void emit_samples(UINT8 mode, const UINT8 *data, int length, pixel_t *pixels, int x, int y); | |
| 589 | ||
| 590 | // template function for doing video update collection | |
| 591 | template<int sample_count, int yres> | |
| 592 | void record_scanline_res(int scanline, INT32 start_pos, INT32 end_pos); | |
| 593 | ||
| 594 | // miscellaneous | |
| 595 | UINT8 input(UINT16 address); | |
| 596 | INT32 scanline_position_from_clock(INT32 clocks_since_hsync); | |
| 597 | }; | |
| 598 | ||
| 599 | ||
| 600 | //************************************************************************** | |
| 601 | // VARIATIONS | |
| 602 | //************************************************************************** | |
| 603 | ||
| 604 | class mc6847_ntsc_device : public mc6847_base_device | |
| 605 | { | |
| 606 | public: | |
| 607 | mc6847_ntsc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); | |
| 608 | }; | |
| 609 | ||
| 610 | class mc6847_pal_device : public mc6847_base_device | |
| 611 | { | |
| 612 | public: | |
| 613 | mc6847_pal_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); | |
| 614 | }; | |
| 615 | ||
| 616 | class mc6847y_ntsc_device : public mc6847_base_device | |
| 617 | { | |
| 618 | public: | |
| 619 | mc6847y_ntsc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); | |
| 620 | }; | |
| 621 | ||
| 622 | class mc6847y_pal_device : public mc6847_base_device | |
| 623 | { | |
| 624 | public: | |
| 625 | mc6847y_pal_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); | |
| 626 | }; | |
| 627 | ||
| 628 | class mc6847t1_ntsc_device : public mc6847_base_device | |
| 629 | { | |
| 630 | public: | |
| 631 | mc6847t1_ntsc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); | |
| 632 | }; | |
| 633 | ||
| 634 | class mc6847t1_pal_device : public mc6847_base_device | |
| 635 | { | |
| 636 | public: | |
| 637 | mc6847t1_pal_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); | |
| 638 | }; | |
| 639 | ||
| 640 | ||
| 641 | extern const device_type MC6847_NTSC; | |
| 642 | extern const device_type MC6847_PAL; | |
| 643 | extern const device_type MC6847Y_NTSC; | |
| 644 | extern const device_type MC6847Y_PAL; | |
| 645 | extern const device_type MC6847T1_NTSC; | |
| 646 | extern const device_type MC6847T1_PAL; | |
| 647 | ||
| 648 | #endif /* __MC6847__ */ |
| Added: svn:mime-type + text/plain Added: svn:eol-style + native |
| r0 | r21685 | |
|---|---|---|
| 1 | /*************************************************************************** | |
| 2 | ||
| 3 | Hitachi HD44352 LCD controller | |
| 4 | ||
| 5 | ***************************************************************************/ | |
| 6 | ||
| 7 | #pragma once | |
| 8 | ||
| 9 | #ifndef __hd44352_H__ | |
| 10 | #define __hd44352_H__ | |
| 11 | ||
| 12 | ||
| 13 | #define MCFG_HD44352_ADD( _tag, _clock, _config) \ | |
| 14 | MCFG_DEVICE_ADD( _tag, HD44352, _clock ) \ | |
| 15 | MCFG_DEVICE_CONFIG( _config ) | |
| 16 | ||
| 17 | //************************************************************************** | |
| 18 | // TYPE DEFINITIONS | |
| 19 | //************************************************************************** | |
| 20 | ||
| 21 | ||
| 22 | // ======================> hd44352_interface | |
| 23 | ||
| 24 | struct hd44352_interface | |
| 25 | { | |
| 26 | devcb_write_line m_on_cb; // ON line | |
| 27 | }; | |
| 28 | ||
| 29 | // ======================> hd44352_device | |
| 30 | ||
| 31 | class hd44352_device : | |
| 32 | public device_t, | |
| 33 | public hd44352_interface | |
| 34 | { | |
| 35 | public: | |
| 36 | // construction/destruction | |
| 37 | hd44352_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); | |
| 38 | ||
| 39 | // device interface | |
| 40 | UINT8 data_read(); | |
| 41 | void data_write(UINT8 data); | |
| 42 | void control_write(UINT8 data); | |
| 43 | ||
| 44 | UINT32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); | |
| 45 | ||
| 46 | protected: | |
| 47 | // device-level overrides | |
| 48 | virtual void device_start(); | |
| 49 | virtual void device_reset(); | |
| 50 | virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); | |
| 51 | virtual void device_config_complete(); | |
| 52 | virtual void device_validity_check(validity_checker &valid) const; | |
| 53 | ||
| 54 | private: | |
| 55 | UINT8 compute_newval(UINT8 type, UINT8 oldval, UINT8 newval); | |
| 56 | UINT8 get_char(UINT16 pos); | |
| 57 | ||
| 58 | static const device_timer_id ON_TIMER = 1; | |
| 59 | emu_timer *m_on_timer; | |
| 60 | ||
| 61 | UINT8 m_video_ram[2][0x180]; | |
| 62 | UINT8 m_control_lines; | |
| 63 | UINT8 m_data_bus; | |
| 64 | UINT8 m_par[3]; | |
| 65 | UINT8 m_state; | |
| 66 | UINT16 m_bank; | |
| 67 | UINT16 m_offset; | |
| 68 | UINT8 m_char_width; | |
| 69 | UINT8 m_lcd_on; | |
| 70 | UINT8 m_scroll; | |
| 71 | UINT32 m_contrast; | |
| 72 | ||
| 73 | UINT8 m_custom_char[4][8]; // 4 chars * 8 bytes | |
| 74 | UINT8 m_byte_count; | |
| 75 | UINT8 m_cursor_status; | |
| 76 | UINT8 m_cursor[8]; | |
| 77 | UINT8 m_cursor_x; | |
| 78 | UINT8 m_cursor_y; | |
| 79 | UINT8 m_cursor_lcd; | |
| 80 | ||
| 81 | devcb_resolved_write_line m_on; // ON line callback | |
| 82 | }; | |
| 83 | ||
| 84 | // device type definition | |
| 85 | extern const device_type HD44352; | |
| 86 | ||
| 87 | #endif |
| Added: svn:mime-type + text/plain Added: svn:eol-style + native |
| r0 | r21685 | |
|---|---|---|
| 1 | /********************************************************************** | |
| 2 | ||
| 3 | Intel 82720 Graphics Display Controller emulation | |
| 4 | ||
| 5 | Copyright MESS Team. | |
| 6 | Visit http://mamedev.org for licensing and usage restrictions. | |
| 7 | ||
| 8 | **********************************************************************/ | |
| 9 | ||
| 10 | /* | |
| 11 | ||
| 12 | TODO: | |
| 13 | ||
| 14 | - implement FIFO as ring buffer | |
| 15 | - commands | |
| 16 | - DMAR | |
| 17 | - DMAW | |
| 18 | - incomplete / unimplemented FIGD / GCHRD draw modes | |
| 19 | - Arc | |
| 20 | - FIGD character | |
| 21 | - slanted character | |
| 22 | - GCHRD character (needs rewrite) | |
| 23 | - read-modify-write cycle | |
| 24 | - read data | |
| 25 | - modify data | |
| 26 | - write data | |
| 27 | - QX-10 diagnostic test has positioning bugs with the bitmap display test; | |
| 28 | - QX-10 diagnostic test misses the zooming factor (external pin); | |
| 29 | - compis2 SAD address for bitmap is 0x20000 for whatever reason (presumably missing banking); | |
| 30 | - A5105 has a FIFO bug with the RDAT, should be a lot larger when it scrolls up. | |
| 31 | The problem is that DMA-ing with RDAT/WDAT shouldn't be instant; | |
| 32 | ||
| 33 | - honor visible area | |
| 34 | - wide mode (32-bit access) | |
| 35 | - light pen | |
| 36 | ||
| 37 | */ | |
| 38 | ||
| 39 | #include "emu.h" | |
| 40 | #include "upd7220.h" | |
| 41 | ||
| 42 | ||
| 43 | ||
| 44 | //************************************************************************** | |
| 45 | // MACROS / CONSTANTS | |
| 46 | //************************************************************************** | |
| 47 | ||
| 48 | #define VERBOSE 0 | |
| 49 | #define LOG(x) do { if (VERBOSE) logerror x; } while (0) | |
| 50 | ||
| 51 | ||
| 52 | // todo typedef | |
| 53 | enum | |
| 54 | { | |
| 55 | COMMAND_INVALID = -1, | |
| 56 | COMMAND_RESET, | |
| 57 | COMMAND_SYNC, | |
| 58 | COMMAND_VSYNC, | |
| 59 | COMMAND_CCHAR, | |
| 60 | COMMAND_START, | |
| 61 | COMMAND_BCTRL, | |
| 62 | COMMAND_ZOOM, | |
| 63 | COMMAND_CURS, | |
| 64 | COMMAND_PRAM, | |
| 65 | COMMAND_PITCH, | |
| 66 | COMMAND_WDAT, | |
| 67 | COMMAND_MASK, | |
| 68 | COMMAND_FIGS, | |
| 69 | COMMAND_FIGD, | |
| 70 | COMMAND_GCHRD, | |
| 71 | COMMAND_RDAT, | |
| 72 | COMMAND_CURD, | |
| 73 | COMMAND_LPRD, | |
| 74 | COMMAND_DMAR, | |
| 75 | COMMAND_DMAW, | |
| 76 | COMMAND_5A | |
| 77 | }; | |
| 78 | ||
| 79 | enum | |
| 80 | { | |
| 81 | FIFO_READ = 0, | |
| 82 | FIFO_WRITE | |
| 83 | }; | |
| 84 | ||
| 85 | enum | |
| 86 | { | |
| 87 | FIFO_EMPTY = -1, | |
| 88 | FIFO_PARAMETER, | |
| 89 | FIFO_COMMAND | |
| 90 | }; | |
| 91 | ||
| 92 | #define UPD7220_COMMAND_RESET 0x00 | |
| 93 | #define UPD7220_COMMAND_SYNC 0x0e // & 0xfe | |
| 94 | #define UPD7220_COMMAND_VSYNC 0x6e // & 0xfe | |
| 95 | #define UPD7220_COMMAND_CCHAR 0x4b | |
| 96 | #define UPD7220_COMMAND_START 0x6b | |
| 97 | #define UPD7220_COMMAND_BCTRL 0x0c // & 0xfe | |
| 98 | #define UPD7220_COMMAND_ZOOM 0x46 | |
| 99 | #define UPD7220_COMMAND_CURS 0x49 | |
| 100 | #define UPD7220_COMMAND_PRAM 0x70 // & 0xf0 | |
| 101 | #define UPD7220_COMMAND_PITCH 0x47 | |
| 102 | #define UPD7220_COMMAND_WDAT 0x20 // & 0xe4 | |
| 103 | #define UPD7220_COMMAND_MASK 0x4a | |
| 104 | #define UPD7220_COMMAND_FIGS 0x4c | |
| 105 | #define UPD7220_COMMAND_FIGD 0x6c | |
| 106 | #define UPD7220_COMMAND_GCHRD 0x68 | |
| 107 | #define UPD7220_COMMAND_RDAT 0xa0 // & 0xe4 | |
| 108 | #define UPD7220_COMMAND_CURD 0xe0 | |
| 109 | #define UPD7220_COMMAND_LPRD 0xc0 | |
| 110 | #define UPD7220_COMMAND_DMAR 0xa4 // & 0xe4 | |
| 111 | #define UPD7220_COMMAND_DMAW 0x24 // & 0xe4 | |
| 112 | #define UPD7220_COMMAND_5A 0x5a | |
| 113 | ||
| 114 | #define UPD7220_SR_DATA_READY 0x01 | |
| 115 | #define UPD7220_SR_FIFO_FULL 0x02 | |
| 116 | #define UPD7220_SR_FIFO_EMPTY 0x04 | |
| 117 | #define UPD7220_SR_DRAWING_IN_PROGRESS 0x08 | |
| 118 | #define UPD7220_SR_DMA_EXECUTE 0x10 | |
| 119 | #define UPD7220_SR_VSYNC_ACTIVE 0x20 | |
| 120 | #define UPD7220_SR_HBLANK_ACTIVE 0x40 | |
| 121 | #define UPD7220_SR_LIGHT_PEN_DETECT 0x80 | |
| 122 | ||
| 123 | #define UPD7220_MODE_S 0x01 | |
| 124 | #define UPD7220_MODE_REFRESH_RAM 0x04 | |
| 125 | #define UPD7220_MODE_I 0x08 | |
| 126 | #define UPD7220_MODE_DRAW_ON_RETRACE 0x10 | |
| 127 | #define UPD7220_MODE_DISPLAY_MASK 0x22 | |
| 128 | #define UPD7220_MODE_DISPLAY_MIXED 0x00 | |
| 129 | #define UPD7220_MODE_DISPLAY_GRAPHICS 0x02 | |
| 130 | #define UPD7220_MODE_DISPLAY_CHARACTER 0x20 | |
| 131 | #define UPD7220_MODE_DISPLAY_INVALID 0x22 | |
| 132 | ||
| 133 | static const int x_dir[8] = { 0, 1, 1, 1, 0,-1,-1,-1}; | |
| 134 | static const int y_dir[8] = { 1, 1, 0,-1,-1,-1, 0, 1}; | |
| 135 | static const int x_dir_dot[8] = { 1, 1, 0,-1,-1,-1, 0, 1}; | |
| 136 | static const int y_dir_dot[8] = { 0,-1,-1,-1, 0, 1, 1, 1}; | |
| 137 | ||
| 138 | ||
| 139 | ||
| 140 | //************************************************************************** | |
| 141 | // GLOBAL VARIABLES | |
| 142 | //************************************************************************** | |
| 143 | ||
| 144 | // devices | |
| 145 | const device_type UPD7220 = &device_creator<upd7220_device>; | |
| 146 | ||
| 147 | ||
| 148 | // default address map | |
| 149 | static ADDRESS_MAP_START( upd7220_vram, AS_0, 8, upd7220_device ) | |
| 150 | AM_RANGE(0x00000, 0x3ffff) AM_RAM | |
| 151 | ADDRESS_MAP_END | |
| 152 | ||
| 153 | ||
| 154 | // internal 128x14 control ROM | |
| 155 | ROM_START( upd7220 ) | |
| 156 | ROM_REGION( 0x100, "upd7220", 0 ) | |
| 157 | ROM_LOAD( "upd7220.bin", 0x000, 0x100, NO_DUMP ) | |
| 158 | ROM_END | |
| 159 | ||
| 160 | ||
| 161 | //------------------------------------------------- | |
| 162 | // memory_space_config - return a description of | |
| 163 | // any address spaces owned by this device | |
| 164 | //------------------------------------------------- | |
| 165 | ||
| 166 | const address_space_config *upd7220_device::memory_space_config(address_spacenum spacenum) const | |
| 167 | { | |
| 168 | return (spacenum == AS_0) ? &m_space_config : NULL; | |
| 169 | } | |
| 170 | ||
| 171 | ||
| 172 | //------------------------------------------------- | |
| 173 | // rom_region - device-specific ROM region | |
| 174 | //------------------------------------------------- | |
| 175 | ||
| 176 | const rom_entry *upd7220_device::device_rom_region() const | |
| 177 | { | |
| 178 | return ROM_NAME( upd7220 ); | |
| 179 | } | |
| 180 | ||
| 181 | ||
| 182 | //------------------------------------------------- | |
| 183 | // device_config_complete - perform any | |
| 184 | // operations now that the configuration is | |
| 185 | // complete | |
| 186 | //------------------------------------------------- | |
| 187 | ||
| 188 | void upd7220_device::device_config_complete() | |
| 189 | { | |
| 190 | // inherit a copy of the static data | |
| 191 | const upd7220_interface *intf = reinterpret_cast<const upd7220_interface *>(static_config()); | |
| 192 | if (intf != NULL) | |
| 193 | *static_cast<upd7220_interface *>(this) = *intf; | |
| 194 | ||
| 195 | // or initialize to defaults if none provided | |
| 196 | else | |
| 197 | { | |
| 198 | memset(&m_out_drq_cb, 0, sizeof(m_out_drq_cb)); | |
| 199 | memset(&m_out_hsync_cb, 0, sizeof(m_out_hsync_cb)); | |
| 200 | memset(&m_out_vsync_cb, 0, sizeof(m_out_vsync_cb)); | |
| 201 | memset(&m_out_blank_cb, 0, sizeof(m_out_blank_cb)); | |
| 202 | } | |
| 203 | } | |
| 204 | ||
| 205 | ||
| 206 | ||
| 207 | //************************************************************************** | |
| 208 | // INLINE HELPERS | |
| 209 | //************************************************************************** | |
| 210 | ||
| 211 | //------------------------------------------------- | |
| 212 | // readbyte - read a byte at the given address | |
| 213 | //------------------------------------------------- | |
| 214 | ||
| 215 | inline UINT8 upd7220_device::readbyte(offs_t address) | |
| 216 | { | |
| 217 | return space().read_byte(address); | |
| 218 | } | |
| 219 | ||
| 220 | ||
| 221 | //------------------------------------------------- | |
| 222 | // writebyte - write a byte at the given address | |
| 223 | //------------------------------------------------- | |
| 224 | ||
| 225 | inline void upd7220_device::writebyte(offs_t address, UINT8 data) | |
| 226 | { | |
| 227 | space().write_byte(address, data); | |
| 228 | } | |
| 229 | ||
| 230 | ||
| 231 | //------------------------------------------------- | |
| 232 | // fifo_clear - | |
| 233 | //------------------------------------------------- | |
| 234 | ||
| 235 | inline void upd7220_device::fifo_clear() | |
| 236 | { | |
| 237 | for (int i = 0; i < 16; i++) | |
| 238 | { | |
| 239 | m_fifo[i] = 0; | |
| 240 | m_fifo_flag[i] = FIFO_EMPTY; | |
| 241 | } | |
| 242 | ||
| 243 | m_fifo_ptr = -1; | |
| 244 | ||
| 245 | m_sr &= ~UPD7220_SR_DATA_READY; | |
| 246 | m_sr |= UPD7220_SR_FIFO_EMPTY; | |
| 247 | m_sr &= ~UPD7220_SR_FIFO_FULL; | |
| 248 | } | |
| 249 | ||
| 250 | ||
| 251 | //------------------------------------------------- | |
| 252 | // fifo_param_count - | |
| 253 | //------------------------------------------------- | |
| 254 | ||
| 255 | inline int upd7220_device::fifo_param_count() | |
| 256 | { | |
| 257 | int i; | |
| 258 | ||
| 259 | for (i = 0; i < 16; i++) | |
| 260 | { | |
| 261 | if (m_fifo_flag[i] != FIFO_PARAMETER) break; | |
| 262 | } | |
| 263 | ||
| 264 | return i; | |
| 265 | } | |
| 266 | ||
| 267 | ||
| 268 | //------------------------------------------------- | |
| 269 | // fifo_set_direction - | |
| 270 | //------------------------------------------------- | |
| 271 | ||
| 272 | inline void upd7220_device::fifo_set_direction(int dir) | |
| 273 | { | |
| 274 | if (m_fifo_dir != dir) | |
| 275 | { | |
| 276 | fifo_clear(); | |
| 277 | } | |
| 278 | ||
| 279 | m_fifo_dir = dir; | |
| 280 | } | |
| 281 | ||
| 282 | ||
| 283 | //------------------------------------------------- | |
| 284 | // queue - | |
| 285 | //------------------------------------------------- | |
| 286 | ||
| 287 | inline void upd7220_device::queue(UINT8 data, int flag) | |
| 288 | { | |
| 289 | if (m_fifo_ptr < 15) | |
| 290 | { | |
| 291 | m_fifo_ptr++; | |
| 292 | ||
| 293 | m_fifo[m_fifo_ptr] = data; | |
| 294 | m_fifo_flag[m_fifo_ptr] = flag; | |
| 295 | ||
| 296 | if (m_fifo_ptr == 16) | |
| 297 | { | |
| 298 | m_sr |= UPD7220_SR_FIFO_FULL; | |
| 299 | } | |
| 300 | ||
| 301 | m_sr &= ~UPD7220_SR_FIFO_EMPTY; | |
| 302 | } | |
| 303 | else | |
| 304 | { | |
| 305 | // TODO what happen? somebody set us up the bomb | |
| 306 | printf("FIFO?\n"); | |
| 307 | } | |
| 308 | } | |
| 309 | ||
| 310 | ||
| 311 | //------------------------------------------------- | |
| 312 | // dequeue - | |
| 313 | //------------------------------------------------- | |
| 314 | ||
| 315 | inline void upd7220_device::dequeue(UINT8 *data, int *flag) | |
| 316 | { | |
| 317 | *data = m_fifo[0]; | |
| 318 | *flag = m_fifo_flag[0]; | |
| 319 | ||
| 320 | if (m_fifo_ptr > -1) | |
| 321 | { | |
| 322 | for (int i = 0; i < 15; i++) | |
| 323 | { | |
| 324 | m_fifo[i] = m_fifo[i + 1]; | |
| 325 | m_fifo_flag[i] = m_fifo_flag[i + 1]; | |
| 326 | } | |
| 327 | ||
| 328 | m_fifo[15] = 0; | |
| 329 | m_fifo_flag[15] = 0; | |
| 330 | ||
| 331 | m_fifo_ptr--; | |
| 332 | ||
| 333 | if (m_fifo_ptr == -1) | |
| 334 | { | |
| 335 | m_sr &= ~UPD7220_SR_DATA_READY; | |
| 336 | m_sr |= UPD7220_SR_FIFO_EMPTY; | |
| 337 | } | |
| 338 | } | |
| 339 | } | |
| 340 | ||
| 341 | ||
| 342 | //------------------------------------------------- | |
| 343 | // update_vsync_timer - | |
| 344 | //------------------------------------------------- | |
| 345 | ||
| 346 | inline void upd7220_device::update_vsync_timer(int state) | |
| 347 | { | |
| 348 | int next_y = state ? m_vs : 0; | |
| 349 | ||
| 350 | attotime duration = m_screen->time_until_pos(next_y, 0); | |
| 351 | ||
| 352 | m_vsync_timer->adjust(duration, !state); | |
| 353 | } | |
| 354 | ||
| 355 | ||
| 356 | //------------------------------------------------- | |
| 357 | // update_hsync_timer - | |
| 358 | //------------------------------------------------- | |
| 359 | ||
| 360 | inline void upd7220_device::update_hsync_timer(int state) | |
| 361 | { | |
| 362 | int y = m_screen->vpos(); | |
| 363 | ||
| 364 | int next_x = state ? m_hs : 0; | |
| 365 | int next_y = state ? y : ((y + 1) % m_al); | |
| 366 | ||
| 367 | attotime duration = m_screen->time_until_pos(next_y, next_x); | |
| 368 | ||
| 369 | m_hsync_timer->adjust(duration, !state); | |
| 370 | } | |
| 371 | ||
| 372 | ||
| 373 | //------------------------------------------------- | |
| 374 | // update_blank_timer - | |
| 375 | //------------------------------------------------- | |
| 376 | ||
| 377 | inline void upd7220_device::update_blank_timer(int state) | |
| 378 | { | |
| 379 | int y = m_screen->vpos(); | |
| 380 | ||
| 381 | int next_x = state ? (m_hs + m_hbp) : (m_hs + m_hbp + (m_aw << 3)); | |
| 382 | int next_y = state ? ((y + 1) % (m_vs + m_vbp + m_al + m_vfp - 1)) : y; | |
| 383 | ||
| 384 | attotime duration = m_screen->time_until_pos(next_y, next_x); | |
| 385 | ||
| 386 | m_hsync_timer->adjust(duration, !state); | |
| 387 | } | |
| 388 | ||
| 389 | ||
| 390 | //------------------------------------------------- | |
| 391 | // recompute_parameters - | |
| 392 | //------------------------------------------------- | |
| 393 | ||
| 394 | inline void upd7220_device::recompute_parameters() | |
| 395 | { | |
| 396 | /* TODO: assume that the pitch also controls number of horizontal pixels in a single cell */ | |
| 397 | int horiz_mult = ((m_pitch == 40) ? 16 : 8); | |
| 398 | int horiz_pix_total = (m_hs + m_hbp + m_aw + m_hfp) * horiz_mult; | |
| 399 | int vert_pix_total = m_vs + m_vbp + m_al + m_vfp; | |
| 400 | ||
| 401 | //printf("%d %d %d %d\n",m_hs,m_hbp,m_aw,m_hfp); | |
| 402 | //printf("%d %d\n",m_aw * 8,m_pitch * 8); | |
| 403 | ||
| 404 | if (horiz_pix_total == 0 || vert_pix_total == 0) //bail out if screen params aren't valid | |
| 405 | return; | |
| 406 | ||
| 407 | attoseconds_t refresh = HZ_TO_ATTOSECONDS(clock() * horiz_mult) * horiz_pix_total * vert_pix_total; | |
| 408 | ||
| 409 | rectangle visarea; | |
| 410 | ||
| 411 | visarea.min_x = 0; //(m_hs + m_hbp) * 8; | |
| 412 | visarea.min_y = 0; //m_vs + m_vbp; | |
| 413 | visarea.max_x = m_aw * horiz_mult - 1;//horiz_pix_total - (m_hfp * 8) - 1; | |
| 414 | visarea.max_y = m_al - 1;//vert_pix_total - m_vfp - 1; | |
| 415 | ||
| 416 | LOG(("uPD7220 '%s' Screen: %u x %u @ %f Hz\n", tag(), horiz_pix_total, vert_pix_total, 1 / ATTOSECONDS_TO_DOUBLE(refresh))); | |
| 417 | LOG(("Visible Area: (%u, %u) - (%u, %u)\n", visarea.min_x, visarea.min_y, visarea.max_x, visarea.max_y)); | |
| 418 | LOG(("%d %d %d %d %d\n",m_hs,m_hbp,m_aw,m_hfp,m_pitch)); | |
| 419 | LOG(("%d %d %d %d\n",m_vs,m_vbp,m_al,m_vfp)); | |
| 420 | ||
| 421 | if (m_m) | |
| 422 | { | |
| 423 | m_screen->configure(horiz_pix_total, vert_pix_total, visarea, refresh); | |
| 424 | ||
| 425 | update_hsync_timer(0); | |
| 426 | update_vsync_timer(0); | |
| 427 | } | |
| 428 | else | |
| 429 | { | |
| 430 | m_hsync_timer->enable(0); | |
| 431 | m_vsync_timer->enable(0); | |
| 432 | } | |
| 433 | ||
| 434 | update_blank_timer(0); | |
| 435 | } | |
| 436 | ||
| 437 | ||
| 438 | //------------------------------------------------- | |
| 439 | // reset_figs_param - | |
| 440 | //------------------------------------------------- | |
| 441 | ||
| 442 | inline void upd7220_device::reset_figs_param() | |
| 443 | { | |
| 444 | m_figs.m_dc = 0x0000; | |
| 445 | m_figs.m_d = 0x0008; | |
| 446 | m_figs.m_d1 = 0x0008; | |
| 447 | m_figs.m_d2 = 0x0000; | |
| 448 | m_figs.m_dm = 0x0000; | |
| 449 | } | |
| 450 | ||
| 451 | ||
| 452 | //------------------------------------------------- | |
| 453 | // advance_ead - | |
| 454 | //------------------------------------------------- | |
| 455 | ||
| 456 | inline void upd7220_device::advance_ead() | |
| 457 | { | |
| 458 | #define EAD m_ead | |
| 459 | #define DAD m_dad | |
| 460 | #define P x_dir[m_figs.m_dir] + (y_dir[m_figs.m_dir] * m_pitch) | |
| 461 | #define MSB(value) (BIT(value, 15)) | |
| 462 | #define LSB(value) (BIT(value, 0)) | |
| 463 | #define LR(value) ((value << 1) | MSB(value)) | |
| 464 | #define RR(value) ((LSB(value) << 15) | (value >> 1)) | |
| 465 | ||
| 466 | switch (m_draw_mode & 0x07) | |
| 467 | { | |
| 468 | case 0: | |
| 469 | EAD += P; | |
| 470 | break; | |
| 471 | ||
| 472 | case 1: | |
| 473 | EAD += P; | |
| 474 | if (MSB(DAD)) EAD++; | |
| 475 | DAD = LR(DAD); | |
| 476 | break; | |
| 477 | ||
| 478 | case 2: | |
| 479 | if (MSB(DAD)) EAD++; | |
| 480 | DAD = LR(DAD); | |
| 481 | break; | |
| 482 | ||
| 483 | case 3: | |
| 484 | EAD -= P; | |
| 485 | if (MSB(DAD)) EAD++; | |
| 486 | DAD = LR(DAD); | |
| 487 | break; | |
| 488 | ||
| 489 | case 4: | |
| 490 | EAD -= P; | |
| 491 | break; | |
| 492 | ||
| 493 | case 5: | |
| 494 | EAD -= P; | |
| 495 | if (LSB(DAD)) EAD--; | |
| 496 | DAD = RR(DAD); | |
| 497 | break; | |
| 498 | ||
| 499 | case 6: | |
| 500 | if (LSB(DAD)) EAD--; | |
| 501 | DAD = RR(DAD); | |
| 502 | break; | |
| 503 | ||
| 504 | case 7: | |
| 505 | EAD += P; | |
| 506 | if (LSB(DAD)) EAD--; | |
| 507 | DAD = RR(DAD); | |
| 508 | break; | |
| 509 | } | |
| 510 | ||
| 511 | EAD &= 0x3ffff; | |
| 512 | } | |
| 513 | ||
| 514 | ||
| 515 | //------------------------------------------------- | |
| 516 | // read_vram - | |
| 517 | //------------------------------------------------- | |
| 518 | ||
| 519 | inline void upd7220_device::read_vram(UINT8 type, UINT8 mod) | |
| 520 | { | |
| 521 | if (type == 1) | |
| 522 | { | |
| 523 | LOG (("uPD7220 invalid type 1 RDAT parameter\n")); | |
| 524 | return; | |
| 525 | } | |
| 526 | ||
| 527 | if (mod) | |
| 528 | LOG (("uPD7220 RDAT used with mod = %02x?\n",mod)); | |
| 529 | ||
| 530 | for (int i = 0; i < m_figs.m_dc; i++) | |
| 531 | { | |
| 532 | switch(type) | |
| 533 | { | |
| 534 | case 0: | |
| 535 | queue(readbyte(m_ead*2), 0); | |
| 536 | queue(readbyte(m_ead*2+1), 0); | |
| 537 | break; | |
| 538 | case 2: | |
| 539 | queue(readbyte(m_ead*2), 0); | |
| 540 | break; | |
| 541 | case 3: | |
| 542 | queue(readbyte(m_ead*2+1), 0); | |
| 543 | break; | |
| 544 | } | |
| 545 | ||
| 546 | advance_ead(); | |
| 547 | } | |
| 548 | } | |
| 549 | ||
| 550 | ||
| 551 | //------------------------------------------------- | |
| 552 | // write_vram - | |
| 553 | //------------------------------------------------- | |
| 554 | ||
| 555 | inline void upd7220_device::write_vram(UINT8 type, UINT8 mod) | |
| 556 | { | |
| 557 | UINT16 result; | |
| 558 | ||
| 559 | if (type == 1) | |
| 560 | { | |
| 561 | printf("uPD7220 invalid type 1 WDAT parameter\n"); | |
| 562 | return; | |
| 563 | } | |
| 564 | ||
| 565 | result = 0; | |
| 566 | ||
| 567 | switch(type) | |
| 568 | { | |
| 569 | case 0: | |
| 570 | result = (m_pr[1] & 0xff); | |
| 571 | result |= (m_pr[2] << 8); | |
| 572 | result &= m_mask; | |
| 573 | break; | |
| 574 | case 2: | |
| 575 | result = (m_pr[1] & 0xff); | |
| 576 | result &= (m_mask & 0xff); | |
| 577 | break; | |
| 578 | case 3: | |
| 579 | result = (m_pr[1] << 8); | |
| 580 | result &= (m_mask & 0xff00); | |
| 581 | break; | |
| 582 | } | |
| 583 | ||
| 584 | //if(result) | |
| 585 | { | |
| 586 | //printf("%04x %02x %02x %04x %02x %02x\n",readbyte(m_ead),m_pr[1],m_pr[2],m_mask,type,mod); | |
| 587 | //printf("%04x %02x %02x\n",m_ead,m_figs.m_dir,m_pitch); | |
| 588 | //printf("%04x %04x %02x %04x\n",m_ead,result,mod,m_figs.m_dc); | |
| 589 | } | |
| 590 | ||
| 591 | for(int i = 0; i < m_figs.m_dc + 1; i++) | |
| 592 | { | |
| 593 | switch(mod & 3) | |
| 594 | { | |
| 595 | case 0x00: //replace | |
| 596 | if(type == 0 || type == 2) | |
| 597 | writebyte(m_ead*2+0, result & 0xff); | |
| 598 | if(type == 0 || type == 3) | |
| 599 | writebyte(m_ead*2+1, result >> 8); | |
| 600 | break; | |
| 601 | case 0x01: //complement | |
| 602 | if(type == 0 || type == 2) | |
| 603 | writebyte(m_ead*2+0, readbyte(m_ead*2+0) ^ (result & 0xff)); | |
| 604 | if(type == 0 || type == 3) | |
| 605 | writebyte(m_ead*2+1, readbyte(m_ead*2+1) ^ (result >> 8)); | |
| 606 | break; | |
| 607 | case 0x02: //reset to zero | |
| 608 | if(type == 0 || type == 2) | |
| 609 | writebyte(m_ead*2+0, readbyte(m_ead*2+0) & ~(result & 0xff)); | |
| 610 | if(type == 0 || type == 3) | |
| 611 | writebyte(m_ead*2+1, readbyte(m_ead*2+1) & ~(result >> 8)); | |
| 612 | break; | |
| 613 | case 0x03: //set to one | |
| 614 | if(type == 0 || type == 2) | |
| 615 | writebyte(m_ead*2+0, readbyte(m_ead*2+0) | (result & 0xff)); | |
| 616 | if(type == 0 || type == 3) | |
| 617 | writebyte(m_ead*2+1, readbyte(m_ead*2+1) | (result >> 8)); | |
| 618 | break; | |
| 619 | } | |
| 620 | ||
| 621 | advance_ead(); | |
| 622 | } | |
| 623 | } | |
| 624 | ||
| 625 | ||
| 626 | //------------------------------------------------- | |
| 627 | // check_pattern - | |
| 628 | //------------------------------------------------- | |
| 629 | ||
| 630 | inline UINT16 upd7220_device::check_pattern(UINT16 pattern) | |
| 631 | { | |
| 632 | UINT16 res = 0; | |
| 633 | ||
| 634 | switch (m_bitmap_mod & 3) | |
| 635 | { | |
| 636 | case 0: res = pattern; break; //replace | |
| 637 | case 1: res = pattern; break; //complement | |
| 638 | case 2: res = 0; break; //reset to zero | |
| 639 | case 3: res |= 0xffff; break; //set to one | |
| 640 | } | |
| 641 | ||
| 642 | return res; | |
| 643 | } | |
| 644 | ||
| 645 | ||
| 646 | //------------------------------------------------- | |
| 647 | // get_text_partition - | |
| 648 | //------------------------------------------------- | |
| 649 | ||
| 650 | inline void upd7220_device::get_text_partition(int index, UINT32 *sad, UINT16 *len, int *im, int *wd) | |
| 651 | { | |
| 652 | *sad = ((m_ra[(index * 4) + 1] & 0x1f) << 8) | m_ra[(index * 4) + 0]; | |
| 653 | *len = ((m_ra[(index * 4) + 3] & 0x3f) << 4) | (m_ra[(index * 4) + 2] >> 4); | |
| 654 | *im = BIT(m_ra[(index * 4) + 3], 6); | |
| 655 | *wd = BIT(m_ra[(index * 4) + 3], 7); | |
| 656 | } | |
| 657 | ||
| 658 | ||
| 659 | //------------------------------------------------- | |
| 660 | // get_graphics_partition - | |
| 661 | //------------------------------------------------- | |
| 662 | ||
| 663 | inline void upd7220_device::get_graphics_partition(int index, UINT32 *sad, UINT16 *len, int *im, int *wd) | |
| 664 | { | |
| 665 | *sad = ((m_ra[(index * 4) + 2] & 0x03) << 16) | (m_ra[(index * 4) + 1] << 8) | m_ra[(index * 4) + 0]; | |
| 666 | *len = ((m_ra[(index * 4) + 3] & 0x3f) << 4) | (m_ra[(index * 4) + 2] >> 4); | |
| 667 | *im = BIT(m_ra[(index * 4) + 3], 6); | |
| 668 | *wd = BIT(m_ra[(index * 4) + 3], 7); | |
| 669 | } | |
| 670 | ||
| 671 | ||
| 672 | ||
| 673 | //************************************************************************** | |
| 674 | // LIVE DEVICE | |
| 675 | //************************************************************************** | |
| 676 | ||
| 677 | //------------------------------------------------- | |
| 678 | // upd7220_device - constructor | |
| 679 | //------------------------------------------------- | |
| 680 | ||
| 681 | upd7220_device::upd7220_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) | |
| 682 | : device_t(mconfig, UPD7220, "uPD7220", tag, owner, clock), | |
| 683 | device_memory_interface(mconfig, *this), | |
| 684 | m_mask(0), | |
| 685 | m_pitch(0), | |
| 686 | m_ead(0), | |
| 687 | m_dad(0), | |
| 688 | m_lad(0), | |
| 689 | m_ra_addr(0), | |
| 690 | m_sr(UPD7220_SR_FIFO_EMPTY), | |
| 691 | m_cr(0), | |
| 692 | m_param_ptr(0), | |
| 693 | m_fifo_ptr(-1), | |
| 694 | m_fifo_dir(0), | |
| 695 | m_mode(0), | |
| 696 | m_draw_mode(0), | |
| 697 | m_de(0), | |
| 698 | m_m(0), | |
| 699 | m_aw(0), | |
| 700 | m_al(0), | |
| 701 | m_vs(0), | |
| 702 | m_vfp(0), | |
| 703 | m_vbp(0), | |
| 704 | m_hs(0), | |
| 705 | m_hfp(0), | |
| 706 | m_hbp(0), | |
| 707 | m_dc(0), | |
| 708 | m_sc(0), | |
| 709 | m_br(0), | |
| 710 | m_ctop(0), | |
| 711 | m_cbot(0), | |
| 712 | m_lr(0), | |
| 713 | m_disp(0), | |
| 714 | m_gchr(0), | |
| 715 | m_bitmap_mod(0), | |
| 716 | m_space_config("videoram", ENDIANNESS_LITTLE, 8, 18, 0, NULL, *ADDRESS_MAP_NAME(upd7220_vram)) | |
| 717 | { | |
| 718 | m_shortname = "upd7220"; | |
| 719 | for (int i = 0; i < 16; i++) | |
| 720 | { | |
| 721 | m_fifo[i] = 0; | |
| 722 | m_fifo_flag[i] = FIFO_EMPTY; | |
| 723 | ||
| 724 | m_ra[i] = 0; | |
| 725 | } | |
| 726 | ||
| 727 | for (int i = 0; i < 17; i++) | |
| 728 | { | |
| 729 | m_pr[i] = 0; | |
| 730 | } | |
| 731 | ||
| 732 | m_figs.m_dir = 0; | |
| 733 | m_figs.m_figure_type = 0; | |
| 734 | m_figs.m_dc = 0; | |
| 735 | m_figs.m_d = 0; | |
| 736 | m_figs.m_d1 = 0; | |
| 737 | m_figs.m_d2 = 0; | |
| 738 | m_figs.m_dm = 0; | |
| 739 | } | |
| 740 | ||
| 741 | ||
| 742 | //------------------------------------------------- | |
| 743 | // device_start - device-specific startup | |
| 744 | //------------------------------------------------- | |
| 745 | ||
| 746 | void upd7220_device::device_start() | |
| 747 | { | |
| 748 | // allocate timers | |
| 749 | m_vsync_timer = timer_alloc(TIMER_VSYNC); | |
| 750 | m_hsync_timer = timer_alloc(TIMER_HSYNC); | |
| 751 | m_blank_timer = timer_alloc(TIMER_BLANK); | |
| 752 | ||
| 753 | // resolve callbacks | |
| 754 | m_out_drq_func.resolve(m_out_drq_cb, *this); | |
| 755 | m_out_hsync_func.resolve(m_out_hsync_cb, *this); | |
| 756 | m_out_vsync_func.resolve(m_out_vsync_cb, *this); | |
| 757 | m_out_blank_func.resolve(m_out_blank_cb, *this); | |
| 758 | ||
| 759 | // find screen | |
| 760 | m_screen = machine().device<screen_device>(m_screen_tag); | |
| 761 | ||
| 762 | if (m_screen == NULL) | |
| 763 | { | |
| 764 | m_screen = owner()->subdevice<screen_device>(m_screen_tag); | |
| 765 | } | |
| 766 | ||
| 767 | assert(m_screen); | |
| 768 | ||
| 769 | // register for state saving | |
| 770 | save_item(NAME(m_ra)); | |
| 771 | save_item(NAME(m_sr)); | |
| 772 | save_item(NAME(m_mode)); | |
| 773 | save_item(NAME(m_de)); | |
| 774 | save_item(NAME(m_aw)); | |
| 775 | save_item(NAME(m_al)); | |
| 776 | save_item(NAME(m_vs)); | |
| 777 | save_item(NAME(m_vfp)); | |
| 778 | save_item(NAME(m_vbp)); | |
| 779 | save_item(NAME(m_hs)); | |
| 780 | save_item(NAME(m_hfp)); | |
| 781 | save_item(NAME(m_hbp)); | |
| 782 | save_item(NAME(m_m)); | |
| 783 | save_item(NAME(m_dc)); | |
| 784 | save_item(NAME(m_sc)); | |
| 785 | save_item(NAME(m_br)); | |
| 786 | save_item(NAME(m_lr)); | |
| 787 | save_item(NAME(m_ctop)); | |
| 788 | save_item(NAME(m_cbot)); | |
| 789 | save_item(NAME(m_ead)); | |
| 790 | save_item(NAME(m_dad)); | |
| 791 | save_item(NAME(m_lad)); | |
| 792 | save_item(NAME(m_disp)); | |
| 793 | save_item(NAME(m_gchr)); | |
| 794 | save_item(NAME(m_mask)); | |
| 795 | save_item(NAME(m_pitch)); | |
| 796 | } | |
| 797 | ||
| 798 | ||
| 799 | //------------------------------------------------- | |
| 800 | // device_reset - device-specific reset | |
| 801 | //------------------------------------------------- | |
| 802 | ||
| 803 | void upd7220_device::device_reset() | |
| 804 | { | |
| 805 | m_out_drq_func(CLEAR_LINE); | |
| 806 | } | |
| 807 | ||
| 808 | ||
| 809 | //------------------------------------------------- | |
| 810 | // device_timer - handler timer events | |
| 811 | //------------------------------------------------- | |
| 812 | ||
| 813 | void upd7220_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) | |
| 814 | { | |
| 815 | switch (id) | |
| 816 | { | |
| 817 | case TIMER_HSYNC: | |
| 818 | if (param) | |
| 819 | { | |
| 820 | m_sr |= UPD7220_SR_HBLANK_ACTIVE; | |
| 821 | } | |
| 822 | else | |
| 823 | { | |
| 824 | m_sr &= ~UPD7220_SR_HBLANK_ACTIVE; | |
| 825 | } | |
| 826 | ||
| 827 | m_out_hsync_func(param); | |
| 828 | ||
| 829 | update_hsync_timer(param); | |
| 830 | break; | |
| 831 | ||
| 832 | case TIMER_VSYNC: | |
| 833 | if (param) | |
| 834 | { | |
| 835 | m_sr |= UPD7220_SR_VSYNC_ACTIVE; | |
| 836 | } | |
| 837 | else | |
| 838 | { | |
| 839 | m_sr &= ~UPD7220_SR_VSYNC_ACTIVE; | |
| 840 | } | |
| 841 | ||
| 842 | m_out_vsync_func(param); | |
| 843 | ||
| 844 | update_vsync_timer(param); | |
| 845 | break; | |
| 846 | ||
| 847 | case TIMER_BLANK: | |
| 848 | if (param) | |
| 849 | { | |
| 850 | m_sr |= UPD7220_SR_HBLANK_ACTIVE; | |
| 851 | } | |
| 852 | else | |
| 853 | { | |
| 854 | m_sr &= ~UPD7220_SR_HBLANK_ACTIVE; | |
| 855 | } | |
| 856 | ||
| 857 | m_out_blank_func(param); | |
| 858 | ||
| 859 | update_blank_timer(param); | |
| 860 | break; | |
| 861 | } | |
| 862 | } | |
| 863 | ||
| 864 | ||
| 865 | //------------------------------------------------- | |
| 866 | // draw_pixel - | |
| 867 | //------------------------------------------------- | |
| 868 | ||
| 869 | void upd7220_device::draw_pixel(int x, int y, UINT8 tile_data) | |
| 870 | { | |
| 871 | UINT32 addr = (y * m_pitch * 2 + (x >> 3)) & 0x3ffff; | |
| 872 | int dad = x & 0x7; | |
| 873 | UINT8 data = readbyte(addr); | |
| 874 | UINT8 new_pixel = (tile_data) & (0x80 >> (dad)); | |
| 875 | ||
| 876 | switch(m_bitmap_mod) | |
| 877 | { | |
| 878 | case 0: //replace | |
| 879 | writebyte(addr, data & ~(0x80 >> (dad))); | |
| 880 | writebyte(addr, data | new_pixel); | |
| 881 | break; | |
| 882 | case 1: //complement | |
| 883 | writebyte(addr, data ^ (new_pixel)); | |
| 884 | break; | |
| 885 | case 2: //reset | |
| 886 | writebyte(addr, data & ((new_pixel) ? 0xff : ~(0x80 >> (dad)))); | |
| 887 | break; | |
| 888 | case 3: //set | |
| 889 | writebyte(addr, data | new_pixel); | |
| 890 | break; | |
| 891 | } | |
| 892 | } | |
| 893 | ||
| 894 | ||
| 895 | //------------------------------------------------- | |
| 896 | // draw_line - | |
| 897 | //------------------------------------------------- | |
| 898 | ||
| 899 | void upd7220_device::draw_line(int x, int y) | |
| 900 | { | |
| 901 | int line_size,i; | |
| 902 | const int line_x_dir[8] = { 0, 1, 1, 0, 0,-1,-1, 0}; | |
| 903 | const int line_y_dir[8] = { 1, 0, 0,-1,-1, 0, 0, 1}; | |
| 904 | const int line_x_step[8] = { 1, 0, 0, 1,-1, 0, 0,-1 }; | |
| 905 | const int line_y_step[8] = { 0, 1,-1, 0, 0,-1, 1, 0 }; | |
| 906 | UINT16 line_pattern; | |
| 907 | int line_step = 0; | |
| 908 | UINT8 dot; | |
| 909 | ||
| 910 | line_size = m_figs.m_dc + 1; | |
| 911 | line_pattern = check_pattern((m_ra[8]) | (m_ra[9]<<8)); | |
| 912 | ||
| 913 | for(i = 0;i<line_size;i++) | |
| 914 | { | |
| 915 | line_step = (m_figs.m_d1 * i); | |
| 916 | line_step/= (m_figs.m_dc + 1); | |
| 917 | line_step >>= 1; | |
| 918 | dot = ((line_pattern >> (i & 0xf)) & 1) << 7; | |
| 919 | draw_pixel(x + (line_step*line_x_step[m_figs.m_dir]),y + (line_step*line_y_step[m_figs.m_dir]),dot >> ((x + line_step*line_x_step[m_figs.m_dir]) & 0x7)); | |
| 920 | x += line_x_dir[m_figs.m_dir]; | |
| 921 | y += line_y_dir[m_figs.m_dir]; | |
| 922 | } | |
| 923 | ||
| 924 | /* TODO: check me*/ | |
| 925 | x += (line_step*line_x_step[m_figs.m_dir]); | |
| 926 | y += (line_step*line_y_step[m_figs.m_dir]); | |
| 927 | ||
| 928 | m_ead = (x >> 4) + (y * m_pitch); | |
| 929 | m_dad = x & 0x0f; | |
| 930 | } | |
| 931 | ||
| 932 | ||
| 933 | //------------------------------------------------- | |
| 934 | // draw_rectangle - | |
| 935 | //------------------------------------------------- | |
| 936 | ||
| 937 | void upd7220_device::draw_rectangle(int x, int y) | |
| 938 | { | |
| 939 | int i; | |
| 940 | const int rect_x_dir[8] = { 0, 1, 0,-1, 1, 1,-1,-1 }; | |
| 941 | const int rect_y_dir[8] = { 1, 0,-1, 0, 1,-1,-1, 1 }; | |
| 942 | UINT8 rect_type,rect_dir; | |
| 943 | UINT16 line_pattern; | |
| 944 | UINT8 dot; | |
| 945 | ||
| 946 | LOG(("uPD7220 rectangle check: %d %d %02x %08x\n",x,y,m_figs.m_dir,m_ead)); | |
| 947 | ||
| 948 | line_pattern = check_pattern((m_ra[8]) | (m_ra[9]<<8)); | |
| 949 | rect_type = (m_figs.m_dir & 1) << 2; | |
| 950 | rect_dir = rect_type | (((m_figs.m_dir >> 1) + 0) & 3); | |
| 951 | ||
| 952 | for(i = 0;i < m_figs.m_d;i++) | |
| 953 | { | |
| 954 | dot = ((line_pattern >> ((i+m_dad) & 0xf)) & 1) << 7; | |
| 955 | draw_pixel(x,y,dot >> (x & 0x7)); | |
| 956 | x+=rect_x_dir[rect_dir]; | |
| 957 | y+=rect_y_dir[rect_dir]; | |
| 958 | } | |
| 959 | ||
| 960 | rect_dir = rect_type | (((m_figs.m_dir >> 1) + 1) & 3); | |
| 961 | ||
| 962 | for(i = 0;i < m_figs.m_d2;i++) | |
| 963 | { | |
| 964 | dot = ((line_pattern >> ((i+m_dad) & 0xf)) & 1) << 7; | |
| 965 | draw_pixel(x,y,dot >> (x & 0x7)); | |
| 966 | x+=rect_x_dir[rect_dir]; | |
| 967 | y+=rect_y_dir[rect_dir]; | |
| 968 | } | |
| 969 | ||
| 970 | rect_dir = rect_type | (((m_figs.m_dir >> 1) + 2) & 3); | |
| 971 | ||
| 972 | for(i = 0;i < m_figs.m_d;i++) | |
| 973 | { | |
| 974 | dot = ((line_pattern >> ((i+m_dad) & 0xf)) & 1) << 7; | |
| 975 | draw_pixel(x,y,dot >> (x & 0x7)); | |
| 976 | x+=rect_x_dir[rect_dir]; | |
| 977 | y+=rect_y_dir[rect_dir]; | |
| 978 | } | |
| 979 | ||
| 980 | rect_dir = rect_type | (((m_figs.m_dir >> 1) + 3) & 3); | |
| 981 | ||
| 982 | for(i = 0;i < m_figs.m_d2;i++) | |
| 983 | { | |
| 984 | dot = ((line_pattern >> ((i+m_dad) & 0xf)) & 1) << 7; | |
| 985 | draw_pixel(x,y,dot >> (x & 0x7)); | |
| 986 | x+=rect_x_dir[rect_dir]; | |
| 987 | y+=rect_y_dir[rect_dir]; | |
| 988 | } | |
| 989 | ||
| 990 | m_ead = (x >> 4) + (y * m_pitch); | |
| 991 | m_dad = x & 0x0f; | |
| 992 | ||
| 993 | } | |
| 994 | ||
| 995 | ||
| 996 | //------------------------------------------------- | |
| 997 | // draw_char - | |
| 998 | //------------------------------------------------- | |
| 999 | ||
| 1000 | void upd7220_device::draw_char(int x, int y) | |
| 1001 | { | |
| 1002 | int xi,yi; | |
| 1003 | int xsize,ysize; | |
| 1004 | UINT8 tile_data; | |
| 1005 | ||
| 1006 | /* snippet for character checking */ | |
| 1007 | #if 0 | |
| 1008 | for(yi=0;yi<8;yi++) | |
| 1009 | { | |
| 1010 | for(xi=0;xi<8;xi++) | |
| 1011 | { | |
| 1012 | printf("%d",(m_ra[(yi & 7) | 8] >> xi) & 1); | |
| 1013 | } | |
| 1014 | printf("\n"); | |
| 1015 | } | |
| 1016 | #endif | |
| 1017 | ||
| 1018 | xsize = m_figs.m_d & 0x3ff; | |
| 1019 | /* Guess: D has presumably upper bits for ysize, QX-10 relies on this (TODO: check this on any real HW) */ | |
| 1020 | ysize = ((m_figs.m_d & 0x400) + m_figs.m_dc) + 1; | |
| 1021 | ||
| 1022 | /* TODO: internal direction, zooming, size stuff bigger than 8, rewrite using draw_pixel function */ | |
| 1023 | for(yi=0;yi<ysize;yi++) | |
| 1024 | { | |
| 1025 | switch(m_figs.m_dir & 7) | |
| 1026 | { | |
| 1027 | case 0: tile_data = BITSWAP8(m_ra[((yi) & 7) | 8],0,1,2,3,4,5,6,7); break; // TODO | |
| 1028 | case 2: tile_data = BITSWAP8(m_ra[((yi) & 7) | 8],0,1,2,3,4,5,6,7); break; | |
| 1029 | case 6: tile_data = BITSWAP8(m_ra[((ysize-1-yi) & 7) | 8],7,6,5,4,3,2,1,0); break; | |
| 1030 | default: tile_data = BITSWAP8(m_ra[((yi) & 7) | 8],7,6,5,4,3,2,1,0); | |
| 1031 | printf("%d %d %d\n",m_figs.m_dir,xsize,ysize); | |
| 1032 | break; | |
| 1033 | } | |
| 1034 | ||
| 1035 | for(xi=0;xi<xsize;xi++) | |
| 1036 | { | |
| 1037 | UINT32 addr = ((y+yi) * m_pitch * 2) + ((x+xi) >> 3); | |
| 1038 | ||
| 1039 | writebyte(addr & 0x3ffff, readbyte(addr & 0x3ffff) & ~(1 << (xi & 7))); | |
| 1040 | writebyte(addr & 0x3ffff, readbyte(addr & 0x3ffff) | ((tile_data) & (1 << (xi & 7)))); | |
| 1041 | } | |
| 1042 | } | |
| 1043 | ||
| 1044 | m_ead = ((x+8*x_dir_dot[m_figs.m_dir]) >> 4) + ((y+8*y_dir_dot[m_figs.m_dir]) * m_pitch); | |
| 1045 | m_dad = ((x+8*x_dir_dot[m_figs.m_dir]) & 0xf); | |
| 1046 | } | |
| 1047 | ||
| 1048 | ||
| 1049 | //------------------------------------------------- | |
| 1050 | // translate_command - | |
| 1051 | //------------------------------------------------- | |
| 1052 | ||
| 1053 | int upd7220_device::translate_command(UINT8 data) | |
| 1054 | { | |
| 1055 | int command = COMMAND_INVALID; | |
| 1056 | ||
| 1057 | switch (data) | |
| 1058 | { | |
| 1059 | case UPD7220_COMMAND_RESET: command = COMMAND_RESET; break; | |
| 1060 | case UPD7220_COMMAND_CCHAR: command = COMMAND_CCHAR; break; | |
| 1061 | case UPD7220_COMMAND_START: command = COMMAND_START; break; | |
| 1062 | case UPD7220_COMMAND_ZOOM: command = COMMAND_ZOOM; break; | |
| 1063 | case UPD7220_COMMAND_CURS: command = COMMAND_CURS; break; | |
| 1064 | case UPD7220_COMMAND_PITCH: command = COMMAND_PITCH; break; | |
| 1065 | case UPD7220_COMMAND_MASK: command = COMMAND_MASK; break; | |
| 1066 | case UPD7220_COMMAND_FIGS: command = COMMAND_FIGS; break; | |
| 1067 | case UPD7220_COMMAND_FIGD: command = COMMAND_FIGD; break; | |
| 1068 | case UPD7220_COMMAND_GCHRD: command = COMMAND_GCHRD; break; | |
| 1069 | case UPD7220_COMMAND_CURD: command = COMMAND_CURD; break; | |
| 1070 | case UPD7220_COMMAND_LPRD: command = COMMAND_LPRD; break; | |
| 1071 | case UPD7220_COMMAND_5A: command = COMMAND_5A; break; | |
| 1072 | default: | |
| 1073 | switch (data & 0xfe) | |
| 1074 | { | |
| 1075 | case UPD7220_COMMAND_SYNC: command = COMMAND_SYNC; break; | |
| 1076 | case UPD7220_COMMAND_VSYNC: command = COMMAND_VSYNC; break; | |
| 1077 | case UPD7220_COMMAND_BCTRL: command = COMMAND_BCTRL; break; | |
| 1078 | default: | |
| 1079 | switch (data & 0xf0) | |
| 1080 | { | |
| 1081 | case UPD7220_COMMAND_PRAM: command = COMMAND_PRAM; break; | |
| 1082 | default: | |
| 1083 | switch (data & 0xe4) | |
| 1084 | { | |
| 1085 | case UPD7220_COMMAND_WDAT: command = COMMAND_WDAT; break; | |
| 1086 | case UPD7220_COMMAND_RDAT: command = COMMAND_RDAT; break; | |
| 1087 | case UPD7220_COMMAND_DMAR: command = COMMAND_DMAR; break; | |
| 1088 | case UPD7220_COMMAND_DMAW: command = COMMAND_DMAW; break; | |
| 1089 | } | |
| 1090 | } | |
| 1091 | } | |
| 1092 | } | |
| 1093 | ||
| 1094 | return command; | |
| 1095 | } | |
| 1096 | ||
| 1097 | ||
| 1098 | //------------------------------------------------- | |
| 1099 | // process_fifo - | |
| 1100 | //------------------------------------------------- | |
| 1101 | ||
| 1102 | void upd7220_device::process_fifo() | |
| 1103 | { | |
| 1104 | UINT8 data; | |
| 1105 | int flag; | |
| 1106 | ||
| 1107 | dequeue(&data, &flag); | |
| 1108 | ||
| 1109 | if (flag == FIFO_COMMAND) | |
| 1110 | { | |
| 1111 | m_cr = data; | |
| 1112 | m_param_ptr = 1; | |
| 1113 | } | |
| 1114 | else | |
| 1115 | { | |
| 1116 | m_pr[m_param_ptr] = data; | |
| 1117 | m_param_ptr++; | |
| 1118 | } | |
| 1119 | ||
| 1120 | switch (translate_command(m_cr)) | |
| 1121 | { | |
| 1122 | case COMMAND_INVALID: | |
| 1123 | printf("uPD7220 '%s' Invalid Command Byte %02x\n", tag(), m_cr); | |
| 1124 | break; | |
| 1125 | ||
| 1126 | case COMMAND_5A: | |
| 1127 | if (m_param_ptr == 4) | |
| 1128 | printf("uPD7220 '%s' Undocumented Command 0x5A Executed %02x %02x %02x\n", tag(),m_pr[1],m_pr[2],m_pr[3] ); | |
| 1129 | break; | |
| 1130 | ||
| 1131 | case COMMAND_RESET: /* reset */ | |
| 1132 | switch (m_param_ptr) | |
| 1133 | { | |
| 1134 | case 0: | |
| 1135 | LOG(("uPD7220 '%s' RESET\n", tag())); | |
| 1136 | ||
| 1137 | m_de = 0; | |
| 1138 | m_ra[0] = m_ra[1] = m_ra[2] = 0; | |
| 1139 | m_ra[3] = 0x19; | |
| 1140 | m_ead = 0; | |
| 1141 | m_dad = 0; | |
| 1142 | m_mask = 0; | |
| 1143 | break; | |
| 1144 | ||
| 1145 | case 9: | |
| 1146 | m_mode = m_pr[1]; | |
| 1147 | m_aw = m_pr[2] + 2; | |
| 1148 | m_hs = (m_pr[3] & 0x1f) + 1; | |
| 1149 | m_vs = ((m_pr[4] & 0x03) << 3) | (m_pr[3] >> 5); | |
| 1150 | m_hfp = (m_pr[4] >> 2) + 1; | |
| 1151 | m_hbp = (m_pr[5] & 0x3f) + 1; | |
| 1152 | m_vfp = m_pr[6] & 0x3f; | |
| 1153 | m_al = ((m_pr[8] & 0x03) << 8) | m_pr[7]; | |
| 1154 | m_vbp = m_pr[8] >> 2; | |
| 1155 | ||
| 1156 | m_pitch = m_aw; | |
| 1157 | ||
| 1158 | LOG(("uPD7220 '%s' Mode: %02x\n", tag(), m_mode)); | |
| 1159 | LOG(("uPD7220 '%s' AW: %u\n", tag(), m_aw)); | |
| 1160 | LOG(("uPD7220 '%s' HS: %u\n", tag(), m_hs)); | |
| 1161 | LOG(("uPD7220 '%s' VS: %u\n", tag(), m_vs)); | |
| 1162 | LOG(("uPD7220 '%s' HFP: %u\n", tag(), m_hfp)); | |
| 1163 | LOG(("uPD7220 '%s' HBP: %u\n", tag(), m_hbp)); | |
| 1164 | LOG(("uPD7220 '%s' VFP: %u\n", tag(), m_vfp)); | |
| 1165 | LOG(("uPD7220 '%s' AL: %u\n", tag(), m_al)); | |
| 1166 | LOG(("uPD7220 '%s' VBP: %u\n", tag(), m_vbp)); | |
| 1167 | LOG(("uPD7220 '%s' PITCH: %u\n", tag(), m_pitch)); | |
| 1168 | ||
| 1169 | recompute_parameters(); | |
| 1170 | break; | |
| 1171 | } | |
| 1172 | break; | |
| 1173 | ||
| 1174 | case COMMAND_SYNC: /* sync format specify */ | |
| 1175 | if (m_param_ptr == 9) | |
| 1176 | { | |
| 1177 | m_mode = m_pr[1]; | |
| 1178 | m_aw = m_pr[2] + 2; | |
| 1179 | m_hs = (m_pr[3] & 0x1f) + 1; | |
| 1180 | m_vs = ((m_pr[4] & 0x03) << 3) | (m_pr[3] >> 5); | |
| 1181 | m_hfp = (m_pr[4] >> 2) + 1; | |
| 1182 | m_hbp = (m_pr[5] & 0x3f) + 1; | |
| 1183 | m_vfp = m_pr[6] & 0x3f; | |
| 1184 | m_al = ((m_pr[8] & 0x03) << 8) | m_pr[7]; | |
| 1185 | m_vbp = m_pr[8] >> 2; | |
| 1186 | ||
| 1187 | m_pitch = m_aw; | |
| 1188 | ||
| 1189 | LOG(("uPD7220 '%s' Mode: %02x\n", tag(), m_mode)); | |
| 1190 | LOG(("uPD7220 '%s' AW: %u\n", tag(), m_aw)); | |
| 1191 | LOG(("uPD7220 '%s' HS: %u\n", tag(), m_hs)); | |
| 1192 | LOG(("uPD7220 '%s' VS: %u\n", tag(), m_vs)); | |
| 1193 | LOG(("uPD7220 '%s' HFP: %u\n", tag(), m_hfp)); | |
| 1194 | LOG(("uPD7220 '%s' HBP: %u\n", tag(), m_hbp)); | |
| 1195 | LOG(("uPD7220 '%s' VFP: %u\n", tag(), m_vfp)); | |
| 1196 | LOG(("uPD7220 '%s' AL: %u\n", tag(), m_al)); | |
| 1197 | LOG(("uPD7220 '%s' VBP: %u\n", tag(), m_vbp)); | |
| 1198 | LOG(("uPD7220 '%s' PITCH: %u\n", tag(), m_pitch)); | |
| 1199 | ||
| 1200 | recompute_parameters(); | |
| 1201 | } | |
| 1202 | break; | |
| 1203 | ||
| 1204 | case COMMAND_VSYNC: /* vertical sync mode */ | |
| 1205 | m_m = m_cr & 0x01; | |
| 1206 | ||
| 1207 | LOG(("uPD7220 '%s' M: %u\n", tag(), m_m)); | |
| 1208 | ||
| 1209 | recompute_parameters(); | |
| 1210 | break; | |
| 1211 | ||
| 1212 | case COMMAND_CCHAR: /* cursor & character characteristics */ | |
| 1213 | if(m_param_ptr == 2) | |
| 1214 | { | |
| 1215 | m_lr = (m_pr[1] & 0x1f) + 1; | |
| 1216 | m_dc = BIT(m_pr[1], 7); | |
| 1217 | ||
| 1218 | LOG(("uPD7220 '%s' LR: %u\n", tag(), m_lr)); | |
| 1219 | LOG(("uPD7220 '%s' DC: %u\n", tag(), m_dc)); | |
| 1220 | } | |
| 1221 | ||
| 1222 | if(m_param_ptr == 3) | |
| 1223 | { | |
| 1224 | m_ctop = m_pr[2] & 0x1f; | |
| 1225 | m_sc = BIT(m_pr[2], 5); | |
| 1226 | m_br = (m_pr[2] >> 6); /* guess, assume that blink rate clears upper bits (if any) */ | |
| 1227 | ||
| 1228 | LOG(("uPD7220 '%s' CTOP: %u\n", tag(), m_ctop)); | |
| 1229 | LOG(("uPD7220 '%s' SC: %u\n", tag(), m_sc)); | |
| 1230 | } | |
| 1231 | ||
| 1232 | if(m_param_ptr == 4) | |
| 1233 | { | |
| 1234 | m_br = ((m_pr[3] & 0x07) << 2) | (m_pr[2] >> 6); | |
| 1235 | m_cbot = m_pr[3] >> 3; | |
| 1236 | ||
| 1237 | LOG(("uPD7220 '%s' BR: %u\n", tag(), m_br)); | |
| 1238 | LOG(("uPD7220 '%s' CBOT: %u\n", tag(), m_cbot)); | |
| 1239 | } | |
| 1240 | break; | |
| 1241 | ||
| 1242 | case COMMAND_START: /* start display & end idle mode */ | |
| 1243 | m_de = 1; | |
| 1244 | ||
| 1245 | //LOG(("uPD7220 '%s' DE: 1\n", tag())); | |
| 1246 | break; | |
| 1247 | ||
| 1248 | case COMMAND_BCTRL: /* display blanking control */ | |
| 1249 | m_de = m_cr & 0x01; | |
| 1250 | ||
| 1251 | //LOG(("uPD7220 '%s' DE: %u\n", tag(), m_de)); | |
| 1252 | break; | |
| 1253 | ||
| 1254 | case COMMAND_ZOOM: /* zoom factors specify */ | |
| 1255 | if (flag == FIFO_PARAMETER) | |
| 1256 | { | |
| 1257 | m_gchr = m_pr[1] & 0x0f; | |
| 1258 | m_disp = m_pr[1] >> 4; | |
| 1259 | ||
| 1260 | LOG(("uPD7220 '%s' GCHR: %01x\n", tag(), m_gchr)); | |
| 1261 | LOG(("uPD7220 '%s' DISP: %01x\n", tag(), m_disp)); | |
| 1262 | } | |
| 1263 | break; | |
| 1264 | ||
| 1265 | case COMMAND_CURS: /* cursor position specify */ | |
| 1266 | if (m_param_ptr >= 3) | |
| 1267 | { | |
| 1268 | UINT8 upper_addr = (m_param_ptr == 3) ? 0 : (m_pr[3] & 0x03); | |
| 1269 | ||
| 1270 | m_ead = (upper_addr << 16) | (m_pr[2] << 8) | m_pr[1]; | |
| 1271 | ||
| 1272 | //LOG(("uPD7220 '%s' EAD: %06x\n", tag(), m_ead)); | |
| 1273 | ||
| 1274 | if(m_param_ptr == 4) | |
| 1275 | { | |
| 1276 | m_dad = m_pr[3] >> 4; | |
| 1277 | //LOG(("uPD7220 '%s' DAD: %01x\n", tag(), m_dad)); | |
| 1278 | } | |
| 1279 | } | |
| 1280 | break; | |
| 1281 | ||
| 1282 | case COMMAND_PRAM: /* parameter RAM load */ | |
| 1283 | if (flag == FIFO_COMMAND) | |
| 1284 | { | |
| 1285 | m_ra_addr = m_cr & 0x0f; | |
| 1286 | } | |
| 1287 | else | |
| 1288 | { | |
| 1289 | if (m_ra_addr < 16) | |
| 1290 | { | |
| 1291 | LOG(("uPD7220 '%s' RA%u: %02x\n", tag(), m_ra_addr, data)); | |
| 1292 | ||
| 1293 | m_ra[m_ra_addr] = data; | |
| 1294 | m_ra_addr++; | |
| 1295 | } | |
| 1296 | ||
| 1297 | m_param_ptr = 0; | |
| 1298 | } | |
| 1299 | break; | |
| 1300 | ||
| 1301 | case COMMAND_PITCH: /* pitch specification */ | |
| 1302 | if (flag == FIFO_PARAMETER) | |
| 1303 | { | |
| 1304 | m_pitch = data; | |
| 1305 | ||
| 1306 | LOG(("uPD7220 '%s' PITCH: %u\n", tag(), m_pitch)); | |
| 1307 | } | |
| 1308 | break; | |
| 1309 | ||
| 1310 | case COMMAND_WDAT: /* write data into display memory */ | |
| 1311 | m_bitmap_mod = m_cr & 3; | |
| 1312 | ||
| 1313 | if (m_param_ptr == 3 || (m_param_ptr == 2 && m_cr & 0x10)) | |
| 1314 | { | |
| 1315 | //printf("%02x = %02x %02x (%c) %04x\n",m_cr,m_pr[2],m_pr[1],m_pr[1],EAD); | |
| 1316 | fifo_set_direction(FIFO_WRITE); | |
| 1317 | ||
| 1318 | write_vram((m_cr & 0x18) >> 3,m_cr & 3); | |
| 1319 | reset_figs_param(); | |
| 1320 | m_param_ptr = 1; | |
| 1321 | } | |
| 1322 | break; | |
| 1323 | ||
| 1324 | case COMMAND_MASK: /* mask register load */ | |
| 1325 | if (m_param_ptr == 3) | |
| 1326 | { | |
| 1327 | m_mask = (m_pr[2] << 8) | m_pr[1]; | |
| 1328 | ||
| 1329 | LOG(("uPD7220 '%s' MASK: %04x\n", tag(), m_mask)); | |
| 1330 | } | |
| 1331 | break; | |
| 1332 | ||
| 1333 | case COMMAND_FIGS: /* figure drawing parameters specify */ | |
| 1334 | if (m_param_ptr == 2) | |
| 1335 | { | |
| 1336 | m_figs.m_dir = m_pr[1] & 0x7; | |
| 1337 | m_figs.m_figure_type = (m_pr[1] & 0xf8) >> 3; | |
| 1338 | ||
| 1339 | //if(m_figs.m_dir != 2) | |
| 1340 | // printf("DIR %02x\n",m_pr[1]); | |
| 1341 | } | |
| 1342 | ||
| 1343 | // the Decision Mate V during start-up test upload only 2 params before execute the | |
| 1344 | // RDAT command, so I assume this is the expected behaviour, but this needs to be verified. | |
| 1345 | if (m_param_ptr == 3) | |
| 1346 | m_figs.m_dc = (m_pr[2]) | (m_figs.m_dc & 0x3f00); | |
| 1347 | ||
| 1348 | if (m_param_ptr == 4) | |
| 1349 | m_figs.m_dc = (m_pr[2]) | ((m_pr[3] & 0x3f) << 8); | |
| 1350 | ||
| 1351 | if (m_param_ptr == 6) | |
| 1352 | m_figs.m_d = (m_pr[4]) | ((m_pr[5] & 0x3f) << 8); | |
| 1353 | ||
| 1354 | if (m_param_ptr == 8) | |
| 1355 | m_figs.m_d2 = (m_pr[6]) | ((m_pr[7] & 0x3f) << 8); | |
| 1356 | ||
| 1357 | if (m_param_ptr == 10) | |
| 1358 | m_figs.m_d1 = (m_pr[8]) | ((m_pr[9] & 0x3f) << 8); | |
| 1359 | ||
| 1360 | if (m_param_ptr == 12) | |
| 1361 | m_figs.m_dm = (m_pr[10]) | ((m_pr[11] & 0x3f) << 8); | |
| 1362 | ||
| 1363 | break; | |
| 1364 | ||
| 1365 | case COMMAND_FIGD: /* figure draw start */ | |
| 1366 | if(m_figs.m_figure_type == 0) | |
| 1367 | { | |
| 1368 | UINT16 line_pattern = check_pattern((m_ra[8]) | (m_ra[9]<<8)); | |
| 1369 | UINT8 dot = ((line_pattern >> (0 & 0xf)) & 1) << 7; | |
| 1370 | ||
| 1371 | draw_pixel(((m_ead % m_pitch) << 4) | (m_dad & 0xf),(m_ead / m_pitch),dot); | |
| 1372 | } | |
| 1373 | else if(m_figs.m_figure_type == 1) | |
| 1374 | draw_line(((m_ead % m_pitch) << 4) | (m_dad & 0xf),(m_ead / m_pitch)); | |
| 1375 | else if(m_figs.m_figure_type == 8) | |
| 1376 | draw_rectangle(((m_ead % m_pitch) << 4) | (m_dad & 0xf),(m_ead / m_pitch)); | |
| 1377 | else | |
| 1378 | printf("uPD7220 '%s' Unimplemented command FIGD %02x\n", tag(),m_figs.m_figure_type); | |
| 1379 | ||
| 1380 | reset_figs_param(); | |
| 1381 | m_sr |= UPD7220_SR_DRAWING_IN_PROGRESS; | |
| 1382 | break; | |
| 1383 | ||
| 1384 | case COMMAND_GCHRD: /* graphics character draw and area filling start */ | |
| 1385 | if(m_figs.m_figure_type == 2) | |
| 1386 | draw_char(((m_ead % m_pitch) << 4) | (m_dad & 0xf),(m_ead / m_pitch)); | |
| 1387 | else | |
| 1388 | printf("uPD7220 '%s' Unimplemented command GCHRD %02x\n", tag(),m_figs.m_figure_type); | |
| 1389 | ||
| 1390 | reset_figs_param(); | |
| 1391 | m_sr |= UPD7220_SR_DRAWING_IN_PROGRESS; | |
| 1392 | break; | |
| 1393 | ||
| 1394 | case COMMAND_RDAT: /* read data from display memory */ | |
| 1395 | fifo_set_direction(FIFO_READ); | |
| 1396 | ||
| 1397 | read_vram((m_cr & 0x18) >> 3,m_cr & 3); | |
| 1398 | reset_figs_param(); | |
| 1399 | ||
| 1400 | m_sr |= UPD7220_SR_DATA_READY; | |
| 1401 | break; | |
| 1402 | ||
| 1403 | case COMMAND_CURD: /* cursor address read */ | |
| 1404 | fifo_set_direction(FIFO_READ); | |
| 1405 | ||
| 1406 | queue(m_ead & 0xff, 0); | |
| 1407 | queue((m_ead >> 8) & 0xff, 0); | |
| 1408 | queue(m_ead >> 16, 0); | |
| 1409 | queue(m_dad & 0xff, 0); | |
| 1410 | queue(m_dad >> 8, 0); | |
| 1411 | ||
| 1412 | m_sr |= UPD7220_SR_DATA_READY; | |
| 1413 | break; | |
| 1414 | ||
| 1415 | case COMMAND_LPRD: /* light pen address read */ | |
| 1416 | fifo_set_direction(FIFO_READ); | |
| 1417 | ||
| 1418 | queue(m_lad & 0xff, 0); | |
| 1419 | queue((m_lad >> 8) & 0xff, 0); | |
| 1420 | queue(m_lad >> 16, 0); | |
| 1421 | ||
| 1422 | m_sr |= UPD7220_SR_DATA_READY; | |
| 1423 | m_sr &= ~UPD7220_SR_LIGHT_PEN_DETECT; | |
| 1424 | break; | |
| 1425 | ||
| 1426 | case COMMAND_DMAR: /* DMA read request */ | |
| 1427 | printf("uPD7220 '%s' Unimplemented command DMAR\n", tag()); | |
| 1428 | break; | |
| 1429 | ||
| 1430 | case COMMAND_DMAW: /* DMA write request */ | |
| 1431 | printf("uPD7220 '%s' Unimplemented command DMAW\n", tag()); | |
| 1432 | break; | |
| 1433 | } | |
| 1434 | } | |
| 1435 | ||
| 1436 | ||
| 1437 | //------------------------------------------------- | |
| 1438 | // read - | |
| 1439 | //------------------------------------------------- | |
| 1440 | ||
| 1441 | READ8_MEMBER( upd7220_device::read ) | |
| 1442 | { | |
| 1443 | UINT8 data; | |
| 1444 | ||
| 1445 | if (offset & 1) | |
| 1446 | { | |
| 1447 | /* FIFO read */ | |
| 1448 | int flag; | |
| 1449 | fifo_set_direction(FIFO_READ); | |
| 1450 | dequeue(&data, &flag); | |
| 1451 | } | |
| 1452 | else | |
| 1453 | { | |
| 1454 | /* status register */ | |
| 1455 | data = m_sr; | |
| 1456 | ||
| 1457 | /* TODO: timing of these */ | |
| 1458 | m_sr &= ~UPD7220_SR_DRAWING_IN_PROGRESS; | |
| 1459 | m_sr &= ~UPD7220_SR_DMA_EXECUTE; | |
| 1460 | } | |
| 1461 | ||
| 1462 | return data; | |
| 1463 | } | |
| 1464 | ||
| 1465 | ||
| 1466 | //------------------------------------------------- | |
| 1467 | // write - | |
| 1468 | //------------------------------------------------- | |
| 1469 | ||
| 1470 | WRITE8_MEMBER( upd7220_device::write ) | |
| 1471 | { | |
| 1472 | if (offset & 1) | |
| 1473 | { | |
| 1474 | /* command into FIFO */ | |
| 1475 | fifo_set_direction(FIFO_WRITE); | |
| 1476 | queue(data, 1); | |
| 1477 | } | |
| 1478 | else | |
| 1479 | { | |
| 1480 | /* parameter into FIFO */ | |
| 1481 | // fifo_set_direction(FIFO_WRITE); | |
| 1482 | queue(data, 0); | |
| 1483 | } | |
| 1484 | ||
| 1485 | process_fifo(); | |
| 1486 | } | |
| 1487 | ||
| 1488 | ||
| 1489 | //------------------------------------------------- | |
| 1490 | // dack_r - | |
| 1491 | //------------------------------------------------- | |
| 1492 | ||
| 1493 | READ8_MEMBER( upd7220_device::dack_r ) | |
| 1494 | { | |
| 1495 | return 0; | |
| 1496 | } | |
| 1497 | ||
| 1498 | ||
| 1499 | //------------------------------------------------- | |
| 1500 | // dack_w - | |
| 1501 | //------------------------------------------------- | |
| 1502 | ||
| 1503 | WRITE8_MEMBER( upd7220_device::dack_w ) | |
| 1504 | { | |
| 1505 | } | |
| 1506 | ||
| 1507 | ||
| 1508 | //------------------------------------------------- | |
| 1509 | // ext_sync_w - | |
| 1510 | //------------------------------------------------- | |
| 1511 | ||
| 1512 | WRITE_LINE_MEMBER( upd7220_device::ext_sync_w ) | |
| 1513 | { | |
| 1514 | //LOG(("uPD7220 '%s' External Synchronization: %u\n", tag(), state)); | |
| 1515 | ||
| 1516 | if (state) | |
| 1517 | { | |
| 1518 | m_sr |= UPD7220_SR_VSYNC_ACTIVE; | |
| 1519 | } | |
| 1520 | else | |
| 1521 | { | |
| 1522 | m_sr &= ~UPD7220_SR_VSYNC_ACTIVE; | |
| 1523 | } | |
| 1524 | } | |
| 1525 | ||
| 1526 | ||
| 1527 | //------------------------------------------------- | |
| 1528 | // ext_sync_w - | |
| 1529 | //------------------------------------------------- | |
| 1530 | ||
| 1531 | WRITE_LINE_MEMBER( upd7220_device::lpen_w ) | |
| 1532 | { | |
| 1533 | /* only if 2 rising edges on the lpen input occur at the same | |
| 1534 | point during successive video fields are the pulses accepted */ | |
| 1535 | ||
| 1536 | /* | |
| 1537 | ||
| 1538 | 1. compute the address of the location on the CRT | |
| 1539 | 2. compare with LAD | |
| 1540 | 3. if not equal move address to LAD | |
| 1541 | 4. if equal set LPEN DETECT flag to 1 | |
| 1542 | ||
| 1543 | */ | |
| 1544 | } | |
| 1545 | ||
| 1546 | ||
| 1547 | //------------------------------------------------- | |
| 1548 | // update_text - | |
| 1549 | //------------------------------------------------- | |
| 1550 | ||
| 1551 | void upd7220_device::update_text(bitmap_rgb32 &bitmap, const rectangle &cliprect) | |
| 1552 | { | |
| 1553 | UINT32 addr, sad; | |
| 1554 | UINT16 len; | |
| 1555 | int im, wd; | |
| 1556 | int y, sy = 0; | |
| 1557 | ||
| 1558 | for (int area = 0; area < 4; area++) | |
| 1559 | { | |
| 1560 | get_text_partition(area, &sad, &len, &im, &wd); | |
| 1561 | ||
| 1562 | for (y = sy; y < sy + len; y++) | |
| 1563 | { | |
| 1564 | addr = sad + (y * m_pitch); | |
| 1565 | ||
| 1566 | if (m_draw_text_cb) | |
| 1567 | m_draw_text_cb(this, bitmap, addr, y, wd, m_pitch, m_lr, m_dc, m_ead); | |
| 1568 | } | |
| 1569 | ||
| 1570 | sy = y + 1; | |
| 1571 | } | |
| 1572 | } | |
| 1573 | ||
| 1574 | ||
| 1575 | //------------------------------------------------- | |
| 1576 | // draw_graphics_line - | |
| 1577 | //------------------------------------------------- | |
| 1578 | ||
| 1579 | void upd7220_device::draw_graphics_line(bitmap_rgb32 &bitmap, UINT32 addr, int y, int wd) | |
| 1580 | { | |
| 1581 | int sx; | |
| 1582 | ||
| 1583 | for (sx = 0; sx < m_pitch * 2; sx++) | |
| 1584 | { | |
| 1585 | if((sx << 3) < m_aw * 16 && y < m_al) | |
| 1586 | m_display_cb(this, bitmap, y, sx << 3, addr); | |
| 1587 | ||
| 1588 | addr+= wd + 1; | |
| 1589 | } | |
| 1590 | } | |
| 1591 | ||
| 1592 | ||
| 1593 | //------------------------------------------------- | |
| 1594 | // update_graphics - | |
| 1595 | //------------------------------------------------- | |
| 1596 | ||
| 1597 | void upd7220_device::update_graphics(bitmap_rgb32 &bitmap, const rectangle &cliprect, int force_bitmap) | |
| 1598 | { | |
| 1599 | UINT32 addr, sad; | |
| 1600 | UINT16 len; | |
| 1601 | int im, wd, area; | |
| 1602 | int y = 0, tsy = 0, bsy = 0; | |
| 1603 | ||
| 1604 | for (area = 0; area < 4; area++) | |
| 1605 | { | |
| 1606 | get_graphics_partition(area, &sad, &len, &im, &wd); | |
| 1607 | ||
| 1608 | if (im || force_bitmap) | |
| 1609 | { | |
| 1610 | get_graphics_partition(area, &sad, &len, &im, &wd); | |
| 1611 | ||
| 1612 | if(area >= 2) // TODO: correct? | |
| 1613 | break; | |
| 1614 | ||
| 1615 | for (y = 0; y < len; y++) | |
| 1616 | { | |
| 1617 | addr = ((sad << 1) & 0x3ffff) + (y * m_pitch * 2); | |
| 1618 | ||
| 1619 | if (m_display_cb) | |
| 1620 | draw_graphics_line(bitmap, addr, y + bsy, wd); | |
| 1621 | } | |
| 1622 | } | |
| 1623 | else | |
| 1624 | { | |
| 1625 | get_text_partition(area, &sad, &len, &im, &wd); | |
| 1626 | ||
| 1627 | if(m_lr) | |
| 1628 | { | |
| 1629 | for (y = 0; y < len; y+=m_lr) | |
| 1630 | { | |
| 1631 | addr = (sad & 0x3ffff) + ((y / m_lr) * m_pitch); | |
| 1632 | ||
| 1633 | if (m_draw_text_cb) | |
| 1634 | m_draw_text_cb(this, bitmap, addr, (y + tsy) / m_lr, wd, m_pitch, m_lr, m_dc, m_ead); | |
| 1635 | } | |
| 1636 | } | |
| 1637 | } | |
| 1638 | ||
| 1639 | if (m_lr) | |
| 1640 | tsy += y; | |
| 1641 | bsy += y; | |
| 1642 | } | |
| 1643 | } | |
| 1644 | ||
| 1645 | ||
| 1646 | //------------------------------------------------- | |
| 1647 | // update_screen - | |
| 1648 | //------------------------------------------------- | |
| 1649 | ||
| 1650 | UINT32 upd7220_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) | |
| 1651 | { | |
| 1652 | if (m_de) | |
| 1653 | { | |
| 1654 | switch (m_mode & UPD7220_MODE_DISPLAY_MASK) | |
| 1655 | { | |
| 1656 | case UPD7220_MODE_DISPLAY_MIXED: | |
| 1657 | update_graphics(bitmap, cliprect, 0); | |
| 1658 | break; | |
| 1659 | ||
| 1660 | case UPD7220_MODE_DISPLAY_GRAPHICS: | |
| 1661 | update_graphics(bitmap, cliprect, 1); | |
| 1662 | break; | |
| 1663 | ||
| 1664 | case UPD7220_MODE_DISPLAY_CHARACTER: | |
| 1665 | update_text(bitmap, cliprect); | |
| 1666 | break; | |
| 1667 | ||
| 1668 | case UPD7220_MODE_DISPLAY_INVALID: | |
| 1669 | LOG(("uPD7220 '%s' Invalid Display Mode!\n", tag())); | |
| 1670 | } | |
| 1671 | } | |
| 1672 | return 0; | |
| 1673 | } |
| Added: svn:mime-type + text/plain Added: svn:eol-style + native |
| r0 | r21685 | |
|---|---|---|
| 1 | /********************************************************************** | |
| 2 | ||
| 3 | NEC uPD7220 Graphics Display Controller emulation | |
| 4 | ||
| 5 | Copyright MESS Team. | |
| 6 | Visit http://mamedev.org for licensing and usage restrictions. | |
| 7 | ||
| 8 | ********************************************************************** | |
| 9 | _____ _____ | |
| 10 | 2xWCLK 1 |* \_/ | 40 Vcc | |
| 11 | _DBIN 2 | | 39 A17 | |
| 12 | HSYNC 3 | | 38 A16 | |
| 13 | V/EXT SYNC 4 | | 37 AD15 | |
| 14 | BLANK 5 | | 36 AD14 | |
| 15 | ALE 6 | | 35 AD13 | |
| 16 | DRQ 7 | | 34 AD12 | |
| 17 | _DACK 8 | | 33 AD11 | |
| 18 | _RD 9 | | 32 AD10 | |
| 19 | _WR 10 | uPD7220 | 31 AD9 | |
| 20 | A0 11 | 82720 | 30 AD8 | |
| 21 | DB0 12 | | 29 AD7 | |
| 22 | DB1 13 | | 28 AD6 | |
| 23 | DB2 14 | | 27 AD5 | |
| 24 | DB3 15 | | 26 AD4 | |
| 25 | DB4 16 | | 25 AD3 | |
| 26 | DB5 17 | | 24 AD2 | |
| 27 | DB6 18 | | 23 AD1 | |
| 28 | DB7 19 | | 22 AD0 | |
| 29 | GND 20 |_____________| 21 LPEN | |
| 30 | ||
| 31 | **********************************************************************/ | |
| 32 | ||
| 33 | #pragma once | |
| 34 | ||
| 35 | #ifndef __UPD7220__ | |
| 36 | #define __UPD7220__ | |
| 37 | ||
| 38 | #include "emu.h" | |
| 39 | ||
| 40 | ||
| 41 | ||
| 42 | //************************************************************************** | |
| 43 | // MACROS / CONSTANTS | |
| 44 | //************************************************************************** | |
| 45 | ||
| 46 | ||
| 47 | ||
| 48 | ||
| 49 | //************************************************************************** | |
| 50 | // INTERFACE CONFIGURATION MACROS | |
| 51 | //************************************************************************** | |
| 52 | ||
| 53 | #define MCFG_UPD7220_ADD(_tag, _clock, _config, _map) \ | |
| 54 | MCFG_DEVICE_ADD(_tag, UPD7220, _clock) \ | |
| 55 | MCFG_DEVICE_CONFIG(_config) \ | |
| 56 | MCFG_DEVICE_ADDRESS_MAP(AS_0, _map) | |
| 57 | ||
| 58 | #define UPD7220_INTERFACE(name) \ | |
| 59 | const upd7220_interface (name) = | |
| 60 | ||
| 61 | ||
| 62 | ||
| 63 | //************************************************************************** | |
| 64 | // TYPE DEFINITIONS | |
| 65 | //************************************************************************** | |
| 66 | ||
| 67 | typedef void (*upd7220_display_pixels_func)(device_t *device, bitmap_rgb32 &bitmap, int y, int x, UINT32 address); | |
| 68 | #define UPD7220_DISPLAY_PIXELS(name) void name(device_t *device, bitmap_rgb32 &bitmap, int y, int x, UINT32 address) | |
| 69 | ||
| 70 | typedef void (*upd7220_draw_text_line)(device_t *device, bitmap_rgb32 &bitmap, UINT32 addr, int y, int wd, int pitch, int lr, int cursor_on, int cursor_addr); | |
| 71 | #define UPD7220_DRAW_TEXT_LINE(name) void name(device_t *device, bitmap_rgb32 &bitmap, UINT32 addr, int y, int wd, int pitch, int lr, int cursor_on, int cursor_addr) | |
| 72 | ||
| 73 | ||
| 74 | // ======================> upd7220_interface | |
| 75 | ||
| 76 | struct upd7220_interface | |
| 77 | { | |
| 78 | const char *m_screen_tag; | |
| 79 | ||
| 80 | upd7220_display_pixels_func m_display_cb; | |
| 81 | upd7220_draw_text_line m_draw_text_cb; | |
| 82 | ||
| 83 | devcb_write_line m_out_drq_cb; | |
| 84 | devcb_write_line m_out_hsync_cb; | |
| 85 | devcb_write_line m_out_vsync_cb; | |
| 86 | devcb_write_line m_out_blank_cb; | |
| 87 | }; | |
| 88 | ||
| 89 | // ======================> upd7220_device | |
| 90 | ||
| 91 | class upd7220_device : public device_t, | |
| 92 | public device_memory_interface, | |
| 93 | public upd7220_interface | |
| 94 | { | |
| 95 | public: | |
| 96 | // construction/destruction | |
| 97 | upd7220_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); | |
| 98 | ||
| 99 | DECLARE_READ8_MEMBER( read ); | |
| 100 | DECLARE_WRITE8_MEMBER( write ); | |
| 101 | ||
| 102 | DECLARE_READ8_MEMBER( dack_r ); | |
| 103 | DECLARE_WRITE8_MEMBER( dack_w ); | |
| 104 | ||
| 105 | DECLARE_WRITE_LINE_MEMBER( ext_sync_w ); | |
| 106 | DECLARE_WRITE_LINE_MEMBER( lpen_w ); | |
| 107 | ||
| 108 | DECLARE_WRITE8_MEMBER( bank_w ); | |
| 109 | DECLARE_READ8_MEMBER( vram_r ); | |
| 110 | DECLARE_WRITE8_MEMBER( vram_w ); | |
| 111 | ||
| 112 | UINT32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); | |
| 113 | virtual const rom_entry *device_rom_region() const; | |
| 114 | virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; | |
| 115 | ||
| 116 | protected: | |
| 117 | // device-level overrides | |
| 118 | virtual void device_start(); | |
| 119 | virtual void device_reset(); | |
| 120 | virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); | |
| 121 | virtual void device_config_complete(); | |
| 122 | ||
| 123 | private: | |
| 124 | static const device_timer_id TIMER_VSYNC = 0; | |
| 125 | static const device_timer_id TIMER_HSYNC = 1; | |
| 126 | static const device_timer_id TIMER_BLANK = 2; | |
| 127 | ||
| 128 | inline UINT8 readbyte(offs_t address); | |
| 129 | inline void writebyte(offs_t address, UINT8 data); | |
| 130 | inline void fifo_clear(); | |
| 131 | inline int fifo_param_count(); | |
| 132 | inline void fifo_set_direction(int dir); | |
| 133 | inline void queue(UINT8 data, int flag); | |
| 134 | inline void dequeue(UINT8 *data, int *flag); | |
| 135 | inline void update_vsync_timer(int state); | |
| 136 | inline void update_hsync_timer(int state); | |
| 137 | inline void update_blank_timer(int state); | |
| 138 | inline void recompute_parameters(); | |
| 139 | inline void reset_figs_param(); | |
| 140 | inline void advance_ead(); | |
| 141 | inline void read_vram(UINT8 type, UINT8 mod); | |
| 142 | inline void write_vram(UINT8 type, UINT8 mod); | |
| 143 | inline UINT16 check_pattern(UINT16 pattern); | |
| 144 | inline void get_text_partition(int index, UINT32 *sad, UINT16 *len, int *im, int *wd); | |
| 145 | inline void get_graphics_partition(int index, UINT32 *sad, UINT16 *len, int *im, int *wd); | |
| 146 | ||
| 147 | void draw_pixel(int x, int y, UINT8 tile_data); | |
| 148 | void draw_line(int x, int y); | |
| 149 | void draw_rectangle(int x, int y); | |
| 150 | void draw_char(int x, int y); | |
| 151 | int translate_command(UINT8 data); | |
| 152 | void process_fifo(); | |
| 153 | void update_text(bitmap_rgb32 &bitmap, const rectangle &cliprect); | |
| 154 | void draw_graphics_line(bitmap_rgb32 &bitmap, UINT32 addr, int y, int wd); | |
| 155 | void update_graphics(bitmap_rgb32 &bitmap, const rectangle &cliprect, int force_bitmap); | |
| 156 | ||
| 157 | devcb_resolved_write_line m_out_drq_func; | |
| 158 | devcb_resolved_write_line m_out_hsync_func; | |
| 159 | devcb_resolved_write_line m_out_vsync_func; | |
| 160 | devcb_resolved_write_line m_out_blank_func; | |
| 161 | ||
| 162 | screen_device *m_screen; | |
| 163 | ||
| 164 | UINT16 m_mask; // mask register | |
| 165 | UINT8 m_pitch; // number of word addresses in display memory in the horizontal direction | |
| 166 | UINT32 m_ead; // execute word address | |
| 167 | UINT16 m_dad; // dot address within the word | |
| 168 | UINT32 m_lad; // light pen address | |
| 169 | ||
| 170 | UINT8 m_ra[16]; // parameter RAM | |
| 171 | int m_ra_addr; // parameter RAM address | |
| 172 | ||
| 173 | UINT8 m_sr; // status register | |
| 174 | UINT8 m_cr; // command register | |
| 175 | UINT8 m_pr[17]; // parameter byte register | |
| 176 | int m_param_ptr; // parameter pointer | |
| 177 | ||
| 178 | UINT8 m_fifo[16]; // FIFO data queue | |
| 179 | int m_fifo_flag[16]; // FIFO flag queue | |
| 180 | int m_fifo_ptr; // FIFO pointer | |
| 181 | int m_fifo_dir; // FIFO direction | |
| 182 | ||
| 183 | UINT8 m_mode; // mode of operation | |
| 184 | UINT8 m_draw_mode; // mode of drawing | |
| 185 | ||
| 186 | int m_de; // display enabled | |
| 187 | int m_m; // 0 = accept external vertical sync (slave mode) / 1 = generate & output vertical sync (master mode) | |
| 188 | int m_aw; // active display words per line - 2 (must be even number with bit 0 = 0) | |
| 189 | int m_al; // active display lines per video field | |
| 190 | int m_vs; // vertical sync width - 1 | |
| 191 | int m_vfp; // vertical front porch width - 1 | |
| 192 | int m_vbp; // vertical back porch width - 1 | |
| 193 | int m_hs; // horizontal sync width - 1 | |
| 194 | int m_hfp; // horizontal front porch width - 1 | |
| 195 | int m_hbp; // horizontal back porch width - 1 | |
| 196 | ||
| 197 | int m_dc; // display cursor | |
| 198 | int m_sc; // 0 = blinking cursor / 1 = steady cursor | |
| 199 | int m_br; // blink rate | |
| 200 | int m_ctop; // cursor top line number in the row | |
| 201 | int m_cbot; // cursor bottom line number in the row (CBOT < LR) | |
| 202 | int m_lr; // lines per character row - 1 | |
| 203 | ||
| 204 | int m_disp; // display zoom factor | |
| 205 | int m_gchr; // zoom factor for graphics character writing and area filling | |
| 206 | ||
| 207 | UINT8 m_bitmap_mod; | |
| 208 | ||
| 209 | struct { | |
| 210 | UINT8 m_dir; // figs param 0: drawing direction | |
| 211 | UINT8 m_figure_type; // figs param 1: figure type | |
| 212 | UINT16 m_dc; // figs param 2: | |
| 213 | UINT16 m_d; // figs param 3: | |
| 214 | UINT16 m_d1; // figs param 4: | |
| 215 | UINT16 m_d2; // figs param 5: | |
| 216 | UINT16 m_dm; // figs param 6: | |
| 217 | } m_figs; | |
| 218 | ||
| 219 | // timers | |
| 220 | emu_timer *m_vsync_timer; // vertical sync timer | |
| 221 | emu_timer *m_hsync_timer; // horizontal sync timer | |
| 222 | emu_timer *m_blank_timer; // CRT blanking timer | |
| 223 | ||
| 224 | const address_space_config m_space_config; | |
| 225 | }; | |
| 226 | ||
| 227 | ||
| 228 | // device type definition | |
| 229 | extern const device_type UPD7220; | |
| 230 | ||
| 231 | ||
| 232 | ||
| 233 | #endif |
| Added: svn:eol-style + native Added: svn:mime-type + text/plain |
| r0 | r21685 | |
|---|---|---|
| 1 | /*************************************************************************** | |
| 2 | ||
| 3 | Hitachi HD44780 LCD controller | |
| 4 | ||
| 5 | TODO: | |
| 6 | - dump internal CGROM | |
| 7 | ||
| 8 | ***************************************************************************/ | |
| 9 | ||
| 10 | #include "emu.h" | |
| 11 | #include "video/hd44780.h" | |
| 12 | ||
| 13 | #define LOG 0 | |
| 14 | ||
| 15 | //************************************************************************** | |
| 16 | // DEVICE DEFINITIONS | |
| 17 | //************************************************************************** | |
| 18 | ||
| 19 | const device_type HD44780 = &device_creator<hd44780_device>; | |
| 20 | const device_type KS0066_F05 = &device_creator<ks0066_f05_device>; | |
| 21 | ||
| 22 | ||
| 23 | //------------------------------------------------- | |
| 24 | // ROM( hd44780 ) | |
| 25 | //------------------------------------------------- | |
| 26 | ||
| 27 | ROM_START( hd44780_a00 ) | |
| 28 | ROM_REGION( 0x1000, "cgrom", 0 ) | |
| 29 | ROM_LOAD( "hd44780_a00.bin", 0x0000, 0x1000, BAD_DUMP CRC(01d108e2) SHA1(bc0cdf0c9ba895f22e183c7bd35a3f655f2ca96f)) // from page 17 of the HD44780 datasheet | |
| 30 | ROM_END | |
| 31 | ||
| 32 | ROM_START( ks0066_f05 ) | |
| 33 | ROM_REGION( 0x1000, "cgrom", 0 ) | |
| 34 | ROM_LOAD( "ks0066_f05.bin", 0x0000, 0x1000, BAD_DUMP CRC(af9e7bd6) SHA1(0196e871584ee5d370856e7307c0f9d1466e3e51)) // from page 51 of the KS0066 datasheet | |
| 35 | ROM_END | |
| 36 | ||
| 37 | //************************************************************************** | |
| 38 | // live device | |
| 39 | //************************************************************************** | |
| 40 | ||
| 41 | //------------------------------------------------- | |
| 42 | // hd44780_device - constructor | |
| 43 | //------------------------------------------------- | |
| 44 | ||
| 45 | hd44780_device::hd44780_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : | |
| 46 | device_t(mconfig, HD44780, "HD44780 A00", tag, owner, clock), | |
| 47 | m_pixel_update_func(NULL) | |
| 48 | { | |
| 49 | m_shortname = "hd44780_a00"; | |
| 50 | set_charset_type(CHARSET_HD44780_A00); | |
| 51 | } | |
| 52 | ||
| 53 | hd44780_device::hd44780_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock) : | |
| 54 | device_t(mconfig, type, name, tag, owner, clock), | |
| 55 | m_pixel_update_func(NULL) | |
| 56 | { | |
| 57 | } | |
| 58 | ||
| 59 | ks0066_f05_device::ks0066_f05_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : | |
| 60 | hd44780_device(mconfig, KS0066_F05, "KS0066 F05", tag, owner, clock) | |
| 61 | { | |
| 62 | m_shortname = "ks0066_f05"; | |
| 63 | set_charset_type(CHARSET_KS0066_F05); | |
| 64 | } | |
| 65 | ||
| 66 | ||
| 67 | //------------------------------------------------- | |
| 68 | // rom_region - device-specific ROM region | |
| 69 | //------------------------------------------------- | |
| 70 | ||
| 71 | const rom_entry *hd44780_device::device_rom_region() const | |
| 72 | { | |
| 73 | switch (m_charset_type) | |
| 74 | { | |
| 75 | case CHARSET_HD44780_A00: return ROM_NAME( hd44780_a00 ); | |
| 76 | case CHARSET_KS0066_F05: return ROM_NAME( ks0066_f05 ); | |
| 77 | } | |
| 78 | ||
| 79 | return NULL; | |
| 80 | } | |
| 81 | ||
| 82 | //------------------------------------------------- | |
| 83 | // device_start - device-specific startup | |
| 84 | //------------------------------------------------- | |
| 85 | ||
| 86 | void hd44780_device::device_start() | |
| 87 | { | |
| 88 | if (region()) | |
| 89 | m_cgrom = (UINT8*)(*region()); | |
| 90 | else | |
| 91 | m_cgrom = (UINT8*)(*memregion("cgrom")); | |
| 92 | ||
| 93 | m_busy_timer = timer_alloc(TIMER_BUSY); | |
| 94 | m_blink_timer = timer_alloc(TIMER_BLINKING); | |
| 95 | m_blink_timer->adjust(attotime::from_msec(409), 0, attotime::from_msec(409)); | |
| 96 | ||
| 97 | // state saving | |
| 98 | save_item(NAME(m_busy_flag)); | |
| 99 | save_item(NAME(m_ac)); | |
| 100 | save_item(NAME(m_dr)); | |
| 101 | save_item(NAME(m_ir)); | |
| 102 | save_item(NAME(m_active_ram)); | |
| 103 | save_item(NAME(m_display_on)); | |
| 104 | save_item(NAME(m_cursor_on)); | |
| 105 | save_item(NAME(m_shift_on)); | |
| 106 | save_item(NAME(m_blink_on)); | |
| 107 | save_item(NAME(m_direction)); | |
| 108 | save_item(NAME(m_data_len)); | |
| 109 | save_item(NAME(m_num_line)); | |
| 110 | save_item(NAME(m_char_size)); | |
| 111 | save_item(NAME(m_disp_shift)); | |
| 112 | save_item(NAME(m_blink)); | |
| 113 | save_item(NAME(m_ddram)); | |
| 114 | save_item(NAME(m_cgram)); | |
| 115 | save_item(NAME(m_nibble)); | |
| 116 | save_item(NAME(m_rs_state)); | |
| 117 | save_item(NAME(m_rw_state)); | |
| 118 | } | |
| 119 | ||
| 120 | //------------------------------------------------- | |
| 121 | // device_reset - device-specific reset | |
| 122 | //------------------------------------------------- | |
| 123 | ||
| 124 | void hd44780_device::device_reset() | |
| 125 | { | |
| 126 | memset(m_ddram, 0x20, sizeof(m_ddram)); // can't use 0 here as it would show CGRAM instead of blank space on a soft reset | |
| 127 | memset(m_cgram, 0, sizeof(m_cgram)); | |
| 128 | ||
| 129 | m_ac = 0; | |
| 130 | m_dr = 0; | |
| 131 | m_ir = 0; | |
| 132 | m_active_ram = DDRAM; | |
| 133 | m_display_on = false; | |
| 134 | m_cursor_on = false; | |
| 135 | m_blink_on = false; | |
| 136 | m_shift_on = false; | |
| 137 | m_direction = 1; | |
| 138 | m_data_len = 8; | |
| 139 | m_num_line = 1; | |
| 140 | m_char_size = 8; | |
| 141 | m_disp_shift = 0; | |
| 142 | m_blink = false; | |
| 143 | m_nibble = false; | |
| 144 | m_first_cmd = true; | |
| 145 | m_rs_state = 0; | |
| 146 | m_rw_state = 0; | |
| 147 | ||
| 148 | set_busy_flag(1520); | |
| 149 | } | |
| 150 | ||
| 151 | ||
| 152 | //------------------------------------------------- | |
| 153 | // device_timer - handler timer events | |
| 154 | //------------------------------------------------- | |
| 155 | ||
| 156 | void hd44780_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) | |
| 157 | { | |
| 158 | switch(id) | |
| 159 | { | |
| 160 | case TIMER_BUSY: | |
| 161 | m_busy_flag = false; | |
| 162 | break; | |
| 163 | ||
| 164 | case TIMER_BLINKING: | |
| 165 | m_blink = !m_blink; | |
| 166 | break; | |
| 167 | } | |
| 168 | } | |
| 169 | ||
| 170 | ||
| 171 | //************************************************************************** | |
| 172 | // HELPERS | |
| 173 | //************************************************************************** | |
| 174 | ||
| 175 | void hd44780_device::set_charset_type(int type) | |
| 176 | { | |
| 177 | m_charset_type = type; | |
| 178 | } | |
| 179 | ||
| 180 | void hd44780_device::set_busy_flag(UINT16 usec) | |
| 181 | { | |
| 182 | m_busy_flag = true; | |
| 183 | m_busy_timer->adjust( attotime::from_usec( usec ) ); | |
| 184 | } | |
| 185 | ||
| 186 | void hd44780_device::update_ac(int direction) | |
| 187 | { | |
| 188 | if (m_active_ram == DDRAM) | |
| 189 | { | |
| 190 | if(direction == 1) | |
| 191 | { | |
| 192 | if(m_num_line == 2 && m_ac == 0x27) | |
| 193 | m_ac = 0x40; | |
| 194 | else if((m_num_line == 2 && m_ac == 0x67) || (m_num_line == 1 && m_ac == 0x4f)) | |
| 195 | m_ac = 0x00; | |
| 196 | else | |
| 197 | m_ac = (m_ac + direction) & 0x7f; | |
| 198 | } | |
| 199 | else | |
| 200 | { | |
| 201 | if(m_num_line == 2 && m_ac == 0x00) | |
| 202 | m_ac = 0x67; | |
| 203 | else if(m_num_line == 1 && m_ac == 0x00) | |
| 204 | m_ac = 0x4f; | |
| 205 | else if(m_num_line == 2 && m_ac == 0x40) | |
| 206 | m_ac = 0x27; | |
| 207 | else | |
| 208 | m_ac = (m_ac + direction) & 0x7f; | |
| 209 | } | |
| 210 | } | |
| 211 | else | |
| 212 | { | |
| 213 | m_ac = (m_ac + direction) & 0x3f; | |
| 214 | } | |
| 215 | } | |
| 216 | ||
| 217 | void hd44780_device::shift_display(int direction) | |
| 218 | { | |
| 219 | if (direction == 1) | |
| 220 | { | |
| 221 | if(m_disp_shift == 0x4f) | |
| 222 | m_disp_shift = 0x00; | |
| 223 | else | |
| 224 | m_disp_shift++; | |
| 225 | } | |
| 226 | else | |
| 227 | { | |
| 228 | if(m_disp_shift == 0x00) | |
| 229 | m_disp_shift = 0x4f; | |
| 230 | else | |
| 231 | m_disp_shift--; | |
| 232 | } | |
| 233 | } | |
| 234 | ||
| 235 | void hd44780_device::update_nibble(int rs, int rw) | |
| 236 | { | |
| 237 | if (m_rs_state != rs || m_rw_state != rw) | |
| 238 | { | |
| 239 | m_rs_state = rs; | |
| 240 | m_rw_state = rw; | |
| 241 | m_nibble = false; | |
| 242 | } | |
| 243 | ||
| 244 | m_nibble = !m_nibble; | |
| 245 | } | |
| 246 | ||
| 247 | inline void hd44780_device::pixel_update(bitmap_ind16 &bitmap, UINT8 line, UINT8 pos, UINT8 y, UINT8 x, int state) | |
| 248 | { | |
| 249 | if (m_pixel_update_func != NULL) | |
| 250 | { | |
| 251 | m_pixel_update_func(*this, bitmap, line, pos, y, x, state); | |
| 252 | } | |
| 253 | else | |
| 254 | { | |
| 255 | UINT8 line_heigh = (m_char_size == 8) ? m_char_size : m_char_size + 1; | |
| 256 | ||
| 257 | if (m_lines <= 2) | |
| 258 | { | |
| 259 | if (pos < m_chars) | |
| 260 | bitmap.pix16(line * (line_heigh+1) + y, pos * 6 + x) = state; | |
| 261 | } | |
| 262 | else if (m_lines <= 4) | |
| 263 | { | |
| 264 | if (pos < m_chars*2) | |
| 265 | { | |
| 266 | if (pos >= m_chars) | |
| 267 | { | |
| 268 | line += 2; | |
| 269 | pos -= m_chars; | |
| 270 | } | |
| 271 | ||
| 272 | if (line < m_lines) | |
| 273 | bitmap.pix16(line * (line_heigh+1) + y, pos * 6 + x) = state; | |
| 274 | } | |
| 275 | } | |
| 276 | else | |
| 277 | { | |
| 278 | fatalerror("%s: use a custom callback for this LCD configuration (%d x %d)\n", tag(), m_lines, m_chars); | |
| 279 | } | |
| 280 | } | |
| 281 | } | |
| 282 | ||
| 283 | ||
| 284 | //************************************************************************** | |
| 285 | // device interface | |
| 286 | //************************************************************************** | |
| 287 | ||
| 288 | UINT32 hd44780_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) | |
| 289 | { | |
| 290 | bitmap.fill(0, cliprect); | |
| 291 | ||
| 292 | if (m_display_on) | |
| 293 | { | |
| 294 | UINT8 line_size = 80 / m_num_line; | |
| 295 | ||
| 296 | for (int line=0; line<m_num_line; line++) | |
| 297 | { | |
| 298 | for (int pos=0; pos<line_size; pos++) | |
| 299 | { | |
| 300 | UINT16 char_pos = line * 0x40 + ((pos + m_disp_shift) % line_size); | |
| 301 | ||
| 302 | int char_base = 0; | |
| 303 | if (m_ddram[char_pos] < 0x10) | |
| 304 | { | |
| 305 | // draw CGRAM characters | |
| 306 | if (m_char_size == 8) | |
| 307 | char_base = (m_ddram[char_pos] & 0x07) * 8; | |
| 308 | else | |
| 309 | char_base = ((m_ddram[char_pos]>>1) & 0x03) * 16; | |
| 310 | } | |
| 311 | else | |
| 312 | { | |
| 313 | // draw CGROM characters | |
| 314 | char_base = m_ddram[char_pos] * 0x10; | |
| 315 | } | |
| 316 | ||
| 317 | for (int y=0; y<m_char_size; y++) | |
| 318 | { | |
| 319 | UINT8 * charset = (m_ddram[char_pos] < 0x10) ? m_cgram : m_cgrom; | |
| 320 | ||
| 321 | for (int x=0; x<5; x++) | |
| 322 | pixel_update(bitmap, line, pos, y, x, BIT(charset[char_base + y], 4 - x)); | |
| 323 | } | |
| 324 | ||
| 325 | // if is the correct position draw cursor and blink | |
| 326 | if (char_pos == m_ac) | |
| 327 | { | |
| 328 | // draw the cursor | |
| 329 | UINT8 cursor_pos = (m_char_size == 8) ? m_char_size : m_char_size + 1; | |
| 330 | if (m_cursor_on) | |
| 331 | for (int x=0; x<5; x++) | |
| 332 | pixel_update(bitmap, line, pos, cursor_pos - 1, x, 1); | |
| 333 | ||
| 334 | if (!m_blink && m_blink_on) | |
| 335 | for (int y=0; y<(cursor_pos - 1); y++) | |
| 336 | for (int x=0; x<5; x++) | |
| 337 | pixel_update(bitmap, line, pos, y, x, 1); | |
| 338 | } | |
| 339 | } | |
| 340 | } | |
| 341 | } | |
| 342 | ||
| 343 | return 0; | |
| 344 | } | |
| 345 | ||
| 346 | READ8_MEMBER(hd44780_device::read) | |
| 347 | { | |
| 348 | switch(offset & 0x01) | |
| 349 | { | |
| 350 | case 0: return control_read(space, 0); | |
| 351 | case 1: return data_read(space, 0); | |
| 352 | } | |
| 353 | ||
| 354 | return 0; | |
| 355 | } | |
| 356 | ||
| 357 | WRITE8_MEMBER(hd44780_device::write) | |
| 358 | { | |
| 359 | switch(offset & 0x01) | |
| 360 | { | |
| 361 | case 0: control_write(space, 0, data); break; | |
| 362 | case 1: data_write(space, 0, data); break; | |
| 363 | } | |
| 364 | } | |
| 365 | ||
| 366 | WRITE8_MEMBER(hd44780_device::control_write) | |
| 367 | { | |
| 368 | if (m_data_len == 4) | |
| 369 | { | |
| 370 | update_nibble(0, 0); | |
| 371 | ||
| 372 | if (m_nibble) | |
| 373 | { | |
| 374 | m_ir = data & 0xf0; | |
| 375 | return; | |
| 376 | } | |
| 377 | else | |
| 378 | { | |
| 379 | m_ir |= ((data>>4) & 0x0f); | |
| 380 | } | |
| 381 | } | |
| 382 | else | |
| 383 | { | |
| 384 | m_ir = data; | |
| 385 | } | |
| 386 | ||
| 387 | if (BIT(m_ir, 7)) // set DDRAM address | |
| 388 | { | |
| 389 | m_active_ram = DDRAM; | |
| 390 | m_ac = m_ir & 0x7f; | |
| 391 | set_busy_flag(37); | |
| 392 | ||
| 393 | if (LOG) logerror("HD44780 '%s': set DDRAM address %x\n", tag(), m_ac); | |
| 394 | } | |
| 395 | else if (BIT(m_ir, 6)) // set CGRAM address | |
| 396 | { | |
| 397 | m_active_ram = CGRAM; | |
| 398 | m_ac = m_ir & 0x3f; | |
| 399 | set_busy_flag(37); | |
| 400 | ||
| 401 | if (LOG) logerror("HD44780 '%s': set CGRAM address %x\n", tag(), m_ac); | |
| 402 | } | |
| 403 | else if (BIT(m_ir, 5)) // function set | |
| 404 | { | |
| 405 | if (!m_first_cmd && m_data_len == (BIT(m_ir, 4) ? 8 : 4) && (m_char_size != (BIT(m_ir, 2) ? 10 : 8) || m_num_line != (BIT(m_ir, 3) + 1))) | |
| 406 | { | |
| 407 | logerror("HD44780 '%s': function set cannot be executed after other instructions unless the interface data length is changed\n", tag()); | |
| 408 | return; | |
| 409 | } | |
| 410 | ||
| 411 | m_char_size = BIT(m_ir, 2) ? 10 : 8; | |
| 412 | m_data_len = BIT(m_ir, 4) ? 8 : 4; | |
| 413 | m_num_line = BIT(m_ir, 3) + 1; | |
| 414 | set_busy_flag(37); | |
| 415 | ||
| 416 | if (LOG) logerror("HD44780 '%s': char size 5x%d, data len %d, lines %d\n", tag(), m_char_size, m_data_len, m_num_line); | |
| 417 | return; | |
| 418 | } | |
| 419 | else if (BIT(m_ir, 4)) // cursor or display shift | |
| 420 | { | |
| 421 | int direct = (BIT(m_ir, 2)) ? +1 : -1; | |
| 422 | ||
| 423 | if (LOG) logerror("HD44780 '%s': %s shift %d\n", tag(), BIT(m_ir, 3) ? "display" : "cursor", direct); | |
| 424 | ||
| 425 | if (BIT(m_ir, 3)) | |
| 426 | shift_display(direct); | |
| 427 | else | |
| 428 | update_ac(direct); | |
| 429 | ||
| 430 | set_busy_flag(37); | |
| 431 | } | |
| 432 | else if (BIT(m_ir, 3)) // display on/off control | |
| 433 | { | |
| 434 | m_display_on = BIT(m_ir, 2); | |
| 435 | m_cursor_on = BIT(m_ir, 1); | |
| 436 | m_blink_on = BIT(m_ir, 0); | |
| 437 | set_busy_flag(37); | |
| 438 | ||
| 439 | if (LOG) logerror("HD44780 '%s': display %d, cursor %d, blink %d\n", tag(), m_display_on, m_cursor_on, m_blink_on); | |
| 440 | } | |
| 441 | else if (BIT(m_ir, 2)) // entry mode set | |
| 442 | { | |
| 443 | m_direction = (BIT(m_ir, 1)) ? +1 : -1; | |
| 444 | m_shift_on = BIT(m_ir, 0); | |
| 445 | set_busy_flag(37); | |
| 446 | ||
| 447 | if (LOG) logerror("HD44780 '%s': entry mode set: direction %d, shift %d\n", tag(), m_direction, m_shift_on); | |
| 448 | } | |
| 449 | else if (BIT(m_ir, 1)) // return home | |
| 450 | { | |
| 451 | if (LOG) logerror("HD44780 '%s': return home\n", tag()); | |
| 452 | ||
| 453 | m_ac = 0; | |
| 454 | m_active_ram = DDRAM; | |
| 455 | m_direction = 1; | |
| 456 | m_disp_shift = 0; | |
| 457 | set_busy_flag(1520); | |
| 458 | } | |
| 459 | else if (BIT(m_ir, 0)) // clear display | |
| 460 | { | |
| 461 | if (LOG) logerror("HD44780 '%s': clear display\n", tag()); | |
| 462 | ||
| 463 | m_ac = 0; | |
| 464 | m_active_ram = DDRAM; | |
| 465 | m_direction = 1; | |
| 466 | m_disp_shift = 0; | |
| 467 | memset(m_ddram, 0x20, sizeof(m_ddram)); | |
| 468 | set_busy_flag(1520); | |
| 469 | } | |
| 470 | ||
| 471 | m_first_cmd = false; | |
| 472 | } | |
| 473 | ||
| 474 | READ8_MEMBER(hd44780_device::control_read) | |
| 475 | { | |
| 476 | if (m_data_len == 4) | |
| 477 | { | |
| 478 | if (!space.debugger_access()) | |
| 479 | update_nibble(0, 1); | |
| 480 | ||
| 481 | if (m_nibble) | |
| 482 | return (m_busy_flag ? 0x80 : 0) | (m_ac & 0x70); | |
| 483 | else | |
| 484 | return (m_ac<<4) & 0xf0; | |
| 485 | } | |
| 486 | else | |
| 487 | { | |
| 488 | return (m_busy_flag ? 0x80 : 0) | (m_ac & 0x7f); | |
| 489 | } | |
| 490 | } | |
| 491 | ||
| 492 | WRITE8_MEMBER(hd44780_device::data_write) | |
| 493 | { | |
| 494 | if (m_busy_flag) | |
| 495 | { | |
| 496 | logerror("HD44780 '%s': Ignoring data write %02x due of busy flag\n", tag(), data); | |
| 497 | return; | |
| 498 | } | |
| 499 | ||
| 500 | if (m_data_len == 4) | |
| 501 | { | |
| 502 | update_nibble(1, 0); | |
| 503 | ||
| 504 | if (m_nibble) | |
| 505 | { | |
| 506 | m_dr = data & 0xf0; | |
| 507 | return; | |
| 508 | } | |
| 509 | else | |
| 510 | { | |
| 511 | m_dr |= ((data>>4) & 0x0f); | |
| 512 | } | |
| 513 | } | |
| 514 | else | |
| 515 | { | |
| 516 | m_dr = data; | |
| 517 | } | |
| 518 | ||
| 519 | if (LOG) logerror("HD44780 '%s': %sRAM write %x %x '%c'\n", tag(), m_active_ram == DDRAM ? "DD" : "CG", m_ac, m_dr, isprint(m_dr) ? m_dr : '.'); | |
| 520 | ||
| 521 | if (m_active_ram == DDRAM) | |
| 522 | m_ddram[m_ac] = m_dr; | |
| 523 | else | |
| 524 | m_cgram[m_ac] = m_dr; | |
| 525 | ||
| 526 | update_ac(m_direction); | |
| 527 | if (m_shift_on) | |
| 528 | shift_display(m_direction); | |
| 529 | set_busy_flag(41); | |
| 530 | } | |
| 531 | ||
| 532 | READ8_MEMBER(hd44780_device::data_read) | |
| 533 | { | |
| 534 | UINT8 data = (m_active_ram == DDRAM) ? m_ddram[m_ac] : m_cgram[m_ac]; | |
| 535 | ||
| 536 | if (LOG) logerror("HD44780 '%s': %sRAM read %x %c\n", tag(), m_active_ram == DDRAM ? "DD" : "CG", m_ac, data); | |
| 537 | ||
| 538 | if (m_data_len == 4) | |
| 539 | { | |
| 540 | if (!space.debugger_access()) | |
| 541 | update_nibble(1, 1); | |
| 542 | ||
| 543 | if (m_nibble) | |
| 544 | return data & 0xf0; | |
| 545 | else | |
| 546 | data = (data<<4) & 0xf0; | |
| 547 | } | |
| 548 | ||
| 549 | if (!space.debugger_access()) | |
| 550 | { | |
| 551 | update_ac(m_direction); | |
| 552 | set_busy_flag(41); | |
| 553 | } | |
| 554 | ||
| 555 | return data; | |
| 556 | } |
| Added: svn:mime-type + text/plain Added: svn:eol-style + native |
| r0 | r21685 | |
|---|---|---|
| 1 | /*************************************************************************** | |
| 2 | ||
| 3 | Hitachi HD44780 LCD controller | |
| 4 | ||
| 5 | ***************************************************************************/ | |
| 6 | ||
| 7 | #pragma once | |
| 8 | ||
| 9 | #ifndef __HD44780_H__ | |
| 10 | #define __HD44780_H__ | |
| 11 | ||
| 12 | ||
| 13 | #define MCFG_HD44780_ADD( _tag ) \ | |
| 14 | MCFG_DEVICE_ADD( _tag, HD44780, 0 ) | |
| 15 | ||
| 16 | #define MCFG_KS0066_F05_ADD( _tag ) \ | |
| 17 | MCFG_DEVICE_ADD( _tag, KS0066_F05, 0 ) | |
| 18 | ||
| 19 | #define MCFG_HD44780_LCD_SIZE(_lines, _chars) \ | |
| 20 | hd44780_device::static_set_lcd_size(*device, _lines, _chars); | |
| 21 | ||
| 22 | #define MCFG_HD44780_PIXEL_UPDATE_CB(_cb) \ | |
| 23 | hd44780_device::static_set_pixel_update_cb(*device, _cb); | |
| 24 | ||
| 25 | //************************************************************************** | |
| 26 | // TYPE DEFINITIONS | |
| 27 | //************************************************************************** | |
| 28 | ||
| 29 | typedef void (*hd44780_pixel_update_func)(device_t &device, bitmap_ind16 &bitmap, UINT8 line, UINT8 pos, UINT8 y, UINT8 x, int state); | |
| 30 | #define HD44780_PIXEL_UPDATE(name) void name(device_t &device, bitmap_ind16 &bitmap, UINT8 line, UINT8 pos, UINT8 y, UINT8 x, int state) | |
| 31 | ||
| 32 | ||
| 33 | // ======================> hd44780_device | |
| 34 | ||
| 35 | class hd44780_device : public device_t | |
| 36 | { | |
| 37 | public: | |
| 38 | // construction/destruction | |
| 39 | hd44780_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); | |
| 40 | hd44780_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock); | |
| 41 | ||
| 42 | // static configuration helpers | |
| 43 | static void static_set_lcd_size(device_t &device, int _lines, int _chars) { hd44780_device &dev=downcast<hd44780_device &>(device); dev.m_lines = _lines; dev.m_chars = _chars; } | |
| 44 | static void static_set_pixel_update_cb(device_t &device, hd44780_pixel_update_func _cb) { downcast<hd44780_device &>(device).m_pixel_update_func = _cb; } | |
| 45 | ||
| 46 | // device interface | |
| 47 | virtual DECLARE_WRITE8_MEMBER(write); | |
| 48 | virtual DECLARE_READ8_MEMBER(read); | |
| 49 | virtual DECLARE_WRITE8_MEMBER(control_write); | |
| 50 | virtual DECLARE_READ8_MEMBER(control_read); | |
| 51 | virtual DECLARE_WRITE8_MEMBER(data_write); | |
| 52 | virtual DECLARE_READ8_MEMBER(data_read); | |
| 53 | virtual UINT32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); | |
| 54 | ||
| 55 | protected: | |
| 56 | // device-level overrides | |
| 57 | virtual void device_start(); | |
| 58 | virtual void device_reset(); | |
| 59 | virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); | |
| 60 | ||
| 61 | // optional information overrides | |
| 62 | virtual const rom_entry *device_rom_region() const; | |
| 63 | ||
| 64 | // charset | |
| 65 | enum | |
| 66 | { | |
| 67 | CHARSET_HD44780_A00, | |
| 68 | CHARSET_KS0066_F05, | |
| 69 | /* | |
| 70 | CHARSET_HD44780_A01, | |
| 71 | CHARSET_HD44780_A02, | |
| 72 | CHARSET_KS0066_F00, | |
| 73 | CHARSET_KS0066_F03, | |
| 74 | CHARSET_KS0066_F04, | |
| 75 | CHARSET_KS0066_F06, | |
| 76 | CHARSET_KS0066_F59, | |
| 77 | */ | |
| 78 | }; | |
| 79 | ||
| 80 | void set_charset_type(int type); | |
| 81 | ||
| 82 | private: | |
| 83 | // internal helper | |
| 84 | void set_busy_flag(UINT16 usec); | |
| 85 | void update_ac(int direction); | |
| 86 | void update_nibble(int rs, int rw); | |
| 87 | void shift_display(int direction); | |
| 88 | void pixel_update(bitmap_ind16 &bitmap, UINT8 line, UINT8 pos, UINT8 y, UINT8 x, int state); | |
| 89 | ||
| 90 | // internal state | |
| 91 | static const device_timer_id TIMER_BUSY = 0; | |
| 92 | static const device_timer_id TIMER_BLINKING = 1; | |
| 93 | ||
| 94 | emu_timer * m_blink_timer; | |
| 95 | emu_timer * m_busy_timer; | |
| 96 | ||
| 97 | UINT8 m_lines; // number of lines | |
| 98 | UINT8 m_chars; // chars for line | |
| 99 | hd44780_pixel_update_func m_pixel_update_func; // pixel update callback | |
| 100 | ||
| 101 | bool m_busy_flag; // busy flag | |
| 102 | UINT8 m_ddram[0x80]; // internal display data RAM | |
| 103 | UINT8 m_cgram[0x40]; // internal chargen RAM | |
| 104 | UINT8 * m_cgrom; // internal chargen ROM | |
| 105 | INT8 m_ac; // address counter | |
| 106 | UINT8 m_dr; // data register | |
| 107 | UINT8 m_ir; // instruction register | |
| 108 | UINT8 m_active_ram; // DDRAM or CGRAM | |
| 109 | bool m_display_on; // display on/off | |
| 110 | bool m_cursor_on; // cursor on/off | |
| 111 | bool m_blink_on; // blink on/off | |
| 112 | bool m_shift_on; // shift on/off | |
| 113 | UINT8 m_disp_shift; // display shift | |
| 114 | INT8 m_direction; // auto increment/decrement | |
| 115 | UINT8 m_data_len; // interface data length 4 or 8 bit | |
| 116 | UINT8 m_num_line; // number of lines | |
| 117 | UINT8 m_char_size; // char size 5x8 or 5x10 | |
| 118 | bool m_blink; | |
| 119 | bool m_first_cmd; | |
| 120 | int m_rs_state; | |
| 121 | int m_rw_state; | |
| 122 | bool m_nibble; | |
| 123 | int m_charset_type; | |
| 124 | ||
| 125 | enum { DDRAM, CGRAM }; | |
| 126 | }; | |
| 127 | ||
| 128 | // ======================> ks0066_f05_device | |
| 129 | ||
| 130 | class ks0066_f05_device : public hd44780_device | |
| 131 | { | |
| 132 | public: | |
| 133 | // construction/destruction | |
| 134 | ks0066_f05_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); | |
| 135 | }; | |
| 136 | ||
| 137 | // device type definition | |
| 138 | extern const device_type HD44780; | |
| 139 | extern const device_type KS0066_F05; | |
| 140 | ||
| 141 | #endif |
| Added: svn:mime-type + text/plain Added: svn:eol-style + native |
| r21684 | r21685 | |
|---|---|---|
| 1 | /***************************************************************************** | |
| 2 | * | |
| 3 | * includes/c64.h | |
| 4 | * | |
| 5 | * Commodore C64 Home Computer | |
| 6 | * | |
| 7 | * peter.trauner@jk.uni-linz.ac.at | |
| 8 | * | |
| 9 | * Documentation: www.funet.fi | |
| 10 | * | |
| 11 | ****************************************************************************/ | |
| 12 | ||
| 13 | #ifndef C64_H_ | |
| 14 | #define C64_H_ | |
| 15 | ||
| 16 | #include "machine/6526cia.h" | |
| 17 | #include "machine/cbmiec.h" | |
| 18 | #include "imagedev/cartslot.h" | |
| 19 | ||
| 20 | #define C64_MAX_ROMBANK 64 // .crt files contain multiple 'CHIPs', i.e. rom banks (of variable size) with headers. Known carts have at most 64 'CHIPs'. | |
| 21 | ||
| 22 | struct C64_ROM { | |
| 23 | int addr, size, index, start; | |
| 24 | }; | |
| 25 | ||
| 26 | struct c64_cart_t { | |
| 27 | C64_ROM bank[C64_MAX_ROMBANK]; | |
| 28 | INT8 game; | |
| 29 | INT8 exrom; | |
| 30 | UINT8 mapper; | |
| 31 | UINT8 n_banks; | |
| 32 | }; | |
| 33 | ||
| 34 | class legacy_c64_state : public driver_device | |
| 35 | { | |
| 36 | public: | |
| 37 | legacy_c64_state(const machine_config &mconfig, device_type type, const char *tag) | |
| 38 | : driver_device(mconfig, type, tag), | |
| 39 | m_iec(*this, CBM_IEC_TAG), | |
| 40 | m_colorram(*this, "colorram"), | |
| 41 | m_basic(*this, "basic"), | |
| 42 | m_chargen(*this, "chargen"), | |
| 43 | m_kernal(*this, "kernal"), | |
| 44 | m_roml_writable(0) | |
| 45 | { } | |
| 46 | ||
| 47 | optional_device<cbm_iec_device> m_iec; | |
| 48 | ||
| 49 | required_shared_ptr<UINT8> m_colorram; | |
| 50 | required_shared_ptr<UINT8> m_basic; | |
| 51 | required_shared_ptr<UINT8> m_chargen; | |
| 52 | required_shared_ptr<UINT8> m_kernal; | |
| 53 | ||
| 54 | DECLARE_READ8_MEMBER( c64_lightpen_x_cb ); | |
| 55 | DECLARE_READ8_MEMBER( c64_lightpen_y_cb ); | |
| 56 | DECLARE_READ8_MEMBER( c64_lightpen_button_cb ); | |
| 57 | DECLARE_READ8_MEMBER( c64_dma_read ); | |
| 58 | DECLARE_READ8_MEMBER( c64_dma_read_ultimax ); | |
| 59 | DECLARE_READ8_MEMBER( c64_dma_read_color ); | |
| 60 | DECLARE_WRITE_LINE_MEMBER( c64_vic_interrupt ); | |
| 61 | DECLARE_READ8_MEMBER( c64_rdy_cb ); | |
| 62 | ||
| 63 | int m_old_level; | |
| 64 | int m_old_data; | |
| 65 | int m_old_exrom; | |
| 66 | int m_old_game; | |
| 67 | UINT8 m_vicirq; | |
| 68 | emu_timer *m_datasette_timer; | |
| 69 | emu_timer *m_cartridge_timer; | |
| 70 | UINT8 *m_memory; | |
| 71 | int m_pal; | |
| 72 | int m_tape_on; | |
| 73 | UINT8 *m_c64_roml; | |
| 74 | UINT8 *m_c64_romh; | |
| 75 | UINT8 *m_vicaddr; | |
| 76 | UINT8 *m_c128_vicaddr; | |
| 77 | UINT8 m_game; | |
| 78 | UINT8 m_exrom; | |
| 79 | UINT8 *m_io_mirror; | |
| 80 | UINT8 m_port_data; | |
| 81 | UINT8 *m_roml; | |
| 82 | UINT8 *m_romh; | |
| 83 | int m_roml_writable; | |
| 84 | int m_ultimax; | |
| 85 | int m_cia1_on; | |
| 86 | int m_io_enabled; | |
| 87 | int m_is_sx64; | |
| 88 | UINT8 *m_io_ram_w_ptr; | |
| 89 | UINT8 *m_io_ram_r_ptr; | |
| 90 | c64_cart_t m_cart; | |
| 91 | int m_nmilevel; | |
| 92 | void c64_legacy_driver_init(); | |
| 93 | DECLARE_DEVICE_IMAGE_LOAD_MEMBER( c64_cart ); | |
| 94 | DECLARE_DEVICE_IMAGE_UNLOAD_MEMBER( c64_cart ); | |
| 95 | }; | |
| 96 | ||
| 97 | ||
| 98 | /*----------- defined in machine/c64.c -----------*/ | |
| 99 | ||
| 100 | ||
| 101 | DECLARE_READ8_HANDLER ( c64_colorram_read ); | |
| 102 | DECLARE_WRITE8_HANDLER ( c64_colorram_write ); | |
| 103 | int c64_paddle_read (device_t *device, address_space &space, int which); | |
| 104 | MACHINE_CONFIG_EXTERN( c64_cartslot ); | |
| 105 | #endif /* C64_H_ */ |
| r21684 | r21685 | |
|---|---|---|
| 7 | 7 | #ifndef C65_H_ |
| 8 | 8 | #define C65_H_ |
| 9 | 9 | |
| 10 | #include "includes/c64_legacy.h" | |
| 11 | 10 | #include "machine/6526cia.h" |
| 11 | #include "machine/cbmiec.h" | |
| 12 | #include "imagedev/cartslot.h" | |
| 12 | 13 | |
| 14 | #define C64_MAX_ROMBANK 64 // .crt files contain multiple 'CHIPs', i.e. rom banks (of variable size) with headers. Known carts have at most 64 'CHIPs'. | |
| 15 | ||
| 16 | struct C64_ROM { | |
| 17 | int addr, size, index, start; | |
| 18 | }; | |
| 19 | ||
| 20 | struct c64_cart_t { | |
| 21 | C64_ROM bank[C64_MAX_ROMBANK]; | |
| 22 | INT8 game; | |
| 23 | INT8 exrom; | |
| 24 | UINT8 mapper; | |
| 25 | UINT8 n_banks; | |
| 26 | }; | |
| 27 | ||
| 13 | 28 | struct dma_t |
| 14 | 29 | { |
| 15 | 30 | int version; |
| r21684 | r21685 | |
| 37 | 52 | UINT8 reg; |
| 38 | 53 | }; |
| 39 | 54 | |
| 40 | class c65_state : public | |
| 55 | class c65_state : public driver_device | |
| 41 | 56 | { |
| 42 | 57 | public: |
| 43 | 58 | c65_state(const machine_config &mconfig, device_type type, const char *tag) |
| 44 | : legacy_c64_state(mconfig, type, tag), | |
| 59 | : driver_device(mconfig, type, tag), | |
| 60 | m_iec(*this, CBM_IEC_TAG), | |
| 61 | m_colorram(*this, "colorram"), | |
| 62 | m_basic(*this, "basic"), | |
| 63 | m_chargen(*this, "chargen"), | |
| 64 | m_kernal(*this, "kernal"), | |
| 45 | 65 | m_c65_chargen(*this, "c65_chargen"), |
| 46 | m_interface(*this, "interface") | |
| 66 | m_interface(*this, "interface"), | |
| 67 | m_roml_writable(0) | |
| 47 | 68 | { } |
| 48 | 69 | |
| 70 | optional_device<cbm_iec_device> m_iec; | |
| 71 | ||
| 72 | required_shared_ptr<UINT8> m_colorram; | |
| 73 | required_shared_ptr<UINT8> m_basic; | |
| 74 | required_shared_ptr<UINT8> m_chargen; | |
| 75 | required_shared_ptr<UINT8> m_kernal; | |
| 49 | 76 | required_shared_ptr<UINT8> m_c65_chargen; |
| 50 | 77 | required_shared_ptr<UINT8> m_interface; |
| 51 | int m_charset_select; | |
| 78 | int m_old_level; | |
| 79 | int m_old_data; | |
| 80 | int m_old_exrom; | |
| 81 | int m_old_game; | |
| 82 | UINT8 m_vicirq; | |
| 83 | emu_timer *m_datasette_timer; | |
| 84 | emu_timer *m_cartridge_timer; | |
| 85 | UINT8 *m_memory; | |
| 86 | int m_pal; | |
| 87 | int m_tape_on; | |
| 88 | UINT8 *m_c64_roml; | |
| 89 | UINT8 *m_c64_romh; | |
| 90 | UINT8 *m_vicaddr; | |
| 91 | UINT8 *m_c128_vicaddr; | |
| 92 | UINT8 m_game; | |
| 93 | UINT8 m_exrom; | |
| 94 | UINT8 *m_io_mirror; | |
| 95 | UINT8 m_port_data; | |
| 96 | UINT8 *m_roml; | |
| 97 | UINT8 *m_romh; | |
| 98 | int m_roml_writable; | |
| 99 | int m_ultimax; | |
| 100 | int m_cia1_on; | |
| 101 | int m_io_enabled; | |
| 102 | int m_is_sx64; | |
| 103 | UINT8 *m_io_ram_w_ptr; | |
| 104 | UINT8 *m_io_ram_r_ptr; | |
| 105 | c64_cart_t m_cart; | |
| 106 | int m_nmilevel; int m_charset_select; | |
| 52 | 107 | int m_c64mode; |
| 53 | 108 | UINT8 m_6511_port; |
| 54 | 109 | UINT8 m_keyline; |
| 55 | 110 | int m_old_value; |
| 56 | int m_nmilevel; | |
| 57 | 111 | dma_t m_dma; |
| 58 | 112 | int m_dump_dma; |
| 59 | 113 | fdc_t m_fdc; |
| r21684 | r21685 | |
| 63 | 117 | DECLARE_DRIVER_INIT(c65); |
| 64 | 118 | DECLARE_DRIVER_INIT(c65pal); |
| 65 | 119 | |
| 120 | DECLARE_READ8_MEMBER( c64_lightpen_x_cb ); | |
| 121 | DECLARE_READ8_MEMBER( c64_lightpen_y_cb ); | |
| 122 | DECLARE_READ8_MEMBER( c64_lightpen_button_cb ); | |
| 123 | DECLARE_READ8_MEMBER( c64_dma_read ); | |
| 124 | DECLARE_READ8_MEMBER( c64_dma_read_ultimax ); | |
| 125 | DECLARE_READ8_MEMBER( c64_dma_read_color ); | |
| 126 | DECLARE_WRITE_LINE_MEMBER( c64_vic_interrupt ); | |
| 127 | DECLARE_READ8_MEMBER( c64_rdy_cb ); | |
| 66 | 128 | DECLARE_READ8_MEMBER( sid_potx_r ); |
| 67 | 129 | DECLARE_READ8_MEMBER( sid_poty_r ); |
| 68 | 130 | DECLARE_MACHINE_START(c65); |
| r21684 | r21685 | |
| 76 | 138 | DECLARE_READ8_MEMBER(c65_cia1_port_a_r); |
| 77 | 139 | DECLARE_WRITE8_MEMBER(c65_cia1_port_a_w); |
| 78 | 140 | DECLARE_WRITE_LINE_MEMBER(c65_cia1_interrupt); |
| 141 | void c64_legacy_driver_init(); | |
| 142 | DECLARE_DEVICE_IMAGE_LOAD_MEMBER( c64_cart ); | |
| 143 | DECLARE_DEVICE_IMAGE_UNLOAD_MEMBER( c64_cart ); | |
| 79 | 144 | }; |
| 80 | 145 | |
| 81 | 146 | |
| r21684 | r21685 | |
| 99 | 164 | extern const legacy_mos6526_interface c65_cia0; |
| 100 | 165 | extern const legacy_mos6526_interface c65_cia1; |
| 101 | 166 | |
| 167 | DECLARE_READ8_HANDLER ( c64_colorram_read ); | |
| 168 | DECLARE_WRITE8_HANDLER ( c64_colorram_write ); | |
| 169 | MACHINE_CONFIG_EXTERN( c64_cartslot ); | |
| 170 | ||
| 102 | 171 | #endif /* C65_H_ */ |
| r21684 | r21685 | |
|---|---|---|
| 1 | /***************************************************************************** | |
| 2 | * | |
| 3 | * video/dl1416.c | |
| 4 | * | |
| 5 | * DL1416 | |
| 6 | * | |
| 7 | * 4-Digit 16-Segment Alphanumeric Intelligent Display | |
| 8 | * with Memory/Decoder/Driver | |
| 9 | * | |
| 10 | * Notes: | |
| 11 | * - Currently supports the DL1416T and by virtue of it being nearly the same, the DL1414. | |
| 12 | * - Partial support for DL1416B is available, it just needs the right | |
| 13 | * character set and MAME core support for its display. | |
| 14 | * - Cursor support is implemented but not tested, as the AIM65 does not | |
| 15 | * seem to use it. | |
| 16 | * | |
| 17 | * Todo: | |
| 18 | * - Is the DL1416A identical to the DL1416T? If not, we need to add | |
| 19 | * support for it. | |
| 20 | * - Add proper support for DL1414 (pretty much DL1416T without the cursor) | |
| 21 | * | |
| 22 | * Changes: | |
| 23 | * - 2007-07-30: Initial version. [Dirk Best] | |
| 24 | * - 2008-02-25: Converted to the new device interface. [Dirk Best] | |
| 25 | * - 2008-12-18: Cleanups. [Dirk Best] | |
| 26 | * - 2011-10-08: Changed the ram to store character rather than segment data. [Lord Nightmare] | |
| 27 | * | |
| 28 | * | |
| 29 | * We use the following order for the segments: | |
| 30 | * | |
| 31 | * 000 111 | |
| 32 | * 7D A E2 | |
| 33 | * 7 D A E 2 | |
| 34 | * 7 DAE 2 | |
| 35 | * 888 999 | |
| 36 | * 6 CBF 3 | |
| 37 | * 6 C B F 3 | |
| 38 | * 6C B F3 | |
| 39 | * 555 444 | |
| 40 | * | |
| 41 | ****************************************************************************/ | |
| 42 | ||
| 43 | #include "emu.h" | |
| 44 | #include "dl1416.h" | |
| 45 | ||
| 46 | ||
| 47 | /*************************************************************************** | |
| 48 | CONSTANTS | |
| 49 | ***************************************************************************/ | |
| 50 | ||
| 51 | #define SEG_UNDEF (-2) | |
| 52 | #define SEG_BLANK (0) | |
| 53 | #define SEG_CURSOR (0xffff) | |
| 54 | #define CURSOR_ON (1) | |
| 55 | #define CURSOR_OFF (0) | |
| 56 | ||
| 57 | /* character set DL1416T */ | |
| 58 | static const int dl1416t_segments[128] = { | |
| 59 | SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, /* undefined */ | |
| 60 | SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, /* undefined */ | |
| 61 | SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, /* undefined */ | |
| 62 | SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, /* undefined */ | |
| 63 | SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, /* undefined */ | |
| 64 | SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, /* undefined */ | |
| 65 | SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, /* undefined */ | |
| 66 | SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, /* undefined */ | |
| 67 | 0x0000, 0x2421, 0x0480, 0x0f3c, /* ! " # */ | |
| 68 | 0x0fbb, 0x5f99, 0xa579, 0x4000, /* $ % & ' */ | |
| 69 | 0xc000, 0x3000, 0xff00, 0x0f00, /* ( ) * + */ | |
| 70 | 0x1000, 0x0300, 0x0020, 0x5000, /* , - . / */ | |
| 71 | 0x0ce1, 0x0c00, 0x0561, 0x0d21, /* 0 1 2 3 */ | |
| 72 | 0x0d80, 0x09a1, 0x09e1, 0x0c01, /* 4 5 6 7 */ | |
| 73 | 0x0de1, 0x0da1, 0x0021, 0x1001, /* 8 9 : ; */ | |
| 74 | 0x5030, 0x0330, 0xa030, 0x0a07, /* < = > ? */ | |
| 75 | 0x097f, 0x03cf, 0x0e3f, 0x00f3, /* @ A B C */ | |
| 76 | 0x0c3f, 0x01f3, 0x01c3, 0x02fb, /* D E F G */ | |
| 77 | 0x03cc, 0x0c33, 0x0c63, 0xc1c0, /* H I J K */ | |
| 78 | 0x00f0, 0x60cc, 0xa0cc, 0x00ff, /* L M N O */ | |
| 79 | 0x03c7, 0x80ff, 0x83c7, 0x03bb, /* P Q R S */ | |
| 80 | 0x0c03, 0x00fc, 0x50c0, 0x90cc, /* T U V W */ | |
| 81 | 0xf000, 0x6800, 0x5033, 0x00e1, /* X Y Z [ */ | |
| 82 | 0xa000, 0x001e, 0x9000, 0x0030, /* \ ] ^ _ */ | |
| 83 | SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, /* undefined */ | |
| 84 | SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, /* undefined */ | |
| 85 | SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, /* undefined */ | |
| 86 | SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, /* undefined */ | |
| 87 | SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, /* undefined */ | |
| 88 | SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, /* undefined */ | |
| 89 | SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, /* undefined */ | |
| 90 | SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF /* undefined */ | |
| 91 | }; | |
| 92 | ||
| 93 | ||
| 94 | /*************************************************************************** | |
| 95 | TYPE DEFINITIONS | |
| 96 | ***************************************************************************/ | |
| 97 | ||
| 98 | struct dl1416_state | |
| 99 | { | |
| 100 | int write_enable; | |
| 101 | int chip_enable; | |
| 102 | int cursor_enable; | |
| 103 | ||
| 104 | UINT16 digit_ram[4]; // holds the digit code for each position | |
| 105 | UINT8 cursor_state[4]; // holds the cursor state for each position, 0=off, 1=on | |
| 106 | }; | |
| 107 | ||
| 108 | ||
| 109 | /***************************************************************************** | |
| 110 | INLINE FUNCTIONS | |
| 111 | *****************************************************************************/ | |
| 112 | ||
| 113 | INLINE dl1416_state *get_safe_token(device_t *device) | |
| 114 | { | |
| 115 | assert(device != NULL); | |
| 116 | assert(device->type() == DL1416B || device->type() == DL1416T); | |
| 117 | ||
| 118 | return (dl1416_state *)downcast<dl1416_device *>(device)->token(); | |
| 119 | } | |
| 120 | ||
| 121 | ||
| 122 | /***************************************************************************** | |
| 123 | DEVICE INTERFACE | |
| 124 | *****************************************************************************/ | |
| 125 | ||
| 126 | static DEVICE_START( dl1416 ) | |
| 127 | { | |
| 128 | dl1416_state *dl1416 = get_safe_token(device); | |
| 129 | ||
| 130 | /* register for state saving */ | |
| 131 | state_save_register_item(device->machine(), "dl1416", device->tag(), 0, dl1416->chip_enable); | |
| 132 | state_save_register_item(device->machine(), "dl1416", device->tag(), 0, dl1416->cursor_enable); | |
| 133 | state_save_register_item(device->machine(), "dl1416", device->tag(), 0, dl1416->write_enable); | |
| 134 | state_save_register_item_array(device->machine(), "dl1416", device->tag(), 0, dl1416->digit_ram); | |
| 135 | } | |
| 136 | ||
| 137 | ||
| 138 | static DEVICE_RESET( dl1416 ) | |
| 139 | { | |
| 140 | int i, pattern; | |
| 141 | dl1416_state *chip = get_safe_token(device); | |
| 142 | const dl1416_interface *intf = (const dl1416_interface *)device->static_config(); | |
| 143 | /* disable all lines */ | |
| 144 | chip->chip_enable = FALSE; | |
| 145 | chip->write_enable = FALSE; | |
| 146 | chip->cursor_enable = FALSE; | |
| 147 | ||
| 148 | /* randomize digit and cursor memory */ | |
| 149 | for (i = 0; i < 4; i++) | |
| 150 | { | |
| 151 | chip->digit_ram[i] = device->machine().rand()&0x3F; | |
| 152 | // TODO: only enable the following line if the device actually has a cursor (DL1416T and DL1416B), if DL1414 then cursor is always 0! | |
| 153 | //chip->cursor_state[i] = ((device->machine().rand()&0xFF) >= 0x80) ? CURSOR_ON : CURSOR_OFF; | |
| 154 | chip->cursor_state[i] = CURSOR_OFF; | |
| 155 | pattern = dl1416t_segments[chip->digit_ram[i]]; | |
| 156 | ||
| 157 | /* If cursor for this digit position is enabled and segment is not */ | |
| 158 | /* undefined, replace digit with cursor */ | |
| 159 | if ((chip->cursor_state[i] == CURSOR_ON) && (pattern != SEG_UNDEF)) | |
| 160 | pattern = SEG_CURSOR; | |
| 161 | ||
| 162 | /* Undefined characters are replaced by blanks */ | |
| 163 | if (pattern == SEG_UNDEF) | |
| 164 | pattern = SEG_BLANK; | |
| 165 | ||
| 166 | /* Call update function */ | |
| 167 | if (intf->update) | |
| 168 | intf->update(device, i, pattern); | |
| 169 | } | |
| 170 | } | |
| 171 | ||
| 172 | ||
| 173 | /***************************************************************************** | |
| 174 | IMPLEMENTATION | |
| 175 | *****************************************************************************/ | |
| 176 | ||
| 177 | /* write enable, active low */ | |
| 178 | WRITE_LINE_DEVICE_HANDLER( dl1416_wr_w ) | |
| 179 | { | |
| 180 | dl1416_state *chip = get_safe_token(device); | |
| 181 | chip->write_enable = !state; | |
| 182 | } | |
| 183 | ||
| 184 | /* chip enable, active low */ | |
| 185 | WRITE_LINE_DEVICE_HANDLER( dl1416_ce_w ) | |
| 186 | { | |
| 187 | dl1416_state *chip = get_safe_token(device); | |
| 188 | chip->chip_enable = !state; | |
| 189 | } | |
| 190 | ||
| 191 | /* cursor enable, active low */ | |
| 192 | WRITE_LINE_DEVICE_HANDLER( dl1416_cu_w ) | |
| 193 | { | |
| 194 | dl1416_state *chip = get_safe_token(device); | |
| 195 | chip->cursor_enable = !state; | |
| 196 | } | |
| 197 | ||
| 198 | /* data */ | |
| 199 | WRITE8_DEVICE_HANDLER( dl1416_data_w ) | |
| 200 | { | |
| 201 | dl1416_state *chip = get_safe_token(device); | |
| 202 | const dl1416_interface *intf = (const dl1416_interface *)device->static_config(); | |
| 203 | ||
| 204 | offset &= 0x03; /* A0-A1 */ | |
| 205 | data &= 0x7f; /* D0-D6 */ | |
| 206 | ||
| 207 | /* Only try to update the data if we are enabled and write is enabled */ | |
| 208 | if (chip->chip_enable && chip->write_enable) | |
| 209 | { | |
| 210 | /* fprintf(stderr,"DL1416 Write: Cursor: %d, Offset: %d, Data: %02X\n (%c)", chip->cursor_enable, offset, data, data); */ | |
| 211 | int i, pattern, previous_state; | |
| 212 | ||
| 213 | if (chip->cursor_enable) /* cursor enable is set */ | |
| 214 | { | |
| 215 | if (device->type() == DL1416B) | |
| 216 | { | |
| 217 | /* DL1416B uses offset to decide cursor pos to change and D0 to hold new state */ | |
| 218 | ||
| 219 | /* The cursor will be set if D0 is high and the original */ | |
| 220 | /* character restored otherwise */ | |
| 221 | previous_state = chip->cursor_state[offset]; | |
| 222 | chip->cursor_state[offset] = data & 1 ? CURSOR_ON : CURSOR_OFF; | |
| 223 | ||
| 224 | if (previous_state != chip->cursor_state[offset]) | |
| 225 | { | |
| 226 | pattern = dl1416t_segments[chip->digit_ram[offset]]; | |
| 227 | ||
| 228 | /* If cursor for this digit position is enabled and segment is not */ | |
| 229 | /* undefined, replace digit with cursor */ | |
| 230 | if ((chip->cursor_state[offset] == CURSOR_ON) && (pattern != SEG_UNDEF)) | |
| 231 | pattern = SEG_CURSOR; | |
| 232 | ||
| 233 | /* Undefined characters are replaced by blanks */ | |
| 234 | if (pattern == SEG_UNDEF) | |
| 235 | pattern = SEG_BLANK; | |
| 236 | ||
| 237 | /* Call update function */ | |
| 238 | if (intf->update) | |
| 239 | intf->update(device, offset, pattern); | |
| 240 | } | |
| 241 | } | |
| 242 | else { | |
| 243 | /* DL1416T uses a bitmap of 4 data bits D0,D1,D2,D3 to decide cursor pos to change and new state */ | |
| 244 | ||
| 245 | for (i = 0; i < 4; i++) | |
| 246 | { | |
| 247 | /* The cursor will be set if D0-D3 is high and the original */ | |
| 248 | /* character at the appropriate position restored otherwise */ | |
| 249 | previous_state = chip->cursor_state[i]; | |
| 250 | chip->cursor_state[i] = data & (1<<i) ? CURSOR_ON : CURSOR_OFF; | |
| 251 | ||
| 252 | if (previous_state != chip->cursor_state[i]) | |
| 253 | { | |
| 254 | pattern = dl1416t_segments[chip->digit_ram[i]]; | |
| 255 | ||
| 256 | /* If cursor for this digit position is enabled and segment is not */ | |
| 257 | /* undefined, replace digit with cursor */ | |
| 258 | if ((chip->cursor_state[i] == CURSOR_ON) && (pattern != SEG_UNDEF)) | |
| 259 | pattern = SEG_CURSOR; | |
| 260 | ||
| 261 | /* Undefined characters are replaced by blanks */ | |
| 262 | if (pattern == SEG_UNDEF) | |
| 263 | pattern = SEG_BLANK; | |
| 264 | ||
| 265 | /* Call update function */ | |
| 266 | if (intf->update) | |
| 267 | intf->update(device, i, pattern); | |
| 268 | } | |
| 269 | } | |
| 270 | } | |
| 271 | } | |
| 272 | else /* cursor enable is not set, so standard write */ | |
| 273 | { | |
| 274 | /* Save written value */ | |
| 275 | chip->digit_ram[offset] = data&0x3f; | |
| 276 | ||
| 277 | /* Load segment pattern from ROM */ | |
| 278 | pattern = dl1416t_segments[data]; /** TODO: handle DL1416T vs DL1416B vs DL1414 here */ | |
| 279 | ||
| 280 | /* If cursor for this digit position is enabled and segment is not */ | |
| 281 | /* undefined, replace digit with cursor */ | |
| 282 | if ((chip->cursor_state[offset] == CURSOR_ON) && (pattern != SEG_UNDEF)) | |
| 283 | pattern = SEG_CURSOR; | |
| 284 | ||
| 285 | /* Undefined characters are replaced by blanks */ | |
| 286 | if (pattern == SEG_UNDEF) | |
| 287 | pattern = SEG_BLANK; | |
| 288 | ||
| 289 | /* Call update function */ | |
| 290 | if (intf->update) | |
| 291 | intf->update(device, offset, pattern); | |
| 292 | } | |
| 293 | } | |
| 294 | } | |
| 295 | ||
| 296 | dl1416_device::dl1416_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock) | |
| 297 | : device_t(mconfig, type, name, tag, owner, clock) | |
| 298 | { | |
| 299 | m_token = global_alloc_clear(dl1416_state); | |
| 300 | } | |
| 301 | ||
| 302 | //------------------------------------------------- | |
| 303 | // device_config_complete - perform any | |
| 304 | // operations now that the configuration is | |
| 305 | // complete | |
| 306 | //------------------------------------------------- | |
| 307 | ||
| 308 | void dl1416_device::device_config_complete() | |
| 309 | { | |
| 310 | } | |
| 311 | ||
| 312 | //------------------------------------------------- | |
| 313 | // device_start - device-specific startup | |
| 314 | //------------------------------------------------- | |
| 315 | ||
| 316 | void dl1416_device::device_start() | |
| 317 | { | |
| 318 | DEVICE_START_NAME( dl1416 )(this); | |
| 319 | } | |
| 320 | ||
| 321 | //------------------------------------------------- | |
| 322 | // device_reset - device-specific reset | |
| 323 | //------------------------------------------------- | |
| 324 | ||
| 325 | void dl1416_device::device_reset() | |
| 326 | { | |
| 327 | DEVICE_RESET_NAME( dl1416 )(this); | |
| 328 | } | |
| 329 | ||
| 330 | ||
| 331 | const device_type DL1416B = &device_creator<dl1416b_device>; | |
| 332 | ||
| 333 | dl1416b_device::dl1416b_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) | |
| 334 | : dl1416_device(mconfig, DL1416B, "DL1416B", tag, owner, clock) | |
| 335 | { | |
| 336 | } | |
| 337 | ||
| 338 | ||
| 339 | const device_type DL1416T = &device_creator<dl1416t_device>; | |
| 340 | ||
| 341 | dl1416t_device::dl1416t_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) | |
| 342 | : dl1416_device(mconfig, DL1416T, "DL1416T", tag, owner, clock) | |
| 343 | { | |
| 344 | } |
| r21684 | r21685 | |
|---|---|---|
| 1 | /***************************************************************************** | |
| 2 | * | |
| 3 | * video/dl1416.h | |
| 4 | * | |
| 5 | * DL1416 | |
| 6 | * | |
| 7 | * 4-Digit 16-Segment Alphanumeric Intelligent Display | |
| 8 | * with Memory/Decoder/Driver | |
| 9 | * | |
| 10 | * See video/dl1416.c for more info | |
| 11 | * | |
| 12 | ****************************************************************************/ | |
| 13 | ||
| 14 | #ifndef DL1416_H_ | |
| 15 | #define DL1416_H_ | |
| 16 | ||
| 17 | #include "devcb.h" | |
| 18 | ||
| 19 | /*************************************************************************** | |
| 20 | TYPE DEFINITIONS | |
| 21 | ***************************************************************************/ | |
| 22 | ||
| 23 | typedef void (*dl1416_update_func)(device_t *device, int digit, int data); | |
| 24 | ||
| 25 | struct dl1416_interface | |
| 26 | { | |
| 27 | dl1416_update_func update; | |
| 28 | }; | |
| 29 | ||
| 30 | ||
| 31 | /*************************************************************************** | |
| 32 | DEVICE CONFIGURATION MACROS | |
| 33 | ***************************************************************************/ | |
| 34 | ||
| 35 | #define MCFG_DL1416B_ADD(_tag, _config) \ | |
| 36 | MCFG_DEVICE_ADD(_tag, DL1416B, 0) \ | |
| 37 | MCFG_DEVICE_CONFIG(_config) | |
| 38 | ||
| 39 | #define MCFG_DL1416T_ADD(_tag, _config) \ | |
| 40 | MCFG_DEVICE_ADD(_tag, DL1416T, 0) \ | |
| 41 | MCFG_DEVICE_CONFIG(_config) | |
| 42 | ||
| 43 | ||
| 44 | /*************************************************************************** | |
| 45 | FUNCTION PROTOTYPES | |
| 46 | ***************************************************************************/ | |
| 47 | ||
| 48 | /* inputs */ | |
| 49 | WRITE_LINE_DEVICE_HANDLER( dl1416_wr_w ); /* write enable */ | |
| 50 | WRITE_LINE_DEVICE_HANDLER( dl1416_ce_w ); /* chip enable */ | |
| 51 | WRITE_LINE_DEVICE_HANDLER( dl1416_cu_w ); /* cursor enable */ | |
| 52 | DECLARE_WRITE8_DEVICE_HANDLER( dl1416_data_w ); | |
| 53 | ||
| 54 | /* device get info callback */ | |
| 55 | class dl1416_device : public device_t | |
| 56 | { | |
| 57 | public: | |
| 58 | dl1416_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock); | |
| 59 | ~dl1416_device() { global_free(m_token); } | |
| 60 | ||
| 61 | // access to legacy token | |
| 62 | void *token() const { assert(m_token != NULL); return m_token; } | |
| 63 | protected: | |
| 64 | // device-level overrides | |
| 65 | virtual void device_config_complete(); | |
| 66 | virtual void device_start(); | |
| 67 | virtual void device_reset(); | |
| 68 | private: | |
| 69 | // internal state | |
| 70 | void *m_token; | |
| 71 | }; | |
| 72 | ||
| 73 | class dl1416b_device : public dl1416_device | |
| 74 | { | |
| 75 | public: | |
| 76 | dl1416b_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); | |
| 77 | }; | |
| 78 | ||
| 79 | extern const device_type DL1416B; | |
| 80 | ||
| 81 | class dl1416t_device : public dl1416_device | |
| 82 | { | |
| 83 | public: | |
| 84 | dl1416t_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); | |
| 85 | }; | |
| 86 | ||
| 87 | extern const device_type DL1416T; | |
| 88 | ||
| 89 | ||
| 90 | #endif /* DL1416_H_ */ |
| r21684 | r21685 | |
|---|---|---|
| 1 | /********************************************************************** | |
| 2 | ||
| 3 | Intel 82720 Graphics Display Controller emulation | |
| 4 | ||
| 5 | Copyright MESS Team. | |
| 6 | Visit http://mamedev.org for licensing and usage restrictions. | |
| 7 | ||
| 8 | **********************************************************************/ | |
| 9 | ||
| 10 | /* | |
| 11 | ||
| 12 | TODO: | |
| 13 | ||
| 14 | - implement FIFO as ring buffer | |
| 15 | - commands | |
| 16 | - DMAR | |
| 17 | - DMAW | |
| 18 | - incomplete / unimplemented FIGD / GCHRD draw modes | |
| 19 | - Arc | |
| 20 | - FIGD character | |
| 21 | - slanted character | |
| 22 | - GCHRD character (needs rewrite) | |
| 23 | - read-modify-write cycle | |
| 24 | - read data | |
| 25 | - modify data | |
| 26 | - write data | |
| 27 | - QX-10 diagnostic test has positioning bugs with the bitmap display test; | |
| 28 | - QX-10 diagnostic test misses the zooming factor (external pin); | |
| 29 | - compis2 SAD address for bitmap is 0x20000 for whatever reason (presumably missing banking); | |
| 30 | - A5105 has a FIFO bug with the RDAT, should be a lot larger when it scrolls up. | |
| 31 | The problem is that DMA-ing with RDAT/WDAT shouldn't be instant; | |
| 32 | ||
| 33 | - honor visible area | |
| 34 | - wide mode (32-bit access) | |
| 35 | - light pen | |
| 36 | ||
| 37 | */ | |
| 38 | ||
| 39 | #include "emu.h" | |
| 40 | #include "upd7220.h" | |
| 41 | ||
| 42 | ||
| 43 | ||
| 44 | //************************************************************************** | |
| 45 | // MACROS / CONSTANTS | |
| 46 | //************************************************************************** | |
| 47 | ||
| 48 | #define VERBOSE 0 | |
| 49 | #define LOG(x) do { if (VERBOSE) logerror x; } while (0) | |
| 50 | ||
| 51 | ||
| 52 | // todo typedef | |
| 53 | enum | |
| 54 | { | |
| 55 | COMMAND_INVALID = -1, | |
| 56 | COMMAND_RESET, | |
| 57 | COMMAND_SYNC, | |
| 58 | COMMAND_VSYNC, | |
| 59 | COMMAND_CCHAR, | |
| 60 | COMMAND_START, | |
| 61 | COMMAND_BCTRL, | |
| 62 | COMMAND_ZOOM, | |
| 63 | COMMAND_CURS, | |
| 64 | COMMAND_PRAM, | |
| 65 | COMMAND_PITCH, | |
| 66 | COMMAND_WDAT, | |
| 67 | COMMAND_MASK, | |
| 68 | COMMAND_FIGS, | |
| 69 | COMMAND_FIGD, | |
| 70 | COMMAND_GCHRD, | |
| 71 | COMMAND_RDAT, | |
| 72 | COMMAND_CURD, | |
| 73 | COMMAND_LPRD, | |
| 74 | COMMAND_DMAR, | |
| 75 | COMMAND_DMAW, | |
| 76 | COMMAND_5A | |
| 77 | }; | |
| 78 | ||
| 79 | enum | |
| 80 | { | |
| 81 | FIFO_READ = 0, | |
| 82 | FIFO_WRITE | |
| 83 | }; | |
| 84 | ||
| 85 | enum | |
| 86 | { | |
| 87 | FIFO_EMPTY = -1, | |
| 88 | FIFO_PARAMETER, | |
| 89 | FIFO_COMMAND | |
| 90 | }; | |
| 91 | ||
| 92 | #define UPD7220_COMMAND_RESET 0x00 | |
| 93 | #define UPD7220_COMMAND_SYNC 0x0e // & 0xfe | |
| 94 | #define UPD7220_COMMAND_VSYNC 0x6e // & 0xfe | |
| 95 | #define UPD7220_COMMAND_CCHAR 0x4b | |
| 96 | #define UPD7220_COMMAND_START 0x6b | |
| 97 | #define UPD7220_COMMAND_BCTRL 0x0c // & 0xfe | |
| 98 | #define UPD7220_COMMAND_ZOOM 0x46 | |
| 99 | #define UPD7220_COMMAND_CURS 0x49 | |
| 100 | #define UPD7220_COMMAND_PRAM 0x70 // & 0xf0 | |
| 101 | #define UPD7220_COMMAND_PITCH 0x47 | |
| 102 | #define UPD7220_COMMAND_WDAT 0x20 // & 0xe4 | |
| 103 | #define UPD7220_COMMAND_MASK 0x4a | |
| 104 | #define UPD7220_COMMAND_FIGS 0x4c | |
| 105 | #define UPD7220_COMMAND_FIGD 0x6c | |
| 106 | #define UPD7220_COMMAND_GCHRD 0x68 | |
| 107 | #define UPD7220_COMMAND_RDAT 0xa0 // & 0xe4 | |
| 108 | #define UPD7220_COMMAND_CURD 0xe0 | |
| 109 | #define UPD7220_COMMAND_LPRD 0xc0 | |
| 110 | #define UPD7220_COMMAND_DMAR 0xa4 // & 0xe4 | |
| 111 | #define UPD7220_COMMAND_DMAW 0x24 // & 0xe4 | |
| 112 | #define UPD7220_COMMAND_5A 0x5a | |
| 113 | ||
| 114 | #define UPD7220_SR_DATA_READY 0x01 | |
| 115 | #define UPD7220_SR_FIFO_FULL 0x02 | |
| 116 | #define UPD7220_SR_FIFO_EMPTY 0x04 | |
| 117 | #define UPD7220_SR_DRAWING_IN_PROGRESS 0x08 | |
| 118 | #define UPD7220_SR_DMA_EXECUTE 0x10 | |
| 119 | #define UPD7220_SR_VSYNC_ACTIVE 0x20 | |
| 120 | #define UPD7220_SR_HBLANK_ACTIVE 0x40 | |
| 121 | #define UPD7220_SR_LIGHT_PEN_DETECT 0x80 | |
| 122 | ||
| 123 | #define UPD7220_MODE_S 0x01 | |
| 124 | #define UPD7220_MODE_REFRESH_RAM 0x04 | |
| 125 | #define UPD7220_MODE_I 0x08 | |
| 126 | #define UPD7220_MODE_DRAW_ON_RETRACE 0x10 | |
| 127 | #define UPD7220_MODE_DISPLAY_MASK 0x22 | |
| 128 | #define UPD7220_MODE_DISPLAY_MIXED 0x00 | |
| 129 | #define UPD7220_MODE_DISPLAY_GRAPHICS 0x02 | |
| 130 | #define UPD7220_MODE_DISPLAY_CHARACTER 0x20 | |
| 131 | #define UPD7220_MODE_DISPLAY_INVALID 0x22 | |
| 132 | ||
| 133 | static const int x_dir[8] = { 0, 1, 1, 1, 0,-1,-1,-1}; | |
| 134 | static const int y_dir[8] = { 1, 1, 0,-1,-1,-1, 0, 1}; | |
| 135 | static const int x_dir_dot[8] = { 1, 1, 0,-1,-1,-1, 0, 1}; | |
| 136 | static const int y_dir_dot[8] = { 0,-1,-1,-1, 0, 1, 1, 1}; | |
| 137 | ||
| 138 | ||
| 139 | ||
| 140 | //************************************************************************** | |
| 141 | // GLOBAL VARIABLES | |
| 142 | //************************************************************************** | |
| 143 | ||
| 144 | // devices | |
| 145 | const device_type UPD7220 = &device_creator<upd7220_device>; | |
| 146 | ||
| 147 | ||
| 148 | // default address map | |
| 149 | static ADDRESS_MAP_START( upd7220_vram, AS_0, 8, upd7220_device ) | |
| 150 | AM_RANGE(0x00000, 0x3ffff) AM_RAM | |
| 151 | ADDRESS_MAP_END | |
| 152 | ||
| 153 | ||
| 154 | // internal 128x14 control ROM | |
| 155 | ROM_START( upd7220 ) | |
| 156 | ROM_REGION( 0x100, "upd7220", 0 ) | |
| 157 | ROM_LOAD( "upd7220.bin", 0x000, 0x100, NO_DUMP ) | |
| 158 | ROM_END | |
| 159 | ||
| 160 | ||
| 161 | //------------------------------------------------- | |
| 162 | // memory_space_config - return a description of | |
| 163 | // any address spaces owned by this device | |
| 164 | //------------------------------------------------- | |
| 165 | ||
| 166 | const address_space_config *upd7220_device::memory_space_config(address_spacenum spacenum) const | |
| 167 | { | |
| 168 | return (spacenum == AS_0) ? &m_space_config : NULL; | |
| 169 | } | |
| 170 | ||
| 171 | ||
| 172 | //------------------------------------------------- | |
| 173 | // rom_region - device-specific ROM region | |
| 174 | //------------------------------------------------- | |
| 175 | ||
| 176 | const rom_entry *upd7220_device::device_rom_region() const | |
| 177 | { | |
| 178 | return ROM_NAME( upd7220 ); | |
| 179 | } | |
| 180 | ||
| 181 | ||
| 182 | //------------------------------------------------- | |
| 183 | // device_config_complete - perform any | |
| 184 | // operations now that the configuration is | |
| 185 | // complete | |
| 186 | //------------------------------------------------- | |
| 187 | ||
| 188 | void upd7220_device::device_config_complete() | |
| 189 | { | |
| 190 | // inherit a copy of the static data | |
| 191 | const upd7220_interface *intf = reinterpret_cast<const upd7220_interface *>(static_config()); | |
| 192 | if (intf != NULL) | |
| 193 | *static_cast<upd7220_interface *>(this) = *intf; | |
| 194 | ||
| 195 | // or initialize to defaults if none provided | |
| 196 | else | |
| 197 | { | |
| 198 | memset(&m_out_drq_cb, 0, sizeof(m_out_drq_cb)); | |
| 199 | memset(&m_out_hsync_cb, 0, sizeof(m_out_hsync_cb)); | |
| 200 | memset(&m_out_vsync_cb, 0, sizeof(m_out_vsync_cb)); | |
| 201 | memset(&m_out_blank_cb, 0, sizeof(m_out_blank_cb)); | |
| 202 | } | |
| 203 | } | |
| 204 | ||
| 205 | ||
| 206 | ||
| 207 | //************************************************************************** | |
| 208 | // INLINE HELPERS | |
| 209 | //************************************************************************** | |
| 210 | ||
| 211 | //------------------------------------------------- | |
| 212 | // readbyte - read a byte at the given address | |
| 213 | //------------------------------------------------- | |
| 214 | ||
| 215 | inline UINT8 upd7220_device::readbyte(offs_t address) | |
| 216 | { | |
| 217 | return space().read_byte(address); | |
| 218 | } | |
| 219 | ||
| 220 | ||
| 221 | //------------------------------------------------- | |
| 222 | // writebyte - write a byte at the given address | |
| 223 | //------------------------------------------------- | |
| 224 | ||
| 225 | inline void upd7220_device::writebyte(offs_t address, UINT8 data) | |
| 226 | { | |
| 227 | space().write_byte(address, data); | |
| 228 | } | |
| 229 | ||
| 230 | ||
| 231 | //------------------------------------------------- | |
| 232 | // fifo_clear - | |
| 233 | //------------------------------------------------- | |
| 234 | ||
| 235 | inline void upd7220_device::fifo_clear() | |
| 236 | { | |
| 237 | for (int i = 0; i < 16; i++) | |
| 238 | { | |
| 239 | m_fifo[i] = 0; | |
| 240 | m_fifo_flag[i] = FIFO_EMPTY; | |
| 241 | } | |
| 242 | ||
| 243 | m_fifo_ptr = -1; | |
| 244 | ||
| 245 | m_sr &= ~UPD7220_SR_DATA_READY; | |
| 246 | m_sr |= UPD7220_SR_FIFO_EMPTY; | |
| 247 | m_sr &= ~UPD7220_SR_FIFO_FULL; | |
| 248 | } | |
| 249 | ||
| 250 | ||
| 251 | //------------------------------------------------- | |
| 252 | // fifo_param_count - | |
| 253 | //------------------------------------------------- | |
| 254 | ||
| 255 | inline int upd7220_device::fifo_param_count() | |
| 256 | { | |
| 257 | int i; | |
| 258 | ||
| 259 | for (i = 0; i < 16; i++) | |
| 260 | { | |
| 261 | if (m_fifo_flag[i] != FIFO_PARAMETER) break; | |
| 262 | } | |
| 263 | ||
| 264 | return i; | |
| 265 | } | |
| 266 | ||
| 267 | ||
| 268 | //------------------------------------------------- | |
| 269 | // fifo_set_direction - | |
| 270 | //------------------------------------------------- | |
| 271 | ||
| 272 | inline void upd7220_device::fifo_set_direction(int dir) | |
| 273 | { | |
| 274 | if (m_fifo_dir != dir) | |
| 275 | { | |
| 276 | fifo_clear(); | |
| 277 | } | |
| 278 | ||
| 279 | m_fifo_dir = dir; | |
| 280 | } | |
| 281 | ||
| 282 | ||
| 283 | //------------------------------------------------- | |
| 284 | // queue - | |
| 285 | //------------------------------------------------- | |
| 286 | ||
| 287 | inline void upd7220_device::queue(UINT8 data, int flag) | |
| 288 | { | |
| 289 | if (m_fifo_ptr < 15) | |
| 290 | { | |
| 291 | m_fifo_ptr++; | |
| 292 | ||
| 293 | m_fifo[m_fifo_ptr] = data; | |
| 294 | m_fifo_flag[m_fifo_ptr] = flag; | |
| 295 | ||
| 296 | if (m_fifo_ptr == 16) | |
| 297 | { | |
| 298 | m_sr |= UPD7220_SR_FIFO_FULL; | |
| 299 | } | |
| 300 | ||
| 301 | m_sr &= ~UPD7220_SR_FIFO_EMPTY; | |
| 302 | } | |
| 303 | else | |
| 304 | { | |
| 305 | // TODO what happen? somebody set us up the bomb | |
| 306 | printf("FIFO?\n"); | |
| 307 | } | |
| 308 | } | |
| 309 | ||
| 310 | ||
| 311 | //------------------------------------------------- | |
| 312 | // dequeue - | |
| 313 | //------------------------------------------------- | |
| 314 | ||
| 315 | inline void upd7220_device::dequeue(UINT8 *data, int *flag) | |
| 316 | { | |
| 317 | *data = m_fifo[0]; | |
| 318 | *flag = m_fifo_flag[0]; | |
| 319 | ||
| 320 | if (m_fifo_ptr > -1) | |
| 321 | { | |
| 322 | for (int i = 0; i < 15; i++) | |
| 323 | { | |
| 324 | m_fifo[i] = m_fifo[i + 1]; | |
| 325 | m_fifo_flag[i] = m_fifo_flag[i + 1]; | |
| 326 | } | |
| 327 | ||
| 328 | m_fifo[15] = 0; | |
| 329 | m_fifo_flag[15] = 0; | |
| 330 | ||
| 331 | m_fifo_ptr--; | |
| 332 | ||
| 333 | if (m_fifo_ptr == -1) | |
| 334 | { | |
| 335 | m_sr &= ~UPD7220_SR_DATA_READY; | |
| 336 | m_sr |= UPD7220_SR_FIFO_EMPTY; | |
| 337 | } | |
| 338 | } | |
| 339 | } | |
| 340 | ||
| 341 | ||
| 342 | //------------------------------------------------- | |
| 343 | // update_vsync_timer - | |
| 344 | //------------------------------------------------- | |
| 345 | ||
| 346 | inline void upd7220_device::update_vsync_timer(int state) | |
| 347 | { | |
| 348 | int next_y = state ? m_vs : 0; | |
| 349 | ||
| 350 | attotime duration = m_screen->time_until_pos(next_y, 0); | |
| 351 | ||
| 352 | m_vsync_timer->adjust(duration, !state); | |
| 353 | } | |
| 354 | ||
| 355 | ||
| 356 | //------------------------------------------------- | |
| 357 | // update_hsync_timer - | |
| 358 | //------------------------------------------------- | |
| 359 | ||
| 360 | inline void upd7220_device::update_hsync_timer(int state) | |
| 361 | { | |
| 362 | int y = m_screen->vpos(); | |
| 363 | ||
| 364 | int next_x = state ? m_hs : 0; | |
| 365 | int next_y = state ? y : ((y + 1) % m_al); | |
| 366 | ||
| 367 | attotime duration = m_screen->time_until_pos(next_y, next_x); | |
| 368 | ||
| 369 | m_hsync_timer->adjust(duration, !state); | |
| 370 | } | |
| 371 | ||
| 372 | ||
| 373 | //------------------------------------------------- | |
| 374 | // update_blank_timer - | |
| 375 | //------------------------------------------------- | |
| 376 | ||
| 377 | inline void upd7220_device::update_blank_timer(int state) | |
| 378 | { | |
| 379 | int y = m_screen->vpos(); | |
| 380 | ||
| 381 | int next_x = state ? (m_hs + m_hbp) : (m_hs + m_hbp + (m_aw << 3)); | |
| 382 | int next_y = state ? ((y + 1) % (m_vs + m_vbp + m_al + m_vfp - 1)) : y; | |
| 383 | ||
| 384 | attotime duration = m_screen->time_until_pos(next_y, next_x); | |
| 385 | ||
| 386 | m_hsync_timer->adjust(duration, !state); | |
| 387 | } | |
| 388 | ||
| 389 | ||
| 390 | //------------------------------------------------- | |
| 391 | // recompute_parameters - | |
| 392 | //------------------------------------------------- | |
| 393 | ||
| 394 | inline void upd7220_device::recompute_parameters() | |
| 395 | { | |
| 396 | /* TODO: assume that the pitch also controls number of horizontal pixels in a single cell */ | |
| 397 | int horiz_mult = ((m_pitch == 40) ? 16 : 8); | |
| 398 | int horiz_pix_total = (m_hs + m_hbp + m_aw + m_hfp) * horiz_mult; | |
| 399 | int vert_pix_total = m_vs + m_vbp + m_al + m_vfp; | |
| 400 | ||
| 401 | //printf("%d %d %d %d\n",m_hs,m_hbp,m_aw,m_hfp); | |
| 402 | //printf("%d %d\n",m_aw * 8,m_pitch * 8); | |
| 403 | ||
| 404 | if (horiz_pix_total == 0 || vert_pix_total == 0) //bail out if screen params aren't valid | |
| 405 | return; | |
| 406 | ||
| 407 | attoseconds_t refresh = HZ_TO_ATTOSECONDS(clock() * horiz_mult) * horiz_pix_total * vert_pix_total; | |
| 408 | ||
| 409 | rectangle visarea; | |
| 410 | ||
| 411 | visarea.min_x = 0; //(m_hs + m_hbp) * 8; | |
| 412 | visarea.min_y = 0; //m_vs + m_vbp; | |
| 413 | visarea.max_x = m_aw * horiz_mult - 1;//horiz_pix_total - (m_hfp * 8) - 1; | |
| 414 | visarea.max_y = m_al - 1;//vert_pix_total - m_vfp - 1; | |
| 415 | ||
| 416 | LOG(("uPD7220 '%s' Screen: %u x %u @ %f Hz\n", tag(), horiz_pix_total, vert_pix_total, 1 / ATTOSECONDS_TO_DOUBLE(refresh))); | |
| 417 | LOG(("Visible Area: (%u, %u) - (%u, %u)\n", visarea.min_x, visarea.min_y, visarea.max_x, visarea.max_y)); | |
| 418 | LOG(("%d %d %d %d %d\n",m_hs,m_hbp,m_aw,m_hfp,m_pitch)); | |
| 419 | LOG(("%d %d %d %d\n",m_vs,m_vbp,m_al,m_vfp)); | |
| 420 | ||
| 421 | if (m_m) | |
| 422 | { | |
| 423 | m_screen->configure(horiz_pix_total, vert_pix_total, visarea, refresh); | |
| 424 | ||
| 425 | update_hsync_timer(0); | |
| 426 | update_vsync_timer(0); | |
| 427 | } | |
| 428 | else | |
| 429 | { | |
| 430 | m_hsync_timer->enable(0); | |
| 431 | m_vsync_timer->enable(0); | |
| 432 | } | |
| 433 | ||
| 434 | update_blank_timer(0); | |
| 435 | } | |
| 436 | ||
| 437 | ||
| 438 | //------------------------------------------------- | |
| 439 | // reset_figs_param - | |
| 440 | //------------------------------------------------- | |
| 441 | ||
| 442 | inline void upd7220_device::reset_figs_param() | |
| 443 | { | |
| 444 | m_figs.m_dc = 0x0000; | |
| 445 | m_figs.m_d = 0x0008; | |
| 446 | m_figs.m_d1 = 0x0008; | |
| 447 | m_figs.m_d2 = 0x0000; | |
| 448 | m_figs.m_dm = 0x0000; | |
| 449 | } | |
| 450 | ||
| 451 | ||
| 452 | //------------------------------------------------- | |
| 453 | // advance_ead - | |
| 454 | //------------------------------------------------- | |
| 455 | ||
| 456 | inline void upd7220_device::advance_ead() | |
| 457 | { | |
| 458 | #define EAD m_ead | |
| 459 | #define DAD m_dad | |
| 460 | #define P x_dir[m_figs.m_dir] + (y_dir[m_figs.m_dir] * m_pitch) | |
| 461 | #define MSB(value) (BIT(value, 15)) | |
| 462 | #define LSB(value) (BIT(value, 0)) | |
| 463 | #define LR(value) ((value << 1) | MSB(value)) | |
| 464 | #define RR(value) ((LSB(value) << 15) | (value >> 1)) | |
| 465 | ||
| 466 | switch (m_draw_mode & 0x07) | |
| 467 | { | |
| 468 | case 0: | |
| 469 | EAD += P; | |
| 470 | break; | |
| 471 | ||
| 472 | case 1: | |
| 473 | EAD += P; | |
| 474 | if (MSB(DAD)) EAD++; | |
| 475 | DAD = LR(DAD); | |
| 476 | break; | |
| 477 | ||
| 478 | case 2: | |
| 479 | if (MSB(DAD)) EAD++; | |
| 480 | DAD = LR(DAD); | |
| 481 | break; | |
| 482 | ||
| 483 | case 3: | |
| 484 | EAD -= P; | |
| 485 | if (MSB(DAD)) EAD++; | |
| 486 | DAD = LR(DAD); | |
| 487 | break; | |
| 488 | ||
| 489 | case 4: | |
| 490 | EAD -= P; | |
| 491 | break; | |
| 492 | ||
| 493 | case 5: | |
| 494 | EAD -= P; | |
| 495 | if (LSB(DAD)) EAD--; | |
| 496 | DAD = RR(DAD); | |
| 497 | break; | |
| 498 | ||
| 499 | case 6: | |
| 500 | if (LSB(DAD)) EAD--; | |
| 501 | DAD = RR(DAD); | |
| 502 | break; | |
| 503 | ||
| 504 | case 7: | |
| 505 | EAD += P; | |
| 506 | if (LSB(DAD)) EAD--; | |
| 507 | DAD = RR(DAD); | |
| 508 | break; | |
| 509 | } | |
| 510 | ||
| 511 | EAD &= 0x3ffff; | |
| 512 | } | |
| 513 | ||
| 514 | ||
| 515 | //------------------------------------------------- | |
| 516 | // read_vram - | |
| 517 | //------------------------------------------------- | |
| 518 | ||
| 519 | inline void upd7220_device::read_vram(UINT8 type, UINT8 mod) | |
| 520 | { | |
| 521 | if (type == 1) | |
| 522 | { | |
| 523 | LOG (("uPD7220 invalid type 1 RDAT parameter\n")); | |
| 524 | return; | |
| 525 | } | |
| 526 | ||
| 527 | if (mod) | |
| 528 | LOG (("uPD7220 RDAT used with mod = %02x?\n",mod)); | |
| 529 | ||
| 530 | for (int i = 0; i < m_figs.m_dc; i++) | |
| 531 | { | |
| 532 | switch(type) | |
| 533 | { | |
| 534 | case 0: | |
| 535 | queue(readbyte(m_ead*2), 0); | |
| 536 | queue(readbyte(m_ead*2+1), 0); | |
| 537 | break; | |
| 538 | case 2: | |
| 539 | queue(readbyte(m_ead*2), 0); | |
| 540 | break; | |
| 541 | case 3: | |
| 542 | queue(readbyte(m_ead*2+1), 0); | |
| 543 | break; | |
| 544 | } | |
| 545 | ||
| 546 | advance_ead(); | |
| 547 | } | |
| 548 | } | |
| 549 | ||
| 550 | ||
| 551 | //------------------------------------------------- | |
| 552 | // write_vram - | |
| 553 | //------------------------------------------------- | |
| 554 | ||
| 555 | inline void upd7220_device::write_vram(UINT8 type, UINT8 mod) | |
| 556 | { | |
| 557 | UINT16 result; | |
| 558 | ||
| 559 | if (type == 1) | |
| 560 | { | |
| 561 | printf("uPD7220 invalid type 1 WDAT parameter\n"); | |
| 562 | return; | |
| 563 | } | |
| 564 | ||
| 565 | result = 0; | |
| 566 | ||
| 567 | switch(type) | |
| 568 | { | |
| 569 | case 0: | |
| 570 | result = (m_pr[1] & 0xff); | |
| 571 | result |= (m_pr[2] << 8); | |
| 572 | result &= m_mask; | |
| 573 | break; | |
| 574 | case 2: | |
| 575 | result = (m_pr[1] & 0xff); | |
| 576 | result &= (m_mask & 0xff); | |
| 577 | break; | |
| 578 | case 3: | |
| 579 | result = (m_pr[1] << 8); | |
| 580 | result &= (m_mask & 0xff00); | |
| 581 | break; | |
| 582 | } | |
| 583 | ||
| 584 | //if(result) | |
| 585 | { | |
| 586 | //printf("%04x %02x %02x %04x %02x %02x\n",readbyte(m_ead),m_pr[1],m_pr[2],m_mask,type,mod); | |
| 587 | //printf("%04x %02x %02x\n",m_ead,m_figs.m_dir,m_pitch); | |
| 588 | //printf("%04x %04x %02x %04x\n",m_ead,result,mod,m_figs.m_dc); | |
| 589 | } | |
| 590 | ||
| 591 | for(int i = 0; i < m_figs.m_dc + 1; i++) | |
| 592 | { | |
| 593 | switch(mod & 3) | |
| 594 | { | |
| 595 | case 0x00: //replace | |
| 596 | if(type == 0 || type == 2) | |
| 597 | writebyte(m_ead*2+0, result & 0xff); | |
| 598 | if(type == 0 || type == 3) | |
| 599 | writebyte(m_ead*2+1, result >> 8); | |
| 600 | break; | |
| 601 | case 0x01: //complement | |
| 602 | if(type == 0 || type == 2) | |
| 603 | writebyte(m_ead*2+0, readbyte(m_ead*2+0) ^ (result & 0xff)); | |
| 604 | if(type == 0 || type == 3) | |
| 605 | writebyte(m_ead*2+1, readbyte(m_ead*2+1) ^ (result >> 8)); | |
| 606 | break; | |
| 607 | case 0x02: //reset to zero | |
| 608 | if(type == 0 || type == 2) | |
| 609 | writebyte(m_ead*2+0, readbyte(m_ead*2+0) & ~(result & 0xff)); | |
| 610 | if(type == 0 || type == 3) | |
| 611 | writebyte(m_ead*2+1, readbyte(m_ead*2+1) & ~(result >> 8)); | |
| 612 | break; | |
| 613 | case 0x03: //set to one | |
| 614 | if(type == 0 || type == 2) | |
| 615 | writebyte(m_ead*2+0, readbyte(m_ead*2+0) | (result & 0xff)); | |
| 616 | if(type == 0 || type == 3) | |
| 617 | writebyte(m_ead*2+1, readbyte(m_ead*2+1) | (result >> 8)); | |
| 618 | break; | |
| 619 | } | |
| 620 | ||
| 621 | advance_ead(); | |
| 622 | } | |
| 623 | } | |
| 624 | ||
| 625 | ||
| 626 | //------------------------------------------------- | |
| 627 | // check_pattern - | |
| 628 | //------------------------------------------------- | |
| 629 | ||
| 630 | inline UINT16 upd7220_device::check_pattern(UINT16 pattern) | |
| 631 | { | |
| 632 | UINT16 res = 0; | |
| 633 | ||
| 634 | switch (m_bitmap_mod & 3) | |
| 635 | { | |
| 636 | case 0: res = pattern; break; //replace | |
| 637 | case 1: res = pattern; break; //complement | |
| 638 | case 2: res = 0; break; //reset to zero | |
| 639 | case 3: res |= 0xffff; break; //set to one | |
| 640 | } | |
| 641 | ||
| 642 | return res; | |
| 643 | } | |
| 644 | ||
| 645 | ||
| 646 | //------------------------------------------------- | |
| 647 | // get_text_partition - | |
| 648 | //------------------------------------------------- | |
| 649 | ||
| 650 | inline void upd7220_device::get_text_partition(int index, UINT32 *sad, UINT16 *len, int *im, int *wd) | |
| 651 | { | |
| 652 | *sad = ((m_ra[(index * 4) + 1] & 0x1f) << 8) | m_ra[(index * 4) + 0]; | |
| 653 | *len = ((m_ra[(index * 4) + 3] & 0x3f) << 4) | (m_ra[(index * 4) + 2] >> 4); | |
| 654 | *im = BIT(m_ra[(index * 4) + 3], 6); | |
| 655 | *wd = BIT(m_ra[(index * 4) + 3], 7); | |
| 656 | } | |
| 657 | ||
| 658 | ||
| 659 | //------------------------------------------------- | |
| 660 | // get_graphics_partition - | |
| 661 | //------------------------------------------------- | |
| 662 | ||
| 663 | inline void upd7220_device::get_graphics_partition(int index, UINT32 *sad, UINT16 *len, int *im, int *wd) | |
| 664 | { | |
| 665 | *sad = ((m_ra[(index * 4) + 2] & 0x03) << 16) | (m_ra[(index * 4) + 1] << 8) | m_ra[(index * 4) + 0]; | |
| 666 | *len = ((m_ra[(index * 4) + 3] & 0x3f) << 4) | (m_ra[(index * 4) + 2] >> 4); | |
| 667 | *im = BIT(m_ra[(index * 4) + 3], 6); | |
| 668 | *wd = BIT(m_ra[(index * 4) + 3], 7); | |
| 669 | } | |
| 670 | ||
| 671 | ||
| 672 | ||
| 673 | //************************************************************************** | |
| 674 | // LIVE DEVICE | |
| 675 | //************************************************************************** | |
| 676 | ||
| 677 | //------------------------------------------------- | |
| 678 | // upd7220_device - constructor | |
| 679 | //------------------------------------------------- | |
| 680 | ||
| 681 | upd7220_device::upd7220_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) | |
| 682 | : device_t(mconfig, UPD7220, "uPD7220", tag, owner, clock), | |
| 683 | device_memory_interface(mconfig, *this), | |
| 684 | m_mask(0), | |
| 685 | m_pitch(0), | |
| 686 | m_ead(0), | |
| 687 | m_dad(0), | |
| 688 | m_lad(0), | |
| 689 | m_ra_addr(0), | |
| 690 | m_sr(UPD7220_SR_FIFO_EMPTY), | |
| 691 | m_cr(0), | |
| 692 | m_param_ptr(0), | |
| 693 | m_fifo_ptr(-1), | |
| 694 | m_fifo_dir(0), | |
| 695 | m_mode(0), | |
| 696 | m_draw_mode(0), | |
| 697 | m_de(0), | |
| 698 | m_m(0), | |
| 699 | m_aw(0), | |
| 700 | m_al(0), | |
| 701 | m_vs(0), | |
| 702 | m_vfp(0), | |
| 703 | m_vbp(0), | |
| 704 | m_hs(0), | |
| 705 | m_hfp(0), | |
| 706 | m_hbp(0), | |
| 707 | m_dc(0), | |
| 708 | m_sc(0), | |
| 709 | m_br(0), | |
| 710 | m_ctop(0), | |
| 711 | m_cbot(0), | |
| 712 | m_lr(0), | |
| 713 | m_disp(0), | |
| 714 | m_gchr(0), | |
| 715 | m_bitmap_mod(0), | |
| 716 | m_space_config("videoram", ENDIANNESS_LITTLE, 8, 18, 0, NULL, *ADDRESS_MAP_NAME(upd7220_vram)) | |
| 717 | { | |
| 718 | m_shortname = "upd7220"; | |
| 719 | for (int i = 0; i < 16; i++) | |
| 720 | { | |
| 721 | m_fifo[i] = 0; | |
| 722 | m_fifo_flag[i] = FIFO_EMPTY; | |
| 723 | ||
| 724 | m_ra[i] = 0; | |
| 725 | } | |
| 726 | ||
| 727 | for (int i = 0; i < 17; i++) | |
| 728 | { | |
| 729 | m_pr[i] = 0; | |
| 730 | } | |
| 731 | ||
| 732 | m_figs.m_dir = 0; | |
| 733 | m_figs.m_figure_type = 0; | |
| 734 | m_figs.m_dc = 0; | |
| 735 | m_figs.m_d = 0; | |
| 736 | m_figs.m_d1 = 0; | |
| 737 | m_figs.m_d2 = 0; | |
| 738 | m_figs.m_dm = 0; | |
| 739 | } | |
| 740 | ||
| 741 | ||
| 742 | //------------------------------------------------- | |
| 743 | // device_start - device-specific startup | |
| 744 | //------------------------------------------------- | |
| 745 | ||
| 746 | void upd7220_device::device_start() | |
| 747 | { | |
| 748 | // allocate timers | |
| 749 | m_vsync_timer = timer_alloc(TIMER_VSYNC); | |
| 750 | m_hsync_timer = timer_alloc(TIMER_HSYNC); | |
| 751 | m_blank_timer = timer_alloc(TIMER_BLANK); | |
| 752 | ||
| 753 | // resolve callbacks | |
| 754 | m_out_drq_func.resolve(m_out_drq_cb, *this); | |
| 755 | m_out_hsync_func.resolve(m_out_hsync_cb, *this); | |
| 756 | m_out_vsync_func.resolve(m_out_vsync_cb, *this); | |
| 757 | m_out_blank_func.resolve(m_out_blank_cb, *this); | |
| 758 | ||
| 759 | // find screen | |
| 760 | m_screen = machine().device<screen_device>(m_screen_tag); | |
| 761 | ||
| 762 | if (m_screen == NULL) | |
| 763 | { | |
| 764 | m_screen = owner()->subdevice<screen_device>(m_screen_tag); | |
| 765 | } | |
| 766 | ||
| 767 | assert(m_screen); | |
| 768 | ||
| 769 | // register for state saving | |
| 770 | save_item(NAME(m_ra)); | |
| 771 | save_item(NAME(m_sr)); | |
| 772 | save_item(NAME(m_mode)); | |
| 773 | save_item(NAME(m_de)); | |
| 774 | save_item(NAME(m_aw)); | |
| 775 | save_item(NAME(m_al)); | |
| 776 | save_item(NAME(m_vs)); | |
| 777 | save_item(NAME(m_vfp)); | |
| 778 | save_item(NAME(m_vbp)); | |
| 779 | save_item(NAME(m_hs)); | |
| 780 | save_item(NAME(m_hfp)); | |
| 781 | save_item(NAME(m_hbp)); | |
| 782 | save_item(NAME(m_m)); | |
| 783 | save_item(NAME(m_dc)); | |
| 784 | save_item(NAME(m_sc)); | |
| 785 | save_item(NAME(m_br)); | |
| 786 | save_item(NAME(m_lr)); | |
| 787 | save_item(NAME(m_ctop)); | |
| 788 | save_item(NAME(m_cbot)); | |
| 789 | save_item(NAME(m_ead)); | |
| 790 | save_item(NAME(m_dad)); | |
| 791 | save_item(NAME(m_lad)); | |
| 792 | save_item(NAME(m_disp)); | |
| 793 | save_item(NAME(m_gchr)); | |
| 794 | save_item(NAME(m_mask)); | |
| 795 | save_item(NAME(m_pitch)); | |
| 796 | } | |
| 797 | ||
| 798 | ||
| 799 | //------------------------------------------------- | |
| 800 | // device_reset - device-specific reset | |
| 801 | //------------------------------------------------- | |
| 802 | ||
| 803 | void upd7220_device::device_reset() | |
| 804 | { | |
| 805 | m_out_drq_func(CLEAR_LINE); | |
| 806 | } | |
| 807 | ||
| 808 | ||
| 809 | //------------------------------------------------- | |
| 810 | // device_timer - handler timer events | |
| 811 | //------------------------------------------------- | |
| 812 | ||
| 813 | void upd7220_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) | |
| 814 | { | |
| 815 | switch (id) | |
| 816 | { | |
| 817 | case TIMER_HSYNC: | |
| 818 | if (param) | |
| 819 | { | |
| 820 | m_sr |= UPD7220_SR_HBLANK_ACTIVE; | |
| 821 | } | |
| 822 | else | |
| 823 | { | |
| 824 | m_sr &= ~UPD7220_SR_HBLANK_ACTIVE; | |
| 825 | } | |
| 826 | ||
| 827 | m_out_hsync_func(param); | |
| 828 | ||
| 829 | update_hsync_timer(param); | |
| 830 | break; | |
| 831 | ||
| 832 | case TIMER_VSYNC: | |
| 833 | if (param) | |
| 834 | { | |
| 835 | m_sr |= UPD7220_SR_VSYNC_ACTIVE; | |
| 836 | } | |
| 837 | else | |
| 838 | { | |
| 839 | m_sr &= ~UPD7220_SR_VSYNC_ACTIVE; | |
| 840 | } | |
| 841 | ||
| 842 | m_out_vsync_func(param); | |
| 843 | ||
| 844 | update_vsync_timer(param); | |
| 845 | break; | |
| 846 | ||
| 847 | case TIMER_BLANK: | |
| 848 | if (param) | |
| 849 | { | |
| 850 | m_sr |= UPD7220_SR_HBLANK_ACTIVE; | |
| 851 | } | |
| 852 | else | |
| 853 | { | |
| 854 | m_sr &= ~UPD7220_SR_HBLANK_ACTIVE; | |
| 855 | } | |
| 856 | ||
| 857 | m_out_blank_func(param); | |
| 858 | ||
| 859 | update_blank_timer(param); | |
| 860 | break; | |
| 861 | } | |
| 862 | } | |
| 863 | ||
| 864 | ||
| 865 | //------------------------------------------------- | |
| 866 | // draw_pixel - | |
| 867 | //------------------------------------------------- | |
| 868 | ||
| 869 | void upd7220_device::draw_pixel(int x, int y, UINT8 tile_data) | |
| 870 | { | |
| 871 | UINT32 addr = (y * m_pitch * 2 + (x >> 3)) & 0x3ffff; | |
| 872 | int dad = x & 0x7; | |
| 873 | UINT8 data = readbyte(addr); | |
| 874 | UINT8 new_pixel = (tile_data) & (0x80 >> (dad)); | |
| 875 | ||
| 876 | switch(m_bitmap_mod) | |
| 877 | { | |
| 878 | case 0: //replace | |
| 879 | writebyte(addr, data & ~(0x80 >> (dad))); | |
| 880 | writebyte(addr, data | new_pixel); | |
| 881 | break; | |
| 882 | case 1: //complement | |
| 883 | writebyte(addr, data ^ (new_pixel)); | |
| 884 | break; | |
| 885 | case 2: //reset | |
| 886 | writebyte(addr, data & ((new_pixel) ? 0xff : ~(0x80 >> (dad)))); | |
| 887 | break; | |
| 888 | case 3: //set | |
| 889 | writebyte(addr, data | new_pixel); | |
| 890 | break; | |
| 891 | } | |
| 892 | } | |
| 893 | ||
| 894 | ||
| 895 | //------------------------------------------------- | |
| 896 | // draw_line - | |
| 897 | //------------------------------------------------- | |
| 898 | ||
| 899 | void upd7220_device::draw_line(int x, int y) | |
| 900 | { | |
| 901 | int line_size,i; | |
| 902 | const int line_x_dir[8] = { 0, 1, 1, 0, 0,-1,-1, 0}; | |
| 903 | const int line_y_dir[8] = { 1, 0, 0,-1,-1, 0, 0, 1}; | |
| 904 | const int line_x_step[8] = { 1, 0, 0, 1,-1, 0, 0,-1 }; | |
| 905 | const int line_y_step[8] = { 0, 1,-1, 0, 0,-1, 1, 0 }; | |
| 906 | UINT16 line_pattern; | |
| 907 | int line_step = 0; | |
| 908 | UINT8 dot; | |
| 909 | ||
| 910 | line_size = m_figs.m_dc + 1; | |
| 911 | line_pattern = check_pattern((m_ra[8]) | (m_ra[9]<<8)); | |
| 912 | ||
| 913 | for(i = 0;i<line_size;i++) | |
| 914 | { | |
| 915 | line_step = (m_figs.m_d1 * i); | |
| 916 | line_step/= (m_figs.m_dc + 1); | |
| 917 | line_step >>= 1; | |
| 918 | dot = ((line_pattern >> (i & 0xf)) & 1) << 7; | |
| 919 | draw_pixel(x + (line_step*line_x_step[m_figs.m_dir]),y + (line_step*line_y_step[m_figs.m_dir]),dot >> ((x + line_step*line_x_step[m_figs.m_dir]) & 0x7)); | |
| 920 | x += line_x_dir[m_figs.m_dir]; | |
| 921 | y += line_y_dir[m_figs.m_dir]; | |
| 922 | } | |
| 923 | ||
| 924 | /* TODO: check me*/ | |
| 925 | x += (line_step*line_x_step[m_figs.m_dir]); | |
| 926 | y += (line_step*line_y_step[m_figs.m_dir]); | |
| 927 | ||
| 928 | m_ead = (x >> 4) + (y * m_pitch); | |
| 929 | m_dad = x & 0x0f; | |
| 930 | } | |
| 931 | ||
| 932 | ||
| 933 | //------------------------------------------------- | |
| 934 | // draw_rectangle - | |
| 935 | //------------------------------------------------- | |
| 936 | ||
| 937 | void upd7220_device::draw_rectangle(int x, int y) | |
| 938 | { | |
| 939 | int i; | |
| 940 | const int rect_x_dir[8] = { 0, 1, 0,-1, 1, 1,-1,-1 }; | |
| 941 | const int rect_y_dir[8] = { 1, 0,-1, 0, 1,-1,-1, 1 }; | |
| 942 | UINT8 rect_type,rect_dir; | |
| 943 | UINT16 line_pattern; | |
| 944 | UINT8 dot; | |
| 945 | ||
| 946 | LOG(("uPD7220 rectangle check: %d %d %02x %08x\n",x,y,m_figs.m_dir,m_ead)); | |
| 947 | ||
| 948 | line_pattern = check_pattern((m_ra[8]) | (m_ra[9]<<8)); | |
| 949 | rect_type = (m_figs.m_dir & 1) << 2; | |
| 950 | rect_dir = rect_type | (((m_figs.m_dir >> 1) + 0) & 3); | |
| 951 | ||
| 952 | for(i = 0;i < m_figs.m_d;i++) | |
| 953 | { | |
| 954 | dot = ((line_pattern >> ((i+m_dad) & 0xf)) & 1) << 7; | |
| 955 | draw_pixel(x,y,dot >> (x & 0x7)); | |
| 956 | x+=rect_x_dir[rect_dir]; | |
| 957 | y+=rect_y_dir[rect_dir]; | |
| 958 | } | |
| 959 | ||
| 960 | rect_dir = rect_type | (((m_figs.m_dir >> 1) + 1) & 3); | |
| 961 | ||
| 962 | for(i = 0;i < m_figs.m_d2;i++) | |
| 963 | { | |
| 964 | dot = ((line_pattern >> ((i+m_dad) & 0xf)) & 1) << 7; | |
| 965 | draw_pixel(x,y,dot >> (x & 0x7)); | |
| 966 | x+=rect_x_dir[rect_dir]; | |
| 967 | y+=rect_y_dir[rect_dir]; | |
| 968 | } | |
| 969 | ||
| 970 | rect_dir = rect_type | (((m_figs.m_dir >> 1) + 2) & 3); | |
| 971 | ||
| 972 | for(i = 0;i < m_figs.m_d;i++) | |
| 973 | { | |
| 974 | dot = ((line_pattern >> ((i+m_dad) & 0xf)) & 1) << 7; | |
| 975 | draw_pixel(x,y,dot >> (x & 0x7)); | |
| 976 | x+=rect_x_dir[rect_dir]; | |
| 977 | y+=rect_y_dir[rect_dir]; | |
| 978 | } | |
| 979 | ||
| 980 | rect_dir = rect_type | (((m_figs.m_dir >> 1) + 3) & 3); | |
| 981 | ||
| 982 | for(i = 0;i < m_figs.m_d2;i++) | |
| 983 | { | |
| 984 | dot = ((line_pattern >> ((i+m_dad) & 0xf)) & 1) << 7; | |
| 985 | draw_pixel(x,y,dot >> (x & 0x7)); | |
| 986 | x+=rect_x_dir[rect_dir]; | |
| 987 | y+=rect_y_dir[rect_dir]; | |
| 988 | } | |
| 989 | ||
| 990 | m_ead = (x >> 4) + (y * m_pitch); | |
| 991 | m_dad = x & 0x0f; | |
| 992 | ||
| 993 | } | |
| 994 | ||
| 995 | ||
| 996 | //------------------------------------------------- | |
| 997 | // draw_char - | |
| 998 | //------------------------------------------------- | |
| 999 | ||
| 1000 | void upd7220_device::draw_char(int x, int y) | |
| 1001 | { | |
| 1002 | int xi,yi; | |
| 1003 | int xsize,ysize; | |
| 1004 | UINT8 tile_data; | |
| 1005 | ||
| 1006 | /* snippet for character checking */ | |
| 1007 | #if 0 | |
| 1008 | for(yi=0;yi<8;yi++) | |
| 1009 | { | |
| 1010 | for(xi=0;xi<8;xi++) | |
| 1011 | { | |
| 1012 | printf("%d",(m_ra[(yi & 7) | 8] >> xi) & 1); | |
| 1013 | } | |
| 1014 | printf("\n"); | |
| 1015 | } | |
| 1016 | #endif | |
| 1017 | ||
| 1018 | xsize = m_figs.m_d & 0x3ff; | |
| 1019 | /* Guess: D has presumably upper bits for ysize, QX-10 relies on this (TODO: check this on any real HW) */ | |
| 1020 | ysize = ((m_figs.m_d & 0x400) + m_figs.m_dc) + 1; | |
| 1021 | ||
| 1022 | /* TODO: internal direction, zooming, size stuff bigger than 8, rewrite using draw_pixel function */ | |
| 1023 | for(yi=0;yi<ysize;yi++) | |
| 1024 | { | |
| 1025 | switch(m_figs.m_dir & 7) | |
| 1026 | { | |
| 1027 | case 0: tile_data = BITSWAP8(m_ra[((yi) & 7) | 8],0,1,2,3,4,5,6,7); break; // TODO | |
| 1028 | case 2: tile_data = BITSWAP8(m_ra[((yi) & 7) | 8],0,1,2,3,4,5,6,7); break; | |
| 1029 | case 6: tile_data = BITSWAP8(m_ra[((ysize-1-yi) & 7) | 8],7,6,5,4,3,2,1,0); break; | |
| 1030 | default: tile_data = BITSWAP8(m_ra[((yi) & 7) | 8],7,6,5,4,3,2,1,0); | |
| 1031 | printf("%d %d %d\n",m_figs.m_dir,xsize,ysize); | |
| 1032 | break; | |
| 1033 | } | |
| 1034 | ||
| 1035 | for(xi=0;xi<xsize;xi++) | |
| 1036 | { | |
| 1037 | UINT32 addr = ((y+yi) * m_pitch * 2) + ((x+xi) >> 3); | |
| 1038 | ||
| 1039 | writebyte(addr & 0x3ffff, readbyte(addr & 0x3ffff) & ~(1 << (xi & 7))); | |
| 1040 | writebyte(addr & 0x3ffff, readbyte(addr & 0x3ffff) | ((tile_data) & (1 << (xi & 7)))); | |
| 1041 | } | |
| 1042 | } | |
| 1043 | ||
| 1044 | m_ead = ((x+8*x_dir_dot[m_figs.m_dir]) >> 4) + ((y+8*y_dir_dot[m_figs.m_dir]) * m_pitch); | |
| 1045 | m_dad = ((x+8*x_dir_dot[m_figs.m_dir]) & 0xf); | |
| 1046 | } | |
| 1047 | ||
| 1048 | ||
| 1049 | //------------------------------------------------- | |
| 1050 | // translate_command - | |
| 1051 | //------------------------------------------------- | |
| 1052 | ||
| 1053 | int upd7220_device::translate_command(UINT8 data) | |
| 1054 | { | |
| 1055 | int command = COMMAND_INVALID; | |
| 1056 | ||
| 1057 | switch (data) | |
| 1058 | { | |
| 1059 | case UPD7220_COMMAND_RESET: command = COMMAND_RESET; break; | |
| 1060 | case UPD7220_COMMAND_CCHAR: command = COMMAND_CCHAR; break; | |
| 1061 | case UPD7220_COMMAND_START: command = COMMAND_START; break; | |
| 1062 | case UPD7220_COMMAND_ZOOM: command = COMMAND_ZOOM; break; | |
| 1063 | case UPD7220_COMMAND_CURS: command = COMMAND_CURS; break; | |
| 1064 | case UPD7220_COMMAND_PITCH: command = COMMAND_PITCH; break; | |
| 1065 | case UPD7220_COMMAND_MASK: command = COMMAND_MASK; break; | |
| 1066 | case UPD7220_COMMAND_FIGS: command = COMMAND_FIGS; break; | |
| 1067 | case UPD7220_COMMAND_FIGD: command = COMMAND_FIGD; break; | |
| 1068 | case UPD7220_COMMAND_GCHRD: command = COMMAND_GCHRD; break; | |
| 1069 | case UPD7220_COMMAND_CURD: command = COMMAND_CURD; break; | |
| 1070 | case UPD7220_COMMAND_LPRD: command = COMMAND_LPRD; break; | |
| 1071 | case UPD7220_COMMAND_5A: command = COMMAND_5A; break; | |
| 1072 | default: | |
| 1073 | switch (data & 0xfe) | |
| 1074 | { | |
| 1075 | case UPD7220_COMMAND_SYNC: command = COMMAND_SYNC; break; | |
| 1076 | case UPD7220_COMMAND_VSYNC: command = COMMAND_VSYNC; break; | |
| 1077 | case UPD7220_COMMAND_BCTRL: command = COMMAND_BCTRL; break; | |
| 1078 | default: | |
| 1079 | switch (data & 0xf0) | |
| 1080 | { | |
| 1081 | case UPD7220_COMMAND_PRAM: command = COMMAND_PRAM; break; | |
| 1082 | default: | |
| 1083 | switch (data & 0xe4) | |
| 1084 | { | |
| 1085 | case UPD7220_COMMAND_WDAT: command = COMMAND_WDAT; break; | |
| 1086 | case UPD7220_COMMAND_RDAT: command = COMMAND_RDAT; break; | |
| 1087 | case UPD7220_COMMAND_DMAR: command = COMMAND_DMAR; break; | |
| 1088 | case UPD7220_COMMAND_DMAW: command = COMMAND_DMAW; break; | |
| 1089 | } | |
| 1090 | } | |
| 1091 | } | |
| 1092 | } | |
| 1093 | ||
| 1094 | return command; | |
| 1095 | } | |
| 1096 | ||
| 1097 | ||
| 1098 | //------------------------------------------------- | |
| 1099 | // process_fifo - | |
| 1100 | //------------------------------------------------- | |
| 1101 | ||
| 1102 | void upd7220_device::process_fifo() | |
| 1103 | { | |
| 1104 | UINT8 data; | |
| 1105 | int flag; | |
| 1106 | ||
| 1107 | dequeue(&data, &flag); | |
| 1108 | ||
| 1109 | if (flag == FIFO_COMMAND) | |
| 1110 | { | |
| 1111 | m_cr = data; | |
| 1112 | m_param_ptr = 1; | |
| 1113 | } | |
| 1114 | else | |
| 1115 | { | |
| 1116 | m_pr[m_param_ptr] = data; | |
| 1117 | m_param_ptr++; | |
| 1118 | } | |
| 1119 | ||
| 1120 | switch (translate_command(m_cr)) | |
| 1121 | { | |
| 1122 | case COMMAND_INVALID: | |
| 1123 | printf("uPD7220 '%s' Invalid Command Byte %02x\n", tag(), m_cr); | |
| 1124 | break; | |
| 1125 | ||
| 1126 | case COMMAND_5A: | |
| 1127 | if (m_param_ptr == 4) | |
| 1128 | printf("uPD7220 '%s' Undocumented Command 0x5A Executed %02x %02x %02x\n", tag(),m_pr[1],m_pr[2],m_pr[3] ); | |
| 1129 | break; | |
| 1130 | ||
| 1131 | case COMMAND_RESET: /* reset */ | |
| 1132 | switch (m_param_ptr) | |
| 1133 | { | |
| 1134 | case 0: | |
| 1135 | LOG(("uPD7220 '%s' RESET\n", tag())); | |
| 1136 | ||
| 1137 | m_de = 0; | |
| 1138 | m_ra[0] = m_ra[1] = m_ra[2] = 0; | |
| 1139 | m_ra[3] = 0x19; | |
| 1140 | m_ead = 0; | |
| 1141 | m_dad = 0; | |
| 1142 | m_mask = 0; | |
| 1143 | break; | |
| 1144 | ||
| 1145 | case 9: | |
| 1146 | m_mode = m_pr[1]; | |
| 1147 | m_aw = m_pr[2] + 2; | |
| 1148 | m_hs = (m_pr[3] & 0x1f) + 1; | |
| 1149 | m_vs = ((m_pr[4] & 0x03) << 3) | (m_pr[3] >> 5); | |
| 1150 | m_hfp = (m_pr[4] >> 2) + 1; | |
| 1151 | m_hbp = (m_pr[5] & 0x3f) + 1; | |
| 1152 | m_vfp = m_pr[6] & 0x3f; | |
| 1153 | m_al = ((m_pr[8] & 0x03) << 8) | m_pr[7]; | |
| 1154 | m_vbp = m_pr[8] >> 2; | |
| 1155 | ||
| 1156 | m_pitch = m_aw; | |
| 1157 | ||
| 1158 | LOG(("uPD7220 '%s' Mode: %02x\n", tag(), m_mode)); | |
| 1159 | LOG(("uPD7220 '%s' AW: %u\n", tag(), m_aw)); | |
| 1160 | LOG(("uPD7220 '%s' HS: %u\n", tag(), m_hs)); | |
| 1161 | LOG(("uPD7220 '%s' VS: %u\n", tag(), m_vs)); | |
| 1162 | LOG(("uPD7220 '%s' HFP: %u\n", tag(), m_hfp)); | |
| 1163 | LOG(("uPD7220 '%s' HBP: %u\n", tag(), m_hbp)); | |
| 1164 | LOG(("uPD7220 '%s' VFP: %u\n", tag(), m_vfp)); | |
| 1165 | LOG(("uPD7220 '%s' AL: %u\n", tag(), m_al)); | |
| 1166 | LOG(("uPD7220 '%s' VBP: %u\n", tag(), m_vbp)); | |
| 1167 | LOG(("uPD7220 '%s' PITCH: %u\n", tag(), m_pitch)); | |
| 1168 | ||
| 1169 | recompute_parameters(); | |
| 1170 | break; | |
| 1171 | } | |
| 1172 | break; | |
| 1173 | ||
| 1174 | case COMMAND_SYNC: /* sync format specify */ | |
| 1175 | if (m_param_ptr == 9) | |
| 1176 | { | |
| 1177 | m_mode = m_pr[1]; | |
| 1178 | m_aw = m_pr[2] + 2; | |
| 1179 | m_hs = (m_pr[3] & 0x1f) + 1; | |
| 1180 | m_vs = ((m_pr[4] & 0x03) << 3) | (m_pr[3] >> 5); | |
| 1181 | m_hfp = (m_pr[4] >> 2) + 1; | |
| 1182 | m_hbp = (m_pr[5] & 0x3f) + 1; | |
| 1183 | m_vfp = m_pr[6] & 0x3f; | |
| 1184 | m_al = ((m_pr[8] & 0x03) << 8) | m_pr[7]; | |
| 1185 | m_vbp = m_pr[8] >> 2; | |
| 1186 | ||
| 1187 | m_pitch = m_aw; | |
| 1188 | ||
| 1189 | LOG(("uPD7220 '%s' Mode: %02x\n", tag(), m_mode)); | |
| 1190 | LOG(("uPD7220 '%s' AW: %u\n", tag(), m_aw)); | |
| 1191 | LOG(("uPD7220 '%s' HS: %u\n", tag(), m_hs)); | |
| 1192 | LOG(("uPD7220 '%s' VS: %u\n", tag(), m_vs)); | |
| 1193 | LOG(("uPD7220 '%s' HFP: %u\n", tag(), m_hfp)); | |
| 1194 | LOG(("uPD7220 '%s' HBP: %u\n", tag(), m_hbp)); | |
| 1195 | LOG(("uPD7220 '%s' VFP: %u\n", tag(), m_vfp)); | |
| 1196 | LOG(("uPD7220 '%s' AL: %u\n", tag(), m_al)); | |
| 1197 | LOG(("uPD7220 '%s' VBP: %u\n", tag(), m_vbp)); | |
| 1198 | LOG(("uPD7220 '%s' PITCH: %u\n", tag(), m_pitch)); | |
| 1199 | ||
| 1200 | recompute_parameters(); | |
| 1201 | } | |
| 1202 | break; | |
| 1203 | ||
| 1204 | case COMMAND_VSYNC: /* vertical sync mode */ | |
| 1205 | m_m = m_cr & 0x01; | |
| 1206 | ||
| 1207 | LOG(("uPD7220 '%s' M: %u\n", tag(), m_m)); | |
| 1208 | ||
| 1209 | recompute_parameters(); | |
| 1210 | break; | |
| 1211 | ||
| 1212 | case COMMAND_CCHAR: /* cursor & character characteristics */ | |
| 1213 | if(m_param_ptr == 2) | |
| 1214 | { | |
| 1215 | m_lr = (m_pr[1] & 0x1f) + 1; | |
| 1216 | m_dc = BIT(m_pr[1], 7); | |
| 1217 | ||
| 1218 | LOG(("uPD7220 '%s' LR: %u\n", tag(), m_lr)); | |
| 1219 | LOG(("uPD7220 '%s' DC: %u\n", tag(), m_dc)); | |
| 1220 | } | |
| 1221 | ||
| 1222 | if(m_param_ptr == 3) | |
| 1223 | { | |
| 1224 | m_ctop = m_pr[2] & 0x1f; | |
| 1225 | m_sc = BIT(m_pr[2], 5); | |
| 1226 | m_br = (m_pr[2] >> 6); /* guess, assume that blink rate clears upper bits (if any) */ | |
| 1227 | ||
| 1228 | LOG(("uPD7220 '%s' CTOP: %u\n", tag(), m_ctop)); | |
| 1229 | LOG(("uPD7220 '%s' SC: %u\n", tag(), m_sc)); | |
| 1230 | } | |
| 1231 | ||
| 1232 | if(m_param_ptr == 4) | |
| 1233 | { | |
| 1234 | m_br = ((m_pr[3] & 0x07) << 2) | (m_pr[2] >> 6); | |
| 1235 | m_cbot = m_pr[3] >> 3; | |
| 1236 | ||
| 1237 | LOG(("uPD7220 '%s' BR: %u\n", tag(), m_br)); | |
| 1238 | LOG(("uPD7220 '%s' CBOT: %u\n", tag(), m_cbot)); | |
| 1239 | } | |
| 1240 | break; | |
| 1241 | ||
| 1242 | case COMMAND_START: /* start display & end idle mode */ | |
| 1243 | m_de = 1; | |
| 1244 | ||
| 1245 | //LOG(("uPD7220 '%s' DE: 1\n", tag())); | |
| 1246 | break; | |
| 1247 | ||
| 1248 | case COMMAND_BCTRL: /* display blanking control */ | |
| 1249 | m_de = m_cr & 0x01; | |
| 1250 | ||
| 1251 | //LOG(("uPD7220 '%s' DE: %u\n", tag(), m_de)); | |
| 1252 | break; | |
| 1253 | ||
| 1254 | case COMMAND_ZOOM: /* zoom factors specify */ | |
| 1255 | if (flag == FIFO_PARAMETER) | |
| 1256 | { | |
| 1257 | m_gchr = m_pr[1] & 0x0f; | |
| 1258 | m_disp = m_pr[1] >> 4; | |
| 1259 | ||
| 1260 | LOG(("uPD7220 '%s' GCHR: %01x\n", tag(), m_gchr)); | |
| 1261 | LOG(("uPD7220 '%s' DISP: %01x\n", tag(), m_disp)); | |
| 1262 | } | |
| 1263 | break; | |
| 1264 | ||
| 1265 | case COMMAND_CURS: /* cursor position specify */ | |
| 1266 | if (m_param_ptr >= 3) | |
| 1267 | { | |
| 1268 | UINT8 upper_addr = (m_param_ptr == 3) ? 0 : (m_pr[3] & 0x03); | |
| 1269 | ||
| 1270 | m_ead = (upper_addr << 16) | (m_pr[2] << 8) | m_pr[1]; | |
| 1271 | ||
| 1272 | //LOG(("uPD7220 '%s' EAD: %06x\n", tag(), m_ead)); | |
| 1273 | ||
| 1274 | if(m_param_ptr == 4) | |
| 1275 | { | |
| 1276 | m_dad = m_pr[3] >> 4; | |
| 1277 | //LOG(("uPD7220 '%s' DAD: %01x\n", tag(), m_dad)); | |
| 1278 | } | |
| 1279 | } | |
| 1280 | break; | |
| 1281 | ||
| 1282 | case COMMAND_PRAM: /* parameter RAM load */ | |
| 1283 | if (flag == FIFO_COMMAND) | |
| 1284 | { | |
| 1285 | m_ra_addr = m_cr & 0x0f; | |
| 1286 | } | |
| 1287 | else | |
| 1288 | { | |
| 1289 | if (m_ra_addr < 16) | |
| 1290 | { | |
| 1291 | LOG(("uPD7220 '%s' RA%u: %02x\n", tag(), m_ra_addr, data)); | |
| 1292 | ||
| 1293 | m_ra[m_ra_addr] = data; | |
| 1294 | m_ra_addr++; | |
| 1295 | } | |
| 1296 | ||
| 1297 | m_param_ptr = 0; | |
| 1298 | } | |
| 1299 | break; | |
| 1300 | ||
| 1301 | case COMMAND_PITCH: /* pitch specification */ | |
| 1302 | if (flag == FIFO_PARAMETER) | |
| 1303 | { | |
| 1304 | m_pitch = data; | |
| 1305 | ||
| 1306 | LOG(("uPD7220 '%s' PITCH: %u\n", tag(), m_pitch)); | |
| 1307 | } | |
| 1308 | break; | |
| 1309 | ||
| 1310 | case COMMAND_WDAT: /* write data into display memory */ | |
| 1311 | m_bitmap_mod = m_cr & 3; | |
| 1312 | ||
| 1313 | if (m_param_ptr == 3 || (m_param_ptr == 2 && m_cr & 0x10)) | |
| 1314 | { | |
| 1315 | //printf("%02x = %02x %02x (%c) %04x\n",m_cr,m_pr[2],m_pr[1],m_pr[1],EAD); | |
| 1316 | fifo_set_direction(FIFO_WRITE); | |
| 1317 | ||
| 1318 | write_vram((m_cr & 0x18) >> 3,m_cr & 3); | |
| 1319 | reset_figs_param(); | |
| 1320 | m_param_ptr = 1; | |
| 1321 | } | |
| 1322 | break; | |
| 1323 | ||
| 1324 | case COMMAND_MASK: /* mask register load */ | |
| 1325 | if (m_param_ptr == 3) | |
| 1326 | { | |
| 1327 | m_mask = (m_pr[2] << 8) | m_pr[1]; | |
| 1328 | ||
| 1329 | LOG(("uPD7220 '%s' MASK: %04x\n", tag(), m_mask)); | |
| 1330 | } | |
| 1331 | break; | |
| 1332 | ||
| 1333 | case COMMAND_FIGS: /* figure drawing parameters specify */ | |
| 1334 | if (m_param_ptr == 2) | |
| 1335 | { | |
| 1336 | m_figs.m_dir = m_pr[1] & 0x7; | |
| 1337 | m_figs.m_figure_type = (m_pr[1] & 0xf8) >> 3; | |
| 1338 | ||
| 1339 | //if(m_figs.m_dir != 2) | |
| 1340 | // printf("DIR %02x\n",m_pr[1]); | |
| 1341 | } | |
| 1342 | ||
| 1343 | // the Decision Mate V during start-up test upload only 2 params before execute the | |
| 1344 | // RDAT command, so I assume this is the expected behaviour, but this needs to be verified. | |
| 1345 | if (m_param_ptr == 3) | |
| 1346 | m_figs.m_dc = (m_pr[2]) | (m_figs.m_dc & 0x3f00); | |
| 1347 | ||
| 1348 | if (m_param_ptr == 4) | |
| 1349 | m_figs.m_dc = (m_pr[2]) | ((m_pr[3] & 0x3f) << 8); | |
| 1350 | ||
| 1351 | if (m_param_ptr == 6) | |
| 1352 | m_figs.m_d = (m_pr[4]) | ((m_pr[5] & 0x3f) << 8); | |
| 1353 | ||
| 1354 | if (m_param_ptr == 8) | |
| 1355 | m_figs.m_d2 = (m_pr[6]) | ((m_pr[7] & 0x3f) << 8); | |
| 1356 | ||
| 1357 | if (m_param_ptr == 10) | |
| 1358 | m_figs.m_d1 = (m_pr[8]) | ((m_pr[9] & 0x3f) << 8); | |
| 1359 | ||
| 1360 | if (m_param_ptr == 12) | |
| 1361 | m_figs.m_dm = (m_pr[10]) | ((m_pr[11] & 0x3f) << 8); | |
| 1362 | ||
| 1363 | break; | |
| 1364 | ||
| 1365 | case COMMAND_FIGD: /* figure draw start */ | |
| 1366 | if(m_figs.m_figure_type == 0) | |
| 1367 | { | |
| 1368 | UINT16 line_pattern = check_pattern((m_ra[8]) | (m_ra[9]<<8)); | |
| 1369 | UINT8 dot = ((line_pattern >> (0 & 0xf)) & 1) << 7; | |
| 1370 | ||
| 1371 | draw_pixel(((m_ead % m_pitch) << 4) | (m_dad & 0xf),(m_ead / m_pitch),dot); | |
| 1372 | } | |
| 1373 | else if(m_figs.m_figure_type == 1) | |
| 1374 | draw_line(((m_ead % m_pitch) << 4) | (m_dad & 0xf),(m_ead / m_pitch)); | |
| 1375 | else if(m_figs.m_figure_type == 8) | |
| 1376 | draw_rectangle(((m_ead % m_pitch) << 4) | (m_dad & 0xf),(m_ead / m_pitch)); | |
| 1377 | else | |
| 1378 | printf("uPD7220 '%s' Unimplemented command FIGD %02x\n", tag(),m_figs.m_figure_type); | |
| 1379 | ||
| 1380 | reset_figs_param(); | |
| 1381 | m_sr |= UPD7220_SR_DRAWING_IN_PROGRESS; | |
| 1382 | break; | |
| 1383 | ||
| 1384 | case COMMAND_GCHRD: /* graphics character draw and area filling start */ | |
| 1385 | if(m_figs.m_figure_type == 2) | |
| 1386 | draw_char(((m_ead % m_pitch) << 4) | (m_dad & 0xf),(m_ead / m_pitch)); | |
| 1387 | else | |
| 1388 | printf("uPD7220 '%s' Unimplemented command GCHRD %02x\n", tag(),m_figs.m_figure_type); | |
| 1389 | ||
| 1390 | reset_figs_param(); | |
| 1391 | m_sr |= UPD7220_SR_DRAWING_IN_PROGRESS; | |
| 1392 | break; | |
| 1393 | ||
| 1394 | case COMMAND_RDAT: /* read data from display memory */ | |
| 1395 | fifo_set_direction(FIFO_READ); | |
| 1396 | ||
| 1397 | read_vram((m_cr & 0x18) >> 3,m_cr & 3); | |
| 1398 | reset_figs_param(); | |
| 1399 | ||
| 1400 | m_sr |= UPD7220_SR_DATA_READY; | |
| 1401 | break; | |
| 1402 | ||
| 1403 | case COMMAND_CURD: /* cursor address read */ | |
| 1404 | fifo_set_direction(FIFO_READ); | |
| 1405 | ||
| 1406 | queue(m_ead & 0xff, 0); | |
| 1407 | queue((m_ead >> 8) & 0xff, 0); | |
| 1408 | queue(m_ead >> 16, 0); | |
| 1409 | queue(m_dad & 0xff, 0); | |
| 1410 | queue(m_dad >> 8, 0); | |
| 1411 | ||
| 1412 | m_sr |= UPD7220_SR_DATA_READY; | |
| 1413 | break; | |
| 1414 | ||
| 1415 | case COMMAND_LPRD: /* light pen address read */ | |
| 1416 | fifo_set_direction(FIFO_READ); | |
| 1417 | ||
| 1418 | queue(m_lad & 0xff, 0); | |
| 1419 | queue((m_lad >> 8) & 0xff, 0); | |
| 1420 | queue(m_lad >> 16, 0); | |
| 1421 | ||
| 1422 | m_sr |= UPD7220_SR_DATA_READY; | |
| 1423 | m_sr &= ~UPD7220_SR_LIGHT_PEN_DETECT; | |
| 1424 | break; | |
| 1425 | ||
| 1426 | case COMMAND_DMAR: /* DMA read request */ | |
| 1427 | printf("uPD7220 '%s' Unimplemented command DMAR\n", tag()); | |
| 1428 | break; | |
| 1429 | ||
| 1430 | case COMMAND_DMAW: /* DMA write request */ | |
| 1431 | printf("uPD7220 '%s' Unimplemented command DMAW\n", tag()); | |
| 1432 | break; | |
| 1433 | } | |
| 1434 | } | |
| 1435 | ||
| 1436 | ||
| 1437 | //------------------------------------------------- | |
| 1438 | // read - | |
| 1439 | //------------------------------------------------- | |
| 1440 | ||
| 1441 | READ8_MEMBER( upd7220_device::read ) | |
| 1442 | { | |
| 1443 | UINT8 data; | |
| 1444 | ||
| 1445 | if (offset & 1) | |
| 1446 | { | |
| 1447 | /* FIFO read */ | |
| 1448 | int flag; | |
| 1449 | fifo_set_direction(FIFO_READ); | |
| 1450 | dequeue(&data, &flag); | |
| 1451 | } | |
| 1452 | else | |
| 1453 | { | |
| 1454 | /* status register */ | |
| 1455 | data = m_sr; | |
| 1456 | ||
| 1457 | /* TODO: timing of these */ | |
| 1458 | m_sr &= ~UPD7220_SR_DRAWING_IN_PROGRESS; | |
| 1459 | m_sr &= ~UPD7220_SR_DMA_EXECUTE; | |
| 1460 | } | |
| 1461 | ||
| 1462 | return data; | |
| 1463 | } | |
| 1464 | ||
| 1465 | ||
| 1466 | //------------------------------------------------- | |
| 1467 | // write - | |
| 1468 | //------------------------------------------------- | |
| 1469 | ||
| 1470 | WRITE8_MEMBER( upd7220_device::write ) | |
| 1471 | { | |
| 1472 | if (offset & 1) | |
| 1473 | { | |
| 1474 | /* command into FIFO */ | |
| 1475 | fifo_set_direction(FIFO_WRITE); | |
| 1476 | queue(data, 1); | |
| 1477 | } | |
| 1478 | else | |
| 1479 | { | |
| 1480 | /* parameter into FIFO */ | |
| 1481 | // fifo_set_direction(FIFO_WRITE); | |
| 1482 | queue(data, 0); | |
| 1483 | } | |
| 1484 | ||
| 1485 | process_fifo(); | |
| 1486 | } | |
| 1487 | ||
| 1488 | ||
| 1489 | //------------------------------------------------- | |
| 1490 | // dack_r - | |
| 1491 | //------------------------------------------------- | |
| 1492 | ||
| 1493 | READ8_MEMBER( upd7220_device::dack_r ) | |
| 1494 | { | |
| 1495 | return 0; | |
| 1496 | } | |
| 1497 | ||
| 1498 | ||
| 1499 | //------------------------------------------------- | |
| 1500 | // dack_w - | |
| 1501 | //------------------------------------------------- | |
| 1502 | ||
| 1503 | WRITE8_MEMBER( upd7220_device::dack_w ) | |
| 1504 | { | |
| 1505 | } | |
| 1506 | ||
| 1507 | ||
| 1508 | //------------------------------------------------- | |
| 1509 | // ext_sync_w - | |
| 1510 | //------------------------------------------------- | |
| 1511 | ||
| 1512 | WRITE_LINE_MEMBER( upd7220_device::ext_sync_w ) | |
| 1513 | { | |
| 1514 | //LOG(("uPD7220 '%s' External Synchronization: %u\n", tag(), state)); | |
| 1515 | ||
| 1516 | if (state) | |
| 1517 | { | |
| 1518 | m_sr |= UPD7220_SR_VSYNC_ACTIVE; | |
| 1519 | } | |
| 1520 | else | |
| 1521 | { | |
| 1522 | m_sr &= ~UPD7220_SR_VSYNC_ACTIVE; | |
| 1523 | } | |
| 1524 | } | |
| 1525 | ||
| 1526 | ||
| 1527 | //------------------------------------------------- | |
| 1528 | // ext_sync_w - | |
| 1529 | //------------------------------------------------- | |
| 1530 | ||
| 1531 | WRITE_LINE_MEMBER( upd7220_device::lpen_w ) | |
| 1532 | { | |
| 1533 | /* only if 2 rising edges on the lpen input occur at the same | |
| 1534 | point during successive video fields are the pulses accepted */ | |
| 1535 | ||
| 1536 | /* | |
| 1537 | ||
| 1538 | 1. compute the address of the location on the CRT | |
| 1539 | 2. compare with LAD | |
| 1540 | 3. if not equal move address to LAD | |
| 1541 | 4. if equal set LPEN DETECT flag to 1 | |
| 1542 | ||
| 1543 | */ | |
| 1544 | } | |
| 1545 | ||
| 1546 | ||
| 1547 | //------------------------------------------------- | |
| 1548 | // update_text - | |
| 1549 | //------------------------------------------------- | |
| 1550 | ||
| 1551 | void upd7220_device::update_text(bitmap_rgb32 &bitmap, const rectangle &cliprect) | |
| 1552 | { | |
| 1553 | UINT32 addr, sad; | |
| 1554 | UINT16 len; | |
| 1555 | int im, wd; | |
| 1556 | int y, sy = 0; | |
| 1557 | ||
| 1558 | for (int area = 0; area < 4; area++) | |
| 1559 | { | |
| 1560 | get_text_partition(area, &sad, &len, &im, &wd); | |
| 1561 | ||
| 1562 | for (y = sy; y < sy + len; y++) | |
| 1563 | { | |
| 1564 | addr = sad + (y * m_pitch); | |
| 1565 | ||
| 1566 | if (m_draw_text_cb) | |
| 1567 | m_draw_text_cb(this, bitmap, addr, y, wd, m_pitch, m_lr, m_dc, m_ead); | |
| 1568 | } | |
| 1569 | ||
| 1570 | sy = y + 1; | |
| 1571 | } | |
| 1572 | } | |
| 1573 | ||
| 1574 | ||
| 1575 | //------------------------------------------------- | |
| 1576 | // draw_graphics_line - | |
| 1577 | //------------------------------------------------- | |
| 1578 | ||
| 1579 | void upd7220_device::draw_graphics_line(bitmap_rgb32 &bitmap, UINT32 addr, int y, int wd) | |
| 1580 | { | |
| 1581 | int sx; | |
| 1582 | ||
| 1583 | for (sx = 0; sx < m_pitch * 2; sx++) | |
| 1584 | { | |
| 1585 | if((sx << 3) < m_aw * 16 && y < m_al) | |
| 1586 | m_display_cb(this, bitmap, y, sx << 3, addr); | |
| 1587 | ||
| 1588 | addr+= wd + 1; | |
| 1589 | } | |
| 1590 | } | |
| 1591 | ||
| 1592 | ||
| 1593 | //------------------------------------------------- | |
| 1594 | // update_graphics - | |
| 1595 | //------------------------------------------------- | |
| 1596 | ||
| 1597 | void upd7220_device::update_graphics(bitmap_rgb32 &bitmap, const rectangle &cliprect, int force_bitmap) | |
| 1598 | { | |
| 1599 | UINT32 addr, sad; | |
| 1600 | UINT16 len; | |
| 1601 | int im, wd, area; | |
| 1602 | int y = 0, tsy = 0, bsy = 0; | |
| 1603 | ||
| 1604 | for (area = 0; area < 4; area++) | |
| 1605 | { | |
| 1606 | get_graphics_partition(area, &sad, &len, &im, &wd); | |
| 1607 | ||
| 1608 | if (im || force_bitmap) | |
| 1609 | { | |
| 1610 | get_graphics_partition(area, &sad, &len, &im, &wd); | |
| 1611 | ||
| 1612 | if(area >= 2) // TODO: correct? | |
| 1613 | break; | |
| 1614 | ||
| 1615 | for (y = 0; y < len; y++) | |
| 1616 | { | |
| 1617 | addr = ((sad << 1) & 0x3ffff) + (y * m_pitch * 2); | |
| 1618 | ||
| 1619 | if (m_display_cb) | |
| 1620 | draw_graphics_line(bitmap, addr, y + bsy, wd); | |
| 1621 | } | |
| 1622 | } | |
| 1623 | else | |
| 1624 | { | |
| 1625 | get_text_partition(area, &sad, &len, &im, &wd); | |
| 1626 | ||
| 1627 | if(m_lr) | |
| 1628 | { | |
| 1629 | for (y = 0; y < len; y+=m_lr) | |
| 1630 | { | |
| 1631 | addr = (sad & 0x3ffff) + ((y / m_lr) * m_pitch); | |
| 1632 | ||
| 1633 | if (m_draw_text_cb) | |
| 1634 | m_draw_text_cb(this, bitmap, addr, (y + tsy) / m_lr, wd, m_pitch, m_lr, m_dc, m_ead); | |
| 1635 | } | |
| 1636 | } | |
| 1637 | } | |
| 1638 | ||
| 1639 | if (m_lr) | |
| 1640 | tsy += y; | |
| 1641 | bsy += y; | |
| 1642 | } | |
| 1643 | } | |
| 1644 | ||
| 1645 | ||
| 1646 | //------------------------------------------------- | |
| 1647 | // update_screen - | |
| 1648 | //------------------------------------------------- | |
| 1649 | ||
| 1650 | UINT32 upd7220_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) | |
| 1651 | { | |
| 1652 | if (m_de) | |
| 1653 | { | |
| 1654 | switch (m_mode & UPD7220_MODE_DISPLAY_MASK) | |
| 1655 | { | |
| 1656 | case UPD7220_MODE_DISPLAY_MIXED: | |
| 1657 | update_graphics(bitmap, cliprect, 0); | |
| 1658 | break; | |
| 1659 | ||
| 1660 | case UPD7220_MODE_DISPLAY_GRAPHICS: | |
| 1661 | update_graphics(bitmap, cliprect, 1); | |
| 1662 | break; | |
| 1663 | ||
| 1664 | case UPD7220_MODE_DISPLAY_CHARACTER: | |
| 1665 | update_text(bitmap, cliprect); | |
| 1666 | break; | |
| 1667 | ||
| 1668 | case UPD7220_MODE_DISPLAY_INVALID: | |
| 1669 | LOG(("uPD7220 '%s' Invalid Display Mode!\n", tag())); | |
| 1670 | } | |
| 1671 | } | |
| 1672 | return 0; | |
| 1673 | } |
| r21684 | r21685 | |
|---|---|---|
| 1 | /********************************************************************** | |
| 2 | ||
| 3 | NEC uPD7220 Graphics Display Controller emulation | |
| 4 | ||
| 5 | Copyright MESS Team. | |
| 6 | Visit http://mamedev.org for licensing and usage restrictions. | |
| 7 | ||
| 8 | ********************************************************************** | |
| 9 | _____ _____ | |
| 10 | 2xWCLK 1 |* \_/ | 40 Vcc | |
| 11 | _DBIN 2 | | 39 A17 | |
| 12 | HSYNC 3 | | 38 A16 | |
| 13 | V/EXT SYNC 4 | | 37 AD15 | |
| 14 | BLANK 5 | | 36 AD14 | |
| 15 | ALE 6 | | 35 AD13 | |
| 16 | DRQ 7 | | 34 AD12 | |
| 17 | _DACK 8 | | 33 AD11 | |
| 18 | _RD 9 | | 32 AD10 | |
| 19 | _WR 10 | uPD7220 | 31 AD9 | |
| 20 | A0 11 | 82720 | 30 AD8 | |
| 21 | DB0 12 | | 29 AD7 | |
| 22 | DB1 13 | | 28 AD6 | |
| 23 | DB2 14 | | 27 AD5 | |
| 24 | DB3 15 | | 26 AD4 | |
| 25 | DB4 16 | | 25 AD3 | |
| 26 | DB5 17 | | 24 AD2 | |
| 27 | DB6 18 | | 23 AD1 | |
| 28 | DB7 19 | | 22 AD0 | |
| 29 | GND 20 |_____________| 21 LPEN | |
| 30 | ||
| 31 | **********************************************************************/ | |
| 32 | ||
| 33 | #pragma once | |
| 34 | ||
| 35 | #ifndef __UPD7220__ | |
| 36 | #define __UPD7220__ | |
| 37 | ||
| 38 | #include "emu.h" | |
| 39 | ||
| 40 | ||
| 41 | ||
| 42 | //************************************************************************** | |
| 43 | // MACROS / CONSTANTS | |
| 44 | //************************************************************************** | |
| 45 | ||
| 46 | ||
| 47 | ||
| 48 | ||
| 49 | //************************************************************************** | |
| 50 | // INTERFACE CONFIGURATION MACROS | |
| 51 | //************************************************************************** | |
| 52 | ||
| 53 | #define MCFG_UPD7220_ADD(_tag, _clock, _config, _map) \ | |
| 54 | MCFG_DEVICE_ADD(_tag, UPD7220, _clock) \ | |
| 55 | MCFG_DEVICE_CONFIG(_config) \ | |
| 56 | MCFG_DEVICE_ADDRESS_MAP(AS_0, _map) | |
| 57 | ||
| 58 | #define UPD7220_INTERFACE(name) \ | |
| 59 | const upd7220_interface (name) = | |
| 60 | ||
| 61 | ||
| 62 | ||
| 63 | //************************************************************************** | |
| 64 | // TYPE DEFINITIONS | |
| 65 | //************************************************************************** | |
| 66 | ||
| 67 | typedef void (*upd7220_display_pixels_func)(device_t *device, bitmap_rgb32 &bitmap, int y, int x, UINT32 address); | |
| 68 | #define UPD7220_DISPLAY_PIXELS(name) void name(device_t *device, bitmap_rgb32 &bitmap, int y, int x, UINT32 address) | |
| 69 | ||
| 70 | typedef void (*upd7220_draw_text_line)(device_t *device, bitmap_rgb32 &bitmap, UINT32 addr, int y, int wd, int pitch, int lr, int cursor_on, int cursor_addr); | |
| 71 | #define UPD7220_DRAW_TEXT_LINE(name) void name(device_t *device, bitmap_rgb32 &bitmap, UINT32 addr, int y, int wd, int pitch, int lr, int cursor_on, int cursor_addr) | |
| 72 | ||
| 73 | ||
| 74 | // ======================> upd7220_interface | |
| 75 | ||
| 76 | struct upd7220_interface | |
| 77 | { | |
| 78 | const char *m_screen_tag; | |
| 79 | ||
| 80 | upd7220_display_pixels_func m_display_cb; | |
| 81 | upd7220_draw_text_line m_draw_text_cb; | |
| 82 | ||
| 83 | devcb_write_line m_out_drq_cb; | |
| 84 | devcb_write_line m_out_hsync_cb; | |
| 85 | devcb_write_line m_out_vsync_cb; | |
| 86 | devcb_write_line m_out_blank_cb; | |
| 87 | }; | |
| 88 | ||
| 89 | // ======================> upd7220_device | |
| 90 | ||
| 91 | class upd7220_device : public device_t, | |
| 92 | public device_memory_interface, | |
| 93 | public upd7220_interface | |
| 94 | { | |
| 95 | public: | |
| 96 | // construction/destruction | |
| 97 | upd7220_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); | |
| 98 | ||
| 99 | DECLARE_READ8_MEMBER( read ); | |
| 100 | DECLARE_WRITE8_MEMBER( write ); | |
| 101 | ||
| 102 | DECLARE_READ8_MEMBER( dack_r ); | |
| 103 | DECLARE_WRITE8_MEMBER( dack_w ); | |
| 104 | ||
| 105 | DECLARE_WRITE_LINE_MEMBER( ext_sync_w ); | |
| 106 | DECLARE_WRITE_LINE_MEMBER( lpen_w ); | |
| 107 | ||
| 108 | DECLARE_WRITE8_MEMBER( bank_w ); | |
| 109 | DECLARE_READ8_MEMBER( vram_r ); | |
| 110 | DECLARE_WRITE8_MEMBER( vram_w ); | |
| 111 | ||
| 112 | UINT32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); | |
| 113 | virtual const rom_entry *device_rom_region() const; | |
| 114 | virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; | |
| 115 | ||
| 116 | protected: | |
| 117 | // device-level overrides | |
| 118 | virtual void device_start(); | |
| 119 | virtual void device_reset(); | |
| 120 | virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); | |
| 121 | virtual void device_config_complete(); | |
| 122 | ||
| 123 | private: | |
| 124 | static const device_timer_id TIMER_VSYNC = 0; | |
| 125 | static const device_timer_id TIMER_HSYNC = 1; | |
| 126 | static const device_timer_id TIMER_BLANK = 2; | |
| 127 | ||
| 128 | inline UINT8 readbyte(offs_t address); | |
| 129 | inline void writebyte(offs_t address, UINT8 data); | |
| 130 | inline void fifo_clear(); | |
| 131 | inline int fifo_param_count(); | |
| 132 | inline void fifo_set_direction(int dir); | |
| 133 | inline void queue(UINT8 data, int flag); | |
| 134 | inline void dequeue(UINT8 *data, int *flag); | |
| 135 | inline void update_vsync_timer(int state); | |
| 136 | inline void update_hsync_timer(int state); | |
| 137 | inline void update_blank_timer(int state); | |
| 138 | inline void recompute_parameters(); | |
| 139 | inline void reset_figs_param(); | |
| 140 | inline void advance_ead(); | |
| 141 | inline void read_vram(UINT8 type, UINT8 mod); | |
| 142 | inline void write_vram(UINT8 type, UINT8 mod); | |
| 143 | inline UINT16 check_pattern(UINT16 pattern); | |
| 144 | inline void get_text_partition(int index, UINT32 *sad, UINT16 *len, int *im, int *wd); | |
| 145 | inline void get_graphics_partition(int index, UINT32 *sad, UINT16 *len, int *im, int *wd); | |
| 146 | ||
| 147 | void draw_pixel(int x, int y, UINT8 tile_data); | |
| 148 | void draw_line(int x, int y); | |
| 149 | void draw_rectangle(int x, int y); | |
| 150 | void draw_char(int x, int y); | |
| 151 | int translate_command(UINT8 data); | |
| 152 | void process_fifo(); | |
| 153 | void update_text(bitmap_rgb32 &bitmap, const rectangle &cliprect); | |
| 154 | void draw_graphics_line(bitmap_rgb32 &bitmap, UINT32 addr, int y, int wd); | |
| 155 | void update_graphics(bitmap_rgb32 &bitmap, const rectangle &cliprect, int force_bitmap); | |
| 156 | ||
| 157 | devcb_resolved_write_line m_out_drq_func; | |
| 158 | devcb_resolved_write_line m_out_hsync_func; | |
| 159 | devcb_resolved_write_line m_out_vsync_func; | |
| 160 | devcb_resolved_write_line m_out_blank_func; | |
| 161 | ||
| 162 | screen_device *m_screen; | |
| 163 | ||
| 164 | UINT16 m_mask; // mask register | |
| 165 | UINT8 m_pitch; // number of word addresses in display memory in the horizontal direction | |
| 166 | UINT32 m_ead; // execute word address | |
| 167 | UINT16 m_dad; // dot address within the word | |
| 168 | UINT32 m_lad; // light pen address | |
| 169 | ||
| 170 | UINT8 m_ra[16]; // parameter RAM | |
| 171 | int m_ra_addr; // parameter RAM address | |
| 172 | ||
| 173 | UINT8 m_sr; // status register | |
| 174 | UINT8 m_cr; // command register | |
| 175 | UINT8 m_pr[17]; // parameter byte register | |
| 176 | int m_param_ptr; // parameter pointer | |
| 177 | ||
| 178 | UINT8 m_fifo[16]; // FIFO data queue | |
| 179 | int m_fifo_flag[16]; // FIFO flag queue | |
| 180 | int m_fifo_ptr; // FIFO pointer | |
| 181 | int m_fifo_dir; // FIFO direction | |
| 182 | ||
| 183 | UINT8 m_mode; // mode of operation | |
| 184 | UINT8 m_draw_mode; // mode of drawing | |
| 185 | ||
| 186 | int m_de; // display enabled | |
| 187 | int m_m; // 0 = accept external vertical sync (slave mode) / 1 = generate & output vertical sync (master mode) | |
| 188 | int m_aw; // active display words per line - 2 (must be even number with bit 0 = 0) | |
| 189 | int m_al; // active display lines per video field | |
| 190 | int m_vs; // vertical sync width - 1 | |
| 191 | int m_vfp; // vertical front porch width - 1 | |
| 192 | int m_vbp; // vertical back porch width - 1 | |
| 193 | int m_hs; // horizontal sync width - 1 | |
| 194 | int m_hfp; // horizontal front porch width - 1 | |
| 195 | int m_hbp; // horizontal back porch width - 1 | |
| 196 | ||
| 197 | int m_dc; // display cursor | |
| 198 | int m_sc; // 0 = blinking cursor / 1 = steady cursor | |
| 199 | int m_br; // blink rate | |
| 200 | int m_ctop; // cursor top line number in the row | |
| 201 | int m_cbot; // cursor bottom line number in the row (CBOT < LR) | |
| 202 | int m_lr; // lines per character row - 1 | |
| 203 | ||
| 204 | int m_disp; // display zoom factor | |
| 205 | int m_gchr; // zoom factor for graphics character writing and area filling | |
| 206 | ||
| 207 | UINT8 m_bitmap_mod; | |
| 208 | ||
| 209 | struct { | |
| 210 | UINT8 m_dir; // figs param 0: drawing direction | |
| 211 | UINT8 m_figure_type; // figs param 1: figure type | |
| 212 | UINT16 m_dc; // figs param 2: | |
| 213 | UINT16 m_d; // figs param 3: | |
| 214 | UINT16 m_d1; // figs param 4: | |
| 215 | UINT16 m_d2; // figs param 5: | |
| 216 | UINT16 m_dm; // figs param 6: | |
| 217 | } m_figs; | |
| 218 | ||
| 219 | // timers | |
| 220 | emu_timer *m_vsync_timer; // vertical sync timer | |
| 221 | emu_timer *m_hsync_timer; // horizontal sync timer | |
| 222 | emu_timer *m_blank_timer; // CRT blanking timer | |
| 223 | ||
| 224 | const address_space_config m_space_config; | |
| 225 | }; | |
| 226 | ||
| 227 | ||
| 228 | // device type definition | |
| 229 | extern const device_type UPD7220; | |
| 230 | ||
| 231 | ||
| 232 | ||
| 233 | #endif |
| r21684 | r21685 | |
|---|---|---|
| 1 | /*************************************************************************** | |
| 2 | ||
| 3 | Hitachi HD44780 LCD controller | |
| 4 | ||
| 5 | TODO: | |
| 6 | - dump internal CGROM | |
| 7 | ||
| 8 | ***************************************************************************/ | |
| 9 | ||
| 10 | #include "emu.h" | |
| 11 | #include "video/hd44780.h" | |
| 12 | ||
| 13 | #define LOG 0 | |
| 14 | ||
| 15 | //************************************************************************** | |
| 16 | // DEVICE DEFINITIONS | |
| 17 | //************************************************************************** | |
| 18 | ||
| 19 | const device_type HD44780 = &device_creator<hd44780_device>; | |
| 20 | const device_type KS0066_F05 = &device_creator<ks0066_f05_device>; | |
| 21 | ||
| 22 | ||
| 23 | //------------------------------------------------- | |
| 24 | // ROM( hd44780 ) | |
| 25 | //------------------------------------------------- | |
| 26 | ||
| 27 | ROM_START( hd44780_a00 ) | |
| 28 | ROM_REGION( 0x1000, "cgrom", 0 ) | |
| 29 | ROM_LOAD( "hd44780_a00.bin", 0x0000, 0x1000, BAD_DUMP CRC(01d108e2) SHA1(bc0cdf0c9ba895f22e183c7bd35a3f655f2ca96f)) // from page 17 of the HD44780 datasheet | |
| 30 | ROM_END | |
| 31 | ||
| 32 | ROM_START( ks0066_f05 ) | |
| 33 | ROM_REGION( 0x1000, "cgrom", 0 ) | |
| 34 | ROM_LOAD( "ks0066_f05.bin", 0x0000, 0x1000, BAD_DUMP CRC(af9e7bd6) SHA1(0196e871584ee5d370856e7307c0f9d1466e3e51)) // from page 51 of the KS0066 datasheet | |
| 35 | ROM_END | |
| 36 | ||
| 37 | //************************************************************************** | |
| 38 | // live device | |
| 39 | //************************************************************************** | |
| 40 | ||
| 41 | //------------------------------------------------- | |
| 42 | // hd44780_device - constructor | |
| 43 | //------------------------------------------------- | |
| 44 | ||
| 45 | hd44780_device::hd44780_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : | |
| 46 | device_t(mconfig, HD44780, "HD44780 A00", tag, owner, clock), | |
| 47 | m_pixel_update_func(NULL) | |
| 48 | { | |
| 49 | m_shortname = "hd44780_a00"; | |
| 50 | set_charset_type(CHARSET_HD44780_A00); | |
| 51 | } | |
| 52 | ||
| 53 | hd44780_device::hd44780_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock) : | |
| 54 | device_t(mconfig, type, name, tag, owner, clock), | |
| 55 | m_pixel_update_func(NULL) | |
| 56 | { | |
| 57 | } | |
| 58 | ||
| 59 | ks0066_f05_device::ks0066_f05_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : | |
| 60 | hd44780_device(mconfig, KS0066_F05, "KS0066 F05", tag, owner, clock) | |
| 61 | { | |
| 62 | m_shortname = "ks0066_f05"; | |
| 63 | set_charset_type(CHARSET_KS0066_F05); | |
| 64 | } | |
| 65 | ||
| 66 | ||
| 67 | //------------------------------------------------- | |
| 68 | // rom_region - device-specific ROM region | |
| 69 | //------------------------------------------------- | |
| 70 | ||
| 71 | const rom_entry *hd44780_device::device_rom_region() const | |
| 72 | { | |
| 73 | switch (m_charset_type) | |
| 74 | { | |
| 75 | case CHARSET_HD44780_A00: return ROM_NAME( hd44780_a00 ); | |
| 76 | case CHARSET_KS0066_F05: return ROM_NAME( ks0066_f05 ); | |
| 77 | } | |
| 78 | ||
| 79 | return NULL; | |
| 80 | } | |
| 81 | ||
| 82 | //------------------------------------------------- | |
| 83 | // device_start - device-specific startup | |
| 84 | //------------------------------------------------- | |
| 85 | ||
| 86 | void hd44780_device::device_start() | |
| 87 | { | |
| 88 | if (region()) | |
| 89 | m_cgrom = (UINT8*)(*region()); | |
| 90 | else | |
| 91 | m_cgrom = (UINT8*)(*memregion("cgrom")); | |
| 92 | ||
| 93 | m_busy_timer = timer_alloc(TIMER_BUSY); | |
| 94 | m_blink_timer = timer_alloc(TIMER_BLINKING); | |
| 95 | m_blink_timer->adjust(attotime::from_msec(409), 0, attotime::from_msec(409)); | |
| 96 | ||
| 97 | // state saving | |
| 98 | save_item(NAME(m_busy_flag)); | |
| 99 | save_item(NAME(m_ac)); | |
| 100 | save_item(NAME(m_dr)); | |
| 101 | save_item(NAME(m_ir)); | |
| 102 | save_item(NAME(m_active_ram)); | |
| 103 | save_item(NAME(m_display_on)); | |
| 104 | save_item(NAME(m_cursor_on)); | |
| 105 | save_item(NAME(m_shift_on)); | |
| 106 | save_item(NAME(m_blink_on)); | |
| 107 | save_item(NAME(m_direction)); | |
| 108 | save_item(NAME(m_data_len)); | |
| 109 | save_item(NAME(m_num_line)); | |
| 110 | save_item(NAME(m_char_size)); | |
| 111 | save_item(NAME(m_disp_shift)); | |
| 112 | save_item(NAME(m_blink)); | |
| 113 | save_item(NAME(m_ddram)); | |
| 114 | save_item(NAME(m_cgram)); | |
| 115 | save_item(NAME(m_nibble)); | |
| 116 | save_item(NAME(m_rs_state)); | |
| 117 | save_item(NAME(m_rw_state)); | |
| 118 | } | |
| 119 | ||
| 120 | //------------------------------------------------- | |
| 121 | // device_reset - device-specific reset | |
| 122 | //------------------------------------------------- | |
| 123 | ||
| 124 | void hd44780_device::device_reset() | |
| 125 | { | |
| 126 | memset(m_ddram, 0x20, sizeof(m_ddram)); // can't use 0 here as it would show CGRAM instead of blank space on a soft reset | |
| 127 | memset(m_cgram, 0, sizeof(m_cgram)); | |
| 128 | ||
| 129 | m_ac = 0; | |
| 130 | m_dr = 0; | |
| 131 | m_ir = 0; | |
| 132 | m_active_ram = DDRAM; | |
| 133 | m_display_on = false; | |
| 134 | m_cursor_on = false; | |
| 135 | m_blink_on = false; | |
| 136 | m_shift_on = false; | |
| 137 | m_direction = 1; | |
| 138 | m_data_len = 8; | |
| 139 | m_num_line = 1; | |
| 140 | m_char_size = 8; | |
| 141 | m_disp_shift = 0; | |
| 142 | m_blink = false; | |
| 143 | m_nibble = false; | |
| 144 | m_first_cmd = true; | |
| 145 | m_rs_state = 0; | |
| 146 | m_rw_state = 0; | |
| 147 | ||
| 148 | set_busy_flag(1520); | |
| 149 | } | |
| 150 | ||
| 151 | ||
| 152 | //------------------------------------------------- | |
| 153 | // device_timer - handler timer events | |
| 154 | //------------------------------------------------- | |
| 155 | ||
| 156 | void hd44780_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) | |
| 157 | { | |
| 158 | switch(id) | |
| 159 | { | |
| 160 | case TIMER_BUSY: | |
| 161 | m_busy_flag = false; | |
| 162 | break; | |
| 163 | ||
| 164 | case TIMER_BLINKING: | |
| 165 | m_blink = !m_blink; | |
| 166 | break; | |
| 167 | } | |
| 168 | } | |
| 169 | ||
| 170 | ||
| 171 | //************************************************************************** | |
| 172 | // HELPERS | |
| 173 | //************************************************************************** | |
| 174 | ||
| 175 | void hd44780_device::set_charset_type(int type) | |
| 176 | { | |
| 177 | m_charset_type = type; | |
| 178 | } | |
| 179 | ||
| 180 | void hd44780_device::set_busy_flag(UINT16 usec) | |
| 181 | { | |
| 182 | m_busy_flag = true; | |
| 183 | m_busy_timer->adjust( attotime::from_usec( usec ) ); | |
| 184 | } | |
| 185 | ||
| 186 | void hd44780_device::update_ac(int direction) | |
| 187 | { | |
| 188 | if (m_active_ram == DDRAM) | |
| 189 | { | |
| 190 | if(direction == 1) | |
| 191 | { | |
| 192 | if(m_num_line == 2 && m_ac == 0x27) | |
| 193 | m_ac = 0x40; | |
| 194 | else if((m_num_line == 2 && m_ac == 0x67) || (m_num_line == 1 && m_ac == 0x4f)) | |
| 195 | m_ac = 0x00; | |
| 196 | else | |
| 197 | m_ac = (m_ac + direction) & 0x7f; | |
| 198 | } | |
| 199 | else | |
| 200 | { | |
| 201 | if(m_num_line == 2 && m_ac == 0x00) | |
| 202 | m_ac = 0x67; | |
| 203 | else if(m_num_line == 1 && m_ac == 0x00) | |
| 204 | m_ac = 0x4f; | |
| 205 | else if(m_num_line == 2 && m_ac == 0x40) | |
| 206 | m_ac = 0x27; | |
| 207 | else | |
| 208 | m_ac = (m_ac + direction) & 0x7f; | |
| 209 | } | |
| 210 | } | |
| 211 | else | |
| 212 | { | |
| 213 | m_ac = (m_ac + direction) & 0x3f; | |
| 214 | } | |
| 215 | } | |
| 216 | ||
| 217 | void hd44780_device::shift_display(int direction) | |
| 218 | { | |
| 219 | if (direction == 1) | |
| 220 | { | |
| 221 | if(m_disp_shift == 0x4f) | |
| 222 | m_disp_shift = 0x00; | |
| 223 | else | |
| 224 | m_disp_shift++; | |
| 225 | } | |
| 226 | else | |
| 227 | { | |
| 228 | if(m_disp_shift == 0x00) | |
| 229 | m_disp_shift = 0x4f; | |
| 230 | else | |
| 231 | m_disp_shift--; | |
| 232 | } | |
| 233 | } | |
| 234 | ||
| 235 | void hd44780_device::update_nibble(int rs, int rw) | |
| 236 | { | |
| 237 | if (m_rs_state != rs || m_rw_state != rw) | |
| 238 | { | |
| 239 | m_rs_state = rs; | |
| 240 | m_rw_state = rw; | |
| 241 | m_nibble = false; | |
| 242 | } | |
| 243 | ||
| 244 | m_nibble = !m_nibble; | |
| 245 | } | |
| 246 | ||
| 247 | inline void hd44780_device::pixel_update(bitmap_ind16 &bitmap, UINT8 line, UINT8 pos, UINT8 y, UINT8 x, int state) | |
| 248 | { | |
| 249 | if (m_pixel_update_func != NULL) | |
| 250 | { | |
| 251 | m_pixel_update_func(*this, bitmap, line, pos, y, x, state); | |
| 252 | } | |
| 253 | else | |
| 254 | { | |
| 255 | UINT8 line_heigh = (m_char_size == 8) ? m_char_size : m_char_size + 1; | |
| 256 | ||
| 257 | if (m_lines <= 2) | |
| 258 | { | |
| 259 | if (pos < m_chars) | |
| 260 | bitmap.pix16(line * (line_heigh+1) + y, pos * 6 + x) = state; | |
| 261 | } | |
| 262 | else if (m_lines <= 4) | |
| 263 | { | |
| 264 | if (pos < m_chars*2) | |
| 265 | { | |
| 266 | if (pos >= m_chars) | |
| 267 | { | |
| 268 | line += 2; | |
| 269 | pos -= m_chars; | |
| 270 | } | |
| 271 | ||
| 272 | if (line < m_lines) | |
| 273 | bitmap.pix16(line * (line_heigh+1) + y, pos * 6 + x) = state; | |
| 274 | } | |
| 275 | } | |
| 276 | else | |
| 277 | { | |
| 278 | fatalerror("%s: use a custom callback for this LCD configuration (%d x %d)\n", tag(), m_lines, m_chars); | |
| 279 | } | |
| 280 | } | |
| 281 | } | |
| 282 | ||
| 283 | ||
| 284 | //************************************************************************** | |
| 285 | // device interface | |
| 286 | //************************************************************************** | |
| 287 | ||
| 288 | UINT32 hd44780_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) | |
| 289 | { | |
| 290 | bitmap.fill(0, cliprect); | |
| 291 | ||
| 292 | if (m_display_on) | |
| 293 | { | |
| 294 | UINT8 line_size = 80 / m_num_line; | |
| 295 | ||
| 296 | for (int line=0; line<m_num_line; line++) | |
| 297 | { | |
| 298 | for (int pos=0; pos<line_size; pos++) | |
| 299 | { | |
| 300 | UINT16 char_pos = line * 0x40 + ((pos + m_disp_shift) % line_size); | |
| 301 | ||
| 302 | int char_base = 0; | |
| 303 | if (m_ddram[char_pos] < 0x10) | |
| 304 | { | |
| 305 | // draw CGRAM characters | |
| 306 | if (m_char_size == 8) | |
| 307 | char_base = (m_ddram[char_pos] & 0x07) * 8; | |
| 308 | else | |
| 309 | char_base = ((m_ddram[char_pos]>>1) & 0x03) * 16; | |
| 310 | } | |
| 311 | else | |
| 312 | { | |
| 313 | // draw CGROM characters | |
| 314 | char_base = m_ddram[char_pos] * 0x10; | |
| 315 | } | |
| 316 | ||
| 317 | for (int y=0; y<m_char_size; y++) | |
| 318 | { | |
| 319 | UINT8 * charset = (m_ddram[char_pos] < 0x10) ? m_cgram : m_cgrom; | |
| 320 | ||
| 321 | for (int x=0; x<5; x++) | |
| 322 | pixel_update(bitmap, line, pos, y, x, BIT(charset[char_base + y], 4 - x)); | |
| 323 | } | |
| 324 | ||
| 325 | // if is the correct position draw cursor and blink | |
| 326 | if (char_pos == m_ac) | |
| 327 | { | |
| 328 | // draw the cursor | |
| 329 | UINT8 cursor_pos = (m_char_size == 8) ? m_char_size : m_char_size + 1; | |
| 330 | if (m_cursor_on) | |
| 331 | for (int x=0; x<5; x++) | |
| 332 | pixel_update(bitmap, line, pos, cursor_pos - 1, x, 1); | |
| 333 | ||
| 334 | if (!m_blink && m_blink_on) | |
| 335 | for (int y=0; y<(cursor_pos - 1); y++) | |
| 336 | for (int x=0; x<5; x++) | |
| 337 | pixel_update(bitmap, line, pos, y, x, 1); | |
| 338 | } | |
| 339 | } | |
| 340 | } | |
| 341 | } | |
| 342 | ||
| 343 | return 0; | |
| 344 | } | |
| 345 | ||
| 346 | READ8_MEMBER(hd44780_device::read) | |
| 347 | { | |
| 348 | switch(offset & 0x01) | |
| 349 | { | |
| 350 | case 0: return control_read(space, 0); | |
| 351 | case 1: return data_read(space, 0); | |
| 352 | } | |
| 353 | ||
| 354 | return 0; | |
| 355 | } | |
| 356 | ||
| 357 | WRITE8_MEMBER(hd44780_device::write) | |
| 358 | { | |
| 359 | switch(offset & 0x01) | |
| 360 | { | |
| 361 | case 0: control_write(space, 0, data); break; | |
| 362 | case 1: data_write(space, 0, data); break; | |
| 363 | } | |
| 364 | } | |
| 365 | ||
| 366 | WRITE8_MEMBER(hd44780_device::control_write) | |
| 367 | { | |
| 368 | if (m_data_len == 4) | |
| 369 | { | |
| 370 | update_nibble(0, 0); | |
| 371 | ||
| 372 | if (m_nibble) | |
| 373 | { | |
| 374 | m_ir = data & 0xf0; | |
| 375 | return; | |
| 376 | } | |
| 377 | else | |
| 378 | { | |
| 379 | m_ir |= ((data>>4) & 0x0f); | |
| 380 | } | |
| 381 | } | |
| 382 | else | |
| 383 | { | |
| 384 | m_ir = data; | |
| 385 | } | |
| 386 | ||
| 387 | if (BIT(m_ir, 7)) // set DDRAM address | |
| 388 | { | |
| 389 | m_active_ram = DDRAM; | |
| 390 | m_ac = m_ir & 0x7f; | |
| 391 | set_busy_flag(37); | |
| 392 | ||
| 393 | if (LOG) logerror("HD44780 '%s': set DDRAM address %x\n", tag(), m_ac); | |
| 394 | } | |
| 395 | else if (BIT(m_ir, 6)) // set CGRAM address | |
| 396 | { | |
| 397 | m_active_ram = CGRAM; | |
| 398 | m_ac = m_ir & 0x3f; | |
| 399 | set_busy_flag(37); | |
| 400 | ||
| 401 | if (LOG) logerror("HD44780 '%s': set CGRAM address %x\n", tag(), m_ac); | |
| 402 | } | |
| 403 | else if (BIT(m_ir, 5)) // function set | |
| 404 | { | |
| 405 | if (!m_first_cmd && m_data_len == (BIT(m_ir, 4) ? 8 : 4) && (m_char_size != (BIT(m_ir, 2) ? 10 : 8) || m_num_line != (BIT(m_ir, 3) + 1))) | |
| 406 | { | |
| 407 | logerror("HD44780 '%s': function set cannot be executed after other instructions unless the interface data length is changed\n", tag()); | |
| 408 | return; | |
| 409 | } | |
| 410 | ||
| 411 | m_char_size = BIT(m_ir, 2) ? 10 : 8; | |
| 412 | m_data_len = BIT(m_ir, 4) ? 8 : 4; | |
| 413 | m_num_line = BIT(m_ir, 3) + 1; | |
| 414 | set_busy_flag(37); | |
| 415 | ||
| 416 | if (LOG) logerror("HD44780 '%s': char size 5x%d, data len %d, lines %d\n", tag(), m_char_size, m_data_len, m_num_line); | |
| 417 | return; | |
| 418 | } | |
| 419 | else if (BIT(m_ir, 4)) // cursor or display shift | |
| 420 | { | |
| 421 | int direct = (BIT(m_ir, 2)) ? +1 : -1; | |
| 422 | ||
| 423 | if (LOG) logerror("HD44780 '%s': %s shift %d\n", tag(), BIT(m_ir, 3) ? "display" : "cursor", direct); | |
| 424 | ||
| 425 | if (BIT(m_ir, 3)) | |
| 426 | shift_display(direct); | |
| 427 | else | |
| 428 | update_ac(direct); | |
| 429 | ||
| 430 | set_busy_flag(37); | |
| 431 | } | |
| 432 | else if (BIT(m_ir, 3)) // display on/off control | |
| 433 | { | |
| 434 | m_display_on = BIT(m_ir, 2); | |
| 435 | m_cursor_on = BIT(m_ir, 1); | |
| 436 | m_blink_on = BIT(m_ir, 0); | |
| 437 | set_busy_flag(37); | |
| 438 | ||
| 439 | if (LOG) logerror("HD44780 '%s': display %d, cursor %d, blink %d\n", tag(), m_display_on, m_cursor_on, m_blink_on); | |
| 440 | } | |
| 441 | else if (BIT(m_ir, 2)) // entry mode set | |
| 442 | { | |
| 443 | m_direction = (BIT(m_ir, 1)) ? +1 : -1; | |
| 444 | m_shift_on = BIT(m_ir, 0); | |
| 445 | set_busy_flag(37); | |
| 446 | ||
| 447 | if (LOG) logerror("HD44780 '%s': entry mode set: direction %d, shift %d\n", tag(), m_direction, m_shift_on); | |
| 448 | } | |
| 449 | else if (BIT(m_ir, 1)) // return home | |
| 450 | { | |
| 451 | if (LOG) logerror("HD44780 '%s': return home\n", tag()); | |
| 452 | ||
| 453 | m_ac = 0; | |
| 454 | m_active_ram = DDRAM; | |
| 455 | m_direction = 1; | |
| 456 | m_disp_shift = 0; | |
| 457 | set_busy_flag(1520); | |
| 458 | } | |
| 459 | else if (BIT(m_ir, 0)) // clear display | |
| 460 | { | |
| 461 | if (LOG) logerror("HD44780 '%s': clear display\n", tag()); | |
| 462 | ||
| 463 | m_ac = 0; | |
| 464 | m_active_ram = DDRAM; | |
| 465 | m_direction = 1; | |
| 466 | m_disp_shift = 0; | |
| 467 | memset(m_ddram, 0x20, sizeof(m_ddram)); | |
| 468 | set_busy_flag(1520); | |
| 469 | } | |
| 470 | ||
| 471 | m_first_cmd = false; | |
| 472 | } | |
| 473 | ||
| 474 | READ8_MEMBER(hd44780_device::control_read) | |
| 475 | { | |
| 476 | if (m_data_len == 4) | |
| 477 | { | |
| 478 | if (!space.debugger_access()) | |
| 479 | update_nibble(0, 1); | |
| 480 | ||
| 481 | if (m_nibble) | |
| 482 | return (m_busy_flag ? 0x80 : 0) | (m_ac & 0x70); | |
| 483 | else | |
| 484 | return (m_ac<<4) & 0xf0; | |
| 485 | } | |
| 486 | else | |
| 487 | { | |
| 488 | return (m_busy_flag ? 0x80 : 0) | (m_ac & 0x7f); | |
| 489 | } | |
| 490 | } | |
| 491 | ||
| 492 | WRITE8_MEMBER(hd44780_device::data_write) | |
| 493 | { | |
| 494 | if (m_busy_flag) | |
| 495 | { | |
| 496 | logerror("HD44780 '%s': Ignoring data write %02x due of busy flag\n", tag(), data); | |
| 497 | return; | |
| 498 | } | |
| 499 | ||
| 500 | if (m_data_len == 4) | |
| 501 | { | |
| 502 | update_nibble(1, 0); | |
| 503 | ||
| 504 | if (m_nibble) | |
| 505 | { | |
| 506 | m_dr = data & 0xf0; | |
| 507 | return; | |
| 508 | } | |
| 509 | else | |
| 510 | { | |
| 511 | m_dr |= ((data>>4) & 0x0f); | |
| 512 | } | |
| 513 | } | |
| 514 | else | |
| 515 | { | |
| 516 | m_dr = data; | |
| 517 | } | |
| 518 | ||
| 519 | if (LOG) logerror("HD44780 '%s': %sRAM write %x %x '%c'\n", tag(), m_active_ram == DDRAM ? "DD" : "CG", m_ac, m_dr, isprint(m_dr) ? m_dr : '.'); | |
| 520 | ||
| 521 | if (m_active_ram == DDRAM) | |
| 522 | m_ddram[m_ac] = m_dr; | |
| 523 | else | |
| 524 | m_cgram[m_ac] = m_dr; | |
| 525 | ||
| 526 | update_ac(m_direction); | |
| 527 | if (m_shift_on) | |
| 528 | shift_display(m_direction); | |
| 529 | set_busy_flag(41); | |
| 530 | } | |
| 531 | ||
| 532 | READ8_MEMBER(hd44780_device::data_read) | |
| 533 | { | |
| 534 | UINT8 data = (m_active_ram == DDRAM) ? m_ddram[m_ac] : m_cgram[m_ac]; | |
| 535 | ||
| 536 | if (LOG) logerror("HD44780 '%s': %sRAM read %x %c\n", tag(), m_active_ram == DDRAM ? "DD" : "CG", m_ac, data); | |
| 537 | ||
| 538 | if (m_data_len == 4) | |
| 539 | { | |
| 540 | if (!space.debugger_access()) | |
| 541 | update_nibble(1, 1); | |
| 542 | ||
| 543 | if (m_nibble) | |
| 544 | return data & 0xf0; | |
| 545 | else | |
| 546 | data = (data<<4) & 0xf0; | |
| 547 | } | |
| 548 | ||
| 549 | if (!space.debugger_access()) | |
| 550 | { | |
| 551 | update_ac(m_direction); | |
| 552 | set_busy_flag(41); | |
| 553 | } | |
| 554 | ||
| 555 | return data; | |
| 556 | } |
| r21684 | r21685 | |
|---|---|---|
| 1 | /*************************************************************************** | |
| 2 | ||
| 3 | Hitachi HD44780 LCD controller | |
| 4 | ||
| 5 | ***************************************************************************/ | |
| 6 | ||
| 7 | #pragma once | |
| 8 | ||
| 9 | #ifndef __HD44780_H__ | |
| 10 | #define __HD44780_H__ | |
| 11 | ||
| 12 | ||
| 13 | #define MCFG_HD44780_ADD( _tag ) \ | |
| 14 | MCFG_DEVICE_ADD( _tag, HD44780, 0 ) | |
| 15 | ||
| 16 | #define MCFG_KS0066_F05_ADD( _tag ) \ | |
| 17 | MCFG_DEVICE_ADD( _tag, KS0066_F05, 0 ) | |
| 18 | ||
| 19 | #define MCFG_HD44780_LCD_SIZE(_lines, _chars) \ | |
| 20 | hd44780_device::static_set_lcd_size(*device, _lines, _chars); | |
| 21 | ||
| 22 | #define MCFG_HD44780_PIXEL_UPDATE_CB(_cb) \ | |
| 23 | hd44780_device::static_set_pixel_update_cb(*device, _cb); | |
| 24 | ||
| 25 | //************************************************************************** | |
| 26 | // TYPE DEFINITIONS | |
| 27 | //************************************************************************** | |
| 28 | ||
| 29 | typedef void (*hd44780_pixel_update_func)(device_t &device, bitmap_ind16 &bitmap, UINT8 line, UINT8 pos, UINT8 y, UINT8 x, int state); | |
| 30 | #define HD44780_PIXEL_UPDATE(name) void name(device_t &device, bitmap_ind16 &bitmap, UINT8 line, UINT8 pos, UINT8 y, UINT8 x, int state) | |
| 31 | ||
| 32 | ||
| 33 | // ======================> hd44780_device | |
| 34 | ||
| 35 | class hd44780_device : public device_t | |
| 36 | { | |
| 37 | public: | |
| 38 | // construction/destruction | |
| 39 | hd44780_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); | |
| 40 | hd44780_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock); | |
| 41 | ||
| 42 | // static configuration helpers | |
| 43 | static void static_set_lcd_size(device_t &device, int _lines, int _chars) { hd44780_device &dev=downcast<hd44780_device &>(device); dev.m_lines = _lines; dev.m_chars = _chars; } | |
| 44 | static void static_set_pixel_update_cb(device_t &device, hd44780_pixel_update_func _cb) { downcast<hd44780_device &>(device).m_pixel_update_func = _cb; } | |
| 45 | ||
| 46 | // device interface | |
| 47 | virtual DECLARE_WRITE8_MEMBER(write); | |
| 48 | virtual DECLARE_READ8_MEMBER(read); | |
| 49 | virtual DECLARE_WRITE8_MEMBER(control_write); | |
| 50 | virtual DECLARE_READ8_MEMBER(control_read); | |
| 51 | virtual DECLARE_WRITE8_MEMBER(data_write); | |
| 52 | virtual DECLARE_READ8_MEMBER(data_read); | |
| 53 | virtual UINT32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); | |
| 54 | ||
| 55 | protected: | |
| 56 | // device-level overrides | |
| 57 | virtual void device_start(); | |
| 58 | virtual void device_reset(); | |
| 59 | virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); | |
| 60 | ||
| 61 | // optional information overrides | |
| 62 | virtual const rom_entry *device_rom_region() const; | |
| 63 | ||
| 64 | // charset | |
| 65 | enum | |
| 66 | { | |
| 67 | CHARSET_HD44780_A00, | |
| 68 | CHARSET_KS0066_F05, | |
| 69 | /* | |
| 70 | CHARSET_HD44780_A01, | |
| 71 | CHARSET_HD44780_A02, | |
| 72 | CHARSET_KS0066_F00, | |
| 73 | CHARSET_KS0066_F03, | |
| 74 | CHARSET_KS0066_F04, | |
| 75 | CHARSET_KS0066_F06, | |
| 76 | CHARSET_KS0066_F59, | |
| 77 | */ | |
| 78 | }; | |
| 79 | ||
| 80 | void set_charset_type(int type); | |
| 81 | ||
| 82 | private: | |
| 83 | // internal helper | |
| 84 | void set_busy_flag(UINT16 usec); | |
| 85 | void update_ac(int direction); | |
| 86 | void update_nibble(int rs, int rw); | |
| 87 | void shift_display(int direction); | |
| 88 | void pixel_update(bitmap_ind16 &bitmap, UINT8 line, UINT8 pos, UINT8 y, UINT8 x, int state); | |
| 89 | ||
| 90 | // internal state | |
| 91 | static const device_timer_id TIMER_BUSY = 0; | |
| 92 | static const device_timer_id TIMER_BLINKING = 1; | |
| 93 | ||
| 94 | emu_timer * m_blink_timer; | |
| 95 | emu_timer * m_busy_timer; | |
| 96 | ||
| 97 | UINT8 m_lines; // number of lines | |
| 98 | UINT8 m_chars; // chars for line | |
| 99 | hd44780_pixel_update_func m_pixel_update_func; // pixel update callback | |
| 100 | ||
| 101 | bool m_busy_flag; // busy flag | |
| 102 | UINT8 m_ddram[0x80]; // internal display data RAM | |
| 103 | UINT8 m_cgram[0x40]; // internal chargen RAM | |
| 104 | UINT8 * m_cgrom; // internal chargen ROM | |
| 105 | INT8 m_ac; // address counter | |
| 106 | UINT8 m_dr; // data register | |
| 107 | UINT8 m_ir; // instruction register | |
| 108 | UINT8 m_active_ram; // DDRAM or CGRAM | |
| 109 | bool m_display_on; // display on/off | |
| 110 | bool m_cursor_on; // cursor on/off | |
| 111 | bool m_blink_on; // blink on/off | |
| 112 | bool m_shift_on; // shift on/off | |
| 113 | UINT8 m_disp_shift; // display shift | |
| 114 | INT8 m_direction; // auto increment/decrement | |
| 115 | UINT8 m_data_len; // interface data length 4 or 8 bit | |
| 116 | UINT8 m_num_line; // number of lines | |
| 117 | UINT8 m_char_size; // char size 5x8 or 5x10 | |
| 118 | bool m_blink; | |
| 119 | bool m_first_cmd; | |
| 120 | int m_rs_state; | |
| 121 | int m_rw_state; | |
| 122 | bool m_nibble; | |
| 123 | int m_charset_type; | |
| 124 | ||
| 125 | enum { DDRAM, CGRAM }; | |
| 126 | }; | |
| 127 | ||
| 128 | // ======================> ks0066_f05_device | |
| 129 | ||
| 130 | class ks0066_f05_device : public hd44780_device | |
| 131 | { | |
| 132 | public: | |
| 133 | // construction/destruction | |
| 134 | ks0066_f05_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); | |
| 135 | }; | |
| 136 | ||
| 137 | // device type definition | |
| 138 | extern const device_type HD44780; | |
| 139 | extern const device_type KS0066_F05; | |
| 140 | ||
| 141 | #endif |
| r21684 | r21685 | |
|---|---|---|
| 1 | /* | |
| 2 | tms3556 emulation | |
| 3 | ||
| 4 | TODO: | |
| 5 | * implement remaining flags in control registers | |
| 6 | * test the whole thing | |
| 7 | * find the bloody tms3556 manual. I mean the register and VRAM interfaces | |
| 8 | are mostly guesswork full of hacks, and I'd like to compare it with | |
| 9 | documentation. | |
| 10 | ||
| 11 | Raphael Nabet, 2004 | |
| 12 | */ | |
| 13 | ||
| 14 | #include "emu.h" | |
| 15 | #include "tms3556.h" | |
| 16 | ||
| 17 | //************************************************************************** | |
| 18 | // MACROS / CONSTANTS | |
| 19 | //************************************************************************** | |
| 20 | ||
| 21 | #define LOG 0 | |
| 22 | ||
| 23 | //************************************************************************** | |
| 24 | // GLOBAL VARIABLES | |
| 25 | //************************************************************************** | |
| 26 | ||
| 27 | // devices | |
| 28 | const device_type TMS3556 = &device_creator<tms3556_device>; | |
| 29 | ||
| 30 | ||
| 31 | // default address map | |
| 32 | static ADDRESS_MAP_START( tms3556, AS_0, 8, tms3556_device ) | |
| 33 | AM_RANGE(0x0000, 0xffff) AM_RAM | |
| 34 | ADDRESS_MAP_END | |
| 35 | ||
| 36 | //------------------------------------------------- | |
| 37 | // memory_space_config - return a description of | |
| 38 | // any address spaces owned by this device | |
| 39 | //------------------------------------------------- | |
| 40 | ||
| 41 | const address_space_config *tms3556_device::memory_space_config(address_spacenum spacenum) const | |
| 42 | { | |
| 43 | return (spacenum == AS_0) ? &m_space_config : NULL; | |
| 44 | } | |
| 45 | ||
| 46 | ||
| 47 | //************************************************************************** | |
| 48 | // INLINE HELPERS | |
| 49 | //************************************************************************** | |
| 50 | ||
| 51 | //------------------------------------------------- | |
| 52 | // readbyte - read a byte at the given address | |
| 53 | //------------------------------------------------- | |
| 54 | ||
| 55 | inline UINT8 tms3556_device::readbyte(offs_t address) | |
| 56 | { | |
| 57 | return space().read_byte(address); | |
| 58 | } | |
| 59 | ||
| 60 | ||
| 61 | //------------------------------------------------- | |
| 62 | // writebyte - write a byte at the given address | |
| 63 | //------------------------------------------------- | |
| 64 | ||
| 65 | inline void tms3556_device::writebyte(offs_t address, UINT8 data) | |
| 66 | { | |
| 67 | space().write_byte(address, data); | |
| 68 | } | |
| 69 | ||
| 70 | ||
| 71 | //************************************************************************** | |
| 72 | // LIVE DEVICE | |
| 73 | //************************************************************************** | |
| 74 | ||
| 75 | //------------------------------------------------- | |
| 76 | // tms3556_device - constructor | |
| 77 | //------------------------------------------------- | |
| 78 | ||
| 79 | tms3556_device::tms3556_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) | |
| 80 | : device_t(mconfig, TMS3556, "Texas Instruments VDP TMS3556", tag, owner, clock), | |
| 81 | device_memory_interface(mconfig, *this), | |
| 82 | m_space_config("videoram", ENDIANNESS_LITTLE, 8, 17, 0, NULL, *ADDRESS_MAP_NAME(tms3556)), | |
| 83 | m_write_ptr(0), | |
| 84 | m_reg_ptr(0), | |
| 85 | m_reg_access_phase(0), | |
| 86 | m_magical_mystery_flag(0), | |
| 87 | m_scanline(0), | |
| 88 | m_blink(0), | |
| 89 | m_blink_count(0) | |
| 90 | { | |
| 91 | for (int i = 0; i < 8; i++) | |
| 92 | { | |
| 93 | m_control_regs[i] = 0; | |
| 94 | m_address_regs[i] = 0; | |
| 95 | } | |
| 96 | } | |
| 97 | ||
| 98 | ||
| 99 | //------------------------------------------------- | |
| 100 | // device_start - device-specific startup | |
| 101 | //------------------------------------------------- | |
| 102 | ||
| 103 | void tms3556_device::device_start() | |
| 104 | { | |
| 105 | // register for state saving | |
| 106 | save_item(NAME(m_control_regs)); | |
| 107 | save_item(NAME(m_address_regs)); | |
| 108 | save_item(NAME(m_write_ptr)); | |
| 109 | save_item(NAME(m_reg_ptr)); | |
| 110 | save_item(NAME(m_reg_access_phase)); | |
| 111 | save_item(NAME(m_magical_mystery_flag)); | |
| 112 | save_item(NAME(m_scanline)); | |
| 113 | save_item(NAME(m_blink)); | |
| 114 | save_item(NAME(m_blink_count)); | |
| 115 | save_item(NAME(m_bg_color)); | |
| 116 | save_item(NAME(m_name_offset)); | |
| 117 | save_item(NAME(m_cg_flag)); | |
| 118 | save_item(NAME(m_char_line_counter)); | |
| 119 | save_item(NAME(m_dbl_h_phase)); | |
| 120 | ||
| 121 | machine().primary_screen->register_screen_bitmap(m_bitmap); | |
| 122 | } | |
| 123 | ||
| 124 | ||
| 125 | /*static const char *const tms3556_mode_names[] = { "DISPLAY OFF", "TEXT", "GRAPHIC", "MIXED" };*/ | |
| 126 | ||
| 127 | ||
| 128 | UINT32 tms3556_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) | |
| 129 | { | |
| 130 | copybitmap(bitmap, m_bitmap, 0, 0, 0, 0, cliprect); | |
| 131 | return 0; | |
| 132 | } | |
| 133 | ||
| 134 | ||
| 135 | //------------------------------------------------- | |
| 136 | // vram_r - VRAM read | |
| 137 | //------------------------------------------------- | |
| 138 | ||
| 139 | READ8_MEMBER( tms3556_device::vram_r ) | |
| 140 | { | |
| 141 | if (LOG) logerror("TMS3556 VRAM Read: %06x\n", offset); | |
| 142 | ||
| 143 | if (m_magical_mystery_flag) | |
| 144 | { | |
| 145 | m_write_ptr = ((m_control_regs[2] << 8) | m_control_regs[1]) + 1; | |
| 146 | m_magical_mystery_flag = 0; | |
| 147 | } | |
| 148 | ||
| 149 | return readbyte(m_address_regs[1]++); | |
| 150 | } | |
| 151 | ||
| 152 | //------------------------------------------------- | |
| 153 | // vram_w - VRAM write | |
| 154 | //------------------------------------------------- | |
| 155 | ||
| 156 | WRITE8_MEMBER( tms3556_device::vram_w ) | |
| 157 | { | |
| 158 | if (LOG) logerror("TMS3556 VRAM Write: %06x = %02x\n", offset, data); | |
| 159 | ||
| 160 | if (m_magical_mystery_flag) | |
| 161 | { | |
| 162 | m_write_ptr = (m_control_regs[2] << 8) | m_control_regs[1]; | |
| 163 | m_magical_mystery_flag = 0; | |
| 164 | } | |
| 165 | ||
| 166 | writebyte(m_write_ptr++, data); | |
| 167 | } | |
| 168 | ||
| 169 | ||
| 170 | //------------------------------------------------- | |
| 171 | // reg_r - read from register port | |
| 172 | //------------------------------------------------- | |
| 173 | ||
| 174 | READ8_MEMBER( tms3556_device::reg_r ) | |
| 175 | { | |
| 176 | if (LOG) logerror("TMS3556 Reg Read: %06x\n", offset); | |
| 177 | ||
| 178 | int reply = 0; | |
| 179 | ||
| 180 | if (m_reg_ptr < 8) | |
| 181 | { | |
| 182 | reply = m_control_regs[m_reg_ptr]; | |
| 183 | m_reg_access_phase = 0; | |
| 184 | } | |
| 185 | else | |
| 186 | { | |
| 187 | // ??? | |
| 188 | } | |
| 189 | ||
| 190 | return reply; | |
| 191 | } | |
| 192 | ||
| 193 | //------------------------------------------------- | |
| 194 | // reg_w - write to register port | |
| 195 | //------------------------------------------------- | |
| 196 | ||
| 197 | WRITE8_MEMBER( tms3556_device::reg_w ) | |
| 198 | { | |
| 199 | if (LOG) logerror("TMS3556 Reg Write: %06x = %02x\n", offset, data); | |
| 200 | ||
| 201 | if ((m_reg_access_phase == 3) && (data)) | |
| 202 | m_reg_access_phase = 0; /* ???????????? */ | |
| 203 | ||
| 204 | switch (m_reg_access_phase) | |
| 205 | { | |
| 206 | case 0: | |
| 207 | m_reg_ptr = data & 0x0f; | |
| 208 | m_reg_access_phase = 1; | |
| 209 | break; | |
| 210 | ||
| 211 | case 1: | |
| 212 | if (m_reg_ptr < 8) | |
| 213 | { | |
| 214 | m_control_regs[m_reg_ptr] = data; | |
| 215 | m_reg_access_phase = 0; | |
| 216 | if (m_reg_ptr == 2) | |
| 217 | m_magical_mystery_flag = 1; | |
| 218 | } | |
| 219 | else if (m_reg_ptr == 9) | |
| 220 | { /* I don't understand what is going on, but it is the only way to | |
| 221 | get this to work */ | |
| 222 | m_address_regs[m_reg_ptr - 8] = ((m_control_regs[2] << 8) | m_control_regs[1]) + 1; | |
| 223 | m_reg_access_phase = 0; | |
| 224 | m_magical_mystery_flag = 0; | |
| 225 | } | |
| 226 | else | |
| 227 | { | |
| 228 | m_address_regs[m_reg_ptr - 8] = (m_control_regs[m_reg_ptr - 8] & 0xff00) | m_control_regs[1]; | |
| 229 | m_reg_access_phase = 2; | |
| 230 | m_magical_mystery_flag = 0; | |
| 231 | } | |
| 232 | break; | |
| 233 | ||
| 234 | case 2: | |
| 235 | m_address_regs[m_reg_ptr - 8] = (m_control_regs[m_reg_ptr - 8] & 0x00ff) | (m_control_regs[2] << 8); | |
| 236 | if ((m_reg_ptr <= 10) || (m_reg_ptr == 15)) | |
| 237 | m_address_regs[m_reg_ptr - 8]++; | |
| 238 | else | |
| 239 | m_address_regs[m_reg_ptr - 8] += 2; | |
| 240 | m_reg_access_phase = 3; | |
| 241 | break; | |
| 242 | ||
| 243 | case 3: | |
| 244 | m_reg_access_phase = 0; | |
| 245 | break; | |
| 246 | } | |
| 247 | } | |
| 248 | ||
| 249 | ||
| 250 | //------------------------------------------------- | |
| 251 | // redraw code | |
| 252 | //------------------------------------------------- | |
| 253 | ||
| 254 | ||
| 255 | //------------------------------------------------- | |
| 256 | // draw_line_empty - draw an empty line (used for | |
| 257 | // top and bottom borders, and screen off mode) | |
| 258 | //------------------------------------------------- | |
| 259 | ||
| 260 | void tms3556_device::draw_line_empty(UINT16 *ln) | |
| 261 | { | |
| 262 | int i; | |
| 263 | ||
| 264 | for (i = 0; i < TMS3556_TOTAL_WIDTH; i++) | |
| 265 | #if TMS3556_DOUBLE_WIDTH | |
| 266 | *ln++ = m_bg_color; | |
| 267 | #endif | |
| 268 | *ln++ = m_bg_color; | |
| 269 | } | |
| 270 | ||
| 271 | ||
| 272 | //------------------------------------------------- | |
| 273 | // draw_line_text_common - draw a line of text | |
| 274 | // (called by draw_line_text and draw_line_mixed) | |
| 275 | //------------------------------------------------- | |
| 276 | ||
| 277 | void tms3556_device::draw_line_text_common(UINT16 *ln) | |
| 278 | { | |
| 279 | int pattern, x, xx, i, name_offset; | |
| 280 | UINT16 fg, bg; | |
| 281 | offs_t nametbl_base; | |
| 282 | offs_t patterntbl_base[4]; | |
| 283 | int name_hi, name_lo; | |
| 284 | int pattern_ix; | |
| 285 | int alphanumeric_mode, dbl_w, dbl_h, dbl_w_phase = 0; | |
| 286 | ||
| 287 | nametbl_base = m_address_regs[2]; | |
| 288 | for (i = 0; i < 4; i++) | |
| 289 | patterntbl_base[i] = m_address_regs[i + 3]; | |
| 290 | ||
| 291 | for (xx = 0; xx < TMS3556_LEFT_BORDER; xx++) | |
| 292 | #if TMS3556_DOUBLE_WIDTH | |
| 293 | *ln++ = m_bg_color; | |
| 294 | #endif | |
| 295 | *ln++ = m_bg_color; | |
| 296 | ||
| 297 | name_offset = m_name_offset; | |
| 298 | ||
| 299 | for (x = 0; x < 40; x++) | |
| 300 | { | |
| 301 | name_hi = readbyte(nametbl_base + name_offset); | |
| 302 | name_lo = readbyte(nametbl_base + name_offset + 1); | |
| 303 | pattern_ix = ((name_hi >> 2) & 2) | ((name_hi >> 4) & 1); | |
| 304 | alphanumeric_mode = (pattern_ix < 2) || ((pattern_ix == 3) && !(m_control_regs[7] & 0x08)); | |
| 305 | fg = (name_hi >> 5) & 0x7; | |
| 306 | if (alphanumeric_mode) | |
| 307 | { | |
| 308 | if (name_hi & 4) | |
| 309 | { /* inverted color */ | |
| 310 | bg = fg; | |
| 311 | fg = m_bg_color; | |
| 312 | } | |
| 313 | else | |
| 314 | bg = m_bg_color; | |
| 315 | dbl_w = name_hi & 0x2; | |
| 316 | dbl_h = name_hi & 0x1; | |
| 317 | } | |
| 318 | else | |
| 319 | { | |
| 320 | bg = name_hi & 0x7; | |
| 321 | dbl_w = 0; | |
| 322 | dbl_h = 0; | |
| 323 | } | |
| 324 | if ((name_lo & 0x80) && m_blink) | |
| 325 | fg = bg; /* blink off time */ | |
| 326 | if (! dbl_h) | |
| 327 | { /* single height */ | |
| 328 | pattern = readbyte(patterntbl_base[pattern_ix] + (name_lo & 0x7f) + 128 * m_char_line_counter); | |
| 329 | if (m_char_line_counter == 0) | |
| 330 | m_dbl_h_phase[x] = 0; | |
| 331 | } | |
| 332 | else | |
| 333 | { /* double height */ | |
| 334 | if (! m_dbl_h_phase[x]) | |
| 335 | /* first phase: pattern from upper half */ | |
| 336 | pattern = readbyte(patterntbl_base[pattern_ix] + (name_lo & 0x7f) + 128 * (5 + (m_char_line_counter >> 1))); | |
| 337 | else | |
| 338 | /* second phase: pattern from lower half */ | |
| 339 | pattern = readbyte(patterntbl_base[pattern_ix] + (name_lo & 0x7f) + 128 * (m_char_line_counter >> 1)); | |
| 340 | if (m_char_line_counter == 0) | |
| 341 | m_dbl_h_phase[x] = !m_dbl_h_phase[x]; | |
| 342 | } | |
| 343 | if (!dbl_w) | |
| 344 | { /* single width */ | |
| 345 | for (xx = 0; xx < 8; xx++) | |
| 346 | { | |
| 347 | UINT16 color = (pattern & 0x80) ? fg : bg; | |
| 348 | #if TMS3556_DOUBLE_WIDTH | |
| 349 | *ln++ = color; | |
| 350 | #endif | |
| 351 | *ln++ = color; | |
| 352 | pattern <<= 1; | |
| 353 | } | |
| 354 | dbl_w_phase = 0; | |
| 355 | } | |
| 356 | else | |
| 357 | { /* double width */ | |
| 358 | if (dbl_w_phase) | |
| 359 | /* second phase: display right half */ | |
| 360 | pattern <<= 4; | |
| 361 | for (xx = 0; xx < 4; xx++) | |
| 362 | { | |
| 363 | UINT16 color = (pattern & 0x80) ? fg : bg; | |
| 364 | #if TMS3556_DOUBLE_WIDTH | |
| 365 | *ln++ = color; *ln++ = color; | |
| 366 | #endif | |
| 367 | *ln++ = color; *ln++ = color; | |
| 368 | pattern <<= 1; | |
| 369 | } | |
| 370 | dbl_w_phase = !dbl_w_phase; | |
| 371 | } | |
| 372 | name_offset += 2; | |
| 373 | } | |
| 374 | ||
| 375 | for (xx = 0; xx < TMS3556_RIGHT_BORDER; xx++) | |
| 376 | #if TMS3556_DOUBLE_WIDTH | |
| 377 | *ln++ = m_bg_color; | |
| 378 | #endif | |
| 379 | *ln++ = m_bg_color; | |
| 380 | ||
| 381 | if (m_char_line_counter == 0) | |
| 382 | m_name_offset = name_offset; | |
| 383 | } | |
| 384 | ||
| 385 | ||
| 386 | //------------------------------------------------- | |
| 387 | // draw_line_bitmap_common - draw a line of bitmap | |
| 388 | // (called by draw_line_bitmap and draw_line_mixed) | |
| 389 | //------------------------------------------------- | |
| 390 | ||
| 391 | void tms3556_device::draw_line_bitmap_common(UINT16 *ln) | |
| 392 | { | |
| 393 | int x, xx; | |
| 394 | offs_t nametbl_base; | |
| 395 | int name_b, name_g, name_r; | |
| 396 | ||
| 397 | nametbl_base = m_address_regs[2]; | |
| 398 | ||
| 399 | for (xx = 0; xx < TMS3556_LEFT_BORDER; xx++) | |
| 400 | #if TMS3556_DOUBLE_WIDTH | |
| 401 | *ln++ = m_bg_color; | |
| 402 | #endif | |
| 403 | *ln++ = m_bg_color; | |
| 404 | ||
| 405 | for (x = 0; x < 40; x++) | |
| 406 | { | |
| 407 | name_b = readbyte(nametbl_base + m_name_offset); | |
| 408 | name_g = readbyte(nametbl_base + m_name_offset + 1); | |
| 409 | name_r = readbyte(nametbl_base + m_name_offset + 2); | |
| 410 | for (xx = 0; xx < 8; xx++) | |
| 411 | { | |
| 412 | UINT16 color = ((name_b >> 5) & 0x4) | ((name_g >> 6) & 0x2) | ((name_r >> 7) & 0x1); | |
| 413 | #if TMS3556_DOUBLE_WIDTH | |
| 414 | *ln++ = color; | |
| 415 | #endif | |
| 416 | *ln++ = color; | |
| 417 | name_b <<= 1; | |
| 418 | name_g <<= 1; | |
| 419 | name_r <<= 1; | |
| 420 | } | |
| 421 | m_name_offset += 3; | |
| 422 | } | |
| 423 | ||
| 424 | for (xx = 0; xx < TMS3556_RIGHT_BORDER; xx++) | |
| 425 | #if TMS3556_DOUBLE_WIDTH | |
| 426 | *ln++ = m_bg_color; | |
| 427 | #endif | |
| 428 | *ln++ = m_bg_color; | |
| 429 | } | |
| 430 | ||
| 431 | ||
| 432 | //------------------------------------------------- | |
| 433 | // draw_line_text - draw a line in text mode | |
| 434 | //------------------------------------------------- | |
| 435 | ||
| 436 | void tms3556_device::draw_line_text(UINT16 *ln) | |
| 437 | { | |
| 438 | if (m_char_line_counter == 0) | |
| 439 | m_char_line_counter = 10; | |
| 440 | m_char_line_counter--; | |
| 441 | draw_line_text_common(ln); | |
| 442 | } | |
| 443 | ||
| 444 | ||
| 445 | //------------------------------------------------- | |
| 446 | // draw_line_bitmap - draw a line in bitmap mode | |
| 447 | //------------------------------------------------- | |
| 448 | ||
| 449 | void tms3556_device::draw_line_bitmap(UINT16 *ln) | |
| 450 | { | |
| 451 | draw_line_bitmap_common(ln); | |
| 452 | m_bg_color = (readbyte(m_address_regs[2] + m_name_offset) >> 5) & 0x7; | |
| 453 | m_name_offset += 2; | |
| 454 | } | |
| 455 | ||
| 456 | ||
| 457 | //------------------------------------------------- | |
| 458 | // draw_line_mixed - draw a line in mixed mode | |
| 459 | //------------------------------------------------- | |
| 460 | ||
| 461 | void tms3556_device::draw_line_mixed(UINT16 *ln) | |
| 462 | { | |
| 463 | if (m_cg_flag) | |
| 464 | { /* bitmap line */ | |
| 465 | draw_line_bitmap_common(ln); | |
| 466 | m_bg_color = (readbyte(m_address_regs[2] + m_name_offset) >> 5) & 0x7; | |
| 467 | m_cg_flag = (readbyte(m_address_regs[2] + m_name_offset) >> 4) & 0x1; | |
| 468 | m_name_offset += 2; | |
| 469 | } | |
| 470 | else | |
| 471 | { /* text line */ | |
| 472 | if (m_char_line_counter == 0) | |
| 473 | m_char_line_counter = 10; | |
| 474 | m_char_line_counter--; | |
| 475 | draw_line_text_common(ln); | |
| 476 | if (m_char_line_counter == 0) | |
| 477 | { | |
| 478 | m_bg_color = (readbyte(m_address_regs[2] + m_name_offset) >> 5) & 0x7; | |
| 479 | m_cg_flag = (readbyte(m_address_regs[2] + m_name_offset) >> 4) & 0x1; | |
| 480 | m_name_offset += 2; | |
| 481 | } | |
| 482 | } | |
| 483 | } | |
| 484 | ||
| 485 | ||
| 486 | //------------------------------------------------- | |
| 487 | // draw_line - draw a line. If non-interlaced mode, | |
| 488 | // duplicate the line. | |
| 489 | //------------------------------------------------- | |
| 490 | ||
| 491 | void tms3556_device::draw_line(bitmap_ind16 &bmp, int line) | |
| 492 | { | |
| 493 | int double_lines = 0; | |
| 494 | UINT16 *ln, *ln2 = NULL; | |
| 495 | ||
| 496 | // if (m_control_regs[4] & 0x??) | |
| 497 | // { // interlaced mode | |
| 498 | // ln = &bmp->pix16(line, m_field); | |
| 499 | // } | |
| 500 | // else | |
| 501 | { /* non-interlaced mode */ | |
| 502 | ln = &bmp.pix16(line); | |
| 503 | ln2 = &bmp.pix16(line, 1); | |
| 504 | double_lines = 1; | |
| 505 | } | |
| 506 | ||
| 507 | if ((line < TMS3556_TOP_BORDER) || (line >= (TMS3556_TOP_BORDER + 250))) | |
| 508 | { | |
| 509 | /* draw top and bottom borders */ | |
| 510 | draw_line_empty(ln); | |
| 511 | } | |
| 512 | else | |
| 513 | { | |
| 514 | /* draw useful area */ | |
| 515 | switch (m_control_regs[6] >> 6) | |
| 516 | { | |
| 517 | case TMS3556_MODE_OFF: | |
| 518 | draw_line_empty(ln); | |
| 519 | break; | |
| 520 | case TMS3556_MODE_TEXT: | |
| 521 | draw_line_text(ln); | |
| 522 | break; | |
| 523 | case TMS3556_MODE_BITMAP: | |
| 524 | draw_line_bitmap(ln); | |
| 525 | break; | |
| 526 | case TMS3556_MODE_MIXED: | |
| 527 | draw_line_mixed(ln); | |
| 528 | break; | |
| 529 | } | |
| 530 | } | |
| 531 | ||
| 532 | if (double_lines) | |
| 533 | { | |
| 534 | memcpy (ln2, ln, TMS3556_TOTAL_WIDTH * (TMS3556_DOUBLE_WIDTH ? 2 : 1)); | |
| 535 | } | |
| 536 | } | |
| 537 | ||
| 538 | ||
| 539 | //------------------------------------------------- | |
| 540 | // interrupt_start_vblank - Do vblank-time tasks | |
| 541 | //------------------------------------------------- | |
| 542 | ||
| 543 | void tms3556_device::interrupt_start_vblank(void) | |
| 544 | { | |
| 545 | /* at every frame, vdp switches fields */ | |
| 546 | //m_field = !m_field; | |
| 547 | ||
| 548 | /* color blinking */ | |
| 549 | if (m_blink_count) | |
| 550 | m_blink_count--; | |
| 551 | if (!m_blink_count) | |
| 552 | { | |
| 553 | m_blink = !m_blink; | |
| 554 | m_blink_count = 60; /*no idea what the real value is*/ | |
| 555 | } | |
| 556 | /* reset background color */ | |
| 557 | m_bg_color = (m_control_regs[7] >> 5) & 0x7; | |
| 558 | /* reset name offset */ | |
| 559 | m_name_offset = 0; | |
| 560 | /* reset character line counter */ | |
| 561 | m_char_line_counter = 0; | |
| 562 | /* reset c/g flag */ | |
| 563 | m_cg_flag = 0; | |
| 564 | /* reset double height phase flags */ | |
| 565 | memset(m_dbl_h_phase, 0, sizeof(m_dbl_h_phase)); | |
| 566 | } | |
| 567 | ||
| 568 | ||
| 569 | //------------------------------------------------- | |
| 570 | // interrupt - scanline handler | |
| 571 | //------------------------------------------------- | |
| 572 | ||
| 573 | void tms3556_device::interrupt(running_machine &machine) | |
| 574 | { | |
| 575 | /* check for start of vblank */ | |
| 576 | if (m_scanline == 310) /*no idea what the real value is*/ | |
| 577 | interrupt_start_vblank(); | |
| 578 | ||
| 579 | /* render the current line */ | |
| 580 | if ((m_scanline >= 0) && (m_scanline < TMS3556_TOTAL_HEIGHT)) | |
| 581 | { | |
| 582 | //if (!video_skip_this_frame()) | |
| 583 | draw_line(m_bitmap, m_scanline); | |
| 584 | } | |
| 585 | ||
| 586 | if (++m_scanline == 313) | |
| 587 | m_scanline = 0; | |
| 588 | } |
| r21684 | r21685 | |
|---|---|---|
| 1 | /********************************************************************* | |
| 2 | ||
| 3 | mc6847.c | |
| 4 | ||
| 5 | Implementation of Motorola 6847 video hardware chip | |
| 6 | ||
| 7 | Sources: | |
| 8 | M6847 data sheet | |
| 9 | M6847T1 info from Rainbow magazine (10/1986-12/1986) | |
| 10 | ||
| 11 | ||
| 12 | AG AS INTEXT INV GM2 GM1 GM0 | |
| 13 | -- -- ------ --- --- --- --- | |
| 14 | 0 0 0 0 X X X Internal Alphanumerics | |
| 15 | 0 0 0 1 X X X Internal Alphanumerics Inverted | |
| 16 | 0 0 1 0 X X X External Alphanumerics | |
| 17 | 0 0 1 1 X X X External Alphanumerics Inverted | |
| 18 | 0 1 0 X X X X Semigraphics 4 | |
| 19 | 0 1 1 X X X X Semigraphics 6 | |
| 20 | 1 X X X 0 0 0 Graphics CG1 (64x64x4) (16 bpr) | |
| 21 | 1 X X X 0 0 1 Graphics RG1 (128x64x2) (16 bpr) | |
| 22 | 1 X X X 0 1 0 Graphics CG2 (128x64x4) (32 bpr) | |
| 23 | 1 X X X 0 1 1 Graphics RG2 (128x96x2) (16 bpr) | |
| 24 | 1 X X X 1 0 0 Graphics CG3 (128x96x4) (32 bpr) | |
| 25 | 1 X X X 1 0 1 Graphics RG3 (128x192x2) (16 bpr) | |
| 26 | 1 X X X 1 1 0 Graphics CG6 (128x192x4) (32 bpr) | |
| 27 | 1 X X X 1 1 1 Graphics RG6 (256x192x2) (32 bpr) | |
| 28 | ||
| 29 | Note: The M6847 relies on an external source (typically a 6883 SAM chip) | |
| 30 | to feed it bytes; so the BPR (bytes per row) figures are effectively | |
| 31 | suggestions. Mismatching modes is responsible for the semigraphic modes | |
| 32 | on the CoCo. | |
| 33 | ||
| 34 | Timing: (source Motorola M6847 Manual, experimentation, SockMaster) | |
| 35 | ||
| 36 | Horizontal Sync: Total Period: 228 clock cycles | |
| 37 | @ CLK(0) + DHS_F - falling edge (high to low) | |
| 38 | @ CLK(16.5) + DHS_R - rising edge (low to high) | |
| 39 | @ CLK(42) - left border start | |
| 40 | @ CLK(71.5) - body start | |
| 41 | @ CLK(199.5) - right border start | |
| 42 | @ CLK(228) + DHS_F - falling edge (high to low) | |
| 43 | ... | |
| 44 | ||
| 45 | Field Sync: Total Period 262*228 clock cycles | |
| 46 | @ CLK(0) + DFS_F - falling edge (high to low) | |
| 47 | @ CLK(32*228) + DFS_R - rising edge (low to high) | |
| 48 | @ CLK(262*228) + DFS_F - falling edge (high to low) (262.5 for the M6847Y) | |
| 49 | ||
| 50 | DHS_F: 550ns | |
| 51 | DHS_R: 740ns | |
| 52 | DFS_F: 520ns | |
| 53 | DFS_R: 500ns | |
| 54 | ||
| 55 | The M6847T1 is a later variant of the M6847 chip that implements lower | |
| 56 | case support and some other nifty features. This chip is in the CoCo 2B. | |
| 57 | I have not been able to find a pinout diagram for this chip so I am | |
| 58 | assuming that the extra text modes on the CoCo 2B are activated by the | |
| 59 | GM2-0 pins. This needs to be confirmed. | |
| 60 | ||
| 61 | The MC6847 datasheet states that a scanline is 227.5 clock cycles, | |
| 62 | but experimentation suggests that it is 228. The game "Dragon Fire" | |
| 63 | has a fine tuned loop that runs in 57 clock cycles by the CPU's | |
| 64 | reckoning (228 actual clock cycles) and would not function correctly | |
| 65 | if skew existed. SockMaster has confirmed that scanlines are in | |
| 66 | fact 228 clock cycles. | |
| 67 | ||
| 68 | **********************************************************************/ | |
| 69 | ||
| 70 | ||
| 71 | #include "emu.h" | |
| 72 | #include "video/mc6847.h" | |
| 73 | ||
| 74 | ||
| 75 | //************************************************************************** | |
| 76 | // CONSTANTS | |
| 77 | //************************************************************************** | |
| 78 | ||
| 79 | #define TOP_BORDER 25 | |
| 80 | #define USE_HORIZONTAL_CLIP false | |
| 81 | ||
| 82 | #define TIMER_HSYNC_PERIOD (228) | |
| 83 | #define TIMER_HSYNC_OFF_TIME (10.0) | |
| 84 | #define TIMER_HSYNC_ON_TIME (TIMER_HSYNC_OFF_TIME + 16.5) | |
| 85 | #define TIMER_FSYNC_OFF_TIME (TIMER_HSYNC_PERIOD * TOP_BORDER + TIMER_HSYNC_ON_TIME) | |
| 86 | #define TIMER_FSYNC_ON_TIME (TIMER_HSYNC_PERIOD * (TOP_BORDER + 192) + TIMER_HSYNC_ON_TIME) | |
| 87 | ||
| 88 | #define LOG_SCANLINE 0 | |
| 89 | #define LOG_HSYNC 0 | |
| 90 | #define LOG_FSYNC 1 | |
| 91 | #define LOG_FLUSH 1 | |
| 92 | #define LOG_INPUT 0 | |
| 93 | ||
| 94 | ||
| 95 | const UINT32 mc6847_base_device::s_palette[mc6847_base_device::PALETTE_LENGTH] = | |
| 96 | { | |
| 97 | MAKE_RGB(0x07, 0xff, 0x00), /* GREEN */ | |
| 98 | MAKE_RGB(0xff, 0xff, 0x00), /* YELLOW */ | |
| 99 | MAKE_RGB(0x3b, 0x08, 0xff), /* BLUE */ | |
| 100 | MAKE_RGB(0xcc, 0x00, 0x3b), /* RED */ | |
| 101 | MAKE_RGB(0xff, 0xff, 0xff), /* BUFF */ | |
| 102 | MAKE_RGB(0x07, 0xe3, 0x99), /* CYAN */ | |
| 103 | MAKE_RGB(0xff, 0x1c, 0xff), /* MAGENTA */ | |
| 104 | MAKE_RGB(0xff, 0x81, 0x00), /* ORANGE */ | |
| 105 | ||
| 106 | MAKE_RGB(0x00, 0x00, 0x00), /* BLACK */ | |
| 107 | MAKE_RGB(0x07, 0xff, 0x00), /* GREEN */ | |
| 108 | MAKE_RGB(0x00, 0x00, 0x00), /* BLACK */ | |
| 109 | MAKE_RGB(0xff, 0xff, 0xff), /* BUFF */ | |
| 110 | ||
| 111 | MAKE_RGB(0x00, 0x7c, 0x00), /* ALPHANUMERIC DARK GREEN */ | |
| 112 | MAKE_RGB(0x07, 0xff, 0x00), /* ALPHANUMERIC BRIGHT GREEN */ | |
| 113 | MAKE_RGB(0x91, 0x00, 0x00), /* ALPHANUMERIC DARK ORANGE */ | |
| 114 | MAKE_RGB(0xff, 0x81, 0x00) /* ALPHANUMERIC BRIGHT ORANGE */ | |
| 115 | }; | |
| 116 | ||
| 117 | ||
| 118 | ||
| 119 | //************************************************************************** | |
| 120 | // FRIEND DEVICE | |
| 121 | //************************************************************************** | |
| 122 | ||
| 123 | //------------------------------------------------- | |
| 124 | // ctor | |
| 125 | //------------------------------------------------- | |
| 126 | ||
| 127 | mc6847_friend_device::mc6847_friend_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, | |
| 128 | const UINT8 *fontdata, bool is_mc6847t1, double tpfs, int field_sync_falling_edge_scanline, bool supports_partial_body_scanlines) | |
| 129 | : device_t(mconfig, type, name, tag, owner, clock), | |
| 130 | m_character_map(fontdata, is_mc6847t1) | |
| 131 | { | |
| 132 | m_tpfs = tpfs; | |
| 133 | m_supports_partial_body_scanlines = supports_partial_body_scanlines; | |
| 134 | ||
| 135 | // The MC6847 and the GIME apply field sync on different scanlines | |
| 136 | m_field_sync_falling_edge_scanline = field_sync_falling_edge_scanline; | |
| 137 | } | |
| 138 | ||
| 139 | ||
| 140 | ||
| 141 | //------------------------------------------------- | |
| 142 | // setup_timer - sets up a single timer relative | |
| 143 | // to the clock | |
| 144 | //------------------------------------------------- | |
| 145 | ||
| 146 | ATTR_FORCE_INLINE emu_timer *mc6847_friend_device::setup_timer(device_timer_id id, double offset, double period) | |
| 147 | { | |
| 148 | emu_timer *timer = timer_alloc(id); | |
| 149 | timer->adjust( | |
| 150 | attotime::from_ticks(offset * 4, m_clock * 4), | |
| 151 | 0, | |
| 152 | attotime::from_ticks(period * 4, m_clock * 4)); | |
| 153 | return timer; | |
| 154 | } | |
| 155 | ||
| 156 | ||
| 157 | ||
| 158 | //------------------------------------------------- | |
| 159 | // device_start - device-specific startup | |
| 160 | //------------------------------------------------- | |
| 161 | ||
| 162 | void mc6847_friend_device::device_start(void) | |
| 163 | { | |
| 164 | /* create the timers */ | |
| 165 | m_frame_timer = setup_timer( TIMER_FRAME, 0, m_tpfs * TIMER_HSYNC_PERIOD); | |
| 166 | m_hsync_on_timer = setup_timer( TIMER_HSYNC_ON, TIMER_HSYNC_ON_TIME, TIMER_HSYNC_PERIOD); | |
| 167 | m_hsync_off_timer = setup_timer(TIMER_HSYNC_OFF, TIMER_HSYNC_OFF_TIME, TIMER_HSYNC_PERIOD); | |
| 168 | m_fsync_timer = timer_alloc(TIMER_FSYNC); | |
| 169 | ||
| 170 | m_top_border_scanlines = 0; | |
| 171 | m_body_scanlines = 0; | |
| 172 | m_wide = false; | |
| 173 | m_recording_scanline = false; | |
| 174 | m_physical_scanline = 0; | |
| 175 | m_logical_scanline_zone = 0; | |
| 176 | m_field_sync = false; | |
| 177 | m_horizontal_sync = false; | |
| 178 | set_geometry(25, 192, false); | |
| 179 | ||
| 180 | /* save states */ | |
| 181 | save_item(NAME(m_physical_scanline)); | |
| 182 | save_item(NAME(m_logical_scanline)); | |
| 183 | save_item(NAME(m_logical_scanline_zone)); | |
| 184 | save_item(NAME(m_horizontal_sync)); | |
| 185 | save_item(NAME(m_field_sync)); | |
| 186 | ||
| 187 | /* artifacting */ | |
| 188 | m_artifacter.setup_config(this); | |
| 189 | } | |
| 190 | ||
| 191 | ||
| 192 | ||
| 193 | //------------------------------------------------- | |
| 194 | // device_start - device-specific reset | |
| 195 | //------------------------------------------------- | |
| 196 | ||
| 197 | void mc6847_friend_device::device_reset(void) | |
| 198 | { | |
| 199 | device_t::device_reset(); | |
| 200 | m_video_changed = true; | |
| 201 | } | |
| 202 | ||
| 203 | ||
| 204 | ||
| 205 | //------------------------------------------------- | |
| 206 | // device_post_load - device-specific post load | |
| 207 | //------------------------------------------------- | |
| 208 | ||
| 209 | void mc6847_friend_device::device_post_load(void) | |
| 210 | { | |
| 211 | device_t::device_post_load(); | |
| 212 | m_video_changed = true; | |
| 213 | } | |
| 214 | ||
| 215 | ||
| 216 | ||
| 217 | //------------------------------------------------- | |
| 218 | // update_field_sync_timer | |
| 219 | //------------------------------------------------- | |
| 220 | ||
| 221 | void mc6847_friend_device::update_field_sync_timer(void) | |
| 222 | { | |
| 223 | /* are we expecting field sync? */ | |
| 224 | bool expected_field_sync = (m_physical_scanline < m_field_sync_falling_edge_scanline) | |
| 225 | || (m_logical_scanline_zone == SCANLINE_ZONE_VBLANK); | |
| 226 | ||
| 227 | /* determine the duration */ | |
| 228 | attotime duration = (expected_field_sync != m_field_sync) ? attotime::from_ticks(160, m_clock) : attotime::never; | |
| 229 | ||
| 230 | /* and reset the timer */ | |
| 231 | m_fsync_timer->adjust(duration, expected_field_sync ? 1 : 0); | |
| 232 | } | |
| 233 | ||
| 234 | ||
| 235 | ||
| 236 | //------------------------------------------------- | |
| 237 | // device_timer | |
| 238 | //------------------------------------------------- | |
| 239 | ||
| 240 | void mc6847_friend_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) | |
| 241 | { | |
| 242 | switch(id) | |
| 243 | { | |
| 244 | case TIMER_FRAME: new_frame(); break; | |
| 245 | case TIMER_HSYNC_ON: change_horizontal_sync(true); break; | |
| 246 | case TIMER_HSYNC_OFF: change_horizontal_sync(false); break; | |
| 247 | case TIMER_FSYNC: change_field_sync(param != 0); break; | |
| 248 | } | |
| 249 | } | |
| 250 | ||
| 251 | ||
| 252 | ||
| 253 | //------------------------------------------------- | |
| 254 | // new_frame | |
| 255 | //------------------------------------------------- | |
| 256 | ||
| 257 | ATTR_FORCE_INLINE void mc6847_friend_device::new_frame(void) | |
| 258 | { | |
| 259 | m_physical_scanline = 0; | |
| 260 | m_logical_scanline = 0; | |
| 261 | m_logical_scanline_zone = SCANLINE_ZONE_FRAME_END; | |
| 262 | } | |
| 263 | ||
| 264 | ||
| 265 | ||
| 266 | //------------------------------------------------- | |
| 267 | // scanline_zone_string | |
| 268 | //------------------------------------------------- | |
| 269 | ||
| 270 | const char *mc6847_friend_device::scanline_zone_string(scanline_zone zone) | |
| 271 | { | |
| 272 | const char *result; | |
| 273 | switch(zone) | |
| 274 | { | |
| 275 | case SCANLINE_ZONE_TOP_BORDER: result = "SCANLINE_ZONE_TOP_BORDER"; break; | |
| 276 | case SCANLINE_ZONE_BODY: result = "SCANLINE_ZONE_BODY"; break; | |
| 277 | case SCANLINE_ZONE_BOTTOM_BORDER: result = "SCANLINE_ZONE_BOTTOM_BORDER"; break; | |
| 278 | case SCANLINE_ZONE_RETRACE: result = "SCANLINE_ZONE_RETRACE"; break; | |
| 279 | case SCANLINE_ZONE_VBLANK: result = "SCANLINE_ZONE_VBLANK"; break; | |
| 280 | case SCANLINE_ZONE_FRAME_END: result = "SCANLINE_ZONE_FRAME_END"; break; | |
| 281 | default: | |
| 282 | fatalerror("Should not get here\n"); | |
| 283 | break; | |
| 284 | } | |
| 285 | return result; | |
| 286 | } | |
| 287 | ||
| 288 | ||
| 289 | ||
| 290 | //------------------------------------------------- | |
| 291 | // change_horizontal_sync | |
| 292 | //------------------------------------------------- | |
| 293 | ||
| 294 | ATTR_FORCE_INLINE void mc6847_friend_device::change_horizontal_sync(bool line) | |
| 295 | { | |
| 296 | g_profiler.start(PROFILER_USER1); | |
| 297 | if (line && !m_horizontal_sync) | |
| 298 | { | |
| 299 | if (LOG_SCANLINE) | |
| 300 | logerror("%s: change_horizontal_sync(): Recording scanline\n", describe_context()); | |
| 301 | ||
| 302 | /* first store the scanline */ | |
| 303 | g_profiler.start(PROFILER_USER2); | |
| 304 | switch((scanline_zone) m_logical_scanline_zone) | |
| 305 | { | |
| 306 | case SCANLINE_ZONE_TOP_BORDER: | |
| 307 | case SCANLINE_ZONE_BOTTOM_BORDER: | |
| 308 | record_border_scanline(m_physical_scanline); | |
| 309 | break; | |
| 310 | ||
| 311 | case SCANLINE_ZONE_BODY: | |
| 312 | m_recording_scanline = true; | |
| 313 | if (m_partial_scanline_clocks > 0) | |
| 314 | record_partial_body_scanline(m_physical_scanline, m_logical_scanline, m_partial_scanline_clocks, 228); | |
| 315 | else | |
| 316 | record_body_scanline(m_physical_scanline, m_logical_scanline); | |
| 317 | m_recording_scanline = false; | |
| 318 | break; | |
| 319 | ||
| 320 | case SCANLINE_ZONE_RETRACE: | |
| 321 | case SCANLINE_ZONE_VBLANK: | |
| 322 | case SCANLINE_ZONE_FRAME_END: | |
| 323 | /* do nothing */ | |
| 324 | break; | |
| 325 | } | |
| 326 | g_profiler.stop(); | |
| 327 | ||
| 328 | /* advance to next scanline */ | |
| 329 | next_scanline(); | |
| 330 | } | |
| 331 | ||
| 332 | /* finally output horizontal sync */ | |
| 333 | if (line != m_horizontal_sync) | |
| 334 | { | |
| 335 | m_horizontal_sync = line; | |
| 336 | ||
| 337 | /* log if apprpriate */ | |
| 338 | if (LOG_HSYNC) | |
| 339 | logerror("%s: change_horizontal_sync(): line=%d\n", describe_context(), line ? 1 : 0); | |
| 340 | ||
| 341 | /* invoke callback */ | |
| 342 | if (!m_res_out_hsync_func.isnull()) | |
| 343 | m_res_out_hsync_func(line); | |
| 344 | ||
| 345 | /* call virtual function */ | |
| 346 | horizontal_sync_changed(m_horizontal_sync); | |
| 347 | } | |
| 348 | ||
| 349 | /* and update the field sync timer */ | |
| 350 | update_field_sync_timer(); | |
| 351 | g_profiler.stop(); | |
| 352 | } | |
| 353 | ||
| 354 | ||
| 355 | ||
| 356 | //------------------------------------------------- | |
| 357 | // change_field_sync | |
| 358 | //------------------------------------------------- | |
| 359 | ||
| 360 | ATTR_FORCE_INLINE void mc6847_friend_device::change_field_sync(bool line) | |
| 361 | { | |
| 362 | /* output field sync */ | |
| 363 | if (line != m_field_sync) | |
| 364 | { | |
| 365 | m_field_sync = line; | |
| 366 | ||
| 367 | /* log if apprpriate */ | |
| 368 | if (LOG_FSYNC) | |
| 369 | logerror("%s: change_field_sync(): line=%d\n", describe_context(), line ? 1 : 0); | |
| 370 | ||
| 371 | /* invoke callback */ | |
| 372 | if (!m_res_out_fsync_func.isnull()) | |
| 373 | m_res_out_fsync_func(line); | |
| 374 | ||
| 375 | /* call virtual function */ | |
| 376 | field_sync_changed(m_field_sync); | |
| 377 | } | |
| 378 | } | |
| 379 | ||
| 380 | ||
| 381 | ||
| 382 | //------------------------------------------------- | |
| 383 | // next_scanline | |
| 384 | //------------------------------------------------- | |
| 385 | ||
| 386 | ATTR_FORCE_INLINE void mc6847_friend_device::next_scanline(void) | |
| 387 | { | |
| 388 | /* advance to next scanline */ | |
| 389 | m_physical_scanline++; | |
| 390 | m_logical_scanline++; | |
| 391 | m_partial_scanline_clocks = 0; | |
| 392 | ||
| 393 | /* check for movement into the next "zone" */ | |
| 394 | if (m_logical_scanline_zone == SCANLINE_ZONE_FRAME_END) | |
| 395 | { | |
| 396 | /* we're now in the top border */ | |
| 397 | m_logical_scanline = 0; | |
| 398 | m_logical_scanline_zone = SCANLINE_ZONE_TOP_BORDER; | |
| 399 | } | |
| 400 | else if ((m_logical_scanline_zone < SCANLINE_ZONE_VBLANK) && (m_physical_scanline >= 25+192+26+6)) | |
| 401 | { | |
| 402 | /* we're now into vblank */ | |
| 403 | m_logical_scanline = 0; | |
| 404 | m_logical_scanline_zone = SCANLINE_ZONE_VBLANK; | |
| 405 | } | |
| 406 | else if ((m_logical_scanline_zone < SCANLINE_ZONE_RETRACE) && (m_physical_scanline >= 25+192+26)) | |
| 407 | { | |
| 408 | /* we're now into retrace */ | |
| 409 | m_logical_scanline = 0; | |
| 410 | m_logical_scanline_zone = SCANLINE_ZONE_RETRACE; | |
| 411 | } | |
| 412 | else if ((m_logical_scanline_zone == SCANLINE_ZONE_TOP_BORDER) && (m_logical_scanline >= m_top_border_scanlines)) | |
| 413 | { | |
| 414 | /* we're now into the body */ | |
| 415 | m_logical_scanline = 0; | |
| 416 | m_logical_scanline_zone = SCANLINE_ZONE_BODY; | |
| 417 | } | |
| 418 | else if ((m_logical_scanline_zone == SCANLINE_ZONE_BODY) && (m_logical_scanline >= m_body_scanlines)) | |
| 419 | { | |
| 420 | /* we're now into the bottom border */ | |
| 421 | m_logical_scanline = 0; | |
| 422 | m_logical_scanline_zone = SCANLINE_ZONE_BOTTOM_BORDER; | |
| 423 | enter_bottom_border(); | |
| 424 | } | |
| 425 | } | |
| 426 | ||
| 427 | ||
| 428 | ||
| 429 | //------------------------------------------------- | |
| 430 | // horizontal_sync_changed | |
| 431 | //------------------------------------------------- | |
| 432 | ||
| 433 | void mc6847_friend_device::horizontal_sync_changed(bool line) | |
| 434 | { | |
| 435 | } | |
| 436 | ||
| 437 | ||
| 438 | ||
| 439 | //------------------------------------------------- | |
| 440 | // field_sync_changed | |
| 441 | //------------------------------------------------- | |
| 442 | ||
| 443 | void mc6847_friend_device::field_sync_changed(bool line) | |
| 444 | { | |
| 445 | } | |
| 446 | ||
| 447 | ||
| 448 | ||
| 449 | //------------------------------------------------- | |
| 450 | // enter_bottom_border | |
| 451 | //------------------------------------------------- | |
| 452 | ||
| 453 | void mc6847_friend_device::enter_bottom_border(void) | |
| 454 | { | |
| 455 | } | |
| 456 | ||
| 457 | ||
| 458 | ||
| 459 | //------------------------------------------------- | |
| 460 | // record_border_scanline | |
| 461 | //------------------------------------------------- | |
| 462 | ||
| 463 | void mc6847_friend_device::record_border_scanline(UINT16 physical_scanline) | |
| 464 | { | |
| 465 | } | |
| 466 | ||
| 467 | ||
| 468 | ||
| 469 | //------------------------------------------------- | |
| 470 | // get_clocks_since_hsync | |
| 471 | //------------------------------------------------- | |
| 472 | ||
| 473 | INT32 mc6847_friend_device::get_clocks_since_hsync() | |
| 474 | { | |
| 475 | UINT64 hsync_on_clocks = attotime_to_clocks(m_hsync_on_timer->start()); | |
| 476 | UINT64 current_clocks = attotime_to_clocks(machine().time()); | |
| 477 | return (INT32) (current_clocks - hsync_on_clocks); | |
| 478 | } | |
| 479 | ||
| 480 | ||
| 481 | ||
| 482 | //------------------------------------------------- | |
| 483 | // video_flush | |
| 484 | //------------------------------------------------- | |
| 485 | ||
| 486 | void mc6847_friend_device::video_flush() | |
| 487 | { | |
| 488 | // first, only flush if... | |
| 489 | // 1. We support partial scanlines | |
| 490 | // 2. We're not already recording | |
| 491 | // 3. We're in the body | |
| 492 | if (m_supports_partial_body_scanlines && !m_recording_scanline && (m_logical_scanline_zone == SCANLINE_ZONE_BODY)) | |
| 493 | { | |
| 494 | UINT32 new_partial_scanline_clocks = get_clocks_since_hsync(); | |
| 495 | if (m_partial_scanline_clocks < new_partial_scanline_clocks) | |
| 496 | { | |
| 497 | if (LOG_FLUSH) | |
| 498 | logerror("%s: new_partial_scanline_clocks=%u\n", describe_context(), new_partial_scanline_clocks); | |
| 499 | ||
| 500 | m_recording_scanline = true; | |
| 501 | record_partial_body_scanline(m_physical_scanline, m_logical_scanline, m_partial_scanline_clocks, new_partial_scanline_clocks); | |
| 502 | m_recording_scanline = false; | |
| 503 | ||
| 504 | m_partial_scanline_clocks = new_partial_scanline_clocks; | |
| 505 | } | |
| 506 | } | |
| 507 | } | |
| 508 | ||
| 509 | ||
| 510 | ||
| 511 | //------------------------------------------------- | |
| 512 | // describe_context | |
| 513 | //------------------------------------------------- | |
| 514 | ||
| 515 | const char *mc6847_friend_device::describe_context(void) | |
| 516 | { | |
| 517 | static char buffer[128]; | |
| 518 | snprintf(buffer, ARRAY_LENGTH(buffer), "%s (scanline %s:%d)", | |
| 519 | machine().describe_context(), | |
| 520 | scanline_zone_string((scanline_zone) m_logical_scanline_zone), | |
| 521 | m_logical_scanline); | |
| 522 | return buffer; | |
| 523 | } | |
| 524 | ||
| 525 | ||
| 526 | ||
| 527 | //************************************************************************** | |
| 528 | // BASE DEVICE | |
| 529 | //************************************************************************** | |
| 530 | ||
| 531 | //------------------------------------------------- | |
| 532 | // ctor | |
| 533 | //------------------------------------------------- | |
| 534 | ||
| 535 | mc6847_base_device::mc6847_base_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const UINT8 *fontdata, double tpfs) | |
| 536 | : mc6847_friend_device(mconfig, type, name, tag, owner, clock, fontdata, (type == MC6847T1_NTSC) || (type == MC6847T1_PAL), tpfs, 25+191, true) | |
| 537 | { | |
| 538 | m_palette = s_palette; | |
| 539 | ||
| 540 | for (int i = 0; i < ARRAY_LENGTH(s_palette); i++) | |
| 541 | { | |
| 542 | m_bw_palette[i] = black_and_white(s_palette[i]); | |
| 543 | } | |
| 544 | } | |
| 545 | ||
| 546 | ||
| 547 | ||
| 548 | //------------------------------------------------- | |
| 549 | // setup_fixed_mode - sets up a particular video | |
| 550 | // mode bit with a decb callback | |
| 551 | //------------------------------------------------- | |
| 552 | ||
| 553 | void mc6847_base_device::setup_fixed_mode(struct devcb_read_line callback, UINT8 mode) | |
| 554 | { | |
| 555 | if (callback.type == DEVCB_TYPE_NULL) | |
| 556 | { | |
| 557 | // do nothing | |
| 558 | } | |
| 559 | else if (callback.type == DEVCB_TYPE_CONSTANT && (callback.index == 0 || callback.index == 1)) | |
| 560 | { | |
| 561 | // this mode is fixed | |
| 562 | m_fixed_mode |= (callback.index ? mode : 0x00); | |
| 563 | m_fixed_mode_mask |= mode; | |
| 564 | } | |
| 565 | else | |
| 566 | { | |
| 567 | // for reasons of performance, we currently only support DEVCB_NULL, | |
| 568 | // DEVCB_LINE_GND and DEVCB_LINE_VCC | |
| 569 | emu_fatalerror("mc6847 does not support this callback type for mode bits\n"); | |
| 570 | } | |
| 571 | } | |
| 572 | ||
| 573 | ||
| 574 | ||
| 575 | //------------------------------------------------- | |
| 576 | // device_start - device-specific startup | |
| 577 | //------------------------------------------------- | |
| 578 | ||
| 579 | void mc6847_base_device::device_start() | |
| 580 | { | |
| 581 | const mc6847_interface *config = (const mc6847_interface *) static_config(); | |
| 582 | assert(config); | |
| 583 | ||
| 584 | /* inherited function */ | |
| 585 | mc6847_friend_device::device_start(); | |
| 586 | ||
| 587 | /* setup */ | |
| 588 | memset(m_data, 0, sizeof(m_data)); | |
| 589 | ||
| 590 | /* resolve callbacks */ | |
| 591 | m_res_input_func.resolve(config->m_input_func, *this); | |
| 592 | m_res_out_hsync_func.resolve(config->m_out_hsync_func, *this); | |
| 593 | m_res_out_fsync_func.resolve(config->m_out_fsync_func, *this); | |
| 594 | m_get_char_rom = config->m_get_char_rom; | |
| 595 | ||
| 596 | /* set up fixed mode */ | |
| 597 | m_fixed_mode = 0x00; | |
| 598 | m_fixed_mode_mask = 0x00; | |
| 599 | setup_fixed_mode(config->m_in_gm2_func, MODE_GM2); | |
| 600 | setup_fixed_mode(config->m_in_gm1_func, MODE_GM1); | |
| 601 | setup_fixed_mode(config->m_in_gm0_func, MODE_GM0); | |
| 602 | setup_fixed_mode(config->m_in_intext_func, MODE_INTEXT); | |
| 603 | setup_fixed_mode(config->m_in_inv_func, MODE_INV); | |
| 604 | setup_fixed_mode(config->m_in_as_func, MODE_AS); | |
| 605 | setup_fixed_mode(config->m_in_ag_func, MODE_AG); | |
| 606 | setup_fixed_mode(config->m_in_css_func, MODE_CSS); | |
| 607 | ||
| 608 | m_dirty = false; | |
| 609 | ||
| 610 | /* state save */ | |
| 611 | save_item(NAME(m_dirty)); | |
| 612 | save_item(NAME(m_mode)); | |
| 613 | ||
| 614 | /* colors */ | |
| 615 | m_palette = config->m_black_and_white ? m_bw_palette : s_palette; | |
| 616 | } | |
| 617 | ||
| 618 | ||
| 619 | ||
| 620 | //------------------------------------------------- | |
| 621 | // device_reset - device-specific reset | |
| 622 | //------------------------------------------------- | |
| 623 | ||
| 624 | void mc6847_base_device::device_reset() | |
| 625 | { | |
| 626 | mc6847_friend_device::device_reset(); | |
| 627 | m_mode = m_fixed_mode; | |
| 628 | } | |
| 629 | ||
| 630 | ||
| 631 | ||
| 632 | //------------------------------------------------- | |
| 633 | // input | |
| 634 | //------------------------------------------------- | |
| 635 | ||
| 636 | UINT8 mc6847_base_device::input(UINT16 address) | |
| 637 | { | |
| 638 | UINT8 data = m_res_input_func(address); | |
| 639 | if (LOG_INPUT) | |
| 640 | logerror("%s: input: address=0x%04X data=0x%02X\n", describe_context(), address, data); | |
| 641 | return data; | |
| 642 | } | |
| 643 | ||
| 644 | ||
| 645 | ||
| 646 | //------------------------------------------------- | |
| 647 | // record_scanline_res | |
| 648 | //------------------------------------------------- | |
| 649 | ||
| 650 | template<int sample_count, int yres> | |
| 651 | void mc6847_base_device::record_scanline_res(int scanline, INT32 start_pos, INT32 end_pos) | |
| 652 | { | |
| 653 | UINT8 current_sample_count = (start_pos > 0) ? m_data[scanline].m_sample_count : 0; | |
| 654 | ||
| 655 | // main loop | |
| 656 | for (INT32 pos = start_pos; pos < end_pos; pos++) | |
| 657 | { | |
| 658 | // set address at beginning of line | |
| 659 | if (pos == 0) | |
| 660 | m_video_address = scanline / (192 / yres) * sample_count; | |
| 661 | ||
| 662 | if ((sample_count == 32) || ((pos % 1) == 0)) | |
| 663 | { | |
| 664 | // input data | |
| 665 | UINT8 data = input(m_video_address++); | |
| 666 | ||
| 667 | if (pos < 32) | |
| 668 | { | |
| 669 | // update values | |
| 670 | //assert(current_sample_count >= 0); | |
| 671 | assert(current_sample_count < ARRAY_LENGTH(m_data[scanline].m_mode)); | |
| 672 | update_value(&m_data[scanline].m_mode[current_sample_count], simplify_mode(data, m_mode)); | |
| 673 | update_value(&m_data[scanline].m_data[current_sample_count], data); | |
| 674 | current_sample_count++; | |
| 675 | } | |
| 676 | } | |
| 677 | } | |
| 678 | ||
| 679 | // update sample count | |
| 680 | update_value(&m_data[scanline].m_sample_count, current_sample_count); | |
| 681 | } | |
| 682 | ||
| 683 | ||
| 684 | ||
| 685 | //------------------------------------------------- | |
| 686 | // record_body_scanline | |
| 687 | //------------------------------------------------- | |
| 688 | ||
| 689 | ATTR_FORCE_INLINE void mc6847_base_device::record_body_scanline(UINT16 physical_scanline, UINT16 scanline, INT32 start_pos, INT32 end_pos) | |
| 690 | { | |
| 691 | // sanity checks | |
| 692 | assert(scanline < 192); | |
| 693 | ||
| 694 | if (m_mode & MODE_AG) | |
| 695 | { | |
| 696 | switch(m_mode & (MODE_GM2|MODE_GM1|MODE_GM0)) | |
| 697 | { | |
| 698 | case 0: | |
| 699 | case MODE_GM0: | |
| 700 | record_scanline_res<16, 64>(scanline, start_pos, end_pos); | |
| 701 | break; | |
| 702 | ||
| 703 | case MODE_GM1: | |
| 704 | record_scanline_res<32, 64>(scanline, start_pos, end_pos); | |
| 705 | break; | |
| 706 | ||
| 707 | case MODE_GM1|MODE_GM0: | |
| 708 | record_scanline_res<16, 96>(scanline, start_pos, end_pos); | |
| 709 | break; | |
| 710 | ||
| 711 | case MODE_GM2: | |
| 712 | record_scanline_res<32, 96>(scanline, start_pos, end_pos); | |
| 713 | break; | |
| 714 | ||
| 715 | case MODE_GM2|MODE_GM0: | |
| 716 | record_scanline_res<16, 192>(scanline, start_pos, end_pos); | |
| 717 | break; | |
| 718 | ||
| 719 | case MODE_GM2|MODE_GM1: | |
| 720 | case MODE_GM2|MODE_GM1|MODE_GM0: | |
| 721 | record_scanline_res<32, 192>(scanline, start_pos, end_pos); | |
| 722 | break; | |
| 723 | ||
| 724 | default: | |
| 725 | /* should not get here */ | |
| 726 | fatalerror("should not get here\n"); | |
| 727 | break; | |
| 728 | } | |
| 729 | } | |
| 730 | else | |
| 731 | { | |
| 732 | record_scanline_res<32, 16>(scanline, start_pos, end_pos); | |
| 733 | } | |
| 734 | } | |
| 735 | ||
| 736 | ||
| 737 | ||
| 738 | //------------------------------------------------- | |
| 739 | // record_body_scanline | |
| 740 | //------------------------------------------------- | |
| 741 | ||
| 742 | void mc6847_base_device::record_body_scanline(UINT16 physical_scanline, UINT16 scanline) | |
| 743 | { | |
| 744 | record_body_scanline(physical_scanline, scanline, 0, 32); | |
| 745 | } | |
| 746 | ||
| 747 | ||
| 748 | ||
| 749 | //------------------------------------------------- | |
| 750 | // record_partial_body_scanline | |
| 751 | //------------------------------------------------- | |
| 752 | ||
| 753 | void mc6847_base_device::record_partial_body_scanline(UINT16 physical_scanline, UINT16 scanline, INT32 start_clock, INT32 end_clock) | |
| 754 | { | |
| 755 | INT32 start_pos = MAX(scanline_position_from_clock(start_clock), 0); | |
| 756 | INT32 end_pos = MIN(scanline_position_from_clock(end_clock), 42); | |
| 757 | ||
| 758 | if (start_pos < end_pos) | |
| 759 | record_body_scanline(physical_scanline, scanline, start_pos, end_pos); | |
| 760 | } | |
| 761 | ||
| 762 | ||
| 763 | ||
| 764 | //------------------------------------------------- | |
| 765 | // scanline_position_from_clock | |
| 766 | //------------------------------------------------- | |
| 767 | ||
| 768 | INT32 mc6847_base_device::scanline_position_from_clock(INT32 clocks_since_hsync) | |
| 769 | { | |
| 770 | return (clocks_since_hsync - 20) / 4; | |
| 771 | } | |
| 772 | ||
| 773 | ||
| 774 | ||
| 775 | //------------------------------------------------- | |
| 776 | // field_sync_changed | |
| 777 | //------------------------------------------------- | |
| 778 | ||
| 779 | void mc6847_base_device::field_sync_changed(bool line) | |
| 780 | { | |
| 781 | /* when field sync is on, the DA* enter the Hi-Z state */ | |
| 782 | if (line && !m_res_input_func.isnull()) | |
| 783 | m_res_input_func(~0); | |
| 784 | } | |
| 785 | ||
| 786 | ||
| 787 | ||
| 788 | //------------------------------------------------- | |
| 789 | // border_value | |
| 790 | //------------------------------------------------- | |
| 791 | ||
| 792 | ATTR_FORCE_INLINE mc6847_base_device::pixel_t mc6847_base_device::border_value(UINT8 mode, const pixel_t *palette, bool is_mc6847t1) | |
| 793 | { | |
| 794 | pixel_t result; | |
| 795 | switch(mc6847_friend_device::border_value(mode, is_mc6847t1)) | |
| 796 | { | |
| 797 | case BORDER_COLOR_BLACK: | |
| 798 | result = palette[8]; | |
| 799 | break; | |
| 800 | case BORDER_COLOR_GREEN: | |
| 801 | result = palette[0]; | |
| 802 | break; | |
| 803 | case BORDER_COLOR_WHITE: | |
| 804 | result = palette[4]; | |
| 805 | break; | |
| 806 | case BORDER_COLOR_ORANGE: | |
| 807 | result = palette[7]; | |
| 808 | break; | |
| 809 | default: | |
| 810 | fatalerror("Should not get here\n"); | |
| 811 | break; | |
| 812 | } | |
| 813 | return result; | |
| 814 | } | |
| 815 | ||
| 816 | ||
| 817 | ||
| 818 | //------------------------------------------------- | |
| 819 | // update | |
| 820 | //------------------------------------------------- | |
| 821 | ||
| 822 | UINT32 mc6847_base_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) | |
| 823 | { | |
| 824 | int base_x = 32; | |
| 825 | int base_y = 25; | |
| 826 | int x, x2, y; | |
| 827 | bool is_mc6847t1 = (type() == MC6847T1_NTSC) || (type() == MC6847T1_PAL); | |
| 828 | int min_x = USE_HORIZONTAL_CLIP ? cliprect.min_x : 0; | |
| 829 | int max_x = USE_HORIZONTAL_CLIP ? cliprect.max_x : (base_x * 2 + 256 - 1); | |
| 830 | int min_y = cliprect.min_y; | |
| 831 | int max_y = cliprect.max_y; | |
| 832 | const pixel_t *palette = m_palette; | |
| 833 | ||
| 834 | /* if the video didn't change, indicate as much */ | |
| 835 | if (!has_video_changed()) | |
| 836 | return UPDATE_HAS_NOT_CHANGED; | |
| 837 | ||
| 838 | /* top border */ | |
| 839 | for (y = min_y; y < base_y; y++) | |
| 840 | { | |
| 841 | for (x = min_x; x <= max_x; x++) | |
| 842 | { | |
| 843 | *bitmap_addr(bitmap, y, x) = border_value(m_data[0].m_mode[0], palette, is_mc6847t1); | |
| 844 | } | |
| 845 | } | |
| 846 | ||
| 847 | for (y = MAX(0, min_y - base_y); y <= MIN(192, max_y - base_y); y++) | |
| 848 | { | |
| 849 | /* left border */ | |
| 850 | for (x = min_x; x < base_x; x++) | |
| 851 | { | |
| 852 | *bitmap_addr(bitmap, y + base_y, x) = border_value(m_data[y].m_mode[0], palette, is_mc6847t1); | |
| 853 | } | |
| 854 | ||
| 855 | /* body */ | |
| 856 | x = 0; | |
| 857 | int width = m_data[y].m_sample_count; | |
| 858 | pixel_t *RESTRICT pixels = bitmap_addr(bitmap, base_y + y, base_x); | |
| 859 | while(x < width) | |
| 860 | { | |
| 861 | /* determine how many bytes exist for which the mode is identical */ | |
| 862 | for (x2 = x + 1; (x2 < width) && (m_data[y].m_mode[x] == m_data[y].m_mode[x2]); x2++) | |
| 863 | ; | |
| 864 | ||
| 865 | /* emit the samples */ | |
| 866 | pixels += emit_mc6847_samples<1>( | |
| 867 | m_data[y].m_mode[x], | |
| 868 | &m_data[y].m_data[x], | |
| 869 | x2 - x, | |
| 870 | pixels, | |
| 871 | m_palette, | |
| 872 | m_get_char_rom, | |
| 873 | x, | |
| 874 | y); | |
| 875 | ||
| 876 | /* update x */ | |
| 877 | x = x2; | |
| 878 | } | |
| 879 | ||
| 880 | /* right border */ | |
| 881 | for (x = base_x + 256; x <= max_x; x++) | |
| 882 | { | |
| 883 | *bitmap_addr(bitmap, y + base_y, x) = border_value(m_data[y].m_mode[width - 1], palette, is_mc6847t1); | |
| 884 | } | |
| 885 | ||
| 886 | /* artifacting */ | |
| 887 | m_artifacter.process_artifacts<1>(bitmap_addr(bitmap, y + base_y, base_x), m_data[y].m_mode[0], palette); | |
| 888 | } | |
| 889 | ||
| 890 | /* bottom border */ | |
| 891 | for (y = base_y + 192; y <= max_y; y++) | |
| 892 | { | |
| 893 | for (x = min_x; x <= max_x; x++) | |
| 894 | { | |
| 895 | int width = m_data[191].m_sample_count; | |
| 896 | *bitmap_addr(bitmap, y, x) = border_value(m_data[191].m_mode[width - 1], palette, is_mc6847t1); | |
| 897 | } | |
| 898 | } | |
| 899 | return 0; | |
| 900 | } | |
| 901 | ||
| 902 | ||
| 903 | ||
| 904 | //************************************************************************** | |
| 905 | // CHARACTER MAP | |
| 906 | //************************************************************************** | |
| 907 | ||
| 908 | mc6847_friend_device::character_map::character_map(const UINT8 *text_fontdata, bool is_mc6847t1) | |
| 909 | { | |
| 910 | int mode, i; | |
| 911 | ||
| 912 | // set up font data | |
| 913 | for (i = 0; i < 64*12; i++) | |
| 914 | { | |
| 915 | m_text_fontdata_inverse[i] = text_fontdata[i] ^ 0xFF; | |
| 916 | m_text_fontdata_lower_case[i] = text_fontdata[i + (i < 32*12 ? 64*12 : 0)] ^ (i < 32*12 ? 0xFF : 0x00); | |
| 917 | m_text_fontdata_lower_case_inverse[i] = m_text_fontdata_lower_case[i] ^ 0xFF; | |
| 918 | } | |
| 919 | ||
| 920 | // loop through all modes | |
| 921 | for (mode = 0; mode < sizeof(m_entries) / sizeof(m_entries[0]); mode++) | |
| 922 | { | |
| 923 | const UINT8 *fontdata; | |
| 924 | UINT8 character_mask; | |
| 925 | UINT8 color_shift_0 = 0; | |
| 926 | UINT8 color_shift_1 = 0; | |
| 927 | UINT8 color_mask_0 = 0x00; | |
| 928 | UINT8 color_mask_1 = 0x00; | |
| 929 | UINT16 color_base_0; | |
| 930 | UINT16 color_base_1; | |
| 931 | ||
| 932 | if ((mode & MODE_INTEXT) && !is_mc6847t1) | |
| 933 | { | |
| 934 | // semigraphics 6 | |
| 935 | fontdata = semigraphics6_fontdata8x12; | |
| 936 | character_mask = 0x3F; | |
| 937 | color_base_0 = 8; | |
| 938 | color_base_1 = mode & MODE_CSS ? 4 : 0; | |
| 939 | color_shift_1 = 6; | |
| 940 | color_mask_1 = 0x03; | |
| 941 | } | |
| 942 | else if (mode & MODE_AS) | |
| 943 | { | |
| 944 | // semigraphics 4 | |
| 945 | fontdata = semigraphics4_fontdata8x12; | |
| 946 | character_mask = 0x0F; | |
| 947 | color_base_0 = 8; | |
| 948 | color_base_1 = 0; | |
| 949 | color_shift_1 = 4; | |
| 950 | color_mask_1 = 0x07; | |
| 951 | } | |
| 952 | else | |
| 953 | { | |
| 954 | // text | |
| 955 | bool is_lower_case = is_mc6847t1 && ((mode & MODE_INV) == 0) && (mode & MODE_GM0); | |
| 956 | bool is_inverse1 = (mode & MODE_INV) ? true : false; | |
| 957 | bool is_inverse2 = is_mc6847t1 && (mode & MODE_GM1); | |
| 958 | bool is_inverse = (is_inverse1 && !is_inverse2) || (!is_inverse1 && is_inverse2); | |
| 959 | fontdata = is_inverse | |
| 960 | ? (is_lower_case ? m_text_fontdata_lower_case_inverse : m_text_fontdata_inverse) | |
| 961 | : (is_lower_case ? m_text_fontdata_lower_case : text_fontdata); | |
| 962 | character_mask = 0x3F; | |
| 963 | color_base_0 = (mode & MODE_CSS ? 14 : 12); | |
| 964 | color_base_1 = (mode & MODE_CSS ? 15 : 13); | |
| 965 | } | |
| 966 | ||
| 967 | // populate the entry | |
| 968 | memset(&m_entries[mode], 0, sizeof(m_entries[mode])); | |
| 969 | m_entries[mode].m_fontdata = fontdata; | |
| 970 | m_entries[mode].m_character_mask = character_mask; | |
| 971 | m_entries[mode].m_color_shift_0 = color_shift_0; | |
| 972 | m_entries[mode].m_color_shift_1 = color_shift_1; | |
| 973 | m_entries[mode].m_color_mask_0 = color_mask_0; | |
| 974 | m_entries[mode].m_color_mask_1 = color_mask_1; | |
| 975 | m_entries[mode].m_color_base_0 = color_base_0; | |
| 976 | m_entries[mode].m_color_base_1 = color_base_1; | |
| 977 | } | |
| 978 | } | |
| 979 | ||
| 980 | ||
| 981 | ||
| 982 | //------------------------------------------------- | |
| 983 | // pal_round_fontdata8x12 | |
| 984 | //------------------------------------------------- | |
| 985 | ||
| 986 | const UINT8 mc6847_friend_device::pal_round_fontdata8x12[] = | |
| 987 | { | |
| 988 | 0x00, 0x00, 0x38, 0x44, 0x04, 0x34, 0x4C, 0x4C, 0x38, 0x00, 0x00, 0x00, | |
| 989 | 0x00, 0x00, 0x10, 0x28, 0x44, 0x44, 0x7C, 0x44, 0x44, 0x00, 0x00, 0x00, | |
| 990 | 0x00, 0x00, 0x78, 0x24, 0x24, 0x38, 0x24, 0x24, 0x78, 0x00, 0x00, 0x00, | |
| 991 | 0x00, 0x00, 0x38, 0x44, 0x40, 0x40, 0x40, 0x44, 0x38, 0x00, 0x00, 0x00, | |
| 992 | 0x00, 0x00, 0x78, 0x24, 0x24, 0x24, 0x24, 0x24, 0x78, 0x00, 0x00, 0x00, | |
| 993 | 0x00, 0x00, 0x7C, 0x40, 0x40, 0x70, 0x40, 0x40, 0x7C, 0x00, 0x00, 0x00, | |
| 994 | 0x00, 0x00, 0x7C, 0x40, 0x40, 0x70, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, | |
| 995 | 0x00, 0x00, 0x38, 0x44, 0x40, 0x40, 0x4C, 0x44, 0x38, 0x00, 0x00, 0x00, | |
| 996 | 0x00, 0x00, 0x44, 0x44, 0x44, 0x7C, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00, | |
| 997 | 0x00, 0x00, 0x38, 0x10, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00, 0x00, 0x00, | |
| 998 | 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x44, 0x38, 0x00, 0x00, 0x00, | |
| 999 | 0x00, 0x00, 0x44, 0x48, 0x50, 0x60, 0x50, 0x48, 0x44, 0x00, 0x00, 0x00, | |
| 1000 | 0x00, 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x7C, 0x00, 0x00, 0x00, | |
| 1001 | 0x00, 0x00, 0x44, 0x6C, 0x54, 0x54, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00, | |
| 1002 | 0x00, 0x00, 0x44, 0x44, 0x64, 0x54, 0x4C, 0x44, 0x44, 0x00, 0x00, 0x00, | |
| 1003 | 0x00, 0x00, 0x38, 0x44, 0x44, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, | |
| 1004 | 0x00, 0x00, 0x78, 0x44, 0x44, 0x78, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, | |
| 1005 | 0x00, 0x00, 0x38, 0x44, 0x44, 0x44, 0x54, 0x48, 0x34, 0x00, 0x00, 0x00, | |
| 1006 | 0x00, 0x00, 0x78, 0x44, 0x44, 0x78, 0x50, 0x48, 0x44, 0x00, 0x00, 0x00, | |
| 1007 | 0x00, 0x00, 0x38, 0x44, 0x40, 0x38, 0x04, 0x44, 0x38, 0x00, 0x00, 0x00, | |
| 1008 | 0x00, 0x00, 0x7C, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, | |
| 1009 | 0x00, 0x00, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, | |
| 1010 | 0x00, 0x00, 0x44, 0x44, 0x44, 0x28, 0x28, 0x10, 0x10, 0x00, 0x00, 0x00, | |
| 1011 | 0x00, 0x00, 0x44, 0x44, 0x44, 0x44, 0x54, 0x6C, 0x44, 0x00, 0x00, 0x00, | |
| 1012 | 0x00, 0x00, 0x44, 0x44, 0x28, 0x10, 0x28, 0x44, 0x44, 0x00, 0x00, 0x00, | |
| 1013 | 0x00, 0x00, 0x44, 0x44, 0x28, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, | |
| 1014 | 0x00, 0x00, 0x7C, 0x04, 0x08, 0x10, 0x20, 0x40, 0x7C, 0x00, 0x00, 0x00, | |
| 1015 | 0x00, 0x00, 0x38, 0x20, 0x20, 0x20, 0x20, 0x20, 0x38, 0x00, 0x00, 0x00, | |
| 1016 | 0x00, 0x00, 0x00, 0x40, 0x20, 0x10, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, | |
| 1017 | 0x00, 0x00, 0x38, 0x08, 0x08, 0x08, 0x08, 0x08, 0x38, 0x00, 0x00, 0x00, | |
| 1018 | 0x00, 0x00, 0x10, 0x38, 0x54, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, | |
| 1019 | 0x00, 0x00, 0x00, 0x10, 0x20, 0x7C, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, | |
| 1020 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 1021 | 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00, | |
| 1022 | 0x00, 0x00, 0x28, 0x28, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 1023 | 0x00, 0x00, 0x28, 0x28, 0x7C, 0x28, 0x7C, 0x28, 0x28, 0x00, 0x00, 0x00, | |
| 1024 | 0x00, 0x00, 0x10, 0x3C, 0x50, 0x38, 0x14, 0x78, 0x10, 0x00, 0x00, 0x00, | |
| 1025 | 0x00, 0x00, 0x60, 0x64, 0x08, 0x10, 0x20, 0x4C, 0x0C, 0x00, 0x00, 0x00, | |
| 1026 | 0x00, 0x00, 0x20, 0x50, 0x50, 0x20, 0x54, 0x48, 0x34, 0x00, 0x00, 0x00, | |
| 1027 | 0x00, 0x00, 0x10, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 1028 | 0x00, 0x00, 0x08, 0x10, 0x20, 0x20, 0x20, 0x10, 0x08, 0x00, 0x00, 0x00, | |
| 1029 | 0x00, 0x00, 0x20, 0x10, 0x08, 0x08, 0x08, 0x10, 0x20, 0x00, 0x00, 0x00, | |
| 1030 | 0x00, 0x00, 0x00, 0x10, 0x54, 0x38, 0x38, 0x54, 0x10, 0x00, 0x00, 0x00, | |
| 1031 | 0x00, 0x00, 0x00, 0x10, 0x10, 0x7C, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, | |
| 1032 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x40, 0x00, 0x00, | |
| 1033 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 1034 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, | |
| 1035 | 0x00, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x40, 0x00, 0x00, 0x00, 0x00, | |
| 1036 | 0x00, 0x00, 0x38, 0x44, 0x4C, 0x54, 0x64, 0x44, 0x38, 0x00, 0x00, 0x00, | |
| 1037 | 0x00, 0x00, 0x10, 0x30, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00, 0x00, 0x00, | |
| 1038 | 0x00, 0x00, 0x38, 0x44, 0x04, 0x38, 0x40, 0x40, 0x7C, 0x00, 0x00, 0x00, | |
| 1039 | 0x00, 0x00, 0x38, 0x44, 0x04, 0x08, 0x04, 0x44, 0x38, 0x00, 0x00, 0x00, | |
| 1040 | 0x00, 0x00, 0x08, 0x18, 0x28, 0x48, 0x7C, 0x08, 0x08, 0x00, 0x00, 0x00, | |
| 1041 | 0x00, 0x00, 0x7C, 0x40, 0x78, 0x04, 0x04, 0x44, 0x38, 0x00, 0x00, 0x00, | |
| 1042 | 0x00, 0x00, 0x38, 0x40, 0x40, 0x78, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, | |
| 1043 | 0x00, 0x00, 0x7C, 0x04, 0x08, 0x10, 0x20, 0x40, 0x40, 0x00, 0x00, 0x00, | |
| 1044 | 0x00, 0x00, 0x38, 0x44, 0x44, 0x38, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, | |
| 1045 | 0x00, 0x00, 0x38, 0x44, 0x44, 0x3C, 0x04, 0x04, 0x38, 0x00, 0x00, 0x00, | |
| 1046 | 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, | |
| 1047 | 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x10, 0x20, 0x00, 0x00, | |
| 1048 | 0x00, 0x00, 0x08, 0x10, 0x20, 0x40, 0x20, 0x10, 0x08, 0x00, 0x00, 0x00, | |
| 1049 | 0x00, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 1050 | 0x00, 0x00, 0x20, 0x10, 0x08, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x00, | |
| 1051 | 0x00, 0x00, 0x38, 0x44, 0x04, 0x08, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00, | |
| 1052 | ||
| 1053 | /* Lower case */ | |
| 1054 | 0x00, 0x00, 0x18, 0x24, 0x20, 0x70, 0x20, 0x24, 0x78, 0x00, 0x00, 0x00, | |
| 1055 | 0x00, 0x00, 0x00, 0x00, 0x38, 0x04, 0x3C, 0x44, 0x3C, 0x00, 0x00, 0x00, | |
| 1056 | 0x00, 0x00, 0x40, 0x40, 0x58, 0x64, 0x44, 0x64, 0x58, 0x00, 0x00, 0x00, | |
| 1057 | 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, 0x40, 0x44, 0x38, 0x00, 0x00, 0x00, | |
| 1058 | 0x00, 0x00, 0x04, 0x04, 0x34, 0x4C, 0x44, 0x4C, 0x34, 0x00, 0x00, 0x00, | |
| 1059 | 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, 0x7C, 0x40, 0x38, 0x00, 0x00, 0x00, | |
| 1060 | 0x00, 0x00, 0x08, 0x14, 0x10, 0x38, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, | |
| 1061 | 0x00, 0x00, 0x00, 0x00, 0x34, 0x4C, 0x44, 0x4C, 0x34, 0x04, 0x38, 0x00, | |
| 1062 | 0x00, 0x00, 0x40, 0x40, 0x58, 0x64, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00, | |
| 1063 | 0x00, 0x00, 0x10, 0x00, 0x30, 0x10, 0x10, 0x10, 0x38, 0x00, 0x00, 0x00, | |
| 1064 | 0x00, 0x00, 0x04, 0x00, 0x04, 0x04, 0x04, 0x04, 0x44, 0x38, 0x00, 0x00, | |
| 1065 | 0x00, 0x00, 0x40, 0x40, 0x48, 0x50, 0x60, 0x50, 0x48, 0x00, 0x00, 0x00, | |
| 1066 | 0x00, 0x00, 0x30, 0x10, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00, 0x00, 0x00, | |
| 1067 | 0x00, 0x00, 0x00, 0x00, 0x78, 0x54, 0x54, 0x54, 0x54, 0x00, 0x00, 0x00, | |
| 1068 | 0x00, 0x00, 0x00, 0x00, 0x58, 0x64, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00, | |
| 1069 | 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, | |
| 1070 | 0x00, 0x00, 0x00, 0x00, 0x78, 0x44, 0x44, 0x44, 0x78, 0x40, 0x40, 0x00, | |
| 1071 | 0x00, 0x00, 0x00, 0x00, 0x3C, 0x44, 0x44, 0x44, 0x3C, 0x04, 0x04, 0x00, | |
| 1072 | 0x00, 0x00, 0x00, 0x00, 0x58, 0x64, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, | |
| 1073 | 0x00, 0x00, 0x00, 0x00, 0x3C, 0x40, 0x38, 0x04, 0x78, 0x00, 0x00, 0x00, | |
| 1074 | 0x00, 0x00, 0x20, 0x20, 0x70, 0x20, 0x20, 0x24, 0x18, 0x00, 0x00, 0x00, | |
| 1075 | 0x00, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x4C, 0x34, 0x00, 0x00, 0x00, | |
| 1076 | 0x00, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x28, 0x10, 0x00, 0x00, 0x00, | |
| 1077 | 0x00, 0x00, 0x00, 0x00, 0x44, 0x54, 0x54, 0x28, 0x28, 0x00, 0x00, 0x00, | |
| 1078 | 0x00, 0x00, 0x00, 0x00, 0x44, 0x28, 0x10, 0x28, 0x44, 0x00, 0x00, 0x00, | |
| 1079 | 0x00, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x3C, 0x04, 0x38, 0x00, 0x00, | |
| 1080 | 0x00, 0x00, 0x00, 0x00, 0x7C, 0x08, 0x10, 0x20, 0x7C, 0x00, 0x00, 0x00, | |
| 1081 | 0x00, 0x00, 0x08, 0x10, 0x10, 0x20, 0x10, 0x10, 0x08, 0x00, 0x00, 0x00, | |
| 1082 | 0x00, 0x00, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, | |
| 1083 | 0x00, 0x00, 0x20, 0x10, 0x10, 0x08, 0x10, 0x10, 0x20, 0x00, 0x00, 0x00, | |
| 1084 | 0x00, 0x00, 0x20, 0x54, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 1085 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00 | |
| 1086 | }; | |
| 1087 | ||
| 1088 | ||
| 1089 | ||
| 1090 | //------------------------------------------------- | |
| 1091 | // pal_square_fontdata8x12 | |
| 1092 | //------------------------------------------------- | |
| 1093 | ||
| 1094 | const UINT8 mc6847_friend_device::pal_square_fontdata8x12[] = | |
| 1095 | { | |
| 1096 | 0x00, 0x00, 0x00, 0x1C, 0x22, 0x02, 0x1A, 0x2A, 0x2A, 0x1C, 0x00, 0x00, | |
| 1097 | 0x00, 0x00, 0x00, 0x08, 0x14, 0x22, 0x22, 0x3E, 0x22, 0x22, 0x00, 0x00, | |
| 1098 | 0x00, 0x00, 0x00, 0x3C, 0x12, 0x12, 0x1C, 0x12, 0x12, 0x3C, 0x00, 0x00, | |
| 1099 | 0x00, 0x00, 0x00, 0x1C, 0x22, 0x20, 0x20, 0x20, 0x22, 0x1C, 0x00, 0x00, | |
| 1100 | 0x00, 0x00, 0x00, 0x3C, 0x12, 0x12, 0x12, 0x12, 0x12, 0x3C, 0x00, 0x00, | |
| 1101 | 0x00, 0x00, 0x00, 0x3E, 0x20, 0x20, 0x3C, 0x20, 0x20, 0x3E, 0x00, 0x00, | |
| 1102 | 0x00, 0x00, 0x00, 0x3E, 0x20, 0x20, 0x3C, 0x20, 0x20, 0x20, 0x00, 0x00, | |
| 1103 | 0x00, 0x00, 0x00, 0x1E, 0x20, 0x20, 0x26, 0x22, 0x22, 0x1E, 0x00, 0x00, | |
| 1104 | 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x3E, 0x22, 0x22, 0x22, 0x00, 0x00, | |
| 1105 | 0x00, 0x00, 0x00, 0x1C, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1C, 0x00, 0x00, | |
| 1106 | 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x22, 0x22, 0x1C, 0x00, 0x00, | |
| 1107 | 0x00, 0x00, 0x00, 0x22, 0x24, 0x28, 0x30, 0x28, 0x24, 0x22, 0x00, 0x00, | |
| 1108 | 0x00, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3E, 0x00, 0x00, | |
| 1109 | 0x00, 0x00, 0x00, 0x22, 0x36, 0x2A, 0x2A, 0x22, 0x22, 0x22, 0x00, 0x00, | |
| 1110 | 0x00, 0x00, 0x00, 0x22, 0x32, 0x2A, 0x26, 0x22, 0x22, 0x22, 0x00, 0x00, | |
| 1111 | 0x00, 0x00, 0x00, 0x3E, 0x22, 0x22, 0x22, 0x22, 0x22, 0x3E, 0x00, 0x00, | |
| 1112 | 0x00, 0x00, 0x00, 0x3C, 0x22, 0x22, 0x3C, 0x20, 0x20, 0x20, 0x00, 0x00, | |
| 1113 | 0x00, 0x00, 0x00, 0x1C, 0x22, 0x22, 0x22, 0x2A, 0x24, 0x1A, 0x00, 0x00, | |
| 1114 | 0x00, 0x00, 0x00, 0x3C, 0x22, 0x22, 0x3C, 0x28, 0x24, 0x22, 0x00, 0x00, | |
| 1115 | 0x00, 0x00, 0x00, 0x1C, 0x22, 0x10, 0x08, 0x04, 0x22, 0x1C, 0x00, 0x00, | |
| 1116 | 0x00, 0x00, 0x00, 0x3E, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, | |
| 1117 | 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x1C, 0x00, 0x00, | |
| 1118 | 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x14, 0x14, 0x08, 0x08, 0x00, 0x00, | |
| 1119 | 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x2A, 0x2A, 0x36, 0x22, 0x00, 0x00, | |
| 1120 | 0x00, 0x00, 0x00, 0x22, 0x22, 0x14, 0x08, 0x14, 0x22, 0x22, 0x00, 0x00, | |
| 1121 | 0x00, 0x00, 0x00, 0x22, 0x22, 0x14, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, | |
| 1122 | 0x00, 0x00, 0x00, 0x3E, 0x02, 0x04, 0x08, 0x10, 0x20, 0x3E, 0x00, 0x00, | |
| 1123 | 0x00, 0x00, 0x00, 0x38, 0x20, 0x20, 0x20, 0x20, 0x20, 0x38, 0x00, 0x00, | |
| 1124 | 0x00, 0x00, 0x00, 0x20, 0x20, 0x10, 0x08, 0x04, 0x02, 0x02, 0x00, 0x00, | |
| 1125 | 0x00, 0x00, 0x00, 0x0E, 0x02, 0x02, 0x02, 0x02, 0x02, 0x0E, 0x00, 0x00, | |
| 1126 | 0x00, 0x00, 0x00, 0x08, 0x1C, 0x2A, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, | |
| 1127 | 0x00, 0x00, 0x00, 0x00, 0x08, 0x10, 0x3E, 0x10, 0x08, 0x00, 0x00, 0x00, | |
| 1128 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 1129 | 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x08, 0x00, 0x00, | |
| 1130 | 0x00, 0x00, 0x00, 0x14, 0x14, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 1131 | 0x00, 0x00, 0x00, 0x14, 0x14, 0x36, 0x00, 0x36, 0x14, 0x14, 0x00, 0x00, | |
| 1132 | 0x00, 0x00, 0x00, 0x08, 0x1E, 0x20, 0x1C, 0x02, 0x3C, 0x08, 0x00, 0x00, | |
| 1133 | 0x00, 0x00, 0x00, 0x32, 0x32, 0x04, 0x08, 0x10, 0x26, 0x26, 0x00, 0x00, | |
| 1134 | 0x00, 0x00, 0x00, 0x10, 0x28, 0x28, 0x10, 0x2A, 0x24, 0x1A, 0x00, 0x00, | |
| 1135 | 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 1136 | 0x00, 0x00, 0x00, 0x08, 0x10, 0x20, 0x20, 0x20, 0x10, 0x08, 0x00, 0x00, | |
| 1137 | 0x00, 0x00, 0x00, 0x08, 0x04, 0x02, 0x02, 0x02, 0x04, 0x08, 0x00, 0x00, | |
| 1138 | 0x00, 0x00, 0x00, 0x00, 0x08, 0x1C, 0x3E, 0x1C, 0x08, 0x00, 0x00, 0x00, | |
| 1139 | 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x3E, 0x08, 0x08, 0x00, 0x00, 0x00, | |
| 1140 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x10, 0x20, 0x00, 0x00, | |
| 1141 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 1142 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, | |
| 1143 | 0x00, 0x00, 0x00, 0x02, 0x02, 0x04, 0x08, 0x10, 0x20, 0x20, 0x00, 0x00, | |
| 1144 | 0x00, 0x00, 0x00, 0x18, 0x24, 0x24, 0x24, 0x24, 0x24, 0x18, 0x00, 0x00, | |
| 1145 | 0x00, 0x00, 0x00, 0x08, 0x18, 0x08, 0x08, 0x08, 0x08, 0x1C, 0x00, 0x00, | |
| 1146 | 0x00, 0x00, 0x00, 0x1C, 0x22, 0x02, 0x1C, 0x20, 0x20, 0x3E, 0x00, 0x00, | |
| 1147 | 0x00, 0x00, 0x00, 0x1C, 0x22, 0x02, 0x0C, 0x02, 0x22, 0x1C, 0x00, 0x00, | |
| 1148 | 0x00, 0x00, 0x00, 0x04, 0x0C, 0x14, 0x3E, 0x04, 0x04, 0x04, 0x00, 0x00, | |
| 1149 | 0x00, 0x00, 0x00, 0x3E, 0x20, 0x3C, 0x02, 0x02, 0x22, 0x1C, 0x00, 0x00, | |
| 1150 | 0x00, 0x00, 0x00, 0x1C, 0x20, 0x20, 0x3C, 0x22, 0x22, 0x1C, 0x00, 0x00, | |
| 1151 | 0x00, 0x00, 0x00, 0x3E, 0x02, 0x04, 0x08, 0x10, 0x20, 0x20, 0x00, 0x00, | |
| 1152 | 0x00, 0x00, 0x00, 0x1C, 0x22, 0x22, 0x1C, 0x22, 0x22, 0x1C, 0x00, 0x00, | |
| 1153 | 0x00, 0x00, 0x00, 0x1C, 0x22, 0x22, 0x1E, 0x02, 0x02, 0x1C, 0x00, 0x00, | |
| 1154 | 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, | |
| 1155 | 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x08, 0x10, 0x00, 0x00, | |
| 1156 | 0x00, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x10, 0x08, 0x04, 0x00, 0x00, | |
| 1157 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, | |
| 1158 | 0x00, 0x00, 0x00, 0x10, 0x08, 0x04, 0x02, 0x04, 0x08, 0x10, 0x00, 0x00, | |
| 1159 | 0x00, 0x00, 0x00, 0x18, 0x24, 0x04, 0x08, 0x08, 0x00, 0x08, 0x00, 0x00, | |
| 1160 | ||
| 1161 | /* Lower case */ | |
| 1162 | 0x00, 0x00, 0x00, 0x0C, 0x12, 0x10, 0x38, 0x10, 0x12, 0x3C, 0x00, 0x00, | |
| 1163 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x02, 0x1E, 0x22, 0x1E, 0x00, 0x00, | |
| 1164 | 0x00, 0x00, 0x00, 0x20, 0x20, 0x3C, 0x22, 0x22, 0x22, 0x3C, 0x00, 0x00, | |
| 1165 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x20, 0x20, 0x20, 0x1C, 0x00, 0x00, | |
| 1166 | 0x00, 0x00, 0x00, 0x02, 0x02, 0x1E, 0x22, 0x22, 0x22, 0x1E, 0x00, 0x00, | |
| 1167 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x22, 0x3E, 0x20, 0x1C, 0x00, 0x00, | |
| 1168 | 0x00, 0x00, 0x00, 0x0C, 0x12, 0x10, 0x38, 0x10, 0x10, 0x10, 0x00, 0x00, | |
| 1169 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x22, 0x22, 0x22, 0x1E, 0x02, 0x1C, | |
| 1170 | 0x00, 0x00, 0x00, 0x20, 0x20, 0x3C, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, | |
| 1171 | 0x00, 0x00, 0x00, 0x08, 0x00, 0x18, 0x08, 0x08, 0x08, 0x1C, 0x00, 0x00, | |
| 1172 | 0x00, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x04, 0x04, 0x04, 0x04, 0x24, 0x18, | |
| 1173 | 0x00, 0x00, 0x00, 0x20, 0x20, 0x24, 0x28, 0x38, 0x24, 0x22, 0x00, 0x00, | |
| 1174 | 0x00, 0x00, 0x00, 0x18, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1C, 0x00, 0x00, | |
| 1175 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x2A, 0x2A, 0x2A, 0x2A, 0x00, 0x00, | |
| 1176 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x2C, 0x32, 0x22, 0x22, 0x22, 0x00, 0x00, | |
| 1177 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x22, 0x22, 0x22, 0x1C, 0x00, 0x00, | |
| 1178 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x22, 0x22, 0x22, 0x3C, 0x20, 0x20, | |
| 1179 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x22, 0x22, 0x22, 0x1E, 0x02, 0x03, | |
| 1180 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x2C, 0x32, 0x20, 0x20, 0x20, 0x00, 0x00, | |
| 1181 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x20, 0x1C, 0x02, 0x3C, 0x00, 0x00, | |
| 1182 | 0x00, 0x00, 0x00, 0x10, 0x3C, 0x10, 0x10, 0x10, 0x12, 0x0C, 0x00, 0x00, | |
| 1183 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x26, 0x1A, 0x00, 0x00, | |
| 1184 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x14, 0x14, 0x08, 0x00, 0x00, | |
| 1185 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x2A, 0x2A, 0x1C, 0x14, 0x00, 0x00, | |
| 1186 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x14, 0x08, 0x14, 0x22, 0x00, 0x00, | |
| 1187 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x1E, 0x02, 0x1C, | |
| 1188 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x04, 0x08, 0x10, 0x3E, 0x00, 0x00, | |
| 1189 | 0x00, 0x00, 0x00, 0x08, 0x10, 0x10, 0x20, 0x10, 0x10, 0x08, 0x00, 0x00, | |
| 1190 | 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x00, 0x08, 0x08, 0x08, 0x00, 0x00, | |
| 1191 | 0x00, 0x00, 0x00, 0x08, 0x04, 0x04, 0x02, 0x04, 0x04, 0x08, 0x00, 0x00, | |
| 1192 | 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x2A, 0x1C, 0x08, 0x00, 0x00, | |
| 1193 | 0x00, 0x00, 0x00, 0x08, 0x04, 0x3E, 0x04, 0x08, 0x00, 0x00, 0x00, 0x00, | |
| 1194 | }; | |
| 1195 | ||
| 1196 | ||
| 1197 | ||
| 1198 | //------------------------------------------------- | |
| 1199 | // ntsc_round_fontdata8x12 | |
| 1200 | //------------------------------------------------- | |
| 1201 | ||
| 1202 | const UINT8 mc6847_friend_device::ntsc_round_fontdata8x12[] = | |
| 1203 | { | |
| 1204 | 0x00, 0x00, 0x38, 0x44, 0x04, 0x34, 0x4C, 0x4C, 0x38, 0x00, 0x00, 0x00, | |
| 1205 | 0x00, 0x00, 0x10, 0x28, 0x44, 0x44, 0x7C, 0x44, 0x44, 0x00, 0x00, 0x00, | |
| 1206 | 0x00, 0x00, 0x78, 0x24, 0x24, 0x38, 0x24, 0x24, 0x78, 0x00, 0x00, 0x00, | |
| 1207 | 0x00, 0x00, 0x38, 0x44, 0x40, 0x40, 0x40, 0x44, 0x38, 0x00, 0x00, 0x00, | |
| 1208 | 0x00, 0x00, 0x78, 0x24, 0x24, 0x24, 0x24, 0x24, 0x78, 0x00, 0x00, 0x00, | |
| 1209 | 0x00, 0x00, 0x7C, 0x40, 0x40, 0x70, 0x40, 0x40, 0x7C, 0x00, 0x00, 0x00, | |
| 1210 | 0x00, 0x00, 0x7C, 0x40, 0x40, 0x70, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, | |
| 1211 | 0x00, 0x00, 0x38, 0x44, 0x40, 0x40, 0x4C, 0x44, 0x38, 0x00, 0x00, 0x00, | |
| 1212 | 0x00, 0x00, 0x44, 0x44, 0x44, 0x7C, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00, | |
| 1213 | 0x00, 0x00, 0x38, 0x10, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00, 0x00, 0x00, | |
| 1214 | 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x44, 0x38, 0x00, 0x00, 0x00, | |
| 1215 | 0x00, 0x00, 0x44, 0x48, 0x50, 0x60, 0x50, 0x48, 0x44, 0x00, 0x00, 0x00, | |
| 1216 | 0x00, 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x7C, 0x00, 0x00, 0x00, | |
| 1217 | 0x00, 0x00, 0x44, 0x6C, 0x54, 0x54, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00, | |
| 1218 | 0x00, 0x00, 0x44, 0x44, 0x64, 0x54, 0x4C, 0x44, 0x44, 0x00, 0x00, 0x00, | |
| 1219 | 0x00, 0x00, 0x38, 0x44, 0x44, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, | |
| 1220 | 0x00, 0x00, 0x78, 0x44, 0x44, 0x78, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, | |
| 1221 | 0x00, 0x00, 0x38, 0x44, 0x44, 0x44, 0x54, 0x48, 0x34, 0x00, 0x00, 0x00, | |
| 1222 | 0x00, 0x00, 0x78, 0x44, 0x44, 0x78, 0x50, 0x48, 0x44, 0x00, 0x00, 0x00, | |
| 1223 | 0x00, 0x00, 0x38, 0x44, 0x40, 0x38, 0x04, 0x44, 0x38, 0x00, 0x00, 0x00, | |
| 1224 | 0x00, 0x00, 0x7C, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, | |
| 1225 | 0x00, 0x00, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, | |
| 1226 | 0x00, 0x00, 0x44, 0x44, 0x44, 0x28, 0x28, 0x10, 0x10, 0x00, 0x00, 0x00, | |
| 1227 | 0x00, 0x00, 0x44, 0x44, 0x44, 0x44, 0x54, 0x6C, 0x44, 0x00, 0x00, 0x00, | |
| 1228 | 0x00, 0x00, 0x44, 0x44, 0x28, 0x10, 0x28, 0x44, 0x44, 0x00, 0x00, 0x00, | |
| 1229 | 0x00, 0x00, 0x44, 0x44, 0x28, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, | |
| 1230 | 0x00, 0x00, 0x7C, 0x04, 0x08, 0x10, 0x20, 0x40, 0x7C, 0x00, 0x00, 0x00, | |
| 1231 | 0x00, 0x00, 0x38, 0x20, 0x20, 0x20, 0x20, 0x20, 0x38, 0x00, 0x00, 0x00, | |
| 1232 | 0x00, 0x00, 0x00, 0x40, 0x20, 0x10, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, | |
| 1233 | 0x00, 0x00, 0x38, 0x08, 0x08, 0x08, 0x08, 0x08, 0x38, 0x00, 0x00, 0x00, | |
| 1234 | 0x00, 0x00, 0x10, 0x38, 0x54, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, | |
| 1235 | 0x00, 0x00, 0x00, 0x10, 0x20, 0x7C, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, | |
| 1236 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 1237 | 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00, | |
| 1238 | 0x00, 0x00, 0x28, 0x28, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 1239 | 0x00, 0x00, 0x28, 0x28, 0x7C, 0x28, 0x7C, 0x28, 0x28, 0x00, 0x00, 0x00, | |
| 1240 | 0x00, 0x00, 0x10, 0x3C, 0x50, 0x38, 0x14, 0x78, 0x10, 0x00, 0x00, 0x00, | |
| 1241 | 0x00, 0x00, 0x60, 0x64, 0x08, 0x10, 0x20, 0x4C, 0x0C, 0x00, 0x00, 0x00, | |
| 1242 | 0x00, 0x00, 0x20, 0x50, 0x50, 0x20, 0x54, 0x48, 0x34, 0x00, 0x00, 0x00, | |
| 1243 | 0x00, 0x00, 0x10, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 1244 | 0x00, 0x00, 0x08, 0x10, 0x20, 0x20, 0x20, 0x10, 0x08, 0x00, 0x00, 0x00, | |
| 1245 | 0x00, 0x00, 0x20, 0x10, 0x08, 0x08, 0x08, 0x10, 0x20, 0x00, 0x00, 0x00, | |
| 1246 | 0x00, 0x00, 0x00, 0x10, 0x54, 0x38, 0x38, 0x54, 0x10, 0x00, 0x00, 0x00, | |
| 1247 | 0x00, 0x00, 0x00, 0x10, 0x10, 0x7C, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, | |
| 1248 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x40, 0x00, 0x00, | |
| 1249 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 1250 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, | |
| 1251 | 0x00, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x40, 0x00, 0x00, 0x00, 0x00, | |
| 1252 | 0x00, 0x00, 0x38, 0x44, 0x4C, 0x54, 0x64, 0x44, 0x38, 0x00, 0x00, 0x00, | |
| 1253 | 0x00, 0x00, 0x10, 0x30, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00, 0x00, 0x00, | |
| 1254 | 0x00, 0x00, 0x38, 0x44, 0x04, 0x38, 0x40, 0x40, 0x7C, 0x00, 0x00, 0x00, | |
| 1255 | 0x00, 0x00, 0x38, 0x44, 0x04, 0x08, 0x04, 0x44, 0x38, 0x00, 0x00, 0x00, | |
| 1256 | 0x00, 0x00, 0x08, 0x18, 0x28, 0x48, 0x7C, 0x08, 0x08, 0x00, 0x00, 0x00, | |
| 1257 | 0x00, 0x00, 0x7C, 0x40, 0x78, 0x04, 0x04, 0x44, 0x38, 0x00, 0x00, 0x00, | |
| 1258 | 0x00, 0x00, 0x38, 0x40, 0x40, 0x78, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, | |
| 1259 | 0x00, 0x00, 0x7C, 0x04, 0x08, 0x10, 0x20, 0x40, 0x40, 0x00, 0x00, 0x00, | |
| 1260 | 0x00, 0x00, 0x38, 0x44, 0x44, 0x38, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, | |
| 1261 | 0x00, 0x00, 0x38, 0x44, 0x44, 0x3C, 0x04, 0x04, 0x38, 0x00, 0x00, 0x00, | |
| 1262 | 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, | |
| 1263 | 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x10, 0x20, 0x00, 0x00, | |
| 1264 | 0x00, 0x00, 0x08, 0x10, 0x20, 0x40, 0x20, 0x10, 0x08, 0x00, 0x00, 0x00, | |
| 1265 | 0x00, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 1266 | 0x00, 0x00, 0x20, 0x10, 0x08, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x00, | |
| 1267 | 0x00, 0x00, 0x38, 0x44, 0x04, 0x08, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00, | |
| 1268 | ||
| 1269 | /* Lower case */ | |
| 1270 | 0x00, 0x00, 0x10, 0x28, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 1271 | 0x00, 0x00, 0x00, 0x00, 0x38, 0x04, 0x3C, 0x44, 0x3C, 0x00, 0x00, 0x00, | |
| 1272 | 0x00, 0x00, 0x40, 0x40, 0x58, 0x64, 0x44, 0x64, 0x58, 0x00, 0x00, 0x00, | |
| 1273 | 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, 0x40, 0x44, 0x38, 0x00, 0x00, 0x00, | |
| 1274 | 0x00, 0x00, 0x04, 0x04, 0x34, 0x4C, 0x44, 0x4C, 0x34, 0x00, 0x00, 0x00, | |
| 1275 | 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, 0x7C, 0x40, 0x38, 0x00, 0x00, 0x00, | |
| 1276 | 0x00, 0x00, 0x08, 0x14, 0x10, 0x38, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, | |
| 1277 | 0x00, 0x00, 0x00, 0x00, 0x34, 0x4C, 0x44, 0x4C, 0x34, 0x04, 0x38, 0x00, | |
| 1278 | 0x00, 0x00, 0x40, 0x40, 0x58, 0x64, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00, | |
| 1279 | 0x00, 0x00, 0x10, 0x00, 0x30, 0x10, 0x10, 0x10, 0x38, 0x00, 0x00, 0x00, | |
| 1280 | 0x00, 0x00, 0x04, 0x00, 0x04, 0x04, 0x04, 0x04, 0x44, 0x38, 0x00, 0x00, | |
| 1281 | 0x00, 0x00, 0x40, 0x40, 0x48, 0x50, 0x60, 0x50, 0x48, 0x00, 0x00, 0x00, | |
| 1282 | 0x00, 0x00, 0x30, 0x10, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00, 0x00, 0x00, | |
| 1283 | 0x00, 0x00, 0x00, 0x00, 0x78, 0x54, 0x54, 0x54, 0x54, 0x00, 0x00, 0x00, | |
| 1284 | 0x00, 0x00, 0x00, 0x00, 0x58, 0x64, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00, | |
| 1285 | 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, | |
| 1286 | 0x00, 0x00, 0x00, 0x00, 0x78, 0x44, 0x44, 0x44, 0x78, 0x40, 0x40, 0x00, | |
| 1287 | 0x00, 0x00, 0x00, 0x00, 0x3C, 0x44, 0x44, 0x44, 0x3C, 0x04, 0x04, 0x00, | |
| 1288 | 0x00, 0x00, 0x00, 0x00, 0x58, 0x64, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, | |
| 1289 | 0x00, 0x00, 0x00, 0x00, 0x3C, 0x40, 0x38, 0x04, 0x78, 0x00, 0x00, 0x00, | |
| 1290 | 0x00, 0x00, 0x20, 0x20, 0x70, 0x20, 0x20, 0x24, 0x18, 0x00, 0x00, 0x00, | |
| 1291 | 0x00, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x4C, 0x34, 0x00, 0x00, 0x00, | |
| 1292 | 0x00, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x28, 0x10, 0x00, 0x00, 0x00, | |
| 1293 | 0x00, 0x00, 0x00, 0x00, 0x44, 0x54, 0x54, 0x28, 0x28, 0x00, 0x00, 0x00, | |
| 1294 | 0x00, 0x00, 0x00, 0x00, 0x44, 0x28, 0x10, 0x28, 0x44, 0x00, 0x00, 0x00, | |
| 1295 | 0x00, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x3C, 0x04, 0x38, 0x00, 0x00, | |
| 1296 | 0x00, 0x00, 0x00, 0x00, 0x7C, 0x08, 0x10, 0x20, 0x7C, 0x00, 0x00, 0x00, | |
| 1297 | 0x00, 0x00, 0x08, 0x10, 0x10, 0x20, 0x10, 0x10, 0x08, 0x00, 0x00, 0x00, | |
| 1298 | 0x00, 0x00, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, | |
| 1299 | 0x00, 0x00, 0x20, 0x10, 0x10, 0x08, 0x10, 0x10, 0x20, 0x00, 0x00, 0x00, | |
| 1300 | 0x00, 0x00, 0x20, 0x54, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 1301 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00, | |
| 1302 | }; | |
| 1303 | ||
| 1304 | ||
| 1305 | ||
| 1306 | //------------------------------------------------- | |
| 1307 | // ntsc_square_fontdata8x12 | |
| 1308 | //------------------------------------------------- | |
| 1309 | ||
| 1310 | const UINT8 mc6847_friend_device::ntsc_square_fontdata8x12[] = | |
| 1311 | { | |
| 1312 | 0x00, 0x00, 0x00, 0x1C, 0x22, 0x02, 0x1A, 0x2A, 0x2A, 0x1C, 0x00, 0x00, | |
| 1313 | 0x00, 0x00, 0x00, 0x08, 0x14, 0x22, 0x22, 0x3E, 0x22, 0x22, 0x00, 0x00, | |
| 1314 | 0x00, 0x00, 0x00, 0x3C, 0x12, 0x12, 0x1C, 0x12, 0x12, 0x3C, 0x00, 0x00, | |
| 1315 | 0x00, 0x00, 0x00, 0x1C, 0x22, 0x20, 0x20, 0x20, 0x22, 0x1C, 0x00, 0x00, | |
| 1316 | 0x00, 0x00, 0x00, 0x3C, 0x12, 0x12, 0x12, 0x12, 0x12, 0x3C, 0x00, 0x00, | |
| 1317 | 0x00, 0x00, 0x00, 0x3E, 0x20, 0x20, 0x38, 0x20, 0x20, 0x3E, 0x00, 0x00, | |
| 1318 | 0x00, 0x00, 0x00, 0x3E, 0x20, 0x20, 0x38, 0x20, 0x20, 0x20, 0x00, 0x00, | |
| 1319 | 0x00, 0x00, 0x00, 0x1E, 0x20, 0x20, 0x26, 0x22, 0x22, 0x1E, 0x00, 0x00, | |
| 1320 | 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x3E, 0x22, 0x22, 0x22, 0x00, 0x00, | |
| 1321 | 0x00, 0x00, 0x00, 0x1C, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1C, 0x00, 0x00, | |
| 1322 | 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x22, 0x22, 0x1C, 0x00, 0x00, | |
| 1323 | 0x00, 0x00, 0x00, 0x22, 0x24, 0x28, 0x30, 0x28, 0x24, 0x22, 0x00, 0x00, | |
| 1324 | 0x00, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3E, 0x00, 0x00, | |
| 1325 | 0x00, 0x00, 0x00, 0x22, 0x36, 0x2A, 0x2A, 0x22, 0x22, 0x22, 0x00, 0x00, | |
| 1326 | 0x00, 0x00, 0x00, 0x22, 0x32, 0x2A, 0x26, 0x22, 0x22, 0x22, 0x00, 0x00, | |
| 1327 | 0x00, 0x00, 0x00, 0x3E, 0x22, 0x22, 0x22, 0x22, 0x22, 0x3E, 0x00, 0x00, | |
| 1328 | 0x00, 0x00, 0x00, 0x3C, 0x22, 0x22, 0x3C, 0x20, 0x20, 0x20, 0x00, 0x00, | |
| 1329 | 0x00, 0x00, 0x00, 0x1C, 0x22, 0x22, 0x22, 0x2A, 0x24, 0x1A, 0x00, 0x00, | |
| 1330 | 0x00, 0x00, 0x00, 0x3C, 0x22, 0x22, 0x3C, 0x28, 0x24, 0x22, 0x00, 0x00, | |
| 1331 | 0x00, 0x00, 0x00, 0x1C, 0x22, 0x10, 0x08, 0x04, 0x22, 0x1C, 0x00, 0x00, | |
| 1332 | 0x00, 0x00, 0x00, 0x3E, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, | |
| 1333 | 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x1C, 0x00, 0x00, | |
| 1334 | 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x14, 0x14, 0x08, 0x08, 0x00, 0x00, | |
| 1335 | 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x2A, 0x2A, 0x36, 0x22, 0x00, 0x00, | |
| 1336 | 0x00, 0x00, 0x00, 0x22, 0x22, 0x14, 0x08, 0x14, 0x22, 0x22, 0x00, 0x00, | |
| 1337 | 0x00, 0x00, 0x00, 0x22, 0x22, 0x14, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, | |
| 1338 | 0x00, 0x00, 0x00, 0x3E, 0x02, 0x04, 0x08, 0x10, 0x20, 0x3E, 0x00, 0x00, | |
| 1339 | 0x00, 0x00, 0x00, 0x38, 0x20, 0x20, 0x20, 0x20, 0x20, 0x38, 0x00, 0x00, | |
| 1340 | 0x00, 0x00, 0x00, 0x20, 0x20, 0x10, 0x08, 0x04, 0x02, 0x02, 0x00, 0x00, | |
| 1341 | 0x00, 0x00, 0x00, 0x0E, 0x02, 0x02, 0x02, 0x02, 0x02, 0x0E, 0x00, 0x00, | |
| 1342 | 0x00, 0x00, 0x00, 0x08, 0x1C, 0x2A, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, | |
| 1343 | 0x00, 0x00, 0x00, 0x00, 0x08, 0x10, 0x3E, 0x10, 0x08, 0x00, 0x00, 0x00, | |
| 1344 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 1345 | 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x08, 0x00, 0x00, | |
| 1346 | 0x00, 0x00, 0x00, 0x14, 0x14, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 1347 | 0x00, 0x00, 0x00, 0x14, 0x14, 0x36, 0x00, 0x36, 0x14, 0x14, 0x00, 0x00, | |
| 1348 | 0x00, 0x00, 0x00, 0x08, 0x1E, 0x20, 0x1C, 0x02, 0x3C, 0x08, 0x00, 0x00, | |
| 1349 | 0x00, 0x00, 0x00, 0x32, 0x32, 0x04, 0x08, 0x10, 0x26, 0x26, 0x00, 0x00, | |
| 1350 | 0x00, 0x00, 0x00, 0x10, 0x28, 0x28, 0x10, 0x2A, 0x24, 0x1A, 0x00, 0x00, | |
| 1351 | 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 1352 | 0x00, 0x00, 0x00, 0x08, 0x10, 0x20, 0x20, 0x20, 0x10, 0x08, 0x00, 0x00, | |
| 1353 | 0x00, 0x00, 0x00, 0x08, 0x04, 0x02, 0x02, 0x02, 0x04, 0x08, 0x00, 0x00, | |
| 1354 | 0x00, 0x00, 0x00, 0x00, 0x08, 0x1C, 0x3E, 0x1C, 0x08, 0x00, 0x00, 0x00, | |
| 1355 | 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x3E, 0x08, 0x08, 0x00, 0x00, 0x00, | |
| 1356 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x10, 0x20, 0x00, 0x00, | |
| 1357 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 1358 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, | |
| 1359 | 0x00, 0x00, 0x00, 0x02, 0x02, 0x04, 0x08, 0x10, 0x20, 0x20, 0x00, 0x00, | |
| 1360 | 0x00, 0x00, 0x00, 0x18, 0x24, 0x24, 0x24, 0x24, 0x24, 0x18, 0x00, 0x00, | |
| 1361 | 0x00, 0x00, 0x00, 0x08, 0x18, 0x08, 0x08, 0x08, 0x08, 0x1C, 0x00, 0x00, | |
| 1362 | 0x00, 0x00, 0x00, 0x1C, 0x22, 0x02, 0x1C, 0x20, 0x20, 0x3E, 0x00, 0x00, | |
| 1363 | 0x00, 0x00, 0x00, 0x1C, 0x22, 0x02, 0x04, 0x02, 0x22, 0x1C, 0x00, 0x00, | |
| 1364 | 0x00, 0x00, 0x00, 0x04, 0x0C, 0x14, 0x3E, 0x04, 0x04, 0x04, 0x00, 0x00, | |
| 1365 | 0x00, 0x00, 0x00, 0x3E, 0x20, 0x3C, 0x02, 0x02, 0x22, 0x1C, 0x00, 0x00, | |
| 1366 | 0x00, 0x00, 0x00, 0x1C, 0x20, 0x20, 0x3C, 0x22, 0x22, 0x1C, 0x00, 0x00, | |
| 1367 | 0x00, 0x00, 0x00, 0x3E, 0x02, 0x04, 0x08, 0x10, 0x20, 0x20, 0x00, 0x00, | |
| 1368 | 0x00, 0x00, 0x00, 0x1C, 0x22, 0x22, 0x1C, 0x22, 0x22, 0x1C, 0x00, 0x00, | |
| 1369 | 0x00, 0x00, 0x00, 0x1C, 0x22, 0x22, 0x1E, 0x02, 0x02, 0x1C, 0x00, 0x00, | |
| 1370 | 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, | |
| 1371 | 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x08, 0x10, 0x00, 0x00, | |
| 1372 | 0x00, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x10, 0x08, 0x04, 0x00, 0x00, | |
| 1373 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, | |
| 1374 | 0x00, 0x00, 0x00, 0x10, 0x08, 0x04, 0x02, 0x04, 0x08, 0x10, 0x00, 0x00, | |
| 1375 | 0x00, 0x00, 0x00, 0x18, 0x24, 0x04, 0x08, 0x08, 0x00, 0x08, 0x00, 0x00, | |
| 1376 | ||
| 1377 | /* Lower case */ | |
| 1378 | 0x00, 0x00, 0x00, 0x0C, 0x12, 0x10, 0x38, 0x10, 0x12, 0x3C, 0x00, 0x00, | |
| 1379 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x02, 0x1E, 0x22, 0x1E, 0x00, 0x00, | |
| 1380 | 0x00, 0x00, 0x00, 0x20, 0x20, 0x3C, 0x22, 0x22, 0x22, 0x3C, 0x00, 0x00, | |
| 1381 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x20, 0x20, 0x20, 0x1C, 0x00, 0x00, | |
| 1382 | 0x00, 0x00, 0x00, 0x02, 0x02, 0x1E, 0x22, 0x22, 0x22, 0x1E, 0x00, 0x00, | |
| 1383 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x22, 0x3E, 0x20, 0x1C, 0x00, 0x00, | |
| 1384 | 0x00, 0x00, 0x00, 0x0C, 0x12, 0x10, 0x38, 0x10, 0x10, 0x10, 0x00, 0x00, | |
| 1385 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x22, 0x22, 0x22, 0x1E, 0x02, 0x1C, | |
| 1386 | 0x00, 0x00, 0x00, 0x20, 0x20, 0x3C, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, | |
| 1387 | 0x00, 0x00, 0x00, 0x08, 0x00, 0x18, 0x08, 0x08, 0x08, 0x1C, 0x00, 0x00, | |
| 1388 | 0x00, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x04, 0x04, 0x04, 0x04, 0x24, 0x18, | |
| 1389 | 0x00, 0x00, 0x00, 0x20, 0x20, 0x24, 0x28, 0x38, 0x24, 0x22, 0x00, 0x00, | |
| 1390 | 0x00, 0x00, 0x00, 0x18, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1C, 0x00, 0x00, | |
| 1391 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x2A, 0x2A, 0x2A, 0x2A, 0x00, 0x00, | |
| 1392 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x2C, 0x32, 0x22, 0x22, 0x22, 0x00, 0x00, | |
| 1393 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x22, 0x22, 0x22, 0x1C, 0x00, 0x00, | |
| 1394 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x22, 0x22, 0x22, 0x3C, 0x20, 0x20, | |
| 1395 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x22, 0x22, 0x22, 0x1E, 0x02, 0x03, | |
| 1396 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x2C, 0x32, 0x20, 0x20, 0x20, 0x00, 0x00, | |
| 1397 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x20, 0x1C, 0x02, 0x3C, 0x00, 0x00, | |
| 1398 | 0x00, 0x00, 0x00, 0x10, 0x3C, 0x10, 0x10, 0x10, 0x12, 0x0C, 0x00, 0x00, | |
| 1399 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x26, 0x1A, 0x00, 0x00, | |
| 1400 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x14, 0x14, 0x08, 0x00, 0x00, | |
| 1401 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x2A, 0x2A, 0x1C, 0x14, 0x00, 0x00, | |
| 1402 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x14, 0x08, 0x14, 0x22, 0x00, 0x00, | |
| 1403 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x1E, 0x02, 0x1C, | |
| 1404 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x04, 0x08, 0x10, 0x3E, 0x00, 0x00, | |
| 1405 | 0x00, 0x00, 0x00, 0x08, 0x10, 0x10, 0x20, 0x10, 0x10, 0x08, 0x00, 0x00, | |
| 1406 | 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x00, 0x08, 0x08, 0x08, 0x00, 0x00, | |
| 1407 | 0x00, 0x00, 0x00, 0x08, 0x04, 0x04, 0x02, 0x04, 0x04, 0x08, 0x00, 0x00, | |
| 1408 | 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x2A, 0x1C, 0x08, 0x00, 0x00, | |
| 1409 | 0x00, 0x00, 0x00, 0x08, 0x04, 0x3E, 0x04, 0x08, 0x00, 0x00, 0x00, 0x00 | |
| 1410 | }; | |
| 1411 | ||
| 1412 | ||
| 1413 | ||
| 1414 | //------------------------------------------------- | |
| 1415 | // semigraphics4_fontdata8x12 | |
| 1416 | //------------------------------------------------- | |
| 1417 | ||
| 1418 | const UINT8 mc6847_friend_device::semigraphics4_fontdata8x12[] = | |
| 1419 | { | |
| 1420 | /* Block Graphics (Semigraphics 4 Graphics ) */ | |
| 1421 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 1422 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, | |
| 1423 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, | |
| 1424 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, | |
| 1425 | 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 1426 | 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, | |
| 1427 | 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, | |
| 1428 | 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, | |
| 1429 | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 1430 | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, | |
| 1431 | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, | |
| 1432 | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, | |
| 1433 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 1434 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, | |
| 1435 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, | |
| 1436 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF | |
| 1437 | }; | |
| 1438 | ||
| 1439 | ||
| 1440 | ||
| 1441 | //------------------------------------------------- | |
| 1442 | // semigraphics6_fontdata8x12 | |
| 1443 | //------------------------------------------------- | |
| 1444 | ||
| 1445 | const UINT8 mc6847_friend_device::semigraphics6_fontdata8x12[] = | |
| 1446 | { | |
| 1447 | /* Semigraphics 6 */ | |
| 1448 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 1449 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, | |
| 1450 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, | |
| 1451 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, | |
| 1452 | 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, | |
| 1453 | 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, | |
| 1454 | 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, 0xF0, 0xF0, 0xF0, 0xF0, | |
| 1455 | 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, | |
| 1456 | 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00, | |
| 1457 | 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F, | |
| 1458 | 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, | |
| 1459 | 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, | |
| 1460 | 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, | |
| 1461 | 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, | |
| 1462 | 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0, | |
| 1463 | 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, | |
| 1464 | 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 1465 | 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, | |
| 1466 | 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, | |
| 1467 | 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, | |
| 1468 | 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, | |
| 1469 | 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, | |
| 1470 | 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0xF0, 0xF0, 0xF0, 0xF0, | |
| 1471 | 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, | |
| 1472 | 0x0F, 0x0F, 0x0F, 0x0F, 0xF0, 0xF0, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00, | |
| 1473 | 0x0F, 0x0F, 0x0F, 0x0F, 0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F, | |
| 1474 | 0x0F, 0x0F, 0x0F, 0x0F, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, | |
| 1475 | 0x0F, 0x0F, 0x0F, 0x0F, 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, | |
| 1476 | 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, | |
| 1477 | 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, | |
| 1478 | 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0, | |
| 1479 | 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, | |
| 1480 | 0xF0, 0xF0, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 1481 | 0xF0, 0xF0, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, | |
| 1482 | 0xF0, 0xF0, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, | |
| 1483 | 0xF0, 0xF0, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, | |
| 1484 | 0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, | |
| 1485 | 0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, | |
| 1486 | 0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F, 0xF0, 0xF0, 0xF0, 0xF0, | |
| 1487 | 0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, | |
| 1488 | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00, | |
| 1489 | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F, | |
| 1490 | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, | |
| 1491 | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, | |
| 1492 | 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, | |
| 1493 | 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, | |
| 1494 | 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0, | |
| 1495 | 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, | |
| 1496 | 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 1497 | 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, | |
| 1498 | 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, | |
| 1499 | 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, | |
| 1500 | 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, | |
| 1501 | 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, | |
| 1502 | 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, 0xF0, 0xF0, 0xF0, 0xF0, | |
| 1503 | 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, | |
| 1504 | 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00, | |
| 1505 | 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F, | |
| 1506 | 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, | |
| 1507 | 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, | |
| 1508 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, | |
| 1509 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, | |
| 1510 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0, | |
| 1511 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF | |
| 1512 | }; | |
| 1513 | ||
| 1514 | ||
| 1515 | ||
| 1516 | //************************************************************************** | |
| 1517 | // ARTIFACTING | |
| 1518 | //************************************************************************** | |
| 1519 | ||
| 1520 | INPUT_PORTS_START(mc6847_artifacting) | |
| 1521 | PORT_START(ARTIFACTING_TAG) | |
| 1522 | PORT_CONFNAME( 0x03, 0x01, "Artifacting" ) | |
| 1523 | PORT_CONFSETTING( 0x00, DEF_STR( Off ) ) | |
| 1524 | PORT_CONFSETTING( 0x01, DEF_STR( Standard ) ) | |
| 1525 | PORT_CONFSETTING( 0x02, DEF_STR( Reverse ) ) | |
| 1526 | INPUT_PORTS_END | |
| 1527 | ||
| 1528 | ioport_constructor mc6847_base_device::device_input_ports() const | |
| 1529 | { | |
| 1530 | return INPUT_PORTS_NAME(mc6847_artifacting); | |
| 1531 | } | |
| 1532 | ||
| 1533 | ||
| 1534 | ||
| 1535 | //------------------------------------------------- | |
| 1536 | // ctor | |
| 1537 | //------------------------------------------------- | |
| 1538 | ||
| 1539 | mc6847_base_device::artifacter::artifacter() | |
| 1540 | { | |
| 1541 | m_config = NULL; | |
| 1542 | m_artifacting = 0; | |
| 1543 | m_saved_artifacting = 0; | |
| 1544 | m_saved_c0 = 0; | |
| 1545 | m_saved_c1 = 0; | |
| 1546 | memset(m_expanded_colors, 0, sizeof(m_expanded_colors)); | |
| 1547 | } | |
| 1548 | ||
| 1549 | ||
| 1550 | ||
| 1551 | //------------------------------------------------- | |
| 1552 | // artifacter::setup_config | |
| 1553 | //------------------------------------------------- | |
| 1554 | ||
| 1555 | void mc6847_base_device::artifacter::setup_config(device_t *device) | |
| 1556 | { | |
| 1557 | char port_name[32]; | |
| 1558 | snprintf(port_name, ARRAY_LENGTH(port_name), "%s:%s", device->tag(), ARTIFACTING_TAG); | |
| 1559 | m_config = device->ioport(port_name); | |
| 1560 | } | |
| 1561 | ||
| 1562 | ||
| 1563 | ||
| 1564 | //------------------------------------------------- | |
| 1565 | // artifacter::update_colors | |
| 1566 | //------------------------------------------------- | |
| 1567 | ||
| 1568 | void mc6847_base_device::artifacter::update_colors(pixel_t c0, pixel_t c1) | |
| 1569 | { | |
| 1570 | /* Boy this code sucks; this code was adapted from the old M6847 | |
| 1571 | * artifacting implmentation. The only reason that it didn't look as | |
| 1572 | * horrible was because the code around it sucked as well. Now that I | |
| 1573 | * have cleaned everything up, the ugliness is much more prominent. | |
| 1574 | * | |
| 1575 | * Hopefully we will have a generic artifacting algorithm that plugs into | |
| 1576 | * the MESS/MAME core directly so we can chuck this hack */ | |
| 1577 | static const double artifact_colors[14*3] = | |
| 1578 | { | |
| 1579 | 0.157, 0.000, 0.157, /* [ 1] - dk purple (reverse 2) */ | |
| 1580 | 0.000, 0.157, 0.000, /* [ 2] - dk green (reverse 1) */ | |
| 1581 | 1.000, 0.824, 1.000, /* [ 3] - lt purple (reverse 4) */ | |
| 1582 | 0.824, 1.000, 0.824, /* [ 4] - lt green (reverse 3) */ | |
| 1583 | 0.706, 0.236, 0.118, /* [ 5] - dk blue (reverse 6) */ | |
| 1584 | 0.000, 0.197, 0.471, /* [ 6] - dk red (reverse 5) */ | |
| 1585 | 1.000, 0.550, 0.393, /* [ 7] - lt blue (reverse 8) */ | |
| 1586 | 0.275, 0.785, 1.000, /* [ 8] - lt red (reverse 7) */ | |
| 1587 | 0.000, 0.500, 1.000, /* [ 9] - red (reverse 10) */ | |
| 1588 | 1.000, 0.500, 0.000, /* [10] - blue (reverse 9) */ | |
| 1589 | 1.000, 0.942, 0.785, /* [11] - cyan (reverse 12) */ | |
| 1590 | 0.393, 0.942, 1.000, /* [12] - yellow (reverse 11) */ | |
| 1591 | 0.236, 0.000, 0.000, /* [13] - black-blue (reverse 14) */ | |
| 1592 | 0.000, 0.000, 0.236 /* [14] - black-red (reverse 13) */ | |
| 1593 | }; | |
| 1594 | ||
| 1595 | static const UINT8 artifact_correction[128] = | |
| 1596 | { | |
| 1597 | 0, 0, 0, 0, 0, 6, 0, 2, | |
| 1598 | 5, 7, 5, 7, 1, 3, 1, 11, | |
| 1599 | 8, 6, 8, 14, 8, 9, 8, 9, | |
| 1600 | 4, 4, 4, 15, 12, 12, 12, 15, | |
| 1601 | ||
| 1602 | 5, 13, 5, 13, 13, 0, 13, 2, | |
| 1603 | 10, 10, 10, 10, 10, 15, 10, 11, | |
| 1604 | 3, 1, 3, 1, 15, 9, 15, 9, | |
| 1605 | 11, 11, 11, 11, 15, 15, 15, 15, | |
| 1606 | ||
| 1607 | 14, 0, 14, 0, 14, 6, 14, 2, | |
| 1608 | 0, 7, 0, 7, 1, 3, 1, 11, | |
| 1609 | 9, 6, 9, 14, 9, 9, 9, 9, | |
| 1610 | 15, 4, 15, 15, 12, 12, 12, 15, | |
| 1611 | ||
| 1612 | 2, 13, 2, 13, 2, 0, 2, 2, | |
| 1613 | 10, 10, 10, 10, 10, 15, 10, 11, | |
| 1614 | 12, 1, 12, 1, 12, 9, 12, 9, | |
| 1615 | 15, 11, 15, 11, 15, 15, 15, 15 | |
| 1616 | }; | |
| 1617 | ||
| 1618 | pixel_t colors[16]; | |
| 1619 | int i; | |
| 1620 | ||
| 1621 | /* do we need to update our artifact colors table? */ | |
| 1622 | if ((m_artifacting != m_saved_artifacting) || (c0 != m_saved_c0) || (c1 != m_saved_c1)) | |
| 1623 | { | |
| 1624 | m_saved_artifacting = m_artifacting; | |
| 1625 | m_saved_c0 = colors[0] = c0; | |
| 1626 | m_saved_c1 = colors[15] = c1; | |
| 1627 | ||
| 1628 | /* mix the other colors */ | |
| 1629 | for (i = 1; i <= 14; i++) | |
| 1630 | { | |
| 1631 | const double *factors = &artifact_colors[((i - 1) ^ (m_artifacting & 0x01)) * 3]; | |
| 1632 | ||
| 1633 | colors[i] = (mix_color(factors[0], c0 >> 16, c1 >> 16) << 16) | |
| 1634 | | (mix_color(factors[1], c0 >> 8, c1 >> 8) << 8) | |
| 1635 | | (mix_color(factors[2], c0 >> 0, c1 >> 0) << 0); | |
| 1636 | } | |
| 1637 | for (i = 0; i < 128; i++) | |
| 1638 | { | |
| 1639 | m_expanded_colors[i] = colors[artifact_correction[i]]; | |
| 1640 | } | |
| 1641 | } | |
| 1642 | } | |
| 1643 | ||
| 1644 | ||
| 1645 | ||
| 1646 | //------------------------------------------------- | |
| 1647 | // artifacter::update | |
| 1648 | //------------------------------------------------- | |
| 1649 | ||
| 1650 | mc6847_base_device::pixel_t mc6847_base_device::artifacter::mix_color(double factor, UINT8 c0, UINT8 c1) | |
| 1651 | { | |
| 1652 | return (UINT32) (UINT8) ((c0 * (1.0 - factor)) + (c1 * (0.0 + factor)) + 0.5); | |
| 1653 | } | |
| 1654 | ||
| 1655 | ||
| 1656 | ||
| 1657 | //************************************************************************** | |
| 1658 | // VARIATIONS | |
| 1659 | //************************************************************************** | |
| 1660 | ||
| 1661 | const device_type MC6847_NTSC = &device_creator<mc6847_ntsc_device>; | |
| 1662 | const device_type MC6847_PAL = &device_creator<mc6847_pal_device>; | |
| 1663 | const device_type MC6847Y_NTSC = &device_creator<mc6847y_ntsc_device>; | |
| 1664 | const device_type MC6847Y_PAL = &device_creator<mc6847y_pal_device>; | |
| 1665 | const device_type MC6847T1_NTSC = &device_creator<mc6847t1_ntsc_device>; | |
| 1666 | const device_type MC6847T1_PAL = &device_creator<mc6847t1_pal_device>; | |
| 1667 | ||
| 1668 | ||
| 1669 | ||
| 1670 | //------------------------------------------------- | |
| 1671 | // mc6847_ntsc_device | |
| 1672 | //------------------------------------------------- | |
| 1673 | ||
| 1674 | mc6847_ntsc_device::mc6847_ntsc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) | |
| 1675 | : mc6847_base_device(mconfig, MC6847_NTSC, "MC6847_NTSC", tag, owner, clock, ntsc_square_fontdata8x12, 262.0) | |
| 1676 | { | |
| 1677 | } | |
| 1678 | ||
| 1679 | ||
| 1680 | ||
| 1681 | //------------------------------------------------- | |
| 1682 | // mc6847_pal_device | |
| 1683 | //------------------------------------------------- | |
| 1684 | ||
| 1685 | mc6847_pal_device::mc6847_pal_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) | |
| 1686 | : mc6847_base_device(mconfig, MC6847_PAL, "MC6847_PAL", tag, owner, clock, pal_square_fontdata8x12, 262.0) | |
| 1687 | { | |
| 1688 | } | |
| 1689 | ||
| 1690 | ||
| 1691 | ||
| 1692 | //------------------------------------------------- | |
| 1693 | // mc6847y_ntsc_device | |
| 1694 | //------------------------------------------------- | |
| 1695 | ||
| 1696 | mc6847y_ntsc_device::mc6847y_ntsc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) | |
| 1697 | : mc6847_base_device(mconfig, MC6847Y_NTSC, "MC6847Y_NTSC", tag, owner, clock, ntsc_square_fontdata8x12, 262.5) | |
| 1698 | { | |
| 1699 | } | |
| 1700 | ||
| 1701 | ||
| 1702 | ||
| 1703 | //------------------------------------------------- | |
| 1704 | // mc6847y_pal_device | |
| 1705 | //------------------------------------------------- | |
| 1706 | ||
| 1707 | mc6847y_pal_device::mc6847y_pal_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) | |
| 1708 | : mc6847_base_device(mconfig, MC6847Y_PAL, "MC6847Y_PAL", tag, owner, clock, pal_square_fontdata8x12, 262.5) | |
| 1709 | { | |
| 1710 | } | |
| 1711 | ||
| 1712 | ||
| 1713 | ||
| 1714 | //------------------------------------------------- | |
| 1715 | // mc6847t1_ntsc_device | |
| 1716 | //------------------------------------------------- | |
| 1717 | ||
| 1718 | mc6847t1_ntsc_device::mc6847t1_ntsc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) | |
| 1719 | : mc6847_base_device(mconfig, MC6847T1_NTSC, "MC6847T1_NTSC", tag, owner, clock, ntsc_round_fontdata8x12, 262.0) | |
| 1720 | { | |
| 1721 | } | |
| 1722 | ||
| 1723 | ||
| 1724 | ||
| 1725 | //------------------------------------------------- | |
| 1726 | // mc6847t1_pal_device | |
| 1727 | //------------------------------------------------- | |
| 1728 | ||
| 1729 | mc6847t1_pal_device::mc6847t1_pal_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) | |
| 1730 | : mc6847_base_device(mconfig, MC6847T1_PAL, "MC6847T1_PAL", tag, owner, clock, pal_round_fontdata8x12, 262.0) | |
| 1731 | { | |
| 1732 | } |
| r21684 | r21685 | |
|---|---|---|
| 1 | /*************************************************************************** | |
| 2 | ||
| 3 | Texas Instruments TMS3556 Video Display Processor | |
| 4 | ||
| 5 | ***************************************************************************/ | |
| 6 | ||
| 7 | ||
| 8 | #pragma once | |
| 9 | ||
| 10 | #ifndef __TMS3556_H__ | |
| 11 | #define __TMS3556_H__ | |
| 12 | ||
| 13 | ///************************************************************************* | |
| 14 | // MACROS / CONSTANTS | |
| 15 | ///************************************************************************* | |
| 16 | ||
| 17 | #define TMS3556_TOP_BORDER 1 | |
| 18 | #define TMS3556_BOTTOM_BORDER 1 | |
| 19 | #define TMS3556_LEFT_BORDER 8 | |
| 20 | #define TMS3556_RIGHT_BORDER 8 | |
| 21 | #define TMS3556_TOTAL_WIDTH (320 + TMS3556_LEFT_BORDER + TMS3556_RIGHT_BORDER) | |
| 22 | #define TMS3556_TOTAL_HEIGHT (250 + TMS3556_TOP_BORDER + TMS3556_BOTTOM_BORDER) | |
| 23 | ||
| 24 | /* if DOUBLE_WIDTH set, the horizontal resolution is doubled */ | |
| 25 | #define TMS3556_DOUBLE_WIDTH 1 | |
| 26 | ||
| 27 | #define TMS3556_MODE_OFF 0 | |
| 28 | #define TMS3556_MODE_TEXT 1 | |
| 29 | #define TMS3556_MODE_BITMAP 2 | |
| 30 | #define TMS3556_MODE_MIXED 3 | |
| 31 | ||
| 32 | ||
| 33 | ///************************************************************************* | |
| 34 | // INTERFACE CONFIGURATION MACROS | |
| 35 | ///************************************************************************* | |
| 36 | ||
| 37 | #define MCFG_TMS3556_ADD(_tag) \ | |
| 38 | MCFG_DEVICE_ADD(_tag, TMS3556, 0) | |
| 39 | ||
| 40 | ///************************************************************************* | |
| 41 | // TYPE DEFINITIONS | |
| 42 | ///************************************************************************* | |
| 43 | ||
| 44 | // ======================> tms3556_device | |
| 45 | ||
| 46 | class tms3556_device : public device_t, | |
| 47 | public device_memory_interface | |
| 48 | { | |
| 49 | public: | |
| 50 | // construction/destruction | |
| 51 | tms3556_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); | |
| 52 | ||
| 53 | DECLARE_READ8_MEMBER( vram_r ); | |
| 54 | DECLARE_WRITE8_MEMBER( vram_w ); | |
| 55 | DECLARE_READ8_MEMBER( reg_r ); | |
| 56 | DECLARE_WRITE8_MEMBER( reg_w ); | |
| 57 | ||
| 58 | void interrupt(running_machine &machine); | |
| 59 | ||
| 60 | UINT32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); | |
| 61 | ||
| 62 | protected: | |
| 63 | // device-level overrides | |
| 64 | virtual void device_start(); | |
| 65 | ||
| 66 | // device_config_memory_interface overrides | |
| 67 | virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; | |
| 68 | ||
| 69 | // address space configurations | |
| 70 | const address_space_config m_space_config; | |
| 71 | ||
| 72 | inline UINT8 readbyte(offs_t address); | |
| 73 | inline void writebyte(offs_t address, UINT8 data); | |
| 74 | ||
| 75 | void draw_line_empty(UINT16 *ln); | |
| 76 | void draw_line_text_common(UINT16 *ln); | |
| 77 | void draw_line_bitmap_common(UINT16 *ln); | |
| 78 | void draw_line_text(UINT16 *ln); | |
| 79 | void draw_line_bitmap(UINT16 *ln); | |
| 80 | void draw_line_mixed(UINT16 *ln); | |
| 81 | void draw_line(bitmap_ind16 &bmp, int line); | |
| 82 | void interrupt_start_vblank(void); | |
| 83 | ||
| 84 | private: | |
| 85 | // registers | |
| 86 | UINT8 m_control_regs[8]; | |
| 87 | UINT16 m_address_regs[8]; | |
| 88 | UINT16 m_write_ptr; | |
| 89 | ||
| 90 | // register interface | |
| 91 | int m_reg_ptr; | |
| 92 | int m_reg_access_phase; | |
| 93 | int m_magical_mystery_flag; | |
| 94 | ||
| 95 | int m_scanline; // scanline counter | |
| 96 | int m_blink, m_blink_count; // blinking | |
| 97 | int m_bg_color; // background color for current line | |
| 98 | int m_name_offset; // current offset in name table | |
| 99 | int m_cg_flag; // c/g flag (mixed mode only) | |
| 100 | int m_char_line_counter; // character line counter (decrements from 10, 0 when we have reached | |
| 101 | // last line of character row) | |
| 102 | int m_dbl_h_phase[40]; // double height phase flags (one per horizontal character position) | |
| 103 | ||
| 104 | bitmap_ind16 m_bitmap; | |
| 105 | }; | |
| 106 | ||
| 107 | ||
| 108 | // device type definition | |
| 109 | extern const device_type TMS3556; | |
| 110 | ||
| 111 | ||
| 112 | #endif |
| r21684 | r21685 | |
|---|---|---|
| 1 | /********************************************************************* | |
| 2 | ||
| 3 | mc6847.h | |
| 4 | ||
| 5 | Implementation of Motorola 6847 video hardware chip | |
| 6 | ||
| 7 | ***************************************************************************/ | |
| 8 | ||
| 9 | #pragma once | |
| 10 | ||
| 11 | #ifndef __MC6847__ | |
| 12 | #define __MC6847__ | |
| 13 | ||
| 14 | ||
| 15 | //************************************************************************** | |
| 16 | // MC6847 CONFIGURATION / INTERFACE | |
| 17 | //************************************************************************** | |
| 18 | ||
| 19 | #define MCFG_MC6847_REMOVE(_tag) \ | |
| 20 | MCFG_DEVICE_REMOVE(_tag) | |
| 21 | ||
| 22 | #define MCFG_MC6847_ADD(_tag, _variant, _clock, _config) \ | |
| 23 | MCFG_DEVICE_ADD(_tag, _variant, _clock) \ | |
| 24 | MCFG_DEVICE_CONFIG(_config) | |
| 25 | ||
| 26 | #define MCFG_SCREEN_MC6847_NTSC_ADD(_tag, _mctag) \ | |
| 27 | MCFG_SCREEN_ADD(_tag, RASTER) \ | |
| 28 | MCFG_SCREEN_UPDATE_DEVICE(_mctag, mc6847_base_device, screen_update) \ | |
| 29 | MCFG_SCREEN_REFRESH_RATE(60) \ | |
| 30 | MCFG_SCREEN_SIZE(320, 243) \ | |
| 31 | MCFG_SCREEN_VISIBLE_AREA(0, 320-1, 1, 241-1) \ | |
| 32 | MCFG_SCREEN_VBLANK_TIME(0) | |
| 33 | #define MCFG_SCREEN_MC6847_PAL_ADD(_tag, _mctag) \ | |
| 34 | MCFG_SCREEN_ADD(_tag, RASTER) \ | |
| 35 | MCFG_SCREEN_UPDATE_DEVICE(_mctag, mc6847_base_device, screen_update) \ | |
| 36 | MCFG_SCREEN_REFRESH_RATE(50) \ | |
| 37 | MCFG_SCREEN_SIZE(320, 243) \ | |
| 38 | MCFG_SCREEN_VISIBLE_AREA(0, 320-1, 1, 241-1) \ | |
| 39 | MCFG_SCREEN_VBLANK_TIME(0) | |
| 40 | /* interface */ | |
| 41 | struct mc6847_interface | |
| 42 | { | |
| 43 | /* screen we are acting on */ | |
| 44 | const char *m_screen_tag; | |
| 45 | ||
| 46 | /* if specified, this gets called whenever reading a byte (offs_t ~0 specifies DA* entering the tristate mode) */ | |
| 47 | devcb_read8 m_input_func; | |
| 48 | ||
| 49 | /* if specified, this gets called for every change of the HS pin (pin 38) */ | |
| 50 | devcb_write_line m_out_hsync_func; | |
| 51 | ||
| 52 | /* if specified, this gets called for every change of the FS pin (pin 37) */ | |
| 53 | devcb_write_line m_out_fsync_func; | |
| 54 | ||
| 55 | /* mode control lines input */ | |
| 56 | devcb_read_line m_in_ag_func; | |
| 57 | devcb_read_line m_in_gm2_func; | |
| 58 | devcb_read_line m_in_gm1_func; | |
| 59 | devcb_read_line m_in_gm0_func; | |
| 60 | devcb_read_line m_in_css_func; | |
| 61 | devcb_read_line m_in_as_func; | |
| 62 | devcb_read_line m_in_intext_func; | |
| 63 | devcb_read_line m_in_inv_func; | |
| 64 | ||
| 65 | /* if specified, this reads the external char rom off of the driver state */ | |
| 66 | UINT8 (*m_get_char_rom)(running_machine &machine, UINT8 ch, int line); | |
| 67 | ||
| 68 | /* if true, this is black and white */ | |
| 69 | bool m_black_and_white; | |
| 70 | }; | |
| 71 | ||
| 72 | #define ARTIFACTING_TAG "artifacting" | |
| 73 | ||
| 74 | INPUT_PORTS_EXTERN(mc6847_artifacting); | |
| 75 | ||
| 76 | ||
| 77 | //************************************************************************** | |
| 78 | // MC6847 CORE | |
| 79 | //************************************************************************** | |
| 80 | ||
| 81 | PALETTE_INIT( mc6847 ); | |
| 82 | PALETTE_INIT( mc6847_bw ); | |
| 83 | ||
| 84 | // base class so that the GIME emulation can access mc6847 stuff | |
| 85 | class mc6847_friend_device : public device_t | |
| 86 | { | |
| 87 | public: | |
| 88 | // inlines | |
| 89 | bool hs_r(void) { return m_horizontal_sync; } | |
| 90 | bool fs_r(void) { return m_field_sync; } | |
| 91 | ||
| 92 | protected: | |
| 93 | mc6847_friend_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, | |
| 94 | const UINT8 *fontdata, bool is_mc6847t1, double tpfs, int field_sync_falling_edge_scanline, bool supports_partial_body_scanlines); | |
| 95 | ||
| 96 | // video mode constants | |
| 97 | static const UINT8 MODE_AG = 0x80; | |
| 98 | static const UINT8 MODE_GM2 = 0x40; | |
| 99 | static const UINT8 MODE_GM1 = 0x20; | |
| 100 | static const UINT8 MODE_GM0 = 0x10; | |
| 101 | static const UINT8 MODE_CSS = 0x08; | |
| 102 | static const UINT8 MODE_AS = 0x04; | |
| 103 | static const UINT8 MODE_INTEXT = 0x02; | |
| 104 | static const UINT8 MODE_INV = 0x01; | |
| 105 | ||
| 106 | // timer constants | |
| 107 | static const device_timer_id TIMER_FRAME = 0; | |
| 108 | static const device_timer_id TIMER_HSYNC_OFF = 1; | |
| 109 | static const device_timer_id TIMER_HSYNC_ON = 2; | |
| 110 | static const device_timer_id TIMER_FSYNC = 3; | |
| 111 | ||
| 112 | // fonts | |
| 113 | static const UINT8 pal_round_fontdata8x12[]; | |
| 114 | static const UINT8 pal_square_fontdata8x12[]; | |
| 115 | static const UINT8 ntsc_round_fontdata8x12[]; | |
| 116 | static const UINT8 ntsc_square_fontdata8x12[]; | |
| 117 | static const UINT8 semigraphics4_fontdata8x12[]; | |
| 118 | static const UINT8 semigraphics6_fontdata8x12[]; | |
| 119 | ||
| 120 | // pixel definitions | |
| 121 | typedef UINT32 pixel_t; | |
| 122 | ||
| 123 | pixel_t *bitmap_addr(bitmap_rgb32 &bitmap, int y, int x) | |
| 124 | { | |
| 125 | return &bitmap.pix32(y, x); | |
| 126 | } | |
| 127 | ||
| 128 | static UINT8 simplify_mode(UINT8 data, UINT8 mode) | |
| 129 | { | |
| 130 | // simplifies MC6847 modes to drop mode flags that are not significant | |
| 131 | return mode & ~((mode & MODE_AG) ? (MODE_AS | MODE_INV) : 0); | |
| 132 | } | |
| 133 | ||
| 134 | // internal class that represents a MC6847 character map | |
| 135 | class character_map | |
| 136 | { | |
| 137 | public: | |
| 138 | // constructor that sets up the font data | |
| 139 | character_map(const UINT8 *fontdata, bool is_mc6847t1); | |
| 140 | ||
| 141 | // optimized template function that emits a single character | |
| 142 | template<int xscale> | |
| 143 | ATTR_FORCE_INLINE void emit_character(UINT8 mode, const UINT8 *data, int length, pixel_t *RESTRICT pixels, int y, const pixel_t *palette) | |
| 144 | { | |
| 145 | for (int i = 0; i < length; i++) | |
| 146 | { | |
| 147 | // get the character | |
| 148 | UINT8 character = data[i]; | |
| 149 | ||
| 150 | // based on the mode, determine which entry to use | |
| 151 | const entry *e = &m_entries[mode % (sizeof(m_entries) / sizeof(m_entries[0]))]; | |
| 152 | ||
| 153 | // identify the character in the font data | |
| 154 | const UINT8 *font_character = e->m_fontdata + (character & e->m_character_mask) * 12; | |
| 155 | ||
| 156 | // get the particular slice out | |
| 157 | UINT8 font_character_slice = font_character[y % 12]; | |
| 158 | ||
| 159 | // get the two colors | |
| 160 | UINT16 color_base_0 = e->m_color_base_0 + ((character >> e->m_color_shift_0) & e->m_color_mask_0); | |
| 161 | UINT16 color_base_1 = e->m_color_base_1 + ((character >> e->m_color_shift_1) & e->m_color_mask_1); | |
| 162 | pixel_t color_0 = palette[color_base_0]; | |
| 163 | pixel_t color_1 = palette[color_base_1]; | |
| 164 | ||
| 165 | // emit the bits | |
| 166 | for (int j = 0; j < 8; j++) | |
| 167 | { | |
| 168 | for (int k = 0; k < xscale; k++) | |
| 169 | { | |
| 170 | pixels[(i * 8 + j) * xscale + k] = bit_test(font_character_slice, j, color_0, color_1); | |
| 171 | } | |
| 172 | } | |
| 173 | } | |
| 174 | }; | |
| 175 | ||
| 176 | private: | |
| 177 | struct entry | |
| 178 | { | |
| 179 | const UINT8 *m_fontdata; | |
| 180 | UINT8 m_character_mask; | |
| 181 | UINT8 m_color_shift_0; | |
| 182 | UINT8 m_color_shift_1; | |
| 183 | UINT8 m_color_mask_0; | |
| 184 | UINT8 m_color_mask_1; | |
| 185 | UINT16 m_color_base_0; | |
| 186 | UINT16 m_color_base_1; | |
| 187 | }; | |
| 188 | ||
| 189 | // lookup table for MC6847 modes to determine font data and color | |
| 190 | entry m_entries[128]; | |
| 191 | ||
| 192 | // text font data calculated on startup | |
| 193 | UINT8 m_text_fontdata_inverse[64*12]; | |
| 194 | UINT8 m_text_fontdata_lower_case[64*12]; | |
| 195 | UINT8 m_text_fontdata_lower_case_inverse[64*12]; | |
| 196 | ||
| 197 | // optimized function that tests a single bit | |
| 198 | ATTR_FORCE_INLINE pixel_t bit_test(UINT8 data, int shift, pixel_t color_0, pixel_t color_1) | |
| 199 | { | |
| 200 | return data & (0x80 >> shift) ? color_1 : color_0; | |
| 201 | } | |
| 202 | }; | |
| 203 | ||
| 204 | // artficater internal class | |
| 205 | class artifacter | |
| 206 | { | |
| 207 | public: | |
| 208 | artifacter(); | |
| 209 | ||
| 210 | // artifacting config | |
| 211 | void setup_config(device_t *device); | |
| 212 | void poll_config(void) { m_artifacting = (m_config!=NULL) ? m_config->read() : 0; } | |
| 213 | ||
| 214 | // artifacting application | |
| 215 | template<int xscale> | |
| 216 | ATTR_FORCE_INLINE void process_artifacts(pixel_t *pixels, UINT8 mode, const pixel_t *palette) | |
| 217 | { | |
| 218 | if (((mode & (MODE_AG|MODE_GM2|MODE_GM1|MODE_GM0)) == (MODE_AG|MODE_GM2|MODE_GM1|MODE_GM0)) | |
| 219 | && (m_artifacting != 0)) | |
| 220 | { | |
| 221 | // identify the new colors and update | |
| 222 | pixel_t c0 = palette[(mode & MODE_CSS) ? 10 : 8]; | |
| 223 | pixel_t c1 = palette[(mode & MODE_CSS) ? 11 : 9]; | |
| 224 | update_colors(c0, c1); | |
| 225 | ||
| 226 | // generate the new line | |
| 227 | pixel_t new_line[256]; | |
| 228 | int x, i; | |
| 229 | for (x = 0; x < 256; x += 2) | |
| 230 | { | |
| 231 | UINT8 val = ((pixels[(x - 2) * xscale] == c1) ? 0x20 : 0x00) | |
| 232 | | ((pixels[(x - 1) * xscale] == c1) ? 0x10 : 0x00) | |
| 233 | | ((pixels[(x + 0) * xscale] == c1) ? 0x08 : 0x00) | |
| 234 | | ((pixels[(x + 1) * xscale] == c1) ? 0x04 : 0x00) | |
| 235 | | ((pixels[(x + 2) * xscale] == c1) ? 0x02 : 0x00) | |
| 236 | | ((pixels[(x + 3) * xscale] == c1) ? 0x01 : 0x00); | |
| 237 | ||
| 238 | new_line[x + 0] = m_expanded_colors[val * 2 + 0]; | |
| 239 | new_line[x + 1] = m_expanded_colors[val * 2 + 1]; | |
| 240 | } | |
| 241 | ||
| 242 | // and copy it in | |
| 243 | for (x = 0; x < 256; x++) | |
| 244 | { | |
| 245 | for (i = 0; i < xscale; i++) | |
| 246 | pixels[x * xscale + i] = new_line[x]; | |
| 247 | } | |
| 248 | } | |
| 249 | } | |
| 250 | ||
| 251 | private: | |
| 252 | ioport_port *m_config; | |
| 253 | ioport_value m_artifacting; | |
| 254 | ioport_value m_saved_artifacting; | |
| 255 | pixel_t m_saved_c0, m_saved_c1; | |
| 256 | pixel_t m_expanded_colors[128]; | |
| 257 | ||
| 258 | void update_colors(pixel_t c0, pixel_t c1); | |
| 259 | static pixel_t mix_color(double factor, UINT8 c0, UINT8 c1); | |
| 260 | }; | |
| 261 | ||
| 262 | enum border_color_t | |
| 263 | { | |
| 264 | BORDER_COLOR_BLACK, | |
| 265 | BORDER_COLOR_GREEN, | |
| 266 | BORDER_COLOR_WHITE, | |
| 267 | BORDER_COLOR_ORANGE | |
| 268 | }; | |
| 269 | ||
| 270 | // callbacks | |
| 271 | devcb_resolved_write_line m_res_out_hsync_func; | |
| 272 | devcb_resolved_write_line m_res_out_fsync_func; | |
| 273 | ||
| 274 | // incidentals | |
| 275 | character_map m_character_map; | |
| 276 | artifacter m_artifacter; | |
| 277 | ||
| 278 | // device-level overrides | |
| 279 | virtual void device_start(void); | |
| 280 | virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); | |
| 281 | virtual void device_reset(void); | |
| 282 | virtual void device_post_load(void); | |
| 283 | ||
| 284 | // other overridables | |
| 285 | virtual void new_frame(void); | |
| 286 | virtual void horizontal_sync_changed(bool line); | |
| 287 | virtual void field_sync_changed(bool line); | |
| 288 | virtual void enter_bottom_border(void); | |
| 289 | virtual void record_border_scanline(UINT16 physical_scanline); | |
| 290 | virtual void record_body_scanline(UINT16 physical_scanline, UINT16 logical_scanline) = 0; | |
| 291 | virtual void record_partial_body_scanline(UINT16 physical_scanline, UINT16 logical_scanline, INT32 start_clock, INT32 end_clock) = 0; | |
| 292 | ||
| 293 | // miscellaneous | |
| 294 | void video_flush(void); | |
| 295 | const char *describe_context(void); | |
| 296 | ||
| 297 | // setup functions | |
| 298 | emu_timer *setup_timer(device_timer_id id, double offset, double period); | |
| 299 | ||
| 300 | // converts to B&W | |
| 301 | static pixel_t black_and_white(pixel_t color) | |
| 302 | { | |
| 303 | UINT8 average_color = (RGB_RED(color) + RGB_GREEN(color) + RGB_BLUE(color)) / 3; | |
| 304 | return MAKE_RGB(average_color, average_color, average_color); | |
| 305 | } | |
| 306 | ||
| 307 | // changes the geometry | |
| 308 | ATTR_FORCE_INLINE void set_geometry(UINT16 top_border_scanlines, UINT16 body_scanlines, bool wide) | |
| 309 | { | |
| 310 | if (UNEXPECTED((m_top_border_scanlines != top_border_scanlines) | |
| 311 | || (m_body_scanlines != body_scanlines) | |
| 312 | || (m_wide != wide))) | |
| 313 | { | |
| 314 | m_top_border_scanlines = top_border_scanlines; | |
| 315 | m_body_scanlines = body_scanlines; | |
| 316 | m_wide = wide; | |
| 317 | update_field_sync_timer(); | |
| 318 | } | |
| 319 | } | |
| 320 | ||
| 321 | // calculates the border color | |
| 322 | static ATTR_FORCE_INLINE border_color_t border_value(UINT8 mode, bool is_mc6847t1) | |
| 323 | { | |
| 324 | border_color_t result; | |
| 325 | ||
| 326 | if (mode & MODE_AG) | |
| 327 | { | |
| 328 | // graphics | |
| 329 | result = mode & MODE_CSS ? BORDER_COLOR_WHITE : BORDER_COLOR_GREEN; | |
| 330 | } | |
| 331 | else if (!is_mc6847t1 || ((mode & MODE_GM2) == 0)) | |
| 332 | { | |
| 333 | // text, black border | |
| 334 | result = BORDER_COLOR_BLACK; | |
| 335 | } | |
| 336 | else | |
| 337 | { | |
| 338 | // text, green or orange border | |
| 339 | result = mode & MODE_CSS ? BORDER_COLOR_ORANGE : BORDER_COLOR_GREEN; | |
| 340 | } | |
| 341 | return result; | |
| 342 | } | |
| 343 | ||
| 344 | // checks to see if the video has changed | |
| 345 | ATTR_FORCE_INLINE bool has_video_changed(void) | |
| 346 | { | |
| 347 | /* poll the artifacting config */ | |
| 348 | m_artifacter.poll_config(); | |
| 349 | ||
| 350 | /* if the video didn't change, indicate as much */ | |
| 351 | bool video_changed = m_video_changed; | |
| 352 | m_video_changed = false; | |
| 353 | return video_changed; | |
| 354 | } | |
| 355 | ||
| 356 | // updates a byte in the video state | |
| 357 | template<class T> | |
| 358 | ATTR_FORCE_INLINE bool update_value(T *ptr, T byte) | |
| 359 | { | |
| 360 | bool result = false; | |
| 361 | if (*ptr != byte) | |
| 362 | { | |
| 363 | *ptr = byte; | |
| 364 | m_video_changed = true; | |
| 365 | result = true; | |
| 366 | } | |
| 367 | return result; | |
| 368 | }; | |
| 369 | ||
| 370 | // template function for emitting graphics bytes | |
| 371 | template<int bits_per_pixel, int xscale> | |
| 372 | ATTR_FORCE_INLINE void emit_graphics(const UINT8 *data, int length, pixel_t *RESTRICT pixels, UINT16 color_base, const pixel_t *RESTRICT palette) | |
| 373 | { | |
| 374 | for (int i = 0; i < length; i++) | |
| 375 | { | |
| 376 | for (int j = 0; j < (8 / bits_per_pixel); j++) | |
| 377 | { | |
| 378 | for (int k = 0; k < xscale; k++) | |
| 379 | { | |
| 380 | UINT16 color = color_base + ((data[i] >> (8 - (j + 1) * bits_per_pixel)) & ((1 << bits_per_pixel) - 1)); | |
| 381 | pixels[(i * (8 / bits_per_pixel) + j) * xscale + k] = palette[color]; | |
| 382 | } | |
| 383 | } | |
| 384 | } | |
| 385 | } | |
| 386 | ||
| 387 | // template function for emitting samples | |
| 388 | template<int xscale> | |
| 389 | UINT32 emit_mc6847_samples(UINT8 mode, const UINT8 *data, int length, pixel_t *RESTRICT pixels, const pixel_t *RESTRICT palette, | |
| 390 | UINT8 (*get_char_rom)(running_machine &machine, UINT8 ch, int line), int x, int y) | |
| 391 | { | |
| 392 | UINT32 result = 0; | |
| 393 | if (mode & MODE_AG) | |
| 394 | { | |
| 395 | /* graphics */ | |
| 396 | switch(mode & (MODE_GM2|MODE_GM1|MODE_GM0)) | |
| 397 | { | |
| 398 | case 0: | |
| 399 | emit_graphics<2, xscale * 4>(data, length, pixels, (mode & MODE_CSS) ? 4 : 0, palette); | |
| 400 | result = length * 8 * xscale * 2; | |
| 401 | break; | |
| 402 | ||
| 403 | case MODE_GM0: | |
| 404 | case MODE_GM1|MODE_GM0: | |
| 405 | case MODE_GM2|MODE_GM0: | |
| 406 | emit_graphics<1, xscale * 2>(data, length, pixels, (mode & MODE_CSS) ? 10 : 8, palette); | |
| 407 | result = length * 8 * xscale * 2; | |
| 408 | break; | |
| 409 | ||
| 410 | case MODE_GM1: | |
| 411 | case MODE_GM2: | |
| 412 | case MODE_GM2|MODE_GM1: | |
| 413 | emit_graphics<2, xscale * 2>(data, length, pixels, (mode & MODE_CSS) ? 4 : 0, palette); | |
| 414 | result = length * 8 * xscale; | |
| 415 | break; | |
| 416 | ||
| 417 | case MODE_GM2|MODE_GM1|MODE_GM0: | |
| 418 | emit_graphics<1, xscale * 1>(data, length, pixels, (mode & MODE_CSS) ? 10 : 8, palette); | |
| 419 | result = length * 8 * xscale; | |
| 420 | break; | |
| 421 | ||
| 422 | default: | |
| 423 | /* should not get here */ | |
| 424 | fatalerror("Should not get here\n"); | |
| 425 | break; | |
| 426 | } | |
| 427 | } | |
| 428 | else if ((get_char_rom != NULL) && ((mode & (MODE_AG|MODE_AS|MODE_INTEXT)) == MODE_INTEXT)) | |
| 429 | { | |
| 430 | /* external ROM */ | |
| 431 | for (int i = 0; i < length; i++) | |
| 432 | { | |
| 433 | UINT8 byte = get_char_rom(machine(), data[i], y % 12) ^ (mode & MODE_INV ? 0xFF : 0x00); | |
| 434 | emit_graphics<2, xscale * 2>(&byte, 1, &pixels[i * 8], (mode & MODE_CSS) ? 14 : 12, palette); | |
| 435 | } | |
| 436 | result = length * 8 * xscale; | |
| 437 | } | |
| 438 | else | |
| 439 | { | |
| 440 | /* text/semigraphics */ | |
| 441 | m_character_map.emit_character<xscale>(mode, data, length, pixels, y, palette); | |
| 442 | result = length * 8 * xscale; | |
| 443 | } | |
| 444 | return result; | |
| 445 | } | |
| 446 | ||
| 447 | private: | |
| 448 | enum scanline_zone | |
| 449 | { | |
| 450 | SCANLINE_ZONE_TOP_BORDER, | |
| 451 | SCANLINE_ZONE_BODY, | |
| 452 | SCANLINE_ZONE_BOTTOM_BORDER, | |
| 453 | SCANLINE_ZONE_RETRACE, | |
| 454 | SCANLINE_ZONE_VBLANK, | |
| 455 | SCANLINE_ZONE_FRAME_END | |
| 456 | }; | |
| 457 | ||
| 458 | // timers | |
| 459 | emu_timer *m_frame_timer; | |
| 460 | emu_timer *m_hsync_on_timer; | |
| 461 | emu_timer *m_hsync_off_timer; | |
| 462 | emu_timer *m_fsync_timer; | |
| 463 | ||
| 464 | // incidentals | |
| 465 | double m_tpfs; | |
| 466 | int m_field_sync_falling_edge_scanline; | |
| 467 | bool m_wide; | |
| 468 | bool m_video_changed; | |
| 469 | UINT16 m_top_border_scanlines; | |
| 470 | UINT16 m_body_scanlines; | |
| 471 | bool m_recording_scanline; | |
| 472 | bool m_supports_partial_body_scanlines; | |
| 473 | ||
| 474 | // video state | |
| 475 | UINT16 m_physical_scanline; | |
| 476 | UINT16 m_logical_scanline; | |
| 477 | UINT16 m_logical_scanline_zone; | |
| 478 | bool m_horizontal_sync; | |
| 479 | bool m_field_sync; | |
| 480 | UINT32 m_partial_scanline_clocks; | |
| 481 | ||
| 482 | // functions | |
| 483 | void change_horizontal_sync(bool line); | |
| 484 | void change_field_sync(bool line); | |
| 485 | void update_field_sync_timer(void); | |
| 486 | void next_scanline(void); | |
| 487 | INT32 get_clocks_since_hsync(); | |
| 488 | ||
| 489 | // debugging | |
| 490 | const char *scanline_zone_string(scanline_zone zone); | |
| 491 | }; | |
| 492 | ||
| 493 | // actual base class for MC6847 family of devices | |
| 494 | class mc6847_base_device : public mc6847_friend_device | |
| 495 | { | |
| 496 | public: | |
| 497 | /* updates the screen -- this will call begin_update(), | |
| 498 | followed by update_row() reapeatedly and after all row | |
| 499 | updating is complete, end_update() */ | |
| 500 | UINT32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); | |
| 501 | ||
| 502 | // mode changing operations | |
| 503 | DECLARE_WRITE_LINE_MEMBER( ag_w ) { change_mode(MODE_AG, state); } | |
| 504 | DECLARE_WRITE_LINE_MEMBER( gm2_w ) { change_mode(MODE_GM2, state); } | |
| 505 | DECLARE_WRITE_LINE_MEMBER( gm1_w ) { change_mode(MODE_GM1, state); } | |
| 506 | DECLARE_WRITE_LINE_MEMBER( gm0_w ) { change_mode(MODE_GM0, state); } | |
| 507 | DECLARE_WRITE_LINE_MEMBER( as_w ) { change_mode(MODE_AS, state); } | |
| 508 | DECLARE_WRITE_LINE_MEMBER( css_w ) { change_mode(MODE_CSS, state); } | |
| 509 | DECLARE_WRITE_LINE_MEMBER( intext_w ) { change_mode(MODE_INTEXT, state); } | |
| 510 | DECLARE_WRITE_LINE_MEMBER( inv_w ) { change_mode(MODE_INV, state); } | |
| 511 | ||
| 512 | protected: | |
| 513 | mc6847_base_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const UINT8 *fontdata, double tpfs); | |
| 514 | ||
| 515 | // device-level overrides | |
| 516 | virtual void device_start(); | |
| 517 | virtual void device_reset(); | |
| 518 | virtual ioport_constructor device_input_ports() const; | |
| 519 | ||
| 520 | // other overrides | |
| 521 | virtual void field_sync_changed(bool line); | |
| 522 | virtual void record_body_scanline(UINT16 physical_scanline, UINT16 scanline); | |
| 523 | virtual void record_partial_body_scanline(UINT16 physical_scanline, UINT16 logical_scanline, INT32 start_clock, INT32 end_clock); | |
| 524 | ||
| 525 | private: | |
| 526 | struct video_scanline | |
| 527 | { | |
| 528 | UINT8 m_sample_count; | |
| 529 | UINT8 m_mode[32]; | |
| 530 | UINT8 m_data[32]; | |
| 531 | }; | |
| 532 | ||
| 533 | // palette | |
| 534 | static const int PALETTE_LENGTH = 16; | |
| 535 | static const UINT32 s_palette[PALETTE_LENGTH]; | |
| 536 | ||
| 537 | // callbacks | |
| 538 | devcb_resolved_read8 m_res_input_func; | |
| 539 | UINT8 (*m_get_char_rom)(running_machine &machine, UINT8 ch, int line); | |
| 540 | ||
| 541 | // incidentals | |
| 542 | UINT8 m_fixed_mode; | |
| 543 | UINT8 m_fixed_mode_mask; | |
| 544 | const pixel_t *m_palette; | |
| 545 | pixel_t m_bw_palette[PALETTE_LENGTH]; | |
| 546 | ||
| 547 | // state | |
| 548 | UINT8 m_mode; | |
| 549 | UINT16 m_video_address; | |
| 550 | bool m_dirty; | |
| 551 | video_scanline m_data[192]; | |
| 552 | ||
| 553 | void change_mode(UINT8 mode, int state) | |
| 554 | { | |
| 555 | // sanity check, to ensure that we're not changing fixed modes | |
| 556 | assert((mode & m_fixed_mode_mask) == 0); | |
| 557 | ||
| 558 | // calculate new mode | |
| 559 | UINT8 new_mode; | |
| 560 | if (state) | |
| 561 | new_mode = m_mode | mode; | |
| 562 | else | |
| 563 | new_mode = m_mode & ~mode; | |
| 564 | ||
| 565 | // has the mode changed? | |
| 566 | if (new_mode != m_mode) | |
| 567 | { | |
| 568 | // it has! check dirty flag | |
| 569 | video_flush(); | |
| 570 | if (!m_dirty) | |
| 571 | { | |
| 572 | m_dirty = true; | |
| 573 | } | |
| 574 | ||
| 575 | // and set the new mode | |
| 576 | m_mode = new_mode; | |
| 577 | } | |
| 578 | } | |
| 579 | ||
| 580 | // setup functions | |
| 581 | void setup_fixed_mode(struct devcb_read_line callback, UINT8 mode); | |
| 582 | ||
| 583 | // runtime functions | |
| 584 | void record_body_scanline(UINT16 physical_scanline, UINT16 scanline, INT32 start_pos, INT32 end_pos); | |
| 585 | pixel_t border_value(UINT8 mode, const pixel_t *palette, bool is_mc6847t1); | |
| 586 | ||
| 587 | template<int xscale> | |
| 588 | void emit_samples(UINT8 mode, const UINT8 *data, int length, pixel_t *pixels, int x, int y); | |
| 589 | ||
| 590 | // template function for doing video update collection | |
| 591 | template<int sample_count, int yres> | |
| 592 | void record_scanline_res(int scanline, INT32 start_pos, INT32 end_pos); | |
| 593 | ||
| 594 | // miscellaneous | |
| 595 | UINT8 input(UINT16 address); | |
| 596 | INT32 scanline_position_from_clock(INT32 clocks_since_hsync); | |
| 597 | }; | |
| 598 | ||
| 599 | ||
| 600 | //************************************************************************** | |
| 601 | // VARIATIONS | |
| 602 | //************************************************************************** | |
| 603 | ||
| 604 | class mc6847_ntsc_device : public mc6847_base_device | |
| 605 | { | |
| 606 | public: | |
| 607 | mc6847_ntsc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); | |
| 608 | }; | |
| 609 | ||
| 610 | class mc6847_pal_device : public mc6847_base_device | |
| 611 | { | |
| 612 | public: | |
| 613 | mc6847_pal_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); | |
| 614 | }; | |
| 615 | ||
| 616 | class mc6847y_ntsc_device : public mc6847_base_device | |
| 617 | { | |
| 618 | public: | |
| 619 | mc6847y_ntsc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); | |
| 620 | }; | |
| 621 | ||
| 622 | class mc6847y_pal_device : public mc6847_base_device | |
| 623 | { | |
| 624 | public: | |
| 625 | mc6847y_pal_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); | |
| 626 | }; | |
| 627 | ||
| 628 | class mc6847t1_ntsc_device : public mc6847_base_device | |
| 629 | { | |
| 630 | public: | |
| 631 | mc6847t1_ntsc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); | |
| 632 | }; | |
| 633 | ||
| 634 | class mc6847t1_pal_device : public mc6847_base_device | |
| 635 | { | |
| 636 | public: | |
| 637 | mc6847t1_pal_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); | |
| 638 | }; | |
| 639 | ||
| 640 | ||
| 641 | extern const device_type MC6847_NTSC; | |
| 642 | extern const device_type MC6847_PAL; | |
| 643 | extern const device_type MC6847Y_NTSC; | |
| 644 | extern const device_type MC6847Y_PAL; | |
| 645 | extern const device_type MC6847T1_NTSC; | |
| 646 | extern const device_type MC6847T1_PAL; | |
| 647 | ||
| 648 | #endif /* __MC6847__ */ |
| r21684 | r21685 | |
|---|---|---|
| 1 | /* | |
| 2 | ||
| 3 | Hitachi HD66421 LCD Controller/Driver | |
| 4 | ||
| 5 | (c) 2001-2007 Tim Schuerewegen | |
| 6 | ||
| 7 | */ | |
| 8 | ||
| 9 | #include "emu.h" | |
| 10 | #include "hd66421.h" | |
| 11 | ||
| 12 | //************************************************************************** | |
| 13 | // MACROS / CONSTANTS | |
| 14 | //************************************************************************** | |
| 15 | ||
| 16 | #define LOG_LEVEL 1 | |
| 17 | #define _logerror(level,x) do { if (LOG_LEVEL > level) logerror x; } while (0) | |
| 18 | ||
| 19 | #define HD66421_RAM_SIZE (HD66421_WIDTH * HD66421_HEIGHT / 4) // 2-bits per pixel | |
| 20 | ||
| 21 | // R0 - control register 1 | |
| 22 | #define LCD_R0_RMW 0x80 // read-modify-write mode | |
| 23 | #define LCD_R0_DISP 0x40 // display on/off | |
| 24 | #define LCD_R0_STBY 0x20 // standby (internal operation and power circuit halt) | |
| 25 | #define LCD_R0_PWR 0x10 | |
| 26 | #define LCD_R0_AMP 0x08 | |
| 27 | #define LCD_R0_REV 0x04 // reverse | |
| 28 | #define LCD_R0_HOLT 0x02 | |
| 29 | #define LCD_R0_ADC 0x01 | |
| 30 | ||
| 31 | // R1 - control register 2 | |
| 32 | #define LCD_R1_BIS1 0x80 // bias ratio (bit 1) | |
| 33 | #define LCD_R1_BIS0 0x40 // bias ratio (bit 0) | |
| 34 | #define LCD_R1_WLS 0x20 | |
| 35 | #define LCD_R1_GRAY 0x10 // grayscale palette 4/32 | |
| 36 | #define LCD_R1_DTY1 0x08 // display duty cycle (bit 1) | |
| 37 | #define LCD_R1_DTY0 0x04 // display duty cycle (bit 0) | |
| 38 | #define LCD_R1_INC 0x02 | |
| 39 | #define LCD_R1_BLK 0x01 // blink function | |
| 40 | ||
| 41 | // register 0 to 16 | |
| 42 | #define LCD_REG_CONTROL_1 0x00 // control register 1 | |
| 43 | #define LCD_REG_CONTROL_2 0x01 // control register 2 | |
| 44 | #define LCD_REG_ADDR_X 0x02 // x address register | |
| 45 | #define LCD_REG_ADDR_Y 0x03 // y address register | |
| 46 | #define LCD_REG_RAM 0x04 // display ram access register | |
| 47 | #define LCD_REG_START_Y 0x05 // display start line register | |
| 48 | #define LCD_REG_BLINK_START 0x06 // blink start line register | |
| 49 | #define LCD_REG_BLINK_END 0x07 // blink end line register | |
| 50 | #define LCD_REG_BLINK_1 0x08 // blink register 1 | |
| 51 | #define LCD_REG_BLINK_2 0x09 // blink register 2 | |
| 52 | #define LCD_REG_BLINK_3 0x0A // blink register 3 | |
| 53 | #define LCD_REG_PARTIAL 0x0B // partial display block register | |
| 54 | #define LCD_REG_COLOR_1 0x0C // gray scale palette 1 (0,0) | |
| 55 | #define LCD_REG_COLOR_2 0x0D // gray scale palette 2 (0,1) | |
| 56 | #define LCD_REG_COLOR_3 0x0E // gray scale palette 3 (1,0) | |
| 57 | #define LCD_REG_COLOR_4 0x0F // gray scale palette 4 (1,1) | |
| 58 | #define LCD_REG_CONTRAST 0x10 // contrast control register | |
| 59 | #define LCD_REG_PLANE 0x11 // plane selection register | |
| 60 | ||
| 61 | //************************************************************************** | |
| 62 | // GLOBAL VARIABLES | |
| 63 | //************************************************************************** | |
| 64 | ||
| 65 | // devices | |
| 66 | const device_type HD66421 = &device_creator<hd66421_device>; | |
| 67 | ||
| 68 | ||
| 69 | // default address map | |
| 70 | static ADDRESS_MAP_START( hd66421, AS_0, 8, hd66421_device ) | |
| 71 | AM_RANGE(0x0000, HD66421_RAM_SIZE) AM_RAM | |
| 72 | ADDRESS_MAP_END | |
| 73 | ||
| 74 | //------------------------------------------------- | |
| 75 | // memory_space_config - return a description of | |
| 76 | // any address spaces owned by this device | |
| 77 | //------------------------------------------------- | |
| 78 | ||
| 79 | const address_space_config *hd66421_device::memory_space_config(address_spacenum spacenum) const | |
| 80 | { | |
| 81 | return (spacenum == AS_0) ? &m_space_config : NULL; | |
| 82 | } | |
| 83 | ||
| 84 | ||
| 85 | //************************************************************************** | |
| 86 | // INLINE HELPERS | |
| 87 | //************************************************************************** | |
| 88 | ||
| 89 | //------------------------------------------------- | |
| 90 | // readbyte - read a byte at the given address | |
| 91 | //------------------------------------------------- | |
| 92 | ||
| 93 | inline UINT8 hd66421_device::readbyte(offs_t address) | |
| 94 | { | |
| 95 | return space().read_byte(address); | |
| 96 | } | |
| 97 | ||
| 98 | ||
| 99 | //------------------------------------------------- | |
| 100 | // writebyte - write a byte at the given address | |
| 101 | //------------------------------------------------- | |
| 102 | ||
| 103 | inline void hd66421_device::writebyte(offs_t address, UINT8 data) | |
| 104 | { | |
| 105 | space().write_byte(address, data); | |
| 106 | } | |
| 107 | ||
| 108 | ||
| 109 | //************************************************************************** | |
| 110 | // LIVE DEVICE | |
| 111 | //************************************************************************** | |
| 112 | ||
| 113 | //------------------------------------------------- | |
| 114 | // hd66421_device - constructor | |
| 115 | //------------------------------------------------- | |
| 116 | ||
| 117 | hd66421_device::hd66421_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) | |
| 118 | : device_t(mconfig, HD66421, "Hitachi HD66421 LCD Controller", tag, owner, clock), | |
| 119 | device_memory_interface(mconfig, *this), | |
| 120 | m_space_config("videoram", ENDIANNESS_LITTLE, 8, 17, 0, NULL, *ADDRESS_MAP_NAME(hd66421)), | |
| 121 | m_cmd(0), | |
| 122 | m_x(0), | |
| 123 | m_y(0) | |
| 124 | { | |
| 125 | for (int i = 0; i < 32; i++) | |
| 126 | { | |
| 127 | m_reg[i] = 0; | |
| 128 | } | |
| 129 | } | |
| 130 | ||
| 131 | ||
| 132 | //------------------------------------------------- | |
| 133 | // device_start - device-specific startup | |
| 134 | //------------------------------------------------- | |
| 135 | ||
| 136 | void hd66421_device::device_start() | |
| 137 | { | |
| 138 | // register for state saving | |
| 139 | save_item(NAME(m_cmd)); | |
| 140 | save_item(NAME(m_reg)); | |
| 141 | save_item(NAME(m_x)); | |
| 142 | save_item(NAME(m_y)); | |
| 143 | } | |
| 144 | ||
| 145 | READ8_MEMBER( hd66421_device::reg_idx_r ) | |
| 146 | { | |
| 147 | _logerror( 2, ("reg_idx_r\n")); | |
| 148 | return m_cmd; | |
| 149 | } | |
| 150 | ||
| 151 | WRITE8_MEMBER( hd66421_device::reg_idx_w ) | |
| 152 | { | |
| 153 | _logerror( 2, ("reg_idx_w (%02X)\n", data)); | |
| 154 | m_cmd = data; | |
| 155 | } | |
| 156 | ||
| 157 | READ8_MEMBER( hd66421_device::reg_dat_r ) | |
| 158 | { | |
| 159 | _logerror( 2, ("reg_dat_r\n")); | |
| 160 | return m_reg[m_cmd]; | |
| 161 | } | |
| 162 | ||
| 163 | WRITE8_MEMBER( hd66421_device::reg_dat_w ) | |
| 164 | { | |
| 165 | _logerror( 2, ("reg_dat_w (%02X)\n", data)); | |
| 166 | m_reg[m_cmd] = data; | |
| 167 | ||
| 168 | switch (m_cmd) | |
| 169 | { | |
| 170 | case LCD_REG_ADDR_X : | |
| 171 | m_x = data; | |
| 172 | break; | |
| 173 | ||
| 174 | case LCD_REG_ADDR_Y : | |
| 175 | m_y = data; | |
| 176 | break; | |
| 177 | ||
| 178 | case LCD_REG_RAM : | |
| 179 | { | |
| 180 | UINT8 r1; | |
| 181 | writebyte(m_y * (HD66421_WIDTH / 4) + m_x, data); | |
| 182 | r1 = m_reg[LCD_REG_CONTROL_2]; | |
| 183 | if (r1 & 0x02) | |
| 184 | m_x++; | |
| 185 | else | |
| 186 | m_y++; | |
| 187 | ||
| 188 | if (m_x >= (HD66421_WIDTH / 4)) | |
| 189 | { | |
| 190 | m_x = 0; | |
| 191 | m_y++; | |
| 192 | } | |
| 193 | ||
| 194 | if (m_y >= HD66421_HEIGHT) | |
| 195 | m_y = 0; | |
| 196 | } | |
| 197 | break; | |
| 198 | } | |
| 199 | } | |
| 200 | ||
| 201 | void hd66421_device::plot_pixel(bitmap_ind16 &bitmap, int x, int y, UINT32 color) | |
| 202 | { | |
| 203 | bitmap.pix16(y, x) = (UINT16)color; | |
| 204 | } | |
| 205 | ||
| 206 | UINT32 hd66421_device::update_screen(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) | |
| 207 | { | |
| 208 | pen_t pen[4]; | |
| 209 | ||
| 210 | _logerror( 1, ("video_update_hd66421\n")); | |
| 211 | ||
| 212 | // update palette | |
| 213 | for (int i = 0; i < 4; i++) | |
| 214 | { | |
| 215 | double bright; | |
| 216 | int temp; | |
| 217 | temp = 31 - (m_reg[LCD_REG_COLOR_1 + i] - m_reg[LCD_REG_CONTRAST] + 0x03); | |
| 218 | if (temp < 0) temp = 0; | |
| 219 | if (temp > 31) temp = 31; | |
| 220 | bright = 1.0 * temp / 31; | |
| 221 | pen[i] = i; | |
| 222 | #ifdef HD66421_BRIGHTNESS_DOES_NOT_WORK | |
| 223 | palette_set_color(machine(), pen[i], 255 * bright, 255 * bright, 255 * bright); | |
| 224 | #else | |
| 225 | palette_set_pen_contrast(machine(), pen[i], bright); | |
| 226 | #endif | |
| 227 | } | |
| 228 | ||
| 229 | // draw bitmap (bottom to top) | |
| 230 | if (m_reg[0] & LCD_R0_DISP) | |
| 231 | { | |
| 232 | int x, y; | |
| 233 | x = 0; | |
| 234 | y = HD66421_HEIGHT - 1; | |
| 235 | ||
| 236 | for (int i = 0; i < HD66421_RAM_SIZE; i++) | |
| 237 | { | |
| 238 | plot_pixel(bitmap, x++, y, pen[(readbyte(i) >> 6) & 3]); | |
| 239 | plot_pixel(bitmap, x++, y, pen[(readbyte(i) >> 4) & 3]); | |
| 240 | plot_pixel(bitmap, x++, y, pen[(readbyte(i) >> 2) & 3]); | |
| 241 | plot_pixel(bitmap, x++, y, pen[(readbyte(i) >> 0) & 3]); | |
| 242 | if (x >= HD66421_WIDTH) | |
| 243 | { | |
| 244 | x = 0; | |
| 245 | y = y - 1; | |
| 246 | } | |
| 247 | } | |
| 248 | } | |
| 249 | else | |
| 250 | { | |
| 251 | rectangle rect(0, HD66421_WIDTH - 1, 0, HD66421_HEIGHT - 1); | |
| 252 | bitmap.fill(get_white_pen(machine()), rect); | |
| 253 | } | |
| 254 | ||
| 255 | return 0; | |
| 256 | } |
| r21684 | r21685 | |
|---|---|---|
| 1 | /*************************************************************************** | |
| 2 | ||
| 3 | Hitachi HD66421 LCD Controller | |
| 4 | ||
| 5 | (c) 2001-2007 Tim Schuerewegen | |
| 6 | ||
| 7 | ***************************************************************************/ | |
| 8 | ||
| 9 | #pragma once | |
| 10 | ||
| 11 | #ifndef __HD66421_H__ | |
| 12 | #define __HD66421_H__ | |
| 13 | ||
| 14 | ||
| 15 | ///************************************************************************* | |
| 16 | // MACROS / CONSTANTS | |
| 17 | ///************************************************************************* | |
| 18 | ||
| 19 | //#define HD66421_BRIGHTNESS_DOES_NOT_WORK | |
| 20 | ||
| 21 | #define HD66421_WIDTH 160 | |
| 22 | #define HD66421_HEIGHT 100 | |
| 23 | ||
| 24 | ||
| 25 | /*----------- defined in video/hd66421.c -----------*/ | |
| 26 | ||
| 27 | ///************************************************************************* | |
| 28 | // INTERFACE CONFIGURATION MACROS | |
| 29 | ///************************************************************************* | |
| 30 | ||
| 31 | #define MCFG_HD66421_ADD(_tag) \ | |
| 32 | MCFG_DEVICE_ADD(_tag, HD66421, 0) | |
| 33 | ||
| 34 | ///************************************************************************* | |
| 35 | // TYPE DEFINITIONS | |
| 36 | ///************************************************************************* | |
| 37 | ||
| 38 | // ======================> hd66421_device | |
| 39 | ||
| 40 | class hd66421_device : public device_t, | |
| 41 | public device_memory_interface | |
| 42 | { | |
| 43 | public: | |
| 44 | // construction/destruction | |
| 45 | hd66421_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); | |
| 46 | ||
| 47 | DECLARE_READ8_MEMBER( reg_idx_r ); | |
| 48 | DECLARE_WRITE8_MEMBER( reg_idx_w ); | |
| 49 | DECLARE_READ8_MEMBER( reg_dat_r ); | |
| 50 | DECLARE_WRITE8_MEMBER( reg_dat_w ); | |
| 51 | ||
| 52 | UINT32 update_screen(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); | |
| 53 | ||
| 54 | protected: | |
| 55 | // device-level overrides | |
| 56 | virtual void device_start(); | |
| 57 | ||
| 58 | // device_config_memory_interface overrides | |
| 59 | virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; | |
| 60 | ||
| 61 | // address space configurations | |
| 62 | const address_space_config m_space_config; | |
| 63 | ||
| 64 | inline UINT8 readbyte(offs_t address); | |
| 65 | inline void writebyte(offs_t address, UINT8 data); | |
| 66 | ||
| 67 | void plot_pixel(bitmap_ind16 &bitmap, int x, int y, UINT32 color); | |
| 68 | ||
| 69 | private: | |
| 70 | UINT8 m_cmd, m_reg[32]; | |
| 71 | int m_x, m_y; | |
| 72 | }; | |
| 73 | ||
| 74 | ||
| 75 | // device type definition | |
| 76 | extern const device_type HD66421; | |
| 77 | ||
| 78 | ||
| 79 | #endif |
| r21684 | r21685 | |
|---|---|---|
| 1 | /*************************************************************************** | |
| 2 | ||
| 3 | Hitachi HD44352 LCD controller | |
| 4 | ||
| 5 | ***************************************************************************/ | |
| 6 | ||
| 7 | #include "emu.h" | |
| 8 | #include "video/hd44352.h" | |
| 9 | ||
| 10 | #define LCD_BYTE_INPUT 0x01 | |
| 11 | #define LCD_BYTE_OUTPUT 0x02 | |
| 12 | #define LCD_CHAR_OUTPUT 0x03 | |
| 13 | #define LCD_ON_OFF 0x04 | |
| 14 | #define LCD_CURSOR_GRAPHIC 0x06 | |
| 15 | #define LCD_CURSOR_CHAR 0x07 | |
| 16 | #define LCD_SCROLL_CHAR_WIDTH 0x08 | |
| 17 | #define LCD_CURSOR_STATUS 0x09 | |
| 18 | #define LCD_USER_CHARACTER 0x0b | |
| 19 | #define LCD_CONTRAST 0x0c | |
| 20 | #define LCD_IRQ_FREQUENCY 0x0d | |
| 21 | #define LCD_CURSOR_POSITION 0x0e | |
| 22 | ||
| 23 | ||
| 24 | // devices | |
| 25 | const device_type HD44352 = &device_creator<hd44352_device>; | |
| 26 | ||
| 27 | //************************************************************************** | |
| 28 | // live device | |
| 29 | //************************************************************************** | |
| 30 | ||
| 31 | //------------------------------------------------- | |
| 32 | // hd44352_device - constructor | |
| 33 | //------------------------------------------------- | |
| 34 | ||
| 35 | hd44352_device::hd44352_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock): | |
| 36 | device_t(mconfig, HD44352, "hd44352", tag, owner, clock) | |
| 37 | { | |
| 38 | } | |
| 39 | ||
| 40 | //------------------------------------------------- | |
| 41 | // device_config_complete - perform any | |
| 42 | // operations now that the configuration is | |
| 43 | // complete | |
| 44 | //------------------------------------------------- | |
| 45 | ||
| 46 | void hd44352_device::device_config_complete() | |
| 47 | { | |
| 48 | // inherit a copy of the static data | |
| 49 | const hd44352_interface *intf = reinterpret_cast<const hd44352_interface *>(static_config()); | |
| 50 | if (intf != NULL) | |
| 51 | *static_cast<hd44352_interface *>(this) = *intf; | |
| 52 | ||
| 53 | // or initialize to defaults if none provided | |
| 54 | else | |
| 55 | { | |
| 56 | memset(&m_on, 0, sizeof(m_on)); | |
| 57 | } | |
| 58 | } | |
| 59 | ||
| 60 | //------------------------------------------------- | |
| 61 | // device_validity_check - perform validity checks | |
| 62 | // on this device | |
| 63 | //------------------------------------------------- | |
| 64 | ||
| 65 | void hd44352_device::device_validity_check(validity_checker &valid) const | |
| 66 | { | |
| 67 | } | |
| 68 | //------------------------------------------------- | |
| 69 | // device_start - device-specific startup | |
| 70 | //------------------------------------------------- | |
| 71 | ||
| 72 | void hd44352_device::device_start() | |
| 73 | { | |
| 74 | m_on.resolve(m_on_cb, *this); | |
| 75 | ||
| 76 | m_on_timer = timer_alloc(ON_TIMER); | |
| 77 | m_on_timer->adjust(attotime::from_hz(m_clock/16384), 0, attotime::from_hz(m_clock/16384)); | |
| 78 | ||
| 79 | save_item( NAME(m_control_lines)); | |
| 80 | save_item( NAME(m_data_bus)); | |
| 81 | save_item( NAME(m_state)); | |
| 82 | save_item( NAME(m_offset)); | |
| 83 | save_item( NAME(m_char_width)); | |
| 84 | save_item( NAME(m_bank)); | |
| 85 | save_item( NAME(m_lcd_on)); | |
| 86 | save_item( NAME(m_scroll)); | |
| 87 | save_item( NAME(m_contrast)); | |
| 88 | save_item( NAME(m_byte_count)); | |
| 89 | save_item( NAME(m_cursor_status)); | |
| 90 | save_item( NAME(m_cursor_x)); | |
| 91 | save_item( NAME(m_cursor_y)); | |
| 92 | save_item( NAME(m_cursor_lcd)); | |
| 93 | save_item( NAME(m_video_ram[0])); | |
| 94 | save_item( NAME(m_video_ram[1])); | |
| 95 | save_item( NAME(m_par)); | |
| 96 | save_item( NAME(m_cursor)); | |
| 97 | save_item( NAME(m_custom_char[0])); | |
| 98 | save_item( NAME(m_custom_char[1])); | |
| 99 | save_item( NAME(m_custom_char[2])); | |
| 100 | save_item( NAME(m_custom_char[3])); | |
| 101 | } | |
| 102 | ||
| 103 | ||
| 104 | //------------------------------------------------- | |
| 105 | // device_reset - device-specific reset | |
| 106 | //------------------------------------------------- | |
| 107 | ||
| 108 | void hd44352_device::device_reset() | |
| 109 | { | |
| 110 | memset(m_video_ram, 0x00, sizeof(m_video_ram)); | |
| 111 | memset(m_par, 0x00, sizeof(m_par)); | |
| 112 | memset(m_custom_char, 0x00, sizeof(m_custom_char)); | |
| 113 | memset(m_cursor, 0x00, sizeof(m_cursor)); | |
| 114 | m_control_lines = 0; | |
| 115 | m_data_bus = 0xff; | |
| 116 | m_state = 0; | |
| 117 | m_bank = 0; | |
| 118 | m_offset = 0; | |
| 119 | m_char_width = 6; | |
| 120 | m_lcd_on = 0; | |
| 121 | m_scroll = 0; | |
| 122 | m_byte_count = 0; | |
| 123 | m_cursor_status = 0; | |
| 124 | m_cursor_x = 0; | |
| 125 | m_cursor_y = 0; | |
| 126 | m_cursor_lcd = 0; | |
| 127 | m_contrast = 0; | |
| 128 | } | |
| 129 | ||
| 130 | ||
| 131 | //------------------------------------------------- | |
| 132 | // device_timer - handler timer events | |
| 133 | //------------------------------------------------- | |
| 134 | void hd44352_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) | |
| 135 | { | |
| 136 | switch(id) | |
| 137 | { | |
| 138 | case ON_TIMER: | |
| 139 | if (m_control_lines & 0x40) | |
| 140 | { | |
| 141 | m_on(ASSERT_LINE); | |
| 142 | m_on(CLEAR_LINE); | |
| 143 | } | |
| 144 | break; | |
| 145 | } | |
| 146 | } | |
| 147 | ||
| 148 | //************************************************************************** | |
| 149 | // device interface | |
| 150 | //************************************************************************** | |
| 151 | ||
| 152 | UINT32 hd44352_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) | |
| 153 | { | |
| 154 | UINT8 cw = m_char_width; | |
| 155 | ||
| 156 | bitmap.fill(0, cliprect); | |
| 157 | ||
| 158 | if (m_control_lines&0x80 && m_lcd_on) | |
| 159 | { | |
| 160 | for (int a=0; a<2; a++) | |
| 161 | for (int py=0; py<4; py++) | |
| 162 | for (int px=0; px<16; px++) | |
| 163 | if (BIT(m_cursor_status, 4) && px == m_cursor_x && py == m_cursor_y && a == m_cursor_lcd) | |
| 164 | { | |
| 165 | //draw the cursor | |
| 166 | for (int c=0; c<cw; c++) | |
| 167 | { | |
| 168 | UINT8 d = compute_newval((m_cursor_status>>5) & 0x07, m_video_ram[a][py*16*cw + px*cw + c + m_scroll * 48], m_cursor[c]); | |
| 169 | for (int b=0; b<8; b++) | |
| 170 | { | |
| 171 | bitmap.pix16(py*8 + b, a*cw*16 + px*cw + c) = BIT(d, 7-b); | |
| 172 | } | |
| 173 | } | |
| 174 | } | |
| 175 | else | |
| 176 | { | |
| 177 | for (int c=0; c<cw; c++) | |
| 178 | { | |
| 179 | UINT8 d = m_video_ram[a][py*16*cw + px*cw + c + m_scroll * 48]; | |
| 180 | for (int b=0; b<8; b++) | |
| 181 | { | |
| 182 | bitmap.pix16(py*8 + b, a*cw*16 + px*cw + c) = BIT(d, 7-b); | |
| 183 | } | |
| 184 | } | |
| 185 | } | |
| 186 | } | |
| 187 | ||
| 188 | return 0; | |
| 189 | } | |
| 190 | ||
| 191 | ||
| 192 | void hd44352_device::control_write(UINT8 data) | |
| 193 | { | |
| 194 | if(m_control_lines == data) | |
| 195 | m_state = 0; | |
| 196 | ||
| 197 | m_control_lines = data; | |
| 198 | } | |
| 199 | ||
| 200 | UINT8 hd44352_device::compute_newval(UINT8 type, UINT8 oldval, UINT8 newval) | |
| 201 | { | |
| 202 | switch(type & 0x07) | |
| 203 | { | |
| 204 | case 0x00: | |
| 205 | return (~oldval) & newval; | |
| 206 | case 0x01: | |
| 207 | return oldval ^ newval; | |
| 208 | case 0x03: | |
| 209 | return oldval & (~newval); | |
| 210 | case 0x04: | |
| 211 | return newval; | |
| 212 | case 0x05: | |
| 213 | return oldval | newval; | |
| 214 | case 0x07: | |
| 215 | return oldval; | |
| 216 | case 0x02: | |
| 217 | case 0x06: | |
| 218 | default: | |
| 219 | return 0; | |
| 220 | } | |
| 221 | } | |
| 222 | ||
| 223 | UINT8 hd44352_device::get_char(UINT16 pos) | |
| 224 | { | |
| 225 | switch ((UINT8)pos/8) | |
| 226 | { | |
| 227 | case 0xcf: | |
| 228 | return m_custom_char[0][pos%8]; | |
| 229 | case 0xdf: | |
| 230 | return m_custom_char[1][pos%8]; | |
| 231 | case 0xef: | |
| 232 | return m_custom_char[2][pos%8]; | |
| 233 | case 0xff: | |
| 234 | return m_custom_char[3][pos%8]; | |
| 235 | default: | |
| 236 | return region()->u8(pos); | |
| 237 | } | |
| 238 | } | |
| 239 | ||
| 240 | void hd44352_device::data_write(UINT8 data) | |
| 241 | { | |
| 242 | // verify that controller is active | |
| 243 | if (!(m_control_lines&0x80)) | |
| 244 | return; | |
| 245 | ||
| 246 | if (m_control_lines & 0x01) | |
| 247 | { | |
| 248 | if (!(m_control_lines&0x02) && !(m_control_lines&0x04)) | |
| 249 | return; | |
| 250 | ||
| 251 | switch (m_state) | |
| 252 | { | |
| 253 | case 0: //parameter 0 | |
| 254 | m_par[m_state++] = data; | |
| 255 | break; | |
| 256 | case 1: //parameter 1 | |
| 257 | m_par[m_state++] = data; | |
| 258 | break; | |
| 259 | case 2: //parameter 2 | |
| 260 | m_par[m_state++] = data; | |
| 261 | break; | |
| 262 | } | |
| 263 | ||
| 264 | switch (m_par[0] & 0x0f) | |
| 265 | { | |
| 266 | case LCD_BYTE_INPUT: | |
| 267 | case LCD_CHAR_OUTPUT: | |
| 268 | { | |
| 269 | if (m_state == 1) | |
| 270 | m_bank = BIT(data, 4); | |
| 271 | else if (m_state == 2) | |
| 272 | m_offset = ((data>>1)&0x3f) % 48 + (BIT(data,7) * 48); | |
| 273 | else if (m_state == 3) | |
| 274 | m_offset += ((data & 0x03) * 96); | |
| 275 | } | |
| 276 | break; | |
| 277 | case LCD_BYTE_OUTPUT: | |
| 278 | { | |
| 279 | if (m_state == 1) | |
| 280 | m_bank = BIT(data, 4); | |
| 281 | else if (m_state == 2) | |
| 282 | m_offset = ((data>>1)&0x3f) % 48 + (BIT(data,7) * 48); | |
| 283 | else if (m_state == 3) | |
| 284 | m_offset += ((data & 0x03) * 96); | |
| 285 | } | |
| 286 | break; | |
| 287 | case LCD_ON_OFF: | |
| 288 | { | |
| 289 | if (m_state == 1) | |
| 290 | m_lcd_on = BIT(data, 4); | |
| 291 | m_data_bus = 0xff; | |
| 292 | m_state = 0; | |
| 293 | } | |
| 294 | break; | |
| 295 | case LCD_SCROLL_CHAR_WIDTH: | |
| 296 | { | |
| 297 | if (m_state == 1) | |
| 298 | { | |
| 299 | m_char_width = 8-((data>>4)&3); | |
| 300 | m_scroll = ((data>>6)&3); | |
| 301 | } | |
| 302 | ||
| 303 | m_data_bus = 0xff; | |
| 304 | m_state = 0; | |
| 305 | } | |
| 306 | break; | |
| 307 | case LCD_CURSOR_STATUS: | |
| 308 | { | |
| 309 | if (m_state == 1) | |
| 310 | m_cursor_status = data; | |
| 311 | m_data_bus = 0xff; | |
| 312 | m_state = 0; | |
| 313 | } | |
| 314 | break; | |
| 315 | case LCD_CONTRAST: | |
| 316 | { | |
| 317 | if (m_state == 1) | |
| 318 | m_contrast = (m_contrast & 0x00ffff) | (data<<16); | |
| 319 | else if (m_state == 2) | |
| 320 | m_contrast = (m_contrast & 0xff00ff) | (data<<8); | |
| 321 | else if (m_state == 3) | |
| 322 | { | |
| 323 | m_contrast = (m_contrast & 0xffff00) | (data<<0); | |
| 324 | m_state = 0; | |
| 325 | } | |
| 326 | ||
| 327 | m_data_bus = 0xff; | |
| 328 | } | |
| 329 | break; | |
| 330 | case LCD_IRQ_FREQUENCY: | |
| 331 | { | |
| 332 | if (m_state == 1) | |
| 333 | { | |
| 334 | UINT32 on_timer_rate; | |
| 335 | ||
| 336 | switch((data>>4) & 0x0f) | |
| 337 | { | |
| 338 | case 0x00: on_timer_rate = 16384; break; | |
| 339 | case 0x01: on_timer_rate = 8; break; | |
| 340 | case 0x02: on_timer_rate = 16; break; | |
| 341 | case 0x03: on_timer_rate = 32; break; | |
| 342 | case 0x04: on_timer_rate = 64; break; | |
| 343 | case 0x05: on_timer_rate = 128; break; | |
| 344 | case 0x06: on_timer_rate = 256; break; | |
| 345 | case 0x07: on_timer_rate = 512; break; | |
| 346 | case 0x08: on_timer_rate = 1024; break; | |
| 347 | case 0x09: on_timer_rate = 2048; break; | |
| 348 | case 0x0a: on_timer_rate = 4096; break; | |
| 349 | case 0x0b: on_timer_rate = 4096; break; | |
| 350 | default: on_timer_rate = 8192; break; | |
| 351 | } | |
| 352 | ||
| 353 | m_on_timer->adjust(attotime::from_hz(m_clock/on_timer_rate), 0, attotime::from_hz(m_clock/on_timer_rate)); | |
| 354 | } | |
| 355 | m_data_bus = 0xff; | |
| 356 | m_state = 0; | |
| 357 | } | |
| 358 | break; | |
| 359 | case LCD_CURSOR_POSITION: | |
| 360 | { | |
| 361 | if (m_state == 1) | |
| 362 | m_cursor_lcd = BIT(data, 4); //0:left lcd 1:right lcd; | |
| 363 | else if (m_state == 2) | |
| 364 | m_cursor_x = ((data>>1)&0x3f) % 48 + (BIT(data,7) * 48); | |
| 365 | else if (m_state == 3) | |
| 366 | { | |
| 367 | m_cursor_y = data & 0x03; | |
| 368 | m_state = 0; | |
| 369 | } | |
| 370 | ||
| 371 | m_data_bus = 0xff; | |
| 372 | } | |
| 373 | break; | |
| 374 | } | |
| 375 | ||
| 376 | m_byte_count = 0; | |
| 377 | m_data_bus = 0xff; | |
| 378 | } | |
| 379 | else | |
| 380 | { | |
| 381 | switch (m_par[0] & 0x0f) | |
| 382 | { | |
| 383 | case LCD_BYTE_INPUT: | |
| 384 | { | |
| 385 | if (((m_par[0]>>5) & 0x07) != 0x03) | |
| 386 | break; | |
| 387 | ||
| 388 | m_offset %= 0x180; | |
| 389 | m_data_bus = ((m_video_ram[m_bank][m_offset]<<4)&0xf0) | ((m_video_ram[m_bank][m_offset]>>4)&0x0f); | |
| 390 | m_offset++; m_byte_count++; | |
| 391 | } | |
| 392 | break; | |
| 393 | case LCD_BYTE_OUTPUT: | |
| 394 | { | |
| 395 | m_offset %= 0x180; | |
| 396 | m_video_ram[m_bank][m_offset] = compute_newval((m_par[0]>>5) & 0x07, m_video_ram[m_bank][m_offset], data); | |
| 397 | m_offset++; m_byte_count++; | |
| 398 | ||
| 399 | m_data_bus = 0xff; | |
| 400 | } | |
| 401 | break; | |
| 402 | case LCD_CHAR_OUTPUT: | |
| 403 | { | |
| 404 | int char_pos = data*8; | |
| 405 | ||
| 406 | for (int i=0; i<m_char_width; i++) | |
| 407 | { | |
| 408 | m_offset %= 0x180; | |
| 409 | m_video_ram[m_bank][m_offset] = compute_newval((m_par[0]>>5) & 0x07, m_video_ram[m_bank][m_offset], get_char(char_pos)); | |
| 410 | m_offset++; char_pos++; | |
| 411 | } | |
| 412 | ||
| 413 | m_byte_count++; | |
| 414 | m_data_bus = 0xff; | |
| 415 | } | |
| 416 | break; | |
| 417 | case LCD_CURSOR_GRAPHIC: | |
| 418 | if (m_byte_count<8) | |
| 419 | { | |
| 420 | m_cursor[m_byte_count] = data; | |
| 421 | m_byte_count++; | |
| 422 | m_data_bus = 0xff; | |
| 423 | } | |
| 424 | break; | |
| 425 | case LCD_CURSOR_CHAR: | |
| 426 | if (m_byte_count<1) | |
| 427 | { | |
| 428 | UINT8 char_code = ((data<<4)&0xf0) | ((data>>4)&0x0f); | |
| 429 | ||
| 430 | for (int i=0; i<8; i++) | |
| 431 | m_cursor[i] = get_char(char_code*8 + i); | |
| 432 | ||
| 433 | m_byte_count++; | |
| 434 | m_data_bus = 0xff; | |
| 435 | } | |
| 436 | break; | |
| 437 | case LCD_USER_CHARACTER: | |
| 438 | if (m_byte_count<8) | |
| 439 | { | |
| 440 | m_custom_char[(m_par[1]&0x03)][m_byte_count] = data; | |
| 441 | m_byte_count++; | |
| 442 | m_data_bus = 0xff; | |
| 443 | } | |
| 444 | break; | |
| 445 | default: | |
| 446 | m_data_bus = 0xff; | |
| 447 | } | |
| 448 | ||
| 449 | m_state=0; | |
| 450 | } | |
| 451 | } | |
| 452 | ||
| 453 | UINT8 hd44352_device::data_read() | |
| 454 | { | |
| 455 | return m_data_bus; | |
| 456 | } |
| r21684 | r21685 | |
|---|---|---|
| 1 | /*************************************************************************** | |
| 2 | ||
| 3 | Hitachi HD44352 LCD controller | |
| 4 | ||
| 5 | ***************************************************************************/ | |
| 6 | ||
| 7 | #pragma once | |
| 8 | ||
| 9 | #ifndef __hd44352_H__ | |
| 10 | #define __hd44352_H__ | |
| 11 | ||
| 12 | ||
| 13 | #define MCFG_HD44352_ADD( _tag, _clock, _config) \ | |
| 14 | MCFG_DEVICE_ADD( _tag, HD44352, _clock ) \ | |
| 15 | MCFG_DEVICE_CONFIG( _config ) | |
| 16 | ||
| 17 | //************************************************************************** | |
| 18 | // TYPE DEFINITIONS | |
| 19 | //************************************************************************** | |
| 20 | ||
| 21 | ||
| 22 | // ======================> hd44352_interface | |
| 23 | ||
| 24 | struct hd44352_interface | |
| 25 | { | |
| 26 | devcb_write_line m_on_cb; // ON line | |
| 27 | }; | |
| 28 | ||
| 29 | // ======================> hd44352_device | |
| 30 | ||
| 31 | class hd44352_device : | |
| 32 | public device_t, | |
| 33 | public hd44352_interface | |
| 34 | { | |
| 35 | public: | |
| 36 | // construction/destruction | |
| 37 | hd44352_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); | |
| 38 | ||
| 39 | // device interface | |
| 40 | UINT8 data_read(); | |
| 41 | void data_write(UINT8 data); | |
| 42 | void control_write(UINT8 data); | |
| 43 | ||
| 44 | UINT32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); | |
| 45 | ||
| 46 | protected: | |
| 47 | // device-level overrides | |
| 48 | virtual void device_start(); | |
| 49 | virtual void device_reset(); | |
| 50 | virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); | |
| 51 | virtual void device_config_complete(); | |
| 52 | virtual void device_validity_check(validity_checker &valid) const; | |
| 53 | ||
| 54 | private: | |
| 55 | UINT8 compute_newval(UINT8 type, UINT8 oldval, UINT8 newval); | |
| 56 | UINT8 get_char(UINT16 pos); | |
| 57 | ||
| 58 | static const device_timer_id ON_TIMER = 1; | |
| 59 | emu_timer *m_on_timer; | |
| 60 | ||
| 61 | UINT8 m_video_ram[2][0x180]; | |
| 62 | UINT8 m_control_lines; | |
| 63 | UINT8 m_data_bus; | |
| 64 | UINT8 m_par[3]; | |
| 65 | UINT8 m_state; | |
| 66 | UINT16 m_bank; | |
| 67 | UINT16 m_offset; | |
| 68 | UINT8 m_char_width; | |
| 69 | UINT8 m_lcd_on; | |
| 70 | UINT8 m_scroll; | |
| 71 | UINT32 m_contrast; | |
| 72 | ||
| 73 | UINT8 m_custom_char[4][8]; // 4 chars * 8 bytes | |
| 74 | UINT8 m_byte_count; | |
| 75 | UINT8 m_cursor_status; | |
| 76 | UINT8 m_cursor[8]; | |
| 77 | UINT8 m_cursor_x; | |
| 78 | UINT8 m_cursor_y; | |
| 79 | UINT8 m_cursor_lcd; | |
| 80 | ||
| 81 | devcb_resolved_write_line m_on; // ON line callback | |
| 82 | }; | |
| 83 | ||
| 84 | // device type definition | |
| 85 | extern const device_type HD44352; | |
| 86 | ||
| 87 | #endif |
| r21684 | r21685 | |
|---|---|---|
| 58 | 58 | #include "video/vic4567.h" |
| 59 | 59 | #include "includes/cbm.h" |
| 60 | 60 | #include "machine/cbm_snqk.h" |
| 61 | #include "includes/c64_legacy.h" | |
| 62 | 61 | #include "includes/c65.h" |
| 63 | 62 | #include "machine/cbmiec.h" |
| 64 | 63 | #include "machine/ram.h" |
| r21684 | r21685 | |
| 202 | 201 | * |
| 203 | 202 | *************************************/ |
| 204 | 203 | |
| 204 | static int c64_paddle_read( device_t *device, address_space &space, int which ) | |
| 205 | { | |
| 206 | running_machine &machine = device->machine(); | |
| 207 | int pot1 = 0xff, pot2 = 0xff, pot3 = 0xff, pot4 = 0xff, temp; | |
| 208 | UINT8 cia0porta = mos6526_pa_r(machine.device("cia_0"), space, 0); | |
| 209 | int controller1 = machine.root_device().ioport("CTRLSEL")->read() & 0x07; | |
| 210 | int controller2 = machine.root_device().ioport("CTRLSEL")->read() & 0x70; | |
| 211 | /* Notice that only a single input is defined for Mouse & Lightpen in both ports */ | |
| 212 | switch (controller1) | |
| 213 | { | |
| 214 | case 0x01: | |
| 215 | if (which) | |
| 216 | pot2 = machine.root_device().ioport("PADDLE2")->read(); | |
| 217 | else | |
| 218 | pot1 = machine.root_device().ioport("PADDLE1")->read(); | |
| 219 | break; | |
| 220 | ||
| 221 | case 0x02: | |
| 222 | if (which) | |
| 223 | pot2 = machine.root_device().ioport("TRACKY")->read(); | |
| 224 | else | |
| 225 | pot1 = machine.root_device().ioport("TRACKX")->read(); | |
| 226 | break; | |
| 227 | ||
| 228 | case 0x03: | |
| 229 | if (which && (machine.root_device().ioport("JOY1_2B")->read() & 0x20)) /* Joy1 Button 2 */ | |
| 230 | pot1 = 0x00; | |
| 231 | break; | |
| 232 | ||
| 233 | case 0x04: | |
| 234 | if (which) | |
| 235 | pot2 = machine.root_device().ioport("LIGHTY")->read(); | |
| 236 | else | |
| 237 | pot1 = machine.root_device().ioport("LIGHTX")->read(); | |
| 238 | break; | |
| 239 | ||
| 240 | case 0x06: | |
| 241 | if (which && (machine.root_device().ioport("OTHER")->read() & 0x04)) /* Lightpen Signal */ | |
| 242 | pot2 = 0x00; | |
| 243 | break; | |
| 244 | ||
| 245 | case 0x00: | |
| 246 | case 0x07: | |
| 247 | break; | |
| 248 | ||
| 249 | default: | |
| 250 | logerror("Invalid Controller Setting %d\n", controller1); | |
| 251 | break; | |
| 252 | } | |
| 253 | ||
| 254 | switch (controller2) | |
| 255 | { | |
| 256 | case 0x10: | |
| 257 | if (which) | |
| 258 | pot4 = machine.root_device().ioport("PADDLE4")->read(); | |
| 259 | else | |
| 260 | pot3 = machine.root_device().ioport("PADDLE3")->read(); | |
| 261 | break; | |
| 262 | ||
| 263 | case 0x20: | |
| 264 | if (which) | |
| 265 | pot4 = machine.root_device().ioport("TRACKY")->read(); | |
| 266 | else | |
| 267 | pot3 = machine.root_device().ioport("TRACKX")->read(); | |
| 268 | break; | |
| 269 | ||
| 270 | case 0x30: | |
| 271 | if (which && (machine.root_device().ioport("JOY2_2B")->read() & 0x20)) /* Joy2 Button 2 */ | |
| 272 | pot4 = 0x00; | |
| 273 | break; | |
| 274 | ||
| 275 | case 0x40: | |
| 276 | if (which) | |
| 277 | pot4 = machine.root_device().ioport("LIGHTY")->read(); | |
| 278 | else | |
| 279 | pot3 = machine.root_device().ioport("LIGHTX")->read(); | |
| 280 | break; | |
| 281 | ||
| 282 | case 0x60: | |
| 283 | if (which && (machine.root_device().ioport("OTHER")->read() & 0x04)) /* Lightpen Signal */ | |
| 284 | pot4 = 0x00; | |
| 285 | break; | |
| 286 | ||
| 287 | case 0x00: | |
| 288 | case 0x70: | |
| 289 | break; | |
| 290 | ||
| 291 | default: | |
| 292 | logerror("Invalid Controller Setting %d\n", controller1); | |
| 293 | break; | |
| 294 | } | |
| 295 | ||
| 296 | if (machine.root_device().ioport("CTRLSEL")->read() & 0x80) /* Swap */ | |
| 297 | { | |
| 298 | temp = pot1; pot1 = pot3; pot3 = temp; | |
| 299 | temp = pot2; pot2 = pot4; pot4 = temp; | |
| 300 | } | |
| 301 | ||
| 302 | switch (cia0porta & 0xc0) | |
| 303 | { | |
| 304 | case 0x40: | |
| 305 | return which ? pot2 : pot1; | |
| 306 | ||
| 307 | case 0x80: | |
| 308 | return which ? pot4 : pot3; | |
| 309 | ||
| 310 | case 0xc0: | |
| 311 | return which ? pot2 : pot1; | |
| 312 | ||
| 313 | default: | |
| 314 | return 0; | |
| 315 | } | |
| 316 | } | |
| 317 | ||
| 205 | 318 | READ8_MEMBER( c65_state::sid_potx_r ) |
| 206 | 319 | { |
| 207 | 320 | device_t *sid = machine().device("sid_r"); |
| r21684 | r21685 | |
| 333 | 446 | /* floppy from serial bus */ |
| 334 | 447 | MCFG_CBM_IEC_ADD(NULL) |
| 335 | 448 | |
| 336 | MCFG_FRAGMENT_ADD(c64_cartslot) | |
| 337 | ||
| 338 | 449 | /* internal ram */ |
| 339 | 450 | MCFG_RAM_ADD(RAM_TAG) |
| 340 | 451 | MCFG_RAM_DEFAULT_SIZE("128K") |
| r21684 | r21685 | |
|---|---|---|
| 432 | 432 | $(MAME_VIDEO)/amigaaga.o \ |
| 433 | 433 | $(MAME_MACHINE)/amiga.o \ |
| 434 | 434 | $(MAME_AUDIO)/amiga.o \ |
| 435 | $(MAME_MACHINE)/cd32.o \ | |
| 435 | $(MAME_MACHINE)/cd32.o \ | |
| 436 | 436 | $(MAME_VIDEO)/tia.o \ |
| 437 | 437 | $(MAME_MACHINE)/atari.o \ |
| 438 | 438 | $(MAME_VIDEO)/atari.o \ |
| r21684 | r21685 | |
| 456 | 456 | $(MAME_VIDEO)/rdpspn16.o \ |
| 457 | 457 | $(MAME_MACHINE)/pcshare.o \ |
| 458 | 458 | $(MAME_MACHINE)/megadriv.o \ |
| 459 | $(MAME_MACHINE)/megacd.o \ | |
| 460 | $(MAME_MACHINE)/megacdcd.o \ | |
| 461 | $(MAME_MACHINE)/mega32x.o \ | |
| 462 | $(MAME_MACHINE)/megavdp.o \ | |
| 459 | $(MAME_MACHINE)/megacd.o \ | |
| 460 | $(MAME_MACHINE)/megacdcd.o \ | |
| 461 | $(MAME_MACHINE)/mega32x.o \ | |
| 462 | $(MAME_MACHINE)/megavdp.o \ | |
| 463 | 463 | $(MAME_MACHINE)/dc.o \ |
| 464 | 464 | $(MAME_DRIVERS)/naomi.o \ |
| 465 | 465 | $(MAME_MACHINE)/dc.o \ |
| r21684 | r21685 | |
| 493 | 493 | $(MAME_DRIVERS)/vectrex.o \ |
| 494 | 494 | $(MAME_VIDEO)/vectrex.o \ |
| 495 | 495 | $(MAME_MACHINE)/vectrex.o \ |
| 496 | $(MAME_DRIVERS)/cps1.o \ | |
| 497 | $(MAME_VIDEO)/cps1.o \ | |
| 498 | $(MAME_DRIVERS)/konamim2.o \ | |
| 496 | $(MAME_DRIVERS)/cps1.o \ | |
| 497 | $(MAME_VIDEO)/cps1.o \ | |
| 498 | $(MAME_DRIVERS)/konamim2.o \ | |
| 499 | 499 | |
| 500 | 500 | |
| 501 | 501 | #------------------------------------------------- |
| r21684 | r21685 | |
| 506 | 506 | $(MESSOBJ)/shared.a: \ |
| 507 | 507 | $(MESS_AUDIO)/mea8000.o \ |
| 508 | 508 | $(MESS_AUDIO)/spchroms.o \ |
| 509 | $(MESS_MACHINE)/microdrv.o \ | |
| 510 | $(MESS_MACHINE)/74145.o \ | |
| 509 | $(MESS_MACHINE)/3c503.o \ | |
| 511 | 510 | $(MESS_MACHINE)/68561mpcc.o \ |
| 512 | 511 | $(MESS_MACHINE)/8530scc.o \ |
| 513 | $(MESS_MACHINE)/at45dbxx.o \ | |
| 514 | $(MESS_MACHINE)/ay31015.o \ | |
| 515 | $(MESS_MACHINE)/er59256.o \ | |
| 512 | $(MESS_MACHINE)/appldriv.o \ | |
| 513 | $(MESS_MACHINE)/applefdc.o \ | |
| 514 | $(MESS_MACHINE)/cntr_covox.o\ | |
| 515 | $(MESS_MACHINE)/dp8390.o \ | |
| 516 | 516 | $(MESS_MACHINE)/hd63450.o \ |
| 517 | 517 | $(MESS_MACHINE)/i8271.o \ |
| 518 | 518 | $(MESS_MACHINE)/ieee488.o \ |
| r21684 | r21685 | |
| 520 | 520 | $(MESS_MACHINE)/kb3600.o \ |
| 521 | 521 | $(MESS_MACHINE)/keyboard.o \ |
| 522 | 522 | $(MESS_MACHINE)/kr2376.o \ |
| 523 | $(MESS_MACHINE)/mc6843.o \ | |
| 524 | $(MESS_MACHINE)/mc6846.o \ | |
| 525 | $(MESS_MACHINE)/mc6854.o \ | |
| 526 | $(MESS_MACHINE)/mm58274c.o \ | |
| 523 | $(MESS_MACHINE)/mb8795.o \ | |
| 524 | $(MESS_MACHINE)/microdrv.o \ | |
| 525 | $(MESS_MACHINE)/midiinport.o \ | |
| 526 | $(MESS_MACHINE)/midioutport.o \ | |
| 527 | 527 | $(MESS_MACHINE)/mpc105.o \ |
| 528 | $(MESS_MACHINE)/mos6530.o \ | |
| 529 | $(MESS_MACHINE)/s100.o \ | |
| 530 | $(MESS_MACHINE)/sed1200.o \ | |
| 531 | 528 | $(MESS_MACHINE)/msm6222b.o \ |
| 532 | $(MESS_MACHINE)/serial.o \ | |
| 533 | 529 | $(MESS_MACHINE)/ncr5380.o \ |
| 534 | $(MESS_MACHINE)/ncr5380n.o | |
| 530 | $(MESS_MACHINE)/ncr5380n.o \ | |
| 535 | 531 | $(MESS_MACHINE)/ncr5390.o \ |
| 532 | $(MESS_MACHINE)/ne1000.o \ | |
| 533 | $(MESS_MACHINE)/ne2000.o \ | |
| 534 | $(MESS_MACHINE)/null_modem.o\ | |
| 536 | 535 | $(MESS_MACHINE)/pc_kbdc.o \ |
| 537 | 536 | $(MESS_MACHINE)/pc_lpt.o \ |
| 538 | $(MESS_MACHINE)/cntr_covox.o \ | |
| 539 | $(MESS_MACHINE)/pcf8593.o \ | |
| 537 | $(MESS_MACHINE)/s100.o \ | |
| 540 | 538 | $(MESS_MACHINE)/sa1403d.o \ |
| 539 | $(MESS_MACHINE)/sed1200.o \ | |
| 540 | $(MESS_MACHINE)/serial.o \ | |
| 541 | 541 | $(MESS_MACHINE)/smartmed.o \ |
| 542 | 542 | $(MESS_MACHINE)/smc92x4.o \ |
| 543 | $(MESS_MACHINE)/terminal.o \ | |
| 544 | $(MESS_MACHINE)/teleprinter.o \ | |
| 545 | $(MESS_MACHINE)/upd7002.o \ | |
| 546 | $(MESS_MACHINE)/wd11c00_17.o \ | |
| 547 | $(MESS_MACHINE)/wd2010.o \ | |
| 548 | $(MESS_VIDEO)/dl1416.o \ | |
| 549 | $(MESS_VIDEO)/hd44780.o \ | |
| 550 | $(MESS_VIDEO)/hd66421.o \ | |
| 551 | $(MESS_VIDEO)/mc6847.o \ | |
| 552 | $(MESS_VIDEO)/tms3556.o \ | |
| 553 | $(MESS_VIDEO)/upd7220.o \ | |
| 554 | $(MESS_MACHINE)/applefdc.o \ | |
| 555 | 543 | $(MESS_MACHINE)/sonydriv.o \ |
| 556 | $(MESS_MACHINE)/appldriv.o \ | |
| 557 | $(MESS_MACHINE)/dp8390.o \ | |
| 558 | $(MESS_MACHINE)/ne1000.o \ | |
| 559 | $(MESS_MACHINE)/ne2000.o \ | |
| 560 | $(MESS_MACHINE)/3c503.o \ | |
| 561 | $(MESS_MACHINE)/z80bin.o \ | |
| 562 | $(MESS_MACHINE)/mb8795.o \ | |
| 563 | $(MESS_MACHINE)/midiinport.o \ | |
| 564 | $(MESS_MACHINE)/midioutport.o \ | |
| 565 | $(MESS_MACHINE)/null_modem.o \ | |
| 566 | $(MESS_MACHINE)/vcsctrl.o \ | |
| 544 | $(MESS_MACHINE)/teleprinter.o \ | |
| 545 | $(MESS_MACHINE)/terminal.o \ | |
| 567 | 546 | $(MESS_MACHINE)/vcs_joy.o \ |
| 547 | $(MESS_MACHINE)/vcs_joybooster.o\ | |
| 548 | $(MESS_MACHINE)/vcs_keypad.o \ | |
| 568 | 549 | $(MESS_MACHINE)/vcs_lightpen.o \ |
| 569 | 550 | $(MESS_MACHINE)/vcs_paddles.o \ |
| 570 | $(MESS_MACHINE)/vcs_joybooster.o \ | |
| 571 | 551 | $(MESS_MACHINE)/vcs_wheel.o \ |
| 572 | $(MESS_MACHINE)/vcs_keypad.o \ | |
| 552 | $(MESS_MACHINE)/vcsctrl.o \ | |
| 553 | $(MESS_MACHINE)/z80bin.o \ | |
| 573 | 554 | |
| 574 | 555 | |
| 575 | ||
| 576 | 556 | #------------------------------------------------- |
| 577 | 557 | # manufacturer-specific groupings for drivers |
| 578 | 558 | #------------------------------------------------- |
| r21684 | r21685 | |
| 610 | 590 | |
| 611 | 591 | $(MESSOBJ)/adc.a: \ |
| 612 | 592 | $(MESS_DRIVERS)/super6.o \ |
| 613 | $(MESS_DRIVERS)/superslave.o | |
| 593 | $(MESS_DRIVERS)/superslave.o\ | |
| 614 | 594 | |
| 615 | 595 | $(MESSOBJ)/alesis.a: \ |
| 616 | 596 | $(MESS_DRIVERS)/alesis.o \ |
| r21684 | r21685 | |
| 659 | 639 | $(MESS_MACHINE)/apollo_eth.o \ |
| 660 | 640 | $(MESS_MACHINE)/apollo_net.o \ |
| 661 | 641 | $(MESS_MACHINE)/apollo_kbd.o \ |
| 662 | $(MESS_MACHINE)/3c505.o \ | |
| 663 | $(MESS_MACHINE)/apollo.o \ | |
| 642 | $(MESS_MACHINE)/3c505.o \ | |
| 643 | $(MESS_MACHINE)/apollo.o \ | |
| 664 | 644 | |
| 665 | 645 | $(MESSOBJ)/apple.a: \ |
| 666 | 646 | $(MESS_VIDEO)/apple2.o \ |
| r21684 | r21685 | |
| 680 | 660 | $(MESS_MACHINE)/a2thunderclock.o \ |
| 681 | 661 | $(MESS_MACHINE)/a2softcard.o \ |
| 682 | 662 | $(MESS_MACHINE)/a2videoterm.o \ |
| 683 | $(MESS_MACHINE)/a2ssc.o \ | |
| 684 | $(MESS_MACHINE)/a2swyft.o \ | |
| 685 | $(MESS_MACHINE)/a2eauxslot.o \ | |
| 663 | $(MESS_MACHINE)/a2ssc.o \ | |
| 664 | $(MESS_MACHINE)/a2swyft.o \ | |
| 665 | $(MESS_MACHINE)/a2eauxslot.o\ | |
| 686 | 666 | $(MESS_MACHINE)/a2themill.o \ |
| 687 | $(MESS_MACHINE)/a2sam.o \ | |
| 688 | $(MESS_MACHINE)/a2alfam2.o \ | |
| 689 | $(MESS_MACHINE)/laser128.o \ | |
| 690 | $(MESS_MACHINE)/a2echoii.o \ | |
| 691 | $(MESS_MACHINE)/a2arcadebd.o \ | |
| 692 | $(MESS_MACHINE)/a2midi.o \ | |
| 693 | $(MESS_MACHINE)/a2vulcan.o \ | |
| 694 | $(MESS_MACHINE)/a2zipdrive.o \ | |
| 667 | $(MESS_MACHINE)/a2sam.o \ | |
| 668 | $(MESS_MACHINE)/a2alfam2.o \ | |
| 669 | $(MESS_MACHINE)/laser128.o \ | |
| 670 | $(MESS_MACHINE)/a2echoii.o \ | |
| 671 | $(MESS_MACHINE)/a2arcadebd.o\ | |
| 672 | $(MESS_MACHINE)/a2midi.o \ | |
| 673 | $(MESS_MACHINE)/a2vulcan.o \ | |
| 674 | $(MESS_MACHINE)/a2zipdrive.o\ | |
| 695 | 675 | $(MESS_MACHINE)/a2estd80col.o \ |
| 696 | 676 | $(MESS_MACHINE)/a2eext80col.o \ |
| 697 | 677 | $(MESS_MACHINE)/a2eramworks3.o \ |
| r21684 | r21685 | |
| 730 | 710 | $(MESS_VIDEO)/pds30_cb264.o \ |
| 731 | 711 | $(MESS_VIDEO)/pds30_procolor816.o \ |
| 732 | 712 | $(MESS_VIDEO)/pds30_sigmalview.o \ |
| 733 | $(MESS_VIDEO)/pds30_30hr.o \ | |
| 734 | $(MESS_VIDEO)/pds30_mc30.o \ | |
| 713 | $(MESS_VIDEO)/pds30_30hr.o \ | |
| 714 | $(MESS_VIDEO)/pds30_mc30.o \ | |
| 735 | 715 | |
| 736 | 716 | $(MESSOBJ)/applied.a: \ |
| 737 | 717 | $(MESS_VIDEO)/mbee.o \ |
| r21684 | r21685 | |
| 821 | 801 | $(MESS_DRIVERS)/pv2000.o \ |
| 822 | 802 | $(MESS_DRIVERS)/pb1000.o \ |
| 823 | 803 | $(MESS_DRIVERS)/fp6000.o \ |
| 824 | $(MESS_VIDEO)/hd44352.o \ | |
| 825 | 804 | |
| 826 | 805 | $(MESSOBJ)/cbm.a: \ |
| 827 | $(MESS_DRIVERS)/pet.o | |
| 806 | $(MESS_DRIVERS)/pet.o \ | |
| 828 | 807 | $(MESS_MACHINE)/petcass.o \ |
| 829 | $(MESS_MACHINE)/petexp.o | |
| 808 | $(MESS_MACHINE)/petexp.o \ | |
| 830 | 809 | $(MESS_MACHINE)/petuser.o \ |
| 831 | 810 | $(MESS_MACHINE)/pet_64k.o \ |
| 832 | 811 | $(MESS_MACHINE)/superpet.o \ |
| 833 | 812 | $(MESS_MACHINE)/mos6702.o \ |
| 834 | 813 | $(MESS_DRIVERS)/c64.o \ |
| 835 | $(MESS_MACHINE)/c64_legacy.o \ | |
| 836 | 814 | $(MESS_DRIVERS)/c64dtv.o \ |
| 837 | 815 | $(MESS_MACHINE)/c64exp.o \ |
| 838 | 816 | $(MESS_MACHINE)/c64user.o \ |
| r21684 | r21685 | |
| 841 | 819 | $(MESS_MACHINE)/c64_4ksa.o \ |
| 842 | 820 | $(MESS_MACHINE)/c64_4tba.o \ |
| 843 | 821 | $(MESS_MACHINE)/c64_16kb.o \ |
| 844 | $(MESS_MACHINE)/c64_bn1541.o | |
| 822 | $(MESS_MACHINE)/c64_bn1541.o\ | |
| 845 | 823 | $(MESS_MACHINE)/c64_comal80.o \ |
| 846 | 824 | $(MESS_MACHINE)/c64_cpm.o \ |
| 847 | 825 | $(MESS_MACHINE)/c64_currah_speech.o \ |
| r21684 | r21685 | |
| 856 | 834 | $(MESS_MACHINE)/c64_exos.o \ |
| 857 | 835 | $(MESS_MACHINE)/c64_fcc.o \ |
| 858 | 836 | $(MESS_MACHINE)/c64_final.o \ |
| 859 | $(MESS_MACHINE)/c64_final3.o | |
| 837 | $(MESS_MACHINE)/c64_final3.o\ | |
| 860 | 838 | $(MESS_MACHINE)/c64_fun_play.o \ |
| 861 | 839 | $(MESS_MACHINE)/c64_geocable.o \ |
| 862 | 840 | $(MESS_MACHINE)/c64_georam.o \ |
| r21684 | r21685 | |
| 874 | 852 | $(MESS_MACHINE)/c64_midi_siel.o \ |
| 875 | 853 | $(MESS_MACHINE)/c64_mikro_assembler.o \ |
| 876 | 854 | $(MESS_MACHINE)/c64_multiscreen.o \ |
| 877 | $(MESS_MACHINE)/c64_neoram.o | |
| 855 | $(MESS_MACHINE)/c64_neoram.o\ | |
| 878 | 856 | $(MESS_MACHINE)/c64_ocean.o \ |
| 879 | 857 | $(MESS_MACHINE)/c64_pagefox.o \ |
| 880 | 858 | $(MESS_MACHINE)/c64_prophet64.o \ |
| r21684 | r21685 | |
| 903 | 881 | $(MESS_MACHINE)/c64_warp_speed.o \ |
| 904 | 882 | $(MESS_MACHINE)/c64_westermann.o \ |
| 905 | 883 | $(MESS_MACHINE)/c64_xl80.o \ |
| 906 | $(MESS_MACHINE)/c64_zaxxon.o | |
| 884 | $(MESS_MACHINE)/c64_zaxxon.o\ | |
| 907 | 885 | $(MESS_MACHINE)/interpod.o \ |
| 908 | 886 | $(MESS_DRIVERS)/vic10.o \ |
| 909 | 887 | $(MESS_MACHINE)/vic10exp.o \ |
| r21684 | r21685 | |
| 933 | 911 | $(MESS_MACHINE)/cbm2_std.o \ |
| 934 | 912 | $(MESS_MACHINE)/cbm2_24k.o \ |
| 935 | 913 | $(MESS_MACHINE)/cbm2_graphic.o \ |
| 936 | $(MESS_MACHINE)/cbm2user.o | |
| 914 | $(MESS_MACHINE)/cbm2user.o \ | |
| 937 | 915 | $(MESS_DRIVERS)/c65.o \ |
| 938 | 916 | $(MESS_MACHINE)/c65.o \ |
| 939 | 917 | $(MESS_DRIVERS)/c128.o \ |
| r21684 | r21685 | |
| 950 | 928 | $(MESS_MACHINE)/d9060hd.o \ |
| 951 | 929 | $(MESS_MACHINE)/softbox.o \ |
| 952 | 930 | $(MESS_MACHINE)/serialbox.o \ |
| 953 | $(MESS_MACHINE)/cmdhd.o \ | |
| 931 | $(MESS_MACHINE)/cmdhd.o \ | |
| 954 | 932 | $(MESS_MACHINE)/fd2000.o \ |
| 955 | 933 | $(MESS_DRIVERS)/clcd.o \ |
| 956 | 934 | $(MESS_MACHINE)/cbm.o \ |
| r21684 | r21685 | |
| 1166 | 1144 | $(MESSOBJ)/exidy.a: \ |
| 1167 | 1145 | $(MESS_MACHINE)/sorcerer.o \ |
| 1168 | 1146 | $(MESS_DRIVERS)/sorcerer.o \ |
| 1169 | $(MESS_MACHINE)/micropolis.o | |
| 1147 | $(MESS_MACHINE)/micropolis.o\ | |
| 1170 | 1148 | |
| 1171 | 1149 | $(MESSOBJ)/fairch.a: \ |
| 1172 | 1150 | $(MESS_VIDEO)/channelf.o \ |
| r21684 | r21685 | |
| 1179 | 1157 | $(MESS_MACHINE)/upd71071.o \ |
| 1180 | 1158 | $(MESS_MACHINE)/fm_scsi.o \ |
| 1181 | 1159 | $(MESS_DRIVERS)/fm7.o \ |
| 1182 | $(MESS_VIDEO)/fm7.o \ | |
| 1160 | $(MESS_VIDEO)/fm7.o \ | |
| 1183 | 1161 | |
| 1184 | 1162 | $(MESSOBJ)/funtech.a: \ |
| 1185 | 1163 | $(MESS_DRIVERS)/supracan.o \ |
| r21684 | r21685 | |
| 1211 | 1189 | $(MESS_MACHINE)/mboard.o \ |
| 1212 | 1190 | $(MESS_DRIVERS)/glasgow.o \ |
| 1213 | 1191 | $(MESS_DRIVERS)/mephisto.o \ |
| 1214 | | |
| 1192 | $(MESS_DRIVERS)/mmodular.o \ | |
| 1215 | 1193 | |
| 1216 | 1194 | |
| 1217 | 1195 | $(MESSOBJ)/hitachi.a: \ |
| 1218 | 1196 | $(MESS_DRIVERS)/bmjr.o \ |
| 1219 | 1197 | $(MESS_DRIVERS)/bml3.o \ |
| 1220 | $(MESS_DRIVERS)/b16.o | |
| 1198 | $(MESS_DRIVERS)/b16.o \ | |
| 1221 | 1199 | |
| 1222 | 1200 | $(MESSOBJ)/homebrew.a: \ |
| 1223 | 1201 | $(MESS_DRIVERS)/4004clk.o \ |
| r21684 | r21685 | |
| 1301 | 1279 | $(MESS_MACHINE)/abc_dos.o \ |
| 1302 | 1280 | $(MESS_MACHINE)/abc_fd2.o \ |
| 1303 | 1281 | $(MESS_MACHINE)/abc_hdc.o \ |
| 1304 | $(MESS_MACHINE)/abc_uni800.o | |
| 1282 | $(MESS_MACHINE)/abc_uni800.o\ | |
| 1305 | 1283 | $(MESS_MACHINE)/abc_sio.o \ |
| 1306 | 1284 | $(MESS_MACHINE)/abc_slutprov.o \ |
| 1307 | 1285 | $(MESS_MACHINE)/abc_turbo.o \ |
| r21684 | r21685 | |
| 1329 | 1307 | $(MESSOBJ)/matsushi.a: \ |
| 1330 | 1308 | $(MESS_DRIVERS)/jr100.o \ |
| 1331 | 1309 | $(MESS_DRIVERS)/jr200.o \ |
| 1332 | $(MESS_DRIVERS)/myb3k.o | |
| 1310 | $(MESS_DRIVERS)/myb3k.o \ | |
| 1333 | 1311 | |
| 1334 | 1312 | $(MESSOBJ)/mb.a: \ |
| 1335 | 1313 | $(MESS_DRIVERS)/microvsn.o \ |
| r21684 | r21685 | |
| 1366 | 1344 | |
| 1367 | 1345 | $(MESSOBJ)/morrow.a: \ |
| 1368 | 1346 | $(MESS_DRIVERS)/mpz80.o \ |
| 1369 | $(MESS_MACHINE)/s100_dj2db.o \ | |
| 1370 | $(MESS_MACHINE)/s100_djdma.o \ | |
| 1347 | $(MESS_MACHINE)/s100_dj2db.o\ | |
| 1348 | $(MESS_MACHINE)/s100_djdma.o\ | |
| 1371 | 1349 | $(MESS_MACHINE)/s100_mm65k16s.o \ |
| 1372 | 1350 | $(MESS_MACHINE)/s100_wunderbus.o \ |
| 1373 | 1351 | |
| r21684 | r21685 | |
| 1430 | 1408 | $(MESS_MACHINE)/sns_sdd1.o \ |
| 1431 | 1409 | $(MESS_MACHINE)/sns_sfx.o \ |
| 1432 | 1410 | $(MESS_MACHINE)/sns_spc7110.o \ |
| 1433 | $(MESS_MACHINE)/sns_sufami.o | |
| 1411 | $(MESS_MACHINE)/sns_sufami.o\ | |
| 1434 | 1412 | $(MESS_MACHINE)/sns_upd.o \ |
| 1435 | 1413 | $(MESS_DRIVERS)/snes.o \ |
| 1436 | 1414 | $(MESS_DRIVERS)/n64.o \ |
| r21684 | r21685 | |
| 1483 | 1461 | |
| 1484 | 1462 | $(MESSOBJ)/palm.a: \ |
| 1485 | 1463 | $(MESS_DRIVERS)/palm.o \ |
| 1486 | $(MESS_MACHINE)/mc68328.o \ | |
| 1487 | 1464 | $(MESS_VIDEO)/mc68328.o \ |
| 1488 | 1465 | $(MESS_DRIVERS)/palmz22.o \ |
| 1489 | 1466 | |
| r21684 | r21685 | |
| 1494 | 1471 | $(MESSOBJ)/pitronic.a: \ |
| 1495 | 1472 | $(MESS_DRIVERS)/beta.o \ |
| 1496 | 1473 | |
| 1497 | $(MESSOBJ)/pc.a: \ | |
| 1474 | $(MESSOBJ)/pc.a: \ | |
| 1498 | 1475 | $(MESS_VIDEO)/pc_aga.o \ |
| 1499 | 1476 | $(MESS_MACHINE)/tandy1t.o \ |
| 1500 | 1477 | $(MESS_MACHINE)/europc.o \ |
| r21684 | r21685 | |
| 1508 | 1485 | $(MESSOBJ)/pc9801.a: \ |
| 1509 | 1486 | $(MESS_MACHINE)/pc9801_26.o \ |
| 1510 | 1487 | $(MESS_MACHINE)/pc9801_86.o \ |
| 1511 | $(MESS_MACHINE)/pc9801_118.o | |
| 1488 | $(MESS_MACHINE)/pc9801_118.o\ | |
| 1512 | 1489 | $(MESS_MACHINE)/pc9801_cbus.o \ |
| 1513 | $(MESS_MACHINE)/pc9801_kbd.o | |
| 1490 | $(MESS_MACHINE)/pc9801_kbd.o\ | |
| 1514 | 1491 | |
| 1515 | 1492 | $(MESSOBJ)/pcshare.a: \ |
| 1516 | 1493 | $(MESS_MACHINE)/pc_turbo.o \ |
| r21684 | r21685 | |
| 1518 | 1495 | $(MESS_MACHINE)/pc_joy.o \ |
| 1519 | 1496 | $(MESS_MACHINE)/pc_keyboards.o \ |
| 1520 | 1497 | $(MESS_MACHINE)/kb_keytro.o \ |
| 1521 | $(MESS_MACHINE)/kb_msnat.o \ | |
| 1498 | $(MESS_MACHINE)/kb_msnat.o \ | |
| 1522 | 1499 | $(MESS_MACHINE)/isa_adlib.o \ |
| 1523 | 1500 | $(MESS_MACHINE)/ser_mouse.o \ |
| 1524 | 1501 | $(MESS_MACHINE)/isa_com.o \ |
| r21684 | r21685 | |
| 1528 | 1505 | $(MESS_MACHINE)/isa_gus.o \ |
| 1529 | 1506 | $(MESS_MACHINE)/isa_hdc.o \ |
| 1530 | 1507 | $(MESS_MACHINE)/isa_ibm_mfc.o \ |
| 1531 | $(MESS_MACHINE)/isa_mpu401.o | |
| 1508 | $(MESS_MACHINE)/isa_mpu401.o\ | |
| 1532 | 1509 | $(MESS_MACHINE)/isa_sblaster.o \ |
| 1533 | 1510 | $(MESS_MACHINE)/isa_stereo_fx.o \ |
| 1534 | 1511 | $(MESS_MACHINE)/isa_ssi2001.o \ |
| 1535 | 1512 | $(MESS_MACHINE)/isa_ide.o \ |
| 1536 | $(MESS_MACHINE)/isa_ide_cd.o | |
| 1513 | $(MESS_MACHINE)/isa_ide_cd.o\ | |
| 1537 | 1514 | $(MESS_MACHINE)/isa_aha1542.o \ |
| 1538 | 1515 | $(MESS_VIDEO)/isa_cga.o \ |
| 1539 | 1516 | $(MESS_VIDEO)/isa_mda.o \ |
| r21684 | r21685 | |
| 1575 | 1552 | |
| 1576 | 1553 | $(MESSOBJ)/psion.a: \ |
| 1577 | 1554 | $(MESS_DRIVERS)/psion.o \ |
| 1578 | $(MESS_MACHINE)/psion_pack.o | |
| 1555 | $(MESS_MACHINE)/psion_pack.o\ | |
| 1579 | 1556 | |
| 1580 | 1557 | $(MESSOBJ)/radio.a: \ |
| 1581 | 1558 | $(MESS_DRIVERS)/radio86.o \ |
| r21684 | r21685 | |
| 1589 | 1566 | $(MESSOBJ)/rca.a: \ |
| 1590 | 1567 | $(MESS_DRIVERS)/studio2.o \ |
| 1591 | 1568 | $(MESS_DRIVERS)/vip.o \ |
| 1592 | $(MESS_MACHINE)/vip_byteio.o | |
| 1569 | $(MESS_MACHINE)/vip_byteio.o\ | |
| 1593 | 1570 | $(MESS_MACHINE)/vip_exp.o \ |
| 1594 | 1571 | $(MESS_MACHINE)/vp550.o \ |
| 1595 | 1572 | $(MESS_MACHINE)/vp570.o \ |
| r21684 | r21685 | |
| 1700 | 1677 | $(MESS_DRIVERS)/x1twin.o \ |
| 1701 | 1678 | $(MESS_DRIVERS)/mz2500.o \ |
| 1702 | 1679 | $(MESS_DRIVERS)/pce220.o \ |
| 1703 | $(MESS_MACHINE)/pce220_ser.o | |
| 1680 | $(MESS_MACHINE)/pce220_ser.o\ | |
| 1704 | 1681 | $(MESS_DRIVERS)/mz6500.o \ |
| 1705 | 1682 | |
| 1706 | 1683 | $(MESSOBJ)/sinclair.a: \ |
| 1707 | 1684 | $(MESS_VIDEO)/spectrum.o \ |
| 1708 | 1685 | $(MESS_VIDEO)/timex.o \ |
| 1709 | $(MESS_VIDEO)/zx.o \ | |
| 1686 | $(MESS_VIDEO)/zx.o \ | |
| 1710 | 1687 | $(MESS_DRIVERS)/zx.o \ |
| 1711 | 1688 | $(MESS_MACHINE)/zx.o \ |
| 1712 | 1689 | $(MESS_DRIVERS)/spectrum.o \ |
| r21684 | r21685 | |
| 1804 | 1781 | $(MESS_VIDEO)/tmc600.o \ |
| 1805 | 1782 | $(MESS_DRIVERS)/tmc2000e.o \ |
| 1806 | 1783 | |
| 1807 | $(MESSOBJ)/tem.a: \ | |
| 1784 | $(MESSOBJ)/tem.a: \ | |
| 1808 | 1785 | $(MESS_DRIVERS)/tec1.o \ |
| 1809 | 1786 | |
| 1810 | $(MESSOBJ)/tesla.a: \ | |
| 1787 | $(MESSOBJ)/tesla.a: \ | |
| 1811 | 1788 | $(MESS_DRIVERS)/ondra.o \ |
| 1812 | 1789 | $(MESS_MACHINE)/ondra.o \ |
| 1813 | 1790 | $(MESS_VIDEO)/ondra.o \ |
| r21684 | r21685 | |
| 1834 | 1811 | $(MESS_MACHINE)/990_hd.o \ |
| 1835 | 1812 | $(MESS_MACHINE)/990_tap.o \ |
| 1836 | 1813 | $(MESS_MACHINE)/ti990.o \ |
| 1837 | $(MESS_MACHINE)/at29040a.o \ | |
| 1838 | 1814 | $(MESS_MACHINE)/ti99/datamux.o \ |
| 1839 | 1815 | $(MESS_MACHINE)/ti99/videowrp.o \ |
| 1840 | 1816 | $(MESS_MACHINE)/ti99/grom.o \ |
| r21684 | r21685 | |
| 1846 | 1822 | $(MESS_MACHINE)/ti99/ti32kmem.o \ |
| 1847 | 1823 | $(MESS_MACHINE)/ti99/ti_fdc.o \ |
| 1848 | 1824 | $(MESS_MACHINE)/ti99/bwg.o \ |
| 1849 | $(MESS_MACHINE)/ti99/hfdc.o | |
| 1825 | $(MESS_MACHINE)/ti99/hfdc.o \ | |
| 1850 | 1826 | $(MESS_MACHINE)/ti99/ti99_hd.o \ |
| 1851 | 1827 | $(MESS_MACHINE)/ti99/p_code.o \ |
| 1852 | 1828 | $(MESS_MACHINE)/ti99/myarcmem.o \ |
| r21684 | r21685 | |
| 1854 | 1830 | $(MESS_MACHINE)/ti99/tn_ide.o \ |
| 1855 | 1831 | $(MESS_MACHINE)/ti99/tn_usbsm.o \ |
| 1856 | 1832 | $(MESS_MACHINE)/ti99/evpc.o \ |
| 1857 | $(MESS_MACHINE)/ti99/hsgpl.o | |
| 1833 | $(MESS_MACHINE)/ti99/hsgpl.o\ | |
| 1858 | 1834 | $(MESS_MACHINE)/ti99/ti_rs232.o \ |
| 1859 | 1835 | $(MESS_MACHINE)/ti99/spchsyn.o \ |
| 1860 | 1836 | $(MESS_MACHINE)/ti99/speech8.o \ |
| r21684 | r21685 | |
| 1896 | 1872 | $(MESSOBJ)/toshiba.a: \ |
| 1897 | 1873 | $(MESS_DRIVERS)/pasopia.o \ |
| 1898 | 1874 | $(MESS_DRIVERS)/pasopia7.o \ |
| 1899 | $(MESS_DRIVERS)/paso1600.o | |
| 1875 | $(MESS_DRIVERS)/paso1600.o \ | |
| 1900 | 1876 | |
| 1901 | 1877 | $(MESSOBJ)/trs.a: \ |
| 1902 | 1878 | $(MESS_MACHINE)/6883sam.o \ |
| 1903 | 1879 | $(MESS_MACHINE)/ds1315.o \ |
| 1904 | 1880 | $(MESS_MACHINE)/coco.o \ |
| 1905 | $(MESS_MACHINE)/coco12.o \ | |
| 1906 | $(MESS_DRIVERS)/coco12.o \ | |
| 1881 | $(MESS_MACHINE)/coco12.o \ | |
| 1882 | $(MESS_DRIVERS)/coco12.o \ | |
| 1907 | 1883 | $(MESS_MACHINE)/coco3.o \ |
| 1908 | 1884 | $(MESS_DRIVERS)/coco3.o \ |
| 1909 | $(MESS_VIDEO)/gime.o \ | |
| 1910 | $(MESS_MACHINE)/dragon.o \ | |
| 1911 | $(MESS_DRIVERS)/dragon.o \ | |
| 1912 | $(MESS_MACHINE)/dgnalpha.o \ | |
| 1913 | $(MESS_MACHINE)/coco_vhd.o \ | |
| 1914 | $(MESS_MACHINE)/cococart.o \ | |
| 1915 | $(MESS_MACHINE)/coco_232.o \ | |
| 1885 | $(MESS_VIDEO)/gime.o \ | |
| 1886 | $(MESS_MACHINE)/dragon.o \ | |
| 1887 | $(MESS_DRIVERS)/dragon.o \ | |
| 1888 | $(MESS_MACHINE)/dgnalpha.o \ | |
| 1889 | $(MESS_MACHINE)/coco_vhd.o \ | |
| 1890 | $(MESS_MACHINE)/cococart.o \ | |
| 1891 | $(MESS_MACHINE)/coco_232.o \ | |
| 1916 | 1892 | $(MESS_MACHINE)/coco_orch90.o\ |
| 1917 | $(MESS_MACHINE)/coco_pak.o \ | |
| 1918 | $(MESS_MACHINE)/coco_fdc.o \ | |
| 1919 | $(MESS_MACHINE)/coco_multi.o \ | |
| 1893 | $(MESS_MACHINE)/coco_pak.o \ | |
| 1894 | $(MESS_MACHINE)/coco_fdc.o \ | |
| 1895 | $(MESS_MACHINE)/coco_multi.o\ | |
| 1920 | 1896 | $(MESS_DRIVERS)/mc10.o \ |
| 1921 | 1897 | $(MESS_MACHINE)/trs80.o \ |
| 1922 | 1898 | $(MESS_VIDEO)/trs80.o \ |
| r21684 | r21685 | |
| 1990 | 1966 | $(MESS_DRIVERS)/wangpc.o \ |
| 1991 | 1967 | $(MESS_MACHINE)/wangpcbus.o \ |
| 1992 | 1968 | $(MESS_MACHINE)/wangpckb.o \ |
| 1993 | $(MESS_MACHINE)/wangpc_emb.o \ | |
| 1994 | $(MESS_MACHINE)/wangpc_lic.o \ | |
| 1995 | $(MESS_MACHINE)/wangpc_lvc.o \ | |
| 1996 | $(MESS_MACHINE)/wangpc_mcc.o \ | |
| 1997 | $(MESS_MACHINE)/wangpc_mvc.o \ | |
| 1998 | $(MESS_MACHINE)/wangpc_rtc.o \ | |
| 1999 | $(MESS_MACHINE)/wangpc_tig.o \ | |
| 2000 | $(MESS_MACHINE)/wangpc_wdc.o \ | |
| 1969 | $(MESS_MACHINE)/wangpc_emb.o\ | |
| 1970 | $(MESS_MACHINE)/wangpc_lic.o\ | |
| 1971 | $(MESS_MACHINE)/wangpc_lvc.o\ | |
| 1972 | $(MESS_MACHINE)/wangpc_mcc.o\ | |
| 1973 | $(MESS_MACHINE)/wangpc_mvc.o\ | |
| 1974 | $(MESS_MACHINE)/wangpc_rtc.o\ | |
| 1975 | $(MESS_MACHINE)/wangpc_tig.o\ | |
| 1976 | $(MESS_MACHINE)/wangpc_wdc.o\ | |
| 2001 | 1977 | |
| 2002 | 1978 | $(MESSOBJ)/wavemate.a: \ |
| 2003 | 1979 | $(MESS_DRIVERS)/bullet.o \ |
| r21684 | r21685 | |
| 2015 | 1991 | $(MESS_MACHINE)/iq151cart.o \ |
| 2016 | 1992 | $(MESS_MACHINE)/iq151_rom.o \ |
| 2017 | 1993 | $(MESS_MACHINE)/iq151_disc2.o \ |
| 2018 | $(MESS_MACHINE)/iq151_minigraf.o | |
| 1994 | $(MESS_MACHINE)/iq151_minigraf.o\ | |
| 2019 | 1995 | $(MESS_MACHINE)/iq151_ms151a.o \ |
| 2020 | 1996 | $(MESS_MACHINE)/iq151_staper.o \ |
| 2021 | 1997 | $(MESS_VIDEO)/iq151_grafik.o \ |
| r21684 | r21685 | |
|---|---|---|
| 1 | /********************************************************************** | |
| 2 | ||
| 3 | Motorola 68328 ("DragonBall") System-on-a-Chip implementation | |
| 4 | ||
| 5 | By MooglyGuy | |
| 6 | contact mooglyguy@gmail.com with licensing and usage questions. | |
| 7 | ||
| 8 | **********************************************************************/ | |
| 9 | ||
| 10 | #include "emu.h" | |
| 11 | #include "cpu/m68000/m68000.h" | |
| 12 | #include "includes/mc68328.h" | |
| 13 | #include "mc68328.h" | |
| 14 | ||
| 15 | #define VERBOSE_LEVEL (0) | |
| 16 | ||
| 17 | INLINE void verboselog(running_machine &machine, int n_level, const char *s_fmt, ...) | |
| 18 | { | |
| 19 | if( VERBOSE_LEVEL >= n_level ) | |
| 20 | { | |
| 21 | va_list v; | |
| 22 | char buf[ 32768 ]; | |
| 23 | va_start( v, s_fmt ); | |
| 24 | vsprintf( buf, s_fmt, v ); | |
| 25 | va_end( v ); | |
| 26 | logerror( "%s: %s", machine.describe_context(), buf ); | |
| 27 | } | |
| 28 | } | |
| 29 | ||
| 30 | static void mc68328_set_interrupt_line(device_t *device, UINT32 line, UINT32 active) | |
| 31 | { | |
| 32 | mc68328_t* mc68328 = mc68328_get_safe_token( device ); | |
| 33 | device_t *cpu = device->machine().device(mc68328->iface->m68k_cpu_tag); | |
| 34 | ||
| 35 | if(active) | |
| 36 | { | |
| 37 | mc68328->regs.ipr |= line; | |
| 38 | ||
| 39 | if(!(mc68328->regs.imr & line) && !(mc68328->regs.isr & line)) | |
| 40 | { | |
| 41 | mc68328->regs.isr |= line; | |
| 42 | ||
| 43 | if(mc68328->regs.isr & INT_M68K_LINE7) | |
| 44 | { | |
| 45 | cpu->execute().set_input_line_and_vector(M68K_IRQ_7, ASSERT_LINE, mc68328->regs.ivr | 0x07); | |
| 46 | } | |
| 47 | else if(mc68328->regs.isr & INT_M68K_LINE6) | |
| 48 | { | |
| 49 | cpu->execute().set_input_line_and_vector(M68K_IRQ_6, ASSERT_LINE, mc68328->regs.ivr | 0x06); | |
| 50 | } | |
| 51 | else if(mc68328->regs.isr & INT_M68K_LINE5) | |
| 52 | { | |
| 53 | cpu->execute().set_input_line_and_vector(M68K_IRQ_5, ASSERT_LINE, mc68328->regs.ivr | 0x05); | |
| 54 | } | |
| 55 | else if(mc68328->regs.isr & INT_M68K_LINE4) | |
| 56 | { | |
| 57 | cpu->execute().set_input_line_and_vector(M68K_IRQ_4, ASSERT_LINE, mc68328->regs.ivr | 0x04); | |
| 58 | } | |
| 59 | else if(mc68328->regs.isr & INT_M68K_LINE3) | |
| 60 | { | |
| 61 | cpu->execute().set_input_line_and_vector(M68K_IRQ_3, ASSERT_LINE, mc68328->regs.ivr | 0x03); | |
| 62 | } | |
| 63 | else if(mc68328->regs.isr & INT_M68K_LINE2) | |
| 64 | { | |
| 65 | cpu->execute().set_input_line_and_vector(M68K_IRQ_2, ASSERT_LINE, mc68328->regs.ivr | 0x02); | |
| 66 | } | |
| 67 | else if(mc68328->regs.isr & INT_M68K_LINE1) | |
| 68 | { | |
| 69 | cpu->execute().set_input_line_and_vector(M68K_IRQ_1, ASSERT_LINE, mc68328->regs.ivr | 0x01); | |
| 70 | } | |
| 71 | } | |
| 72 | } | |
| 73 | else | |
| 74 | { | |
| 75 | mc68328->regs.isr &= ~line; | |
| 76 | ||
| 77 | if((line & INT_M68K_LINE7) && !(mc68328->regs.isr & INT_M68K_LINE7)) | |
| 78 | { | |
| 79 | cpu->execute().set_input_line(M68K_IRQ_7, CLEAR_LINE); | |
| 80 | } | |
| 81 | if((line & INT_M68K_LINE6) && !(mc68328->regs.isr & INT_M68K_LINE6)) | |
| 82 | { | |
| 83 | cpu->execute().set_input_line(M68K_IRQ_6, CLEAR_LINE); | |
| 84 | } | |
| 85 | if((line & INT_M68K_LINE5) && !(mc68328->regs.isr & INT_M68K_LINE5)) | |
| 86 | { | |
| 87 | cpu->execute().set_input_line(M68K_IRQ_5, CLEAR_LINE); | |
| 88 | } | |
| 89 | if((line & INT_M68K_LINE4) && !(mc68328->regs.isr & INT_M68K_LINE4)) | |
| 90 | { | |
| 91 | cpu->execute().set_input_line(M68K_IRQ_4, CLEAR_LINE); | |
| 92 | } | |
| 93 | if((line & INT_M68K_LINE3) && !(mc68328->regs.isr & INT_M68K_LINE3)) | |
| 94 | { | |
| 95 | cpu->execute().set_input_line(M68K_IRQ_3, CLEAR_LINE); | |
| 96 | } | |
| 97 | if((line & INT_M68K_LINE2) && !(mc68328->regs.isr & INT_M68K_LINE2)) | |
| 98 | { | |
| 99 | cpu->execute().set_input_line(M68K_IRQ_2, CLEAR_LINE); | |
| 100 | } | |
| 101 | if((line & INT_M68K_LINE1) && !(mc68328->regs.isr & INT_M68K_LINE1)) | |
| 102 | { | |
| 103 | cpu->execute().set_input_line(M68K_IRQ_1, CLEAR_LINE); | |
| 104 | } | |
| 105 | } | |
| 106 | } | |
| 107 | ||
| 108 | static void mc68328_poll_port_d_interrupts(device_t *device) | |
| 109 | { | |
| 110 | mc68328_t* mc68328 = mc68328_get_safe_token( device ); | |
| 111 | UINT8 line_transitions = mc68328->regs.pddataedge & mc68328->regs.pdirqedge; | |
| 112 | UINT8 line_holds = mc68328->regs.pddata &~ mc68328->regs.pdirqedge; | |
| 113 | UINT8 line_interrupts = (line_transitions | line_holds) & mc68328->regs.pdirqen; | |
| 114 | ||
| 115 | if(line_interrupts) | |
| 116 | { | |
| 117 | mc68328_set_interrupt_line(device, line_interrupts << 8, 1); | |
| 118 | } | |
| 119 | else | |
| 120 | { | |
| 121 | mc68328_set_interrupt_line(device, INT_KBDINTS, 0); | |
| 122 | } | |
| 123 | } | |
| 124 | ||
| 125 | void mc68328_set_penirq_line(device_t *device, int state) | |
| 126 | { | |
| 127 | mc68328_t* mc68328 = mc68328_get_safe_token( device ); | |
| 128 | ||
| 129 | if(state) | |
| 130 | { | |
| 131 | mc68328_set_interrupt_line(device, INT_PEN, 1); | |
| 132 | } | |
| 133 | else | |
| 134 | { | |
| 135 | mc68328->regs.ipr &= ~INT_PEN; | |
| 136 | mc68328_set_interrupt_line(device, INT_PEN, 0); | |
| 137 | } | |
| 138 | } | |
| 139 | ||
| 140 | void mc68328_set_port_d_lines(device_t *device, UINT8 state, int bit) | |
| 141 | { | |
| 142 | mc68328_t* mc68328 = mc68328_get_safe_token( device ); | |
| 143 | UINT8 old_button_state = mc68328->regs.pddata; | |
| 144 | ||
| 145 | if(state & (1 << bit)) | |
| 146 | { | |
| 147 | mc68328->regs.pddata |= (1 << bit); | |
| 148 | } | |
| 149 | else | |
| 150 | { | |
| 151 | mc68328->regs.pddata &= ~(1 << bit); | |
| 152 | } | |
| 153 | ||
| 154 | mc68328->regs.pddataedge |= ~old_button_state & mc68328->regs.pddata; | |
| 155 | ||
| 156 | mc68328_poll_port_d_interrupts(device); | |
| 157 | } | |
| 158 | ||
| 159 | static UINT32 mc68328_get_timer_frequency(device_t *device, UINT32 index) | |
| 160 | { | |
| 161 | mc68328_t* mc68328 = mc68328_get_safe_token( device ); | |
| 162 | UINT32 frequency = 0; | |
| 163 | ||
| 164 | switch(mc68328->regs.tctl[index] & TCTL_CLKSOURCE) | |
| 165 | { | |
| 166 | case TCTL_CLKSOURCE_SYSCLK: | |
| 167 | frequency = 32768 * 506; | |
| 168 | break; | |
| 169 | ||
| 170 | case TCTL_CLKSOURCE_SYSCLK16: | |
| 171 | frequency = (32768 * 506) / 16; | |
| 172 | break; | |
| 173 | ||
| 174 | case TCTL_CLKSOURCE_32KHZ4: | |
| 175 | case TCTL_CLKSOURCE_32KHZ5: | |
| 176 | case TCTL_CLKSOURCE_32KHZ6: | |
| 177 | case TCTL_CLKSOURCE_32KHZ7: | |
| 178 | frequency = 32768; | |
| 179 | break; | |
| 180 | } | |
| 181 | frequency /= (mc68328->regs.tprer[index] + 1); | |
| 182 | ||
| 183 | return frequency; | |
| 184 | } | |
| 185 | ||
| 186 | static void mc68328_maybe_start_timer(device_t *device, UINT32 index, UINT32 new_enable) | |
| 187 | { | |
| 188 | mc68328_t* mc68328 = mc68328_get_safe_token( device ); | |
| 189 | ||
| 190 | if((mc68328->regs.tctl[index] & TCTL_TEN) == TCTL_TEN_ENABLE && (mc68328->regs.tctl[index] & TCTL_CLKSOURCE) > TCTL_CLKSOURCE_STOP) | |
| 191 | { | |
| 192 | if((mc68328->regs.tctl[index] & TCTL_CLKSOURCE) == TCTL_CLKSOURCE_TIN) | |
| 193 | { | |
| 194 | mc68328->gptimer[index]->adjust(attotime::never); | |
| 195 | } | |
| 196 | else if(mc68328->regs.tcmp[index] == 0) | |
| 197 | { | |
| 198 | mc68328->gptimer[index]->adjust(attotime::never); | |
| 199 | } | |
| 200 | else | |
| 201 | { | |
| 202 | UINT32 frequency = mc68328_get_timer_frequency(device, index); | |
| 203 | attotime period = (attotime::from_hz(frequency) * mc68328->regs.tcmp[index]); | |
| 204 | ||
| 205 | if(new_enable) | |
| 206 | { | |
| 207 | mc68328->regs.tcn[index] = 0x0000; | |
| 208 | } | |
| 209 | ||
| 210 | mc68328->gptimer[index]->adjust(period); | |
| 211 | } | |
| 212 | } | |
| 213 | else | |
| 214 | { | |
| 215 | mc68328->gptimer[index]->adjust(attotime::never); | |
| 216 | } | |
| 217 | } | |
| 218 | ||
| 219 | static void mc68328_timer_compare_event(device_t *device, UINT32 index) | |
| 220 | { | |
| 221 | mc68328_t* mc68328 = mc68328_get_safe_token( device ); | |
| 222 | ||
| 223 | mc68328->regs.tcn[index] = mc68328->regs.tcmp[index]; | |
| 224 | mc68328->regs.tstat[index] |= TSTAT_COMP; | |
| 225 | ||
| 226 | if((mc68328->regs.tctl[index] & TCTL_FRR) == TCTL_FRR_RESTART) | |
| 227 | { | |
| 228 | UINT32 frequency = mc68328_get_timer_frequency(device, index); | |
| 229 | ||
| 230 | if(frequency > 0) | |
| 231 | { | |
| 232 | attotime period = attotime::from_hz(frequency) * mc68328->regs.tcmp[index]; | |
| 233 | ||
| 234 | mc68328->regs.tcn[index] = 0x0000; | |
| 235 | ||
| 236 | mc68328->gptimer[index]->adjust(period); | |
| 237 | } | |
| 238 | else | |
| 239 | { | |
| 240 | mc68328->gptimer[index]->adjust(attotime::never); | |
| 241 | } | |
| 242 | } | |
| 243 | else | |
| 244 | { | |
| 245 | UINT32 frequency = mc68328_get_timer_frequency(device, index); | |
| 246 | ||
| 247 | if(frequency > 0) | |
| 248 | { | |
| 249 | attotime period = attotime::from_hz(frequency) * 0x10000; | |
| 250 | ||
| 251 | mc68328->gptimer[index]->adjust(period); | |
| 252 | } | |
| 253 | else | |
| 254 | { | |
| 255 | mc68328->gptimer[index]->adjust(attotime::never); | |
| 256 | } | |
| 257 | } | |
| 258 | if((mc68328->regs.tctl[index] & TCTL_IRQEN) == TCTL_IRQEN_ENABLE) | |
| 259 | { | |
| 260 | mc68328_set_interrupt_line(device, (index == 0) ? INT_TIMER1 : INT_TIMER2, 1); | |
| 261 | } | |
| 262 | } | |
| 263 | ||
| 264 | static TIMER_CALLBACK( mc68328_timer1_hit ) | |
| 265 | { | |
| 266 | device_t *device = machine.device(MC68328_TAG); | |
| 267 | ||
| 268 | mc68328_timer_compare_event(device, 0); | |
| 269 | } | |
| 270 | ||
| 271 | static TIMER_CALLBACK( mc68328_timer2_hit ) | |
| 272 | { | |
| 273 | device_t *device = machine.device(MC68328_TAG); | |
| 274 | ||
| 275 | mc68328_timer_compare_event(device, 1); | |
| 276 | } | |
| 277 | ||
| 278 | static TIMER_CALLBACK( mc68328_pwm_transition ) | |
| 279 | { | |
| 280 | device_t *device = machine.device(MC68328_TAG); | |
| 281 | mc68328_t* mc68328 = mc68328_get_safe_token( device ); | |
| 282 | ||
| 283 | if(mc68328->regs.pwmw >= mc68328->regs.pwmp || mc68328->regs.pwmw == 0 || mc68328->regs.pwmp == 0) | |
| 284 | { | |
| 285 | mc68328->pwm->adjust(attotime::never); | |
| 286 | return; | |
| 287 | } | |
| 288 | ||
| 289 | if(((mc68328->regs.pwmc & PWMC_POL) == 0 && (mc68328->regs.pwmc & PWMC_PIN) != 0) || | |
| 290 | ((mc68328->regs.pwmc & PWMC_POL) != 0 && (mc68328->regs.pwmc & PWMC_PIN) == 0)) | |
| 291 | { | |
| 292 | UINT32 frequency = 32768 * 506; | |
| 293 | UINT32 divisor = 4 << (mc68328->regs.pwmc & PWMC_CLKSEL); // ?? Datasheet says 2 <<, but then we're an octave higher than CoPilot. | |
| 294 | attotime period; | |
| 295 | ||
| 296 | frequency /= divisor; | |
| 297 | period = attotime::from_hz(frequency) * (mc68328->regs.pwmp - mc68328->regs.pwmw); | |
| 298 | ||
| 299 | mc68328->pwm->adjust(period); | |
| 300 | ||
| 301 | if(mc68328->regs.pwmc & PWMC_IRQEN) | |
| 302 | { | |
| 303 | mc68328_set_interrupt_line(device, INT_PWM, 1); | |
| 304 | } | |
| 305 | } | |
| 306 | else | |
| 307 | { | |
| 308 | UINT32 frequency = 32768 * 506; | |
| 309 | UINT32 divisor = 4 << (mc68328->regs.pwmc & PWMC_CLKSEL); // ?? Datasheet says 2 <<, but then we're an octave higher than CoPilot. | |
| 310 | attotime period; | |
| 311 | ||
| 312 | frequency /= divisor; | |
| 313 | period = attotime::from_hz(frequency) * mc68328->regs.pwmw; | |
| 314 | ||
| 315 | mc68328->pwm->adjust(period); | |
| 316 | } | |
| 317 | ||
| 318 | mc68328->regs.pwmc ^= PWMC_PIN; | |
| 319 | ||
| 320 | if( !mc68328->out_pwm.isnull() ) | |
| 321 | { | |
| 322 | mc68328->out_pwm( 0, (mc68328->regs.pwmc & PWMC_PIN) ? 1 : 0 ); | |
| 323 | } | |
| 324 | } | |
| 325 | ||
| 326 | static TIMER_CALLBACK( mc68328_rtc_tick ) | |
| 327 | { | |
| 328 | device_t *device = machine.device(MC68328_TAG); | |
| 329 | mc68328_t* mc68328 = mc68328_get_safe_token( device ); | |
| 330 | ||
| 331 | if(mc68328->regs.rtcctl & RTCCTL_ENABLE) | |
| 332 | { | |
| 333 | UINT32 set_int = 0; | |
| 334 | ||
| 335 | mc68328->regs.hmsr++; | |
| 336 | ||
| 337 | if(mc68328->regs.rtcienr & RTCINT_SECOND) | |
| 338 | { | |
| 339 | set_int = 1; | |
| 340 | mc68328->regs.rtcisr |= RTCINT_SECOND; | |
| 341 | } | |
| 342 | ||
| 343 | if((mc68328->regs.hmsr & 0x0000003f) == 0x0000003c) | |
| 344 | { | |
| 345 | mc68328->regs.hmsr &= 0xffffffc0; | |
| 346 | mc68328->regs.hmsr += 0x00010000; | |
| 347 | ||
| 348 | if(mc68328->regs.rtcienr & RTCINT_MINUTE) | |
| 349 | { | |
| 350 | set_int = 1; | |
| 351 | mc68328->regs.rtcisr |= RTCINT_MINUTE; | |
| 352 | } | |
| 353 | ||
| 354 | if((mc68328->regs.hmsr & 0x003f0000) == 0x003c0000) | |
| 355 | { | |
| 356 | mc68328->regs.hmsr &= 0xffc0ffff; | |
| 357 | mc68328->regs.hmsr += 0x0100000; | |
| 358 | ||
| 359 | if((mc68328->regs.hmsr & 0x1f000000) == 0x18000000) | |
| 360 | { | |
| 361 | mc68328->regs.hmsr &= 0xe0ffffff; | |
| 362 | ||
| 363 | if(mc68328->regs.rtcienr & RTCINT_DAY) | |
| 364 | { | |
| 365 | set_int = 1; | |
| 366 | mc68328->regs.rtcisr |= RTCINT_DAY; | |
| 367 | } | |
| 368 | } | |
| 369 | } | |
| 370 | ||
| 371 | if(mc68328->regs.stpwtch != 0x003f) | |
| 372 | { | |
| 373 | mc68328->regs.stpwtch--; | |
| 374 | mc68328->regs.stpwtch &= 0x003f; | |
| 375 | ||
| 376 | if(mc68328->regs.stpwtch == 0x003f) | |
| 377 | { | |
| 378 | if(mc68328->regs.rtcienr & RTCINT_STOPWATCH) | |
| 379 | { | |
| 380 | set_int = 1; | |
| 381 | mc68328->regs.rtcisr |= RTCINT_STOPWATCH; | |
| 382 | } | |
| 383 | } | |
| 384 | } | |
| 385 | } | |
| 386 | ||
| 387 | if(mc68328->regs.hmsr == mc68328->regs.alarm) | |
| 388 | { | |
| 389 | if(mc68328->regs.rtcienr & RTCINT_ALARM) | |
| 390 | { | |
| 391 | set_int = 1; | |
| 392 | mc68328->regs.rtcisr |= RTCINT_STOPWATCH; | |
| 393 | } | |
| 394 | } | |
| 395 | ||
| 396 | if(set_int) | |
| 397 | { | |
| 398 | mc68328_set_interrupt_line(device, INT_RTC, 1); | |
| 399 | } | |
| 400 | else | |
| 401 | { | |
| 402 | mc68328_set_interrupt_line(device, INT_RTC, 0); | |
| 403 | } | |
| 404 | } | |
| 405 | } | |
| 406 | ||
| 407 | WRITE16_DEVICE_HANDLER( mc68328_w ) | |
| 408 | { | |
| 409 | mc68328_t* mc68328 = mc68328_get_safe_token( device ); | |
| 410 | UINT32 address = offset << 1; | |
| 411 | UINT16 temp16[4] = { 0 }; | |
| 412 | UINT32 imr_old = mc68328->regs.imr, imr_diff; | |
| 413 | ||
| 414 | switch(address) | |
| 415 | { | |
| 416 | case 0x000: | |
| 417 | if( mem_mask & 0x00ff ) | |
| 418 | { | |
| 419 | verboselog(space.machine(), 2, "mc68328_w: Unknown address (0xfff001) = %02x\n", data & 0x00ff); | |
| 420 | } | |
| 421 | else | |
| 422 | { | |
| 423 | verboselog(space.machine(), 2, "mc68328_w: SCR = %02x\n", (data >> 8) & 0x00ff); | |
| 424 | } | |
| 425 | break; | |
| 426 | ||
| 427 | case 0x100: | |
| 428 | verboselog(space.machine(), 2, "mc68328_w: GRPBASEA = %04x\n", data); | |
| 429 | mc68328->regs.grpbasea = data; | |
| 430 | break; | |
| 431 | ||
| 432 | case 0x102: | |
| 433 | verboselog(space.machine(), 2, "mc68328_w: GRPBASEB = %04x\n", data); | |
| 434 | mc68328->regs.grpbaseb = data; | |
| 435 | break; | |
| 436 | ||
| 437 | case 0x104: | |
| 438 | verboselog(space.machine(), 2, "mc68328_w: GRPBASEC = %04x\n", data); | |
| 439 | mc68328->regs.grpbasec = data; | |
| 440 | break; | |
| 441 | ||
| 442 | case 0x106: | |
| 443 | verboselog(space.machine(), 2, "mc68328_w: GRPBASED = %04x\n", data); | |
| 444 | mc68328->regs.grpbased = data; | |
| 445 | break; | |
| 446 | ||
| 447 | case 0x108: | |
| 448 | verboselog(space.machine(), 2, "mc68328_w: GRPMASKA = %04x\n", data); | |
| 449 | mc68328->regs.grpmaska = data; | |
| 450 | break; | |
| 451 | ||
| 452 | case 0x10a: | |
| 453 | verboselog(space.machine(), 2, "mc68328_w: GRPMASKB = %04x\n", data); | |
| 454 | mc68328->regs.grpmaskb = data; | |
| 455 | break; | |
| 456 | ||
| 457 | case 0x10c: | |
| 458 | verboselog(space.machine(), 2, "mc68328_w: GRPMASKC = %04x\n", data); | |
| 459 | mc68328->regs.grpmaskc = data; | |
| 460 | break; | |
| 461 | ||
| 462 | case 0x10e: | |
| 463 | verboselog(space.machine(), 2, "mc68328_w: GRPMASKD = %04x\n", data); | |
| 464 | mc68328->regs.grpmaskd = data; | |
| 465 | break; | |
| 466 | ||
| 467 | case 0x110: | |
| 468 | verboselog(space.machine(), 5, "mc68328_w: CSA0(0) = %04x\n", data); | |
| 469 | mc68328->regs.csa0 &= 0xffff0000 | (~mem_mask); | |
| 470 | mc68328->regs.csa0 |= data & mem_mask; | |
| 471 | break; | |
| 472 | ||
| 473 | case 0x112: | |
| 474 | verboselog(space.machine(), 5, "mc68328_w: CSA0(16) = %04x\n", data); | |
| 475 | mc68328->regs.csa0 &= ~(mem_mask << 16); | |
| 476 | mc68328->regs.csa0 |= (data & mem_mask) << 16; | |
| 477 | break; | |
| 478 | ||
| 479 | case 0x114: | |
| 480 | verboselog(space.machine(), 5, "mc68328_w: CSA1(0) = %04x\n", data); | |
| 481 | mc68328->regs.csa1 &= 0xffff0000 | (~mem_mask); | |
| 482 | mc68328->regs.csa1 |= data & mem_mask; | |
| 483 | break; | |
| 484 | ||
| 485 | case 0x116: | |
| 486 | verboselog(space.machine(), 5, "mc68328_w: CSA1(16) = %04x\n", data); | |
| 487 | mc68328->regs.csa1 &= ~(mem_mask << 16); | |
| 488 | mc68328->regs.csa1 |= (data & mem_mask) << 16; | |
| 489 | break; | |
| 490 | ||
| 491 | case 0x118: | |
| 492 | verboselog(space.machine(), 5, "mc68328_w: CSA2(0) = %04x\n", data); | |
| 493 | mc68328->regs.csa2 &= 0xffff0000 | (~mem_mask); | |
| 494 | mc68328->regs.csa2 |= data & mem_mask; | |
| 495 | break; | |
| 496 | ||
| 497 | case 0x11a: | |
| 498 | verboselog(space.machine(), 5, "mc68328_w: CSA2(16) = %04x\n", data); | |
| 499 | mc68328->regs.csa2 &= ~(mem_mask << 16); | |
| 500 | mc68328->regs.csa2 |= (data & mem_mask) << 16; | |
| 501 | break; | |
| 502 | ||
| 503 | case 0x11c: | |
| 504 | verboselog(space.machine(), 5, "mc68328_w: CSA3(0) = %04x\n", data); | |
| 505 | mc68328->regs.csa3 &= 0xffff0000 | (~mem_mask); | |
| 506 | mc68328->regs.csa3 |= data & mem_mask; | |
| 507 | break; | |
| 508 | ||
| 509 | case 0x11e: | |
| 510 | verboselog(space.machine(), 5, "mc68328_w: CSA3(16) = %04x\n", data); | |
| 511 | mc68328->regs.csa3 &= ~(mem_mask << 16); | |
| 512 | mc68328->regs.csa3 |= (data & mem_mask) << 16; | |
| 513 | break; | |
| 514 | ||
| 515 | case 0x120: | |
| 516 | verboselog(space.machine(), 5, "mc68328_w: CSB0(0) = %04x\n", data); | |
| 517 | mc68328->regs.csb0 &= 0xffff0000 | (~mem_mask); | |
| 518 | mc68328->regs.csb0 |= data & mem_mask; | |
| 519 | break; | |
| 520 | ||
| 521 | case 0x122: | |
| 522 | verboselog(space.machine(), 5, "mc68328_w: CSB0(16) = %04x\n", data); | |
| 523 | mc68328->regs.csb0 &= ~(mem_mask << 16); | |
| 524 | mc68328->regs.csb0 |= (data & mem_mask) << 16; | |
| 525 | break; | |
| 526 | ||
| 527 | case 0x124: | |
| 528 | verboselog(space.machine(), 5, "mc68328_w: CSB1(0) = %04x\n", data); | |
| 529 | mc68328->regs.csb1 &= 0xffff0000 | (~mem_mask); | |
| 530 | mc68328->regs.csb1 |= data & mem_mask; | |
| 531 | break; | |
| 532 | ||
| 533 | case 0x126: | |
| 534 | verboselog(space.machine(), 5, "mc68328_w: CSB1(16) = %04x\n", data); | |
| 535 | mc68328->regs.csb1 &= ~(mem_mask << 16); | |
| 536 | mc68328->regs.csb1 |= (data & mem_mask) << 16; | |
| 537 | break; | |
| 538 | ||
| 539 | case 0x128: | |
| 540 | verboselog(space.machine(), 5, "mc68328_w: CSB2(0) = %04x\n", data); | |
| 541 | mc68328->regs.csb2 &= 0xffff0000 | (~mem_mask); | |
| 542 | mc68328->regs.csb2 |= data & mem_mask; | |
| 543 | break; | |
| 544 | ||
| 545 | case 0x12a: | |
| 546 | verboselog(space.machine(), 5, "mc68328_w: CSB2(16) = %04x\n", data); | |
| 547 | mc68328->regs.csb2 &= ~(mem_mask << 16); | |
| 548 | mc68328->regs.csb2 |= (data & mem_mask) << 16; | |
| 549 | break; | |
| 550 | ||
| 551 | case 0x12c: | |
| 552 | verboselog(space.machine(), 5, "mc68328_w: CSB3(0) = %04x\n", data); | |
| 553 | mc68328->regs.csb3 &= 0xffff0000 | (~mem_mask); | |
| 554 | mc68328->regs.csb3 |= data & mem_mask; | |
| 555 | break; | |
| 556 | ||
| 557 | case 0x12e: | |
| 558 | verboselog(space.machine(), 5, "mc68328_w: CSB3(16) = %04x\n", data); | |
| 559 | mc68328->regs.csb3 &= ~(mem_mask << 16); | |
| 560 | mc68328->regs.csb3 |= (data & mem_mask) << 16; | |
| 561 | break; | |
| 562 | ||
| 563 | case 0x130: | |
| 564 | verboselog(space.machine(), 5, "mc68328_w: CSC0(0) = %04x\n", data); | |
| 565 | mc68328->regs.csc0 &= 0xffff0000 | (~mem_mask); | |
| 566 | mc68328->regs.csc0 |= data & mem_mask; | |
| 567 | break; | |
| 568 | ||
| 569 | case 0x132: | |
| 570 | verboselog(space.machine(), 5, "mc68328_w: CSC0(16) = %04x\n", data); | |
| 571 | mc68328->regs.csc0 &= ~(mem_mask << 16); | |
| 572 | mc68328->regs.csc0 |= (data & mem_mask) << 16; | |
| 573 | break; | |
| 574 | ||
| 575 | case 0x134: | |
| 576 | verboselog(space.machine(), 5, "mc68328_w: CSC1(0) = %04x\n", data); | |
| 577 | mc68328->regs.csc1 &= 0xffff0000 | (~mem_mask); | |
| 578 | mc68328->regs.csc1 |= data & mem_mask; | |
| 579 | break; | |
| 580 | ||
| 581 | case 0x136: | |
| 582 | verboselog(space.machine(), 5, "mc68328_w: CSC1(16) = %04x\n", data); | |
| 583 | mc68328->regs.csc1 &= ~(mem_mask << 16); | |
| 584 | mc68328->regs.csc1 |= (data & mem_mask) << 16; | |
| 585 | break; | |
| 586 | ||
| 587 | case 0x138: | |
| 588 | verboselog(space.machine(), 5, "mc68328_w: CSC2(0) = %04x\n", data); | |
| 589 | mc68328->regs.csc2 &= 0xffff0000 | (~mem_mask); | |
| 590 | mc68328->regs.csc2 |= data & mem_mask; | |
| 591 | break; | |
| 592 | ||
| 593 | case 0x13a: | |
| 594 | verboselog(space.machine(), 5, "mc68328_w: CSC2(16) = %04x\n", data); | |
| 595 | mc68328->regs.csc2 &= ~(mem_mask << 16); | |
| 596 | mc68328->regs.csc2 |= (data & mem_mask) << 16; | |
| 597 | break; | |
| 598 | ||
| 599 | case 0x13c: | |
| 600 | verboselog(space.machine(), 5, "mc68328_w: CSC3(0) = %04x\n", data); | |
| 601 | mc68328->regs.csc3 &= 0xffff0000 | (~mem_mask); | |
| 602 | mc68328->regs.csc3 |= data & mem_mask; | |
| 603 | break; | |
| 604 | ||
| 605 | case 0x13e: | |
| 606 | verboselog(space.machine(), 5, "mc68328_w: CSC3(16) = %04x\n", data); | |
| 607 | mc68328->regs.csc3 &= ~(mem_mask << 16); | |
| 608 | mc68328->regs.csc3 |= (data & mem_mask) << 16; | |
| 609 | break; | |
| 610 | ||
| 611 | case 0x140: | |
| 612 | verboselog(space.machine(), 5, "mc68328_w: CSD0(0) = %04x\n", data); | |
| 613 | mc68328->regs.csd0 &= 0xffff0000 | (~mem_mask); | |
| 614 | mc68328->regs.csd0 |= data & mem_mask; | |
| 615 | break; | |
| 616 | ||
| 617 | case 0x142: | |
| 618 | verboselog(space.machine(), 5, "mc68328_w: CSD0(16) = %04x\n", data); | |
| 619 | mc68328->regs.csd0 &= ~(mem_mask << 16); | |
| 620 | mc68328->regs.csd0 |= (data & mem_mask) << 16; | |
| 621 | break; | |
| 622 | ||
| 623 | case 0x144: | |
| 624 | verboselog(space.machine(), 5, "mc68328_w: CSD1(0) = %04x\n", data); | |
| 625 | mc68328->regs.csd1 &= 0xffff0000 | (~mem_mask); | |
| 626 | mc68328->regs.csd1 |= data & mem_mask; | |
| 627 | break; | |
| 628 | ||
| 629 | case 0x146: | |
| 630 | verboselog(space.machine(), 5, "mc68328_w: CSD1(16) = %04x\n", data); | |
| 631 | mc68328->regs.csd1 &= ~(mem_mask << 16); | |
| 632 | mc68328->regs.csd1 |= (data & mem_mask) << 16; | |
| 633 | break; | |
| 634 | ||
| 635 | case 0x148: | |
| 636 | verboselog(space.machine(), 5, "mc68328_w: CSD2(0) = %04x\n", data); | |
| 637 | mc68328->regs.csd2 &= 0xffff0000 | (~mem_mask); | |
| 638 | mc68328->regs.csd2 |= data & mem_mask; | |
| 639 | break; | |
| 640 | ||
| 641 | case 0x14a: | |
| 642 | verboselog(space.machine(), 5, "mc68328_w: CSD2(16) = %04x\n", data); | |
| 643 | mc68328->regs.csd2 &= ~(mem_mask << 16); | |
| 644 | mc68328->regs.csd2 |= (data & mem_mask) << 16; | |
| 645 | break; | |
| 646 | ||
| 647 | case 0x14c: | |
| 648 | verboselog(space.machine(), 5, "mc68328_w: CSD3(0) = %04x\n", data); | |
| 649 | mc68328->regs.csd3 &= 0xffff0000 | (~mem_mask); | |
| 650 | mc68328->regs.csd3 |= data & mem_mask; | |
| 651 | break; | |
| 652 | ||
| 653 | case 0x14e: | |
| 654 | verboselog(space.machine(), 5, "mc68328_w: CSD3(16) = %04x\n", data); | |
| 655 | mc68328->regs.csd3 &= ~(mem_mask << 16); | |
| 656 | mc68328->regs.csd3 |= (data & mem_mask) << 16; | |
| 657 | break; | |
| 658 | ||
| 659 | case 0x200: | |
| 660 | verboselog(space.machine(), 2, "mc68328_w: PLLCR = %04x\n", data); | |
| 661 | mc68328->regs.pllcr = data; | |
| 662 | break; | |
| 663 | ||
| 664 | case 0x202: | |
| 665 | verboselog(space.machine(), 2, "mc68328_w: PLLFSR = %04x\n", data); | |
| 666 | mc68328->regs.pllfsr = data; | |
| 667 | break; | |
| 668 | ||
| 669 | case 0x206: | |
| 670 | if( mem_mask & 0x00ff ) | |
| 671 | { | |
| 672 | verboselog(space.machine(), 2, "mc68328_w: PCTLR = %02x\n", data & 0x00ff); | |
| 673 | mc68328->regs.pctlr = data & 0x00ff; | |
| 674 | } | |
| 675 | else | |
| 676 | { | |
| 677 | verboselog(space.machine(), 2, "mc68328_w: Unknown address (0xfff206) = %02x\n", (data >> 8) & 0x00ff); | |
| 678 | } | |
| 679 | break; | |
| 680 | ||
| 681 | case 0x300: | |
| 682 | if( mem_mask & 0x00ff ) | |
| 683 | { | |
| 684 | verboselog(space.machine(), 2, "mc68328_w: Unknown address (0xfff301) = %02x\n", data & 0x00ff); | |
| 685 | } | |
| 686 | else | |
| 687 | { | |
| 688 | verboselog(space.machine(), 2, "mc68328_w: IVR = %02x\n", (data >> 8) & 0x00ff); | |
| 689 | mc68328->regs.ivr = (data >> 8) & 0x00ff; | |
| 690 | } | |
| 691 | break; | |
| 692 | ||
| 693 | case 0x302: | |
| 694 | verboselog(space.machine(), 2, "mc68328_w: ICR = %04x\n", data); | |
| 695 | mc68328->regs.icr = data; | |
| 696 | break; | |
| 697 | ||
| 698 | case 0x304: | |
| 699 | verboselog(space.machine(), 2, "mc68328_w: IMR(16) = %04x\n", data); | |
| 700 | mc68328->regs.imr &= ~(mem_mask << 16); | |
| 701 | mc68328->regs.imr |= (data & mem_mask) << 16; | |
| 702 | mc68328->regs.isr &= ~((data & mem_mask) << 16); | |
| 703 | ||
| 704 | imr_diff = imr_old ^ mc68328->regs.imr; | |
| 705 | mc68328_set_interrupt_line(device, imr_diff, 0); | |
| 706 | break; | |
| 707 | ||
| 708 | case 0x306: | |
| 709 | verboselog(space.machine(), 2, "mc68328_w: IMR(0) = %04x\n", data); | |
| 710 | mc68328->regs.imr &= 0xffff0000 | (~mem_mask); | |
| 711 | mc68328->regs.imr |= data & mem_mask; | |
| 712 | mc68328->regs.isr &= ~(data & mem_mask); | |
| 713 | ||
| 714 | imr_diff = imr_old ^ mc68328->regs.imr; | |
| 715 | mc68328_set_interrupt_line(device, imr_diff, 0); | |
| 716 | break; | |
| 717 | ||
| 718 | case 0x308: | |
| 719 | { | |
| 720 | verboselog(space.machine(), 2, "mc68328_w: IWR(16) = %04x\n", data); | |
| 721 | mc68328->regs.iwr &= ~(mem_mask << 16); | |
| 722 | mc68328->regs.iwr |= (data & mem_mask) << 16; | |
| 723 | } | |
| 724 | break; | |
| 725 | ||
| 726 | case 0x30a: | |
| 727 | verboselog(space.machine(), 2, "mc68328_w: IWR(0) = %04x\n", data); | |
| 728 | mc68328->regs.iwr &= 0xffff0000 | (~mem_mask); | |
| 729 | mc68328->regs.iwr |= data & mem_mask; | |
| 730 | break; | |
| 731 | ||
| 732 | case 0x30c: | |
| 733 | verboselog(space.machine(), 2, "mc68328_w: ISR(16) = %04x\n", data); | |
| 734 | // Clear edge-triggered IRQ1 | |
| 735 | if((mc68328->regs.icr & ICR_ET1) == ICR_ET1 && (data & INT_IRQ1_SHIFT) == INT_IRQ1_SHIFT) | |
| 736 | { | |
| 737 | mc68328->regs.isr &= ~INT_IRQ1; | |
| 738 | } | |
| 739 | ||
| 740 | // Clear edge-triggered IRQ2 | |
| 741 | if((mc68328->regs.icr & ICR_ET2) == ICR_ET2 && (data & INT_IRQ2_SHIFT) == INT_IRQ2_SHIFT) | |
| 742 | { | |
| 743 | mc68328->regs.isr &= ~INT_IRQ2; | |
| 744 | } | |
| 745 | ||
| 746 | // Clear edge-triggered IRQ3 | |
| 747 | if((mc68328->regs.icr & ICR_ET3) == ICR_ET3 && (data & INT_IRQ3_SHIFT) == INT_IRQ3_SHIFT) | |
| 748 | { | |
| 749 | mc68328->regs.isr &= ~INT_IRQ3; | |
| 750 | } | |
| 751 | ||
| 752 | // Clear edge-triggered IRQ6 | |
| 753 | if((mc68328->regs.icr & ICR_ET6) == ICR_ET6 && (data & INT_IRQ6_SHIFT) == INT_IRQ6_SHIFT) | |
| 754 | { | |
| 755 | mc68328->regs.isr &= ~INT_IRQ6; | |
| 756 | } | |
| 757 | ||
| 758 | // Clear edge-triggered IRQ7 | |
| 759 | if((data & INT_IRQ7_SHIFT) == INT_IRQ7_SHIFT) | |
| 760 | { | |
| 761 | mc68328->regs.isr &= ~INT_IRQ7; | |
| 762 | } | |
| 763 | break; | |
| 764 | ||
| 765 | case 0x30e: | |
| 766 | verboselog(space.machine(), 2, "mc68328_w: ISR(0) = %04x (Ignored)\n", data); | |
| 767 | break; | |
| 768 | ||
| 769 | case 0x310: | |
| 770 | verboselog(space.machine(), 2, "mc68328_w: IPR(16) = %04x (Ignored)\n"); | |
| 771 | break; | |
| 772 | ||
| 773 | case 0x312: | |
| 774 | verboselog(space.machine(), 2, "mc68328_w: IPR(0) = %04x (Ignored)\n"); | |
| 775 | break; | |
| 776 | ||
| 777 | case 0x400: | |
| 778 | if( mem_mask & 0x00ff ) | |
| 779 | { | |
| 780 | verboselog(space.machine(), 2, "mc68328_w: PADATA = %02x\n", data & 0x00ff); | |
| 781 | mc68328->regs.padata = data & 0x00ff; | |
| 782 | if(!mc68328->out_port_a.isnull()) | |
| 783 | { | |
| 784 | mc68328->out_port_a( 0, data & 0x00ff ); | |
| 785 | } | |
| 786 | } | |
| 787 | else | |
| 788 | { | |
| 789 | verboselog(space.machine(), 2, "mc68328_w: PADIR = %02x\n", (data >> 8) & 0x00ff); | |
| 790 | mc68328->regs.padir = (data >> 8) & 0x00ff; | |
| 791 | } | |
| 792 | break; | |
| 793 | ||
| 794 | case 0x402: | |
| 795 | if( mem_mask & 0x00ff ) | |
| 796 | { | |
| 797 | verboselog(space.machine(), 2, "mc68328_w: PASEL = %02x\n", data & 0x00ff); | |
| 798 | mc68328->regs.pasel = data & 0x00ff; | |
| 799 | } | |
| 800 | else | |
| 801 | { | |
| 802 | verboselog(space.machine(), 2, "mc68328_w: Unknown address (0xfff402) = %02x\n", (data >> 8) & 0x00ff); | |
| 803 | } | |
| 804 | break; | |
| 805 | ||
| 806 | case 0x408: | |
| 807 | if( mem_mask & 0x00ff ) | |
| 808 | { | |
| 809 | verboselog(space.machine(), 2, "mc68328_w: PBDATA = %02x\n", data & 0x00ff); | |
| 810 | mc68328->regs.pbdata = data & 0x00ff; | |
| 811 | if(!mc68328->out_port_b.isnull()) | |
| 812 | { | |
| 813 | mc68328->out_port_b( 0, data & 0x00ff ); | |
| 814 | } | |
| 815 | } | |
| 816 | else | |
| 817 | { | |
| 818 | verboselog(space.machine(), 2, "mc68328_w: PBDIR = %02x\n", (data >> 8) & 0x00ff); | |
| 819 | mc68328->regs.pbdir = (data >> 8) & 0x00ff; | |
| 820 | } | |
| 821 | break; | |
| 822 | ||
| 823 | case 0x40a: | |
| 824 | if( mem_mask & 0x00ff ) | |
| 825 | { | |
| 826 | verboselog(space.machine(), 2, "mc68328_w: PBSEL = %02x\n", data & 0x00ff); | |
| 827 | mc68328->regs.pbsel = data & 0x00ff; | |
| 828 | } | |
| 829 | else | |
| 830 | { | |
| 831 | verboselog(space.machine(), 2, "mc68328_w: Unknown address (0xfff40a) = %02x\n", (data >> 8) & 0x00ff); | |
| 832 | } | |
| 833 | break; | |
| 834 | ||
| 835 | case 0x410: | |
| 836 | if( mem_mask & 0x00ff ) | |
| 837 | { | |
| 838 | verboselog(space.machine(), 2, "mc68328_w: PCDATA = %02x\n", data & 0x00ff); | |
| 839 | mc68328->regs.pcdata = data & 0x00ff; | |
| 840 | if(!mc68328->out_port_c.isnull()) | |
| 841 | { | |
| 842 | mc68328->out_port_c( 0, data & 0x00ff ); | |
| 843 | } | |
| 844 | } | |
| 845 | else | |
| 846 | { | |
| 847 | verboselog(space.machine(), 2, "mc68328_w: PCDIR = %02x\n", (data >> 8) & 0x00ff); | |
| 848 | mc68328->regs.pcdir = (data >> 8) & 0x00ff; | |
| 849 | } | |
| 850 | break; | |
| 851 | ||
| 852 | case 0x412: | |
| 853 | if( mem_mask & 0x00ff ) | |
| 854 | { | |
| 855 | verboselog(space.machine(), 2, "mc68328_w: PCSEL = %02x\n", data & 0x00ff); | |
| 856 | mc68328->regs.pcsel = data & 0x00ff; | |
| 857 | } | |
| 858 | else | |
| 859 | { | |
| 860 | verboselog(space.machine(), 2, "mc68328_w: Unknown address (0xfff412) = %02x\n", (data >> 8) & 0x00ff); | |
| 861 | } | |
| 862 | break; | |
| 863 | ||
| 864 | case 0x418: | |
| 865 | if( mem_mask & 0x00ff ) | |
| 866 | { | |
| 867 | verboselog(space.machine(), 2, "mc68328_w: PDDATA = %02x\n", data & 0x00ff); | |
| 868 | ||
| 869 | mc68328->regs.pddataedge &= ~(data & 0x00ff); | |
| 870 | mc68328_poll_port_d_interrupts(device); | |
| 871 | } | |
| 872 | else | |
| 873 | { | |
| 874 | verboselog(space.machine(), 2, "mc68328_w: PDDIR = %02x\n", (data >> 8) & 0x00ff); | |
| 875 | mc68328->regs.pddir = (data >> 8) & 0x00ff; | |
| 876 | } | |
| 877 | break; | |
| 878 | ||
| 879 | case 0x41a: | |
| 880 | if( mem_mask & 0x00ff ) | |
| 881 | { | |
| 882 | verboselog(space.machine(), 2, "mc68328_w: Unknown address (0xfff41b) = %02x\n", data & 0x00ff); | |
| 883 | } | |
| 884 | else | |
| 885 | { | |
| 886 | verboselog(space.machine(), 2, "mc68328_w: PDPUEN = %02x\n", (data >> 8) & 0x00ff); | |
| 887 | mc68328->regs.pdpuen = (data >> 8) & 0x00ff; | |
| 888 | } | |
| 889 | break; | |
| 890 | ||
| 891 | case 0x41c: | |
| 892 | if( mem_mask & 0x00ff ) | |
| 893 | { | |
| 894 | verboselog(space.machine(), 2, "mc68328_w: PDIRQEN = %02x\n", data & 0x00ff); | |
| 895 | mc68328->regs.pdirqen = data & 0x00ff; | |
| 896 | ||
| 897 | mc68328_poll_port_d_interrupts(device); | |
| 898 | } | |
| 899 | else | |
| 900 | { | |
| 901 | verboselog(space.machine(), 2, "mc68328_w: PDPOL = %02x\n", (data >> 8) & 0x00ff); | |
| 902 | mc68328->regs.pdpol = (data >> 8) & 0x00ff; | |
| 903 | } | |
| 904 | break; | |
| 905 | ||
| 906 | case 0x41e: | |
| 907 | if( mem_mask & 0x00ff ) | |
| 908 | { | |
| 909 | verboselog(space.machine(), 2, "mc68328_w: PDIRQEDGE = %02x\n", data & 0x00ff); | |
| 910 | mc68328->regs.pdirqedge = data & 0x00ff; | |
| 911 | } | |
| 912 | else | |
| 913 | { | |
| 914 | verboselog(space.machine(), 2, "mc68328_w: Unknown address (0xfff41e) = %02x\n", (data >> 8) & 0x00ff); | |
| 915 | } | |
| 916 | break; | |
| 917 | ||
| 918 | case 0x420: | |
| 919 | if( mem_mask & 0x00ff ) | |
| 920 | { | |
| 921 | verboselog(space.machine(), 2, "mc68328_w: PEDATA = %02x\n", data & 0x00ff); | |
| 922 | mc68328->regs.pedata = data & 0x00ff; | |
| 923 | if(!mc68328->out_port_e.isnull()) | |
| 924 | { | |
| 925 | mc68328->out_port_e( 0, data & 0x00ff ); | |
| 926 | } | |
| 927 | } | |
| 928 | else | |
| 929 | { | |
| 930 | verboselog(space.machine(), 2, "mc68328_w: PEDIR = %02x\n", (data >> 8) & 0x00ff); | |
| 931 | mc68328->regs.pedir = (data >> 8) & 0x00ff; | |
| 932 | } | |
| 933 | break; | |
| 934 | ||
| 935 | case 0x422: | |
| 936 | if( mem_mask & 0x00ff ) | |
| 937 | { | |
| 938 | verboselog(space.machine(), 2, "mc68328_w: PESEL = %02x\n", data & 0x00ff); | |
| 939 | mc68328->regs.pesel = data & 0x00ff; | |
| 940 | } | |
| 941 | else | |
| 942 | { | |
| 943 | verboselog(space.machine(), 2, "mc68328_w: PEPUEN = %02x\n", (data >> 8) & 0x00ff); | |
| 944 | mc68328->regs.pepuen = (data >> 8) & 0x00ff; | |
| 945 | mc68328->regs.pedata |= mc68328->regs.pepuen; | |
| 946 | } | |
| 947 | break; | |
| 948 | ||
| 949 | case 0x428: | |
| 950 | if( mem_mask & 0x00ff ) | |
| 951 | { | |
| 952 | verboselog(space.machine(), 2, "mc68328_w: PFDATA = %02x\n", data & 0x00ff); | |
| 953 | mc68328->regs.pfdata = data & 0x00ff; | |
| 954 | if(!mc68328->out_port_f.isnull()) | |
| 955 | { | |
| 956 | mc68328->out_port_f( 0, data & 0x00ff ); | |
| 957 | } | |
| 958 | } | |
| 959 | else | |
| 960 | { | |
| 961 | verboselog(space.machine(), 2, "mc68328_w: PFDIR = %02x\n", (data >> 8) & 0x00ff); | |
| 962 | mc68328->regs.pfdir = (data >> 8) & 0x00ff; | |
| 963 | } | |
| 964 | break; | |
| 965 | ||
| 966 | case 0x42a: | |
| 967 | if( mem_mask & 0x00ff ) | |
| 968 | { | |
| 969 | verboselog(space.machine(), 2, "mc68328_w: PFSEL = %02x\n", data & 0x00ff); | |
| 970 | mc68328->regs.pfsel = data & 0x00ff; | |
| 971 | } | |
| 972 | else | |
| 973 | { | |
| 974 | verboselog(space.machine(), 2, "mc68328_w: PFPUEN = %02x\n", (data >> 8) & 0x00ff); | |
| 975 | mc68328->regs.pfpuen = (data >> 8) & 0x00ff; | |
| 976 | } | |
| 977 | break; | |
| 978 | ||
| 979 | case 0x430: | |
| 980 | if( mem_mask & 0x00ff ) | |
| 981 | { | |
| 982 | verboselog(space.machine(), 2, "mc68328_w: PGDATA = %02x\n", data & 0x00ff); | |
| 983 | mc68328->regs.pgdata = data & 0x00ff; | |
| 984 | if(!mc68328->out_port_g.isnull()) | |
| 985 | { | |
| 986 | mc68328->out_port_g( 0, data & 0x00ff ); | |
| 987 | } | |
| 988 | } | |
| 989 | else | |
| 990 | { | |
| 991 | verboselog(space.machine(), 2, "mc68328_w: PGDIR = %02x\n", (data >> 8) & 0x00ff); | |
| 992 | mc68328->regs.pgdir = (data >> 8) & 0x00ff; | |
| 993 | } | |
| 994 | break; | |
| 995 | ||
| 996 | case 0x432: | |
| 997 | if( mem_mask & 0x00ff ) | |
| 998 | { | |
| 999 | verboselog(space.machine(), 2, "mc68328_w: PGSEL = %02x\n", data & 0x00ff); | |
| 1000 | mc68328->regs.pgsel = data & 0x00ff; | |
| 1001 | } | |
| 1002 | else | |
| 1003 | { | |
| 1004 | verboselog(space.machine(), 2, "mc68328_w: PGPUEN = %02x\n", (data >> 8) & 0x00ff); | |
| 1005 | mc68328->regs.pgpuen = (data >> 8) & 0x00ff; | |
| 1006 | } | |
| 1007 | break; | |
| 1008 | ||
| 1009 | case 0x438: | |
| 1010 | if( mem_mask & 0x00ff ) | |
| 1011 | { | |
| 1012 | verboselog(space.machine(), 2, "mc68328_w: PJDATA = %02x\n", data & 0x00ff); | |
| 1013 | mc68328->regs.pjdata = data & 0x00ff; | |
| 1014 | if(!mc68328->out_port_j.isnull()) | |
| 1015 | { | |
| 1016 | mc68328->out_port_j( 0, data & 0x00ff ); | |
| 1017 | } | |
| 1018 | } | |
| 1019 | else | |
| 1020 | { | |
| 1021 | verboselog(space.machine(), 2, "mc68328_w: PJDIR = %02x\n", (data >> 8) & 0x00ff); | |
| 1022 | mc68328->regs.pjdir = (data >> 8) & 0x00ff; | |
| 1023 | } | |
| 1024 | break; | |
| 1025 | ||
| 1026 | case 0x43a: | |
| 1027 | if( mem_mask & 0x00ff ) | |
| 1028 | { | |
| 1029 | verboselog(space.machine(), 2, "mc68328_w: PJSEL = %02x\n", data & 0x00ff); | |
| 1030 | mc68328->regs.pjsel = data & 0x00ff; | |
| 1031 | } | |
| 1032 | else | |
| 1033 | { | |
| 1034 | verboselog(space.machine(), 2, "mc68328_w: Unknown address (0xfff43a) = %02x\n", (data >> 8) & 0x00ff); | |
| 1035 | } | |
| 1036 | break; | |
| 1037 | ||
| 1038 | case 0x440: | |
| 1039 | if( mem_mask & 0x00ff ) | |
| 1040 | { | |
| 1041 | verboselog(space.machine(), 2, "mc68328_w: PKDATA = %02x\n", data & 0x00ff); | |
| 1042 | mc68328->regs.pkdata = data & 0x00ff; | |
| 1043 | if(!mc68328->out_port_k.isnull()) | |
| 1044 | { | |
| 1045 | mc68328->out_port_k( 0, data & 0x00ff ); | |
| 1046 | } | |
| 1047 | } | |
| 1048 | else | |
| 1049 | { | |
| 1050 | verboselog(space.machine(), 2, "mc68328_w: PKDIR = %02x\n", (data >> 8) & 0x00ff); | |
| 1051 | mc68328->regs.pkdir = (data >> 8) & 0x00ff; | |
| 1052 | } | |
| 1053 | break; | |
| 1054 | ||
| 1055 | case 0x442: | |
| 1056 | if( mem_mask & 0x00ff ) | |
| 1057 | { | |
| 1058 | verboselog(space.machine(), 2, "mc68328_w: PKSEL = %02x\n", data & 0x00ff); | |
| 1059 | mc68328->regs.pksel = data & 0x00ff; | |
| 1060 | } | |
| 1061 | else | |
| 1062 | { | |
| 1063 | verboselog(space.machine(), 2, "mc68328_w: PKPUEN = %02x\n", (data >> 8) & 0x00ff); | |
| 1064 | mc68328->regs.pgpuen = (data >> 8) & 0x00ff; | |
| 1065 | } | |
| 1066 | break; | |
| 1067 | ||
| 1068 | case 0x448: | |
| 1069 | if( mem_mask & 0x00ff ) | |
| 1070 | { | |
| 1071 | verboselog(space.machine(), 2, "mc68328_w: PMDATA = %02x\n", data & 0x00ff); | |
| 1072 | mc68328->regs.pmdata = data & 0x00ff; | |
| 1073 | if(!mc68328->out_port_m.isnull()) | |
| 1074 | { | |
| 1075 | mc68328->out_port_m( 0, data & 0x00ff ); | |
| 1076 | } | |
| 1077 | } | |
| 1078 | else | |
| 1079 | { | |
| 1080 | verboselog(space.machine(), 2, "mc68328_w: PMDIR = %02x\n", (data >> 8) & 0x00ff); | |
| 1081 | mc68328->regs.pmdir = (data >> 8) & 0x00ff; | |
| 1082 | } | |
| 1083 | break; | |
| 1084 | ||
| 1085 | case 0x44a: | |
| 1086 | if( mem_mask & 0x00ff ) | |
| 1087 | { | |
| 1088 | verboselog(space.machine(), 2, "mc68328_w: PMSEL = %02x\n", data & 0x00ff); | |
| 1089 | mc68328->regs.pmsel = data & 0x00ff; | |
| 1090 | } | |
| 1091 | else | |
| 1092 | { | |
| 1093 | verboselog(space.machine(), 2, "mc68328_w: PMPUEN = %02x\n", (data >> 8) & 0x00ff); | |
| 1094 | mc68328->regs.pmpuen = (data >> 8) & 0x00ff; | |
| 1095 | } | |
| 1096 | break; | |
| 1097 | ||
| 1098 | case 0x500: | |
| 1099 | verboselog(space.machine(), 2, "mc68328_w: PWMC = %04x\n", data); | |
| 1100 | ||
| 1101 | mc68328->regs.pwmc = data; | |
| 1102 | ||
| 1103 | if(mc68328->regs.pwmc & PWMC_PWMIRQ) | |
| 1104 | { | |
| 1105 | mc68328_set_interrupt_line(device, INT_PWM, 1); | |
| 1106 | } | |
| 1107 | ||
| 1108 | mc68328->regs.pwmc &= ~PWMC_LOAD; | |
| 1109 | ||
| 1110 | if((mc68328->regs.pwmc & PWMC_PWMEN) != 0 && mc68328->regs.pwmw != 0 && mc68328->regs.pwmp != 0) | |
| 1111 | { | |
| 1112 | UINT32 frequency = 32768 * 506; | |
| 1113 | UINT32 divisor = 4 << (mc68328->regs.pwmc & PWMC_CLKSEL); // ?? Datasheet says 2 <<, but then we're an octave higher than CoPilot. | |
| 1114 | attotime period; | |
| 1115 | frequency /= divisor; | |
| 1116 | period = attotime::from_hz(frequency) * mc68328->regs.pwmw; | |
| 1117 | mc68328->pwm->adjust(period); | |
| 1118 | if(mc68328->regs.pwmc & PWMC_IRQEN) | |
| 1119 | { | |
| 1120 | mc68328_set_interrupt_line(device, INT_PWM, 1); | |
| 1121 | } | |
| 1122 | mc68328->regs.pwmc ^= PWMC_PIN; | |
| 1123 | } | |
| 1124 | else | |
| 1125 | { | |
| 1126 | mc68328->pwm->adjust(attotime::never); | |
| 1127 | } | |
| 1128 | break; | |
| 1129 | ||
| 1130 | case 0x502: | |
| 1131 | verboselog(space.machine(), 2, "mc68328_w: PWMP = %04x\n", data); | |
| 1132 | mc68328->regs.pwmp = data; | |
| 1133 | break; | |
| 1134 | ||
| 1135 | case 0x504: | |
| 1136 | verboselog(space.machine(), 2, "mc68328_w: PWMW = %04x\n", data); | |
| 1137 | mc68328->regs.pwmw = data; | |
| 1138 | break; | |
| 1139 | ||
| 1140 | case 0x506: | |
| 1141 | verboselog(space.machine(), 2, "mc68328_w: PWMCNT = %04x\n", data); | |
| 1142 | mc68328->regs.pwmcnt = 0; | |
| 1143 | break; | |
| 1144 | ||
| 1145 | case 0x600: | |
| 1146 | verboselog(space.machine(), 2, "mc68328_w: TCTL1 = %04x\n", data); | |
| 1147 | temp16[0] = mc68328->regs.tctl[0]; | |
| 1148 | mc68328->regs.tctl[0] = data; | |
| 1149 | if((temp16[0] & TCTL_TEN) == (mc68328->regs.tctl[0] & TCTL_TEN)) | |
| 1150 | { | |
| 1151 | mc68328_maybe_start_timer(device, 0, 0); | |
| 1152 | } | |
| 1153 | else if((temp16[0] & TCTL_TEN) != TCTL_TEN_ENABLE && (mc68328->regs.tctl[0] & TCTL_TEN) == TCTL_TEN_ENABLE) | |
| 1154 | { | |
| 1155 | mc68328_maybe_start_timer(device, 0, 1); | |
| 1156 | } | |
| 1157 | break; | |
| 1158 | ||
| 1159 | case 0x602: | |
| 1160 | verboselog(space.machine(), 2, "mc68328_w: TPRER1 = %04x\n", data); | |
| 1161 | mc68328->regs.tprer[0] = data; | |
| 1162 | mc68328_maybe_start_timer(device, 0, 0); | |
| 1163 | break; | |
| 1164 | ||
| 1165 | case 0x604: | |
| 1166 | verboselog(space.machine(), 2, "mc68328_w: TCMP1 = %04x\n", data); | |
| 1167 | mc68328->regs.tcmp[0] = data; | |
| 1168 | mc68328_maybe_start_timer(device, 0, 0); | |
| 1169 | break; | |
| 1170 | ||
| 1171 | case 0x606: | |
| 1172 | verboselog(space.machine(), 2, "mc68328_w: TCR1 = %04x (Ignored)\n", data); | |
| 1173 | break; | |
| 1174 | ||
| 1175 | case 0x608: | |
| 1176 | verboselog(space.machine(), 2, "mc68328_w: TCN1 = %04x (Ignored)\n", data); | |
| 1177 | break; | |
| 1178 | ||
| 1179 | case 0x60a: | |
| 1180 | verboselog(space.machine(), 5, "mc68328_w: TSTAT1 = %04x\n", data); | |
| 1181 | mc68328->regs.tstat[0] &= ~mc68328->regs.tclear[0]; | |
| 1182 | if(!(mc68328->regs.tstat[0] & TSTAT_COMP)) | |
| 1183 | { | |
| 1184 | mc68328_set_interrupt_line(device, INT_TIMER1, 0); | |
| 1185 | } | |
| 1186 | break; | |
| 1187 | ||
| 1188 | case 0x60c: | |
| 1189 | verboselog(space.machine(), 2, "mc68328_w: TCTL2 = %04x\n", data); | |
| 1190 | temp16[0] = mc68328->regs.tctl[1]; | |
| 1191 | mc68328->regs.tctl[1] = data; | |
| 1192 | if((temp16[0] & TCTL_TEN) == (mc68328->regs.tctl[1] & TCTL_TEN)) | |
| 1193 | { | |
| 1194 | mc68328_maybe_start_timer(device, 1, 0); | |
| 1195 | } | |
| 1196 | else if((temp16[0] & TCTL_TEN) != TCTL_TEN_ENABLE && (mc68328->regs.tctl[1] & TCTL_TEN) == TCTL_TEN_ENABLE) | |
| 1197 | { | |
| 1198 | mc68328_maybe_start_timer(device, 1, 1); | |
| 1199 | } | |
| 1200 | break; | |
| 1201 | ||
| 1202 | case 0x60e: | |
| 1203 | verboselog(space.machine(), 2, "mc68328_w: TPRER2 = %04x\n", data); | |
| 1204 | mc68328->regs.tprer[1] = data; | |
| 1205 | mc68328_maybe_start_timer(device, 1, 0); | |
| 1206 | break; | |
| 1207 | ||
| 1208 | case 0x610: | |
| 1209 | verboselog(space.machine(), 2, "mc68328_w: TCMP2 = %04x\n", data); | |
| 1210 | mc68328->regs.tcmp[1] = data; | |
| 1211 | mc68328_maybe_start_timer(device, 1, 0); | |
| 1212 | break; | |
| 1213 | ||
| 1214 | case 0x612: | |
| 1215 | verboselog(space.machine(), 2, "mc68328_w: TCR2 = %04x (Ignored)\n", data); | |
| 1216 | break; | |
| 1217 | ||
| 1218 | case 0x614: | |
| 1219 | verboselog(space.machine(), 2, "mc68328_w: TCN2 = %04x (Ignored)\n", data); | |
| 1220 | break; | |
| 1221 | ||
| 1222 | case 0x616: | |
| 1223 | verboselog(space.machine(), 2, "mc68328_w: TSTAT2 = %04x\n", data); | |
| 1224 | mc68328->regs.tstat[1] &= ~mc68328->regs.tclear[1]; | |
| 1225 | if(!(mc68328->regs.tstat[1] & TSTAT_COMP)) | |
| 1226 | { | |
| 1227 | mc68328_set_interrupt_line(device, INT_TIMER2, 0); | |
| 1228 | } | |
| 1229 | break; | |
| 1230 | ||
| 1231 | case 0x618: | |
| 1232 | verboselog(space.machine(), 2, "mc68328_w: WCTLR = %04x\n", data); | |
| 1233 | mc68328->regs.wctlr = data; | |
| 1234 | break; | |
| 1235 | ||
| 1236 | case 0x61a: | |
| 1237 | verboselog(space.machine(), 2, "mc68328_w: WCMPR = %04x\n", data); | |
| 1238 | mc68328->regs.wcmpr = data; | |
| 1239 | break; | |
| 1240 | ||
| 1241 | case 0x61c: | |
| 1242 | verboselog(space.machine(), 2, "mc68328_w: WCN = %04x (Ignored)\n", data); | |
| 1243 | break; | |
| 1244 | ||
| 1245 | case 0x700: | |
| 1246 | verboselog(space.machine(), 2, "mc68328_w: SPISR = %04x\n", data); | |
| 1247 | mc68328->regs.spisr = data; | |
| 1248 | break; | |
| 1249 | ||
| 1250 | case 0x800: | |
| 1251 | verboselog(space.machine(), 2, "mc68328_w: SPIMDATA = %04x\n", data); | |
| 1252 | if(!mc68328->out_spim.isnull()) | |
| 1253 | { | |
| 1254 | mc68328->out_spim( 0, data, 0xffff ); | |
| 1255 | } | |
| 1256 | else | |
| 1257 | { | |
| 1258 | mc68328->regs.spimdata = data; | |
| 1259 | } | |
| 1260 | break; | |
| 1261 | ||
| 1262 | case 0x802: | |
| 1263 | verboselog(space.machine(), 2, "mc68328_w: SPIMCONT = %04x\n", data); | |
| 1264 | verboselog(space.machine(), 3, " Count = %d\n", data & SPIM_CLOCK_COUNT); | |
| 1265 | verboselog(space.machine(), 3, " Polarity = %s\n", (data & SPIM_POL) ? "Inverted" : "Active-high"); | |
| 1266 | verboselog(space.machine(), 3, " Phase = %s\n", (data & SPIM_PHA) ? "Opposite" : "Normal"); | |
| 1267 | verboselog(space.machine(), 3, " IRQ Enable = %s\n", (data & SPIM_IRQEN) ? "Enable" : "Disable"); | |
| 1268 | verboselog(space.machine(), 3, " IRQ Pending = %s\n", (data & SPIM_SPIMIRQ) ? "Yes" : "No"); | |
| 1269 | verboselog(space.machine(), 3, " Exchange = %s\n", (data & SPIM_XCH) ? "Initiate" : "Idle"); | |
| 1270 | verboselog(space.machine(), 3, " SPIM Enable = %s\n", (data & SPIM_SPMEN) ? "Enable" : "Disable"); | |
| 1271 | verboselog(space.machine(), 3, " Data Rate = Divide By %d\n", 1 << ((((data & SPIM_RATE) >> 13) & 0x0007) + 2) ); | |
| 1272 | mc68328->regs.spimcont = data; | |
| 1273 | // $$HACK$$ We should probably emulate the ADS7843 A/D device properly. | |
| 1274 | if(data & SPIM_XCH) | |
| 1275 | { | |
| 1276 | mc68328->regs.spimcont &= ~SPIM_XCH; | |
| 1277 | if(mc68328->iface->spim_xch_trigger) | |
| 1278 | { | |
| 1279 | (mc68328->iface->spim_xch_trigger)( device ); | |
| 1280 | } | |
| 1281 | if(data & SPIM_IRQEN) | |
| 1282 | { | |
| 1283 | mc68328->regs.spimcont |= SPIM_SPIMIRQ; | |
| 1284 | verboselog(space.machine(), 3, "Triggering SPIM Interrupt\n" ); | |
| 1285 | mc68328_set_interrupt_line(device, INT_SPIM, 1); | |
| 1286 | } | |
| 1287 | } | |
| 1288 | if(!(data & SPIM_IRQEN)) | |
| 1289 | { | |
| 1290 | mc68328_set_interrupt_line(device, INT_SPIM, 0); | |
| 1291 | } | |
| 1292 | break; | |
| 1293 | ||
| 1294 | case 0x900: | |
| 1295 | verboselog(space.machine(), 2, "mc68328_w: USTCNT = %04x\n", data); | |
| 1296 | mc68328->regs.ustcnt = data; | |
| 1297 | break; | |
| 1298 | ||
| 1299 | case 0x902: | |
| 1300 | verboselog(space.machine(), 2, "mc68328_w: UBAUD = %04x\n", data); | |
| 1301 | mc68328->regs.ubaud = data; | |
| 1302 | break; | |
| 1303 | ||
| 1304 | case 0x904: | |
| 1305 | verboselog(space.machine(), 2, "mc68328_w: URX = %04x\n", data); | |
| 1306 | break; | |
| 1307 | ||
| 1308 | case 0x906: | |
| 1309 | verboselog(space.machine(), 2, "mc68328_w: UTX = %04x\n", data); | |
| 1310 | break; | |
| 1311 | ||
| 1312 | case 0x908: | |
| 1313 | verboselog(space.machine(), 2, "mc68328_w: UMISC = %04x\n", data); | |
| 1314 | mc68328->regs.umisc = data; | |
| 1315 | break; | |
| 1316 | ||
| 1317 | case 0xa00: | |
| 1318 | verboselog(space.machine(), 2, "mc68328_w: LSSA(16) = %04x\n", data); | |
| 1319 | mc68328->regs.lssa &= ~(mem_mask << 16); | |
| 1320 | mc68328->regs.lssa |= (data & mem_mask) << 16; | |
| 1321 | verboselog(space.machine(), 3, " Address: %08x\n", mc68328->regs.lssa); | |
| 1322 | break; | |
| 1323 | ||
| 1324 | case 0xa02: | |
| 1325 | verboselog(space.machine(), 2, "mc68328_w: LSSA(0) = %04x\n", data); | |
| 1326 | mc68328->regs.lssa &= 0xffff0000 | (~mem_mask); | |
| 1327 | mc68328->regs.lssa |= data & mem_mask; | |
| 1328 | verboselog(space.machine(), 3, " Address: %08x\n", mc68328->regs.lssa); | |
| 1329 | break; | |
| 1330 | ||
| 1331 | case 0xa04: | |
| 1332 | if( mem_mask & 0x00ff ) | |
| 1333 | { | |
| 1334 | verboselog(space.machine(), 2, "mc68328_w: LVPW = %02x\n", data & 0x00ff); | |
| 1335 | mc68328->regs.lvpw = data & 0x00ff; | |
| 1336 | verboselog(space.machine(), 3, " Page Width: %d or %d\n", (mc68328->regs.lvpw + 1) * ((mc68328->regs.lpicf & 0x01) ? 8 : 16)); | |
| 1337 | } | |
| 1338 | else | |
| 1339 | { | |
| 1340 | verboselog(space.machine(), 2, "mc68328_w: Unknown address (0xfffa04) = %02x\n", (data >> 8) & 0x00ff); | |
| 1341 | } | |
| 1342 | break; | |
| 1343 | ||
| 1344 | case 0xa08: | |
| 1345 | verboselog(space.machine(), 2, "mc68328_w: LXMAX = %04x\n", data); | |
| 1346 | mc68328->regs.lxmax = data; | |
| 1347 | verboselog(space.machine(), 3, " Width: %d\n", (data & 0x03ff) + 1); | |
| 1348 | break; | |
| 1349 | ||
| 1350 | case 0xa0a: | |
| 1351 | verboselog(space.machine(), 2, "mc68328_w: LYMAX = %04x\n", data); | |
| 1352 | mc68328->regs.lymax = data; | |
| 1353 | verboselog(space.machine(), 3, " Height: %d\n", (data & 0x03ff) + 1); | |
| 1354 | break; | |
| 1355 | ||
| 1356 | case 0xa18: | |
| 1357 | verboselog(space.machine(), 2, "mc68328_w: LCXP = %04x\n", data); | |
| 1358 | mc68328->regs.lcxp = data; | |
| 1359 | verboselog(space.machine(), 3, " X Position: %d\n", data & 0x03ff); | |
| 1360 | switch(mc68328->regs.lcxp >> 14) | |
| 1361 | { | |
| 1362 | case 0: | |
| 1363 | verboselog(space.machine(), 3, " Cursor Control: Transparent\n"); | |
| 1364 | break; | |
| 1365 | ||
| 1366 | case 1: | |
| 1367 | verboselog(space.machine(), 3, " Cursor Control: Black\n"); | |
| 1368 | break; | |
| 1369 | ||
| 1370 | case 2: | |
| 1371 | verboselog(space.machine(), 3, " Cursor Control: Reverse\n"); | |
| 1372 | break; | |
| 1373 | ||
| 1374 | case 3: | |
| 1375 | verboselog(space.machine(), 3, " Cursor Control: Invalid\n"); | |
| 1376 | break; | |
| 1377 | } | |
| 1378 | break; | |
| 1379 | ||
| 1380 | case 0xa1a: | |
| 1381 | verboselog(space.machine(), 2, "mc68328_w: LCYP = %04x\n", data); | |
| 1382 | mc68328->regs.lcyp = data; | |
| 1383 | verboselog(space.machine(), 3, " Y Position: %d\n", data & 0x01ff); | |
| 1384 | break; | |
| 1385 | ||
| 1386 | case 0xa1c: | |
| 1387 | verboselog(space.machine(), 2, "mc68328_w: LCWCH = %04x\n", data); | |
| 1388 | mc68328->regs.lcwch = data; | |
| 1389 | verboselog(space.machine(), 3, " Width: %d\n", (data >> 8) & 0x1f); | |
| 1390 | verboselog(space.machine(), 3, " Height: %d\n", data & 0x1f); | |
| 1391 | break; | |
| 1392 | ||
| 1393 | case 0xa1e: | |
| 1394 | if( mem_mask & 0x00ff ) | |
| 1395 | { | |
| 1396 | verboselog(space.machine(), 2, "mc68328_w: LBLKC = %02x\n", data & 0x00ff); | |
| 1397 | mc68328->regs.lblkc = data & 0x00ff; | |
| 1398 | verboselog(space.machine(), 3, " Blink Enable: %d\n", mc68328->regs.lblkc >> 7); | |
| 1399 | verboselog(space.machine(), 3, " Blink Divisor: %d\n", mc68328->regs.lblkc & 0x7f); | |
| 1400 | } | |
| 1401 | else | |
| 1402 | { | |
| 1403 | verboselog(space.machine(), 2, "mc68328_w: Unknown address (0xfffa1e) = %02x\n", (data >> 8) & 0x00ff); | |
| 1404 | } | |
| 1405 | break; | |
| 1406 | ||
| 1407 | case 0xa20: | |
| 1408 | if( mem_mask & 0x00ff ) | |
| 1409 | { | |
| 1410 | verboselog(space.machine(), 2, "mc68328_w: LPOLCF = %02x\n", data & 0x00ff); | |
| 1411 | mc68328->regs.lpolcf = data & 0x00ff; | |
| 1412 | verboselog(space.machine(), 3, " LCD Shift Clock Polarity: %s\n", (mc68328->regs.lpicf & 0x08) ? "Active positive edge of LCLK" : "Active negative edge of LCLK"); | |
| 1413 | verboselog(space.machine(), 3, " First-line marker polarity: %s\n", (mc68328->regs.lpicf & 0x04) ? "Active Low" : "Active High"); | |
| 1414 | verboselog(space.machine(), 3, " Line-pulse polarity: %s\n", (mc68328->regs.lpicf & 0x02) ? "Active Low" : "Active High"); | |
| 1415 | verboselog(space.machine(), 3, " Pixel polarity: %s\n", (mc68328->regs.lpicf & 0x01) ? "Active Low" : "Active High"); | |
| 1416 | } | |
| 1417 | else | |
| 1418 | { | |
| 1419 | verboselog(space.machine(), 2, "mc68328_w: LPICF = %02x\n", (data >> 8) & 0x00ff); | |
| 1420 | mc68328->regs.lpicf = (data >> 8) & 0x00ff; | |
| 1421 | switch((mc68328->regs.lpicf >> 1) & 0x03) | |
| 1422 | { | |
| 1423 | case 0: | |
| 1424 | verboselog(space.machine(), 3, " Bus Size: 1-bit\n"); | |
| 1425 | break; | |
| 1426 | ||
| 1427 | case 1: | |
| 1428 | verboselog(space.machine(), 3, " Bus Size: 2-bit\n"); | |
| 1429 | break; | |
| 1430 | ||
| 1431 | case 2: | |
| 1432 | verboselog(space.machine(), 3, " Bus Size: 4-bit\n"); | |
| 1433 | break; | |
| 1434 | ||
| 1435 | case 3: | |
| 1436 | verboselog(space.machine(), 3, " Bus Size: unused\n"); | |
| 1437 | break; | |
| 1438 | } | |
| 1439 | verboselog(space.machine(), 3, " Gray scale enable: %d\n", mc68328->regs.lpicf & 0x01); | |
| 1440 | } | |
| 1441 | break; | |
| 1442 | ||
| 1443 | case 0xa22: | |
| 1444 | if( mem_mask & 0x00ff ) | |
| 1445 | { | |
| 1446 | verboselog(space.machine(), 2, "mc68328_w: LACDRC = %02x\n", data & 0x00ff); | |
| 1447 | mc68328->regs.lacdrc = data & 0x00ff; | |
| 1448 | } | |
| 1449 | else | |
| 1450 | { | |
| 1451 | verboselog(space.machine(), 2, "mc68328_w: Unknown address (0xfffa22) = %02x\n", (data >> 8) & 0x00ff); | |
| 1452 | } | |
| 1453 | break; | |
| 1454 | ||
| 1455 | case 0xa24: | |
| 1456 | if( mem_mask & 0x00ff ) | |
| 1457 | { | |
| 1458 | verboselog(space.machine(), 2, "mc68328_w: LPXCD = %02x\n", data & 0x00ff); | |
| 1459 | mc68328->regs.lpxcd = data & 0x00ff; | |
| 1460 | verboselog(space.machine(), 3, " Clock Divisor: %d\n", mc68328->regs.lpxcd + 1); | |
| 1461 | } | |
| 1462 | else | |
| 1463 | { | |
| 1464 | verboselog(space.machine(), 2, "mc68328_w: Unknown address (0xfffa24) = %02x\n", (data >> 8) & 0x00ff); | |
| 1465 | } | |
| 1466 | break; | |
| 1467 | ||
| 1468 | case 0xa26: | |
| 1469 | if( mem_mask & 0x00ff ) | |
| 1470 | { | |
| 1471 | verboselog(space.machine(), 2, "mc68328_w: LCKCON = %02x\n", data & 0x00ff); | |
| 1472 | mc68328->regs.lckcon = data & 0x00ff; | |
| 1473 | verboselog(space.machine(), 3, " LCDC Enable: %d\n", (mc68328->regs.lckcon >> 7) & 0x01); | |
| 1474 | verboselog(space.machine(), 3, " DMA Burst Length: %d\n", ((mc68328->regs.lckcon >> 6) & 0x01) ? 16 : 8); | |
| 1475 | verboselog(space.machine(), 3, " DMA Bursting Clock Control: %d\n", ((mc68328->regs.lckcon >> 4) & 0x03) + 1); | |
| 1476 | verboselog(space.machine(), 3, " Bus Width: %d\n", ((mc68328->regs.lckcon >> 1) & 0x01) ? 8 : 16); | |
| 1477 | verboselog(space.machine(), 3, " Pixel Clock Divider Source: %s\n", (mc68328->regs.lckcon & 0x01) ? "PIX" : "SYS"); | |
| 1478 | } | |
| 1479 | else | |
| 1480 | { | |
| 1481 | verboselog(space.machine(), 2, "mc68328_w: Unknown address (0xfffa26) = %02x\n", (data >> 8) & 0x00ff); | |
| 1482 | } | |
| 1483 | break; | |
| 1484 | ||
| 1485 | case 0xa28: | |
| 1486 | if( mem_mask & 0x00ff ) | |
| 1487 | { | |
| 1488 | verboselog(space.machine(), 2, "mc68328_w: LLBAR = %02x\n", data & 0x00ff); | |
| 1489 | mc68328->regs.llbar = data & 0x00ff; | |
| 1490 | verboselog(space.machine(), 3, " Address: %d\n", (mc68328->regs.llbar & 0x7f) * ((mc68328->regs.lpicf & 0x01) ? 8 : 16)); | |
| 1491 | } | |
| 1492 | else | |
| 1493 | { | |
| 1494 | verboselog(space.machine(), 2, "mc68328_w: Unknown address (0xfffa28) = %02x\n", (data >> 8) & 0x00ff); | |
| 1495 | } | |
| 1496 | break; | |
| 1497 | ||
| 1498 | case 0xa2a: | |
| 1499 | if( mem_mask & 0x00ff ) | |
| 1500 | { | |
| 1501 | verboselog(space.machine(), 2, "mc68328_w: LOTCR = %02x\n", data & 0x00ff); | |
| 1502 | } | |
| 1503 | else | |
| 1504 | { | |
| 1505 | verboselog(space.machine(), 2, "mc68328_w: Unknown address (0xfffa2a) = %02x\n", (data >> 8) & 0x00ff); | |
| 1506 | } | |
| 1507 | break; | |
| 1508 | ||
| 1509 | case 0xa2c: | |
| 1510 | if( mem_mask & 0x00ff ) | |
| 1511 | { | |
| 1512 | verboselog(space.machine(), 2, "mc68328_w: LPOSR = %02x\n", data & 0x00ff); | |
| 1513 | mc68328->regs.lposr = data & 0x00ff; | |
| 1514 | verboselog(space.machine(), 3, " Byte Offset: %d\n", (mc68328->regs.lposr >> 3) & 0x01); | |
| 1515 | verboselog(space.machine(), 3, " Pixel Offset: %d\n", mc68328->regs.lposr & 0x07); | |
| 1516 | } | |
| 1517 | else | |
| 1518 | { | |
| 1519 | verboselog(space.machine(), 2, "mc68328_w: Unknown address (0xfffa2c) = %02x\n", (data >> 8) & 0x00ff); | |
| 1520 | } | |
| 1521 | break; | |
| 1522 | ||
| 1523 | case 0xa30: | |
| 1524 | if( mem_mask & 0x00ff ) | |
| 1525 | { | |
| 1526 | verboselog(space.machine(), 2, "mc68328_w: LFRCM = %02x\n", data & 0x00ff); | |
| 1527 | mc68328->regs.lfrcm = data & 0x00ff; | |
| 1528 | verboselog(space.machine(), 3, " X Modulation: %d\n", (mc68328->regs.lfrcm >> 4) & 0x0f); | |
| 1529 | verboselog(space.machine(), 3, " Y Modulation: %d\n", mc68328->regs.lfrcm & 0x0f); | |
| 1530 | } | |
| 1531 | else | |
| 1532 | { | |
| 1533 | verboselog(space.machine(), 2, "mc68328_w: Unknown address (0xfffa30) = %02x\n", (data >> 8) & 0x00ff); | |
| 1534 | } | |
| 1535 | break; | |
| 1536 | ||
| 1537 | case 0xa32: | |
| 1538 | verboselog(space.machine(), 2, "mc68328_w: LGPMR = %04x\n", data); | |
| 1539 | mc68328->regs.lgpmr = data; | |
| 1540 | verboselog(space.machine(), 3, " Palette 0: %d\n", (mc68328->regs.lgpmr >> 8) & 0x07); | |
| 1541 | verboselog(space.machine(), 3, " Palette 1: %d\n", (mc68328->regs.lgpmr >> 12) & 0x07); | |
| 1542 | verboselog(space.machine(), 3, " Palette 2: %d\n", (mc68328->regs.lgpmr >> 0) & 0x07); | |
| 1543 | verboselog(space.machine(), 3, " Palette 3: %d\n", (mc68328->regs.lgpmr >> 4) & 0x07); | |
| 1544 | break; | |
| 1545 | ||
| 1546 | case 0xb00: | |
| 1547 | verboselog(space.machine(), 2, "mc68328_w: HMSR(0) = %04x\n", data); | |
| 1548 | mc68328->regs.hmsr &= ~(mem_mask << 16); | |
| 1549 | mc68328->regs.hmsr |= (data & mem_mask) << 16; | |
| 1550 | mc68328->regs.hmsr &= 0x1f3f003f; | |
| 1551 | break; | |
| 1552 | ||
| 1553 | case 0xb02: | |
| 1554 | verboselog(space.machine(), 2, "mc68328_w: HMSR(16) = %04x\n", data); | |
| 1555 | mc68328->regs.hmsr &= 0xffff0000 | (~mem_mask); | |
| 1556 | mc68328->regs.hmsr |= data & mem_mask; | |
| 1557 | mc68328->regs.hmsr &= 0x1f3f003f; | |
| 1558 | break; | |
| 1559 | ||
| 1560 | case 0xb04: | |
| 1561 | verboselog(space.machine(), 2, "mc68328_w: ALARM(0) = %04x\n", data); | |
| 1562 | mc68328->regs.alarm &= ~(mem_mask << 16); | |
| 1563 | mc68328->regs.alarm |= (data & mem_mask) << 16; | |
| 1564 | mc68328->regs.alarm &= 0x1f3f003f; | |
| 1565 | break; | |
| 1566 | ||
| 1567 | case 0xb06: | |
| 1568 | verboselog(space.machine(), 2, "mc68328_w: ALARM(16) = %04x\n", data); | |
| 1569 | mc68328->regs.alarm &= 0xffff0000 | (~mem_mask); | |
| 1570 | mc68328->regs.alarm |= data & mem_mask; | |
| 1571 | mc68328->regs.alarm &= 0x1f3f003f; | |
| 1572 | break; | |
| 1573 | ||
| 1574 | case 0xb0c: | |
| 1575 | verboselog(space.machine(), 2, "mc68328_w: RTCCTL = %04x\n", data); | |
| 1576 | mc68328->regs.rtcctl = data & 0x00a0; | |
| 1577 | break; | |
| 1578 | ||
| 1579 | case 0xb0e: | |
| 1580 | verboselog(space.machine(), 2, "mc68328_w: RTCISR = %04x\n", data); | |
| 1581 | mc68328->regs.rtcisr &= ~data; | |
| 1582 | if(mc68328->regs.rtcisr == 0) | |
| 1583 | { | |
| 1584 | mc68328_set_interrupt_line(device, INT_RTC, 0); | |
| 1585 | } | |
| 1586 | break; | |
| 1587 | ||
| 1588 | case 0xb10: | |
| 1589 | verboselog(space.machine(), 2, "mc68328_w: RTCIENR = %04x\n", data); | |
| 1590 | mc68328->regs.rtcienr = data & 0x001f; | |
| 1591 | break; | |
| 1592 | ||
| 1593 | case 0xb12: | |
| 1594 | verboselog(space.machine(), 2, "mc68328_w: STPWTCH = %04x\n", data); | |
| 1595 | mc68328->regs.stpwtch = data & 0x003f; | |
| 1596 | break; | |
| 1597 | ||
| 1598 | default: | |
| 1599 | verboselog(space.machine(), 0, "mc68328_w: Unknown address (0x%06x) = %04x (%04x)\n", 0xfff000 + address, data, mem_mask); | |
| 1600 | break; | |
| 1601 | } | |
| 1602 | } | |
| 1603 | ||
| 1604 | READ16_DEVICE_HANDLER( mc68328_r ) | |
| 1605 | { | |
| 1606 | mc68328_t* mc68328 = mc68328_get_safe_token( device ); | |
| 1607 | UINT16 temp16 = 0; | |
| 1608 | UINT32 address = offset << 1; | |
| 1609 | ||
| 1610 | switch(address) | |
| 1611 | { | |
| 1612 | case 0x000: | |
| 1613 | if( mem_mask & 0x00ff ) | |
| 1614 | { | |
| 1615 | verboselog(space.machine(), 2, "mc68328_r (%04x): Unknown address (0xfff001)\n", mem_mask); | |
| 1616 | } | |
| 1617 | else | |
| 1618 | { | |
| 1619 | verboselog(space.machine(), 2, "mc68328_r (%04x): SCR = %02x\n", mem_mask, mc68328->regs.scr); | |
| 1620 | return mc68328->regs.scr << 8; | |
| 1621 | } | |
| 1622 | break; | |
| 1623 | ||
| 1624 | case 0x100: | |
| 1625 | verboselog(space.machine(), 2, "mc68328_r (%04x): GRPBASEA = %04x\n", mem_mask, mc68328->regs.grpbasea); | |
| 1626 | return mc68328->regs.grpbasea; | |
| 1627 | ||
| 1628 | case 0x102: | |
| 1629 | verboselog(space.machine(), 2, "mc68328_r (%04x): GRPBASEB = %04x\n", mem_mask, mc68328->regs.grpbaseb); | |
| 1630 | return mc68328->regs.grpbaseb; | |
| 1631 | ||
| 1632 | case 0x104: | |
| 1633 | verboselog(space.machine(), 2, "mc68328_r (%04x): GRPBASEC = %04x\n", mem_mask, mc68328->regs.grpbasec); | |
| 1634 | return mc68328->regs.grpbasec; | |
| 1635 | ||
| 1636 | case 0x106: | |
| 1637 | verboselog(space.machine(), 2, "mc68328_r (%04x): GRPBASED = %04x\n", mem_mask, mc68328->regs.grpbased); | |
| 1638 | return mc68328->regs.grpbased; | |
| 1639 | ||
| 1640 | case 0x108: | |
| 1641 | verboselog(space.machine(), 2, "mc68328_r (%04x): GRPMASKA = %04x\n", mem_mask, mc68328->regs.grpmaska); | |
| 1642 | return mc68328->regs.grpmaska; | |
| 1643 | ||
| 1644 | case 0x10a: | |
| 1645 | verboselog(space.machine(), 2, "mc68328_r (%04x): GRPMASKB = %04x\n", mem_mask, mc68328->regs.grpmaskb); | |
| 1646 | return mc68328->regs.grpmaskb; | |
| 1647 | ||
| 1648 | case 0x10c: | |
| 1649 | verboselog(space.machine(), 2, "mc68328_r (%04x): GRPMASKC = %04x\n", mem_mask, mc68328->regs.grpmaskc); | |
| 1650 | return mc68328->regs.grpmaskc; | |
| 1651 | ||
| 1652 | case 0x10e: | |
| 1653 | verboselog(space.machine(), 2, "mc68328_r (%04x): GRPMASKD = %04x\n", mem_mask, mc68328->regs.grpmaskd); | |
| 1654 | return mc68328->regs.grpmaskd; | |
| 1655 | ||
| 1656 | case 0x110: | |
| 1657 | verboselog(space.machine(), 5, "mc68328_r (%04x): CSA0(0) = %04x\n", mem_mask, mc68328->regs.csa0 & 0x0000ffff); | |
| 1658 | return mc68328->regs.csa0 & 0x0000ffff; | |
| 1659 | ||
| 1660 | case 0x112: | |
| 1661 | verboselog(space.machine(), 5, "mc68328_r (%04x): CSA0(16) = %04x\n", mem_mask, mc68328->regs.csa0 >> 16); | |
| 1662 | return mc68328->regs.csa0 >> 16; | |
| 1663 | ||
| 1664 | case 0x114: | |
| 1665 | verboselog(space.machine(), 5, "mc68328_r (%04x): CSA1(0) = %04x\n", mem_mask, mc68328->regs.csa1 & 0x0000ffff); | |
| 1666 | return mc68328->regs.csa1 & 0x0000ffff; | |
| 1667 | ||
| 1668 | case 0x116: | |
| 1669 | verboselog(space.machine(), 5, "mc68328_r (%04x): CSA1(16) = %04x\n", mem_mask, mc68328->regs.csa1 >> 16); | |
| 1670 | return mc68328->regs.csa1 >> 16; | |
| 1671 | ||
| 1672 | case 0x118: | |
| 1673 | verboselog(space.machine(), 5, "mc68328_r (%04x): CSA2(0) = %04x\n", mem_mask, mc68328->regs.csa2 & 0x0000ffff); | |
| 1674 | return mc68328->regs.csa2 & 0x0000ffff; | |
| 1675 | ||
| 1676 | case 0x11a: | |
| 1677 | verboselog(space.machine(), 5, "mc68328_r (%04x): CSA2(16) = %04x\n", mem_mask, mc68328->regs.csa2 >> 16); | |
| 1678 | return mc68328->regs.csa2 >> 16; | |
| 1679 | ||
| 1680 | case 0x11c: | |
| 1681 | verboselog(space.machine(), 5, "mc68328_r (%04x): CSA3(0) = %04x\n", mem_mask, mc68328->regs.csa3 & 0x0000ffff); | |
| 1682 | return mc68328->regs.csa3 & 0x0000ffff; | |
| 1683 | ||
| 1684 | case 0x11e: | |
| 1685 | verboselog(space.machine(), 5, "mc68328_r (%04x): CSA3(16) = %04x\n", mem_mask, mc68328->regs.csa3 >> 16); | |
| 1686 | return mc68328->regs.csa3 >> 16; | |
| 1687 | ||
| 1688 | case 0x120: | |
| 1689 | verboselog(space.machine(), 5, "mc68328_r (%04x): CSB0(0) = %04x\n", mem_mask, mc68328->regs.csb0 & 0x0000ffff); | |
| 1690 | return mc68328->regs.csb0 & 0x0000ffff; | |
| 1691 | ||
| 1692 | case 0x122: | |
| 1693 | verboselog(space.machine(), 5, "mc68328_r (%04x): CSB0(16) = %04x\n", mem_mask, mc68328->regs.csb0 >> 16); | |
| 1694 | return mc68328->regs.csb0 >> 16; | |
| 1695 | ||
| 1696 | case 0x124: | |
| 1697 | verboselog(space.machine(), 5, "mc68328_r (%04x): CSB1(0) = %04x\n", mem_mask, mc68328->regs.csb1 & 0x0000ffff); | |
| 1698 | return mc68328->regs.csb1 & 0x0000ffff; | |
| 1699 | ||
| 1700 | case 0x126: | |
| 1701 | verboselog(space.machine(), 5, "mc68328_r (%04x): CSB1(16) = %04x\n", mem_mask, mc68328->regs.csb1 >> 16); | |
| 1702 | return mc68328->regs.csb1 >> 16; | |
| 1703 | ||
| 1704 | case 0x128: | |
| 1705 | verboselog(space.machine(), 5, "mc68328_r (%04x): CSB2(0) = %04x\n", mem_mask, mc68328->regs.csb2 & 0x0000ffff); | |
| 1706 | return mc68328->regs.csb2 & 0x0000ffff; | |
| 1707 | ||
| 1708 | case 0x12a: | |
| 1709 | verboselog(space.machine(), 5, "mc68328_r (%04x): CSB2(16) = %04x\n", mem_mask, mc68328->regs.csb2 >> 16); | |
| 1710 | return mc68328->regs.csb2 >> 16; | |
| 1711 | ||
| 1712 | case 0x12c: | |
| 1713 | verboselog(space.machine(), 5, "mc68328_r (%04x): CSB3(0) = %04x\n", mem_mask, mc68328->regs.csb3 & 0x0000ffff); | |
| 1714 | return mc68328->regs.csb3 & 0x0000ffff; | |
| 1715 | ||
| 1716 | case 0x12e: | |
| 1717 | verboselog(space.machine(), 5, "mc68328_r (%04x): CSB3(16) = %04x\n", mem_mask, mc68328->regs.csb3 >> 16); | |
| 1718 | return mc68328->regs.csb3 >> 16; | |
| 1719 | ||
| 1720 | case 0x130: | |
| 1721 | verboselog(space.machine(), 5, "mc68328_r (%04x): CSC0(0) = %04x\n", mem_mask, mc68328->regs.csc0 & 0x0000ffff); | |
| 1722 | return mc68328->regs.csc0 & 0x0000ffff; | |
| 1723 | ||
| 1724 | case 0x132: | |
| 1725 | verboselog(space.machine(), 5, "mc68328_r (%04x): CSC0(16) = %04x\n", mem_mask, mc68328->regs.csc0 >> 16); | |
| 1726 | return mc68328->regs.csc0 >> 16; | |
| 1727 | ||
| 1728 | case 0x134: | |
| 1729 | verboselog(space.machine(), 5, "mc68328_r (%04x): CSC1(0) = %04x\n", mem_mask, mc68328->regs.csc1 & 0x0000ffff); | |
| 1730 | return mc68328->regs.csc1 & 0x0000ffff; | |
| 1731 | ||
| 1732 | case 0x136: | |
| 1733 | verboselog(space.machine(), 5, "mc68328_r (%04x): CSC1(16) = %04x\n", mem_mask, mc68328->regs.csc1 >> 16); | |
| 1734 | return mc68328->regs.csc1 >> 16; | |
| 1735 | ||
| 1736 | case 0x138: | |
| 1737 | verboselog(space.machine(), 5, "mc68328_r (%04x): CSC2(0) = %04x\n", mem_mask, mc68328->regs.csc2 & 0x0000ffff); | |
| 1738 | return mc68328->regs.csc2 & 0x0000ffff; | |
| 1739 | ||
| 1740 | case 0x13a: | |
| 1741 | verboselog(space.machine(), 5, "mc68328_r (%04x): CSC2(16) = %04x\n", mem_mask, mc68328->regs.csc2 >> 16); | |
| 1742 | return mc68328->regs.csc2 >> 16; | |
| 1743 | ||
| 1744 | case 0x13c: | |
| 1745 | verboselog(space.machine(), 5, "mc68328_r (%04x): CSC3(0) = %04x\n", mem_mask, mc68328->regs.csc3 & 0x0000ffff); | |
| 1746 | return mc68328->regs.csc3 & 0x0000ffff; | |
| 1747 | ||
| 1748 | case 0x13e: | |
| 1749 | verboselog(space.machine(), 5, "mc68328_r (%04x): CSC3(16) = %04x\n", mem_mask, mc68328->regs.csc3 >> 16); | |
| 1750 | return mc68328->regs.csc3 >> 16; | |
| 1751 | ||
| 1752 | case 0x140: | |
| 1753 | verboselog(space.machine(), 5, "mc68328_r (%04x): CSD0(0) = %04x\n", mem_mask, mc68328->regs.csd0 & 0x0000ffff); | |
| 1754 | return mc68328->regs.csd0 & 0x0000ffff; | |
| 1755 | ||
| 1756 | case 0x142: | |
| 1757 | verboselog(space.machine(), 5, "mc68328_r (%04x): CSD0(16) = %04x\n", mem_mask, mc68328->regs.csd0 >> 16); | |
| 1758 | return mc68328->regs.csd0 >> 16; | |
| 1759 | ||
| 1760 | case 0x144: | |
| 1761 | verboselog(space.machine(), 5, "mc68328_r (%04x): CSD1(0) = %04x\n", mem_mask, mc68328->regs.csd1 & 0x0000ffff); | |
| 1762 | return mc68328->regs.csd1 & 0x0000ffff; | |
| 1763 | ||
| 1764 | case 0x146: | |
| 1765 | verboselog(space.machine(), 5, "mc68328_r (%04x): CSD1(16) = %04x\n", mem_mask, mc68328->regs.csd1 >> 16); | |
| 1766 | return mc68328->regs.csd1 >> 16; | |
| 1767 | ||
| 1768 | case 0x148: | |
| 1769 | verboselog(space.machine(), 5, "mc68328_r (%04x): CSD2(0) = %04x\n", mem_mask, mc68328->regs.csd2 & 0x0000ffff); | |
| 1770 | return mc68328->regs.csd2 & 0x0000ffff; | |
| 1771 | ||
| 1772 | case 0x14a: | |
| 1773 | verboselog(space.machine(), 5, "mc68328_r (%04x): CSD2(16) = %04x\n", mem_mask, mc68328->regs.csd2 >> 16); | |
| 1774 | return mc68328->regs.csd2 >> 16; | |
| 1775 | ||
| 1776 | case 0x14c: | |
| 1777 | verboselog(space.machine(), 5, "mc68328_r (%04x): CSD3(0) = %04x\n", mem_mask, mc68328->regs.csd3 & 0x0000ffff); | |
| 1778 | return mc68328->regs.csd3 & 0x0000ffff; | |
| 1779 | ||
| 1780 | case 0x14e: | |
| 1781 | verboselog(space.machine(), 5, "mc68328_r (%04x): CSD3(16) = %04x\n", mem_mask, mc68328->regs.csd3 >> 16); | |
| 1782 | return mc68328->regs.csd3 >> 16; | |
| 1783 | ||
| 1784 | case 0x200: | |
| 1785 | verboselog(space.machine(), 2, "mc68328_r (%04x): PLLCR = %04x\n", mem_mask, mc68328->regs.pllcr); | |
| 1786 | return mc68328->regs.pllcr; | |
| 1787 | ||
| 1788 | case 0x202: | |
| 1789 | verboselog(space.machine(), 2, "mc68328_r (%04x): PLLFSR = %04x\n", mem_mask, mc68328->regs.pllfsr); | |
| 1790 | mc68328->regs.pllfsr ^= 0x8000; | |
| 1791 | return mc68328->regs.pllfsr; | |
| 1792 | ||
| 1793 | case 0x206: | |
| 1794 | if( mem_mask & 0x00ff ) | |
| 1795 | { | |
| 1796 | verboselog(space.machine(), 2, "mc68328_r (%04x): Unknown address (0xfff206)\n", mem_mask); | |
| 1797 | } | |
| 1798 | else | |
| 1799 | { | |
| 1800 | verboselog(space.machine(), 2, "mc68328_r (%04x): PCTLR = %02x\n", mem_mask, mc68328->regs.pctlr); | |
| 1801 | return mc68328->regs.pctlr << 8; | |
| 1802 | } | |
| 1803 | break; | |
| 1804 | ||
| 1805 | case 0x300: | |
| 1806 | if( mem_mask & 0x00ff ) | |
| 1807 | { | |
| 1808 | verboselog(space.machine(), 2, "mc68328_r (%04x): Unknown address (0xfff301)\n", mem_mask); | |
| 1809 | } | |
| 1810 | else | |
| 1811 | { | |
| 1812 | verboselog(space.machine(), 2, "mc68328_r (%04x): IVR = %02x\n", mem_mask, mc68328->regs.ivr); | |
| 1813 | return mc68328->regs.ivr << 8; | |
| 1814 | } | |
| 1815 | break; | |
| 1816 | ||
| 1817 | case 0x302: | |
| 1818 | verboselog(space.machine(), 2, "mc68328_r (%04x): ICR = %04x\n", mem_mask, mc68328->regs.icr); | |
| 1819 | return mc68328->regs.icr; | |
| 1820 | ||
| 1821 | case 0x304: | |
| 1822 | verboselog(space.machine(), 2, "mc68328_r (%04x): IMR(16) = %04x\n", mem_mask, mc68328->regs.imr >> 16); | |
| 1823 | return mc68328->regs.imr >> 16; | |
| 1824 | ||
| 1825 | case 0x306: | |
| 1826 | verboselog(space.machine(), 2, "mc68328_r (%04x): IMR(0) = %04x\n", mem_mask, mc68328->regs.imr & 0x0000ffff); | |
| 1827 | return mc68328->regs.imr & 0x0000ffff; | |
| 1828 | ||
| 1829 | case 0x308: | |
| 1830 | verboselog(space.machine(), 2, "mc68328_r (%04x): IWR(16) = %04x\n", mem_mask, mc68328->regs.iwr >> 16); | |
| 1831 | return mc68328->regs.iwr >> 16; | |
| 1832 | ||
| 1833 | case 0x30a: | |
| 1834 | verboselog(space.machine(), 2, "mc68328_r (%04x): IWR(0) = %04x\n", mem_mask, mc68328->regs.iwr & 0x0000ffff); | |
| 1835 | return mc68328->regs.iwr & 0x0000ffff; | |
| 1836 | ||
| 1837 | case 0x30c: | |
| 1838 | verboselog(space.machine(), 2, "mc68328_r (%04x): ISR(16) = %04x\n", mem_mask, mc68328->regs.isr >> 16); | |
| 1839 | return mc68328->regs.isr >> 16; | |
| 1840 | ||
| 1841 | case 0x30e: | |
| 1842 | verboselog(space.machine(), 2, "mc68328_r (%04x): ISR(0) = %04x\n", mem_mask, mc68328->regs.isr & 0x0000ffff); | |
| 1843 | return mc68328->regs.isr & 0x0000ffff; | |
| 1844 | ||
| 1845 | case 0x310: | |
| 1846 | verboselog(space.machine(), 2, "mc68328_r (%04x): IPR(16) = %04x\n", mem_mask, mc68328->regs.ipr >> 16); | |
| 1847 | return mc68328->regs.ipr >> 16; | |
| 1848 | ||
| 1849 | case 0x312: | |
| 1850 | verboselog(space.machine(), 2, "mc68328_r (%04x): IPR(0) = %04x\n", mem_mask, mc68328->regs.ipr & 0x0000ffff); | |
| 1851 | return mc68328->regs.ipr & 0x0000ffff; | |
| 1852 | ||
| 1853 | case 0x400: | |
| 1854 | if( mem_mask & 0x00ff ) | |
| 1855 | { | |
| 1856 | verboselog(space.machine(), 2, "mc68328_r (%04x): PADATA = %02x\n", mem_mask, mc68328->regs.padata); | |
| 1857 | if(!mc68328->in_port_a.isnull()) | |
| 1858 | { | |
| 1859 | return mc68328->in_port_a( 0 ); | |
| 1860 | } | |
| 1861 | else | |
| 1862 | { | |
| 1863 | return mc68328->regs.padata; | |
| 1864 | } | |
| 1865 | } | |
| 1866 | else | |
| 1867 | { | |
| 1868 | verboselog(space.machine(), 2, "mc68328_r (%04x): PADIR = %02x\n", mem_mask, mc68328->regs.padir); | |
| 1869 | return mc68328->regs.padir << 8; | |
| 1870 | } | |
| 1871 | break; | |
| 1872 | ||
| 1873 | case 0x402: | |
| 1874 | if( mem_mask & 0x00ff ) | |
| 1875 | { | |
| 1876 | verboselog(space.machine(), 2, "mc68328_r (%04x): PASEL = %02x\n", mem_mask, mc68328->regs.pasel); | |
| 1877 | return mc68328->regs.pasel; | |
| 1878 | } | |
| 1879 | else | |
| 1880 | { | |
| 1881 | verboselog(space.machine(), 2, "mc68328_r (%04x): Unknown address (0xfff402)\n", mem_mask); | |
| 1882 | } | |
| 1883 | break; | |
| 1884 | ||
| 1885 | case 0x408: | |
| 1886 | if( mem_mask & 0x00ff ) | |
| 1887 | { | |
| 1888 | verboselog(space.machine(), 2, "mc68328_r (%04x): PBDATA = %02x\n", mem_mask, mc68328->regs.pbdata); | |
| 1889 | if(!mc68328->in_port_b.isnull()) | |
| 1890 | { | |
| 1891 | return mc68328->in_port_b( 0 ); | |
| 1892 | } | |
| 1893 | else | |
| 1894 | { | |
| 1895 | return mc68328->regs.pbdata; | |
| 1896 | } | |
| 1897 | } | |
| 1898 | else | |
| 1899 | { | |
| 1900 | verboselog(space.machine(), 2, "mc68328_r (%04x): PBDIR = %02x\n", mem_mask, mc68328->regs.pbdir); | |
| 1901 | return mc68328->regs.pbdir << 8; | |
| 1902 | } | |
| 1903 | break; | |
| 1904 | ||
| 1905 | case 0x40a: | |
| 1906 | if( mem_mask & 0x00ff ) | |
| 1907 | { | |
| 1908 | verboselog(space.machine(), 2, "mc68328_r (%04x): PBSEL = %02x\n", mem_mask, mc68328->regs.pbsel); | |
| 1909 | return mc68328->regs.pbsel; | |
| 1910 | } | |
| 1911 | else | |
| 1912 | { | |
| 1913 | verboselog(space.machine(), 2, "mc68328_r (%04x): Unknown address (0xfff40a)\n", mem_mask); | |
| 1914 | } | |
| 1915 | break; | |
| 1916 | ||
| 1917 | case 0x410: | |
| 1918 | if( mem_mask & 0x00ff ) | |
| 1919 | { | |
| 1920 | verboselog(space.machine(), 2, "mc68328_r (%04x): PCDATA = %02x\n", mem_mask, mc68328->regs.pcdata); | |
| 1921 | if(!mc68328->in_port_c.isnull()) | |
| 1922 | { | |
| 1923 | return mc68328->in_port_c( 0 ); | |
| 1924 | } | |
| 1925 | else | |
| 1926 | { | |
| 1927 | return mc68328->regs.pcdata; | |
| 1928 | } | |
| 1929 | } | |
| 1930 | else | |
| 1931 | { | |
| 1932 | verboselog(space.machine(), 2, "mc68328_r (%04x): PCDIR = %02x\n", mem_mask, mc68328->regs.pcdir); | |
| 1933 | return mc68328->regs.pcdir << 8; | |
| 1934 | } | |
| 1935 | break; | |
| 1936 | ||
| 1937 | case 0x412: | |
| 1938 | if( mem_mask & 0x00ff ) | |
| 1939 | { | |
| 1940 | verboselog(space.machine(), 2, "mc68328_r (%04x): PCSEL = %02x\n", mem_mask, mc68328->regs.pcsel); | |
| 1941 | return mc68328->regs.pcsel; | |
| 1942 | } | |
| 1943 | else | |
| 1944 | { | |
| 1945 | verboselog(space.machine(), 2, "mc68328_r (%04x): Unknown address (0xfff412)\n", mem_mask); | |
| 1946 | } | |
| 1947 | break; | |
| 1948 | ||
| 1949 | case 0x418: | |
| 1950 | if( mem_mask & 0x00ff ) | |
| 1951 | { | |
| 1952 | verboselog(space.machine(), 2, "mc68328_r (%04x): PDDATA = %02x\n", mem_mask, mc68328->regs.pddata); | |
| 1953 | if(!mc68328->in_port_d.isnull()) | |
| 1954 | { | |
| 1955 | return mc68328->in_port_d( 0 ); | |
| 1956 | } | |
| 1957 | else | |
| 1958 | { | |
| 1959 | return mc68328->regs.pddata; | |
| 1960 | } | |
| 1961 | } | |
| 1962 | else | |
| 1963 | { | |
| 1964 | verboselog(space.machine(), 2, "mc68328_r (%04x): PDDIR = %02x\n", mem_mask, mc68328->regs.pddir); | |
| 1965 | return mc68328->regs.pddir << 8; | |
| 1966 | } | |
| 1967 | break; | |
| 1968 | ||
| 1969 | case 0x41a: | |
| 1970 | if( mem_mask & 0x00ff ) | |
| 1971 | { | |
| 1972 | verboselog(space.machine(), 2, "mc68328_r (%04x): Unknown address (0xfff41b)\n", mem_mask); | |
| 1973 | } | |
| 1974 | else | |
| 1975 | { | |
| 1976 | verboselog(space.machine(), 2, "mc68328_r (%04x): PDPUEN = %02x\n", mem_mask, mc68328->regs.pdpuen); | |
| 1977 | return mc68328->regs.pdpuen << 8; | |
| 1978 | } | |
| 1979 | break; | |
| 1980 | ||
| 1981 | case 0x41c: | |
| 1982 | if( mem_mask & 0x00ff ) | |
| 1983 | { | |
| 1984 | verboselog(space.machine(), 2, "mc68328_r (%04x): PDIRQEN = %02x\n", mem_mask, mc68328->regs.pdirqen); | |
| 1985 | return mc68328->regs.pdirqen; | |
| 1986 | } | |
| 1987 | else | |
| 1988 | { | |
| 1989 | verboselog(space.machine(), 2, "mc68328_r (%04x): PDPOL = %02x\n", mem_mask, mc68328->regs.pdpol); | |
| 1990 | return mc68328->regs.pdpol << 8; | |
| 1991 | } | |
| 1992 | break; | |
| 1993 | ||
| 1994 | case 0x41e: | |
| 1995 | if( mem_mask & 0x00ff ) | |
| 1996 | { | |
| 1997 | verboselog(space.machine(), 2, "mc68328_r (%04x): PDIRQEDGE = %02x\n", mem_mask, mc68328->regs.pdirqedge); | |
| 1998 | return mc68328->regs.pdirqedge; | |
| 1999 | } | |
| 2000 | else | |
| 2001 | { | |
| 2002 | verboselog(space.machine(), 2, "mc68328_r (%04x): Unknown address (0xfff41e)\n", mem_mask); | |
| 2003 | } | |
| 2004 | break; | |
| 2005 | ||
| 2006 | case 0x420: | |
| 2007 | if( mem_mask & 0x00ff ) | |
| 2008 | { | |
| 2009 | verboselog(space.machine(), 2, "mc68328_r (%04x): PEDATA = %02x\n", mem_mask, mc68328->regs.pedata); | |
| 2010 | if(!mc68328->in_port_e.isnull()) | |
| 2011 | { | |
| 2012 | return mc68328->in_port_e( 0 ); | |
| 2013 | } | |
| 2014 | else | |
| 2015 | { | |
| 2016 | return mc68328->regs.pedata; | |
| 2017 | } | |
| 2018 | } | |
| 2019 | else | |
| 2020 | { | |
| 2021 | verboselog(space.machine(), 2, "mc68328_r (%04x): PEDIR = %02x\n", mem_mask, mc68328->regs.pedir); | |
| 2022 | return mc68328->regs.pedir << 8; | |
| 2023 | } | |
| 2024 | break; | |
| 2025 | ||
| 2026 | case 0x422: | |
| 2027 | if( mem_mask & 0x00ff ) | |
| 2028 | { | |
| 2029 | verboselog(space.machine(), 2, "mc68328_r (%04x): PESEL = %02x\n", mem_mask, mc68328->regs.pesel); | |
| 2030 | return mc68328->regs.pesel; | |
| 2031 | } | |
| 2032 | else | |
| 2033 | { | |
| 2034 | verboselog(space.machine(), 2, "mc68328_r (%04x): PEPUEN = %02x\n", mem_mask, mc68328->regs.pepuen); | |
| 2035 | return mc68328->regs.pepuen << 8; | |
| 2036 | } | |
| 2037 | break; | |
| 2038 | ||
| 2039 | case 0x428: | |
| 2040 | if( mem_mask & 0x00ff ) | |
| 2041 | { | |
| 2042 | verboselog(space.machine(), 2, "mc68328_r (%04x): PFDATA = %02x\n", mem_mask, mc68328->regs.pfdata); | |
| 2043 | if(!mc68328->in_port_f.isnull()) | |
| 2044 | { | |
| 2045 | return mc68328->in_port_f( 0 ); | |
| 2046 | } | |
| 2047 | else | |
| 2048 | { | |
| 2049 | return mc68328->regs.pfdata; | |
| 2050 | } | |
| 2051 | } | |
| 2052 | else | |
| 2053 | { | |
| 2054 | verboselog(space.machine(), 2, "mc68328_r (%04x): PFDIR = %02x\n", mem_mask, mc68328->regs.pfdir); | |
| 2055 | return mc68328->regs.pfdir << 8; | |
| 2056 | } | |
| 2057 | break; | |
| 2058 | ||
| 2059 | case 0x42a: | |
| 2060 | if( mem_mask & 0x00ff ) | |
| 2061 | { | |
| 2062 | verboselog(space.machine(), 2, "mc68328_r (%04x): PFSEL = %02x\n", mem_mask, mc68328->regs.pfsel); | |
| 2063 | return mc68328->regs.pfsel; | |
| 2064 | } | |
| 2065 | else | |
| 2066 | { | |
| 2067 | verboselog(space.machine(), 2, "mc68328_r (%04x): PFPUEN = %02x\n", mem_mask, mc68328->regs.pfpuen); | |
| 2068 | return mc68328->regs.pfpuen << 8; | |
| 2069 | } | |
| 2070 | break; | |
| 2071 | ||
| 2072 | case 0x430: | |
| 2073 | if( mem_mask & 0x00ff ) | |
| 2074 | { | |
| 2075 | verboselog(space.machine(), 2, "mc68328_r (%04x): PGDATA = %02x\n", mem_mask, mc68328->regs.pgdata); | |
| 2076 | if(!mc68328->in_port_g.isnull()) | |
| 2077 | { | |
| 2078 | return mc68328->in_port_g( 0 ); | |
| 2079 | } | |
| 2080 | else | |
| 2081 | { | |
| 2082 | return mc68328->regs.pgdata; | |
| 2083 | } | |
| 2084 | } | |
| 2085 | else | |
| 2086 | { | |
| 2087 | verboselog(space.machine(), 2, "mc68328_r (%04x): PGDIR = %02x\n", mem_mask, mc68328->regs.pgdir); | |
| 2088 | return mc68328->regs.pgdir << 8; | |
| 2089 | } | |
| 2090 | break; | |
| 2091 | ||
| 2092 | case 0x432: | |
| 2093 | if( mem_mask & 0x00ff ) | |
| 2094 | { | |
| 2095 | verboselog(space.machine(), 2, "mc68328_r (%04x): PGSEL = %02x\n", mem_mask, mc68328->regs.pgsel); | |
| 2096 | return mc68328->regs.pgsel; | |
| 2097 | } | |
| 2098 | else | |
| 2099 | { | |
| 2100 | verboselog(space.machine(), 2, "mc68328_r (%04x): PGPUEN = %02x\n", mem_mask, mc68328->regs.pgpuen); | |
| 2101 | return mc68328->regs.pgpuen << 8; | |
| 2102 | } | |
| 2103 | break; | |
| 2104 | ||
| 2105 | case 0x438: | |
| 2106 | if( mem_mask & 0x00ff ) | |
| 2107 | { | |
| 2108 | verboselog(space.machine(), 2, "mc68328_r (%04x): PJDATA = %02x\n", mem_mask, mc68328->regs.pjdata); | |
| 2109 | if(!mc68328->in_port_j.isnull()) | |
| 2110 | { | |
| 2111 | return mc68328->in_port_j( 0 ); | |
| 2112 | } | |
| 2113 | else | |
| 2114 | { | |
| 2115 | return mc68328->regs.pjdata; | |
| 2116 | } | |
| 2117 | } | |
| 2118 | else | |
| 2119 | { | |
| 2120 | verboselog(space.machine(), 2, "mc68328_r (%04x): PJDIR = %02x\n", mem_mask, mc68328->regs.pjdir); | |
| 2121 | return mc68328->regs.pjdir << 8; | |
| 2122 | } | |
| 2123 | break; | |
| 2124 | ||
| 2125 | case 0x43a: | |
| 2126 | if( mem_mask & 0x00ff ) | |
| 2127 | { | |
| 2128 | verboselog(space.machine(), 2, "mc68328_r (%04x): PJSEL = %02x\n", mem_mask, mc68328->regs.pjsel); | |
| 2129 | return mc68328->regs.pjsel; | |
| 2130 | } | |
| 2131 | else | |
| 2132 | { | |
| 2133 | verboselog(space.machine(), 2, "mc68328_r (%04x): Unknown address (0xfff43a)\n", mem_mask); | |
| 2134 | } | |
| 2135 | break; | |
| 2136 | ||
| 2137 | case 0x440: | |
| 2138 | if( mem_mask & 0x00ff ) | |
| 2139 | { | |
| 2140 | verboselog(space.machine(), 2, "mc68328_r (%04x): PKDATA = %02x\n", mem_mask, mc68328->regs.pkdata); | |
| 2141 | if(!mc68328->in_port_k.isnull()) | |
| 2142 | { | |
| 2143 | return mc68328->in_port_k( 0 ); | |
| 2144 | } | |
| 2145 | else | |
| 2146 | { | |
| 2147 | return mc68328->regs.pkdata; | |
| 2148 | } | |
| 2149 | } | |
| 2150 | else | |
| 2151 | { | |
| 2152 | verboselog(space.machine(), 2, "mc68328_r (%04x): PKDIR = %02x\n", mem_mask, mc68328->regs.pkdir); | |
| 2153 | return mc68328->regs.pkdir << 8; | |
| 2154 | } | |
| 2155 | break; | |
| 2156 | ||
| 2157 | case 0x442: | |
| 2158 | if( mem_mask & 0x00ff ) | |
| 2159 | { | |
| 2160 | verboselog(space.machine(), 2, "mc68328_r (%04x): PKSEL = %02x\n", mem_mask, mc68328->regs.pksel); | |
| 2161 | return mc68328->regs.pksel; | |
| 2162 | } | |
| 2163 | else | |
| 2164 | { | |
| 2165 | verboselog(space.machine(), 2, "mc68328_r (%04x): PKPUEN = %02x\n", mem_mask, mc68328->regs.pkpuen); | |
| 2166 | return mc68328->regs.pkpuen << 8; | |
| 2167 | } | |
| 2168 | break; | |
| 2169 | ||
| 2170 | case 0x448: | |
| 2171 | if( mem_mask & 0x00ff ) | |
| 2172 | { | |
| 2173 | verboselog(space.machine(), 2, "mc68328_r (%04x): PMDATA = %02x\n", mem_mask, mc68328->regs.pmdata); | |
| 2174 | if(!mc68328->in_port_m.isnull()) | |
| 2175 | { | |
| 2176 | return mc68328->in_port_m( 0 ); | |
| 2177 | } | |
| 2178 | else | |
| 2179 | { | |
| 2180 | return mc68328->regs.pmdata; | |
| 2181 | } | |
| 2182 | } | |
| 2183 | else | |
| 2184 | { | |
| 2185 | verboselog(space.machine(), 2, "mc68328_r (%04x): PMDIR = %02x\n", mem_mask, mc68328->regs.pmdir); | |
| 2186 | return mc68328->regs.pmdir << 8; | |
| 2187 | } | |
| 2188 | break; | |
| 2189 | ||
| 2190 | case 0x44a: | |
| 2191 | if( mem_mask & 0x00ff ) | |
| 2192 | { | |
| 2193 | verboselog(space.machine(), 2, "mc68328_r (%04x): PMSEL = %02x\n", mem_mask, mc68328->regs.pmsel); | |
| 2194 | return mc68328->regs.pmsel; | |
| 2195 | } | |
| 2196 | else | |
| 2197 | { | |
| 2198 | verboselog(space.machine(), 2, "mc68328_r (%04x): PMPUEN = %02x\n", mem_mask, mc68328->regs.pmpuen); | |
| 2199 | return mc68328->regs.pmpuen << 8; | |
| 2200 | } | |
| 2201 | break; | |
| 2202 | ||
| 2203 | case 0x500: | |
| 2204 | verboselog(space.machine(), 2, "mc68328_r (%04x): PWMC = %04x\n", mem_mask, mc68328->regs.pwmc); | |
| 2205 | temp16 = mc68328->regs.pwmc; | |
| 2206 | if(mc68328->regs.pwmc & PWMC_PWMIRQ) | |
| 2207 | { | |
| 2208 | mc68328->regs.pwmc &= ~PWMC_PWMIRQ; | |
| 2209 | mc68328_set_interrupt_line(device, INT_PWM, 0); | |
| 2210 | } | |
| 2211 | return temp16; | |
| 2212 | ||
| 2213 | case 0x502: | |
| 2214 | verboselog(space.machine(), 2, "mc68328_r (%04x): PWMP = %04x\n", mem_mask, mc68328->regs.pwmp); | |
| 2215 | return mc68328->regs.pwmp; | |
| 2216 | ||
| 2217 | case 0x504: | |
| 2218 | verboselog(space.machine(), 2, "mc68328_r (%04x): PWMW = %04x\n", mem_mask, mc68328->regs.pwmw); | |
| 2219 | return mc68328->regs.pwmw; | |
| 2220 | ||
| 2221 | case 0x506: | |
| 2222 | verboselog(space.machine(), 2, "mc68328_r (%04x): PWMCNT = %04x\n", mem_mask, mc68328->regs.pwmcnt); | |
| 2223 | return mc68328->regs.pwmcnt; | |
| 2224 | ||
| 2225 | case 0x600: | |
| 2226 | verboselog(space.machine(), 2, "mc68328_r (%04x): TCTL1 = %04x\n", mem_mask, mc68328->regs.tctl[0]); | |
| 2227 | return mc68328->regs.tctl[0]; | |
| 2228 | ||
| 2229 | case 0x602: | |
| 2230 | verboselog(space.machine(), 2, "mc68328_r (%04x): TPRER1 = %04x\n", mem_mask, mc68328->regs.tprer[0]); | |
| 2231 | return mc68328->regs.tprer[0]; | |
| 2232 | ||
| 2233 | case 0x604: | |
| 2234 | verboselog(space.machine(), 2, "mc68328_r (%04x): TCMP1 = %04x\n", mem_mask, mc68328->regs.tcmp[0]); | |
| 2235 | return mc68328->regs.tcmp[0]; | |
| 2236 | ||
| 2237 | case 0x606: | |
| 2238 | verboselog(space.machine(), 2, "mc68328_r (%04x): TCR1 = %04x\n", mem_mask, mc68328->regs.tcr[0]); | |
| 2239 | return mc68328->regs.tcr[0]; | |
| 2240 | ||
| 2241 | case 0x608: | |
| 2242 | verboselog(space.machine(), 2, "mc68328_r (%04x): TCN1 = %04x\n", mem_mask, mc68328->regs.tcn[0]); | |
| 2243 | return mc68328->regs.tcn[0]; | |
| 2244 | ||
| 2245 | case 0x60a: | |
| 2246 | verboselog(space.machine(), 5, "mc68328_r (%04x): TSTAT1 = %04x\n", mem_mask, mc68328->regs.tstat[0]); | |
| 2247 | mc68328->regs.tclear[0] |= mc68328->regs.tstat[0]; | |
| 2248 | return mc68328->regs.tstat[0]; | |
| 2249 | ||
| 2250 | case 0x60c: | |
| 2251 | verboselog(space.machine(), 2, "mc68328_r (%04x): TCTL2 = %04x\n", mem_mask, mc68328->regs.tctl[1]); | |
| 2252 | return mc68328->regs.tctl[1]; | |
| 2253 | ||
| 2254 | case 0x60e: | |
| 2255 | verboselog(space.machine(), 2, "mc68328_r (%04x): TPREP2 = %04x\n", mem_mask, mc68328->regs.tprer[1]); | |
| 2256 | return mc68328->regs.tprer[1]; | |
| 2257 | ||
| 2258 | case 0x610: | |
| 2259 | verboselog(space.machine(), 2, "mc68328_r (%04x): TCMP2 = %04x\n", mem_mask, mc68328->regs.tcmp[1]); | |
| 2260 | return mc68328->regs.tcmp[1]; | |
| 2261 | ||
| 2262 | case 0x612: | |
| 2263 | verboselog(space.machine(), 2, "mc68328_r (%04x): TCR2 = %04x\n", mem_mask, mc68328->regs.tcr[1]); | |
| 2264 | return mc68328->regs.tcr[1]; | |
| 2265 | ||
| 2266 | case 0x614: | |
| 2267 | verboselog(space.machine(), 2, "mc68328_r (%04x): TCN2 = %04x\n", mem_mask, mc68328->regs.tcn[1]); | |
| 2268 | return mc68328->regs.tcn[1]; | |
| 2269 | ||
| 2270 | case 0x616: | |
| 2271 | verboselog(space.machine(), 2, "mc68328_r (%04x): TSTAT2 = %04x\n", mem_mask, mc68328->regs.tstat[1]); | |
| 2272 | mc68328->regs.tclear[1] |= mc68328->regs.tstat[1]; | |
| 2273 | return mc68328->regs.tstat[1]; | |
| 2274 | ||
| 2275 | case 0x618: | |
| 2276 | verboselog(space.machine(), 2, "mc68328_r (%04x): WCTLR = %04x\n", mem_mask, mc68328->regs.wctlr); | |
| 2277 | return mc68328->regs.wctlr; | |
| 2278 | ||
| 2279 | case 0x61a: | |
| 2280 | verboselog(space.machine(), 2, "mc68328_r (%04x): WCMPR = %04x\n", mem_mask, mc68328->regs.wcmpr); | |
| 2281 | return mc68328->regs.wcmpr; | |
| 2282 | ||
| 2283 | case 0x61c: | |
| 2284 | verboselog(space.machine(), 2, "mc68328_r (%04x): WCN = %04x\n", mem_mask, mc68328->regs.wcn); | |
| 2285 | return mc68328->regs.wcn; | |
| 2286 | ||
| 2287 | case 0x700: | |
| 2288 | verboselog(space.machine(), 2, "mc68328_r (%04x): SPISR = %04x\n", mem_mask, mc68328->regs.spisr); | |
| 2289 | return mc68328->regs.spisr; | |
| 2290 | ||
| 2291 | case 0x800: | |
| 2292 | verboselog(space.machine(), 2, "mc68328_r (%04x): SPIMDATA = %04x\n", mem_mask, mc68328->regs.spimdata); | |
| 2293 | if(!mc68328->in_spim.isnull()) | |
| 2294 | { | |
| 2295 | return mc68328->in_spim( 0, 0xffff ); | |
| 2296 | } | |
| 2297 | return mc68328->regs.spimdata; | |
| 2298 | ||
| 2299 | case 0x802: | |
| 2300 | verboselog(space.machine(), 2, "mc68328_r (%04x): SPIMCONT = %04x\n", mem_mask, mc68328->regs.spimcont); | |
| 2301 | if(mc68328->regs.spimcont & SPIM_XCH) | |
| 2302 | { | |
| 2303 | mc68328->regs.spimcont &= ~SPIM_XCH; | |
| 2304 | mc68328->regs.spimcont |= SPIM_SPIMIRQ; | |
| 2305 | return ((mc68328->regs.spimcont | SPIM_XCH) &~ SPIM_SPIMIRQ); | |
| 2306 | } | |
| 2307 | return mc68328->regs.spimcont; | |
| 2308 | ||
| 2309 | case 0x900: | |
| 2310 | verboselog(space.machine(), 2, "mc68328_r (%04x): USTCNT = %04x\n", mem_mask, mc68328->regs.ustcnt); | |
| 2311 | return mc68328->regs.ustcnt; | |
| 2312 | ||
| 2313 | case 0x902: | |
| 2314 | verboselog(space.machine(), 2, "mc68328_r (%04x): UBAUD = %04x\n", mem_mask, mc68328->regs.ubaud); | |
| 2315 | return mc68328->regs.ubaud; | |
| 2316 | ||
| 2317 | case 0x904: | |
| 2318 | verboselog(space.machine(), 5, "mc68328_r (%04x): URX = %04x\n", mem_mask, mc68328->regs.urx); | |
| 2319 | return mc68328->regs.urx; | |
| 2320 | ||
| 2321 | case 0x906: | |
| 2322 | verboselog(space.machine(), 5, "mc68328_r (%04x): UTX = %04x\n", mem_mask, mc68328->regs.utx); | |
| 2323 | return mc68328->regs.utx | UTX_FIFO_EMPTY | UTX_FIFO_HALF | UTX_TX_AVAIL; | |
| 2324 | ||
| 2325 | case 0x908: | |
| 2326 | verboselog(space.machine(), 2, "mc68328_r (%04x): UMISC = %04x\n", mem_mask, mc68328->regs.umisc); | |
| 2327 | return mc68328->regs.umisc; | |
| 2328 | ||
| 2329 | case 0xa00: | |
| 2330 | verboselog(space.machine(), 2, "mc68328_r (%04x): LSSA(16) = %04x\n", mem_mask, mc68328->regs.lssa >> 16); | |
| 2331 | return mc68328->regs.lssa >> 16; | |
| 2332 | ||
| 2333 | case 0xa02: | |
| 2334 | verboselog(space.machine(), 2, "mc68328_r (%04x): LSSA(0) = %04x\n", mem_mask, mc68328->regs.lssa & 0x0000ffff); | |
| 2335 | return mc68328->regs.lssa & 0x0000ffff; | |
| 2336 | ||
| 2337 | case 0xa04: | |
| 2338 | if( mem_mask & 0x00ff ) | |
| 2339 | { | |
| 2340 | verboselog(space.machine(), 2, "mc68328_r (%04x): LVPW = %02x\n", mem_mask, mc68328->regs.lvpw); | |
| 2341 | return mc68328->regs.lvpw; | |
| 2342 | } | |
| 2343 | else | |
| 2344 | { | |
| 2345 | verboselog(space.machine(), 2, "mc68328_r (%04x): Unknown address (0xfffa04)\n", mem_mask); | |
| 2346 | } | |
| 2347 | break; | |
| 2348 | ||
| 2349 | case 0xa08: | |
| 2350 | verboselog(space.machine(), 2, "mc68328_r (%04x): LXMAX = %04x\n", mem_mask, mc68328->regs.lxmax); | |
| 2351 | return mc68328->regs.lxmax; | |
| 2352 | ||
| 2353 | case 0xa0a: | |
| 2354 | verboselog(space.machine(), 2, "mc68328_r (%04x): LYMAX = %04x\n", mem_mask, mc68328->regs.lymax); | |
| 2355 | return mc68328->regs.lymax; | |
| 2356 | ||
| 2357 | case 0xa18: | |
| 2358 | verboselog(space.machine(), 2, "mc68328_r (%04x): LCXP = %04x\n", mem_mask, mc68328->regs.lcxp); | |
| 2359 | return mc68328->regs.lcxp; | |
| 2360 | ||
| 2361 | case 0xa1a: | |
| 2362 | verboselog(space.machine(), 2, "mc68328_r (%04x): LCYP = %04x\n", mem_mask, mc68328->regs.lcyp); | |
| 2363 | return mc68328->regs.lcyp; | |
| 2364 | ||
| 2365 | case 0xa1c: | |
| 2366 | verboselog(space.machine(), 2, "mc68328_r (%04x): LCWCH = %04x\n", mem_mask, mc68328->regs.lcwch); | |
| 2367 | return mc68328->regs.lcwch; | |
| 2368 | ||
| 2369 | case 0xa1e: | |
| 2370 | if( mem_mask & 0x00ff ) | |
| 2371 | { | |
| 2372 | verboselog(space.machine(), 2, "mc68328_r (%04x): LBLKC = %02x\n", mem_mask, mc68328->regs.lblkc); | |
| 2373 | return mc68328->regs.lblkc; | |
| 2374 | } | |
| 2375 | else | |
| 2376 | { | |
| 2377 | verboselog(space.machine(), 2, "mc68328_r (%04x): Unknown address (0xfffa1e)\n", mem_mask); | |
| 2378 | } | |
| 2379 | break; | |
| 2380 | ||
| 2381 | case 0xa20: | |
| 2382 | if( mem_mask & 0x00ff ) | |
| 2383 | { | |
| 2384 | verboselog(space.machine(), 2, "mc68328_r (%04x): LPOLCF = %02x\n", mem_mask, mc68328->regs.lpolcf); | |
| 2385 | return mc68328->regs.lpolcf; | |
| 2386 | } | |
| 2387 | else | |
| 2388 | { | |
| 2389 | verboselog(space.machine(), 2, "mc68328_r (%04x): LPICF = %02x\n", mem_mask, mc68328->regs.lpicf); | |
| 2390 | return mc68328->regs.lpicf << 8; | |
| 2391 | } | |
| 2392 | break; | |
| 2393 | ||
| 2394 | case 0xa22: | |
| 2395 | if( mem_mask & 0x00ff ) | |
| 2396 | { | |
| 2397 | verboselog(space.machine(), 2, "mc68328_r (%04x): LACDRC = %02x\n", mem_mask, mc68328->regs.lacdrc); | |
| 2398 | return mc68328->regs.lacdrc; | |
| 2399 | } | |
| 2400 | else | |
| 2401 | { | |
| 2402 | verboselog(space.machine(), 2, "mc68328_r (%04x): Unknown address (0xfffa22)\n", mem_mask); | |
| 2403 | } | |
| 2404 | break; | |
| 2405 | ||
| 2406 | case 0xa24: | |
| 2407 | if( mem_mask & 0x00ff ) | |
| 2408 | { | |
| 2409 | verboselog(space.machine(), 2, "mc68328_r (%04x): LPXCD = %02x\n", mem_mask, mc68328->regs.lpxcd); | |
| 2410 | return mc68328->regs.lpxcd; | |
| 2411 | } | |
| 2412 | else | |
| 2413 | { | |
| 2414 | verboselog(space.machine(), 2, "mc68328_r (%04x): Unknown address (0xfffa24)\n", mem_mask); | |
| 2415 | } | |
| 2416 | break; | |
| 2417 | ||
| 2418 | case 0xa26: | |
| 2419 | if( mem_mask & 0x00ff ) | |
| 2420 | { | |
| 2421 | verboselog(space.machine(), 2, "mc68328_r (%04x): LCKCON = %02x\n", mem_mask, mc68328->regs.lckcon); | |
| 2422 | return mc68328->regs.lckcon; | |
| 2423 | } | |
| 2424 | else | |
| 2425 | { | |
| 2426 | verboselog(space.machine(), 2, "mc68328_r (%04x): Unknown address (0xfffa26)\n", mem_mask); | |
| 2427 | } | |
| 2428 | break; | |
| 2429 | ||
| 2430 | case 0xa28: | |
| 2431 | if( mem_mask & 0x00ff ) | |
| 2432 | { | |
| 2433 | verboselog(space.machine(), 2, "mc68328_r (%04x): LLBAR = %02x\n", mem_mask, mc68328->regs.llbar); | |
| 2434 | return mc68328->regs.llbar; | |
| 2435 | } | |
| 2436 | else | |
| 2437 | { | |
| 2438 | verboselog(space.machine(), 2, "mc68328_r (%04x): Unknown address (0xfffa28)\n", mem_mask); | |
| 2439 | } | |
| 2440 | break; | |
| 2441 | ||
| 2442 | case 0xa2a: | |
| 2443 | if( mem_mask & 0x00ff ) | |
| 2444 | { | |
| 2445 | verboselog(space.machine(), 2, "mc68328_r (%04x): LOTCR = %02x\n", mem_mask, mc68328->regs.lotcr); | |
| 2446 | return mc68328->regs.lotcr; | |
| 2447 | } | |
| 2448 | else | |
| 2449 | { | |
| 2450 | verboselog(space.machine(), 2, "mc68328_r (%04x): Unknown address (0xfffa2a)\n", mem_mask); | |
| 2451 | } | |
| 2452 | break; | |
| 2453 | ||
| 2454 | case 0xa2c: | |
| 2455 | if( mem_mask & 0x00ff ) | |
| 2456 | { | |
| 2457 | verboselog(space.machine(), 2, "mc68328_r (%04x): LPOSR = %02x\n", mem_mask, mc68328->regs.lposr); | |
| 2458 | return mc68328->regs.lposr; | |
| 2459 | } | |
| 2460 | else | |
| 2461 | { | |
| 2462 | verboselog(space.machine(), 2, "mc68328_r (%04x): Unknown address (0xfffa2c)\n", mem_mask); | |
| 2463 | } | |
| 2464 | break; | |
| 2465 | ||
| 2466 | case 0xa30: | |
| 2467 | if( mem_mask & 0x00ff ) | |
| 2468 | { | |
| 2469 | verboselog(space.machine(), 2, "mc68328_r (%04x): LFRCM = %02x\n", mem_mask, mc68328->regs.lfrcm); | |
| 2470 | return mc68328->regs.lfrcm; | |
| 2471 | } | |
| 2472 | else | |
| 2473 | { | |
| 2474 | verboselog(space.machine(), 2, "mc68328_r (%04x): Unknown address (0xfffa30)\n", mem_mask); | |
| 2475 | } | |
| 2476 | break; | |
| 2477 | ||
| 2478 | case 0xa32: | |
| 2479 | verboselog(space.machine(), 2, "mc68328_r (%04x): LGPMR = %04x\n", mem_mask, mc68328->regs.lgpmr); | |
| 2480 | return mc68328->regs.lgpmr; | |
| 2481 | ||
| 2482 | case 0xb00: | |
| 2483 | verboselog(space.machine(), 2, "mc68328_r (%04x): HMSR(0) = %04x\n", mem_mask, mc68328->regs.hmsr & 0x0000ffff); | |
| 2484 | return mc68328->regs.hmsr & 0x0000ffff; | |
| 2485 | ||
| 2486 | case 0xb02: | |
| 2487 | verboselog(space.machine(), 2, "mc68328_r (%04x): HMSR(16) = %04x\n", mem_mask, mc68328->regs.hmsr >> 16); | |
| 2488 | return mc68328->regs.hmsr >> 16; | |
| 2489 | ||
| 2490 | case 0xb04: | |
| 2491 | verboselog(space.machine(), 2, "mc68328_r (%04x): ALARM(0) = %04x\n", mem_mask, mc68328->regs.alarm & 0x0000ffff); | |
| 2492 | return mc68328->regs.alarm & 0x0000ffff; | |
| 2493 | ||
| 2494 | case 0xb06: | |
| 2495 | verboselog(space.machine(), 2, "mc68328_r (%04x): ALARM(16) = %04x\n", mem_mask, mc68328->regs.alarm >> 16); | |
| 2496 | return mc68328->regs.alarm >> 16; | |
| 2497 | ||
| 2498 | case 0xb0c: | |
| 2499 | verboselog(space.machine(), 2, "mc68328_r (%04x): RTCCTL = %04x\n", mem_mask, mc68328->regs.rtcctl); | |
| 2500 | return mc68328->regs.rtcctl; | |
| 2501 | ||
| 2502 | case 0xb0e: | |
| 2503 | verboselog(space.machine(), 2, "mc68328_r (%04x): RTCISR = %04x\n", mem_mask, mc68328->regs.rtcisr); | |
| 2504 | return mc68328->regs.rtcisr; | |
| 2505 | ||
| 2506 | case 0xb10: | |
| 2507 | verboselog(space.machine(), 2, "mc68328_r (%04x): RTCIENR = %04x\n", mem_mask, mc68328->regs.rtcienr); | |
| 2508 | return mc68328->regs.rtcienr; | |
| 2509 | ||
| 2510 | case 0xb12: | |
| 2511 | verboselog(space.machine(), 2, "mc68328_r (%04x): STPWTCH = %04x\n", mem_mask, mc68328->regs.stpwtch); | |
| 2512 | return mc68328->regs.stpwtch; | |
| 2513 | ||
| 2514 | default: | |
| 2515 | verboselog(space.machine(), 0, "mc68328_r (%04x): Unknown address (0x%06x)\n", mem_mask, 0xfff000 + address); | |
| 2516 | break; | |
| 2517 | } | |
| 2518 | return 0; | |
| 2519 | } | |
| 2520 | ||
| 2521 | static DEVICE_RESET( mc68328 ) | |
| 2522 | { | |
| 2523 | mc68328_t* mc68328 = mc68328_get_safe_token( device ); | |
| 2524 | ||
| 2525 | mc68328->regs.scr = 0x0c; | |
| 2526 | mc68328->regs.grpbasea = 0x0000; | |
| 2527 | mc68328->regs.grpbaseb = 0x0000; | |
| 2528 | mc68328->regs.grpbasec = 0x0000; | |
| 2529 | mc68328->regs.grpbased = 0x0000; | |
| 2530 | mc68328->regs.grpmaska = 0x0000; | |
| 2531 | mc68328->regs.grpmaskb = 0x0000; | |
| 2532 | mc68328->regs.grpmaskc = 0x0000; | |
| 2533 | mc68328->regs.grpmaskd = 0x0000; | |
| 2534 | mc68328->regs.csa0 = 0x00010006; | |
| 2535 | mc68328->regs.csa1 = 0x00010006; | |
| 2536 | mc68328->regs.csa2 = 0x00010006; | |
| 2537 | mc68328->regs.csa3 = 0x00010006; | |
| 2538 | mc68328->regs.csb0 = 0x00010006; | |
| 2539 | mc68328->regs.csb1 = 0x00010006; | |
| 2540 | mc68328->regs.csb2 = 0x00010006; | |
| 2541 | mc68328->regs.csb3 = 0x00010006; | |
| 2542 | mc68328->regs.csc0 = 0x00010006; | |
| 2543 | mc68328->regs.csc1 = 0x00010006; | |
| 2544 | mc68328->regs.csc2 = 0x00010006; | |
| 2545 | mc68328->regs.csc3 = 0x00010006; | |
| 2546 | mc68328->regs.csd0 = 0x00010006; | |
| 2547 | mc68328->regs.csd1 = 0x00010006; | |
| 2548 | mc68328->regs.csd2 = 0x00010006; | |
| 2549 | mc68328->regs.csd3 = 0x00010006; | |
| 2550 | ||
| 2551 | mc68328->regs.pllcr = 0x2400; | |
| 2552 | mc68328->regs.pllfsr = 0x0123; | |
| 2553 | mc68328->regs.pctlr = 0x1f; | |
| 2554 | ||
| 2555 | mc68328->regs.ivr = 0x00; | |
| 2556 | mc68328->regs.icr = 0x0000; | |
| 2557 | mc68328->regs.imr = 0x00ffffff; | |
| 2558 | mc68328->regs.iwr = 0x00ffffff; | |
| 2559 | mc68328->regs.isr = 0x00000000; | |
| 2560 | mc68328->regs.ipr = 0x00000000; | |
| 2561 | ||
| 2562 | mc68328->regs.padir = 0x00; | |
| 2563 | mc68328->regs.padata = 0x00; | |
| 2564 | mc68328->regs.pasel = 0x00; | |
| 2565 | mc68328->regs.pbdir = 0x00; | |
| 2566 | mc68328->regs.pbdata = 0x00; | |
| 2567 | mc68328->regs.pbsel = 0x00; | |
| 2568 | mc68328->regs.pcdir = 0x00; | |
| 2569 | mc68328->regs.pcdata = 0x00; | |
| 2570 | mc68328->regs.pcsel = 0x00; | |
| 2571 | mc68328->regs.pddir = 0x00; | |
| 2572 | mc68328->regs.pddata = 0x00; | |
| 2573 | mc68328->regs.pdpuen = 0xff; | |
| 2574 | mc68328->regs.pdpol = 0x00; | |
| 2575 | mc68328->regs.pdirqen = 0x00; | |
| 2576 | mc68328->regs.pddataedge = 0x00; | |
| 2577 | mc68328->regs.pdirqedge = 0x00; | |
| 2578 | mc68328->regs.pedir = 0x00; | |
| 2579 | mc68328->regs.pedata = 0x00; | |
| 2580 | mc68328->regs.pepuen = 0x80; | |
| 2581 | mc68328->regs.pesel = 0x80; | |
| 2582 | mc68328->regs.pfdir = 0x00; | |
| 2583 | mc68328->regs.pfdata = 0x00; | |
| 2584 | mc68328->regs.pfpuen = 0xff; | |
| 2585 | mc68328->regs.pfsel = 0xff; | |
| 2586 | mc68328->regs.pgdir = 0x00; | |
| 2587 | mc68328->regs.pgdata = 0x00; | |
| 2588 | mc68328->regs.pgpuen = 0xff; | |
| 2589 | mc68328->regs.pgsel = 0xff; | |
| 2590 | mc68328->regs.pjdir = 0x00; | |
| 2591 | mc68328->regs.pjdata = 0x00; | |
| 2592 | mc68328->regs.pjsel = 0x00; | |
| 2593 | mc68328->regs.pkdir = 0x00; | |
| 2594 | mc68328->regs.pkdata = 0x00; | |
| 2595 | mc68328->regs.pkpuen = 0xff; | |
| 2596 | mc68328->regs.pksel = 0xff; | |
| 2597 | mc68328->regs.pmdir = 0x00; | |
| 2598 | mc68328->regs.pmdata = 0x00; | |
| 2599 | mc68328->regs.pmpuen = 0xff; | |
| 2600 | mc68328->regs.pmsel = 0xff; | |
| 2601 | ||
| 2602 | mc68328->regs.pwmc = 0x0000; | |
| 2603 | mc68328->regs.pwmp = 0x0000; | |
| 2604 | mc68328->regs.pwmw = 0x0000; | |
| 2605 | mc68328->regs.pwmcnt = 0x0000; | |
| 2606 | ||
| 2607 | mc68328->regs.tctl[0] = mc68328->regs.tctl[1] = 0x0000; | |
| 2608 | mc68328->regs.tprer[0] = mc68328->regs.tprer[1] = 0x0000; | |
| 2609 | mc68328->regs.tcmp[0] = mc68328->regs.tcmp[1] = 0xffff; | |
| 2610 | mc68328->regs.tcr[0] = mc68328->regs.tcr[1] = 0x0000; | |
| 2611 | mc68328->regs.tcn[0] = mc68328->regs.tcn[1] = 0x0000; | |
| 2612 | mc68328->regs.tstat[0] = mc68328->regs.tstat[1] = 0x0000; | |
| 2613 | mc68328->regs.wctlr = 0x0000; | |
| 2614 | mc68328->regs.wcmpr = 0xffff; | |
| 2615 | mc68328->regs.wcn = 0x0000; | |
| 2616 | ||
| 2617 | mc68328->regs.spisr = 0x0000; | |
| 2618 | ||
| 2619 | mc68328->regs.spimdata = 0x0000; | |
| 2620 | mc68328->regs.spimcont = 0x0000; | |
| 2621 | ||
| 2622 | mc68328->regs.ustcnt = 0x0000; | |
| 2623 | mc68328->regs.ubaud = 0x003f; | |
| 2624 | mc68328->regs.urx = 0x0000; | |
| 2625 | mc68328->regs.utx = 0x0000; | |
| 2626 | mc68328->regs.umisc = 0x0000; | |
| 2627 | ||
| 2628 | mc68328->regs.lssa = 0x00000000; | |
| 2629 | mc68328->regs.lvpw = 0xff; | |
| 2630 | mc68328->regs.lxmax = 0x03ff; | |
| 2631 | mc68328->regs.lymax = 0x01ff; | |
| 2632 | mc68328->regs.lcxp = 0x0000; | |
| 2633 | mc68328->regs.lcyp = 0x0000; | |
| 2634 | mc68328->regs.lcwch = 0x0101; | |
| 2635 | mc68328->regs.lblkc = 0x7f; | |
| 2636 | mc68328->regs.lpicf = 0x00; | |
| 2637 | mc68328->regs.lpolcf = 0x00; | |
| 2638 | mc68328->regs.lacdrc = 0x00; | |
| 2639 | mc68328->regs.lpxcd = 0x00; | |
| 2640 | mc68328->regs.lckcon = 0x40; | |
| 2641 | mc68328->regs.llbar = 0x3e; | |
| 2642 | mc68328->regs.lotcr = 0x3f; | |
| 2643 | mc68328->regs.lposr = 0x00; | |
| 2644 | mc68328->regs.lfrcm = 0xb9; | |
| 2645 | mc68328->regs.lgpmr = 0x1073; | |
| 2646 | ||
| 2647 | mc68328->regs.hmsr = 0x00000000; | |
| 2648 | mc68328->regs.alarm = 0x00000000; | |
| 2649 | mc68328->regs.rtcctl = 0x00; | |
| 2650 | mc68328->regs.rtcisr = 0x00; | |
| 2651 | mc68328->regs.rtcienr = 0x00; | |
| 2652 | mc68328->regs.stpwtch = 0x00; | |
| 2653 | ||
| 2654 | mc68328->rtc->adjust(attotime::from_hz(1), 0, attotime::from_hz(1)); | |
| 2655 | } | |
| 2656 | ||
| 2657 | static void mc68328_register_state_save(device_t *device) | |
| 2658 | { | |
| 2659 | mc68328_t* mc68328 = mc68328_get_safe_token( device ); | |
| 2660 | ||
| 2661 | state_save_register_global(device->machine(), mc68328->regs.scr); | |
| 2662 | state_save_register_global(device->machine(), mc68328->regs.grpbasea); | |
| 2663 | state_save_register_global(device->machine(), mc68328->regs.grpbaseb); | |
| 2664 | state_save_register_global(device->machine(), mc68328->regs.grpbasec); | |
| 2665 | state_save_register_global(device->machine(), mc68328->regs.grpbased); | |
| 2666 | state_save_register_global(device->machine(), mc68328->regs.grpmaska); | |
| 2667 | state_save_register_global(device->machine(), mc68328->regs.grpmaskb); | |
| 2668 | state_save_register_global(device->machine(), mc68328->regs.grpmaskc); | |
| 2669 | state_save_register_global(device->machine(), mc68328->regs.grpmaskd); | |
| 2670 | state_save_register_global(device->machine(), mc68328->regs.csa0); | |
| 2671 | state_save_register_global(device->machine(), mc68328->regs.csa1); | |
| 2672 | state_save_register_global(device->machine(), mc68328->regs.csa2); | |
| 2673 | state_save_register_global(device->machine(), mc68328->regs.csa3); | |
| 2674 | state_save_register_global(device->machine(), mc68328->regs.csb0); | |
| 2675 | state_save_register_global(device->machine(), mc68328->regs.csb1); | |
| 2676 | state_save_register_global(device->machine(), mc68328->regs.csb2); | |
| 2677 | state_save_register_global(device->machine(), mc68328->regs.csb3); | |
| 2678 | state_save_register_global(device->machine(), mc68328->regs.csc0); | |
| 2679 | state_save_register_global(device->machine(), mc68328->regs.csc1); | |
| 2680 | state_save_register_global(device->machine(), mc68328->regs.csc2); | |
| 2681 | state_save_register_global(device->machine(), mc68328->regs.csc3); | |
| 2682 | state_save_register_global(device->machine(), mc68328->regs.csd0); | |
| 2683 | state_save_register_global(device->machine(), mc68328->regs.csd1); | |
| 2684 | state_save_register_global(device->machine(), mc68328->regs.csd2); | |
| 2685 | state_save_register_global(device->machine(), mc68328->regs.csd3); | |
| 2686 | ||
| 2687 | state_save_register_global(device->machine(), mc68328->regs.pllcr); | |
| 2688 | state_save_register_global(device->machine(), mc68328->regs.pllfsr); | |
| 2689 | state_save_register_global(device->machine(), mc68328->regs.pctlr); | |
| 2690 | ||
| 2691 | state_save_register_global(device->machine(), mc68328->regs.ivr); | |
| 2692 | state_save_register_global(device->machine(), mc68328->regs.icr); | |
| 2693 | state_save_register_global(device->machine(), mc68328->regs.imr); | |
| 2694 | state_save_register_global(device->machine(), mc68328->regs.iwr); | |
| 2695 | state_save_register_global(device->machine(), mc68328->regs.isr); | |
| 2696 | state_save_register_global(device->machine(), mc68328->regs.ipr); | |
| 2697 | ||
| 2698 | state_save_register_global(device->machine(), mc68328->regs.padir); | |
| 2699 | state_save_register_global(device->machine(), mc68328->regs.padata); | |
| 2700 | state_save_register_global(device->machine(), mc68328->regs.pasel); | |
| 2701 | state_save_register_global(device->machine(), mc68328->regs.pbdir); | |
| 2702 | state_save_register_global(device->machine(), mc68328->regs.pbdata); | |
| 2703 | state_save_register_global(device->machine(), mc68328->regs.pbsel); | |
| 2704 | state_save_register_global(device->machine(), mc68328->regs.pcdir); | |
| 2705 | state_save_register_global(device->machine(), mc68328->regs.pcdata); | |
| 2706 | state_save_register_global(device->machine(), mc68328->regs.pcsel); | |
| 2707 | state_save_register_global(device->machine(), mc68328->regs.pddir); | |
| 2708 | state_save_register_global(device->machine(), mc68328->regs.pddata); | |
| 2709 | state_save_register_global(device->machine(), mc68328->regs.pdpuen); | |
| 2710 | state_save_register_global(device->machine(), mc68328->regs.pdpol); | |
| 2711 | state_save_register_global(device->machine(), mc68328->regs.pdirqen); | |
| 2712 | state_save_register_global(device->machine(), mc68328->regs.pddataedge); | |
| 2713 | state_save_register_global(device->machine(), mc68328->regs.pdirqedge); | |
| 2714 | state_save_register_global(device->machine(), mc68328->regs.pedir); | |
| 2715 | state_save_register_global(device->machine(), mc68328->regs.pedata); | |
| 2716 | state_save_register_global(device->machine(), mc68328->regs.pepuen); | |
| 2717 | state_save_register_global(device->machine(), mc68328->regs.pesel); | |
| 2718 | state_save_register_global(device->machine(), mc68328->regs.pfdir); | |
| 2719 | state_save_register_global(device->machine(), mc68328->regs.pfdata); | |
| 2720 | state_save_register_global(device->machine(), mc68328->regs.pfpuen); | |
| 2721 | state_save_register_global(device->machine(), mc68328->regs.pfsel); | |
| 2722 | state_save_register_global(device->machine(), mc68328->regs.pgdir); | |
| 2723 | state_save_register_global(device->machine(), mc68328->regs.pgdata); | |
| 2724 | state_save_register_global(device->machine(), mc68328->regs.pgpuen); | |
| 2725 | state_save_register_global(device->machine(), mc68328->regs.pgsel); | |
| 2726 | state_save_register_global(device->machine(), mc68328->regs.pjdir); | |
| 2727 | state_save_register_global(device->machine(), mc68328->regs.pjdata); | |
| 2728 | state_save_register_global(device->machine(), mc68328->regs.pjsel); | |
| 2729 | state_save_register_global(device->machine(), mc68328->regs.pkdir); | |
| 2730 | state_save_register_global(device->machine(), mc68328->regs.pkdata); | |
| 2731 | state_save_register_global(device->machine(), mc68328->regs.pkpuen); | |
| 2732 | state_save_register_global(device->machine(), mc68328->regs.pksel); | |
| 2733 | state_save_register_global(device->machine(), mc68328->regs.pmdir); | |
| 2734 | state_save_register_global(device->machine(), mc68328->regs.pmdata); | |
| 2735 | state_save_register_global(device->machine(), mc68328->regs.pmpuen); | |
| 2736 | state_save_register_global(device->machine(), mc68328->regs.pmsel); | |
| 2737 | ||
| 2738 | state_save_register_global(device->machine(), mc68328->regs.pwmc); | |
| 2739 | state_save_register_global(device->machine(), mc68328->regs.pwmp); | |
| 2740 | state_save_register_global(device->machine(), mc68328->regs.pwmw); | |
| 2741 | state_save_register_global(device->machine(), mc68328->regs.pwmcnt); | |
| 2742 | ||
| 2743 | state_save_register_global(device->machine(), mc68328->regs.tctl[0]); | |
| 2744 | state_save_register_global(device->machine(), mc68328->regs.tctl[1]); | |
| 2745 | state_save_register_global(device->machine(), mc68328->regs.tprer[0]); | |
| 2746 | state_save_register_global(device->machine(), mc68328->regs.tprer[1]); | |
| 2747 | state_save_register_global(device->machine(), mc68328->regs.tcmp[0]); | |
| 2748 | state_save_register_global(device->machine(), mc68328->regs.tcmp[1]); | |
| 2749 | state_save_register_global(device->machine(), mc68328->regs.tcr[0]); | |
| 2750 | state_save_register_global(device->machine(), mc68328->regs.tcr[1]); | |
| 2751 | state_save_register_global(device->machine(), mc68328->regs.tcn[0]); | |
| 2752 | state_save_register_global(device->machine(), mc68328->regs.tcn[1]); | |
| 2753 | state_save_register_global(device->machine(), mc68328->regs.tstat[0]); | |
| 2754 | state_save_register_global(device->machine(), mc68328->regs.tstat[1]); | |
| 2755 | state_save_register_global(device->machine(), mc68328->regs.wctlr); | |
| 2756 | state_save_register_global(device->machine(), mc68328->regs.wcmpr); | |
| 2757 | state_save_register_global(device->machine(), mc68328->regs.wcn); | |
| 2758 | ||
| 2759 | state_save_register_global(device->machine(), mc68328->regs.spisr); | |
| 2760 | ||
| 2761 | state_save_register_global(device->machine(), mc68328->regs.spimdata); | |
| 2762 | state_save_register_global(device->machine(), mc68328->regs.spimcont); | |
| 2763 | ||
| 2764 | state_save_register_global(device->machine(), mc68328->regs.ustcnt); | |
| 2765 | state_save_register_global(device->machine(), mc68328->regs.ubaud); | |
| 2766 | state_save_register_global(device->machine(), mc68328->regs.urx); | |
| 2767 | state_save_register_global(device->machine(), mc68328->regs.utx); | |
| 2768 | state_save_register_global(device->machine(), mc68328->regs.umisc); | |
| 2769 | ||
| 2770 | state_save_register_global(device->machine(), mc68328->regs.lssa); | |
| 2771 | state_save_register_global(device->machine(), mc68328->regs.lvpw); | |
| 2772 | state_save_register_global(device->machine(), mc68328->regs.lxmax); | |
| 2773 | state_save_register_global(device->machine(), mc68328->regs.lymax); | |
| 2774 | state_save_register_global(device->machine(), mc68328->regs.lcxp); | |
| 2775 | state_save_register_global(device->machine(), mc68328->regs.lcyp); | |
| 2776 | state_save_register_global(device->machine(), mc68328->regs.lcwch); | |
| 2777 | state_save_register_global(device->machine(), mc68328->regs.lblkc); | |
| 2778 | state_save_register_global(device->machine(), mc68328->regs.lpicf); | |
| 2779 | state_save_register_global(device->machine(), mc68328->regs.lpolcf); | |
| 2780 | state_save_register_global(device->machine(), mc68328->regs.lacdrc); | |
| 2781 | state_save_register_global(device->machine(), mc68328->regs.lpxcd); | |
| 2782 | state_save_register_global(device->machine(), mc68328->regs.lckcon); | |
| 2783 | state_save_register_global(device->machine(), mc68328->regs.llbar); | |
| 2784 | state_save_register_global(device->machine(), mc68328->regs.lotcr); | |
| 2785 | state_save_register_global(device->machine(), mc68328->regs.lposr); | |
| 2786 | state_save_register_global(device->machine(), mc68328->regs.lfrcm); | |
| 2787 | state_save_register_global(device->machine(), mc68328->regs.lgpmr); | |
| 2788 | ||
| 2789 | state_save_register_global(device->machine(), mc68328->regs.hmsr); | |
| 2790 | state_save_register_global(device->machine(), mc68328->regs.alarm); | |
| 2791 | state_save_register_global(device->machine(), mc68328->regs.rtcctl); | |
| 2792 | state_save_register_global(device->machine(), mc68328->regs.rtcisr); | |
| 2793 | state_save_register_global(device->machine(), mc68328->regs.rtcienr); | |
| 2794 | state_save_register_global(device->machine(), mc68328->regs.stpwtch); | |
| 2795 | } | |
| 2796 | ||
| 2797 | static DEVICE_START( mc68328 ) | |
| 2798 | { | |
| 2799 | mc68328_t* mc68328 = mc68328_get_safe_token( device ); | |
| 2800 | ||
| 2801 | mc68328->iface = (const mc68328_interface*)device->static_config(); | |
| 2802 | ||
| 2803 | mc68328->out_port_a.resolve(mc68328->iface->out_port_a_func, *device); | |
| 2804 | mc68328->out_port_b.resolve(mc68328->iface->out_port_b_func, *device); | |
| 2805 | mc68328->out_port_c.resolve(mc68328->iface->out_port_c_func, *device); | |
| 2806 | mc68328->out_port_d.resolve(mc68328->iface->out_port_d_func, *device); | |
| 2807 | mc68328->out_port_e.resolve(mc68328->iface->out_port_e_func, *device); | |
| 2808 | mc68328->out_port_f.resolve(mc68328->iface->out_port_f_func, *device); | |
| 2809 | mc68328->out_port_g.resolve(mc68328->iface->out_port_g_func, *device); | |
| 2810 | mc68328->out_port_j.resolve(mc68328->iface->out_port_j_func, *device); | |
| 2811 | mc68328->out_port_k.resolve(mc68328->iface->out_port_k_func, *device); | |
| 2812 | mc68328->out_port_m.resolve(mc68328->iface->out_port_m_func, *device); | |
| 2813 | ||
| 2814 | mc68328->in_port_a.resolve(mc68328->iface->in_port_a_func, *device); | |
| 2815 | mc68328->in_port_b.resolve(mc68328->iface->in_port_b_func, *device); | |
| 2816 | mc68328->in_port_c.resolve(mc68328->iface->in_port_c_func, *device); | |
| 2817 | mc68328->in_port_d.resolve(mc68328->iface->in_port_d_func, *device); | |
| 2818 | mc68328->in_port_e.resolve(mc68328->iface->in_port_e_func, *device); | |
| 2819 | mc68328->in_port_f.resolve(mc68328->iface->in_port_f_func, *device); | |
| 2820 | mc68328->in_port_g.resolve(mc68328->iface->in_port_g_func, *device); | |
| 2821 | mc68328->in_port_j.resolve(mc68328->iface->in_port_j_func, *device); | |
| 2822 | mc68328->in_port_k.resolve(mc68328->iface->in_port_k_func, *device); | |
| 2823 | mc68328->in_port_m.resolve(mc68328->iface->in_port_m_func, *device); | |
| 2824 | ||
| 2825 | mc68328->out_pwm.resolve(mc68328->iface->out_pwm_func, *device); | |
| 2826 | ||
| 2827 | mc68328->out_spim.resolve(mc68328->iface->out_spim_func, *device); | |
| 2828 | mc68328->in_spim.resolve(mc68328->iface->in_spim_func, *device); | |
| 2829 | ||
| 2830 | mc68328->gptimer[0] = device->machine().scheduler().timer_alloc(FUNC(mc68328_timer1_hit)); | |
| 2831 | mc68328->gptimer[1] = device->machine().scheduler().timer_alloc(FUNC(mc68328_timer2_hit)); | |
| 2832 | mc68328->rtc = device->machine().scheduler().timer_alloc(FUNC(mc68328_rtc_tick)); | |
| 2833 | mc68328->pwm = device->machine().scheduler().timer_alloc(FUNC(mc68328_pwm_transition)); | |
| 2834 | ||
| 2835 | mc68328_register_state_save(device); | |
| 2836 | } | |
| 2837 | ||
| 2838 | const device_type MC68328 = &device_creator<mc68328_device>; | |
| 2839 | ||
| 2840 | mc68328_device::mc68328_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) | |
| 2841 | : device_t(mconfig, MC68328, "Motorola MC68328 (DragonBall) Integrated Processor", tag, owner, clock) | |
| 2842 | { | |
| 2843 | m_token = global_alloc_clear(mc68328_t); | |
| 2844 | } | |
| 2845 | ||
| 2846 | //------------------------------------------------- | |
| 2847 | // device_config_complete - perform any | |
| 2848 | // operations now that the configuration is | |
| 2849 | // complete | |
| 2850 | //------------------------------------------------- | |
| 2851 | ||
| 2852 | void mc68328_device::device_config_complete() | |
| 2853 | { | |
| 2854 | } | |
| 2855 | ||
| 2856 | //------------------------------------------------- | |
| 2857 | // device_start - device-specific startup | |
| 2858 | //------------------------------------------------- | |
| 2859 | ||
| 2860 | void mc68328_device::device_start() | |
| 2861 | { | |
| 2862 | DEVICE_START_NAME( mc68328 )(this); | |
| 2863 | } | |
| 2864 | ||
| 2865 | //------------------------------------------------- | |
| 2866 | // device_reset - device-specific reset | |
| 2867 | //------------------------------------------------- | |
| 2868 | ||
| 2869 | void mc68328_device::device_reset() | |
| 2870 | { | |
| 2871 | DEVICE_RESET_NAME( mc68328 )(this); | |
| 2872 | } |
| r21684 | r21685 | |
|---|---|---|
| 1 | /********************************************************************** | |
| 2 | ||
| 3 | Motorola 68328 ("DragonBall") System-on-a-Chip private data | |
| 4 | ||
| 5 | By MooglyGuy | |
| 6 | contact mooglyguy@gmail.com with licensing and usage questions. | |
| 7 | ||
| 8 | **********************************************************************/ | |
| 9 | ||
| 10 | #ifndef __MC68328_PRIVATE_H_ | |
| 11 | #define __MC68328_PRIVATE_H_ | |
| 12 | ||
| 13 | struct mc68328_regs_t | |
| 14 | { | |
| 15 | // $(FF)FFF000 | |
| 16 | UINT8 scr; // System Control Register | |
| 17 | UINT8 unused0[255]; | |
| 18 | ||
| 19 | // $(FF)FFF100 | |
| 20 | UINT16 grpbasea; // Chip Select Group A Base Register | |
| 21 | UINT16 grpbaseb; // Chip Select Group B Base Register | |
| 22 | UINT16 grpbasec; // Chip Select Group C Base Register | |
| 23 | UINT16 grpbased; // Chip Select Group D Base Register | |
| 24 | UINT16 grpmaska; // Chip Select Group A Mask Register | |
| 25 | UINT16 grpmaskb; // Chip Select Group B Mask Register | |
| 26 | UINT16 grpmaskc; // Chip Select Group C Mask Register | |
| 27 | UINT16 grpmaskd; // Chip Select Group D Mask Register | |
| 28 | UINT32 csa0; // Group A Chip Select 0 Register | |
| 29 | UINT32 csa1; // Group A Chip Select 1 Register | |
| 30 | UINT32 csa2; // Group A Chip Select 2 Register | |
| 31 | UINT32 csa3; // Group A Chip Select 3 Register | |
| 32 | UINT32 csb0; // Group B Chip Select 0 Register | |
| 33 | UINT32 csb1; // Group B Chip Select 1 Register | |
| 34 | UINT32 csb2; // Group B Chip Select 2 Register | |
| 35 | UINT32 csb3; // Group B Chip Select 3 Register | |
| 36 | UINT32 csc0; // Group C Chip Select 0 Register | |
| 37 | UINT32 csc1; // Group C Chip Select 1 Register | |
| 38 | UINT32 csc2; // Group C Chip Select 2 Register | |
| 39 | UINT32 csc3; // Group C Chip Select 3 Register | |
| 40 | UINT32 csd0; // Group D Chip Select 0 Register | |
| 41 | UINT32 csd1; // Group D Chip Select 1 Register | |
| 42 | UINT32 csd2; // Group D Chip Select 2 Register | |
| 43 | UINT32 csd3; // Group D Chip Select 3 Register | |
| 44 | UINT8 unused1[176]; | |
| 45 | ||
| 46 | // $(FF)FFF200 | |
| 47 | UINT16 pllcr; // PLL Control Register | |
| 48 | UINT16 pllfsr; // PLL Frequency Select Register | |
| 49 | UINT8 pad2[3]; | |
| 50 | UINT8 pctlr; // Power Control Register | |
| 51 | UINT8 unused3[248]; | |
| 52 | ||
| 53 | // $(FF)FFF300 | |
| 54 | UINT8 ivr; // Interrupt Vector Register | |
| 55 | UINT8 unused4[1]; | |
| 56 | UINT16 icr; // Interrupt Control Register | |
| 57 | UINT32 imr; // Interrupt Mask Register | |
| 58 | UINT32 iwr; // Interrupt Wakeup Enable Register | |
| 59 | UINT32 isr; // Interrupt Status Register | |
| 60 | UINT32 ipr; // Interrupt Pending Register | |
| 61 | UINT8 unused5[236]; | |
| 62 | ||
| 63 | // $(FF)FFF400 | |
| 64 | UINT8 padir; // Port A Direction Register | |
| 65 | UINT8 padata; // Port A Data Register | |
| 66 | UINT8 unused6[1]; | |
| 67 | UINT8 pasel; // Port A Select Register | |
| 68 | UINT8 unused7[4]; | |
| 69 | ||
| 70 | UINT8 pbdir; // Port B Direction Register | |
| 71 | UINT8 pbdata; // Port B Data Register | |
| 72 | UINT8 unused8[1]; | |
| 73 | UINT8 pbsel; // Port B Select Register | |
| 74 | UINT8 unused9[4]; | |
| 75 | ||
| 76 | UINT8 pcdir; // Port C Direction Register | |
| 77 | UINT8 pcdata; // Port C Data Register | |
| 78 | UINT8 unused10[1]; | |
| 79 | UINT8 pcsel; // Port C Select Register | |
| 80 | UINT8 unused11[4]; | |
| 81 | ||
| 82 | UINT8 pddir; // Port D Direction Register | |
| 83 | UINT8 pddata; // Port D Data Register | |
| 84 | UINT8 pdpuen; // Port D Pullup Enable Register | |
| 85 | UINT8 unused12[1]; | |
| 86 | UINT8 pdpol; // Port D Polarity Register | |
| 87 | UINT8 pdirqen; // Port D IRQ Enable Register | |
| 88 | UINT8 pddataedge; // Port D Data Edge Level | |
| 89 | UINT8 pdirqedge; // Port D IRQ Edge Register | |
| 90 | ||
| 91 | UINT8 pedir; // Port E Direction Register | |
| 92 | UINT8 pedata; // Port E Data Register | |
| 93 | UINT8 pepuen; // Port E Pullup Enable Register | |
| 94 | UINT8 pesel; // Port E Select Register | |
| 95 | UINT8 unused14[4]; | |
| 96 | ||
| 97 | UINT8 pfdir; // Port F Direction Register | |
| 98 | UINT8 pfdata; // Port F Data Register | |
| 99 | UINT8 pfpuen; // Port F Pullup Enable Register | |
| 100 | UINT8 pfsel; // Port F Select Register | |
| 101 | UINT8 unused15[4]; | |
| 102 | ||
| 103 | UINT8 pgdir; // Port G Direction Register | |
| 104 | UINT8 pgdata; // Port G Data Register | |
| 105 | UINT8 pgpuen; // Port G Pullup Enable Register | |
| 106 | UINT8 pgsel; // Port G Select Register | |
| 107 | UINT8 unused16[4]; | |
| 108 | ||
| 109 | UINT8 pjdir; // Port J Direction Register | |
| 110 | UINT8 pjdata; // Port J Data Register | |
| 111 | UINT8 unused17[1]; | |
| 112 | UINT8 pjsel; // Port J Select Register | |
| 113 | UINT8 unused18[4]; | |
| 114 | UINT8 pkdir; // Port K Direction Register | |
| 115 | UINT8 pkdata; // Port K Data Register | |
| 116 | UINT8 pkpuen; // Port K Pullup Enable Register | |
| 117 | UINT8 pksel; // Port K Select Register | |
| 118 | UINT8 unused19[4]; | |
| 119 | ||
| 120 | UINT8 pmdir; // Port M Direction Register | |
| 121 | UINT8 pmdata; // Port M Data Register | |
| 122 | UINT8 pmpuen; // Port M Pullup Enable Register | |
| 123 | UINT8 pmsel; // Port M Select Register | |
| 124 | UINT8 unused20[180]; | |
| 125 | ||
| 126 | // $(FF)FFF500 | |
| 127 | UINT16 pwmc; // PWM Control Register | |
| 128 | UINT16 pwmp; // PWM Period Register | |
| 129 | UINT16 pwmw; // PWM Width Register | |
| 130 | UINT16 pwmcnt; // PWN Counter | |
| 131 | UINT8 unused21[248]; | |
| 132 | ||
| 133 | // $(FF)FFF600 | |
| 134 | UINT16 tctl[2]; // Timer Control Register | |
| 135 | UINT16 tprer[2]; // Timer Prescaler Register | |
| 136 | UINT16 tcmp[2]; // Timer Compare Register | |
| 137 | UINT16 tcr[2]; // Timer Capture Register | |
| 138 | UINT16 tcn[2]; // Timer Counter | |
| 139 | UINT16 tstat[2]; // Timer Status | |
| 140 | UINT16 wctlr; // Watchdog Control Register | |
| 141 | UINT16 wcmpr; // Watchdog Compare Register | |
| 142 | UINT16 wcn; // Watchdog Counter | |
| 143 | UINT8 tclear[2]; // Timer Clearable Status | |
| 144 | UINT8 unused22[224]; | |
| 145 | ||
| 146 | // $(FF)FFF700 | |
| 147 | UINT16 spisr; // SPIS Register | |
| 148 | UINT8 unused23[254]; | |
| 149 | ||
| 150 | // $(FF)FFF800 | |
| 151 | UINT16 spimdata; // SPIM Data Register | |
| 152 | UINT16 spimcont; // SPIM Control/Status Register | |
| 153 | UINT8 unused24[252]; | |
| 154 | ||
| 155 | // $(FF)FFF900 | |
| 156 | UINT16 ustcnt; // UART Status/Control Register | |
| 157 | UINT16 ubaud; // UART Baud Control Register | |
| 158 | UINT16 urx; // UART RX Register | |
| 159 | UINT16 utx; // UART TX Register | |
| 160 | UINT16 umisc; // UART Misc Register | |
| 161 | UINT8 unused25[246]; | |
| 162 | ||
| 163 | // $(FF)FFFA00 | |
| 164 | UINT32 lssa; // Screen Starting Address Register | |
| 165 | UINT8 unused26[1]; | |
| 166 | UINT8 lvpw; // Virtual Page Width Register | |
| 167 | UINT8 unused27[2]; | |
| 168 | UINT16 lxmax; // Screen Width Register | |
| 169 | UINT16 lymax; // Screen Height Register | |
| 170 | UINT8 unused28[12]; | |
| 171 | UINT16 lcxp; // Cursor X Position | |
| 172 | UINT16 lcyp; // Cursor Y Position | |
| 173 | UINT16 lcwch; // Cursor Width & Height Register | |
| 174 | UINT8 unused29[1]; | |
| 175 | UINT8 lblkc; // Blink Control Register | |
| 176 | UINT8 lpicf; // Panel Interface Config Register | |
| 177 | UINT8 lpolcf; // Polarity Config Register | |
| 178 | UINT8 unused30[1]; | |
| 179 | UINT8 lacdrc; // ACD (M) Rate Control Register | |
| 180 | UINT8 unused31[1]; | |
| 181 | UINT8 lpxcd; // Pixel Clock Divider Register | |
| 182 | UINT8 unused32[1]; | |
| 183 | UINT8 lckcon; // Clocking Control Register | |
| 184 | UINT8 unused33[1]; | |
| 185 | UINT8 llbar; // Last Buffer Address Register | |
| 186 | UINT8 unused34[1]; | |
| 187 | UINT8 lotcr; // Octet Terminal Count Register | |
| 188 | UINT8 unused35[1]; | |
| 189 | UINT8 lposr; // Panning Offset Register | |
| 190 | UINT8 unused36[3]; | |
| 191 | UINT8 lfrcm; // Frame Rate Control Modulation Register | |
| 192 | UINT16 lgpmr; // Gray Palette Mapping Register | |
| 193 | UINT8 unused37[204]; | |
| 194 | ||
| 195 | // $(FF)FFFB00 | |
| 196 | UINT32 hmsr; // RTC Hours Minutes Seconds Register | |
| 197 | UINT32 alarm; // RTC Alarm Register | |
| 198 | UINT8 unused38[4]; | |
| 199 | UINT16 rtcctl; // RTC Control Register | |
| 200 | UINT16 rtcisr; // RTC Interrupt Status Register | |
| 201 | UINT16 rtcienr; // RTC Interrupt Enable Register | |
| 202 | UINT16 stpwtch; // Stopwatch Minutes | |
| 203 | UINT8 unused42[1260]; | |
| 204 | }; | |
| 205 | ||
| 206 | struct mc68328_t | |
| 207 | { | |
| 208 | const mc68328_interface* iface; | |
| 209 | ||
| 210 | mc68328_regs_t regs; | |
| 211 | ||
| 212 | emu_timer *gptimer[2]; | |
| 213 | emu_timer *rtc; | |
| 214 | emu_timer *pwm; | |
| 215 | ||
| 216 | devcb_resolved_write8 out_port_a; /* 8-bit output */ | |
| 217 | devcb_resolved_write8 out_port_b; /* 8-bit output */ | |
| 218 | devcb_resolved_write8 out_port_c; /* 8-bit output */ | |
| 219 | devcb_resolved_write8 out_port_d; /* 8-bit output */ | |
| 220 | devcb_resolved_write8 out_port_e; /* 8-bit output */ | |
| 221 | devcb_resolved_write8 out_port_f; /* 8-bit output */ | |
| 222 | devcb_resolved_write8 out_port_g; /* 8-bit output */ | |
| 223 | devcb_resolved_write8 out_port_j; /* 8-bit output */ | |
| 224 | devcb_resolved_write8 out_port_k; /* 8-bit output */ | |
| 225 | devcb_resolved_write8 out_port_m; /* 8-bit output */ | |
| 226 | ||
| 227 | devcb_resolved_read8 in_port_a; /* 8-bit input */ | |
| 228 | devcb_resolved_read8 in_port_b; /* 8-bit input */ | |
| 229 | devcb_resolved_read8 in_port_c; /* 8-bit input */ | |
| 230 | devcb_resolved_read8 in_port_d; /* 8-bit input */ | |
| 231 | devcb_resolved_read8 in_port_e; /* 8-bit input */ | |
| 232 | devcb_resolved_read8 in_port_f; /* 8-bit input */ | |
| 233 | devcb_resolved_read8 in_port_g; /* 8-bit input */ | |
| 234 | devcb_resolved_read8 in_port_j; /* 8-bit input */ | |
| 235 | devcb_resolved_read8 in_port_k; /* 8-bit input */ | |
| 236 | devcb_resolved_read8 in_port_m; /* 8-bit input */ | |
| 237 | ||
| 238 | devcb_resolved_write8 out_pwm; /* 1-bit output */ | |
| 239 | ||
| 240 | devcb_resolved_write16 out_spim; /* 16-bit output */ | |
| 241 | devcb_resolved_read16 in_spim; /* 16-bit input */ | |
| 242 | }; | |
| 243 | ||
| 244 | #define SCR_BETO 0x80 | |
| 245 | #define SCR_WPV 0x40 | |
| 246 | #define SCR_PRV 0x20 | |
| 247 | #define SCR_BETEN 0x10 | |
| 248 | #define SCR_SO 0x08 | |
| 249 | #define SCR_DMAP 0x04 | |
| 250 | #define SCR_WDTH8 0x01 | |
| 251 | ||
| 252 | #define ICR_POL6 0x0100 | |
| 253 | #define ICR_POL3 0x0200 | |
| 254 | #define ICR_POL2 0x0400 | |
| 255 | #define ICR_POL1 0x0800 | |
| 256 | #define ICR_ET6 0x1000 | |
| 257 | #define ICR_ET3 0x2000 | |
| 258 | #define ICR_ET2 0x4000 | |
| 259 | #define ICR_ET1 0x8000 | |
| 260 | ||
| 261 | #define INT_SPIM 0x000001 | |
| 262 | #define INT_TIMER2 0x000002 | |
| 263 | #define INT_UART 0x000004 | |
| 264 | #define INT_WDT 0x000008 | |
| 265 | #define INT_RTC 0x000010 | |
| 266 | #define INT_RESERVED 0x000020 | |
| 267 | #define INT_KB 0x000040 | |
| 268 | #define INT_PWM 0x000080 | |
| 269 | #define INT_INT0 0x000100 | |
| 270 | #define INT_INT1 0x000200 | |
| 271 | #define INT_INT2 0x000400 | |
| 272 | #define INT_INT3 0x000800 | |
| 273 | #define INT_INT4 0x001000 | |
| 274 | #define INT_INT5 0x002000 | |
| 275 | #define INT_INT6 0x004000 | |
| 276 | #define INT_INT7 0x008000 | |
| 277 | #define INT_KBDINTS 0x00ff00 | |
| 278 | #define INT_IRQ1 0x010000 | |
| 279 | #define INT_IRQ2 0x020000 | |
| 280 | #define INT_IRQ3 0x040000 | |
| 281 | #define INT_IRQ6 0x080000 | |
| 282 | #define INT_PEN 0x100000 | |
| 283 | #define INT_SPIS 0x200000 | |
| 284 | #define INT_TIMER1 0x400000 | |
| 285 | #define INT_IRQ7 0x800000 | |
| 286 | ||
| 287 | #define INT_M68K_LINE1 (INT_IRQ1) | |
| 288 | #define INT_M68K_LINE2 (INT_IRQ2) | |
| 289 | #define INT_M68K_LINE3 (INT_IRQ3) | |
| 290 | #define INT_M68K_LINE4 (INT_INT0 | INT_INT1 | INT_INT2 | INT_INT3 | INT_INT4 | INT_INT5 | INT_INT6 | INT_INT7 | \ | |
| 291 | INT_PWM | INT_KB | INT_RTC | INT_WDT | INT_UART | INT_TIMER2 | INT_SPIM) | |
| 292 | #define INT_M68K_LINE5 (INT_PEN) | |
| 293 | #define INT_M68K_LINE6 (INT_IRQ6 | INT_TIMER1 | INT_SPIS) | |
| 294 | #define INT_M68K_LINE7 (INT_IRQ7) | |
| 295 | #define INT_M68K_LINE67 (INT_M68K_LINE6 | INT_M68K_LINE7) | |
| 296 | #define INT_M68K_LINE567 (INT_M68K_LINE5 | INT_M68K_LINE6 | INT_M68K_LINE7) | |
| 297 | #define INT_M68K_LINE4567 (INT_M68K_LINE4 | INT_M68K_LINE5 | INT_M68K_LINE6 | INT_M68K_LINE7) | |
| 298 | #define INT_M68K_LINE34567 (INT_M68K_LINE3 | INT_M68K_LINE4 | INT_M68K_LINE5 | INT_M68K_LINE6 | INT_M68K_LINE7) | |
| 299 | #define INT_M68K_LINE234567 (INT_M68K_LINE2 | INT_M68K_LINE3 | INT_M68K_LINE4 | INT_M68K_LINE5 | INT_M68K_LINE6 | INT_M68K_LINE7) | |
| 300 | ||
| 301 | #define INT_IRQ1_SHIFT 0x000001 | |
| 302 | #define INT_IRQ2_SHIFT 0x000002 | |
| 303 | #define INT_IRQ3_SHIFT 0x000004 | |
| 304 | #define INT_IRQ6_SHIFT 0x000008 | |
| 305 | #define INT_PEN_SHIFT 0x000010 | |
| 306 | #define INT_SPIS_SHIFT 0x000020 | |
| 307 | #define INT_TIMER1_SHIFT 0x000040 | |
| 308 | #define INT_IRQ7_SHIFT 0x000080 | |
| 309 | ||
| 310 | #define INT_ACTIVE 1 | |
| 311 | #define INT_INACTIVE 0 | |
| 312 | ||
| 313 | #define GRPBASE_BASE_ADDR 0xfff0 | |
| 314 | #define GRPBASE_VALID 0x0001 | |
| 315 | ||
| 316 | #define GRPMASK_BASE_MASK 0xfff0 | |
| 317 | ||
| 318 | #define CSAB_COMPARE 0xff000000 | |
| 319 | #define CSAB_BSW 0x00010000 | |
| 320 | #define CSAB_MASK 0x0000ff00 | |
| 321 | #define CSAB_RO 0x00000008 | |
| 322 | #define CSAB_WAIT 0x00000007 | |
| 323 | ||
| 324 | #define CSCD_COMPARE 0xfff00000 | |
| 325 | #define CSCD_BSW 0x00010000 | |
| 326 | #define CSCD_MASK 0x0000fff0 | |
| 327 | #define CSCD_RO 0x00000008 | |
| 328 | #define CSCD_WAIT 0x00000007 | |
| 329 | ||
| 330 | #define PLLCR_PIXCLK_SEL 0x3800 | |
| 331 | #define PLLCR_PIXCLK_SEL_DIV2 0x0000 | |
| 332 | #define PLLCR_PIXCLK_SEL_DIV4 0x0800 | |
| 333 | #define PLLCR_PIXCLK_SEL_DIV8 0x1000 | |
| 334 | #define PLLCR_PIXCLK_SEL_DIV16 0x1800 | |
| 335 | #define PLLCR_PIXCLK_SEL_DIV1_0 0x2000 | |
| 336 | #define PLLCR_PIXCLK_SEL_DIV1_1 0x2800 | |
| 337 | #define PLLCR_PIXCLK_SEL_DIV1_2 0x3000 | |
| 338 | #define PLLCR_PIXCLK_SEL_DIV1_3 0x3800 | |
| 339 | #define PLLCR_SYSCLK_SEL 0x0700 | |
| 340 | #define PLLCR_SYSCLK_SEL_DIV2 0x0000 | |
| 341 | #define PLLCR_SYSCLK_SEL_DIV4 0x0100 | |
| 342 | #define PLLCR_SYSCLK_SEL_DIV8 0x0200 | |
| 343 | #define PLLCR_SYSCLK_SEL_DIV16 0x0300 | |
| 344 | #define PLLCR_SYSCLK_SEL_DIV1_0 0x0400 | |
| 345 | #define PLLCR_SYSCLK_SEL_DIV1_1 0x0500 | |
| 346 | #define PLLCR_SYSCLK_SEL_DIV1_2 0x0600 | |
| 347 | #define PLLCR_SYSCLK_SEL_DIV1_3 0x0700 | |
| 348 | #define PLLCR_CLKEN 0x0010 | |
| 349 | #define PLLCR_DISPLL 0x0008 | |
| 350 | ||
| 351 | #define PLLFSR_CLK32 0x8000 | |
| 352 | #define PLLFSR_PROT 0x4000 | |
| 353 | #define PLLFSR_QCNT 0x0f00 | |
| 354 | #define PLLFSR_PCNT 0x00ff | |
| 355 | ||
| 356 | #define PCTLR_PC_EN 0x80 | |
| 357 | #define PCTLR_STOP 0x40 | |
| 358 | #define PCTLR_WIDTH 0x1f | |
| 359 | ||
| 360 | #define CXP_CC 0xc000 | |
| 361 | #define CXP_CC_XLU 0x0000 | |
| 362 | #define CXP_CC_BLACK 0x4000 | |
| 363 | #define CXP_CC_INVERSE 0x8000 | |
| 364 | #define CXP_CC_INVALID 0xc000 | |
| 365 | #define CXP_MASK 0x03ff | |
| 366 | ||
| 367 | #define CYP_MASK 0x01ff | |
| 368 | ||
| 369 | #define CWCH_CW 0x1f00 | |
| 370 | #define CWCH_CH 0x001f | |
| 371 | ||
| 372 | #define BLKC_BKEN 0x80 | |
| 373 | #define BLKC_BD 0x7f | |
| 374 | ||
| 375 | #define LPICF_PBSIZ 0x06 | |
| 376 | #define LPICF_PBSIZ_1 0x00 | |
| 377 | #define LPICF_PBSIZ_2 0x02 | |
| 378 | #define LPICF_PBSIZ_4 0x04 | |
| 379 | #define LPICF_PBSIZ_INVALID 0x06 | |
| 380 | ||
| 381 | #define LPOLCF_LCKPOL 0x08 | |
| 382 | #define LPOLCF_FLMPOL 0x04 | |
| 383 | #define LPOLCF_LPPOL 0x02 | |
| 384 | #define LPOLCF_PIXPOL 0x01 | |
| 385 | ||
| 386 | #define LACDRC_MASK 0x0f | |
| 387 | ||
| 388 | #define LPXCD_MASK 0x3f | |
| 389 | ||
| 390 | #define LCKCON_LCDC_EN 0x80 | |
| 391 | #define LCKCON_LCDON 0x80 | |
| 392 | #define LCKCON_DMA16 0x40 | |
| 393 | #define LCKCON_WS 0x30 | |
| 394 | #define LCKCON_WS_1 0x00 | |
| 395 | #define LCKCON_WS_2 0x10 | |
| 396 | #define LCKCON_WS_3 0x20 | |
| 397 | #define LCKCON_WS_4 0x30 | |
| 398 | #define LCKCON_DWIDTH 0x02 | |
| 399 | #define LCKCON_PCDS 0x01 | |
| 400 | ||
| 401 | #define LBAR_MASK 0x7f | |
| 402 | ||
| 403 | #define LPOSR_BOS 0x08 | |
| 404 | #define LPOSR_POS 0x07 | |
| 405 | ||
| 406 | #define LFRCM_XMOD 0xf0 | |
| 407 | #define LFRCM_YMOD 0x0f | |
| 408 | ||
| 409 | #define LGPMR_PAL1 0x7000 | |
| 410 | #define LGPMR_PAL0 0x0700 | |
| 411 | #define LGPMR_PAL3 0x0070 | |
| 412 | #define LGPMR_PAL2 0x0007 | |
| 413 | ||
| 414 | #define RTCHMSR_HOURS 0x1f000000 | |
| 415 | #define RTCHMSR_MINUTES 0x003f0000 | |
| 416 | #define RTCHMSR_SECONDS 0x0000003f | |
| 417 | ||
| 418 | #define RTCCTL_38_4 0x0020 | |
| 419 | #define RTCCTL_ENABLE 0x0080 | |
| 420 | ||
| 421 | #define RTCINT_STOPWATCH 0x0001 | |
| 422 | #define RTCINT_MINUTE 0x0002 | |
| 423 | #define RTCINT_ALARM 0x0004 | |
| 424 | #define RTCINT_DAY 0x0008 | |
| 425 | #define RTCINT_SECOND 0x0010 | |
| 426 | ||
| 427 | #define RTCSTPWTCH_MASK 0x003f | |
| 428 | ||
| 429 | #define TCTL_TEN 0x0001 | |
| 430 | #define TCTL_TEN_ENABLE 0x0001 | |
| 431 | #define TCTL_CLKSOURCE 0x000e | |
| 432 | #define TCTL_CLKSOURCE_STOP 0x0000 | |
| 433 | #define TCTL_CLKSOURCE_SYSCLK 0x0002 | |
| 434 | #define TCTL_CLKSOURCE_SYSCLK16 0x0004 | |
| 435 | #define TCTL_CLKSOURCE_TIN 0x0006 | |
| 436 | #define TCTL_CLKSOURCE_32KHZ4 0x0008 | |
| 437 | #define TCTL_CLKSOURCE_32KHZ5 0x000a | |
| 438 | #define TCTL_CLKSOURCE_32KHZ6 0x000c | |
| 439 | #define TCTL_CLKSOURCE_32KHZ7 0x000e | |
| 440 | #define TCTL_IRQEN 0x0010 | |
| 441 | #define TCTL_IRQEN_ENABLE 0x0010 | |
| 442 | #define TCTL_OM 0x0020 | |
| 443 | #define TCTL_OM_ACTIVELOW 0x0000 | |
| 444 | #define TCTL_OM_TOGGLE 0x0020 | |
| 445 | #define TCTL_CAPTURE 0x00c0 | |
| 446 | #define TCTL_CAPTURE_NOINT 0x0000 | |
| 447 | #define TCTL_CAPTURE_RISING 0x0040 | |
| 448 | #define TCTL_CAPTURE_FALLING 0x0080 | |
| 449 | #define TCTL_CAPTURE_BOTH 0x00c0 | |
| 450 | #define TCTL_FRR 0x0100 | |
| 451 | #define TCTL_FRR_RESTART 0x0000 | |
| 452 | #define TCTL_FRR_FREERUN 0x0100 | |
| 453 | ||
| 454 | #define TSTAT_COMP 0x0001 | |
| 455 | #define TSTAT_CAPT 0x0002 | |
| 456 | ||
| 457 | #define WCTLR_WDRST 0x0008 | |
| 458 | #define WCTLR_LOCK 0x0004 | |
| 459 | #define WCTLR_FI 0x0002 | |
| 460 | #define WCTLR_WDEN 0x0001 | |
| 461 | ||
| 462 | #define USTCNT_UART_EN 0x8000 | |
| 463 | #define USTCNT_RX_EN 0x4000 | |
| 464 | #define USTCNT_TX_EN 0x2000 | |
| 465 | #define USTCNT_RX_CLK_CONT 0x1000 | |
| 466 | #define USTCNT_PARITY_EN 0x0800 | |
| 467 | #define USTCNT_ODD_EVEN 0x0400 | |
| 468 | #define USTCNT_STOP_BITS 0x0200 | |
| 469 | #define USTCNT_8_7 0x0100 | |
| 470 | #define USTCNT_GPIO_DELTA_EN 0x0080 | |
| 471 | #define USTCNT_CTS_DELTA_EN 0x0040 | |
| 472 | #define USTCNT_RX_FULL_EN 0x0020 | |
| 473 | #define USTCNT_RX_HALF_EN 0x0010 | |
| 474 | #define USTCNT_RX_RDY_EN 0x0008 | |
| 475 | #define USTCNT_TX_EMPTY_EN 0x0004 | |
| 476 | #define USTCNT_TX_HALF_EN 0x0002 | |
| 477 | #define USTCNT_TX_AVAIL_EN 0x0001 | |
| 478 | ||
| 479 | #define UBAUD_GPIO_DELTA 0x8000 | |
| 480 | #define UBAUD_GPIO 0x4000 | |
| 481 | #define UBAUD_GPIO_DIR 0x2000 | |
| 482 | #define UBAUD_GPIO_SRC 0x1000 | |
| 483 | #define UBAUD_BAUD_SRC 0x0800 | |
| 484 | #define UBAUD_DIVIDE 0x0700 | |
| 485 | #define UBAUD_DIVIDE_1 0x0000 | |
| 486 | #define UBAUD_DIVIDE_2 0x0100 | |
| 487 | #define UBAUD_DIVIDE_4 0x0200 | |
| 488 | #define UBAUD_DIVIDE_8 0x0300 | |
| 489 | #define UBAUD_DIVIDE_16 0x0400 | |
| 490 | #define UBAUD_DIVIDE_32 0x0500 | |
| 491 | #define UBAUD_DIVIDE_64 0x0600 | |
| 492 | #define UBAUD_DIVIDE_128 0x0700 | |
| 493 | #define UBAUD_PRESCALER 0x00ff | |
| 494 | ||
| 495 | #define URX_FIFO_FULL 0x8000 | |
| 496 | #define URX_FIFO_HALF 0x4000 | |
| 497 | #define URX_DATA_READY 0x2000 | |
| 498 | #define URX_OVRUN 0x0800 | |
| 499 | #define URX_FRAME_ERROR 0x0400 | |
| 500 | #define URX_BREAK 0x0200 | |
| 501 | #define URX_PARITY_ERROR 0x0100 | |
| 502 | ||
| 503 | #define UTX_FIFO_EMPTY 0x8000 | |
| 504 | #define UTX_FIFO_HALF 0x4000 | |
| 505 | #define UTX_TX_AVAIL 0x2000 | |
| 506 | #define UTX_SEND_BREAK 0x1000 | |
| 507 | #define UTX_IGNORE_CTS 0x0800 | |
| 508 | #define UTX_CTS_STATUS 0x0200 | |
| 509 | #define UTX_CTS_DELTA 0x0100 | |
| 510 | ||
| 511 | #define UMISC_CLK_SRC 0x4000 | |
| 512 | #define UMISC_FORCE_PERR 0x2000 | |
| 513 | #define UMISC_LOOP 0x1000 | |
| 514 | #define UMISC_RTS_CONT 0x0080 | |
| 515 | #define UMISC_RTS 0x0040 | |
| 516 | #define UMISC_IRDA_ENABLE 0x0020 | |
| 517 | #define UMISC_IRDA_LOOP 0x0010 | |
| 518 | ||
| 519 | #define SPIS_SPIS_IRQ 0x8000 | |
| 520 | #define SPIS_IRQEN 0x4000 | |
| 521 | #define SPIS_ENPOL 0x2000 | |
| 522 | #define SPIS_DATA_RDY 0x1000 | |
| 523 | #define SPIS_OVRWR 0x0800 | |
| 524 | #define SPIS_PHA 0x0400 | |
| 525 | #define SPIS_POL 0x0200 | |
| 526 | #define SPIS_SPISEN 0x0100 | |
| 527 | ||
| 528 | #define SPIM_CLOCK_COUNT 0x000f | |
| 529 | #define SPIM_POL 0x0010 | |
| 530 | #define SPIM_POL_HIGH 0x0000 | |
| 531 | #define SPIM_POL_LOW 0x0010 | |
| 532 | #define SPIM_PHA 0x0020 | |
| 533 | #define SPIM_PHA_NORMAL 0x0000 | |
| 534 | #define SPIM_PHA_OPPOSITE 0x0020 | |
| 535 | #define SPIM_IRQEN 0x0040 | |
| 536 | #define SPIM_SPIMIRQ 0x0080 | |
| 537 | #define SPIM_XCH 0x0100 | |
| 538 | #define SPIM_XCH_IDLE 0x0000 | |
| 539 | #define SPIM_XCH_INIT 0x0100 | |
| 540 | #define SPIM_SPMEN 0x0200 | |
| 541 | #define SPIM_SPMEN_DISABLE 0x0000 | |
| 542 | #define SPIM_SPMEN_ENABLE 0x0200 | |
| 543 | #define SPIM_RATE 0xe000 | |
| 544 | #define SPIM_RATE_4 0x0000 | |
| 545 | #define SPIM_RATE_8 0x2000 | |
| 546 | #define SPIM_RATE_16 0x4000 | |
| 547 | #define SPIM_RATE_32 0x6000 | |
| 548 | #define SPIM_RATE_64 0x8000 | |
| 549 | #define SPIM_RATE_128 0xa000 | |
| 550 | #define SPIM_RATE_256 0xc000 | |
| 551 | #define SPIM_RATE_512 0xe000 | |
| 552 | ||
| 553 | #define PWMC_PWMIRQ 0x8000 | |
| 554 | #define PWMC_IRQEN 0x4000 | |
| 555 | #define PWMC_LOAD 0x0100 | |
| 556 | #define PWMC_PIN 0x0080 | |
| 557 | #define PWMC_POL 0x0040 | |
| 558 | #define PWMC_PWMEN 0x0010 | |
| 559 | #define PWMC_CLKSEL 0x0007 | |
| 560 | ||
| 561 | INLINE mc68328_t* mc68328_get_safe_token( device_t *device ) | |
| 562 | { | |
| 563 | assert( device != NULL ); | |
| 564 | assert( device->type() == MC68328 ); | |
| 565 | return (mc68328_t*) downcast<mc68328_device *>(device)->token(); | |
| 566 | } | |
| 567 | ||
| 568 | #endif // __MC68328_PRIVATE_H_ |
| r21684 | r21685 | |
|---|---|---|
| 1 | /* | |
| 2 | ||
| 3 | Atmel Serial DataFlash | |
| 4 | ||
| 5 | (c) 2001-2007 Tim Schuerewegen | |
| 6 | ||
| 7 | AT45DB041 - 528 KByte | |
| 8 | AT45DB081 - 1056 KByte | |
| 9 | AT45DB161 - 2112 KByte | |
| 10 | ||
| 11 | */ | |
| 12 | ||
| 13 | #include "at45dbxx.h" | |
| 14 | ||
| 15 | #define LOG_LEVEL 1 | |
| 16 | #define _logerror(level,x) do { if (LOG_LEVEL > level) logerror x; } while (0) | |
| 17 | ||
| 18 | #define FLASH_CMD_52 0x52 | |
| 19 | #define FLASH_CMD_57 0x57 | |
| 20 | #define FLASH_CMD_60 0x60 | |
| 21 | #define FLASH_CMD_82 0x82 | |
| 22 | ||
| 23 | #define FLASH_MODE_XX 0 // unknown | |
| 24 | #define FLASH_MODE_SI 1 // input | |
| 25 | #define FLASH_MODE_SO 2 // output | |
| 26 | ||
| 27 | ||
| 28 | //************************************************************************** | |
| 29 | // GLOBAL VARIABLES | |
| 30 | //************************************************************************** | |
| 31 | ||
| 32 | // device type definition | |
| 33 | const device_type AT45DB041 = &device_creator<at45db041_device>; | |
| 34 | const device_type AT45DB081 = &device_creator<at45db081_device>; | |
| 35 | const device_type AT45DB161 = &device_creator<at45db161_device>; | |
| 36 | ||
| 37 | ||
| 38 | //************************************************************************** | |
| 39 | // LIVE DEVICE | |
| 40 | //************************************************************************** | |
| 41 | ||
| 42 | //------------------------------------------------- | |
| 43 | // at45db041_device - constructor | |
| 44 | //------------------------------------------------- | |
| 45 | ||
| 46 | at45db041_device::at45db041_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) | |
| 47 | : device_t(mconfig, AT45DB041, "AT45DB041", tag, owner, clock), | |
| 48 | device_nvram_interface(mconfig, *this) | |
| 49 | { | |
| 50 | } | |
| 51 | ||
| 52 | ||
| 53 | at45db041_device::at45db041_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock) | |
| 54 | : device_t(mconfig, type, name, tag, owner, clock), | |
| 55 | device_nvram_interface(mconfig, *this) | |
| 56 | { | |
| 57 | } | |
| 58 | ||
| 59 | ||
| 60 | at45db081_device::at45db081_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) | |
| 61 | : at45db041_device(mconfig, AT45DB081, "AT45DB081", tag, owner, clock) | |
| 62 | { | |
| 63 | } | |
| 64 | ||
| 65 | ||
| 66 | at45db161_device::at45db161_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) | |
| 67 | : at45db041_device(mconfig, AT45DB161, "AT45DB161", tag, owner, clock) | |
| 68 | { | |
| 69 | } | |
| 70 | ||
| 71 | ||
| 72 | //------------------------------------------------- | |
| 73 | // device_start - device-specific startup | |
| 74 | //------------------------------------------------- | |
| 75 | ||
| 76 | void at45db041_device::device_start() | |
| 77 | { | |
| 78 | m_size = num_pages() * page_size(); | |
| 79 | m_data = auto_alloc_array(machine(), UINT8, m_size); | |
| 80 | m_buffer1 = auto_alloc_array(machine(), UINT8, page_size()); | |
| 81 | m_buffer2 = auto_alloc_array(machine(), UINT8, page_size()); | |
| 82 | ||
| 83 | // data | |
| 84 | save_pointer(NAME(m_data), m_size); | |
| 85 | // pins | |
| 86 | save_item(NAME(m_pin.cs)); | |
| 87 | save_item(NAME(m_pin.sck)); | |
| 88 | save_item(NAME(m_pin.si)); | |
| 89 | save_item(NAME(m_pin.so)); | |
| 90 | save_item(NAME(m_pin.wp)); | |
| 91 | save_item(NAME(m_pin.reset)); | |
| 92 | save_item(NAME(m_pin.busy)); | |
| 93 | } | |
| 94 | ||
| 95 | ||
| 96 | //------------------------------------------------- | |
| 97 | // device_reset - device-specific reset | |
| 98 | //------------------------------------------------- | |
| 99 | ||
| 100 | void at45db041_device::device_reset() | |
| 101 | { | |
| 102 | _logerror( 1, ("at45dbxx_reset\n")); | |
| 103 | // mode | |
| 104 | m_mode = FLASH_MODE_SI; | |
| 105 | // command | |
| 106 | memset(&m_cmd.data[0], 0, sizeof(m_cmd.data)); | |
| 107 | m_cmd.size = 0; | |
| 108 | // input/output | |
| 109 | m_io.data = NULL; | |
| 110 | m_io.size = 0; | |
| 111 | m_io.pos = 0; | |
| 112 | // pins | |
| 113 | m_pin.cs = 0; | |
| 114 | m_pin.sck = 0; | |
| 115 | m_pin.si = 0; | |
| 116 | m_pin.so = 0; | |
| 117 | m_pin.wp = 0; | |
| 118 | m_pin.reset = 0; | |
| 119 | m_pin.busy = 0; | |
| 120 | // output | |
| 121 | m_so_byte = 0; | |
| 122 | m_so_bits = 0; | |
| 123 | // input | |
| 124 | m_si_byte = 0; | |
| 125 | m_si_bits = 0; | |
| 126 | } | |
| 127 | ||
| 128 | ||
| 129 | //------------------------------------------------- | |
| 130 | // nvram_default - called to initialize NVRAM to | |
| 131 | // its default state | |
| 132 | //------------------------------------------------- | |
| 133 | ||
| 134 | void at45db041_device::nvram_default() | |
| 135 | { | |
| 136 | memset(m_data, 0xff, m_size); | |
| 137 | ||
| 138 | if (region() != NULL) | |
| 139 | { | |
| 140 | UINT32 bytes = region()->bytes(); | |
| 141 | if (bytes > m_size) | |
| 142 | bytes = m_size; | |
| 143 | ||
| 144 | memcpy(m_data, region()->base(), bytes); | |
| 145 | } | |
| 146 | } | |
| 147 | ||
| 148 | //------------------------------------------------- | |
| 149 | // nvram_read - called to read NVRAM from the | |
| 150 | // .nv file | |
| 151 | //------------------------------------------------- | |
| 152 | ||
| 153 | void at45db041_device::nvram_read(emu_file &file) | |
| 154 | { | |
| 155 | file.read(m_data, m_size); | |
| 156 | } | |
| 157 | ||
| 158 | //------------------------------------------------- | |
| 159 | // nvram_write - called to write NVRAM to the | |
| 160 | // .nv file | |
| 161 | //------------------------------------------------- | |
| 162 | ||
| 163 | void at45db041_device::nvram_write(emu_file &file) | |
| 164 | { | |
| 165 | file.write(m_data, m_size); | |
| 166 | } | |
| 167 | ||
| 168 | UINT8 at45db041_device::read_byte() | |
| 169 | { | |
| 170 | UINT8 data; | |
| 171 | // check mode | |
| 172 | if ((m_mode != FLASH_MODE_SO) || (!m_io.data)) return 0; | |
| 173 | // read byte | |
| 174 | data = m_io.data[m_io.pos++]; | |
| 175 | _logerror( 2, ("at45dbxx_read_byte (%02X) (%03d/%03d)\n", data, m_io.pos, m_io.size)); | |
| 176 | if (m_io.pos == m_io.size) m_io.pos = 0; | |
| 177 | return data; | |
| 178 | } | |
| 179 | ||
| 180 | void at45db041_device::flash_set_io(UINT8* data, UINT32 size, UINT32 pos) | |
| 181 | { | |
| 182 | m_io.data = data; | |
| 183 | m_io.size = size; | |
| 184 | m_io.pos = pos; | |
| 185 | } | |
| 186 | ||
| 187 | UINT32 at45db041_device::flash_get_page_addr() | |
| 188 | { | |
| 189 | return ((m_cmd.data[1] & 0x0F) << 7) | ((m_cmd.data[2] & 0xFE) >> 1); | |
| 190 | } | |
| 191 | ||
| 192 | UINT32 at45db041_device::flash_get_byte_addr() | |
| 193 | { | |
| 194 | return ((m_cmd.data[2] & 0x01) << 8) | ((m_cmd.data[3] & 0xFF) >> 0); | |
| 195 | } | |
| 196 | ||
| 197 | UINT32 at45db081_device::flash_get_page_addr() | |
| 198 | { | |
| 199 | return ((m_cmd.data[1] & 0x1F) << 7) | ((m_cmd.data[2] & 0xFE) >> 1); | |
| 200 | } | |
| 201 | ||
| 202 | UINT32 at45db161_device::flash_get_page_addr() | |
| 203 | { | |
| 204 | return ((m_cmd.data[1] & 0x3F) << 6) | ((m_cmd.data[2] & 0xFC) >> 2); | |
| 205 | } | |
| 206 | ||
| 207 | UINT32 at45db161_device::flash_get_byte_addr() | |
| 208 | { | |
| 209 | return ((m_cmd.data[2] & 0x03) << 8) | ((m_cmd.data[3] & 0xFF) >> 0); | |
| 210 | } | |
| 211 | ||
| 212 | void at45db041_device::write_byte(UINT8 data) | |
| 213 | { | |
| 214 | // check mode | |
| 215 | if (m_mode != FLASH_MODE_SI) return; | |
| 216 | // process byte | |
| 217 | if (m_cmd.size < 8) | |
| 218 | { | |
| 219 | UINT8 opcode; | |
| 220 | _logerror( 2, ("at45dbxx_write_byte (%02X)\n", data)); | |
| 221 | // add to command buffer | |
| 222 | m_cmd.data[m_cmd.size++] = data; | |
| 223 | // check opcode | |
| 224 | opcode = m_cmd.data[0]; | |
| 225 | switch (opcode) | |
| 226 | { | |
| 227 | // status register read | |
| 228 | case FLASH_CMD_57 : | |
| 229 | { | |
| 230 | // 8 bits command | |
| 231 | if (m_cmd.size == 1) | |
| 232 | { | |
| 233 | _logerror( 1, ("at45dbxx opcode %02X - status register read\n", opcode)); | |
| 234 | m_status = (m_status & 0xC7) | device_id(); // 80 = busy / 40 = compare fail | |
| 235 | flash_set_io(&m_status, 1, 0); | |
| 236 | m_mode = FLASH_MODE_SO; | |
| 237 | m_cmd.size = 8; | |
| 238 | } | |
| 239 | } | |
| 240 | break; | |
| 241 | // main memory page to buffer 1 compare | |
| 242 | case FLASH_CMD_60 : | |
| 243 | { | |
| 244 | // 8 bits command + 4 bits reserved + 11 bits page address + 9 bits don't care | |
| 245 | if (m_cmd.size == 4) | |
| 246 | { | |
| 247 | UINT32 page; | |
| 248 | UINT8 comp; | |
| 249 | page = flash_get_page_addr(); | |
| 250 | _logerror( 1, ("at45dbxx opcode %02X - main memory page to buffer 1 compare [%04X]\n", opcode, page)); | |
| 251 | comp = memcmp( m_data + page * page_size(), m_buffer1, page_size()) == 0 ? 0 : 1; | |
| 252 | if (comp) m_status |= 0x40; else m_status &= ~0x40; | |
| 253 | _logerror( 1, ("at45dbxx page compare %s\n", comp ? "failure" : "success")); | |
| 254 | m_mode = FLASH_MODE_SI; | |
| 255 | m_cmd.size = 8; | |
| 256 | } | |
| 257 | } | |
| 258 | break; | |
| 259 | // main memory page read | |
| 260 | case FLASH_CMD_52 : | |
| 261 | { | |
| 262 | // 8 bits command + 4 bits reserved + 11 bits page address + 9 bits buffer address + 32 bits don't care | |
| 263 | if (m_cmd.size == 8) | |
| 264 | { | |
| 265 | UINT32 page, byte; | |
| 266 | page = flash_get_page_addr(); | |
| 267 | byte = flash_get_byte_addr(); | |
| 268 | _logerror( 1, ("at45dbxx opcode %02X - main memory page read [%04X/%04X]\n", opcode, page, byte)); | |
| 269 | flash_set_io(m_data + page * page_size(), page_size(), byte); | |
| 270 | m_mode = FLASH_MODE_SO; | |
| 271 | m_cmd.size = 8; | |
| 272 | } | |
| 273 | } | |
| 274 | break; | |
| 275 | // main memory page program through buffer 1 | |
| 276 | case FLASH_CMD_82 : | |
| 277 | { | |
| 278 | // 8 bits command + 4 bits reserved + 11 bits page address + 9 bits buffer address | |
| 279 | if (m_cmd.size == 4) | |
| 280 | { | |
| 281 | UINT32 page, byte; | |
| 282 | page = flash_get_page_addr(); | |
| 283 | byte = flash_get_byte_addr(); | |
| 284 | _logerror( 1, ("at45dbxx opcode %02X - main memory page program through buffer 1 [%04X/%04X]\n",opcode, page, byte)); | |
| 285 | flash_set_io(m_buffer1, page_size(), byte); | |
| 286 | memset( m_buffer1, 0xFF, page_size()); | |
| 287 | m_mode = FLASH_MODE_SI; | |
| 288 | m_cmd.size = 8; | |
| 289 | } | |
| 290 | } | |
| 291 | break; | |
| 292 | // other | |
| 293 | default : | |
| 294 | { | |
| 295 | _logerror( 1, ("at45dbxx opcode %02X - unknown\n", opcode)); | |
| 296 | m_cmd.data[0] = 0; | |
| 297 | m_cmd.size = 0; | |
| 298 | } | |
| 299 | break; | |
| 300 | } | |
| 301 | } | |
| 302 | else | |
| 303 | { | |
| 304 | _logerror( 2, ("at45dbxx_write_byte (%02X) (%03d/%03d)\n", data, m_io.pos + 1, m_io.size)); | |
| 305 | // store byte | |
| 306 | m_io.data[m_io.pos] = data; | |
| 307 | m_io.pos++; | |
| 308 | if (m_io.pos == m_io.size) m_io.pos = 0; | |
| 309 | } | |
| 310 | } | |
| 311 | ||
| 312 | READ_LINE_MEMBER(at45db041_device::so_r) | |
| 313 | { | |
| 314 | if (m_pin.cs == 0) return 0; | |
| 315 | return m_pin.so; | |
| 316 | } | |
| 317 | ||
| 318 | WRITE_LINE_MEMBER(at45db041_device::si_w) | |
| 319 | { | |
| 320 | if (m_pin.cs == 0) return; | |
| 321 | m_pin.si = state; | |
| 322 | } | |
| 323 | ||
| 324 | WRITE_LINE_MEMBER(at45db041_device::cs_w) | |
| 325 | { | |
| 326 | // check if changed | |
| 327 | if (m_pin.cs == state) return; | |
| 328 | // cs low-to-high | |
| 329 | if (state != 0) | |
| 330 | { | |
| 331 | // complete program command | |
| 332 | if ((m_cmd.size >= 4) && (m_cmd.data[0] == FLASH_CMD_82)) | |
| 333 | { | |
| 334 | UINT32 page, byte; | |
| 335 | page = flash_get_page_addr(); | |
| 336 | byte = flash_get_byte_addr(); | |
| 337 | _logerror( 1, ("at45dbxx - program data stored in buffer 1 into selected page in main memory [%04X/%04X]\n", page, byte)); | |
| 338 | memcpy( m_data + page * page_size(), m_buffer1, page_size()); | |
| 339 | } | |
| 340 | // reset | |
| 341 | at45db041_device::device_reset(); | |
| 342 | } | |
| 343 | // save cs | |
| 344 | m_pin.cs = state; | |
| 345 | } | |
| 346 | ||
| 347 | WRITE_LINE_MEMBER(at45db041_device::sck_w) | |
| 348 | { | |
| 349 | // check if changed | |
| 350 | if (m_pin.sck == state) return; | |
| 351 | // sck high-to-low | |
| 352 | if (state == 0) | |
| 353 | { | |
| 354 | // output (part 1) | |
| 355 | if (m_so_bits == 8) | |
| 356 | { | |
| 357 | m_so_bits = 0; | |
| 358 | m_so_byte = read_byte(); | |
| 359 | } | |
| 360 | // input | |
| 361 | if (m_pin.si) m_si_byte = m_si_byte | (1 << m_si_bits); | |
| 362 | m_si_bits++; | |
| 363 | if (m_si_bits == 8) | |
| 364 | { | |
| 365 | m_si_bits = 0; | |
| 366 | write_byte(m_si_byte); | |
| 367 | m_si_byte = 0; | |
| 368 | } | |
| 369 | // output (part 2) | |
| 370 | m_pin.so = (m_so_byte >> m_so_bits) & 1; | |
| 371 | m_so_bits++; | |
| 372 | } | |
| 373 | // save sck | |
| 374 | m_pin.sck = state; | |
| 375 | } |
| r21684 | r21685 | |
|---|---|---|
| 1 | /* | |
| 2 | ||
| 3 | Atmel Serial DataFlash | |
| 4 | ||
| 5 | (c) 2001-2007 Tim Schuerewegen | |
| 6 | ||
| 7 | AT45DB041 - 528 KByte | |
| 8 | AT45DB081 - 1056 KByte | |
| 9 | AT45DB161 - 2112 KByte | |
| 10 | ||
| 11 | */ | |
| 12 | ||
| 13 | #ifndef _AT45DBXX_H_ | |
| 14 | #define _AT45DBXX_H_ | |
| 15 | ||
| 16 | #include "emu.h" | |
| 17 | ||
| 18 | ||
| 19 | //************************************************************************** | |
| 20 | // INTERFACE CONFIGURATION MACROS | |
| 21 | //************************************************************************** | |
| 22 | ||
| 23 | #define MCFG_AT45DB041_ADD(_tag) \ | |
| 24 | MCFG_DEVICE_ADD(_tag, AT45DB041, 0) | |
| 25 | ||
| 26 | #define MCFG_AT45DB081_ADD(_tag) \ | |
| 27 | MCFG_DEVICE_ADD(_tag, AT45DB081, 0) | |
| 28 | ||
| 29 | #define MCFG_AT45DB161_ADD(_tag) \ | |
| 30 | MCFG_DEVICE_ADD(_tag, AT45DB161, 0) | |
| 31 | ||
| 32 | ||
| 33 | // ======================> at45db041_device | |
| 34 | ||
| 35 | class at45db041_device : public device_t, | |
| 36 | public device_nvram_interface | |
| 37 | { | |
| 38 | public: | |
| 39 | at45db041_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); | |
| 40 | at45db041_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock); | |
| 41 | ||
| 42 | DECLARE_WRITE_LINE_MEMBER(cs_w); | |
| 43 | DECLARE_WRITE_LINE_MEMBER(sck_w); | |
| 44 | DECLARE_WRITE_LINE_MEMBER(si_w); | |
| 45 | DECLARE_READ_LINE_MEMBER(so_r); | |
| 46 | ||
| 47 | UINT8 *get_ptr() { return m_data; } | |
| 48 | ||
| 49 | protected: | |
| 50 | // device-level overrides | |
| 51 | virtual void device_start(); | |
| 52 | virtual void device_reset(); | |
| 53 | ||
| 54 | // device_nvram_interface overrides | |
| 55 | virtual void nvram_default(); | |
| 56 | virtual void nvram_read(emu_file &file); | |
| 57 | virtual void nvram_write(emu_file &file); | |
| 58 | ||
| 59 | protected: | |
| 60 | virtual int num_pages() const { return 2048; } | |
| 61 | virtual int page_size() const { return 264; } | |
| 62 | virtual UINT8 device_id() const { return 0x18; } | |
| 63 | ||
| 64 | UINT8 read_byte(); | |
| 65 | void flash_set_io(UINT8* data, UINT32 size, UINT32 pos); | |
| 66 | virtual UINT32 flash_get_page_addr(); | |
| 67 | virtual UINT32 flash_get_byte_addr(); | |
| 68 | void write_byte(UINT8 data); | |
| 69 | ||
| 70 | // internal state | |
| 71 | UINT8 * m_data; | |
| 72 | UINT32 m_size; | |
| 73 | UINT8 m_mode; | |
| 74 | UINT8 m_status; | |
| 75 | UINT8 * m_buffer1; | |
| 76 | UINT8 * m_buffer2; | |
| 77 | UINT8 m_si_byte; | |
| 78 | UINT8 m_si_bits; | |
| 79 | UINT8 m_so_byte; | |
| 80 | UINT8 m_so_bits; | |
| 81 | ||
| 82 | struct AT45DBXX_PINS | |
| 83 | { | |
| 84 | int cs; // chip select | |
| 85 | int sck; // serial clock | |
| 86 | int si; // serial input | |
| 87 | int so; // serial output | |
| 88 | int wp; // write protect | |
| 89 | int reset; // reset | |
| 90 | int busy; // busy | |
| 91 | } m_pin; | |
| 92 | ||
| 93 | struct AT45DBXX_IO | |
| 94 | { | |
| 95 | UINT8 *data; | |
| 96 | UINT32 size; | |
| 97 | UINT32 pos; | |
| 98 | } m_io; | |
| 99 | ||
| 100 | struct AT45DBXX_CMD | |
| 101 | { | |
| 102 | UINT8 data[8]; | |
| 103 | UINT8 size; | |
| 104 | } m_cmd; | |
| 105 | }; | |
| 106 | ||
| 107 | // ======================> at45db081_device | |
| 108 | ||
| 109 | class at45db081_device : public at45db041_device | |
| 110 | { | |
| 111 | public: | |
| 112 | at45db081_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); | |
| 113 | ||
| 114 | protected: | |
| 115 | virtual int num_pages() const { return 4096; } | |
| 116 | virtual int page_size() const { return 264; } | |
| 117 | virtual UINT8 device_id() const { return 0x20; } | |
| 118 | ||
| 119 | virtual UINT32 flash_get_page_addr(); | |
| 120 | }; | |
| 121 | ||
| 122 | // ======================> at45db161_device | |
| 123 | ||
| 124 | class at45db161_device : public at45db041_device | |
| 125 | { | |
| 126 | public: | |
| 127 | at45db161_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); | |
| 128 | ||
| 129 | protected: | |
| 130 | virtual int num_pages() const { return 4096; } | |
| 131 | virtual int page_size() const { return 528; } | |
| 132 | virtual UINT8 device_id() const { return 0x28; } | |
| 133 | ||
| 134 | virtual UINT32 flash_get_page_addr(); | |
| 135 | virtual UINT32 flash_get_byte_addr(); | |
| 136 | }; | |
| 137 | ||
| 138 | ||
| 139 | // device type definition | |
| 140 | extern const device_type AT45DB041; | |
| 141 | extern const device_type AT45DB081; | |
| 142 | extern const device_type AT45DB161; | |
| 143 | ||
| 144 | #endif |
| r21684 | r21685 | |
|---|---|---|
| 1 | /* | |
| 2 | Atmel at29c040a flash EEPROM | |
| 3 | ||
| 4 | 512k*8 FEEPROM, organized in pages of 256 bytes. | |
| 5 | ||
| 6 | References: | |
| 7 | Datasheets were found on Atmel's site (www.atmel.com) | |
| 8 | ||
| 9 | Raphael Nabet 2003 | |
| 10 | ||
| 11 | September 2010: Rewritten as device | |
| 12 | February 2012: Rewritten as class | |
| 13 | */ | |
| 14 | ||
| 15 | #include "at29040a.h" | |
| 16 | ||
| 17 | #define VERBOSE 2 | |
| 18 | #define LOG logerror | |
| 19 | ||
| 20 | #define FEEPROM_SIZE 0x80000 | |
| 21 | #define SECTOR_SIZE 0x00100 | |
| 22 | #define BOOT_BLOCK_SIZE 0x04000 | |
| 23 | ||
| 24 | #define ADDRESS_MASK 0x7ffff | |
| 25 | #define SECTOR_ADDRESS_MASK 0x7ff00 | |
| 26 | #define BYTE_ADDRESS_MASK 0x000ff | |
| 27 | ||
| 28 | #define PRG_TIMER 1 | |
| 29 | ||
| 30 | #define VERSION 0 | |
| 31 | ||
| 32 | /* | |
| 33 | Constructor. | |
| 34 | */ | |
| 35 | at29040a_device::at29040a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) | |
| 36 | : device_t(mconfig, AT29040A, "ATMEL 29040A 512K*8 FEEPROM", tag, owner, clock), | |
| 37 | device_nvram_interface(mconfig, *this) | |
| 38 | { | |
| 39 | } | |
| 40 | ||
| 41 | //------------------------------------------------- | |
| 42 | // nvram_default - called to initialize NVRAM to | |
| 43 | // its default state | |
| 44 | //------------------------------------------------- | |
| 45 | ||
| 46 | void at29040a_device::nvram_default() | |
| 47 | { | |
| 48 | memset(m_eememory, 0, FEEPROM_SIZE+2); | |
| 49 | } | |
| 50 | ||
| 51 | //------------------------------------------------- | |
| 52 | // nvram_read - called to read NVRAM from the | |
| 53 | // .nv file | |
| 54 | //------------------------------------------------- | |
| 55 | ||
| 56 | void at29040a_device::nvram_read(emu_file &file) | |
| 57 | { | |
| 58 | file.read(m_eememory, FEEPROM_SIZE+2); | |
| 59 | } | |
| 60 | ||
| 61 | //------------------------------------------------- | |
| 62 | // nvram_write - called to write NVRAM to the | |
| 63 | // .nv file | |
| 64 | //------------------------------------------------- | |
| 65 | ||
| 66 | void at29040a_device::nvram_write(emu_file &file) | |
| 67 | { | |
| 68 | m_eememory[0] = VERSION; | |
| 69 | file.write(m_eememory, FEEPROM_SIZE+2); | |
| 70 | } | |
| 71 | ||
| 72 | /* | |
| 73 | programming timer callback | |
| 74 | */ | |
| 75 | void at29040a_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) | |
| 76 | { | |
| 77 | switch (m_pgm) | |
| 78 | { | |
| 79 | case PGM_1: | |
| 80 | /* programming cycle timeout */ | |
| 81 | if (VERBOSE>7) LOG("at29040a: Programming cycle timeout\n"); | |
| 82 | m_pgm = PGM_0; | |
| 83 | break; | |
| 84 | ||
| 85 | case PGM_2: | |
| 86 | /* programming cycle start */ | |
| 87 | if (VERBOSE>7) LOG("at29040a: Sector write start\n"); | |
| 88 | m_pgm = PGM_3; | |
| 89 | /* max delay 10ms, typical delay 5 to 7 ms */ | |
| 90 | m_programming_timer->adjust(attotime::from_msec(5)); | |
| 91 | break; | |
| 92 | ||
| 93 | case PGM_3: | |
| 94 | /* programming cycle end */ | |
| 95 | memcpy(m_eememory + 2 + (m_programming_last_offset & ~0xff), m_programming_buffer, SECTOR_SIZE); | |
| 96 | if (VERBOSE>7) LOG("at29040a: Sector write completed at location %04x + 2\n", (m_programming_last_offset & ~0xff)); | |
| 97 | if (m_enabling_sdb) | |
| 98 | { | |
| 99 | m_sdp = true; | |
| 100 | } | |
| 101 | if (m_disabling_sdb) | |
| 102 | { | |
| 103 | m_sdp = false; | |
| 104 | } | |
| 105 | if (VERBOSE>7) LOG("at29040a: Software data protection = %d\n", m_sdp); | |
| 106 | ||
| 107 | m_pgm = PGM_0; | |
| 108 | m_enabling_sdb = false; | |
| 109 | m_disabling_sdb = false; | |
| 110 | ||
| 111 | break; | |
| 112 | ||
| 113 | default: | |
| 114 | if (VERBOSE>1) LOG("internal error in %s %d\n", __FILE__, __LINE__); | |
| 115 | break; | |
| 116 | } | |
| 117 | } | |
| 118 | ||
| 119 | void at29040a_device::sync_flags() | |
| 120 | { | |
| 121 | if (m_lower_bbl) m_eememory[1] |= 0x04; | |
| 122 | else m_eememory[1] &= ~0x04; | |
| 123 | ||
| 124 | if (m_higher_bbl) m_eememory[1] |= 0x02; | |
| 125 | else m_eememory[1] &= ~0x02; | |
| 126 | ||
| 127 | if (m_sdp) m_eememory[1] |= 0x01; | |
| 128 | else m_eememory[1] &= ~0x01; | |
| 129 | } | |
| 130 | ||
| 131 | /* | |
| 132 | read a byte from FEEPROM | |
| 133 | */ | |
| 134 | READ8_MEMBER( at29040a_device::read ) | |
| 135 | { | |
| 136 | int reply; | |
| 137 | ||
| 138 | offset &= ADDRESS_MASK; | |
| 139 | ||
| 140 | /* reading in the midst of any command sequence cancels it (right???) */ | |
| 141 | m_cmd = CMD_0; | |
| 142 | m_long_sequence = false; | |
| 143 | // m_higher_bbl = true; // who says that? | |
| 144 | ||
| 145 | sync_flags(); | |
| 146 | ||
| 147 | /* reading before the start of a programming cycle cancels it (right???) */ | |
| 148 | if (m_pgm == PGM_1) | |
| 149 | { | |
| 150 | // attempt to access a locked out boot block: cancel programming | |
| 151 | // command if necessary | |
| 152 | m_pgm = PGM_0; | |
| 153 | m_enabling_sdb = false; | |
| 154 | m_disabling_sdb = false; | |
| 155 | m_programming_timer->adjust(attotime::never); | |
| 156 | } | |
| 157 | ||
| 158 | if (m_id_mode) | |
| 159 | { | |
| 160 | switch (offset) | |
| 161 | { | |
| 162 | case 0x00000: | |
| 163 | reply = 0x1f; // Manufacturer code | |
| 164 | break; | |
| 165 | ||
| 166 | case 0x00001: | |
| 167 | reply = 0xa4; // Device code | |
| 168 | break; | |
| 169 | ||
| 170 | case 0x00002: | |
| 171 | reply = m_lower_bbl? 0xff : 0xfe; | |
| 172 | break; | |
| 173 | ||
| 174 | case 0x7fff2: | |
| 175 | reply = m_higher_bbl? 0xff : 0xfe; | |
| 176 | break; | |
| 177 | ||
| 178 | default: | |
| 179 | reply = 0; | |
| 180 | break; | |
| 181 | } | |
| 182 | } | |
| 183 | else if ((m_pgm == PGM_2) || (m_pgm == PGM_3)) | |
| 184 | { | |
| 185 | if (m_pgm == PGM_2) | |
| 186 | { // DATA* polling starts the programming cycle (right???) | |
| 187 | m_pgm = PGM_3; | |
| 188 | /* max delay 10ms, typical delay 5 to 7 ms */ | |
| 189 | m_programming_timer->adjust(attotime::from_msec(5)); | |
| 190 | } | |
| 191 | ||
| 192 | reply = m_toggle_bit? 0x02 : 0x00; | |
| 193 | m_toggle_bit = !m_toggle_bit; | |
| 194 | ||
| 195 | if ((offset == m_programming_last_offset) && (! (m_programming_buffer[m_programming_last_offset & 0xff] & 0x01))) | |
| 196 | reply |= 0x01; | |
| 197 | } | |
| 198 | else | |
| 199 | reply = m_eememory[offset+2]; | |
| 200 | ||
| 201 | if (VERBOSE>7) LOG("at29040a: %05x -> %02x\n", offset, reply); | |
| 202 | ||
| 203 | return reply; | |
| 204 | } | |
| 205 | ||
| 206 | /* | |
| 207 | Write a byte to FEEPROM | |
| 208 | */ | |
| 209 | WRITE8_MEMBER( at29040a_device::write ) | |
| 210 | { | |
| 211 | offset &= ADDRESS_MASK; | |
| 212 | if (VERBOSE>7) LOG("at29040a: %05x <- %02x\n", offset, data); | |
| 213 | ||
| 214 | /* The special CFI commands assume a smaller address space according */ | |
| 215 | /* to the specification ("address format A14-A0") */ | |
| 216 | offs_t cfi_offset = offset & 0x7fff; | |
| 217 | ||
| 218 | if (m_enabling_bbl) | |
| 219 | { | |
| 220 | if (VERBOSE>7) LOG("at29040a: Enabling boot block lockout\n"); | |
| 221 | m_enabling_bbl = false; | |
| 222 | ||
| 223 | if ((offset == 0x00000) && (data == 0x00)) | |
| 224 | { | |
| 225 | if (VERBOSE>7) LOG("at29040a: Enabling lower boot block lockout\n"); | |
| 226 | m_lower_bbl = true; | |
| 227 | sync_flags(); | |
| 228 | return; | |
| 229 | } | |
| 230 | else | |
| 231 | { | |
| 232 | if ((offset == 0x7ffff) && (data == 0xff)) | |
| 233 | { | |
| 234 | if (VERBOSE>7) LOG("at29040a: Enabling higher boot block lockout\n"); | |
| 235 | m_higher_bbl = true; | |
| 236 | sync_flags(); | |
| 237 | return; | |
| 238 | } | |
| 239 | else | |
| 240 | { | |
| 241 | if (VERBOSE>1) LOG("at29040a: Invalid boot block specification: %05x/%02x\n", offset, data); | |
| 242 | } | |
| 243 | } | |
| 244 | } | |
| 245 | ||
| 246 | switch (m_cmd) | |
| 247 | { | |
| 248 | case CMD_0: | |
| 249 | if ((cfi_offset == 0x5555) && (data == 0xaa)) | |
| 250 | { | |
| 251 | if (VERBOSE>7) LOG("at29040a: Command sequence started\n"); | |
| 252 | m_cmd = CMD_1; | |
| 253 | } | |
| 254 | else | |
| 255 | { | |
| 256 | m_cmd = CMD_0; | |
| 257 | m_long_sequence = false; | |
| 258 | } | |
| 259 | break; | |
| 260 | ||
| 261 | case CMD_1: | |
| 262 | if ((cfi_offset == 0x2aaa) && (data == 0x55)) | |
| 263 | { | |
| 264 | m_cmd = CMD_2; | |
| 265 | } | |
| 266 | else | |
| 267 | { | |
| 268 | m_cmd = CMD_0; | |
| 269 | m_long_sequence = false; | |
| 270 | if (VERBOSE>7) LOG("at29040a: Command sequence aborted\n"); | |
| 271 | } | |
| 272 | break; | |
| 273 | ||
| 274 | case CMD_2: | |
| 275 | if (cfi_offset == 0x5555) | |
| 276 | { | |
| 277 | if (!m_long_sequence) | |
| 278 | if (VERBOSE>7) LOG("at29040a: Command sequence completed\n"); | |
| 279 | ||
| 280 | m_pgm = PGM_0; | |
| 281 | m_enabling_sdb = false; | |
| 282 | m_disabling_sdb = false; | |
| 283 | m_programming_timer->adjust(attotime::never); | |
| 284 | ||
| 285 | /* process command */ | |
| 286 | switch (data) | |
| 287 | { | |
| 288 | case 0x10: | |
| 289 | /* Software chip erase */ | |
| 290 | if (m_long_sequence) | |
| 291 | { | |
| 292 | if (m_lower_bbl || m_higher_bbl) | |
| 293 | { | |
| 294 | if (VERBOSE>1) LOG("at29040a: Chip erase sequence deactivated due to previous boot block lockout.\n"); | |
| 295 | } | |
| 296 | else | |
| 297 | { | |
| 298 | if (VERBOSE>7) LOG("at29040a: Erase chip\n"); | |
| 299 | memset(m_eememory+2, 0xff, FEEPROM_SIZE); | |
| 300 | } | |
| 301 | } | |
| 302 | break; | |
| 303 | ||
| 304 | case 0x20: | |
| 305 | /* Software data protection disable */ | |
| 306 | if (VERBOSE>7) LOG("at29040a: Software data protection disable\n"); | |
| 307 | // The complete sequence is aa-55-80-aa-55-20 | |
| 308 | // so we need a 80 before, else the sequence is invalid | |
| 309 | if (m_long_sequence) | |
| 310 | { | |
| 311 | m_pgm = PGM_1; | |
| 312 | m_disabling_sdb = true; | |
| 313 | /* set command timeout (right???) */ | |
| 314 | //m_programming_timer->adjust(attotime::from_usec(150), id, 0.); | |
| 315 | } | |
| 316 | break; | |
| 317 | ||
| 318 | case 0x40: | |
| 319 | /* Boot block lockout enable */ | |
| 320 | // Complete sequence is aa-55-80-aa-55-40 | |
| 321 | if (VERBOSE>7) LOG("at29040a: Boot block lockout enable\n"); | |
| 322 | if (m_long_sequence) m_enabling_bbl = true; | |
| 323 | break; | |
| 324 | ||
| 325 | case 0x80: | |
| 326 | m_long_sequence = true; | |
| 327 | break; | |
| 328 | ||
| 329 | case 0x90: | |
| 330 | /* Software product identification entry */ | |
| 331 | if (VERBOSE>7) LOG("at29040a: Identification mode (start)\n"); | |
| 332 | m_id_mode = true; | |
| 333 | break; | |
| 334 | ||
| 335 | case 0xa0: | |
| 336 | /* Software data protection enable */ | |
| 337 | if (VERBOSE>7) LOG("at29040a: Software data protection enable\n"); | |
| 338 | m_pgm = PGM_1; | |
| 339 | m_enabling_sdb = true; | |
| 340 | /* set command timeout (right???) */ | |
| 341 | //m_programming_timer->adjust(attotime::from_usec(150), id, 0.); | |
| 342 | break; | |
| 343 | ||
| 344 | case 0xf0: | |
| 345 | /* Software product identification exit */ | |
| 346 | if (VERBOSE>7) LOG("at29040a: Identification mode (end)\n"); | |
| 347 | m_id_mode = false; | |
| 348 | break; | |
| 349 | } | |
| 350 | m_cmd = CMD_0; | |
| 351 | if (data != 0x80) m_long_sequence = false; | |
| 352 | ||
| 353 | /* return, because we don't want to write the EEPROM with the command byte */ | |
| 354 | return; | |
| 355 | } | |
| 356 | else | |
| 357 | { | |
| 358 | m_cmd = CMD_0; | |
| 359 | m_long_sequence = false; | |
| 360 | } | |
| 361 | } | |
| 362 | if ((m_pgm == PGM_2) | |
| 363 | && ((offset & ~0xff) != (m_programming_last_offset & ~0xff))) | |
| 364 | { | |
| 365 | /* cancel current programming cycle */ | |
| 366 | if (VERBOSE>7) LOG("at29040a: invalid sector change (from %05x to %05x); cancel programming cycle\n",(offset & ~0xff), (m_programming_last_offset & ~0xff)); | |
| 367 | m_pgm = PGM_0; | |
| 368 | m_enabling_sdb = false; | |
| 369 | m_disabling_sdb = false; | |
| 370 | m_programming_timer->adjust(attotime::never); | |
| 371 | } | |
| 372 | ||
| 373 | if (((m_pgm == PGM_0) && !m_sdp) // write directly | |
| 374 | || (m_pgm == PGM_1)) // write after unlocking | |
| 375 | { | |
| 376 | if (((offset < BOOT_BLOCK_SIZE) && m_lower_bbl) | |
| 377 | || ((offset >= FEEPROM_SIZE-BOOT_BLOCK_SIZE) && m_higher_bbl)) | |
| 378 | { | |
| 379 | // attempt to access a locked out boot block: cancel programming | |
| 380 | // command if necessary | |
| 381 | if (VERBOSE>7) LOG("at29040a: attempt to access a locked out boot block: offset = %05x, lowblock=%d, highblock=%d\n", offset, m_lower_bbl, m_higher_bbl); | |
| 382 | ||
| 383 | m_pgm = PGM_0; | |
| 384 | m_enabling_sdb = false; | |
| 385 | m_disabling_sdb = false; | |
| 386 | } | |
| 387 | else | |
| 388 | { /* enter programming mode */ | |
| 389 | if (VERBOSE>7) LOG("at29040a: enter programming mode (m_pgm=%d)\n", m_pgm); | |
| 390 | memset(m_programming_buffer, 0xff, SECTOR_SIZE); | |
| 391 | m_pgm = PGM_2; | |
| 392 | } | |
| 393 | } | |
| 394 | if (m_pgm == PGM_2) | |
| 395 | { | |
| 396 | /* write data to programming buffer */ | |
| 397 | if (VERBOSE>7) LOG("at29040a: Write data to programming buffer\n"); | |
| 398 | m_programming_buffer[offset & 0xff] = data; | |
| 399 | m_programming_last_offset = offset; | |
| 400 | m_programming_timer->adjust(attotime::from_usec(150)); // next byte must be written before the timer expires | |
| 401 | } | |
| 402 | } | |
| 403 | ||
| 404 | void at29040a_device::device_start(void) | |
| 405 | { | |
| 406 | m_programming_buffer = (UINT8*)malloc(SECTOR_SIZE); | |
| 407 | m_programming_timer = timer_alloc(PRG_TIMER); | |
| 408 | ||
| 409 | m_eememory = (UINT8*)malloc(FEEPROM_SIZE+2); | |
| 410 | } | |
| 411 | ||
| 412 | void at29040a_device::device_stop(void) | |
| 413 | { | |
| 414 | free(m_programming_buffer); | |
| 415 | free(m_eememory); | |
| 416 | } | |
| 417 | ||
| 418 | void at29040a_device::device_reset(void) | |
| 419 | { | |
| 420 | if (m_eememory[0] != VERSION) | |
| 421 | { | |
| 422 | if (VERBOSE>1) LOG("AT29040A: Warning: Version mismatch; expected %d but found %d for %s. Resetting.\n", VERSION, m_eememory[0], tag()); | |
| 423 | m_eememory[0] = 0; | |
| 424 | m_eememory[1] = 0; | |
| 425 | } | |
| 426 | ||
| 427 | m_lower_bbl = ((m_eememory[1] & 0x04)!=0); | |
| 428 | m_higher_bbl = ((m_eememory[1] & 0x02)!=0); | |
| 429 | m_sdp = ((m_eememory[1] & 0x01)!=0); | |
| 430 | ||
| 431 | if (VERBOSE>7) LOG("at29040a (%s): LowerBBL = %d, HigherBBL = %d, SoftDataProt = %d\n", tag(), m_lower_bbl, m_higher_bbl, m_sdp); | |
| 432 | ||
| 433 | m_id_mode = false; | |
| 434 | m_cmd = CMD_0; | |
| 435 | m_enabling_bbl = false; | |
| 436 | m_long_sequence = false; | |
| 437 | m_pgm = PGM_0; | |
| 438 | m_enabling_sdb = false; | |
| 439 | m_disabling_sdb = false; | |
| 440 | m_toggle_bit = false; | |
| 441 | m_programming_last_offset = 0; | |
| 442 | } | |
| 443 | ||
| 444 | const device_type AT29040A = &device_creator<at29040a_device>; |
| r21684 | r21685 | |
|---|---|---|
| 1 | /* | |
| 2 | ATMEL 29040a | |
| 3 | ||
| 4 | Michael Zapf | |
| 5 | September 2010: Rewritten as device | |
| 6 | February 2012: Rewritten as class | |
| 7 | */ | |
| 8 | ||
| 9 | #ifndef __AT29040__ | |
| 10 | #define __AT29040__ | |
| 11 | ||
| 12 | #include "emu.h" | |
| 13 | ||
| 14 | extern const device_type AT29040A; | |
| 15 | ||
| 16 | /* | |
| 17 | at29c40a state | |
| 18 | ||
| 19 | Command states (CMD_0 is the initial state): | |
| 20 | CMD_0: default state | |
| 21 | CMD_1: state after writing aa to 5555 | |
| 22 | CMD_2: state after writing 55 to 2aaa | |
| 23 | ||
| 24 | Programming states (s_programming_0 is the initial state): | |
| 25 | PGM_0: default state | |
| 26 | PGM_1: a program and enable/disable lock command has been executed, but programming has not actually started. | |
| 27 | PGM_2: the programming buffer is being written to | |
| 28 | PGM_3: the programming buffer is being burnt to flash ROM | |
| 29 | */ | |
| 30 | enum s_cmd_t | |
| 31 | { | |
| 32 | CMD_0 = 0x0, | |
| 33 | CMD_1 = 0x1, | |
| 34 | CMD_2 = 0x2 | |
| 35 | }; | |
| 36 | ||
| 37 | enum s_pgm_t | |
| 38 | { | |
| 39 | PGM_0 = 0x0, | |
| 40 | PGM_1 = 0x1, | |
| 41 | PGM_2 = 0x2, | |
| 42 | PGM_3 = 0x3 | |
| 43 | }; | |
| 44 | ||
| 45 | class at29040a_device : public device_t, public device_nvram_interface | |
| 46 | { | |
| 47 | public: | |
| 48 | at29040a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); | |
| 49 | DECLARE_READ8_MEMBER( read ); | |
| 50 | DECLARE_WRITE8_MEMBER( write ); | |
| 51 | ||
| 52 | protected: | |
| 53 | virtual void device_start(void); | |
| 54 | virtual void device_reset(void); | |
| 55 | virtual void device_stop(void); | |
| 56 | virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); | |
| 57 | ||
| 58 | void nvram_default(); | |
| 59 | void nvram_read(emu_file &file); | |
| 60 | void nvram_write(emu_file &file); | |
| 61 | ||
| 62 | private: | |
| 63 | void sync_flags(void); | |
| 64 | ||
| 65 | UINT8* m_eememory; | |
| 66 | ||
| 67 | bool m_lower_bbl; /* set when lower boot block lockout is enabled */ | |
| 68 | bool m_higher_bbl; /* set when upper boot block lockout is enabled */ | |
| 69 | bool m_sdp; /* set when in software data protect mode */ | |
| 70 | ||
| 71 | bool m_id_mode; /* set when in chip id mode */ | |
| 72 | s_cmd_t m_cmd; /* command state */ | |
| 73 | bool m_enabling_bbl; /* set when a boot block lockout command is expecting its parameter */ | |
| 74 | bool m_long_sequence; /* set if 0x80 command has just been executed (some command require this prefix) */ | |
| 75 | s_pgm_t m_pgm; /* programming state */ | |
| 76 | bool m_enabling_sdb; /* set when a sdp enable command is in progress */ | |
| 77 | bool m_disabling_sdb; /* set when a sdp disable command is in progress */ | |
| 78 | bool m_dirty; /* set when the memory contents should be set */ | |
| 79 | bool m_toggle_bit; // indicates flashing in progress (toggles for each query) | |
| 80 | UINT8* m_programming_buffer; | |
| 81 | int m_programming_last_offset; | |
| 82 | emu_timer* m_programming_timer; | |
| 83 | }; | |
| 84 | ||
| 85 | #define MCFG_AT29040A_ADD(_tag ) \ | |
| 86 | MCFG_DEVICE_ADD(_tag, AT29040A, 0) | |
| 87 | ||
| 88 | #endif |
| r21684 | r21685 | |
|---|---|---|
| 1 | /********************************************************************* | |
| 2 | ||
| 3 | er59256.c | |
| 4 | ||
| 5 | Microchip ER59256 serial eeprom. | |
| 6 | ||
| 7 | ||
| 8 | *********************************************************************/ | |
| 9 | ||
| 10 | #include "emu.h" | |
| 11 | #include "er59256.h" | |
| 12 | ||
| 13 | /* LOGLEVEL 0=no logging, 1=just commands and data, 2=everything ! */ | |
| 14 | ||
| 15 | #define LOGLEVEL 0 | |
| 16 | ||
| 17 | #define LOG(level,...) if(LOGLEVEL>=level) logerror(__VA_ARGS__) | |
| 18 | #define LOG_BITS(bits) logerror("CS=%d CK=%d DI=%d DO=%d", (bits&CS_MASK) ? 1 : 0, (bits&CK_MASK) ? 1 : 0, (bits&DI_MASK) ? 1 : 0, (bits&DO_MASK) ? 1 : 0) | |
| 19 | ||
| 20 | /*************************************************************************** | |
| 21 | TYPE DEFINITIONS | |
| 22 | ***************************************************************************/ | |
| 23 | ||
| 24 | struct er59256_t | |
| 25 | { | |
| 26 | /* The actual memory */ | |
| 27 | UINT16 eerom[EEROM_WORDS]; | |
| 28 | ||
| 29 | /* Bits as they appear on the io pins, current state */ | |
| 30 | UINT8 io_bits; | |
| 31 | ||
| 32 | /* Bits as they appear on the io pins, previous state */ | |
| 33 | UINT8 old_io_bits; | |
| 34 | ||
| 35 | ||
| 36 | /* the 16 bit shift in/out reg */ | |
| 37 | UINT16 in_shifter; | |
| 38 | UINT32 out_shifter; | |
| 39 | ||
| 40 | /* Count of bits received since last CS low->high */ | |
| 41 | UINT8 bitcount; | |
| 42 | ||
| 43 | /* Command & addresss */ | |
| 44 | UINT8 command; | |
| 45 | ||
| 46 | /* Write enable and write in progress flags */ | |
| 47 | UINT8 flags; | |
| 48 | }; | |
| 49 | ||
| 50 | /*************************************************************************** | |
| 51 | FUNCTION PROTOTYPES | |
| 52 | ************************************************************************/ | |
| 53 | ||
| 54 | static void decode_command(er59256_t *er59256); | |
| 55 | ||
| 56 | /*************************************************************************** | |
| 57 | INLINE FUNCTIONS | |
| 58 | ***************************************************************************/ | |
| 59 | ||
| 60 | INLINE er59256_t *get_token(device_t *device) | |
| 61 | { | |
| 62 | assert(device->type() == ER59256); | |
| 63 | return (er59256_t *) downcast<er59256_device *>(device)->token(); | |
| 64 | } | |
| 65 | ||
| 66 | ||
| 67 | /*************************************************************************** | |
| 68 | IMPLEMENTATION | |
| 69 | ***************************************************************************/ | |
| 70 | ||
| 71 | void er59256_preload_rom(device_t *device, const UINT16 *rom_data, int count) | |
| 72 | { | |
| 73 | er59256_t *er59256 = get_token(device); | |
| 74 | int WordNo; | |
| 75 | ||
| 76 | logerror("Preloading %d words of data\n",count); | |
| 77 | ||
| 78 | if(count>EEROM_WORDS) | |
| 79 | memcpy(&er59256->eerom,rom_data,count*2); | |
| 80 | else | |
| 81 | memcpy(&er59256->eerom,rom_data,EEROM_WORDS*2); | |
| 82 | ||
| 83 | for(WordNo=0;WordNo<EEROM_WORDS;WordNo++) | |
| 84 | logerror("%04X ",er59256->eerom[WordNo]); | |
| 85 | ||
| 86 | logerror("\n"); | |
| 87 | } | |
| 88 | ||
| 89 | UINT8 er59256_data_loaded(device_t *device) | |
| 90 | { | |
| 91 | er59256_t *er59256 = get_token(device); | |
| 92 | ||
| 93 | return (er59256->flags & FLAG_DATA_LOADED) ? 1 : 0; | |
| 94 | } | |
| 95 | ||
| 96 | /*------------------------------------------------- | |
| 97 | DEVICE_START( er59256 ) | |
| 98 | -------------------------------------------------*/ | |
| 99 | ||
| 100 | static DEVICE_START( er59256 ) | |
| 101 | { | |
| 102 | er59256_t *er59256 = get_token(device); | |
| 103 | ||
| 104 | memset(er59256, 0x00, sizeof(er59256_t)); | |
| 105 | ||
| 106 | // Start with rom defaulted to erased | |
| 107 | memset(&er59256->eerom, 0xFF, EEROM_WORDS*2); | |
| 108 | ||
| 109 | er59256->command=CMD_INVALID; | |
| 110 | ||
| 111 | er59256->flags&= ~FLAG_DATA_LOADED; | |
| 112 | } | |
| 113 | ||
| 114 | static DEVICE_STOP( er59256 ) | |
| 115 | { | |
| 116 | /* Save contents of eerom */ | |
| 117 | } | |
| 118 | ||
| 119 | void er59256_set_iobits(device_t *device, UINT8 newbits) | |
| 120 | { | |
| 121 | er59256_t *er59256 = get_token(device); | |
| 122 | //UINT32 bit; | |
| 123 | ||
| 124 | // Make sure we only apply valid bits | |
| 125 | newbits&=ALL_MASK; | |
| 126 | ||
| 127 | if(LOGLEVEL>1) | |
| 128 | { | |
| 129 | logerror("er59256:newbits=%02X : ",newbits); | |
| 130 | LOG_BITS(newbits); | |
| 131 | logerror(" io_bits=%02X : ",er59256->io_bits); | |
| 132 | LOG_BITS(er59256->io_bits); | |
| 133 | logerror(" old_io_bits=%02X : ",er59256->old_io_bits); | |
| 134 | LOG_BITS(er59256->old_io_bits); | |
| 135 | logerror(" bitcount=%d, in_shifter=%04X, out_shifter=%05X, flags=%02X\n",er59256->bitcount,er59256->in_shifter,er59256->out_shifter,er59256->flags); | |
| 136 | } | |
| 137 | // Only do anything if the inputs have changed | |
| 138 | if((newbits&IN_MASK)!=(er59256->io_bits&IN_MASK)) | |
| 139 | { | |
| 140 | // save the current state, then set the new one, remembering to preserve data out | |
| 141 | er59256->old_io_bits=er59256->io_bits; | |
| 142 | er59256->io_bits=(newbits & ~DO_MASK) | (er59256->old_io_bits&DO_MASK); | |
| 143 | ||
| 144 | if(CS_RISE(er59256)) | |
| 145 | { | |
| 146 | er59256->flags&=~FLAG_START_BIT; | |
| 147 | er59256->command=CMD_INVALID; | |
| 148 | } | |
| 149 | ||
| 150 | if(LOGLEVEL>1) | |
| 151 | { | |
| 152 | if(CK_RISE(er59256)) logerror("er59256:CK rise\n"); | |
| 153 | if(CS_RISE(er59256)) logerror("er59256:CS rise\n"); | |
| 154 | if(CK_FALL(er59256)) logerror("er59256:CK fall\n"); | |
| 155 | if(CS_FALL(er59256)) logerror("er59256:CS fall\n"); | |
| 156 | } | |
| 157 | ||
| 158 | if(CK_RISE(er59256) && CS_VALID(er59256)) | |
| 159 | { | |
| 160 | if((STARTED(er59256)==0) && (GET_DI(er59256)==1)) | |
| 161 | { | |
| 162 | er59256->bitcount=0; | |
| 163 | er59256->flags|=FLAG_START_BIT; | |
| 164 | } | |
| 165 | else | |
| 166 | { | |
| 167 | SHIFT_IN(er59256); | |
| 168 | er59256->bitcount++; | |
| 169 | ||
| 170 | if(er59256->bitcount==CMD_BITLEN) | |
| 171 | decode_command(er59256); | |
| 172 | ||
| 173 | if((er59256->bitcount==WRITE_BITLEN) && ((er59256->command & CMD_MASK)==CMD_WRITE)) | |
| 174 | { | |
| 175 | er59256->eerom[er59256->command & ADDR_MASK]=er59256->in_shifter; | |
| 176 | LOG(1,"er59256:write[%02X]=%04X\n",(er59256->command & ADDR_MASK),er59256->in_shifter); | |
| 177 | er59256->command=CMD_INVALID; | |
| 178 | } | |
| 179 | LOG(1,"out_shifter=%05X, io_bits=%02X\n",er59256->out_shifter,er59256->io_bits); | |
| 180 | SHIFT_OUT(er59256); | |
| 181 | } | |
| 182 | ||
| 183 | LOG(2,"io_bits:out=%02X\n",er59256->io_bits); | |
| 184 | } | |
| 185 | } | |
| 186 | } | |
| 187 | ||
| 188 | UINT8 er59256_get_iobits(device_t *device) | |
| 189 | { | |
| 190 | er59256_t *er59256 = get_token(device); | |
| 191 | ||
| 192 | return er59256->io_bits; | |
| 193 | } | |
| 194 | ||
| 195 | ||
| 196 | static void decode_command(er59256_t *er59256) | |
| 197 | { | |
| 198 | er59256->out_shifter=0x0000; | |
| 199 | er59256->command=(er59256->in_shifter & (CMD_MASK | ADDR_MASK)); | |
| 200 | ||
| 201 | switch(er59256->command & CMD_MASK) | |
| 202 | { | |
| 203 | case CMD_READ : er59256->out_shifter=er59256->eerom[er59256->command & ADDR_MASK]; | |
| 204 | LOG(1,"er59256:read[%02X]=%04X\n",(er59256->command&ADDR_MASK),er59256->eerom[er59256->command & ADDR_MASK]); | |
| 205 | break; | |
| 206 | case CMD_WRITE : break; | |
| 207 | case CMD_ERASE : if (WRITE_ENABLED(er59256)) er59256->eerom[er59256->command & ADDR_MASK]=0xFF; | |
| 208 | LOG(1,"er59256:erase[%02X]\n",(er59256->command&ADDR_MASK)); | |
| 209 | break; | |
| 210 | case CMD_EWEN : er59256->flags|=FLAG_WRITE_EN; | |
| 211 | LOG(1,"er59256:erase/write enabled\n"); | |
| 212 | break; | |
| 213 | case CMD_EWDS : er59256->flags&=~FLAG_WRITE_EN; | |
| 214 | LOG(1,"er59256:erase/write disabled\n"); | |
| 215 | break; | |
| 216 | case CMD_ERAL : if (WRITE_ENABLED(er59256)) memset(&er59256->eerom, 0xFF, EEROM_WORDS*2); | |
| 217 | LOG(1,"er59256:erase all\n"); | |
| 218 | break; | |
| 219 | } | |
| 220 | ||
| 221 | if ((er59256->command & CMD_MASK)!=CMD_WRITE) | |
| 222 | er59256->command=CMD_INVALID; | |
| 223 | } | |
| 224 | ||
| 225 | const device_type ER59256 = &device_creator<er59256_device>; | |
| 226 | ||
| 227 | er59256_device::er59256_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) | |
| 228 | : device_t(mconfig, ER59256, "Microchip ER59256 serial eeprom.", tag, owner, clock) | |
| 229 | { | |
| 230 | m_token = global_alloc_clear(er59256_t); | |
| 231 | } | |
| 232 | ||
| 233 | //------------------------------------------------- | |
| 234 | // device_config_complete - perform any | |
| 235 | // operations now that the configuration is | |
| 236 | // complete | |
| 237 | //------------------------------------------------- | |
| 238 | ||
| 239 | void er59256_device::device_config_complete() | |
| 240 | { | |
| 241 | } | |
| 242 | ||
| 243 | //------------------------------------------------- | |
| 244 | // device_start - device-specific startup | |
| 245 | //------------------------------------------------- | |
| 246 | ||
| 247 | void er59256_device::device_start() | |
| 248 | { | |
| 249 | DEVICE_START_NAME( er59256 )(this); | |
| 250 | } | |
| 251 | ||
| 252 | //------------------------------------------------- | |
| 253 | // device_stop - device-specific stop | |
| 254 | //------------------------------------------------- | |
| 255 | ||
| 256 | void er59256_device::device_stop() | |
| 257 | { | |
| 258 | DEVICE_STOP_NAME( er59256 )(this); | |
| 259 | } |
| r21684 | r21685 | |
|---|---|---|
| 1 | /********************************************************************* | |
| 2 | ||
| 3 | er59256.h | |
| 4 | ||
| 5 | Microchip ER59256 serial eeprom. | |
| 6 | ||
| 7 | ||
| 8 | *********************************************************************/ | |
| 9 | ||
| 10 | #ifndef _ER59256_H_ | |
| 11 | #define _ER59256_H_ | |
| 12 | ||
| 13 | /*************************************************************************** | |
| 14 | MACROS | |
| 15 | ***************************************************************************/ | |
| 16 | ||
| 17 | class er59256_device : public device_t | |
| 18 | { | |
| 19 | public: | |
| 20 | er59256_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); | |
| 21 | ~er59256_device() { global_free(m_token); } | |
| 22 | ||
| 23 | // access to legacy token | |
| 24 | void *token() const { assert(m_token != NULL); return m_token; } | |
| 25 | protected: | |
| 26 | // device-level overrides | |
| 27 | virtual void device_config_complete(); | |
| 28 | virtual void device_start(); | |
| 29 | virtual void device_stop(); | |
| 30 | private: | |
| 31 | // internal state | |
| 32 | void *m_token; | |
| 33 | }; | |
| 34 | ||
| 35 | extern const device_type ER59256; | |
| 36 | ||
| 37 | ||
| 38 | #define MCFG_ER59256_ADD(_tag) \ | |
| 39 | MCFG_DEVICE_ADD((_tag), ER59256, 0) | |
| 40 | ||
| 41 | /*************************************************************************** | |
| 42 | CONSTANTS | |
| 43 | ***************************************************************************/ | |
| 44 | ||
| 45 | #define EEROM_WORDS 0x10 | |
| 46 | ||
| 47 | #define CK_SHIFT 0x00 | |
| 48 | #define DI_SHIFT 0x01 | |
| 49 | #define DO_SHIFT 0x02 | |
| 50 | #define CS_SHIFT 0x03 | |
| 51 | ||
| 52 | #define CK_MASK (1<<CK_SHIFT) | |
| 53 | #define DI_MASK (1<<DI_SHIFT) | |
| 54 | #define DO_MASK (1<<DO_SHIFT) | |
| 55 | #define CS_MASK (1<<CS_SHIFT) | |
| 56 | ||
| 57 | #define ALL_MASK (CK_MASK | DI_MASK | DO_MASK | CS_MASK) | |
| 58 | #define IN_MASK (CK_MASK | DI_MASK | CS_MASK) | |
| 59 | ||
| 60 | #define GET_CK(eep) ((eep->io_bits & CK_MASK) >> CK_SHIFT) | |
| 61 | #define GET_DI(eep) ((eep->io_bits & DI_MASK) >> DI_SHIFT) | |
| 62 | #define GET_DO(eep) ((eep->io_bits & DO_MASK) >> DO_SHIFT) | |
| 63 | #define GET_CS(eep) ((eep->io_bits & CS_MASK) >> CS_SHIFT) | |
| 64 | ||
| 65 | #define SET_CK(eep,data) eep->io_bits=((eep->io_bits & ~CK_MASK) | ((data & 0x01) << CK_SHIFT)) | |
| 66 | #define SET_DI(eep,data) eep->io_bits=((eep->io_bits & ~DI_MASK) | ((data & 0x01) << DI_SHIFT)) | |
| 67 | #define SET_DO(eep,data) eep->io_bits=((eep->io_bits & ~DO_MASK) | ((data & 0x01) << DO_SHIFT)) | |
| 68 | #define SET_CS(eep,data) eep->io_bits=((eep->io_bits & ~CS_MASK) | ((data & 0x01) << CS_SHIFT)) | |
| 69 | ||
| 70 | #define CK_RISE(eep) ((eep->io_bits & CK_MASK) & ~(eep->old_io_bits & CK_MASK)) | |
| 71 | #define CS_RISE(eep) ((eep->io_bits & CS_MASK) & ~(eep->old_io_bits & CS_MASK)) | |
| 72 | #define CS_VALID(eep) ((eep->io_bits & CS_MASK) & (eep->old_io_bits & CS_MASK)) | |
| 73 | ||
| 74 | #define CK_FALL(eep) (~(eep->io_bits & CK_MASK) & (eep->old_io_bits & CK_MASK)) | |
| 75 | #define CS_FALL(eep) (~(eep->io_bits & CS_MASK) & (eep->old_io_bits & CS_MASK)) | |
| 76 | ||
| 77 | ||
| 78 | #define SHIFT_IN(eep) eep->in_shifter=(eep->in_shifter<<1) | GET_DI(eep) | |
| 79 | #define SHIFT_OUT(eep) SET_DO(eep,(eep->out_shifter & 0x10000)>>16); eep->out_shifter=(eep->out_shifter<<1) | |
| 80 | ||
| 81 | #define CMD_READ 0x80 | |
| 82 | #define CMD_WRITE 0x40 | |
| 83 | #define CMD_ERASE 0xC0 | |
| 84 | #define CMD_EWEN 0x30 | |
| 85 | #define CMD_EWDS 0x00 | |
| 86 | #define CMD_ERAL 0x20 | |
| 87 | #define CMD_INVALID 0xF0 | |
| 88 | ||
| 89 | #define CMD_MASK 0xF0 | |
| 90 | #define ADDR_MASK 0x0F | |
| 91 | ||
| 92 | // CMD_BITLEN is 1 start bit plus 4 command bits plus 4 address bits | |
| 93 | #define CMD_BITLEN 8 | |
| 94 | #define DATA_BITLEN 16 | |
| 95 | #define WRITE_BITLEN CMD_BITLEN+DATA_BITLEN | |
| 96 | ||
| 97 | #define FLAG_WRITE_EN 0x01 | |
| 98 | #define FLAG_START_BIT 0x02 | |
| 99 | #define FLAG_DATA_LOADED 0x04 | |
| 100 | ||
| 101 | #define WRITE_ENABLED(eep) ((eep->flags & FLAG_WRITE_EN) ? 1 : 0) | |
| 102 | #define STARTED(eep) ((eep->flags & FLAG_START_BIT) ? 1 : 0) | |
| 103 | ||
| 104 | /*************************************************************************** | |
| 105 | FUNCTION PROTOTYPES | |
| 106 | ***************************************************************************/ | |
| 107 | ||
| 108 | void er59256_set_iobits(device_t *device, UINT8 newbits); | |
| 109 | UINT8 er59256_get_iobits(device_t *device); | |
| 110 | void er59256_preload_rom(device_t *device, const UINT16 *rom_data, int count); | |
| 111 | UINT8 er59256_data_loaded(device_t *device); | |
| 112 | #endif |
| r21684 | r21685 | |
|---|---|---|
| 1 | /***************************************************************************** | |
| 2 | * | |
| 3 | * machine/74145.c | |
| 4 | * | |
| 5 | * BCD-to-Decimal decoder | |
| 6 | * | |
| 7 | * __ __ | |
| 8 | * 0-| v |-VCC | |
| 9 | * 1-| |-A | |
| 10 | * 2-| |-B | |
| 11 | * 3-| |-C | |
| 12 | * 4-| |-D | |
| 13 | * 5-| |-9 | |
| 14 | * 6-| |-8 | |
| 15 | * GND-|_____|-7 | |
| 16 | * | |
| 17 | * | |
| 18 | * Truth table | |
| 19 | * _______________________________ | |
| 20 | * | Inputs | Outputs | | |
| 21 | * | D C B A | 0 1 2 3 4 5 6 7 8 9 | | |
| 22 | * |-------------------------------| | |
| 23 | * | L L L L | L H H H H H H H H H | | |
| 24 | * | L L L H | H L H H H H H H H H | | |
| 25 | * | L L H L | H H L H H H H H H H | | |
| 26 | * | L L H H | H H H L H H H H H H | | |
| 27 | * | L H L L | H H H H L H H H H H | | |
| 28 | * |-------------------------------| | |
| 29 | * | L H L H | H H H H H L H H H H | | |
| 30 | * | L H H L | H H H H H H L H H H | | |
| 31 | * | L H H H | H H H H H H H L H H | | |
| 32 | * | H L L L | H H H H H H H H L H | | |
| 33 | * | H L L H | H H H H H H H H H L | | |
| 34 | * |-------------------------------| | |
| 35 | * | H L H L | H H H H H H H H H H | | |
| 36 | * | H L H H | H H H H H H H H H H | | |
| 37 | * | H H L L | H H H H H H H H H H | | |
| 38 | * | H H L H | H H H H H H H H H H | | |
| 39 | * | H H H L | H H H H H H H H H H | | |
| 40 | * | H H H H | H H H H H H H H H H | | |
| 41 | * ------------------------------- | |
| 42 | * | |
| 43 | ****************************************************************************/ | |
| 44 | ||
| 45 | #include "emu.h" | |
| 46 | #include "74145.h" | |
| 47 | #include "coreutil.h" | |
| 48 | ||
| 49 | /***************************************************************************** | |
| 50 | GLOBAL VARIABLES | |
| 51 | *****************************************************************************/ | |
| 52 | ||
| 53 | const ttl74145_interface default_ttl74145 = | |
| 54 | { | |
| 55 | DEVCB_NULL, | |
| 56 | DEVCB_NULL, | |
| 57 | DEVCB_NULL, | |
| 58 | DEVCB_NULL, | |
| 59 | DEVCB_NULL, | |
| 60 | DEVCB_NULL, | |
| 61 | DEVCB_NULL, | |
| 62 | DEVCB_NULL, | |
| 63 | DEVCB_NULL, | |
| 64 | DEVCB_NULL | |
| 65 | }; | |
| 66 | ||
| 67 | ||
| 68 | const device_type TTL74145 = &device_creator<ttl74145_device>; | |
| 69 | ||
| 70 | /*************************************************************************** | |
| 71 | DEVICE INTERFACE | |
| 72 | ***************************************************************************/ | |
| 73 | //------------------------------------------------- | |
| 74 | // ttl74145_device - constructor | |
| 75 | //------------------------------------------------- | |
| 76 | ||
| 77 | ttl74145_device::ttl74145_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) | |
| 78 | : device_t(mconfig, TTL74145, "TTL74145", tag, owner, clock) | |
| 79 | , m_number(0) | |
| 80 | { | |
| 81 | } | |
| 82 | ||
| 83 | ||
| 84 | //------------------------------------------------- | |
| 85 | // device_start - device-specific startup | |
| 86 | //------------------------------------------------- | |
| 87 | ||
| 88 | void ttl74145_device::device_start() | |
| 89 | { | |
| 90 | /* resolve callbacks */ | |
| 91 | m_output_line_0_func.resolve(m_output_line_0_cb, *this); | |
| 92 | m_output_line_1_func.resolve(m_output_line_1_cb, *this); | |
| 93 | m_output_line_2_func.resolve(m_output_line_2_cb, *this); | |
| 94 | m_output_line_3_func.resolve(m_output_line_3_cb, *this); | |
| 95 | m_output_line_4_func.resolve(m_output_line_4_cb, *this); | |
| 96 | m_output_line_5_func.resolve(m_output_line_5_cb, *this); | |
| 97 | m_output_line_6_func.resolve(m_output_line_6_cb, *this); | |
| 98 | m_output_line_7_func.resolve(m_output_line_7_cb, *this); | |
| 99 | m_output_line_8_func.resolve(m_output_line_8_cb, *this); | |
| 100 | m_output_line_9_func.resolve(m_output_line_9_cb, *this); | |
| 101 | ||
| 102 | // register for state saving | |
| 103 | save_item(NAME(m_number)); | |
| 104 | } | |
| 105 | ||
| 106 | //------------------------------------------------- | |
| 107 | // device_config_complete - perform any | |
| 108 | // operations now that the configuration is | |
| 109 | // complete | |
| 110 | //------------------------------------------------- | |
| 111 | ||
| 112 | void ttl74145_device::device_config_complete() | |
| 113 | { | |
| 114 | // inherit a copy of the static data | |
| 115 | const ttl74145_interface *intf = reinterpret_cast<const ttl74145_interface *>(static_config()); | |
| 116 | if (intf != NULL) | |
| 117 | *static_cast<ttl74145_interface *>(this) = *intf; | |
| 118 | ||
| 119 | // or initialize to defaults if none provided | |
| 120 | else | |
| 121 | { | |
| 122 | memset(&m_output_line_0_cb, 0, sizeof(m_output_line_0_cb)); | |
| 123 | memset(&m_output_line_1_cb, 0, sizeof(m_output_line_1_cb)); | |
| 124 | memset(&m_output_line_2_cb, 0, sizeof(m_output_line_2_cb)); | |
| 125 | memset(&m_output_line_3_cb, 0, sizeof(m_output_line_3_cb)); | |
| 126 | memset(&m_output_line_4_cb, 0, sizeof(m_output_line_4_cb)); | |
| 127 | memset(&m_output_line_5_cb, 0, sizeof(m_output_line_5_cb)); | |
| 128 | memset(&m_output_line_6_cb, 0, sizeof(m_output_line_6_cb)); | |
| 129 | memset(&m_output_line_7_cb, 0, sizeof(m_output_line_7_cb)); | |
| 130 | memset(&m_output_line_8_cb, 0, sizeof(m_output_line_8_cb)); | |
| 131 | memset(&m_output_line_9_cb, 0, sizeof(m_output_line_9_cb)); | |
| 132 | } | |
| 133 | } | |
| 134 | ||
| 135 | //------------------------------------------------- | |
| 136 | // device_start - device-specific reset | |
| 137 | //------------------------------------------------- | |
| 138 | ||
| 139 | void ttl74145_device::device_reset() | |
| 140 | { | |
| 141 | m_number = 0; | |
| 142 | } | |
| 143 | ||
| 144 | /*************************************************************************** | |
| 145 | IMPLEMENTATION | |
| 146 | ***************************************************************************/ | |
| 147 | ||
| 148 | void ttl74145_device::write(UINT8 data) | |
| 149 | { | |
| 150 | /* decode number */ | |
| 151 | UINT16 new_number = bcd_2_dec(data & 0x0f); | |
| 152 | ||
| 153 | /* call output callbacks if the number changed */ | |
| 154 | if (new_number != m_number) | |
| 155 | { | |
| 156 | m_output_line_0_func(new_number == 0); | |
| 157 | m_output_line_1_func(new_number == 1); | |
| 158 | m_output_line_2_func(new_number == 2); | |
| 159 | m_output_line_3_func(new_number == 3); | |
| 160 | m_output_line_4_func(new_number == 4); | |
| 161 | m_output_line_5_func(new_number == 5); | |
| 162 | m_output_line_6_func(new_number == 6); | |
| 163 | m_output_line_7_func(new_number == 7); | |
| 164 | m_output_line_8_func(new_number == 8); | |
| 165 | m_output_line_9_func(new_number == 9); | |
| 166 | } | |
| 167 | ||
| 168 | /* update state */ | |
| 169 | m_number = new_number; | |
| 170 | } | |
| 171 | ||
| 172 | ||
| 173 | UINT16 ttl74145_device::read() | |
| 174 | { | |
| 175 | return (1 << m_number) & 0x3ff; | |
| 176 | } |
| r21684 | r21685 | |
|---|---|---|
| 1 | /*************************************************************************** | |
| 2 | ||
| 3 | TTL74145 | |
| 4 | ||
| 5 | BCD-to-Decimal decoder | |
| 6 | ||
| 7 | ***************************************************************************/ | |
| 8 | ||
| 9 | #ifndef __TTL74145_H__ | |
| 10 | #define __TTL74145_H__ | |
| 11 | ||
| 12 | //************************************************************************** | |
| 13 | // INTERFACE CONFIGURATION MACROS | |
| 14 | //************************************************************************** | |
| 15 | #define MCFG_TTL74145_ADD(_tag, _intf) \ | |
| 16 | MCFG_DEVICE_ADD(_tag, TTL74145, 0) \ | |
| 17 | MCFG_DEVICE_CONFIG(_intf) | |
| 18 | ||
| 19 | ||
| 20 | //************************************************************************** | |
| 21 | // TYPE DEFINITIONS | |
| 22 | //************************************************************************** | |
| 23 | ||
| 24 | // ======================> ttl74145_interface | |
| 25 | ||
| 26 | struct ttl74145_interface | |
| 27 | { | |
| 28 | devcb_write_line m_output_line_0_cb; | |
| 29 | devcb_write_line m_output_line_1_cb; | |
| 30 | devcb_write_line m_output_line_2_cb; | |
| 31 | devcb_write_line m_output_line_3_cb; | |
| 32 | devcb_write_line m_output_line_4_cb; | |
| 33 | devcb_write_line m_output_line_5_cb; | |
| 34 | devcb_write_line m_output_line_6_cb; | |
| 35 | devcb_write_line m_output_line_7_cb; | |
| 36 | devcb_write_line m_output_line_8_cb; | |
| 37 | devcb_write_line m_output_line_9_cb; | |
| 38 | }; | |
| 39 | ||
| 40 | // ======================> ttl74145_device | |
| 41 | ||
| 42 | class ttl74145_device : public device_t, | |
| 43 | public ttl74145_interface | |
| 44 | { | |
| 45 | public: | |
| 46 | // construction/destruction | |
| 47 | ttl74145_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); | |
| 48 | ||
| 49 | UINT16 read(); | |
| 50 | void write(UINT8 data); | |
| 51 | protected: | |
| 52 | // device-level overrides | |
| 53 | virtual void device_start(); | |
| 54 | virtual void device_reset(); | |
| 55 | virtual void device_config_complete(); | |
| 56 | ||
| 57 | private: | |
| 58 | devcb_resolved_write_line m_output_line_0_func; | |
| 59 | devcb_resolved_write_line m_output_line_1_func; | |
| 60 | devcb_resolved_write_line m_output_line_2_func; | |
| 61 | devcb_resolved_write_line m_output_line_3_func; | |
| 62 | devcb_resolved_write_line m_output_line_4_func; | |
| 63 | devcb_resolved_write_line m_output_line_5_func; | |
| 64 | devcb_resolved_write_line m_output_line_6_func; | |
| 65 | devcb_resolved_write_line m_output_line_7_func; | |
| 66 | devcb_resolved_write_line m_output_line_8_func; | |
| 67 | devcb_resolved_write_line m_output_line_9_func; | |
| 68 | ||
| 69 | /* decoded number */ | |
| 70 | UINT16 m_number; | |
| 71 | }; | |
| 72 | ||
| 73 | // device type definition | |
| 74 | extern const device_type TTL74145; | |
| 75 | ||
| 76 | //************************************************************************** | |
| 77 | // DEFAULT INTERFACES | |
| 78 | //************************************************************************** | |
| 79 | ||
| 80 | extern const ttl74145_interface default_ttl74145; | |
| 81 | ||
| 82 | ||
| 83 | #endif /* TTL74145 */ |
| r21684 | r21685 | |
|---|---|---|
| 1 | /********************************************************************* | |
| 2 | ||
| 3 | Philips PCF8593 CMOS clock/calendar circuit | |
| 4 | ||
| 5 | (c) 2001-2007 Tim Schuerewegen | |
| 6 | ||
| 7 | *********************************************************************/ | |
| 8 | ||
| 9 | #include "pcf8593.h" | |
| 10 | ||
| 11 | ||
| 12 | /*************************************************************************** | |
| 13 | PARAMETERS/CONSTANTS/MACROS | |
| 14 | ***************************************************************************/ | |
| 15 | ||
| 16 | #define LOG_LEVEL 1 | |
| 17 | #define _logerror(level,x) do { if (LOG_LEVEL > level) logerror x; } while (0) | |
| 18 | ||
| 19 | // get/set date | |
| 20 | #define RTC_GET_DATE_YEAR ((m_data[5] >> 6) & 3) | |
| 21 | #define RTC_SET_DATE_YEAR(x) m_data[5] = (m_data[5] & 0x3F) | (((x) % 4) << 6) | |
| 22 | #define RTC_GET_DATE_MONTH bcd_to_integer( m_data[6]) | |
| 23 | #define RTC_SET_DATE_MONTH(x) m_data[6] = convert_to_bcd( x) | |
| 24 | #define RTC_GET_DATE_DAY (bcd_to_integer( m_data[5] & 0x3F)) | |
| 25 | #define RTC_SET_DATE_DAY(x) m_data[5] = (m_data[5] & 0xC0) | convert_to_bcd( x) | |
| 26 | ||
| 27 | // get/set time | |
| 28 | #define RTC_GET_TIME_HOUR bcd_to_integer( m_data[4]) | |
| 29 | #define RTC_SET_TIME_HOUR(x) m_data[4] = convert_to_bcd( x) | |
| 30 | #define RTC_GET_TIME_MINUTE bcd_to_integer( m_data[3]) | |
| 31 | #define RTC_SET_TIME_MINUTE(x) m_data[3] = convert_to_bcd( x) | |
| 32 | #define RTC_GET_TIME_SECOND bcd_to_integer( m_data[2]) | |
| 33 | #define RTC_SET_TIME_SECOND(x) m_data[2] = convert_to_bcd( x) | |
| 34 | ||
| 35 | ||
| 36 | //************************************************************************** | |
| 37 | // GLOBAL VARIABLES | |
| 38 | //************************************************************************** | |
| 39 | ||
| 40 | const device_type PCF8593 = &device_creator<pcf8593_device>; | |
| 41 | ||
| 42 | ||
| 43 | //------------------------------------------------- | |
| 44 | // pcf8593_device - constructor | |
| 45 | //------------------------------------------------- | |
| 46 | ||
| 47 | pcf8593_device::pcf8593_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) | |
| 48 | : device_t(mconfig, PCF8593, "PCF8593 RTC", tag, owner, clock), | |
| 49 | device_rtc_interface(mconfig, *this), | |
| 50 | device_nvram_interface(mconfig, *this) | |
| 51 | { | |
| 52 | } | |
| 53 | ||
| 54 | ||
| 55 | //------------------------------------------------- | |
| 56 | // device_start - device-specific startup | |
| 57 | //------------------------------------------------- | |
| 58 | ||
| 59 | void pcf8593_device::device_start() | |
| 60 | { | |
| 61 | _logerror( 0, ("pcf8593_init\n")); | |
| 62 | memset(m_register, 0, sizeof(m_register)); | |
| 63 | m_timer = timer_alloc(TIMER_UPDATE_COUNTER); | |
| 64 | m_timer->adjust(attotime::from_seconds(1), 0, attotime::from_seconds(1)); | |
| 65 | } | |
| 66 | ||
| 67 | //------------------------------------------------- | |
| 68 | // device_reset - device-specific reset | |
| 69 | //------------------------------------------------- | |
| 70 | ||
| 71 | void pcf8593_device::device_reset() | |
| 72 | { | |
| 73 | _logerror( 0, ("pcf8593_reset\n")); | |
| 74 | m_pin_scl = 1; | |
| 75 | m_pin_sda = 1; | |
| 76 | m_active = FALSE; | |
| 77 | m_inp = 0; | |
| 78 | m_mode = RTC_MODE_RECV; | |
| 79 | m_bits = 0; | |
| 80 | m_pos = 0; | |
| 81 | clear_buffer_rx(); | |
| 82 | set_time(true, RTC_GET_DATE_YEAR, RTC_GET_DATE_MONTH, RTC_GET_DATE_DAY, 0, RTC_GET_TIME_HOUR, RTC_GET_TIME_MINUTE, RTC_GET_TIME_SECOND); | |
| 83 | } | |
| 84 | ||
| 85 | ||
| 86 | //------------------------------------------------- | |
| 87 | // device_timer - handler timer events | |
| 88 | //------------------------------------------------- | |
| 89 | ||
| 90 | void pcf8593_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) | |
| 91 | { | |
| 92 | switch(id) | |
| 93 | { | |
| 94 | case TIMER_UPDATE_COUNTER: | |
| 95 | _logerror( 2, ("pcf8593_timer_callback (%d)\n", param)); | |
| 96 | // check if counting is enabled | |
| 97 | if (!(m_data[0] & 0x80)) | |
| 98 | advance_seconds(); | |
| 99 | break; | |
| 100 | } | |
| 101 | } | |
| 102 | ||
| 103 | ||
| 104 | //------------------------------------------------- | |
| 105 | // rtc_clock_updated - | |
| 106 | //------------------------------------------------- | |
| 107 | ||
| 108 | void pcf8593_device::rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second) | |
| 109 | { | |
| 110 | RTC_SET_TIME_SECOND(second); | |
| 111 | RTC_SET_TIME_MINUTE(minute); | |
| 112 | RTC_SET_TIME_HOUR(hour); | |
| 113 | RTC_SET_DATE_DAY(day); | |
| 114 | RTC_SET_DATE_MONTH(month); | |
| 115 | RTC_SET_DATE_YEAR(year); | |
| 116 | } | |
| 117 | ||
| 118 | ||
| 119 | //------------------------------------------------- | |
| 120 | // nvram_default - called to initialize NVRAM to | |
| 121 | // its default state | |
| 122 | //------------------------------------------------- | |
| 123 | ||
| 124 | void pcf8593_device::nvram_default() | |
| 125 | { | |
| 126 | memset(m_data, 0, sizeof(m_data)); | |
| 127 | } | |
| 128 | ||
| 129 | //------------------------------------------------- | |
| 130 | // nvram_read - called to read NVRAM from the | |
| 131 | // .nv file | |
| 132 | //------------------------------------------------- | |
| 133 | ||
| 134 | void pcf8593_device::nvram_read(emu_file &file) | |
| 135 | { | |
| 136 | file.read(m_data, sizeof(m_data)); | |
| 137 | } | |
| 138 | ||
| 139 | ||
| 140 | //------------------------------------------------- | |
| 141 | // nvram_write - called to write NVRAM to the | |
| 142 | // .nv file | |
| 143 | //------------------------------------------------- | |
| 144 | ||
| 145 | void pcf8593_device::nvram_write(emu_file &file) | |
| 146 | { | |
| 147 | file.write(m_data, sizeof(m_data)); | |
| 148 | } | |
| 149 | ||
| 150 | ||
| 151 | ||
| 152 | /*------------------------------------------------- | |
| 153 | pcf8593_pin_scl | |
| 154 | -------------------------------------------------*/ | |
| 155 | ||
| 156 | WRITE_LINE_MEMBER(pcf8593_device::scl_w) | |
| 157 | { | |
| 158 | // send bit | |
| 159 | if ((m_active) && (!m_pin_scl) && (state)) | |
| 160 | { | |
| 161 | switch (m_mode) | |
| 162 | { | |
| 163 | // HOST -> RTC | |
| 164 | case RTC_MODE_RECV : | |
| 165 | { | |
| 166 | // get bit | |
| 167 | if (m_pin_sda) m_data_recv[m_data_recv_index] = m_data_recv[m_data_recv_index] | (0x80 >> m_bits); | |
| 168 | m_bits++; | |
| 169 | // bit 9 = end | |
| 170 | if (m_bits > 8) | |
| 171 | { | |
| 172 | _logerror( 2, ("pcf8593_write_byte(%02X)\n", m_data_recv[m_data_recv_index])); | |
| 173 | // enter receive mode when 1st byte = 0xA3 | |
| 174 | if ((m_data_recv[0] == 0xA3) && (m_data_recv_index == 0)) | |
| 175 | { | |
| 176 | m_mode = RTC_MODE_SEND; | |
| 177 | } | |
| 178 | // A2 + xx = "read from pos xx" command | |
| 179 | if ((m_data_recv[0] == 0xA2) && (m_data_recv_index == 1)) | |
| 180 | { | |
| 181 | m_pos = m_data_recv[1]; | |
| 182 | } | |
| 183 | // A2 + xx + .. = write byte | |
| 184 | if ((m_data_recv[0] == 0xA2) && (m_data_recv_index >= 2)) | |
| 185 | { | |
| 186 | UINT8 rtc_pos, rtc_val; | |
| 187 | rtc_pos = m_data_recv[1] + (m_data_recv_index - 2); | |
| 188 | rtc_val = m_data_recv[m_data_recv_index]; | |
| 189 | //if (rtc_pos == 0) rtc_val = rtc_val & 3; // what is this doing here? | |
| 190 | m_data[rtc_pos] = rtc_val; | |
| 191 | set_time(false, RTC_GET_DATE_YEAR, RTC_GET_DATE_MONTH, RTC_GET_DATE_DAY, 0, RTC_GET_TIME_HOUR, RTC_GET_TIME_MINUTE, RTC_GET_TIME_SECOND); | |
| 192 | } | |
| 193 | // next byte | |
| 194 | m_bits = 0; | |
| 195 | m_data_recv_index++; | |
| 196 | } | |
| 197 | } | |
| 198 | break; | |
| 199 | // RTC -> HOST | |
| 200 | case RTC_MODE_SEND : | |
| 201 | { | |
| 202 | // set bit | |
| 203 | m_inp = (m_data[m_pos] >> (7 - m_bits)) & 1; | |
| 204 | m_bits++; | |
| 205 | // bit 9 = end | |
| 206 | if (m_bits > 8) | |
| 207 | { | |
| 208 | _logerror( 2, ("pcf8593_read_byte(%02X)\n", m_data[m_pos])); | |
| 209 | // end ? | |
| 210 | if (m_pin_sda) | |
| 211 | { | |
| 212 | _logerror( 2, ("pcf8593 end\n")); | |
| 213 | m_mode = RTC_MODE_RECV; | |
| 214 | clear_buffer_rx(); | |
| 215 | } | |
| 216 | // next byte | |
| 217 | m_bits = 0; | |
| 218 | m_pos++; | |
| 219 | } | |
| 220 | } | |
| 221 | break; | |
| 222 | } | |
| 223 | } | |
| 224 | // save scl | |
| 225 | m_pin_scl = state; | |
| 226 | } | |
| 227 | ||
| 228 | ||
| 229 | ||
| 230 | /*------------------------------------------------- | |
| 231 | pcf8593_pin_sda_w | |
| 232 | -------------------------------------------------*/ | |
| 233 | ||
| 234 | WRITE_LINE_MEMBER(pcf8593_device::sda_w) | |
| 235 | { | |
| 236 | // clock is high | |
| 237 | if (m_pin_scl) | |
| 238 | { | |
| 239 | // log init I2C | |
| 240 | if (state) _logerror( 1, ("pcf8593 init i2c\n")); | |
| 241 | // start condition (high to low when clock is high) | |
| 242 | if ((!state) && (m_pin_sda)) | |
| 243 | { | |
| 244 | _logerror( 1, ("pcf8593 start condition\n")); | |
| 245 | m_active = TRUE; | |
| 246 | m_bits = 0; | |
| 247 | m_data_recv_index = 0; | |
| 248 | clear_buffer_rx(); | |
| 249 | //m_pos = 0; | |
| 250 | } | |
| 251 | // stop condition (low to high when clock is high) | |
| 252 | if ((state) && (!m_pin_sda)) | |
| 253 | { | |
| 254 | _logerror( 1, ("pcf8593 stop condition\n")); | |
| 255 | m_active = FALSE; | |
| 256 | } | |
| 257 | } | |
| 258 | // save sda | |
| 259 | m_pin_sda = state; | |
| 260 | } | |
| 261 | ||
| 262 | ||
| 263 | ||
| 264 | /*------------------------------------------------- | |
| 265 | pcf8593_pin_sda_r | |
| 266 | -------------------------------------------------*/ | |
| 267 | ||
| 268 | READ_LINE_MEMBER(pcf8593_device::sda_r) | |
| 269 | { | |
| 270 | return m_inp; | |
| 271 | } | |
| 272 | ||
| 273 | ||
| 274 | ||
| 275 | /*------------------------------------------------- | |
| 276 | pcf8593_clear_buffer_rx | |
| 277 | -------------------------------------------------*/ | |
| 278 | ||
| 279 | void pcf8593_device::clear_buffer_rx() | |
| 280 | { | |
| 281 | memset(&m_data_recv[0], 0, sizeof( m_data_recv)); | |
| 282 | m_data_recv_index = 0; | |
| 283 | } |
| r21684 | r21685 | |
|---|---|---|
| 1 | /********************************************************************* | |
| 2 | ||
| 3 | Philips PCF8593 CMOS clock/calendar circuit | |
| 4 | ||
| 5 | (c) 2001-2007 Tim Schuerewegen | |
| 6 | ||
| 7 | *********************************************************************/ | |
| 8 | ||
| 9 | #ifndef __PCF8593_H__ | |
| 10 | #define __PCF8593_H__ | |
| 11 | ||
| 12 | #include "emu.h" | |
| 13 | ||
| 14 | ||
| 15 | //************************************************************************** | |
| 16 | // INTERFACE CONFIGURATION MACROS | |
| 17 | //************************************************************************** | |
| 18 | ||
| 19 | #define MCFG_PCF8593_ADD(_tag) \ | |
| 20 | MCFG_DEVICE_ADD(_tag, PCF8593, 0) | |
| 21 | ||
| 22 | #define MCFG_PCF8593_REMOVE(_tag) \ | |
| 23 | MCFG_DEVICE_REMOVE(_tag) | |
| 24 | ||
| 25 | ||
| 26 | // ======================> pcf8593_device | |
| 27 | ||
| 28 | class pcf8593_device : public device_t, | |
| 29 | public device_rtc_interface, | |
| 30 | public device_nvram_interface | |
| 31 | { | |
| 32 | public: | |
| 33 | pcf8593_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); | |
| 34 | ||
| 35 | DECLARE_WRITE_LINE_MEMBER(scl_w); | |
| 36 | DECLARE_WRITE_LINE_MEMBER(sda_w); | |
| 37 | DECLARE_READ_LINE_MEMBER(sda_r); | |
| 38 | ||
| 39 | protected: | |
| 40 | // device-level overrides | |
| 41 | virtual void device_start(); | |
| 42 | virtual void device_reset(); | |
| 43 | virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); | |
| 44 | ||
| 45 | // device_rtc_interface overrides | |
| 46 | virtual bool rtc_feature_y2k() { return true; } | |
| 47 | virtual void rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second); | |
| 48 | ||
| 49 | // device_nvram_interface overrides | |
| 50 | virtual void nvram_default(); | |
| 51 | virtual void nvram_read(emu_file &file); | |
| 52 | virtual void nvram_write(emu_file &file); | |
| 53 | ||
| 54 | private: | |
| 55 | void clear_buffer_rx(); | |
| 56 | ||
| 57 | static const device_timer_id TIMER_UPDATE_COUNTER = 0; | |
| 58 | ||
| 59 | // internal state | |
| 60 | UINT8 m_data[16]; | |
| 61 | int m_pin_scl; | |
| 62 | int m_pin_sda; | |
| 63 | int m_inp; | |
| 64 | int m_active; | |
| 65 | int m_bits; | |
| 66 | UINT8 m_data_recv_index; | |
| 67 | UINT8 m_data_recv[50]; | |
| 68 | UINT8 m_mode; | |
| 69 | UINT8 m_pos; | |
| 70 | emu_timer * m_timer; | |
| 71 | enum { RTC_MODE_NONE, RTC_MODE_SEND, RTC_MODE_RECV }; | |
| 72 | }; | |
| 73 | ||
| 74 | // device type definition | |
| 75 | extern const device_type PCF8593; | |
| 76 | ||
| 77 | #endif /* __PCF8593_H__ */ |
| r21684 | r21685 | |
|---|---|---|
| 1 | /*************************************************************************** | |
| 2 | ||
| 3 | mm58274c.c | |
| 4 | ||
| 5 | mm58274c emulation | |
| 6 | ||
| 7 | Reference: | |
| 8 | * National Semiconductor MM58274C Microprocessor Compatible Real Time Clock | |
| 9 | <http://www.national.com/ds/MM/MM58274C.pdf> | |
| 10 | ||
| 11 | Todo: | |
| 12 | * Clock initialization will only work with the BwG: we need to provide | |
| 13 | a way to customize it. | |
| 14 | * Save the config to NVRAM? | |
| 15 | * Support interrupt pin output | |
| 16 | ||
| 17 | Raphael Nabet, 2002 | |
| 18 | ||
| 19 | ***************************************************************************/ | |
| 20 | ||
| 21 | #include "emu.h" | |
| 22 | #include "mm58274c.h" | |
| 23 | ||
| 24 | struct mm58274c_t | |
| 25 | { | |
| 26 | const mm58274c_interface *intf; | |
| 27 | ||
| 28 | int status; /* status register (*read* from address 0 = control register) */ | |
| 29 | int control; /* control register (*write* to address 0) */ | |
| 30 | ||
| 31 | int clk_set; /* clock setting register */ | |
| 32 | int int_ctl; /* interrupt control register */ | |
| 33 | ||
| 34 | ||
| 35 | int wday; /* day of the week (1-7 (1=day1 as set in init)) */ | |
| 36 | int years1; /* years (BCD: 0-99) */ | |
| 37 | int years2; | |
| 38 | int months1; /* months (BCD: 1-12) */ | |
| 39 | int months2; | |
| 40 | int days1; /* days (BCD: 1-31) */ | |
| 41 | int days2; | |
| 42 | int hours1; /* hours (BCD : 0-23) */ | |
| 43 | int hours2; | |
| 44 | int minutes1; /* minutes (BCD : 0-59) */ | |
| 45 | int minutes2; | |
| 46 | int seconds1; /* seconds (BCD : 0-59) */ | |
| 47 | int seconds2; | |
| 48 | int tenths; /* tenths of second (BCD : 0-9) */ | |
| 49 | ||
| 50 | emu_timer *increment_rtc; | |
| 51 | emu_timer *interrupt_timer; | |
| 52 | }; | |
| 53 | ||
| 54 | enum | |
| 55 | { | |
| 56 | st_dcf = 0x8, /* data-changed flag */ | |
| 57 | st_if = 0x1, /* interrupt flag */ | |
| 58 | ||
| 59 | ctl_test = 0x8, /* test mode (0=normal, 1=test) (not emulated) */ | |
| 60 | ctl_clkstop = 0x4, /* clock start/stop (0=run, 1=stop) */ | |
| 61 | ctl_intsel = 0x2, /* interrupt select (0=clock setting register, 1=interrupt register) */ | |
| 62 | ctl_intstop = 0x1, /* interrupt start stop (0=interrupt run, 1=interrupt stop) */ | |
| 63 | ||
| 64 | clk_set_leap = 0xc, /* leap year counter (0 indicates a leap year) */ | |
| 65 | clk_set_leap_inc = 0x4, /* leap year increment */ | |
| 66 | clk_set_pm = 0x2, /* am/pm indicator (0 = am, 1 = pm, 0 in 24-hour mode) */ | |
| 67 | clk_set_24 = 0x1, /* 12/24-hour select bit (1= 24-hour mode) */ | |
| 68 | ||
| 69 | int_ctl_rpt = 0x8, /* 1 for repeated interrupt */ | |
| 70 | int_ctl_dly = 0x7 /* 0 no interrupt, 1 = .1 second, 2=.5, 3=1, 4=5, 5=10, 6=30, 7=60 */ | |
| 71 | }; | |
| 72 | ||
| 73 | ||
| 74 | INLINE mm58274c_t *get_safe_token(device_t *device) | |
| 75 | { | |
| 76 | assert(device != NULL); | |
| 77 | assert(device->type() == MM58274C); | |
| 78 | ||
| 79 | return (mm58274c_t *)downcast<mm58274c_device *>(device)->token(); | |
| 80 | } | |
| 81 | ||
| 82 | static attotime interrupt_period_table(int val) | |
| 83 | { | |
| 84 | switch(val) | |
| 85 | { | |
| 86 | case 0: return attotime::from_msec(0); | |
| 87 | case 1: return attotime::from_msec(100); | |
| 88 | case 2: return attotime::from_msec(500); | |
| 89 | case 3: return attotime::from_seconds(1); | |
| 90 | case 4: return attotime::from_seconds(5); | |
| 91 | case 5: return attotime::from_seconds(10); | |
| 92 | case 6: return attotime::from_seconds(30); | |
| 93 | case 7: return attotime::from_seconds(60); | |
| 94 | default: fatalerror("out of range\n"); | |
| 95 | } | |
| 96 | }; | |
| 97 | ||
| 98 | READ8_DEVICE_HANDLER( mm58274c_r ) | |
| 99 | { | |
| 100 | mm58274c_t *mm58274c = get_safe_token(device); | |
| 101 | int reply; | |
| 102 | ||
| 103 | offset &= 0xf; | |
| 104 | ||
| 105 | switch (offset) | |
| 106 | { | |
| 107 | case 0x0: /* Control Register */ | |
| 108 | reply = mm58274c->status; | |
| 109 | mm58274c->status = 0; | |
| 110 | break; | |
| 111 | ||
| 112 | case 0x1: /* Tenths of Seconds */ | |
| 113 | reply = mm58274c->tenths; | |
| 114 | break; | |
| 115 | ||
| 116 | case 0x2: /* Units Seconds */ | |
| 117 | reply = mm58274c->seconds2; | |
| 118 | break; | |
| 119 | ||
| 120 | case 0x3: /* Tens Seconds */ | |
| 121 | reply = mm58274c->seconds1; | |
| 122 | break; | |
| 123 | ||
| 124 | case 0x04: /* Units Minutes */ | |
| 125 | reply = mm58274c->minutes2; | |
| 126 | break; | |
| 127 | ||
| 128 | case 0x5: /* Tens Minutes */ | |
| 129 | reply = mm58274c->minutes1; | |
| 130 | break; | |
| 131 | ||
| 132 | case 0x6: /* Units Hours */ | |
| 133 | reply = mm58274c->hours2; | |
| 134 | break; | |
| 135 | ||
| 136 | case 0x7: /* Tens Hours */ | |
| 137 | reply = mm58274c->hours1; | |
| 138 | break; | |
| 139 | ||
| 140 | case 0x8: /* Units Days */ | |
| 141 | reply = mm58274c->days2; | |
| 142 | break; | |
| 143 | ||
| 144 | case 0x9: /* Tens Days */ | |
| 145 | reply = mm58274c->days1; | |
| 146 | break; | |
| 147 | ||
| 148 | case 0xA: /* Units Months */ | |
| 149 | reply = mm58274c->months2; | |
| 150 | break; | |
| 151 | ||
| 152 | case 0xB: /* Tens Months */ | |
| 153 | reply = mm58274c->months1; | |
| 154 | break; | |
| 155 | ||
| 156 | case 0xC: /* Units Years */ | |
| 157 | reply = mm58274c->years2; | |
| 158 | break; | |
| 159 | ||
| 160 | case 0xD: /* Tens Years */ | |
| 161 | reply = mm58274c->years1; | |
| 162 | break; | |
| 163 | ||
| 164 | case 0xE: /* Day of Week */ | |
| 165 | reply = mm58274c->wday; | |
| 166 | break; | |
| 167 | ||
| 168 | case 0xF: /* Clock Setting & Interrupt Registers */ | |
| 169 | if (mm58274c->control & ctl_intsel) | |
| 170 | /* interrupt register */ | |
| 171 | reply = mm58274c->int_ctl; | |
| 172 | else | |
| 173 | { /* clock setting register */ | |
| 174 | if (mm58274c->clk_set & clk_set_24) | |
| 175 | /* 24-hour mode */ | |
| 176 | reply = mm58274c->clk_set & ~clk_set_pm; | |
| 177 | else | |
| 178 | /* 12-hour mode */ | |
| 179 | reply = mm58274c->clk_set; | |
| 180 | } | |
| 181 | break; | |
| 182 | ||
| 183 | default: | |
| 184 | reply = 0; | |
| 185 | break; | |
| 186 | } | |
| 187 | ||
| 188 | return reply; | |
| 189 | } | |
| 190 | ||
| 191 | ||
| 192 | WRITE8_DEVICE_HANDLER (mm58274c_w) | |
| 193 | { | |
| 194 | mm58274c_t *mm58274c = get_safe_token(device); | |
| 195 | ||
| 196 | offset &= 0xf; | |
| 197 | data &= 0xf; | |
| 198 | ||
| 199 | switch (offset) | |
| 200 | { | |
| 201 | case 0x0: /* Control Register (test mode and interrupt not emulated) */ | |
| 202 | if ((! (mm58274c->control & ctl_intstop)) && (data & ctl_intstop)) | |
| 203 | /* interrupt stop */ | |
| 204 | mm58274c->interrupt_timer->enable(0); | |
| 205 | else if ((mm58274c->control & ctl_intstop) && (! (data & ctl_intstop))) | |
| 206 | { | |
| 207 | /* interrupt run */ | |
| 208 | attotime period = interrupt_period_table(mm58274c->int_ctl & int_ctl_dly); | |
| 209 | ||
| 210 | mm58274c->interrupt_timer->adjust(period, 0, mm58274c->int_ctl & int_ctl_rpt ? period : attotime::zero); | |
| 211 | } | |
| 212 | if (data & ctl_clkstop) | |
| 213 | /* stopping the clock clears the tenth counter */ | |
| 214 | mm58274c->tenths = 0; | |
| 215 | mm58274c->control = data; | |
| 216 | break; | |
| 217 | ||
| 218 | case 0x1: /* Tenths of Seconds: cannot be written */ | |
| 219 | break; | |
| 220 | ||
| 221 | case 0x2: /* Units Seconds */ | |
| 222 | mm58274c->seconds2 = data; | |
| 223 | break; | |
| 224 | ||
| 225 | case 0x3: /* Tens Seconds */ | |
| 226 | mm58274c->seconds1 = data; | |
| 227 | break; | |
| 228 | ||
| 229 | case 0x4: /* Units Minutes */ | |
| 230 | mm58274c->minutes2 = data; | |
| 231 | break; | |
| 232 | ||
| 233 | case 0x5: /* Tens Minutes */ | |
| 234 | mm58274c->minutes1 = data; | |
| 235 | break; | |
| 236 | ||
| 237 | case 0x6: /* Units Hours */ | |
| 238 | mm58274c->hours2 = data; | |
| 239 | break; | |
| 240 | ||
| 241 | case 0x7: /* Tens Hours */ | |
| 242 | mm58274c->hours1 = data; | |
| 243 | break; | |
| 244 | ||
| 245 | case 0x8: /* Units Days */ | |
| 246 | mm58274c->days2 = data; | |
| 247 | break; | |
| 248 | ||
| 249 | case 0x9: /* Tens Days */ | |
| 250 | mm58274c->days1 = data; | |
| 251 | break; | |
| 252 | ||
| 253 | case 0xA: /* Units Months */ | |
| 254 | mm58274c->months2 = data; | |
| 255 | break; | |
| 256 | ||
| 257 | case 0xB: /* Tens Months */ | |
| 258 | mm58274c->months1 = data; | |
| 259 | break; | |
| 260 | ||
| 261 | case 0xC: /* Units Years */ | |
| 262 | mm58274c->years2 = data; | |
| 263 | break; | |
| 264 | ||
| 265 | case 0xD: /* Tens Years */ | |
| 266 | mm58274c->years1 = data; | |
| 267 | break; | |
| 268 | ||
| 269 | case 0xE: /* Day of Week */ | |
| 270 | mm58274c->wday = data; | |
| 271 | break; | |
| 272 | ||
| 273 | case 0xF: /* Clock Setting & Interrupt Registers */ | |
| 274 | if (mm58274c->control & ctl_intsel) | |
| 275 | { | |
| 276 | /* interrupt register (not emulated) */ | |
| 277 | mm58274c->int_ctl = data; | |
| 278 | if (! (mm58274c->control & ctl_intstop)) | |
| 279 | { | |
| 280 | /* interrupt run */ | |
| 281 | attotime period = interrupt_period_table(mm58274c->int_ctl & int_ctl_dly); | |
| 282 | ||
| 283 | mm58274c->interrupt_timer->adjust(period, 0, mm58274c->int_ctl & int_ctl_rpt ? period : attotime::zero); | |
| 284 | } | |
| 285 | } | |
| 286 | else | |
| 287 | { | |
| 288 | /* clock setting register */ | |
| 289 | mm58274c->clk_set = data; | |
| 290 | #if 0 | |
| 291 | if (mm58274c->clk_set & clk_set_24) | |
| 292 | /* 24-hour mode */ | |
| 293 | mm58274c->clk_set &= ~clk_set_pm; | |
| 294 | #endif | |
| 295 | } | |
| 296 | break; | |
| 297 | } | |
| 298 | } | |
| 299 | ||
| 300 | ||
| 301 | /* | |
| 302 | Set RTC interrupt flag | |
| 303 | */ | |
| 304 | static TIMER_CALLBACK(rtc_interrupt_callback) | |
| 305 | { | |
| 306 | device_t *device = (device_t *)ptr; | |
| 307 | mm58274c_t *mm58274c = get_safe_token(device); | |
| 308 | mm58274c->status |= st_if; | |
| 309 | } | |
| 310 | ||
| 311 | ||
| 312 | /* | |
| 313 | Increment RTC clock (timed interrupt every 1/10s) | |
| 314 | */ | |
| 315 | ||
| 316 | static TIMER_CALLBACK(increment_rtc) | |
| 317 | { | |
| 318 | device_t *device = (device_t *)ptr; | |
| 319 | mm58274c_t *mm58274c = get_safe_token(device); | |
| 320 | if (! (mm58274c->control & ctl_clkstop)) | |
| 321 | { | |
| 322 | mm58274c->status |= st_dcf; | |
| 323 | ||
| 324 | if ((++mm58274c->tenths) == 10) | |
| 325 | { | |
| 326 | mm58274c->tenths = 0; | |
| 327 | ||
| 328 | if ((++mm58274c->seconds2) == 10) | |
| 329 | { | |
| 330 | mm58274c->seconds2 = 0; | |
| 331 | ||
| 332 | if ((++mm58274c->seconds1) == 6) | |
| 333 | { | |
| 334 | mm58274c->seconds1 = 0; | |
| 335 | ||
| 336 | if ((++mm58274c->minutes2) == 10) | |
| 337 | { | |
| 338 | mm58274c->minutes2 = 0; | |
| 339 | ||
| 340 | if ((++mm58274c->minutes1) == 6) | |
| 341 | { | |
| 342 | mm58274c->minutes1 = 0; | |
| 343 | ||
| 344 | if ((++mm58274c->hours2) == 10) | |
| 345 | { | |
| 346 | mm58274c->hours2 = 0; | |
| 347 | ||
| 348 | mm58274c->hours1++; | |
| 349 | } | |
| 350 | ||
| 351 | /* handle wrap-around */ | |
| 352 | if ((! (mm58274c->clk_set & clk_set_24)) | |
| 353 | && ((mm58274c->hours1*10 + mm58274c->hours2) == 12)) | |
| 354 | { | |
| 355 | mm58274c->clk_set ^= clk_set_pm; | |
| 356 | } | |
| 357 | if ((! (mm58274c->clk_set & clk_set_24)) | |
| 358 | && ((mm58274c->hours1*10 + mm58274c->hours2) == 13)) | |
| 359 | { | |
| 360 | mm58274c->hours1 = 0; | |
| 361 | mm58274c->hours2 = 1; | |
| 362 | } | |
| 363 | ||
| 364 | if ((mm58274c->clk_set & clk_set_24) | |
| 365 | && ((mm58274c->hours1*10 + mm58274c->hours2) == 24)) | |
| 366 | { | |
| 367 | mm58274c->hours1 = mm58274c->hours2 = 0; | |
| 368 | } | |
| 369 | ||
| 370 | /* increment day if needed */ | |
| 371 | if ((mm58274c->clk_set & clk_set_24) | |
| 372 | ? ((mm58274c->hours1*10 + mm58274c->hours2) == 0) | |
| 373 | : (((mm58274c->hours1*10 + mm58274c->hours2) == 12) | |
| 374 | && (! (mm58274c->clk_set & clk_set_pm)))) | |
| 375 | { | |
| 376 | int days_in_month; | |
| 377 | ||
| 378 | if ((++mm58274c->days2) == 10) | |
| 379 | { | |
| 380 | mm58274c->days2 = 0; | |
| 381 | ||
| 382 | mm58274c->days1++; | |
| 383 | } | |
| 384 | ||
| 385 | if ((++mm58274c->wday) == 8) | |
| 386 | mm58274c->wday = 1; | |
| 387 | ||
| 388 | { | |
| 389 | static const int days_in_month_array[] = | |
| 390 | { | |
| 391 | 31,28,31, 30,31,30, | |
| 392 | 31,31,30, 31,30,31 | |
| 393 | }; | |
| 394 | ||
| 395 | if (((mm58274c->months1*10 + mm58274c->months2) != 2) || (mm58274c->clk_set & clk_set_leap)) | |
| 396 | days_in_month = days_in_month_array[mm58274c->months1*10 + mm58274c->months2 - 1]; | |
| 397 | else | |
| 398 | days_in_month = 29; | |
| 399 | } | |
| 400 | ||
| 401 | ||
| 402 | if ((mm58274c->days1*10 + mm58274c->days2) == days_in_month+1) | |
| 403 | { | |
| 404 | mm58274c->days1 = 0; | |
| 405 | mm58274c->days2 = 1; | |
| 406 | ||
| 407 | if ((++mm58274c->months2) == 10) | |
| 408 | { | |
| 409 | mm58274c->months2 = 0; | |
| 410 | ||
| 411 | mm58274c->months1++; | |
| 412 | } | |
| 413 | ||
| 414 | if ((mm58274c->months1*10 + mm58274c->months2) == 13) | |
| 415 | { | |
| 416 | mm58274c->months1 = 0; | |
| 417 | mm58274c->months2 = 1; | |
| 418 | ||
| 419 | mm58274c->clk_set = (mm58274c->clk_set & ~clk_set_leap) | |
| 420 | | ((mm58274c->clk_set + clk_set_leap_inc) & clk_set_leap); | |
| 421 | ||
| 422 | if ((++mm58274c->years2) == 10) | |
| 423 | { | |
| 424 | mm58274c->years2 = 0; | |
| 425 | ||
| 426 | if ((++mm58274c->years1) == 10) | |
| 427 | mm58274c->years1 = 0; | |
| 428 | } | |
| 429 | } | |
| 430 | } | |
| 431 | } | |
| 432 | } | |
| 433 | } | |
| 434 | } | |
| 435 | } | |
| 436 | } | |
| 437 | } | |
| 438 | } | |
| 439 | ||
| 440 | /* Device Interface */ | |
| 441 | ||
| 442 | static DEVICE_START( mm58274c ) | |
| 443 | { | |
| 444 | mm58274c_t *mm58274c = get_safe_token(device); | |
| 445 | ||
| 446 | // validate arguments | |
| 447 | assert(device != NULL); | |
| 448 | assert(device->tag() != NULL); | |
| 449 | assert(device->static_config() != NULL); | |
| 450 | ||
| 451 | mm58274c->intf = (const mm58274c_interface*)device->static_config(); | |
| 452 | // register for state saving | |
| 453 | state_save_register_item(device->machine(), "mm58274c", device->tag(), 0, mm58274c->status); | |
| 454 | state_save_register_item(device->machine(), "mm58274c", device->tag(), 0, mm58274c->control); | |
| 455 | state_save_register_item(device->machine(), "mm58274c", device->tag(), 0, mm58274c->clk_set); | |
| 456 | state_save_register_item(device->machine(), "mm58274c", device->tag(), 0, mm58274c->int_ctl); | |
| 457 | state_save_register_item(device->machine(), "mm58274c", device->tag(), 0, mm58274c->wday); | |
| 458 | state_save_register_item(device->machine(), "mm58274c", device->tag(), 0, mm58274c->years1); | |
| 459 | state_save_register_item(device->machine(), "mm58274c", device->tag(), 0, mm58274c->years2); | |
| 460 | state_save_register_item(device->machine(), "mm58274c", device->tag(), 0, mm58274c->months1); | |
| 461 | state_save_register_item(device->machine(), "mm58274c", device->tag(), 0, mm58274c->months2); | |
| 462 | state_save_register_item(device->machine(), "mm58274c", device->tag(), 0, mm58274c->days1); | |
| 463 | state_save_register_item(device->machine(), "mm58274c", device->tag(), 0, mm58274c->days2); | |
| 464 | state_save_register_item(device->machine(), "mm58274c", device->tag(), 0, mm58274c->hours1); | |
| 465 | state_save_register_item(device->machine(), "mm58274c", device->tag(), 0, mm58274c->hours2); | |
| 466 | state_save_register_item(device->machine(), "mm58274c", device->tag(), 0, mm58274c->minutes1); | |
| 467 | state_save_register_item(device->machine(), "mm58274c", device->tag(), 0, mm58274c->minutes2); | |
| 468 | state_save_register_item(device->machine(), "mm58274c", device->tag(), 0, mm58274c->seconds1); | |
| 469 | state_save_register_item(device->machine(), "mm58274c", device->tag(), 0, mm58274c->seconds2); | |
| 470 | state_save_register_item(device->machine(), "mm58274c", device->tag(), 0, mm58274c->tenths); | |
| 471 | ||
| 472 | mm58274c->increment_rtc = device->machine().scheduler().timer_alloc(FUNC(increment_rtc), ((void*)device)); | |
| 473 | mm58274c->increment_rtc->adjust(attotime::zero, 0, attotime::from_msec(100)); | |
| 474 | mm58274c->interrupt_timer = device->machine().scheduler().timer_alloc(FUNC(rtc_interrupt_callback), ((void*)device)); | |
| 475 | } | |
| 476 | ||
| 477 | ||
| 478 | static DEVICE_RESET( mm58274c ) | |
| 479 | { | |
| 480 | mm58274c_t *mm58274c = get_safe_token(device); | |
| 481 | system_time systime; | |
| 482 | ||
| 483 | /* get the current date/time from the core */ | |
| 484 | device->machine().current_datetime(systime); | |
| 485 | ||
| 486 | mm58274c->clk_set = systime.local_time.year & 3 << 2; | |
| 487 | if (mm58274c->intf->mode24) | |
| 488 | mm58274c->clk_set |= clk_set_24; | |
| 489 | ||
| 490 | /* The clock count starts on 1st January 1900 */ | |
| 491 | mm58274c->wday = 1 + ((systime.local_time.weekday - mm58274c->intf->day1)%7); | |
| 492 | mm58274c->years1 = (systime.local_time.year / 10) % 10; | |
| 493 | mm58274c->years2 = systime.local_time.year % 10; | |
| 494 | mm58274c->months1 = (systime.local_time.month + 1) / 10; | |
| 495 | mm58274c->months2 = (systime.local_time.month + 1) % 10; | |
| 496 | mm58274c->days1 = systime.local_time.mday / 10; | |
| 497 | mm58274c->days2 = systime.local_time.mday % 10; | |
| 498 | if (!mm58274c->intf->mode24) | |
| 499 | { | |
| 500 | /* 12-hour mode */ | |
| 501 | if (systime.local_time.hour > 12) | |
| 502 | { | |
| 503 | systime.local_time.hour -= 12; | |
| 504 | mm58274c->clk_set |= clk_set_pm; | |
| 505 | } | |
| 506 | if (systime.local_time.hour == 0) | |
| 507 | systime.local_time.hour = 12; | |
| 508 | } | |
| 509 | mm58274c->hours1 = systime.local_time.hour / 10; | |
| 510 | mm58274c->hours2 = systime.local_time.hour % 10; | |
| 511 | mm58274c->minutes1 = systime.local_time.minute / 10; | |
| 512 | mm58274c->minutes2 = systime.local_time.minute % 10; | |
| 513 | mm58274c->seconds1 = systime.local_time.second / 10; | |
| 514 | mm58274c->seconds2 = systime.local_time.second % 10; | |
| 515 | mm58274c->tenths = 0; | |
| 516 | } | |
| 517 | ||
| 518 | const device_type MM58274C = &device_creator<mm58274c_device>; | |
| 519 | ||
| 520 | mm58274c_device::mm58274c_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) | |
| 521 | : device_t(mconfig, MM58274C, "National Semiconductor MM58274C", tag, owner, clock) | |
| 522 | { | |
| 523 | m_token = global_alloc_clear(mm58274c_t); | |
| 524 | } | |
| 525 | ||
| 526 | //------------------------------------------------- | |
| 527 | // device_config_complete - perform any | |
| 528 | // operations now that the configuration is | |
| 529 | // complete | |
| 530 | //------------------------------------------------- | |
| 531 | ||
| 532 | void mm58274c_device::device_config_complete() | |
| 533 | { | |
| 534 | } | |
| 535 | ||
| 536 | //------------------------------------------------- | |
| 537 | // device_start - device-specific startup | |
| 538 | //------------------------------------------------- | |
| 539 | ||
| 540 | void mm58274c_device::device_start() | |
| 541 | { | |
| 542 | DEVICE_START_NAME( mm58274c )(this); | |
| 543 | } | |
| 544 | ||
| 545 | //------------------------------------------------- | |
| 546 | // device_reset - device-specific reset | |
| 547 | //------------------------------------------------- | |
| 548 | ||
| 549 | void mm58274c_device::device_reset() | |
| 550 | { | |
| 551 | DEVICE_RESET_NAME( mm58274c )(this); | |
| 552 | } |
| r21684 | r21685 | |
|---|---|---|
| 1 | #ifndef MM58274C_H | |
| 2 | #define MM58274C_H | |
| 3 | ||
| 4 | /*************************************************************************** | |
| 5 | MACROS | |
| 6 | ***************************************************************************/ | |
| 7 | ||
| 8 | class mm58274c_device : public device_t | |
| 9 | { | |
| 10 | public: | |
| 11 | mm58274c_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); | |
| 12 | ~mm58274c_device() { global_free(m_token); } | |
| 13 | ||
| 14 | // access to legacy token | |
| 15 | void *token() const { assert(m_token != NULL); return m_token; } | |
| 16 | protected: | |
| 17 | // device-level overrides | |
| 18 | virtual void device_config_complete(); | |
| 19 | virtual void device_start(); | |
| 20 | virtual void device_reset(); | |
| 21 | private: | |
| 22 | // internal state | |
| 23 | void *m_token; | |
| 24 | }; | |
| 25 | ||
| 26 | extern const device_type MM58274C; | |
| 27 | ||
| 28 | ||
| 29 | /*************************************************************************** | |
| 30 | FUNCTION PROTOTYPES | |
| 31 | ***************************************************************************/ | |
| 32 | /* interface */ | |
| 33 | /* | |
| 34 | Initializes the clock chip. | |
| 35 | day1 must be set to a value from 0 (sunday), 1 (monday) ... | |
| 36 | to 6 (saturday) and is needed to correctly retrieve the day-of-week | |
| 37 | from the host system clock. | |
| 38 | */ | |
| 39 | struct mm58274c_interface | |
| 40 | { | |
| 41 | int mode24; /* 24/12 mode */ | |
| 42 | int day1; /* first day of week */ | |
| 43 | }; | |
| 44 | ||
| 45 | DECLARE_READ8_DEVICE_HANDLER ( mm58274c_r ); | |
| 46 | DECLARE_WRITE8_DEVICE_HANDLER( mm58274c_w ); | |
| 47 | ||
| 48 | /*************************************************************************** | |
| 49 | DEVICE CONFIGURATION MACROS | |
| 50 | ***************************************************************************/ | |
| 51 | ||
| 52 | #define MCFG_MM58274C_ADD(_tag, _intrf) \ | |
| 53 | MCFG_DEVICE_ADD(_tag, MM58274C, 0) \ | |
| 54 | MCFG_DEVICE_CONFIG(_intrf) | |
| 55 | ||
| 56 | #endif /* MM58274C_H */ |
| r21684 | r21685 | |
|---|---|---|
| 1 | /****************************************************************************** | |
| 2 | uPD7002 Analogue to Digital Converter | |
| 3 | ||
| 4 | MESS Driver By: | |
| 5 | ||
| 6 | Gordon Jefferyes | |
| 7 | mess_bbc@gjeffery.dircon.co.uk | |
| 8 | ||
| 9 | ******************************************************************************/ | |
| 10 | ||
| 11 | #include "emu.h" | |
| 12 | #include "upd7002.h" | |
| 13 | ||
| 14 | ||
| 15 | struct uPD7002_t | |
| 16 | { | |
| 17 | /* Pointer to our interface */ | |
| 18 | const uPD7002_interface *intf; | |
| 19 | ||
| 20 | /* Status Register | |
| 21 | D0 and D1 define the currently selected input channel | |
| 22 | D2 flag output | |
| 23 | D3 0 = 8 bit mode 1 = 12 bit mode | |
| 24 | D4 2nd MSB of conversion | |
| 25 | D5 MSB of conversion | |
| 26 | D6 0 = busy, 1 = not busy (~busy) | |
| 27 | D7 0 = conversion completed, 1 = conversion not completed (~EOC) | |
| 28 | */ | |
| 29 | int status; | |
| 30 | ||
| 31 | /* High data byte | |
| 32 | This byte contains the 8 most significant bits of the analogue to digital conversion. */ | |
| 33 | int data1; | |
| 34 | ||
| 35 | /* Low data byte | |
| 36 | In 12 bit mode: Bits 7 to 4 define the four low order bits of the conversion. | |
| 37 | In 8 bit mode. All bits 7 to 4 are inaccurate. | |
| 38 | Bits 3 to 0 are always set to low. */ | |
| 39 | int data0; | |
| 40 | ||
| 41 | ||
| 42 | /* temporary store of the next A to D conversion */ | |
| 43 | int digitalvalue; | |
| 44 | ||
| 45 | /* this counter is used to check a full end of conversion has been reached | |
| 46 | if the uPD7002 is half way through one conversion and a new conversion is requested | |
| 47 | the counter at the end of the first conversion will not match and not be processed | |
| 48 | only then at the end of the second conversion will the conversion complete function run */ | |
| 49 | int conversion_counter; | |
| 50 | }; | |
| 51 | ||
| 52 | ||
| 53 | /***************************************************************************** | |
| 54 | Implementation | |
| 55 | *****************************************************************************/ | |
| 56 | ||
| 57 | INLINE uPD7002_t *get_safe_token(device_t *device) | |
| 58 | { | |
| 59 | assert(device != NULL); | |
| 60 | assert(device->type() == UPD7002); | |
| 61 | ||
| 62 | return (uPD7002_t *)downcast<uPD7002_device *>(device)->token(); | |
| 63 | } | |
| 64 | ||
| 65 | READ8_DEVICE_HANDLER ( uPD7002_EOC_r ) | |
| 66 | { | |
| 67 | uPD7002_t *uPD7002 = get_safe_token(device); | |
| 68 | return (uPD7002->status>>7)&0x01; | |
| 69 | } | |
| 70 | ||
| 71 | ||
| 72 | static TIMER_CALLBACK(uPD7002_conversioncomplete) | |
| 73 | { | |
| 74 | device_t *device = (device_t *)ptr; | |
| 75 | uPD7002_t *uPD7002 = get_safe_token(device); | |
| 76 | ||
| 77 | int counter_value = param; | |
| 78 | if (counter_value==uPD7002->conversion_counter) | |
| 79 | { | |
| 80 | // this really always does a 12 bit conversion | |
| 81 | uPD7002->data1 = uPD7002->digitalvalue>>8; | |
| 82 | uPD7002->data0 = uPD7002->digitalvalue&0xf0; | |
| 83 | ||
| 84 | // set the status register with top 2 MSB, not busy and conversion complete | |
| 85 | uPD7002->status = (uPD7002->status & 0x0f)|((uPD7002->data1 & 0xc0)>>2)|0x40; | |
| 86 | ||
| 87 | // call the EOC function with EOC from status | |
| 88 | // uPD7002_EOC_r(0) this has just been set to 0 | |
| 89 | if (uPD7002->intf->EOC_func) (uPD7002->intf->EOC_func)(device,0); | |
| 90 | uPD7002->conversion_counter=0; | |
| 91 | } | |
| 92 | } | |
| 93 | ||
| 94 | ||
| 95 | READ8_DEVICE_HANDLER ( uPD7002_r ) | |
| 96 | { | |
| 97 | uPD7002_t *uPD7002 = get_safe_token(device); | |
| 98 | ||
| 99 | switch(offset&0x03) | |
| 100 | { | |
| 101 | case 0: | |
| 102 | return uPD7002->status; | |
| 103 | ||
| 104 | case 1: | |
| 105 | return uPD7002->data1; | |
| 106 | ||
| 107 | case 2: case 3: | |
| 108 | return uPD7002->data0; | |
| 109 | } | |
| 110 | return 0; | |
| 111 | } | |
| 112 | ||
| 113 | ||
| 114 | ||
| 115 | WRITE8_DEVICE_HANDLER ( uPD7002_w ) | |
| 116 | { | |
| 117 | uPD7002_t *uPD7002 = get_safe_token(device); | |
| 118 | /* logerror("write to uPD7002 $%02X = $%02X\n",offset,data); */ | |
| 119 | ||
| 120 | switch(offset&0x03) | |
| 121 | { | |
| 122 | case 0: | |
| 123 | /* | |
| 124 | Data Latch/AD start | |
| 125 | D0 and D1 together define which one of the four input channels is selected | |
| 126 | D2 flag input, normally set to 0???? | |
| 127 | D3 defines whether an 8 (0) or 12 (1) bit resolution conversion should occur | |
| 128 | D4 to D7 not used. | |
| 129 | ||
| 130 | an 8 bit conversion typically takes 4ms | |
| 131 | an 12 bit conversion typically takes 10ms | |
| 132 | ||
| 133 | writing to this register will initiate a conversion. | |
| 134 | */ | |
| 135 | ||
| 136 | /* set D6=0 busy ,D7=1 conversion not complete */ | |
| 137 | uPD7002->status=(data & 0x0f) | 0x80; | |
| 138 | ||
| 139 | // call the EOC function with EOC from status | |
| 140 | // uPD7002_EOC_r(0) this has just been set to 1 | |
| 141 | if (uPD7002->intf->EOC_func) uPD7002->intf->EOC_func(device, 1); | |
| 142 | ||
| 143 | /* the uPD7002 works by sampling the analogue value at the start of the conversion | |
| 144 | so it is read hear and stored until the end of the A to D conversion */ | |
| 145 | ||
| 146 | // this function should return a 16 bit value. | |
| 147 | uPD7002->digitalvalue = uPD7002->intf->get_analogue_func(device, uPD7002->status & 0x03); | |
| 148 | ||
| 149 | uPD7002->conversion_counter++; | |
| 150 | ||
| 151 | // call a timer to start the conversion | |
| 152 | if (uPD7002->status & 0x08) | |
| 153 | { | |
| 154 | // 12 bit conversion takes 10ms | |
| 155 | space.machine().scheduler().timer_set(attotime::from_msec(10), FUNC(uPD7002_conversioncomplete), uPD7002->conversion_counter, (void *)device); | |
| 156 | } else { | |
| 157 | // 8 bit conversion takes 4ms | |
| 158 | space.machine().scheduler().timer_set(attotime::from_msec(4), FUNC(uPD7002_conversioncomplete), uPD7002->conversion_counter, (void *)device); | |
| 159 | } | |
| 160 | break; | |
| 161 | ||
| 162 | case 1: case 2: | |
| 163 | /* Nothing */ | |
| 164 | break; | |
| 165 | ||
| 166 | case 3: | |
| 167 | /* Test Mode: Used for inspecting the device, The data input-output terminals assume an input | |
| 168 | state and are connected to the A/D counter. Therefore, the A/D conversion data | |
| 169 | read out after this is meaningless. | |
| 170 | */ | |
| 171 | break; | |
| 172 | } | |
| 173 | } | |
| 174 | ||
| 175 | /* Device Interface */ | |
| 176 | ||
| 177 | static DEVICE_START( uPD7002 ) | |
| 178 | { | |
| 179 | uPD7002_t *uPD7002 = get_safe_token(device); | |
| 180 | // validate arguments | |
| 181 | ||
| 182 | assert(device != NULL); | |
| 183 | assert(device->tag() != NULL); | |
| 184 | assert(device->static_config() != NULL); | |
| 185 | ||
| 186 | uPD7002->intf = (const uPD7002_interface*)device->static_config(); | |
| 187 | uPD7002->status = 0; | |
| 188 | uPD7002->data1 = 0; | |
| 189 | uPD7002->data0 = 0; | |
| 190 | uPD7002->digitalvalue = 0; | |
| 191 | uPD7002->conversion_counter = 0; | |
| 192 | ||
| 193 | // register for state saving | |
| 194 | state_save_register_item(device->machine(), "uPD7002", device->tag(), 0, uPD7002->status); | |
| 195 | state_save_register_item(device->machine(), "uPD7002", device->tag(), 0, uPD7002->data1); | |
| 196 | state_save_register_item(device->machine(), "uPD7002", device->tag(), 0, uPD7002->data0); | |
| 197 | state_save_register_item(device->machine(), "uPD7002", device->tag(), 0, uPD7002->digitalvalue); | |
| 198 | state_save_register_item(device->machine(), "uPD7002", device->tag(), 0, uPD7002->conversion_counter); | |
| 199 | } | |
| 200 | ||
| 201 | static DEVICE_RESET( uPD7002 ) | |
| 202 | { | |
| 203 | uPD7002_t *uPD7002 = get_safe_token(device); | |
| 204 | uPD7002->status = 0; | |
| 205 | uPD7002->data1 = 0; | |
| 206 | uPD7002->data0 = 0; | |
| 207 | uPD7002->digitalvalue = 0; | |
| 208 | uPD7002->conversion_counter = 0; | |
| 209 | } | |
| 210 | ||
| 211 | const device_type UPD7002 = &device_creator<uPD7002_device>; | |
| 212 | ||
| 213 | uPD7002_device::uPD7002_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) | |
| 214 | : device_t(mconfig, UPD7002, "uPD7002", tag, owner, clock) | |
| 215 | { | |
| 216 | m_token = global_alloc_clear(uPD7002_t); | |
| 217 | } | |
| 218 | ||
| 219 | //------------------------------------------------- | |
| 220 | // device_config_complete - perform any | |
| 221 | // operations now that the configuration is | |
| 222 | // complete | |
| 223 | //------------------------------------------------- | |
| 224 | ||
| 225 | void uPD7002_device::device_config_complete() | |
| 226 | { | |
| 227 | } | |
| 228 | ||
| 229 | //------------------------------------------------- | |
| 230 | // device_start - device-specific startup | |
| 231 | //------------------------------------------------- | |
| 232 | ||
| 233 | void uPD7002_device::device_start() | |
| 234 | { | |
| 235 | DEVICE_START_NAME( uPD7002 )(this); | |
| 236 | } | |
| 237 | ||
| 238 | //------------------------------------------------- | |
| 239 | // device_reset - device-specific reset | |
| 240 | //------------------------------------------------- | |
| 241 | ||
| 242 | void uPD7002_device::device_reset() | |
| 243 | { | |
| 244 | DEVICE_RESET_NAME( uPD7002 )(this); | |
| 245 | } |
| r21684 | r21685 | |
|---|---|---|
| 1 | /***************************************************************************** | |
| 2 | * | |
| 3 | * machine/upd7002.h | |
| 4 | * | |
| 5 | * uPD7002 Analogue to Digital Converter | |
| 6 | * | |
| 7 | * Driver by Gordon Jefferyes <mess_bbc@gjeffery.dircon.co.uk> | |
| 8 | * | |
| 9 | ****************************************************************************/ | |
| 10 | ||
| 11 | #ifndef UPD7002_H_ | |
| 12 | #define UPD7002_H_ | |
| 13 | ||
| 14 | /*************************************************************************** | |
| 15 | MACROS | |
| 16 | ***************************************************************************/ | |
| 17 | ||
| 18 | class uPD7002_device : public device_t | |
| 19 | { | |
| 20 | public: | |
| 21 | uPD7002_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); | |
| 22 | ~uPD7002_device() { global_free(m_token); } | |
| 23 | ||
| 24 | // access to legacy token | |
| 25 | void *token() const { assert(m_token != NULL); return m_token; } | |
| 26 | protected: | |
| 27 | // device-level overrides | |
| 28 | virtual void device_config_complete(); | |
| 29 | virtual void device_start(); | |
| 30 | virtual void device_reset(); | |
| 31 | private: | |
| 32 | // internal state | |
| 33 | void *m_token; | |
| 34 | }; | |
| 35 | ||
| 36 | extern const device_type UPD7002; | |
| 37 | ||
| 38 | ||
| 39 | /*************************************************************************** | |
| 40 | TYPE DEFINITIONS | |
| 41 | ***************************************************************************/ | |
| 42 | ||
| 43 | typedef int (*uPD7002_get_analogue_func)(device_t *device, int channel_number); | |
| 44 | #define UPD7002_GET_ANALOGUE(name) int name(device_t *device, int channel_number ) | |
| 45 | ||
| 46 | typedef void (*uPD7002_eoc_func)(device_t *device, int data); | |
| 47 | #define UPD7002_EOC(name) void name(device_t *device, int data ) | |
| 48 | ||
| 49 | ||
| 50 | struct uPD7002_interface | |
| 51 | { | |
| 52 | uPD7002_get_analogue_func get_analogue_func; | |
| 53 | uPD7002_eoc_func EOC_func; | |
| 54 | }; | |
| 55 | ||
| 56 | /*************************************************************************** | |
| 57 | FUNCTION PROTOTYPES | |
| 58 | ***************************************************************************/ | |
| 59 | ||
| 60 | /* Standard handlers */ | |
| 61 | ||
| 62 | DECLARE_READ8_DEVICE_HANDLER ( uPD7002_EOC_r ); | |
| 63 | DECLARE_READ8_DEVICE_HANDLER ( uPD7002_r ); | |
| 64 | DECLARE_WRITE8_DEVICE_HANDLER ( uPD7002_w ); | |
| 65 | ||
| 66 | ||
| 67 | /*************************************************************************** | |
| 68 | DEVICE CONFIGURATION MACROS | |
| 69 | ***************************************************************************/ | |
| 70 | ||
| 71 | #define MCFG_UPD7002_ADD(_tag, _intrf) \ | |
| 72 | MCFG_DEVICE_ADD(_tag, UPD7002, 0) \ | |
| 73 | MCFG_DEVICE_CONFIG(_intrf) | |
| 74 | ||
| 75 | ||
| 76 | #endif /* UPD7002_H_ */ |
| r21684 | r21685 | |
|---|---|---|
| 1 | /**************************************************************************** | |
| 2 | ||
| 3 | ay31015.c by Robbbert, May 2008. Bugs fixed by Judge. | |
| 4 | ||
| 5 | Code for the AY-3-1014A, AY-3-1015(D), AY-5-1013(A), and AY-6-1013 UARTs | |
| 6 | The HD6402 UART is compatible with the AY-3-1015 UART. | |
| 7 | ||
| 8 | This is cycle-accurate according to the specifications. | |
| 9 | ||
| 10 | It supports independent receive and transmit clocks, | |
| 11 | and transmission and reception can occur simultaneously if desired. | |
| 12 | ||
| 13 | ***************************************************************************** | |
| 14 | ||
| 15 | Differences between the chip types: | |
| 16 | - All units have pull-up resistors on the inputs, except for the AY-3-1014A which is CMOS-compatible. | |
| 17 | - AY-3-1014A and AY-3-1015 - 1.5 stop bits mode available. | |
| 18 | - Max baud rate of 30k, except AY-5-1013 which has 20k. | |
| 19 | - AY-5-1013 has extended temperature ratings. | |
| 20 | - AY-5-1013 and AY-6-1013 require a -12 volt supply on pin 2. Pin is not used otherwise. | |
| 21 | - AY-5-1013 and AY-6-1013 do not reset the received data register when XR pin is used. | |
| 22 | ||
| 23 | ****************************************************************************** | |
| 24 | ||
| 25 | It is not clear in the documentation as to which settings will reset the device. | |
| 26 | To be safe, we will always reset whenever the control register changes. | |
| 27 | ||
| 28 | Also, it not clear exactly what happens under various error conditions. | |
| 29 | ||
| 30 | ******************************************************************************** | |
| 31 | ||
| 32 | Device Data: | |
| 33 | ||
| 34 | * Common Controls: | |
| 35 | -- Pin 1 - Vcc - 5 volts | |
| 36 | -- Pin 2 - not used (on AY-5-1013 and AY-6-1013 this is Voo = -12 volts) | |
| 37 | -- Pin 3 - Gnd - 0 volts | |
| 38 | -- Pin 21 - XR - External Reset - resets all registers to initial state except for the control register | |
| 39 | -- Pin 35 - NP - No Parity - "1" will kill any parity processing | |
| 40 | -- Pin 36 - TSB - Number of Stop Bits - "0" = 1 stop bit; "1" = 2 stop bits. If "1", and 5 bits per character, then we have 1.5 stop bits | |
| 41 | -- pin 37 - NB1 | |
| 42 | -- pin 38 - NB2 - Number of bits per character = NB1 + (NB2 * 2) + 5 | |
| 43 | -- pin 39 - EPS - Odd or Even Parity Select - "0" = Odd parity; "1" = Even parity. Has no effect if NP is high. | |
| 44 | -- Pin 34 - CS - Control Strobe - Read NP, TSB, EPS, NB1, NB2 into the control register. | |
| 45 | ||
| 46 | Format of data stream: | |
| 47 | Start bit (low), Bit 0, Bit 1... highest bit, Parity bit (if enabled), 1-2 stop bits (high) | |
| 48 | ||
| 49 | ||
| 50 | * Receiver Controls: | |
| 51 | -- Pin 17 - RCP - Clock which is 16x the desired baud rate | |
| 52 | -- Pin 20 - SI - Serial input stream - "1" = Mark (waiting for input), "0" = Space (Start bit) initiates the transfer of a byte | |
| 53 | -- Pin 4 - RDE - "0" causes the received data to appear on RD1 to RD8. | |
| 54 | -- Pins 5 to 12 - RD8 to RD1 - These are the data lines (bits 7 to 0). Data is right-justified. | |
| 55 | -- Pin 16 - SWE - Status word enable - causes the status bits (PE, FE, OR, DAV, TBMT) to appear at the pins. | |
| 56 | -- Pin 19 - DAV - "1" indicates that a byte has been received by the UART, and should now be accepted by the computer | |
| 57 | -- Pin 18 - RDAV - "0" will force DAV low. | |
| 58 | -- Pin 13 - PE - Parity error - "1" indicates that a parity error occurred | |
| 59 | -- Pin 14 - FE - Framing error - "1" Indicates that the stop bit was missing | |
| 60 | -- Pin 15 - OR - overrun - "1" indicates that a new character has become available before the computer had accepted the previous character | |
| 61 | ||
| 62 | * Transmitter controls: | |
| 63 | -- Pin 40 - TCP - Clock which is 16x the desired baud rate | |
| 64 | -- Pin 25 - SO - Serial output stream - it will stay at "1" while no data is being transmitted | |
| 65 | -- Pins 26 to 33 - DB1 to DB8 - These are the data lines containing the byte to be sent | |
| 66 | -- Pin 23 - DS - Data Strobe - "0" will copy DB1 to DB8 into the transmit buffer | |
| 67 | -- Pin 22 - TBMT - Transmit buffer Empty - "1" indicates to the computer that another byte may be sent to the UART | |
| 68 | -- Pin 24 - EOC - End of Character - "0" means that a character is being sent. | |
| 69 | ||
| 70 | ******************************************* COMMON CONTROLS ********************************************************/ | |
| 71 | ||
| 72 | #include "emu.h" | |
| 73 | #include "ay31015.h" | |
| 74 | ||
| 75 | enum state_t | |
| 76 | { | |
| 77 | IDLE, | |
| 78 | START_BIT, | |
| 79 | PROCESSING, | |
| 80 | PARITY_BIT, | |
| 81 | FIRST_STOP_BIT, | |
| 82 | SECOND_STOP_BIT, | |
| 83 | PREP_TIME | |
| 84 | }; | |
| 85 | ||
| 86 | ||
| 87 | struct ay31015_t | |
| 88 | { | |
| 89 | const ay31015_config *config; | |
| 90 | ||
| 91 | int pins[41]; | |
| 92 | ||
| 93 | UINT8 control_reg; | |
| 94 | UINT8 status_reg; | |
| 95 | UINT16 second_stop_bit; // 0, 8, 16 | |
| 96 | UINT16 total_pulses; // bits * 16 | |
| 97 | UINT8 internal_sample; | |
| 98 | ||
| 99 | state_t rx_state; | |
| 100 | UINT8 rx_data; // byte being received | |
| 101 | UINT8 rx_buffer; // received byte waiting to be accepted by computer | |
| 102 | UINT8 rx_bit_count; | |
| 103 | UINT8 rx_parity; | |
| 104 | UINT16 rx_pulses; // total pulses left | |
| 105 | double rx_clock; | |
| 106 | emu_timer *rx_timer; | |
| 107 | ||
| 108 | state_t tx_state; | |
| 109 | UINT8 tx_data; // byte being sent | |
| 110 | UINT8 tx_buffer; // next byte to send | |
| 111 | UINT8 tx_parity; | |
| 112 | UINT16 tx_pulses; // total pulses left | |
| 113 | double tx_clock; | |
| 114 | emu_timer *tx_timer; | |
| 115 | ||
| 116 | devcb_resolved_read8 read_si; /* SI - pin 20 - This will be called whenever the SI pin is sampled. Optional */ | |
| 117 | devcb_resolved_write8 write_so; /* SO - pin 25 - This will be called whenever data is put on the SO pin. Optional */ | |
| 118 | devcb_resolved_write8 status_changed; /* This will be called whenever one of the status pins may have changed. Optional */ | |
| 119 | }; | |
| 120 | ||
| 121 | ||
| 122 | /* control reg */ | |
| 123 | #define CONTROL_NB1 0x01 | |
| 124 | #define CONTROL_NB2 0x02 | |
| 125 | #define CONTROL_TSB 0x04 | |
| 126 | #define CONTROL_EPS 0x08 | |
| 127 | #define CONTROL_NP 0x10 | |
| 128 | ||
| 129 | ||
| 130 | /* status reg */ | |
| 131 | #define STATUS_TBMT 0x01 | |
| 132 | #define STATUS_DAV 0x02 | |
| 133 | #define STATUS_OR 0x04 | |
| 134 | #define STATUS_FE 0x08 | |
| 135 | #define STATUS_PE 0x10 | |
| 136 | #define STATUS_EOC 0x20 | |
| 137 | ||
| 138 | ||
| 139 | /*------------------------------------------------- | |
| 140 | get_safe_token - safely gets the data | |
| 141 | -------------------------------------------------*/ | |
| 142 | ||
| 143 | INLINE ay31015_t *get_safe_token(device_t *device) | |
| 144 | { | |
| 145 | assert(device != NULL); | |
| 146 | assert(device->type() == AY31015); | |
| 147 | return (ay31015_t *) downcast<ay31015_device *>(device)->token(); | |
| 148 | } | |
| 149 | ||
| 150 | ||
| 151 | INLINE UINT8 ay31015_get_si( device_t *device ) | |
| 152 | { | |
| 153 | ay31015_t *ay31015 = get_safe_token( device ); | |
| 154 | ||
| 155 | if ( !ay31015->read_si.isnull() ) | |
| 156 | ay31015->pins[AY31015_SI] = ay31015->read_si( 0 ) ? 1 : 0; | |
| 157 | ||
| 158 | return ay31015->pins[AY31015_SI]; | |
| 159 | } | |
| 160 | ||
| 161 | ||
| 162 | INLINE void ay31015_set_so( device_t *device, int data ) | |
| 163 | { | |
| 164 | ay31015_t *ay31015 = get_safe_token( device ); | |
| 165 | ||
| 166 | ay31015->pins[AY31015_SO] = data ? 1 : 0; | |
| 167 | ||
| 168 | if ( !ay31015->write_so.isnull() ) | |
| 169 | ay31015->write_so( 0, ay31015->pins[AY31015_SO] ); | |
| 170 | } | |
| 171 | ||
| 172 | ||
| 173 | INLINE int ay31015_update_status_pin( ay31015_t *ay31015, UINT8 reg_bit, ay31015_output_pin_t pin ) | |
| 174 | { | |
| 175 | int new_value = ( ay31015->status_reg & reg_bit ) ? 1 : 0; | |
| 176 | ||
| 177 | if ( new_value == ay31015->pins[pin] ) | |
| 178 | return 0; | |
| 179 | ||
| 180 | ay31015->pins[pin] = new_value; | |
| 181 | return 1; | |
| 182 | } | |
| 183 | ||
| 184 | ||
| 185 | /*------------------------------------------------- | |
| 186 | ay31015_update_status_pins - Update the status pins | |
| 187 | -------------------------------------------------*/ | |
| 188 | static void ay31015_update_status_pins( device_t *device ) | |
| 189 | { | |
| 190 | ay31015_t *ay31015 = get_safe_token( device ); | |
| 191 | int status_pins_changed = 0; | |
| 192 | ||
| 193 | /* Should status pins be updated? */ | |
| 194 | if ( ! ay31015->pins[AY31015_SWE] ) | |
| 195 | { | |
| 196 | status_pins_changed += ay31015_update_status_pin( ay31015, STATUS_PE, AY31015_PE ); | |
| 197 | status_pins_changed += ay31015_update_status_pin( ay31015, STATUS_FE, AY31015_FE ); | |
| 198 | status_pins_changed += ay31015_update_status_pin( ay31015, STATUS_OR, AY31015_OR ); | |
| 199 | status_pins_changed += ay31015_update_status_pin( ay31015, STATUS_DAV, AY31015_DAV ); | |
| 200 | status_pins_changed += ay31015_update_status_pin( ay31015, STATUS_TBMT, AY31015_TBMT ); | |
| 201 | } | |
| 202 | status_pins_changed += ay31015_update_status_pin( ay31015, STATUS_EOC, AY31015_EOC ); | |
| 203 | ||
| 204 | if ( status_pins_changed && !ay31015->status_changed.isnull() ) | |
| 205 | { | |
| 206 | ay31015->status_changed( 0, status_pins_changed ); | |
| 207 | } | |
| 208 | } | |
| 209 | ||
| 210 | ||
| 211 | /*************************************************** RECEIVE CONTROLS *************************************************/ | |
| 212 | ||
| 213 | ||
| 214 | /*------------------------------------------------- | |
| 215 | ay31015_rx_process - convert serial to parallel | |
| 216 | -------------------------------------------------*/ | |
| 217 | static TIMER_CALLBACK( ay31015_rx_process ) | |
| 218 | { | |
| 219 | device_t *device = (device_t *)ptr; | |
| 220 | ay31015_t *ay31015 = get_safe_token( device ); | |
| 221 | ||
| 222 | switch (ay31015->rx_state) | |
| 223 | { | |
| 224 | case PREP_TIME: // assist sync by ensuring high bit occurs | |
| 225 | ay31015->rx_pulses--; | |
| 226 | if (ay31015_get_si( device )) | |
| 227 | ay31015->rx_state = IDLE; | |
| 228 | return; | |
| 229 | ||
| 230 | case IDLE: | |
| 231 | ay31015->rx_pulses--; | |
| 232 | if (!ay31015_get_si( device )) | |
| 233 | { | |
| 234 | ay31015->rx_state = START_BIT; | |
| 235 | ay31015->rx_pulses = 16; | |
| 236 | } | |
| 237 | return; | |
| 238 | ||
| 239 | case START_BIT: | |
| 240 | ay31015->rx_pulses--; | |
| 241 | if (ay31015->rx_pulses == 8) // start bit must be low at sample time | |
| 242 | { | |
| 243 | if ( ay31015_get_si( device ) ) | |
| 244 | ay31015->rx_state = IDLE; | |
| 245 | } | |
| 246 | else | |
| 247 | if (!ay31015->rx_pulses) // end of start bit | |
| 248 | { | |
| 249 | ay31015->rx_state = PROCESSING; | |
| 250 | ay31015->rx_pulses = ay31015->total_pulses; | |
| 251 | ay31015->rx_bit_count = 0; | |
| 252 | ay31015->rx_parity = 0; | |
| 253 | ay31015->rx_data = 0; | |
| 254 | } | |
| 255 | return; | |
| 256 | ||
| 257 | case PROCESSING: | |
| 258 | ay31015->rx_pulses--; | |
| 259 | if (!ay31015->rx_pulses) // end of a byte | |
| 260 | { | |
| 261 | ay31015->rx_pulses = 16; | |
| 262 | if (ay31015->control_reg & CONTROL_NP) // see if we need to get a parity bit | |
| 263 | ay31015->rx_state = FIRST_STOP_BIT; | |
| 264 | else | |
| 265 | ay31015->rx_state = PARITY_BIT; | |
| 266 | } | |
| 267 | else | |
| 268 | if (!(ay31015->rx_pulses & 15)) // end of a bit | |
| 269 | ay31015->rx_bit_count++; | |
| 270 | else | |
| 271 | if ((ay31015->rx_pulses & 15) == 8) // sample input stream | |
| 272 | { | |
| 273 | ay31015->internal_sample = ay31015_get_si( device ); | |
| 274 | ay31015->rx_parity ^= ay31015->internal_sample; // calculate cumulative parity | |
| 275 | ay31015->rx_data |= ay31015->internal_sample << ay31015->rx_bit_count; | |
| 276 | } | |
| 277 | return; | |
| 278 | ||
| 279 | case PARITY_BIT: | |
| 280 | ay31015->rx_pulses--; | |
| 281 | ||
| 282 | if (ay31015->rx_pulses == 8) // sample input stream | |
| 283 | { | |
| 284 | ay31015->rx_parity ^= ay31015_get_si( device ); // calculate cumulative parity | |
| 285 | } | |
| 286 | else | |
| 287 | if (!ay31015->rx_pulses) // end of a byte | |
| 288 | { | |
| 289 | ay31015->rx_pulses = 16; | |
| 290 | ay31015->rx_state = FIRST_STOP_BIT; | |
| 291 | ||
| 292 | if ((!(ay31015->control_reg & CONTROL_EPS)) && (ay31015->rx_parity)) | |
| 293 | ay31015->rx_parity = 0; // odd parity, ok | |
| 294 | else | |
| 295 | if ((ay31015->control_reg & CONTROL_EPS) && (!ay31015->rx_parity)) | |
| 296 | ay31015->rx_parity = 0; // even parity, ok | |
| 297 | else | |
| 298 | ay31015->rx_parity = 1; // parity error | |
| 299 | } | |
| 300 | return; | |
| 301 | ||
| 302 | case FIRST_STOP_BIT: | |
| 303 | ay31015->rx_pulses--; | |
| 304 | if (ay31015->rx_pulses == 8) // sample input stream | |
| 305 | ay31015->internal_sample = ay31015_get_si( device ); | |
| 306 | else | |
| 307 | if (ay31015->rx_pulses == 7) // set error flags | |
| 308 | { | |
| 309 | if (!ay31015->internal_sample) | |
| 310 | { | |
| 311 | ay31015->status_reg |= STATUS_FE; // framing error - the stop bit not high | |
| 312 | ay31015->rx_state = PREP_TIME; // lost sync - start over | |
| 313 | // return; | |
| 314 | } | |
| 315 | else | |
| 316 | ay31015->status_reg &= ~STATUS_FE; | |
| 317 | ||
| 318 | if ((ay31015->rx_parity) && (!(ay31015->control_reg & CONTROL_NP))) | |
| 319 | ay31015->status_reg |= STATUS_PE; // parity error | |
| 320 | else | |
| 321 | ay31015->status_reg &= ~STATUS_PE; | |
| 322 | ||
| 323 | if (ay31015->status_reg & STATUS_DAV) | |
| 324 | ay31015->status_reg |= STATUS_OR; // overrun error - previous byte still in buffer | |
| 325 | else | |
| 326 | ay31015->status_reg &= ~STATUS_OR; | |
| 327 | ||
| 328 | ay31015->rx_buffer = ay31015->rx_data; // bring received byte out for computer to read | |
| 329 | ||
| 330 | ay31015_update_status_pins( device ); | |
| 331 | } | |
| 332 | else | |
| 333 | if (ay31015->rx_pulses == 6) | |
| 334 | { | |
| 335 | ay31015->status_reg |= STATUS_DAV; // tell computer that new byte is ready | |
| 336 | ay31015_update_status_pins( device ); | |
| 337 | } | |
| 338 | else | |
| 339 | if (ay31015->rx_pulses == 4) | |
| 340 | { | |
| 341 | if (ay31015->second_stop_bit) | |
| 342 | { | |
| 343 | /* We should wait for the full first stop bit and | |
| 344 | the beginning of the second stop bit */ | |
| 345 | ay31015->rx_state = SECOND_STOP_BIT; | |
| 346 | ay31015->rx_pulses += ay31015->second_stop_bit - 7; | |
| 347 | } | |
| 348 | else | |
| 349 | { | |
| 350 | /* We have seen a STOP bit, go back to PREP_TIME */ | |
| 351 | ay31015->rx_state = PREP_TIME; | |
| 352 | } | |
| 353 | } | |
| 354 | return; | |
| 355 | ||
| 356 | case SECOND_STOP_BIT: | |
| 357 | ay31015->rx_pulses--; | |
| 358 | if (!ay31015->rx_pulses) | |
| 359 | ay31015->rx_state = PREP_TIME; | |
| 360 | return; | |
| 361 | ||
| 362 | } | |
| 363 | } | |
| 364 | ||
| 365 | ||
| 366 | /*************************************************** TRANSMIT CONTROLS *************************************************/ | |
| 367 | ||
| 368 | ||
| 369 | /*------------------------------------------------- | |
| 370 | ay31015_tx_process - convert parallel to serial | |
| 371 | -------------------------------------------------*/ | |
| 372 | static TIMER_CALLBACK( ay31015_tx_process ) | |
| 373 | { | |
| 374 | device_t *device = (device_t *)ptr; | |
| 375 | ay31015_t *ay31015 = get_safe_token( device ); | |
| 376 | ||
| 377 | UINT8 t1; | |
| 378 | switch (ay31015->tx_state) | |
| 379 | { | |
| 380 | case IDLE: | |
| 381 | if (!(ay31015->status_reg & STATUS_TBMT)) | |
| 382 | { | |
| 383 | ay31015->tx_state = PREP_TIME; // When idle, see if a byte has been sent to us | |
| 384 | ay31015->tx_pulses = 1; | |
| 385 | } | |
| 386 | return; | |
| 387 | ||
| 388 | case PREP_TIME: // This phase lets the transmitter regain sync after an idle period | |
| 389 | ay31015->tx_pulses--; | |
| 390 | if (!ay31015->tx_pulses) | |
| 391 | { | |
| 392 | ay31015->tx_state = START_BIT; | |
| 393 | ay31015->tx_pulses = 16; | |
| 394 | } | |
| 395 | return; | |
| 396 | ||
| 397 | case START_BIT: | |
| 398 | if (ay31015->tx_pulses == 16) // beginning of start bit | |
| 399 | { | |
| 400 | ay31015->tx_data = ay31015->tx_buffer; // load the shift register | |
| 401 | ay31015->status_reg |= STATUS_TBMT; // tell computer that another byte can be sent to uart | |
| 402 | ay31015_set_so( device, 0 ); /* start bit begins now (we are "spacing") */ | |
| 403 | ay31015->status_reg &= ~STATUS_EOC; // we are no longer idle | |
| 404 | ay31015->tx_parity = 0; | |
| 405 | ay31015_update_status_pins( device ); | |
| 406 | } | |
| 407 | ||
| 408 | ay31015->tx_pulses--; | |
| 409 | if (!ay31015->tx_pulses) // end of start bit | |
| 410 | { | |
| 411 | ay31015->tx_state = PROCESSING; | |
| 412 | ay31015->tx_pulses = ay31015->total_pulses; | |
| 413 | } | |
| 414 | return; | |
| 415 | ||
| 416 | case PROCESSING: | |
| 417 | if (!(ay31015->tx_pulses & 15)) // beginning of a data bit | |
| 418 | { | |
| 419 | if (ay31015->tx_data & 1) | |
| 420 | { | |
| 421 | ay31015_set_so( device, 1 ); | |
| 422 | ay31015->tx_parity++; // calculate cumulative parity | |
| 423 | } | |
| 424 | else | |
| 425 | ay31015_set_so( device, 0 ); | |
| 426 | ||
| 427 | ay31015->tx_data >>= 1; // adjust the shift register | |
| 428 | } | |
| 429 | ||
| 430 | ay31015->tx_pulses--; | |
| 431 | if (!ay31015->tx_pulses) // all data bits sent | |
| 432 | { | |
| 433 | ay31015->tx_pulses = 16; | |
| 434 | if (ay31015->control_reg & CONTROL_NP) // see if we need to make a parity bit | |
| 435 | ay31015->tx_state = FIRST_STOP_BIT; | |
| 436 | else | |
| 437 | ay31015->tx_state = PARITY_BIT; | |
| 438 | } | |
| 439 | ||
| 440 | return; | |
| 441 | ||
| 442 | case PARITY_BIT: | |
| 443 | if (ay31015->tx_pulses == 16) | |
| 444 | { | |
| 445 | t1 = (ay31015->control_reg & CONTROL_EPS) ? 0 : 1; | |
| 446 | t1 ^= (ay31015->tx_parity & 1); | |
| 447 | if (t1) | |
| 448 | ay31015_set_so( device, 1 ); /* extra bit to set the correct parity */ | |
| 449 | else | |
| 450 | ay31015_set_so( device, 0 ); /* it was already correct */ | |
| 451 | } | |
| 452 | ||
| 453 | ay31015->tx_pulses--; | |
| 454 | if (!ay31015->tx_pulses) | |
| 455 | { | |
| 456 | ay31015->tx_state = FIRST_STOP_BIT; | |
| 457 | ay31015->tx_pulses = 16; | |
| 458 | } | |
| 459 | return; | |
| 460 | ||
| 461 | case FIRST_STOP_BIT: | |
| 462 | if (ay31015->tx_pulses == 16) | |
| 463 | ay31015_set_so( device, 1 ); /* create a stop bit (marking and soon idle) */ | |
| 464 | ay31015->tx_pulses--; | |
| 465 | if (!ay31015->tx_pulses) | |
| 466 | { | |
| 467 | ay31015->status_reg |= STATUS_EOC; // character is completely sent | |
| 468 | if (ay31015->second_stop_bit) | |
| 469 | { | |
| 470 | ay31015->tx_state = SECOND_STOP_BIT; | |
| 471 | ay31015->tx_pulses = ay31015->second_stop_bit; | |
| 472 | } | |
| 473 | else | |
| 474 | if (ay31015->status_reg & STATUS_TBMT) | |
| 475 | ay31015->tx_state = IDLE; // if nothing to send, go idle | |
| 476 | else | |
| 477 | { | |
| 478 | ay31015->tx_pulses = 16; | |
| 479 | ay31015->tx_state = START_BIT; // otherwise immediately start next byte | |
| 480 | } | |
| 481 | ay31015_update_status_pins( device ); | |
| 482 | } | |
| 483 | return; | |
| 484 | ||
| 485 | case SECOND_STOP_BIT: | |
| 486 | ay31015->tx_pulses--; | |
| 487 | if (!ay31015->tx_pulses) | |
| 488 | { | |
| 489 | if (ay31015->status_reg & STATUS_TBMT) | |
| 490 | ay31015->tx_state = IDLE; // if nothing to send, go idle | |
| 491 | else | |
| 492 | { | |
| 493 | ay31015->tx_pulses = 16; | |
| 494 | ay31015->tx_state = START_BIT; // otherwise immediately start next byte | |
| 495 | } | |
| 496 | } | |
| 497 | return; | |
| 498 | ||
| 499 | } | |
| 500 | } | |
| 501 | ||
| 502 | ||
| 503 | /*------------------------------------------------- | |
| 504 | ay31015_reset - reset internal state | |
| 505 | -------------------------------------------------*/ | |
| 506 | static void ay31015_reset( device_t *device ) | |
| 507 | { | |
| 508 | ay31015_t *ay31015 = get_safe_token( device ); | |
| 509 | ||
| 510 | /* total pulses = 16 * data-bits */ | |
| 511 | UINT8 t1; | |
| 512 | ||
| 513 | if ( ay31015->control_reg & CONTROL_NB2 ) | |
| 514 | t1 = ( ay31015->control_reg & CONTROL_NB1 ) ? 8 : 7; | |
| 515 | else | |
| 516 | t1 = ( ay31015->control_reg & CONTROL_NB1 ) ? 6 : 5; | |
| 517 | ||
| 518 | ay31015->total_pulses = t1 << 4; /* total clock pulses to load a byte */ | |
| 519 | ay31015->second_stop_bit = ((ay31015->control_reg & CONTROL_TSB) ? 16 : 0); /* 2nd stop bit */ | |
| 520 | if ((t1 == 5) && (ay31015->second_stop_bit == 16)) | |
| 521 | ay31015->second_stop_bit = 8; /* 5 data bits and 2 stop bits = 1.5 stop bits */ | |
| 522 | ay31015->status_reg = STATUS_EOC | STATUS_TBMT; | |
| 523 | ay31015->tx_data = 0; | |
| 524 | ay31015->rx_state = PREP_TIME; | |
| 525 | ay31015->tx_state = IDLE; | |
| 526 | ay31015->pins[AY31015_SI] = 1; | |
| 527 | ay31015_set_so( device, 1 ); | |
| 528 | ||
| 529 | if ( ay31015->config->type == AY_3_1015 ) | |
| 530 | ay31015->rx_data = 0; | |
| 531 | ||
| 532 | } | |
| 533 | ||
| 534 | ||
| 535 | /*------------------------------------------------- | |
| 536 | ay31015_transfer_control_pins - transfers contents of controls pins to the control register | |
| 537 | -------------------------------------------------*/ | |
| 538 | static void ay31015_transfer_control_pins( device_t *device ) | |
| 539 | { | |
| 540 | ay31015_t *ay31015 = get_safe_token( device ); | |
| 541 | UINT8 control = 0; | |
| 542 | ||
| 543 | control |= ay31015->pins[AY31015_NP ] ? CONTROL_NP : 0; | |
| 544 | control |= ay31015->pins[AY31015_TSB] ? CONTROL_TSB : 0; | |
| 545 | control |= ay31015->pins[AY31015_NB1] ? CONTROL_NB1 : 0; | |
| 546 | control |= ay31015->pins[AY31015_NB2] ? CONTROL_NB2 : 0; | |
| 547 | control |= ay31015->pins[AY31015_EPS] ? CONTROL_EPS : 0; | |
| 548 | ||
| 549 | if ( ay31015->control_reg != control ) | |
| 550 | { | |
| 551 | ay31015->control_reg = control; | |
| 552 | ay31015_reset( device ); | |
| 553 | } | |
| 554 | } | |
| 555 | ||
| 556 | ||
| 557 | /*------------------------------------------------- | |
| 558 | ay31015_set_input_pin - set an input pin | |
| 559 | -------------------------------------------------*/ | |
| 560 | void ay31015_set_input_pin( device_t *device, ay31015_input_pin_t pin, int data ) | |
| 561 | { | |
| 562 | ay31015_t *ay31015 = get_safe_token(device); | |
| 563 | ||
| 564 | data = data ? 1 : 0; | |
| 565 | ||
| 566 | switch ( pin ) | |
| 567 | { | |
| 568 | case AY31015_SWE: | |
| 569 | ay31015->pins[pin] = data; | |
| 570 | ay31015_update_status_pins( device ); | |
| 571 | break; | |
| 572 | case AY31015_RDAV: | |
| 573 | ay31015->pins[pin] = data; | |
| 574 | if ( ! data ) | |
| 575 | { | |
| 576 | ay31015->status_reg &= ~STATUS_DAV; | |
| 577 | ay31015->pins[AY31015_DAV] = 0; | |
| 578 | } | |
| 579 | break; | |
| 580 | case AY31015_SI: | |
| 581 | ay31015->pins[pin] = data; | |
| 582 | break; | |
| 583 | case AY31015_XR: | |
| 584 | ay31015->pins[pin] = data; | |
| 585 | if ( data ) | |
| 586 | ay31015_reset( device ); | |
| 587 | break; | |
| 588 | case AY31015_CS: | |
| 589 | case AY31015_NP: | |
| 590 | case AY31015_TSB: | |
| 591 | case AY31015_NB1: | |
| 592 | case AY31015_NB2: | |
| 593 | case AY31015_EPS: | |
| 594 | ay31015->pins[pin] = data; | |
| 595 | if ( ay31015->pins[AY31015_CS] ) | |
| 596 | ay31015_transfer_control_pins( device ); | |
| 597 | break; | |
| 598 | } | |
| 599 | } | |
| 600 | ||
| 601 | ||
| 602 | /*------------------------------------------------- | |
| 603 | ay31015_get_output_pin - get the status of an output pin | |
| 604 | -------------------------------------------------*/ | |
| 605 | int ay31015_get_output_pin( device_t *device, ay31015_output_pin_t pin ) | |
| 606 | { | |
| 607 | ay31015_t *ay31015 = get_safe_token(device); | |
| 608 | ||
| 609 | return ay31015->pins[pin]; | |
| 610 | } | |
| 611 | ||
| 612 | ||
| 613 | INLINE void ay31015_update_rx_timer( device_t *device ) | |
| 614 | { | |
| 615 | ay31015_t *ay31015 = get_safe_token( device ); | |
| 616 | ||
| 617 | if ( ay31015->rx_clock > 0.0 ) | |
| 618 | { | |
| 619 | ay31015->rx_timer->adjust( attotime::from_hz( ay31015->rx_clock ), 0, attotime::from_hz( ay31015->rx_clock ) ); | |
| 620 | } | |
| 621 | else | |
| 622 | { | |
| 623 | ay31015->rx_timer->enable( 0 ); | |
| 624 | } | |
| 625 | } | |
| 626 | ||
| 627 | ||
| 628 | INLINE void ay31015_update_tx_timer( device_t *device ) | |
| 629 | { | |
| 630 | ay31015_t *ay31015 = get_safe_token( device ); | |
| 631 | ||
| 632 | if ( ay31015->tx_clock > 0.0 ) | |
| 633 | { | |
| 634 | ay31015->tx_timer->adjust( attotime::from_hz( ay31015->tx_clock ), 0, attotime::from_hz( ay31015->tx_clock ) ); | |
| 635 | } | |
| 636 | else | |
| 637 | { | |
| 638 | ay31015->tx_timer->enable( 0 ); | |
| 639 | } | |
| 640 | } | |
| 641 | ||
| 642 | ||
| 643 | /*------------------------------------------------- | |
| 644 | ay31015_set_receiver_clock - set receive clock | |
| 645 | -------------------------------------------------*/ | |
| 646 | void ay31015_set_receiver_clock( device_t *device, double new_clock ) | |
| 647 | { | |
| 648 | ay31015_t *ay31015 = get_safe_token(device); | |
| 649 | ||
| 650 | ay31015->rx_clock = new_clock; | |
| 651 | ay31015_update_rx_timer( device ); | |
| 652 | } | |
| 653 | ||
| 654 | ||
| 655 | /*------------------------------------------------- | |
| 656 | ay31015_set_transmitter_clock - set transmit clock | |
| 657 | -------------------------------------------------*/ | |
| 658 | void ay31015_set_transmitter_clock( device_t *device, double new_clock ) | |
| 659 | { | |
| 660 | ay31015_t *ay31015 = get_safe_token(device); | |
| 661 | ||
| 662 | ay31015->tx_clock = new_clock; | |
| 663 | ay31015_update_tx_timer( device ); | |
| 664 | } | |
| 665 | ||
| 666 | ||
| 667 | /*------------------------------------------------- | |
| 668 | ay31015_get_received_data - return a byte to the computer | |
| 669 | -------------------------------------------------*/ | |
| 670 | UINT8 ay31015_get_received_data( device_t *device ) | |
| 671 | { | |
| 672 | ay31015_t *ay31015 = get_safe_token(device); | |
| 673 | ||
| 674 | return ay31015->rx_buffer; | |
| 675 | } | |
| 676 | ||
| 677 | ||
| 678 | /*------------------------------------------------- | |
| 679 | ay31015_set_transmit_data - accept a byte to transmit, if able | |
| 680 | -------------------------------------------------*/ | |
| 681 | void ay31015_set_transmit_data( device_t *device, UINT8 data ) | |
| 682 | { | |
| 683 | ay31015_t *ay31015 = get_safe_token(device); | |
| 684 | ||
| 685 | if (ay31015->status_reg & STATUS_TBMT) | |
| 686 | { | |
| 687 | ay31015->tx_buffer = data; | |
| 688 | ay31015->status_reg &= ~STATUS_TBMT; | |
| 689 | ay31015_update_status_pins( device ); | |
| 690 | } | |
| 691 | } | |
| 692 | ||
| 693 | ||
| 694 | static DEVICE_START(ay31015) | |
| 695 | { | |
| 696 | ay31015_t *ay31015 = get_safe_token(device); | |
| 697 | ||
| 698 | ay31015->config = (const ay31015_config*)device->static_config(); | |
| 699 | ||
| 700 | ay31015->read_si.resolve(ay31015->config->read_si_cb, *device); | |
| 701 | ay31015->write_so.resolve(ay31015->config->write_so_cb, *device); | |
| 702 | ay31015->status_changed.resolve(ay31015->config->status_changed_cb, *device); | |
| 703 | ||
| 704 | ay31015->tx_clock = ay31015->config->transmitter_clock; | |
| 705 | ay31015->rx_clock = ay31015->config->receiver_clock; | |
| 706 | ||
| 707 | ay31015->rx_timer = device->machine().scheduler().timer_alloc(FUNC(ay31015_rx_process), (void *)device ); | |
| 708 | ay31015->tx_timer = device->machine().scheduler().timer_alloc(FUNC(ay31015_tx_process), (void *)device ); | |
| 709 | ||
| 710 | ay31015_update_rx_timer( device ); | |
| 711 | ay31015_update_tx_timer( device ); | |
| 712 | } | |
| 713 | ||
| 714 | ||
| 715 | static DEVICE_RESET( ay31015 ) | |
| 716 | { | |
| 717 | ay31015_t *ay31015 = get_safe_token(device); | |
| 718 | ||
| 719 | ay31015->control_reg = 0; | |
| 720 | ay31015->rx_data = 0; | |
| 721 | ||
| 722 | ay31015_reset( device ); | |
| 723 | } | |
| 724 | ||
| 725 | ||
| 726 | const device_type AY31015 = &device_creator<ay31015_device>; | |
| 727 | ||
| 728 | ay31015_device::ay31015_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) | |
| 729 | : device_t(mconfig, AY31015, "AY-3-1015", tag, owner, clock) | |
| 730 | { | |
| 731 | m_token = global_alloc_clear(ay31015_t); | |
| 732 | } | |
| 733 | ||
| 734 | //------------------------------------------------- | |
| 735 | // device_config_complete - perform any | |
| 736 | // operations now that the configuration is | |
| 737 | // complete | |
| 738 | //------------------------------------------------- | |
| 739 | ||
| 740 | void ay31015_device::device_config_complete() | |
| 741 | { | |
| 742 | } | |
| 743 | ||
| 744 | //------------------------------------------------- | |
| 745 | // device_start - device-specific startup | |
| 746 | //------------------------------------------------- | |
| 747 | ||
| 748 | void ay31015_device::device_start() | |
| 749 | { | |
| 750 | DEVICE_START_NAME( ay31015 )(this); | |
| 751 | } | |
| 752 | ||
| 753 | //------------------------------------------------- | |
| 754 | // device_reset - device-specific reset | |
| 755 | //------------------------------------------------- | |
| 756 | ||
| 757 | void ay31015_device::device_reset() | |
| 758 | { | |
| 759 | DEVICE_RESET_NAME( ay31015 )(this); | |
| 760 | } |
| r21684 | r21685 | |
|---|---|---|
| 1 | /* ay31015.h | |
| 2 | ||
| 3 | Written for MESS by Robbbert on May 29th, 2008. | |
| 4 | ||
| 5 | */ | |
| 6 | ||
| 7 | #ifndef __AY31015_H_ | |
| 8 | #define __AY31015_H_ | |
| 9 | ||
| 10 | /*************************************************************************** | |
| 11 | TYPE DEFINITIONS | |
| 12 | ***************************************************************************/ | |
| 13 | ||
| 14 | ||
| 15 | enum ay31015_type_t | |
| 16 | { | |
| 17 | /* For AY-3-1014A, AY-3-1015(D) and HD6402 variants */ | |
| 18 | AY_3_1015, | |
| 19 | ||
| 20 | /* For AY-3-1014, AY-5-1013 and AY-6-1013 variants */ | |
| 21 | AY_5_1013 | |
| 22 | }; | |
| 23 | ||
| 24 | ||
| 25 | enum ay31015_input_pin_t | |
| 26 | { | |
| 27 | AY31015_SWE=16, /* -SWE - Pin 16 - Status word enable */ | |
| 28 | AY31015_RDAV=18, /* -RDAV - Pin 18 - Reset data available */ | |
| 29 | AY31015_SI=20, /* SI - Pin 20 - Serial input */ | |
| 30 | AY31015_XR=21, /* XR - Pin 21 - External reset */ | |
| 31 | AY31015_CS=34, /* CS - Pin 34 - Control strobe */ | |
| 32 | AY31015_NP=35, /* NP - Pin 35 - No parity */ | |
| 33 | AY31015_TSB=36, /* TSB - Pin 36 - Number of stop bits */ | |
| 34 | AY31015_NB1=37, /* NB1 - Pin 37 - Number of bits #1 */ | |
| 35 | AY31015_NB2=38, /* NB2 - Pin 38 - Number of bits #2 */ | |
| 36 | AY31015_EPS=39 /* EPS - Pin 39 - Odd/Even parity select */ | |
| 37 | }; | |
| 38 | ||
| 39 | ||
| 40 | enum ay31015_output_pin_t | |
| 41 | { | |
| 42 | AY31015_PE=13, /* PE - Pin 13 - Parity error */ | |
| 43 | AY31015_FE=14, /* FE - Pin 14 - Framing error */ | |
| 44 | AY31015_OR=15, /* OR - Pin 15 - Over-run */ | |
| 45 | AY31015_DAV=19, /* DAV - Pin 19 - Data available */ | |
| 46 | AY31015_TBMT=22, /* TBMT - Pin 22 - Transmit buffer empty */ | |
| 47 | AY31015_EOC=24, /* EOC - Pin 24 - End of character */ | |
| 48 | AY31015_SO=25 /* SO - Pin 25 - Serial output */ | |
| 49 | }; | |
| 50 | ||
| 51 | ||
| 52 | struct ay31015_config | |
| 53 | { | |
| 54 | ay31015_type_t type; /* Type of chip */ | |
| 55 | double transmitter_clock; /* TCP - pin 40 */ | |
| 56 | double receiver_clock; /* RCP - pin 17 */ | |
| 57 | devcb_read8 read_si_cb; /* SI - pin 20 - This will be called whenever the SI pin is sampled. Optional */ | |
| 58 | devcb_write8 write_so_cb; /* SO - pin 25 - This will be called whenever data is put on the SO pin. Optional */ | |
| 59 | devcb_write8 status_changed_cb; /* This will be called whenever one of the status pins may have changed. Optional */ | |
| 60 | }; | |
| 61 | ||
| 62 | ||
| 63 | /*************************************************************************** | |
| 64 | DEVICE CONFIGURATION MACROS | |
| 65 | ***************************************************************************/ | |
| 66 | ||
| 67 | #define MCFG_AY31015_ADD(_tag, _config) \ | |
| 68 | MCFG_DEVICE_ADD(_tag, AY31015, 0) \ | |
| 69 | MCFG_DEVICE_CONFIG(_config) | |
| 70 | ||
| 71 | ||
| 72 | /*************************************************************************** | |
| 73 | FUNCTION PROTOTYPES | |
| 74 | ***************************************************************************/ | |
| 75 | ||
| 76 | /* Set an input pin */ | |
| 77 | void ay31015_set_input_pin( device_t *device, ay31015_input_pin_t pin, int data ); | |
| 78 | ||
| 79 | ||
| 80 | /* Get an output pin */ | |
| 81 | int ay31015_get_output_pin( device_t *device, ay31015_output_pin_t pin ); | |
| 82 | ||
| 83 | ||
| 84 | /* Set a new transmitter clock (new_clock is in Hz) */ | |
| 85 | void ay31015_set_transmitter_clock( device_t *device, double new_clock ); | |
| 86 | ||
| 87 | ||
| 88 | /* Set a new receiver clock (new_clock is in Hz) */ | |
| 89 | void ay31015_set_receiver_clock( device_t *device, double new_clock ); | |
| 90 | ||
| 91 | ||
| 92 | /* Reead the received data */ | |
| 93 | /* The received data is available on RD8-RD1 (pins 5-12) */ | |
| 94 | UINT8 ay31015_get_received_data( device_t *device ); | |
| 95 | ||
| 96 | ||
| 97 | /* Set the transmitter buffer */ | |
| 98 | /* The data to transmit is set on DB1-DB8 (pins 26-33) */ | |
| 99 | void ay31015_set_transmit_data( device_t *device, UINT8 data ); | |
| 100 | ||
| 101 | ||
| 102 | /*************************************************************************** | |
| 103 | DEVICE INTERFACE | |
| 104 | ***************************************************************************/ | |
| 105 | ||
| 106 | class ay31015_device : public device_t | |
| 107 | { | |
| 108 | public: | |
| 109 | ay31015_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); | |
| 110 | ~ay31015_device() { global_free(m_token); } | |
| 111 | ||
| 112 | // access to legacy token | |
| 113 | void *token() const { assert(m_token != NULL); return m_token; } | |
| 114 | protected: | |
| 115 | // device-level overrides | |
| 116 | virtual void device_config_complete(); | |
| 117 | virtual void device_start(); | |
| 118 | virtual void device_reset(); | |
| 119 | private: | |
| 120 | // internal state | |
| 121 | void *m_token; | |
| 122 | }; | |
| 123 | ||
| 124 | extern const device_type AY31015; | |
| 125 | ||
| 126 | #endif |
| r21684 | r21685 | |
|---|---|---|
| 1 | /********************************************************************** | |
| 2 | ||
| 3 | Copyright (C) Antoine Mine' 2007 | |
| 4 | ||
| 5 | Motorola 6843 Floppy Disk Controller emulation. | |
| 6 | ||
| 7 | **********************************************************************/ | |
| 8 | ||
| 9 | /* | |
| 10 | Main MC 6843 features are: | |
| 11 | - single density floppies | |
| 12 | - IBM 3740 compatible | |
| 13 | - DMA-able | |
| 14 | - high-level commands (including multi-sector read/write) | |
| 15 | ||
| 16 | CLONES: HD 46503S seems to be a clone of MC 6843 | |
| 17 | ||
| 18 | BUGS | |
| 19 | The driver was designed with Thomson computer emulation in mind | |
| 20 | (CD 90-015 5"1/4 floppy controller) and works in this context. | |
| 21 | It might work in other contexts but has currently shortcomings: | |
| 22 | - DMA is not emulated | |
| 23 | - Free-Format Read is not emulated | |
| 24 | - Free-Format Write only supports track formatting, in a specific | |
| 25 | format (FWF=1, Thomson-like sector formats) | |
| 26 | - very rough timing: basically, there is a fixed delay between | |
| 27 | a command request (CMR write) and its response (first byte | |
| 28 | available, seek complete, etc.); there is no delay between | |
| 29 | read / write | |
| 30 | */ | |
| 31 | ||
| 32 | ||
| 33 | #include "emu.h" | |
| 34 | #include "mc6843.h" | |
| 35 | #include "imagedev/flopdrv.h" | |
| 36 | ||
| 37 | ||
| 38 | /******************* parameters ******************/ | |
| 39 | ||
| 40 | #define VERBOSE 0 | |
| 41 | ||
| 42 | ||
| 43 | /******************* internal chip data structure ******************/ | |
| 44 | ||
| 45 | struct mc6843_t | |
| 46 | { | |
| 47 | /* interface */ | |
| 48 | const mc6843_interface* iface; | |
| 49 | ||
| 50 | /* registers */ | |
| 51 | UINT8 CTAR; /* current track */ | |
| 52 | UINT8 CMR; /* command */ | |
| 53 | UINT8 ISR; /* interrupt status */ | |
| 54 | UINT8 SUR; /* set-up */ | |
| 55 | UINT8 STRA; /* status */ | |
| 56 | UINT8 STRB; /* status */ | |
| 57 | UINT8 SAR; /* sector address */ | |
| 58 | UINT8 GCR; /* general count */ | |
| 59 | UINT8 CCR; /* CRC control */ | |
| 60 | UINT8 LTAR; /* logical address track (=track destination) */ | |
| 61 | ||
| 62 | /* internal state */ | |
| 63 | UINT8 drive; | |
| 64 | UINT8 side; | |
| 65 | UINT8 data[128]; /* sector buffer */ | |
| 66 | UINT32 data_size; /* size of data */ | |
| 67 | UINT32 data_idx; /* current read/write position in data */ | |
| 68 | UINT32 data_id; /* chrd_id for sector write */ | |
| 69 | UINT8 index_pulse; | |
| 70 | ||
| 71 | /* trigger delayed actions (bottom halves) */ | |
| 72 | emu_timer* timer_cont; | |
| 73 | ||
| 74 | }; | |
| 75 | ||
| 76 | ||
| 77 | ||
| 78 | /* macro-command numbers */ | |
| 79 | #define CMD_STZ 0x2 /* seek track zero */ | |
| 80 | #define CMD_SEK 0x3 /* seek */ | |
| 81 | #define CMD_SSR 0x4 /* single sector read */ | |
| 82 | #define CMD_SSW 0x5 /* single sector write */ | |
| 83 | #define CMD_RCR 0x6 /* read CRC */ | |
| 84 | #define CMD_SWD 0x7 /* single sector write with delete data mark */ | |
| 85 | #define CMD_MSW 0xd /* multiple sector write */ | |
| 86 | #define CMD_MSR 0xc /* multiple sector read */ | |
| 87 | #define CMD_FFW 0xb /* free format write */ | |
| 88 | #define CMD_FFR 0xa /* free format read */ | |
| 89 | ||
| 90 | /* coarse delays */ | |
| 91 | #define DELAY_SEEK attotime::from_usec( 100 ) /* track seek time */ | |
| 92 | #define DELAY_ADDR attotime::from_usec( 100 ) /* search-address time */ | |
| 93 | ||
| 94 | ||
| 95 | ||
| 96 | static const char *const mc6843_cmd[16] = | |
| 97 | { | |
| 98 | "---", "---", "STZ", "SEK", "SSR", "SSW", "RCR", "SWD", | |
| 99 | "---", "---", "FFR", "FFW", "MSR", "MSW", "---", "---", | |
| 100 | }; | |
| 101 | ||
| 102 | ||
| 103 | /******************* utility function and macros ********************/ | |
| 104 | ||
| 105 | #define LOG(x) do { if (VERBOSE) logerror x; } while (0) | |
| 106 | ||
| 107 | ||
| 108 | ||
| 109 | INLINE mc6843_t* get_safe_token( device_t *device ) | |
| 110 | { | |
| 111 | assert( device != NULL ); | |
| 112 | assert( device->type() == MC6843 ); | |
| 113 | return (mc6843_t*) downcast<mc6843_device *>(device)->token(); | |
| 114 | } | |
| 115 | ||
| 116 | ||
| 117 | /************************** floppy interface ****************************/ | |
| 118 | ||
| 119 | ||
| 120 | ||
| 121 | static device_t* mc6843_floppy_image ( device_t *device ) | |
| 122 | { | |
| 123 | mc6843_t* mc6843 = get_safe_token( device ); | |
| 124 | return floppy_get_device( device->machine(), mc6843->drive ); | |
| 125 | } | |
| 126 | ||
| 127 | ||
| 128 | ||
| 129 | void mc6843_set_drive( device_t *device, int drive ) | |
| 130 | { | |
| 131 | mc6843_t* mc6843 = get_safe_token( device ); | |
| 132 | mc6843->drive = drive; | |
| 133 | } | |
| 134 | ||
| 135 | ||
| 136 | ||
| 137 | void mc6843_set_side( device_t *device, int side ) | |
| 138 | { | |
| 139 | mc6843_t* mc6843 = get_safe_token( device ); | |
| 140 | mc6843->side = side; | |
| 141 | } | |
| 142 | ||
| 143 | ||
| 144 | ||
| 145 | /* called after ISR or STRB has changed */ | |
| 146 | static void mc6843_status_update( device_t *device ) | |
| 147 | { | |
| 148 | mc6843_t* mc6843 = get_safe_token( device ); | |
| 149 | int irq = 0; | |
| 150 | ||
| 151 | /* ISR3 */ | |
| 152 | if ( (mc6843->CMR & 0x40) || ! mc6843->STRB ) | |
| 153 | mc6843->ISR &= ~8; | |
| 154 | else | |
| 155 | mc6843->ISR |= 8; | |
| 156 | ||
| 157 | /* interrupts */ | |
| 158 | if ( mc6843->ISR & 4 ) | |
| 159 | irq = 1; /* unmaskable */ | |
| 160 | if ( ! (mc6843->CMR & 0x80) ) | |
| 161 | { | |
| 162 | /* maskable */ | |
| 163 | if ( mc6843->ISR & ~4 ) | |
| 164 | irq = 1; | |
| 165 | } | |
| 166 | ||
| 167 | if ( mc6843->iface->irq_func ) | |
| 168 | { | |
| 169 | mc6843->iface->irq_func( device, irq ); | |
| 170 | LOG(( "mc6843_status_update: irq=%i (CMR=%02X, ISR=%02X)\n", irq, mc6843->CMR, mc6843->ISR )); | |
| 171 | } | |
| 172 | } | |
| 173 | ||
| 174 | ||
| 175 | void mc6843_set_index_pulse ( device_t *device, int index_pulse ) | |
| 176 | { | |
| 177 | mc6843_t* mc6843 = get_safe_token( device ); | |
| 178 | mc6843->index_pulse = index_pulse; | |
| 179 | } | |
| 180 | ||
| 181 | ||
| 182 | /* called at end of command */ | |
| 183 | static void mc6843_cmd_end( device_t *device ) | |
| 184 | { | |
| 185 | mc6843_t* mc6843 = get_safe_token( device ); | |
| 186 | int cmd = mc6843->CMR & 0x0f; | |
| 187 | if ( ( cmd == CMD_STZ ) || ( cmd == CMD_SEK ) ) | |
| 188 | { | |
| 189 | mc6843->ISR |= 0x02; /* set Settling Time Complete */ | |
| 190 | } | |
| 191 | else | |
| 192 | { | |
| 193 | mc6843->ISR |= 0x01; /* set Macro Command Complete */ | |
| 194 | } | |
| 195 | mc6843->STRA &= ~0x80; /* clear Busy */ | |
| 196 | mc6843->CMR &= 0xf0; /* clear command */ | |
| 197 | mc6843_status_update( device ); | |
| 198 | } | |
| 199 | ||
| 200 | ||
| 201 | ||
| 202 | /* Seek Track Zero bottom half */ | |
| 203 | static void mc6843_finish_STZ( device_t *device ) | |
| 204 | { | |
| 205 | mc6843_t* mc6843 = get_safe_token( device ); | |
| 206 | device_t* img = mc6843_floppy_image( device ); | |
| 207 | int i; | |
| 208 | ||
| 209 | /* seek to track zero */ | |
| 210 | for ( i=0; i<83; i++ ) | |
| 211 | { | |
| 212 | if (floppy_tk00_r(img) == CLEAR_LINE) | |
| 213 | break; | |
| 214 | floppy_drive_seek( img, -1 ); | |
| 215 | } | |
| 216 | ||
| 217 | LOG(( "%f mc6843_finish_STZ: actual=%i\n", device->machine().time().as_double(), floppy_drive_get_current_track( img ) )); | |
| 218 | ||
| 219 | /* update state */ | |
| 220 | mc6843->CTAR = 0; | |
| 221 | mc6843->GCR = 0; | |
| 222 | mc6843->SAR = 0; | |
| 223 | mc6843->STRB |= floppy_tk00_r(img) << 4; | |
| 224 | ||
| 225 | mc6843_cmd_end( device ); | |
| 226 | } | |
| 227 | ||
| 228 | ||
| 229 | ||
| 230 | /* Seek bottom half */ | |
| 231 | static void mc6843_finish_SEK( device_t *device ) | |
| 232 | { | |
| 233 | mc6843_t* mc6843 = get_safe_token( device ); | |
| 234 | device_t* img = mc6843_floppy_image( device ); | |
| 235 | ||
| 236 | /* seek to track */ | |
| 237 | floppy_drive_seek( img, mc6843->GCR - mc6843->CTAR ); | |
| 238 | ||
| 239 | LOG(( "%f mc6843_finish_SEK: from %i to %i (actual=%i)\n", device->machine().time().as_double(), mc6843->CTAR, mc6843->GCR, floppy_drive_get_current_track( img ) )); | |
| 240 | ||
| 241 | /* update state */ | |
| 242 | mc6843->CTAR = mc6843->GCR; | |
| 243 | mc6843->SAR = 0; | |
| 244 | mc6843_cmd_end( device ); | |
| 245 | } | |
| 246 | ||
| 247 | ||
| 248 | ||
| 249 | /* preamble to all sector read / write commands, returns 1 if found */ | |
| 250 | static int mc6843_address_search( device_t *device, chrn_id* id ) | |
| 251 | { | |
| 252 | mc6843_t* mc6843 = get_safe_token( device ); | |
| 253 | device_t* img = mc6843_floppy_image( device ); | |
| 254 | int r = 0; | |
| 255 | ||
| 256 | while ( 1 ) | |
| 257 | { | |
| 258 | if ( ( ! floppy_drive_get_next_id( img, mc6843->side, id ) ) || ( id->flags & ID_FLAG_CRC_ERROR_IN_ID_FIELD ) || ( id->N != 0 ) ) | |
| 259 | { | |
| 260 | /* read address error */ | |
| 261 | LOG(( "%f mc6843_address_search: get_next_id failed\n", device->machine().time().as_double() )); | |
| 262 | mc6843->STRB |= 0x0a; /* set CRC error & Sector Address Undetected */ | |
| 263 | mc6843_cmd_end( device ); | |
| 264 | return 0; | |
| 265 | } | |
| 266 | ||
| 267 | if ( id->C != mc6843->LTAR ) | |
| 268 | { | |
| 269 | /* track mismatch */ | |
| 270 | LOG(( "%f mc6843_address_search: track mismatch: logical=%i real=%i\n", device->machine().time().as_double(), mc6843->LTAR, id->C )); | |
| 271 | mc6843->data[0] = id->C; /* make the track number available to the CPU */ | |
| 272 | mc6843->STRA |= 0x20; /* set Track Not Equal */ | |
| 273 | mc6843_cmd_end( device ); | |
| 274 | return 0; | |
| 275 | } | |
| 276 | ||
| 277 | if ( id->R == mc6843->SAR ) | |
| 278 | { | |
| 279 | /* found! */ | |
| 280 | LOG(( "%f mc6843_address_search: sector %i found on track %i\n", device->machine().time().as_double(), id->R, id->C )); | |
| 281 | if ( ! (mc6843->CMR & 0x20) ) | |
| 282 | { | |
| 283 | mc6843->ISR |= 0x04; /* if no DMA, set Status Sense */ | |
| 284 | } | |
| 285 | return 1; | |
| 286 | } | |
| 287 | ||
| 288 | if ( floppy_drive_get_flag_state( img, FLOPPY_DRIVE_INDEX ) ) | |
| 289 | { | |
| 290 | r++; | |
| 291 | if ( r >= 4 ) | |
| 292 | { | |
| 293 | /* time-out after 3 full revolutions */ | |
| 294 | LOG(( "%f mc6843_address_search: no sector %i found after 3 revolutions\n", device->machine().time().as_double(), mc6843->SAR )); | |
| 295 | mc6843->STRB |= 0x08; /* set Sector Address Undetected */ | |
| 296 | mc6843_cmd_end( device ); | |
| 297 | return 0; | |
| 298 | } | |
| 299 | } | |
| 300 | } | |
| 301 | ||
| 302 | return 0; /* unreachable */ | |
| 303 | } | |
| 304 | ||
| 305 | ||
| 306 | ||
| 307 | /* preamble specific to read commands (adds extra checks) */ | |
| 308 | static int mc6843_address_search_read( device_t *device, chrn_id* id ) | |
| 309 | { | |
| 310 | mc6843_t* mc6843 = get_safe_token( device ); | |
| 311 | if ( ! mc6843_address_search( device, id ) ) | |
| 312 | return 0; | |
| 313 | ||
| 314 | if ( id->flags & ID_FLAG_CRC_ERROR_IN_DATA_FIELD ) | |
| 315 | { | |
| 316 | LOG(( "%f mc6843_address_search_read: data CRC error\n", device->machine().time().as_double() )); | |
| 317 | mc6843->STRB |= 0x06; /* set CRC error & Data Mark Undetected */ | |
| 318 | mc6843_cmd_end( device ); | |
| 319 | return 0; | |
| 320 | } | |
| 321 | ||
| 322 | if ( id->flags & ID_FLAG_DELETED_DATA ) | |
| 323 | { | |
| 324 | LOG(( "%f mc6843_address_search_read: deleted data\n", device->machine().time().as_double() )); | |
| 325 | mc6843->STRA |= 0x02; /* set Delete Data Mark Detected */ | |
| 326 | } | |
| 327 | ||
| 328 | return 1; | |
| 329 | } | |
| 330 | ||
| 331 | ||
| 332 | ||
| 333 | ||
| 334 | /* Read CRC bottom half */ | |
| 335 | static void mc6843_finish_RCR( device_t *device ) | |
| 336 | { | |
| 337 | chrn_id id; | |
| 338 | if ( ! mc6843_address_search_read( device, &id ) ) | |
| 339 | return; | |
| 340 | mc6843_cmd_end( device ); | |
| 341 | } | |
| 342 | ||
| 343 | ||
| 344 | ||
| 345 | /* Single / Multiple Sector Read bottom half */ | |
| 346 | static void mc6843_cont_SR( device_t *device ) | |
| 347 | { | |
| 348 | mc6843_t* mc6843 = get_safe_token( device ); | |
| 349 | chrn_id id; | |
| 350 | device_t* img = mc6843_floppy_image( device ); | |
| 351 | ||
| 352 | /* sector seek */ | |
| 353 | if ( ! mc6843_address_search_read( device, &id ) ) | |
| 354 | return; | |
| 355 | ||
| 356 | /* sector read */ | |
| 357 | floppy_drive_read_sector_data( img, mc6843->side, id.data_id, mc6843->data, 128 ); | |
| 358 | mc6843->data_idx = 0; | |
| 359 | mc6843->data_size = 128; | |
| 360 | mc6843->STRA |= 0x01; /* set Data Transfer Request */ | |
| 361 | mc6843_status_update( device ); | |
| 362 | } | |
| 363 | ||
| 364 | ||
| 365 | ||
| 366 | /* Single / Multiple Sector Write bottom half */ | |
| 367 | static void mc6843_cont_SW( device_t *device ) | |
| 368 | { | |
| 369 | mc6843_t* mc6843 = get_safe_token( device ); | |
| 370 | chrn_id id; | |
| 371 | ||
| 372 | /* sector seek */ | |
| 373 | if ( ! mc6843_address_search( device, &id ) ) | |
| 374 | return; | |
| 375 | ||
| 376 | /* setup sector write buffer */ | |
| 377 | mc6843->data_idx = 0; | |
| 378 | mc6843->data_size = 128; | |
| 379 | mc6843->STRA |= 0x01; /* set Data Transfer Request */ | |
| 380 | mc6843->data_id = id.data_id; /* for subsequent write sector command */ | |
| 381 | mc6843_status_update( device ); | |
| 382 | } | |
| 383 | ||
| 384 | ||
| 385 | ||
| 386 | /* bottom halves, called to continue / finish a command after some delay */ | |
| 387 | static TIMER_CALLBACK( mc6843_cont ) | |
| 388 | { | |
| 389 | device_t* device = (device_t*) ptr; | |
| 390 | mc6843_t* mc6843 = get_safe_token( device ); | |
| 391 | int cmd = mc6843->CMR & 0x0f; | |
| 392 | ||
| 393 | LOG(( "%f mc6843_cont: timer called for cmd=%s(%i)\n", device->machine().time().as_double(), mc6843_cmd[cmd], cmd )); | |
| 394 | ||
| 395 | mc6843->timer_cont->adjust( attotime::never ); | |
| 396 | ||
| 397 | switch ( cmd ) | |
| 398 | { | |
| 399 | case CMD_STZ: mc6843_finish_STZ( device ); break; | |
| 400 | case CMD_SEK: mc6843_finish_SEK( device ); break; | |
| 401 | case CMD_SSR: mc6843_cont_SR( device ); break; | |
| 402 | case CMD_SSW: mc6843_cont_SW( device ); break; | |
| 403 | case CMD_RCR: mc6843_finish_RCR( device ); break; | |
| 404 | case CMD_SWD: mc6843_cont_SW( device ); break; | |
| 405 | case CMD_MSW: mc6843_cont_SW( device ); break; | |
| 406 | case CMD_MSR: mc6843_cont_SR( device ); break; | |
| 407 | } | |
| 408 | } | |
| 409 | ||
| 410 | ||
| 411 | ||
| 412 | /************************** CPU interface ****************************/ | |
| 413 | ||
| 414 | ||
| 415 | ||
| 416 | READ8_DEVICE_HANDLER ( mc6843_r ) | |
| 417 | { | |
| 418 | mc6843_t* mc6843 = get_safe_token( device ); | |
| 419 | UINT8 data = 0; | |
| 420 | ||
| 421 | switch ( offset ) { | |
| 422 | case 0: /* Data Input Register (DIR) */ | |
| 423 | { | |
| 424 | int cmd = mc6843->CMR & 0x0f; | |
| 425 | ||
| 426 | LOG(( "%f $%04x mc6843_r: data input cmd=%s(%i), pos=%i/%i, GCR=%i, ", | |
| 427 | space.machine().time().as_double(), space.machine().firstcpu->pcbase( ), | |
| 428 | mc6843_cmd[cmd], cmd, mc6843->data_idx, | |
| 429 | mc6843->data_size, mc6843->GCR )); | |
| 430 | ||
| 431 | if ( cmd == CMD_SSR || cmd == CMD_MSR ) | |
| 432 | { | |
| 433 | /* sector read */ | |
| 434 | assert( mc6843->data_size > 0 ); | |
| 435 | assert( mc6843->data_idx < mc6843->data_size ); | |
| 436 | assert( mc6843->data_idx < sizeof(mc6843->data) ); | |
| 437 | data = mc6843->data[ mc6843->data_idx ]; | |
| 438 | mc6843->data_idx++; | |
| 439 | ||
| 440 | if ( mc6843->data_idx >= mc6843->data_size ) | |
| 441 | { | |
| 442 | /* end of sector read */ | |
| 443 | ||
| 444 | mc6843->STRA &= ~0x01; /* clear Data Transfer Request */ | |
| 445 | ||
| 446 | if ( cmd == CMD_MSR ) | |
| 447 | { | |
| 448 | /* schedule next sector in multiple sector read */ | |
| 449 | mc6843->GCR--; | |
| 450 | mc6843->SAR++; | |
| 451 | if ( mc6843->GCR == 0xff ) | |
| 452 | { | |
| 453 | mc6843_cmd_end( device ); | |
| 454 | } | |
| 455 | else if ( mc6843->SAR > 26 ) | |
| 456 | ||
| 457 | { | |
| 458 | mc6843->STRB |= 0x08; /* set Sector Address Undetected */ | |
| 459 | mc6843_cmd_end( device ); | |
| 460 | } | |
| 461 | else | |
| 462 | { | |
| 463 | mc6843->timer_cont->adjust( DELAY_ADDR ); | |
| 464 | } | |
| 465 | } | |
| 466 | else | |
| 467 | { | |
| 468 | mc6843_cmd_end( device ); | |
| 469 | } | |
| 470 | } | |
| 471 | } | |
| 472 | else if ( cmd == 0 ) | |
| 473 | { | |
| 474 | data = mc6843->data[0]; | |
| 475 | } | |
| 476 | else | |
| 477 | { | |
| 478 | /* XXX TODO: other read modes */ | |
| 479 | data = mc6843->data[0]; | |
| 480 | logerror( "$%04x mc6843 read in unsupported command mode %i\n", space.machine().firstcpu->pcbase( ), cmd ); | |
| 481 | } | |
| 482 | ||
| 483 | LOG(( "data=%02X\n", data )); | |
| 484 | ||
| 485 | break; | |
| 486 | } | |
| 487 | ||
| 488 | case 1: /* Current-Track Address Register (CTAR) */ | |
| 489 | data = mc6843->CTAR; | |
| 490 | LOG(( "%f $%04x mc6843_r: read CTAR %i (actual=%i)\n", | |
| 491 | space.machine().time().as_double(), space.machine().firstcpu->pcbase( ), data, | |
| 492 | floppy_drive_get_current_track( mc6843_floppy_image( device ) ) )); | |
| 493 | break; | |
| 494 | ||
| 495 | case 2: /* Interrupt Status Register (ISR) */ | |
| 496 | data = mc6843->ISR; | |
| 497 | LOG(( "%f $%04x mc6843_r: read ISR %02X: cmd=%scomplete settle=%scomplete sense-rq=%i STRB=%i\n", | |
| 498 | space.machine().time().as_double(), space.machine().firstcpu->pcbase( ), data, | |
| 499 | (data & 1) ? "" : "not-" , (data & 2) ? "" : "not-", | |
| 500 | (data >> 2) & 1, (data >> 3) & 1 )); | |
| 501 | ||
| 502 | /* reset */ | |
| 503 | mc6843->ISR &= 8; /* keep STRB */ | |
| 504 | mc6843_status_update( device ); | |
| 505 | break; | |
| 506 | ||
| 507 | case 3: /* Status Register A (STRA) */ | |
| 508 | { | |
| 509 | /* update */ | |
| 510 | device_t* img = mc6843_floppy_image( device ); | |
| 511 | int flag = floppy_drive_get_flag_state( img, FLOPPY_DRIVE_READY); | |
| 512 | mc6843->STRA &= 0xa3; | |
| 513 | if ( flag & FLOPPY_DRIVE_READY ) | |
| 514 | mc6843->STRA |= 0x04; | |
| 515 | ||
| 516 | mc6843->STRA |= !floppy_tk00_r(img) << 3; | |
| 517 | mc6843->STRA |= !floppy_wpt_r(img) << 4; | |
| 518 | ||
| 519 | if ( mc6843->index_pulse ) | |
| 520 | mc6843->STRA |= 0x40; | |
| 521 | ||
| 522 | data = mc6843->STRA; | |
| 523 | LOG(( "%f $%04x mc6843_r: read STRA %02X: data-rq=%i del-dta=%i ready=%i t0=%i wp=%i trk-dif=%i idx=%i busy=%i\n", | |
| 524 | space.machine().time().as_double(), space.machine().firstcpu->pcbase( ), data, | |
| 525 | data & 1, (data >> 1) & 1, (data >> 2) & 1, (data >> 3) & 1, | |
| 526 | (data >> 4) & 1, (data >> 5) & 1, (data >> 6) & 1, (data >> 7) & 1 )); | |
| 527 | break; | |
| 528 | } | |
| 529 | ||
| 530 | case 4: /* Status Register B (STRB) */ | |
| 531 | data = mc6843->STRB; | |
| 532 | LOG(( "%f $%04x mc6843_r: read STRB %02X: data-err=%i CRC-err=%i dta--mrk-err=%i sect-mrk-err=%i seek-err=%i fi=%i wr-err=%i hard-err=%i\n", | |
| 533 | space.machine().time().as_double(), space.machine().firstcpu->pcbase( ), data, | |
| 534 | data & 1, (data >> 1) & 1, (data >> 2) & 1, (data >> 3) & 1, | |
| 535 | (data >> 4) & 1, (data >> 5) & 1, (data >> 6) & 1, (data >> 7) & 1 )); | |
| 536 | ||
| 537 | /* (partial) reset */ | |
| 538 | mc6843->STRB &= ~0xfb; | |
| 539 | mc6843_status_update( device ); | |
| 540 | break; | |
| 541 | ||
| 542 | case 7: /* Logical-Track Address Register (LTAR) */ | |
| 543 | data = mc6843->LTAR; | |
| 544 | LOG(( "%f $%04x mc6843_r: read LTAR %i (actual=%i)\n", | |
| 545 | space.machine().time().as_double(), space.machine().firstcpu->pcbase( ), data, | |
| 546 | floppy_drive_get_current_track( mc6843_floppy_image( device ) ) )); | |
| 547 | break; | |
| 548 | ||
| 549 | default: | |
| 550 | logerror( "$%04x mc6843 invalid read offset %i\n", space.machine().firstcpu->pcbase( ), offset ); | |
| 551 | } | |
| 552 | ||
| 553 | return data; | |
| 554 | } | |
| 555 | ||
| 556 | WRITE8_DEVICE_HANDLER ( mc6843_w ) | |
| 557 | { | |
| 558 | mc6843_t* mc6843 = get_safe_token( device ); | |
| 559 | switch ( offset ) { | |
| 560 | case 0: /* Data Output Register (DOR) */ | |
| 561 | { | |
| 562 | int cmd = mc6843->CMR & 0x0f; | |
| 563 | int FWF = (mc6843->CMR >> 4) & 1; | |
| 564 | ||
| 565 | LOG(( "%f $%04x mc6843_w: data output cmd=%s(%i), pos=%i/%i, GCR=%i, data=%02X\n", | |
| 566 | space.machine().time().as_double(), space.machine().firstcpu->pcbase( ), | |
| 567 | mc6843_cmd[cmd], cmd, mc6843->data_idx, | |
| 568 | mc6843->data_size, mc6843->GCR, data )); | |
| 569 | ||
| 570 | if ( cmd == CMD_SSW || cmd == CMD_MSW || cmd == CMD_SWD ) | |
| 571 | { | |
| 572 | /* sector write */ | |
| 573 | assert( mc6843->data_size > 0 ); | |
| 574 | assert( mc6843->data_idx < mc6843->data_size ); | |
| 575 | assert( mc6843->data_idx < sizeof(mc6843->data) ); | |
| 576 | mc6843->data[ mc6843->data_idx ] = data; | |
| 577 | mc6843->data_idx++; | |
| 578 | if ( mc6843->data_idx >= mc6843->data_size ) | |
| 579 | { | |
| 580 | /* end of sector write */ | |
| 581 | device_t* img = mc6843_floppy_image( device ); | |
| 582 | ||
| 583 | LOG(( "%f $%04x mc6843_w: write sector %i\n", space.machine().time().as_double(), space.machine().firstcpu->pcbase( ), mc6843->data_id )); | |
| 584 | ||
| 585 | floppy_drive_write_sector_data( | |
| 586 | img, mc6843->side, mc6843->data_id, | |
| 587 | mc6843->data, mc6843->data_size, | |
| 588 | (cmd == CMD_SWD) ? ID_FLAG_DELETED_DATA : 0 ); | |
| 589 | ||
| 590 | mc6843->STRA &= ~0x01; /* clear Data Transfer Request */ | |
| 591 | ||
| 592 | if ( cmd == CMD_MSW ) | |
| 593 | { | |
| 594 | mc6843->GCR--; | |
| 595 | mc6843->SAR++; | |
| 596 | if ( mc6843->GCR == 0xff ) | |
| 597 | { | |
| 598 | mc6843_cmd_end( device ); | |
| 599 | } | |
| 600 | else if ( mc6843->SAR > 26 ) | |
| 601 | ||
| 602 | { | |
| 603 | mc6843->STRB |= 0x08; /* set Sector Address Undetected */ | |
| 604 | mc6843_cmd_end( device ); | |
| 605 | } | |
| 606 | else | |
| 607 | { | |
| 608 | mc6843->timer_cont->adjust( DELAY_ADDR ); | |
| 609 | } | |
| 610 | } | |
| 611 | else | |
| 612 | { | |
| 613 | mc6843_cmd_end( device ); | |
| 614 | } | |
| 615 | } | |
| 616 | } | |
| 617 | else if ( (cmd == CMD_FFW) && FWF ) | |
| 618 | { | |
| 619 | /* assume we are formatting */ | |
| 620 | UINT8 nibble; | |
| 621 | nibble = | |
| 622 | (data & 0x01) | | |
| 623 | ((data & 0x04) >> 1 )| | |
| 624 | ((data & 0x10) >> 2 )| | |
| 625 | ((data & 0x40) >> 3 ); | |
| 626 | ||
| 627 | assert( mc6843->data_idx < sizeof(mc6843->data) ); | |
| 628 | ||
| 629 | mc6843->data[mc6843->data_idx / 2] = | |
| 630 | (mc6843->data[mc6843->data_idx / 2] << 4) | nibble; | |
| 631 | ||
| 632 | if ( (mc6843->data_idx == 0) && (mc6843->data[0] == 0xfe ) ) | |
| 633 | { | |
| 634 | /* address mark detected */ | |
| 635 | mc6843->data_idx = 2; | |
| 636 | } | |
| 637 | else if ( mc6843->data_idx == 9 ) | |
| 638 | { | |
| 639 | /* address id field complete */ | |
| 640 | if ( (mc6843->data[2] == 0) && (mc6843->data[4] == 0) ) | |
| 641 | { | |
| 642 | /* valid address id field */ | |
| 643 | device_t* img = mc6843_floppy_image( device ); | |
| 644 | UINT8 track = mc6843->data[1]; | |
| 645 | UINT8 sector = mc6843->data[3]; | |
| 646 | UINT8 filler = 0xe5; /* standard Thomson filler */ | |
| 647 | LOG(( "%f $%04x mc6843_w: address id detected track=%i sector=%i\n", space.machine().time().as_double(), space.machine().firstcpu->pcbase( ), track, sector)); | |
| 648 | floppy_drive_format_sector( img, mc6843->side, sector, track, 0, sector, 0, filler ); | |
| 649 | } | |
| 650 | else | |
| 651 | { | |
| 652 | /* abort */ | |
| 653 | mc6843->data_idx = 0; | |
| 654 | } | |
| 655 | } | |
| 656 | else if ( mc6843->data_idx > 0 ) | |
| 657 | { | |
| 658 | /* accumulate address id field */ | |
| 659 | mc6843->data_idx++; | |
| 660 | } | |
| 661 | } | |
| 662 | else if ( cmd == 0 ) | |
| 663 | { | |
| 664 | /* nothing */ | |
| 665 | } | |
| 666 | else | |
| 667 | { | |
| 668 | /* XXX TODO: other write modes */ | |
| 669 | logerror( "$%04x mc6843 write %02X in unsupported command mode %i (FWF=%i)\n", space.machine().firstcpu->pcbase( ), data, cmd, FWF ); | |
| 670 | } | |
| 671 | break; | |
| 672 | } | |
| 673 | ||
| 674 | case 1: /* Current-Track Address Register (CTAR) */ | |
| 675 | mc6843->CTAR = data & 0x7f; | |
| 676 | LOG(( "%f $%04x mc6843_w: set CTAR to %i %02X (actual=%i) \n", | |
| 677 | space.machine().time().as_double(), space.machine().firstcpu->pcbase( ), mc6843->CTAR, data, | |
| 678 | floppy_drive_get_current_track( mc6843_floppy_image( device ) ) )); | |
| 679 | break; | |
| 680 | ||
| 681 | case 2: /* Command Register (CMR) */ | |
| 682 | { | |
| 683 | int cmd = data & 15; | |
| 684 | ||
| 685 | LOG(( "%f $%04x mc6843_w: set CMR to $%02X: cmd=%s(%i) FWF=%i DMA=%i ISR3-intr=%i fun-intr=%i\n", | |
| 686 | space.machine().time().as_double(), space.machine().firstcpu->pcbase( ), | |
| 687 | data, mc6843_cmd[cmd], cmd, (data >> 4) & 1, (data >> 5) & 1, | |
| 688 | (data >> 6) & 1, (data >> 7) & 1 )); | |
| 689 | ||
| 690 | /* sanitize state */ | |
| 691 | mc6843->STRA &= ~0x81; /* clear Busy & Data Transfer Request */ | |
| 692 | mc6843->data_idx = 0; | |
| 693 | mc6843->data_size = 0; | |
| 694 | ||
| 695 | /* commands are initiated by updating some flags and scheduling | |
| 696 | a bottom-half (mc6843_cont) after some delay */ | |
| 697 | ||
| 698 | switch (cmd) | |
| 699 | { | |
| 700 | case CMD_SSW: | |
| 701 | case CMD_SSR: | |
| 702 | case CMD_SWD: | |
| 703 | case CMD_RCR: | |
| 704 | case CMD_MSR: | |
| 705 | case CMD_MSW: | |
| 706 | mc6843->STRA |= 0x80; /* set Busy */ | |
| 707 | mc6843->STRA &= ~0x22; /* clear Track Not Equal & Delete Data Mark Detected */ | |
| 708 | mc6843->STRB &= ~0x04; /* clear Data Mark Undetected */ | |
| 709 | mc6843->timer_cont->adjust( DELAY_ADDR ); | |
| 710 | break; | |
| 711 | case CMD_STZ: | |
| 712 | case CMD_SEK: | |
| 713 | mc6843->STRA |= 0x80; /* set Busy */ | |
| 714 | mc6843->timer_cont->adjust( DELAY_SEEK ); | |
| 715 | break; | |
| 716 | case CMD_FFW: | |
| 717 | case CMD_FFR: | |
| 718 | mc6843->data_idx = 0; | |
| 719 | mc6843->STRA |= 0x01; /* set Data Transfer Request */ | |
| 720 | break; | |
| 721 | } | |
| 722 | ||
| 723 | mc6843->CMR = data; | |
| 724 | mc6843_status_update( device ); | |
| 725 | break; | |
| 726 | } | |
| 727 | ||
| 728 | case 3: /* Set-Up Register (SUR) */ | |
| 729 | mc6843->SUR = data; | |
| 730 | ||
| 731 | /* assume CLK freq = 1MHz (IBM 3740 compatibility) */ | |
| 732 | LOG(( "%f $%04x mc6843_w: set SUR to $%02X: head settling time=%fms, track-to-track seek time=%f\n", | |
| 733 | space.machine().time().as_double(), space.machine().firstcpu->pcbase( ), | |
| 734 | data, 4.096 * (data & 15), 1.024 * ((data >> 4) & 15) )); | |
| 735 | break; | |
| 736 | ||
| 737 | case 4: /* Sector Address Register (SAR) */ | |
| 738 | mc6843->SAR = data & 0x1f; | |
| 739 | LOG(( "%f $%04x mc6843_w: set SAR to %i (%02X)\n", space.machine().time().as_double(), space.machine().firstcpu->pcbase( ), mc6843->SAR, data )); | |
| 740 | break; | |
| 741 | ||
| 742 | case 5: /* General Count Register (GCR) */ | |
| 743 | mc6843->GCR = data & 0x7f; | |
| 744 | LOG(( "%f $%04x mc6843_w: set GCR to %i (%02X)\n", space.machine().time().as_double(), space.machine().firstcpu->pcbase( ), mc6843->GCR, data )); | |
| 745 | break; | |
| 746 | ||
| 747 | case 6: /* CRC Control Register (CCR) */ | |
| 748 | mc6843->CCR = data & 3; | |
| 749 | LOG(( "%f $%04x mc6843_w: set CCR to %02X: CRC=%s shift=%i\n", | |
| 750 | space.machine().time().as_double(), space.machine().firstcpu->pcbase( ), data, | |
| 751 | (data & 1) ? "enabled" : "disabled", (data >> 1) & 1 )); | |
| 752 | break; | |
| 753 | ||
| 754 | case 7: /* Logical-Track Address Register (LTAR) */ | |
| 755 | mc6843->LTAR = data & 0x7f; | |
| 756 | LOG(( "%f $%04x mc6843_w: set LTAR to %i %02X (actual=%i)\n", | |
| 757 | space.machine().time().as_double(), space.machine().firstcpu->pcbase( ), mc6843->LTAR, data, | |
| 758 | floppy_drive_get_current_track( mc6843_floppy_image( device ) ) )); | |
| 759 | break; | |
| 760 | ||
| 761 | default: | |
| 762 | logerror( "$%04x mc6843 invalid write offset %i (data=$%02X)\n", space.machine().firstcpu->pcbase( ), offset, data ); | |
| 763 | } | |
| 764 | } | |
| 765 | ||
| 766 | ||
| 767 | ||
| 768 | /************************ reset *****************************/ | |
| 769 | ||
| 770 | static DEVICE_RESET( mc6843 ) | |
| 771 | { | |
| 772 | mc6843_t* mc6843 = get_safe_token( device ); | |
| 773 | int i; | |
| 774 | LOG (( "mc6843 reset\n" )); | |
| 775 | ||
| 776 | /* setup/reset floppy drive */ | |
| 777 | for ( i = 0; i < 4; i++ ) | |
| 778 | { | |
| 779 | device_t * img = floppy_get_device( device->machine(), i ); | |
| 780 | floppy_mon_w(img, CLEAR_LINE); | |
| 781 | floppy_drive_set_ready_state( img, FLOPPY_DRIVE_READY, 0 ); | |
| 782 | floppy_drive_set_rpm( img, 300. ); | |
| 783 | } | |
| 784 | ||
| 785 | /* reset registers */ | |
| 786 | mc6843->CMR &= 0xf0; /* zero only command */ | |
| 787 | mc6843->ISR = 0; | |
| 788 | mc6843->STRA &= 0x5c; | |
| 789 | mc6843->SAR = 0; | |
| 790 | mc6843->STRB &= 0x20; | |
| 791 | mc6843_status_update( device ); | |
| 792 | ||
| 793 | mc6843->data_size = 0; | |
| 794 | mc6843->data_idx = 0; | |
| 795 | mc6843->timer_cont->adjust( attotime::never ); | |
| 796 | } | |
| 797 | ||
| 798 | ||
| 799 | ||
| 800 | /************************ start *****************************/ | |
| 801 | ||
| 802 | static DEVICE_START( mc6843 ) | |
| 803 | { | |
| 804 | mc6843_t* mc6843 = get_safe_token( device ); | |
| 805 | ||
| 806 | mc6843->iface = (const mc6843_interface*)device->static_config(); | |
| 807 | ||
| 808 | mc6843->timer_cont = device->machine().scheduler().timer_alloc(FUNC(mc6843_cont), (void*) device) ; | |
| 809 | ||
| 810 | state_save_register_item( device->machine(),"mc6843", device->tag(), 0, mc6843->CTAR ); | |
| 811 | state_save_register_item( device->machine(),"mc6843", device->tag(), 0, mc6843->CMR ); | |
| 812 | state_save_register_item( device->machine(),"mc6843", device->tag(), 0, mc6843->ISR ); | |
| 813 | state_save_register_item( device->machine(),"mc6843", device->tag(), 0, mc6843->SUR ); | |
| 814 | state_save_register_item( device->machine(),"mc6843", device->tag(), 0, mc6843->STRA ); | |
| 815 | state_save_register_item( device->machine(),"mc6843", device->tag(), 0, mc6843->STRB ); | |
| 816 | state_save_register_item( device->machine(),"mc6843", device->tag(), 0, mc6843->SAR ); | |
| 817 | state_save_register_item( device->machine(),"mc6843", device->tag(), 0, mc6843->GCR ); | |
| 818 | state_save_register_item( device->machine(),"mc6843", device->tag(), 0, mc6843->CCR ); | |
| 819 | state_save_register_item( device->machine(),"mc6843", device->tag(), 0, mc6843->LTAR ); | |
| 820 | state_save_register_item( device->machine(),"mc6843", device->tag(), 0, mc6843->drive ); | |
| 821 | state_save_register_item( device->machine(),"mc6843", device->tag(), 0, mc6843->side ); | |
| 822 | state_save_register_item_array( device->machine(),"mc6843", device->tag(), 0, mc6843->data ); | |
| 823 | state_save_register_item( device->machine(),"mc6843", device->tag(), 0, mc6843->data_size ); | |
| 824 | state_save_register_item( device->machine(),"mc6843", device->tag(), 0, mc6843->data_idx ); | |
| 825 | state_save_register_item( device->machine(),"mc6843", device->tag(), 0, mc6843->data_id ); | |
| 826 | } | |
| 827 | ||
| 828 | ||
| 829 | const device_type MC6843 = &device_creator<mc6843_device>; | |
| 830 | ||
| 831 | mc6843_device::mc6843_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) | |
| 832 | : device_t(mconfig, MC6843, "Motorola MC6843 floppy controller", tag, owner, clock) | |
| 833 | { | |
| 834 | m_token = global_alloc_clear(mc6843_t); | |
| 835 | } | |
| 836 | ||
| 837 | //------------------------------------------------- | |
| 838 | // device_config_complete - perform any | |
| 839 | // operations now that the configuration is | |
| 840 | // complete | |
| 841 | //------------------------------------------------- | |
| 842 | ||
| 843 | void mc6843_device::device_config_complete() | |
| 844 | { | |
| 845 | } | |
| 846 | ||
| 847 | //------------------------------------------------- | |
| 848 | // device_start - device-specific startup | |
| 849 | //------------------------------------------------- | |
| 850 | ||
| 851 | void mc6843_device::device_start() | |
| 852 | { | |
| 853 | DEVICE_START_NAME( mc6843 )(this); | |
| 854 | } | |
| 855 | ||
| 856 | //------------------------------------------------- | |
| 857 | // device_reset - device-specific reset | |
| 858 | //------------------------------------------------- | |
| 859 | ||
| 860 | void mc6843_device::device_reset() | |
| 861 | { | |
| 862 | DEVICE_RESET_NAME( mc6843 )(this); | |
| 863 | } |
| r21684 | r21685 | |
|---|---|---|
| 1 | /********************************************************************** | |
| 2 | ||
| 3 | Copyright (C) Antoine Mine' 2007 | |
| 4 | ||
| 5 | Motorola 6843 Floppy Disk Controller emulation. | |
| 6 | ||
| 7 | **********************************************************************/ | |
| 8 | ||
| 9 | #ifndef MC6843_H | |
| 10 | #define MC6843_H | |
| 11 | ||
| 12 | class mc6843_device : public device_t | |
| 13 | { | |
| 14 | public: | |
| 15 | mc6843_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); | |
| 16 | ~mc6843_device() { global_free(m_token); } | |
| 17 | ||
| 18 | // access to legacy token | |
| 19 | void *token() const { assert(m_token != NULL); return m_token; } | |
| 20 | protected: | |
| 21 | // device-level overrides | |
| 22 | virtual void device_config_complete(); | |
| 23 | virtual void device_start(); | |
| 24 | virtual void device_reset(); | |
| 25 | private: | |
| 26 | // internal state | |
| 27 | void *m_token; | |
| 28 | }; | |
| 29 | ||
| 30 | extern const device_type MC6843; | |
| 31 | ||
| 32 | ||
| 33 | ||
| 34 | /* ---------- configuration ------------ */ | |
| 35 | ||
| 36 | struct mc6843_interface | |
| 37 | { | |
| 38 | void ( * irq_func ) ( device_t *device, int state ); | |
| 39 | }; | |
| 40 | ||
| 41 | ||
| 42 | #define MCFG_MC6843_ADD(_tag, _intrf) \ | |
| 43 | MCFG_DEVICE_ADD(_tag, MC6843, 0) \ | |
| 44 | MCFG_DEVICE_CONFIG(_intrf) | |
| 45 | ||
| 46 | #define MCFG_MC6843_REMOVE(_tag) \ | |
| 47 | MCFG_DEVICE_REMOVE(_tag) | |
| 48 | ||
| 49 | ||
| 50 | /* ---------- functions ------------ */ | |
| 51 | ||
| 52 | extern DECLARE_READ8_DEVICE_HANDLER ( mc6843_r ); | |
| 53 | extern DECLARE_WRITE8_DEVICE_HANDLER ( mc6843_w ); | |
| 54 | ||
| 55 | extern void mc6843_set_drive ( device_t *device, int drive ); | |
| 56 | extern void mc6843_set_side ( device_t *device, int side ); | |
| 57 | extern void mc6843_set_index_pulse ( device_t *device, int index_pulse ); | |
| 58 | ||
| 59 | #endif |
| r21684 | r21685 | |
|---|---|---|
| 1 | /*************************************************************************** | |
| 2 | ||
| 3 | MIOT 6530 emulation | |
| 4 | ||
| 5 | The timer seems to follow these rules: | |
| 6 | - When the timer flag changes from 0 to 1 the timer continues to count | |
| 7 | down at a 1 cycle rate. | |
| 8 | - When the timer is being read or written the timer flag is reset. | |
| 9 | - When the timer flag is set and the timer contents are 0, the counting | |
| 10 | stops. | |
| 11 | ||
| 12 | From the operation of the KIM1 it expects the irqflag to be set whenever | |
| 13 | the unit is reset. This is something that is not clear from the datasheet | |
| 14 | and should be verified against real hardware. | |
| 15 | ||
| 16 | ***************************************************************************/ | |
| 17 | ||
| 18 | #include "emu.h" | |
| 19 | #include "mos6530.h" | |
| 20 | ||
| 21 | ||
| 22 | /*************************************************************************** | |
| 23 | CONSTANTS | |
| 24 | ***************************************************************************/ | |
| 25 | ||
| 26 | enum | |
| 27 | { | |
| 28 | TIMER_IDLE, | |
| 29 | TIMER_COUNTING, | |
| 30 | TIMER_FINISHING | |
| 31 | }; | |
| 32 | ||
| 33 | #define TIMER_FLAG 0x80 | |
| 34 | ||
| 35 | ||
| 36 | ||
| 37 | /*************************************************************************** | |
| 38 | TYPE DEFINITIONS | |
| 39 | ***************************************************************************/ | |
| 40 | ||
| 41 | struct mos6530_port | |
| 42 | { | |
| 43 | devcb_resolved_read8 in_port_func; | |
| 44 | devcb_resolved_write8 out_port_func; | |
| 45 | ||
| 46 | UINT8 in; | |
| 47 | UINT8 out; | |
| 48 | UINT8 ddr; | |
| 49 | }; | |
| 50 | ||
| 51 | ||
| 52 | struct mos6530_state | |
| 53 | { | |
| 54 | devcb_resolved_write_line out_irq_func; | |
| 55 | ||
| 56 | mos6530_port port[2]; | |
| 57 | ||
| 58 | UINT8 irqstate; | |
| 59 | UINT8 irqenable; | |
| 60 | ||
| 61 | UINT8 timershift; | |
| 62 | UINT8 timerstate; | |
| 63 | emu_timer * timer; | |
| 64 | ||
| 65 | UINT32 clock; | |
| 66 | }; | |
| 67 | ||
| 68 | ||
| 69 | ||
| 70 | /*************************************************************************** | |
| 71 | INLINE FUNCTIONS | |
| 72 | ***************************************************************************/ | |
| 73 | ||
| 74 | /*------------------------------------------------- | |
| 75 | get_safe_token - convert a device's token | |
| 76 | into a mos6530_state | |
| 77 | -------------------------------------------------*/ | |
| 78 | ||
| 79 | INLINE mos6530_state *get_safe_token(device_t *device) | |
| 80 | { | |
| 81 | assert(device != NULL); | |
| 82 | assert(device->type() == MOS6530); | |
| 83 | return (mos6530_state *)downcast<mos6530_device *>(device)->token(); | |
| 84 | } | |
| 85 | ||
| 86 | ||
| 87 | /*------------------------------------------------- | |
| 88 | update_irqstate - update the IRQ state | |
| 89 | based on interrupt enables | |
| 90 | -------------------------------------------------*/ | |
| 91 | ||
| 92 | INLINE void update_irqstate(device_t *device) | |
| 93 | { | |
| 94 | mos6530_state *miot = get_safe_token(device); | |
| 95 | UINT8 out = miot->port[1].out; | |
| 96 | ||
| 97 | if ( miot->irqenable ) | |
| 98 | out = ( ( miot->irqstate & TIMER_FLAG ) ? 0x00 : 0x80 ) | ( out & 0x7F ); | |
| 99 | ||
| 100 | if (!miot->port[1].out_port_func.isnull()) | |
| 101 | miot->port[1].out_port_func(0, out); | |
| 102 | else | |
| 103 | logerror("6530MIOT chip %s: Port B is being written to but has no handler.\n", device->tag()); | |
| 104 | } | |
| 105 | ||
| 106 | ||
| 107 | /*------------------------------------------------- | |
| 108 | get_timer - return the current timer value | |
| 109 | -------------------------------------------------*/ | |
| 110 | ||
| 111 | INLINE UINT8 get_timer(mos6530_state *miot) | |
| 112 | { | |
| 113 | /* if idle, return 0 */ | |
| 114 | if (miot->timerstate == TIMER_IDLE) | |
| 115 | return 0; | |
| 116 | ||
| 117 | /* if counting, return the number of ticks remaining */ | |
| 118 | else if (miot->timerstate == TIMER_COUNTING) | |
| 119 | return miot->timer->remaining().as_ticks(miot->clock) >> miot->timershift; | |
| 120 | ||
| 121 | /* if finishing, return the number of ticks without the shift */ | |
| 122 | else | |
| 123 | return miot->timer->remaining().as_ticks(miot->clock); | |
| 124 | } | |
| 125 | ||
| 126 | ||
| 127 | /*************************************************************************** | |
| 128 | INTERNAL FUNCTIONS | |
| 129 | ***************************************************************************/ | |
| 130 | ||
| 131 | /*------------------------------------------------- | |
| 132 | timer_end_callback - callback to process the | |
| 133 | timer | |
| 134 | -------------------------------------------------*/ | |
| 135 | ||
| 136 | static TIMER_CALLBACK( timer_end_callback ) | |
| 137 | { | |
| 138 | device_t *device = (device_t *)ptr; | |
| 139 | mos6530_state *miot = get_safe_token(device); | |
| 140 | ||
| 141 | assert(miot->timerstate != TIMER_IDLE); | |
| 142 | ||
| 143 | /* if we finished counting, switch to the finishing state */ | |
| 144 | if (miot->timerstate == TIMER_COUNTING) | |
| 145 | { | |
| 146 | miot->timerstate = TIMER_FINISHING; | |
| 147 | miot->timer->adjust(attotime::from_ticks(256, miot->clock)); | |
| 148 | ||
| 149 | /* signal timer IRQ as well */ | |
| 150 | miot->irqstate |= TIMER_FLAG; | |
| 151 | update_irqstate(device); | |
| 152 | } | |
| 153 | ||
| 154 | /* if we finished finishing, switch to the idle state */ | |
| 155 | else if (miot->timerstate == TIMER_FINISHING) | |
| 156 | { | |
| 157 | miot->timerstate = TIMER_IDLE; | |
| 158 | miot->timer->adjust(attotime::never); | |
| 159 | } | |
| 160 | } | |
| 161 | ||
| 162 | ||
| 163 | ||
| 164 | /*************************************************************************** | |
| 165 | I/O ACCESS | |
| 166 | ***************************************************************************/ | |
| 167 | ||
| 168 | /*------------------------------------------------- | |
| 169 | mos6530_w - master I/O write access | |
| 170 | -------------------------------------------------*/ | |
| 171 | ||
| 172 | WRITE8_DEVICE_HANDLER( mos6530_w ) | |
| 173 | { | |
| 174 | mos6530_state *miot = get_safe_token(device); | |
| 175 | ||
| 176 | /* if A2 == 1, we are writing to the timer */ | |
| 177 | if (offset & 0x04) | |
| 178 | { | |
| 179 | static const UINT8 timershift[4] = { 0, 3, 6, 10 }; | |
| 180 | attotime curtime = space.machine().time(); | |
| 181 | INT64 target; | |
| 182 | ||
| 183 | /* A0-A1 contain the timer divisor */ | |
| 184 | miot->timershift = timershift[offset & 3]; | |
| 185 | ||
| 186 | /* A3 contains the timer IRQ enable */ | |
| 187 | if (offset & 8) | |
| 188 | miot->irqenable |= TIMER_FLAG; | |
| 189 | else | |
| 190 | miot->irqenable &= ~TIMER_FLAG; | |
| 191 | ||
| 192 | /* writes here clear the timer flag */ | |
| 193 | if (miot->timerstate != TIMER_FINISHING || get_timer(miot) != 0xff) | |
| 194 | miot->irqstate &= ~TIMER_FLAG; | |
| 195 | update_irqstate(device); | |
| 196 | ||
| 197 | /* update the timer */ | |
| 198 | miot->timerstate = TIMER_COUNTING; | |
| 199 | target = curtime.as_ticks(miot->clock) + 1 + (data << miot->timershift); | |
| 200 | miot->timer->adjust(attotime::from_ticks(target, miot->clock) - curtime); | |
| 201 | } | |
| 202 | ||
| 203 | /* if A2 == 0, we are writing to the I/O section */ | |
| 204 | else | |
| 205 | { | |
| 206 | /* A1 selects the port */ | |
| 207 | mos6530_port *port = &miot->port[(offset >> 1) & 1]; | |
| 208 | ||
| 209 | /* if A0 == 1, we are writing to the port's DDR */ | |
| 210 | if (offset & 1) | |
| 211 | port->ddr = data; | |
| 212 | ||
| 213 | /* if A0 == 0, we are writing to the port's output */ | |
| 214 | else | |
| 215 | { | |
| 216 | UINT8 olddata = port->out; | |
| 217 | port->out = data; | |
| 218 | ||
| 219 | if ( ( offset & 2 ) && miot->irqenable ) | |
| 220 | { | |
| 221 | olddata = ( ( miot->irqstate & TIMER_FLAG ) ? 0x00 : 0x80 ) | ( olddata & 0x7F ); | |
| 222 | data = ( ( miot->irqstate & TIMER_FLAG ) ? 0x00 : 0x80 ) | ( data & 0x7F ); | |
| 223 | } | |
| 224 | ||
| 225 | if (!port->out_port_func.isnull()) | |
| 226 | port->out_port_func(0, data); | |
| 227 | else | |
| 228 | logerror("6530MIOT chip %s: Port %c is being written to but has no handler. PC: %08X - %02X\n", device->tag(), 'A' + (offset & 1), space.machine().firstcpu->pc(), data); | |
| 229 | } | |
| 230 | } | |
| 231 | } | |
| 232 | ||
| 233 | ||
| 234 | /*------------------------------------------------- | |
| 235 | mos6530_r - master I/O read access | |
| 236 | -------------------------------------------------*/ | |
| 237 | ||
| 238 | READ8_DEVICE_HANDLER( mos6530_r ) | |
| 239 | { | |
| 240 | mos6530_state *miot = get_safe_token(device); | |
| 241 | UINT8 val = 0; | |
| 242 | ||
| 243 | /* if A2 == 1 and A0 == 1, we are reading interrupt flags */ | |
| 244 | if ((offset & 0x05) == 0x05) | |
| 245 | { | |
| 246 | val = miot->irqstate; | |
| 247 | } | |
| 248 | ||
| 249 | /* if A2 == 1 and A0 == 0, we are reading the timer */ | |
| 250 | else if ((offset & 0x05) == 0x04) | |
| 251 | { | |
| 252 | val = get_timer(miot); | |
| 253 | ||
| 254 | /* A3 contains the timer IRQ enable */ | |
| 255 | if (offset & 8) | |
| 256 | miot->irqenable |= TIMER_FLAG; | |
| 257 | else | |
| 258 | miot->irqenable &= ~TIMER_FLAG; | |
| 259 | ||
| 260 | /* implicitly clears the timer flag */ | |
| 261 | if (miot->timerstate != TIMER_FINISHING || val != 0xff) | |
| 262 | miot->irqstate &= ~TIMER_FLAG; | |
| 263 | update_irqstate(device); | |
| 264 | } | |
| 265 | ||
| 266 | /* if A2 == 0 and A0 == anything, we are reading from ports */ | |
| 267 | else | |
| 268 | { | |
| 269 | /* A1 selects the port */ | |
| 270 | mos6530_port *port = &miot->port[(offset >> 1) & 1]; | |
| 271 | ||
| 272 | /* if A0 == 1, we are reading the port's DDR */ | |
| 273 | if (offset & 1) | |
| 274 | val = port->ddr; | |
| 275 | ||
| 276 | /* if A0 == 0, we are reading the port as an input */ | |
| 277 | else | |
| 278 | { | |
| 279 | UINT8 out = port->out; | |
| 280 | ||
| 281 | if ( ( offset & 2 ) && miot->irqenable ) | |
| 282 | out = ( ( miot->irqstate & TIMER_FLAG ) ? 0x00 : 0x80 ) | ( out & 0x7F ); | |
| 283 | ||
| 284 | /* call the input callback if it exists */ | |
| 285 | if (!port->in_port_func.isnull()) | |
| 286 | { | |
| 287 | port->in = port->in_port_func(0); | |
| 288 | } | |
| 289 | else | |
| 290 | logerror("6530MIOT chip %s: Port %c is being read but has no handler. PC: %08X\n", device->tag(), 'A' + (offset & 1), space.machine().firstcpu->pc()); | |
| 291 | ||
| 292 | /* apply the DDR to the result */ | |
| 293 | val = (out & port->ddr) | (port->in & ~port->ddr); | |
| 294 | } | |
| 295 | } | |
| 296 | return val; | |
| 297 | } | |
| 298 | ||
| 299 | ||
| 300 | /*------------------------------------------------- | |
| 301 | mos6530_porta_in_set - set port A input | |
| 302 | value | |
| 303 | -------------------------------------------------*/ | |
| 304 | ||
| 305 | void mos6530_porta_in_set(device_t *device, UINT8 data, UINT8 mask) | |
| 306 | { | |
| 307 | mos6530_state *miot = get_safe_token(device); | |
| 308 | miot->port[0].in = (miot->port[0].in & ~mask) | (data & mask); | |
| 309 | } | |
| 310 | ||
| 311 | ||
| 312 | /*------------------------------------------------- | |
| 313 | mos6530_portb_in_set - set port B input | |
| 314 | value | |
| 315 | -------------------------------------------------*/ | |
| 316 | ||
| 317 | void mos6530_portb_in_set(device_t *device, UINT8 data, UINT8 mask) | |
| 318 | { | |
| 319 | mos6530_state *miot = get_safe_token(device); | |
| 320 | miot->port[1].in = (miot->port[1].in & ~mask) | (data & mask); | |
| 321 | } | |
| 322 | ||
| 323 | ||
| 324 | /*------------------------------------------------- | |
| 325 | mos6530_porta_in_get - return port A input | |
| 326 | value | |
| 327 | -------------------------------------------------*/ | |
| 328 | ||
| 329 | UINT8 mos6530_porta_in_get(device_t *device) | |
| 330 | { | |
| 331 | mos6530_state *miot = get_safe_token(device); | |
| 332 | return miot->port[0].in; | |
| 333 | } | |
| 334 | ||
| 335 | ||
| 336 | /*------------------------------------------------- | |
| 337 | mos6530_portb_in_get - return port B input | |
| 338 | value | |
| 339 | -------------------------------------------------*/ | |
| 340 | ||
| 341 | UINT8 mos6530_portb_in_get(device_t *device) | |
| 342 | { | |
| 343 | mos6530_state *miot = get_safe_token(device); | |
| 344 | return miot->port[1].in; | |
| 345 | } | |
| 346 | ||
| 347 | ||
| 348 | /*------------------------------------------------- | |
| 349 | mos6530_porta_in_get - return port A output | |
| 350 | value | |
| 351 | -------------------------------------------------*/ | |
| 352 | ||
| 353 | UINT8 mos6530_porta_out_get(device_t *device) | |
| 354 | { | |
| 355 | mos6530_state *miot = get_safe_token(device); | |
| 356 | return miot->port[0].out; | |
| 357 | } | |
| 358 | ||
| 359 | ||
| 360 | /*------------------------------------------------- | |
| 361 | mos6530_portb_in_get - return port B output | |
| 362 | value | |
| 363 | -------------------------------------------------*/ | |
| 364 | ||
| 365 | UINT8 mos6530_portb_out_get(device_t *device) | |
| 366 | { | |
| 367 | mos6530_state *miot = get_safe_token(device); | |
| 368 | return miot->port[1].out; | |
| 369 | } | |
| 370 | ||
| 371 | ||
| 372 | /*************************************************************************** | |
| 373 | DEVICE INTERFACE | |
| 374 | ***************************************************************************/ | |
| 375 | ||
| 376 | static DEVICE_START( mos6530 ) | |
| 377 | { | |
| 378 | mos6530_state *miot = get_safe_token(device); | |
| 379 | const mos6530_interface *intf = (const mos6530_interface*)device->static_config(); | |
| 380 | ||
| 381 | /* validate arguments */ | |
| 382 | assert(device != NULL); | |
| 383 | assert(device->tag() != NULL); | |
| 384 | ||
| 385 | /* set static values */ | |
| 386 | miot->clock = device->clock(); | |
| 387 | ||
| 388 | /* resolve callbacks */ | |
| 389 | miot->port[0].in_port_func.resolve(intf->in_pa_func, *device); | |
| 390 | miot->port[1].in_port_func.resolve(intf->in_pb_func, *device); | |
| 391 | miot->port[0].out_port_func.resolve(intf->out_pa_func, *device); | |
| 392 | miot->port[1].out_port_func.resolve(intf->out_pb_func, *device); | |
| 393 | ||
| 394 | /* allocate timers */ | |
| 395 | miot->timer = device->machine().scheduler().timer_alloc(FUNC(timer_end_callback), (void *)device); | |
| 396 | ||
| 397 | /* register for save states */ | |
| 398 | device->save_item(NAME(miot->port[0].in)); | |
| 399 | device->save_item(NAME(miot->port[0].out)); | |
| 400 | device->save_item(NAME(miot->port[0].ddr)); | |
| 401 | device->save_item(NAME(miot->port[1].in)); | |
| 402 | device->save_item(NAME(miot->port[1].out)); | |
| 403 | device->save_item(NAME(miot->port[1].ddr)); | |
| 404 | ||
| 405 | device->save_item(NAME(miot->irqstate)); | |
| 406 | device->save_item(NAME(miot->irqenable)); | |
| 407 | ||
| 408 | device->save_item(NAME(miot->timershift)); | |
| 409 | device->save_item(NAME(miot->timerstate)); | |
| 410 | } | |
| 411 | ||
| 412 | ||
| 413 | static DEVICE_RESET( mos6530 ) | |
| 414 | { | |
| 415 | mos6530_state *miot = get_safe_token(device); | |
| 416 | ||
| 417 | /* reset I/O states */ | |
| 418 | miot->port[0].out = 0; | |
| 419 | miot->port[0].ddr = 0; | |
| 420 | miot->port[1].out = 0; | |
| 421 | miot->port[1].ddr = 0; | |
| 422 | ||
| 423 | /* reset IRQ states */ | |
| 424 | miot->irqenable = 0; | |
| 425 | miot->irqstate = TIMER_FLAG; | |
| 426 | update_irqstate(device); | |
| 427 | ||
| 428 | /* reset timer states */ | |
| 429 | miot->timershift = 0; | |
| 430 | miot->timerstate = TIMER_IDLE; | |
| 431 | miot->timer->adjust(attotime::never); | |
| 432 | } | |
| 433 | ||
| 434 | ||
| 435 | const device_type MOS6530 = &device_creator<mos6530_device>; | |
| 436 | ||
| 437 | mos6530_device::mos6530_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) | |
| 438 | : device_t(mconfig, MOS6530, "MOS6530", tag, owner, clock) | |
| 439 | { | |
| 440 | m_token = global_alloc_clear(mos6530_state); | |
| 441 | } | |
| 442 | ||
| 443 | //------------------------------------------------- | |
| 444 | // device_config_complete - perform any | |
| 445 | // operations now that the configuration is | |
| 446 | // complete | |
| 447 | //------------------------------------------------- | |
| 448 | ||
| 449 | void mos6530_device::device_config_complete() | |
| 450 | { | |
| 451 | } | |
| 452 | ||
| 453 | //------------------------------------------------- | |
| 454 | // device_start - device-specific startup | |
| 455 | //------------------------------------------------- | |
| 456 | ||
| 457 | void mos6530_device::device_start() | |
| 458 | { | |
| 459 | DEVICE_START_NAME( mos6530 )(this); | |
| 460 | } | |
| 461 | ||
| 462 | //------------------------------------------------- | |
| 463 | // device_reset - device-specific reset | |
| 464 | //------------------------------------------------- | |
| 465 | ||
| 466 | void mos6530_device::device_reset() | |
| 467 | { | |
| 468 | DEVICE_RESET_NAME( mos6530 )(this); | |
| 469 | } |
| r21684 | r21685 | |
|---|---|---|
| 1 | /********************************************************************** | |
| 2 | ||
| 3 | MOS Technology 6530 Memory, I/O, Timer Array emulation | |
| 4 | ||
| 5 | Copyright MESS Team. | |
| 6 | Visit http://mamedev.org for licensing and usage restrictions. | |
| 7 | ||
| 8 | ********************************************************************** | |
| 9 | _____ _____ | |
| 10 | Vss 1 |* \_/ | 40 PA1 | |
| 11 | PA0 2 | | 39 PA2 | |
| 12 | phi2 3 | | 38 PA3 | |
| 13 | RS0 4 | | 37 PA4 | |
| 14 | A9 5 | | 36 PA5 | |
| 15 | A8 6 | | 35 PA6 | |
| 16 | A7 7 | | 34 PA7 | |
| 17 | A6 8 | | 33 DB0 | |
| 18 | R/W 9 | | 32 DB1 | |
| 19 | A5 10 | MCS6530 | 31 DB2 | |
| 20 | A4 11 | | 30 DB3 | |
| 21 | A3 12 | | 29 DB4 | |
| 22 | A2 13 | | 28 DB5 | |
| 23 | A1 14 | | 27 DB6 | |
| 24 | A0 15 | | 26 DB7 | |
| 25 | _RES 16 | | 25 PB0 | |
| 26 | IRQ/PB7 17 | | 24 PB1 | |
| 27 | CS1/PB6 18 | | 23 PB2 | |
| 28 | CS2/PB5 19 | | 22 PB3 | |
| 29 | Vcc 20 |_____________| 21 PB4 | |
| 30 | ||
| 31 | **********************************************************************/ | |
| 32 | ||
| 33 | #ifndef __MIOT6530_H__ | |
| 34 | #define __MIOT6530_H__ | |
| 35 | ||
| 36 | /*************************************************************************** | |
| 37 | MACROS / CONSTANTS | |
| 38 | ***************************************************************************/ | |
| 39 | ||
| 40 | class mos6530_device : public device_t | |
| 41 | { | |
| 42 | public: | |
| 43 | mos6530_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); | |
| 44 | ~mos6530_device() { global_free(m_token); } | |
| 45 | ||
| 46 | // access to legacy token | |
| 47 | void *token() const { assert(m_token != NULL); return m_token; } | |
| 48 | protected: | |
| 49 | // device-level overrides | |
| 50 | virtual void device_config_complete(); | |
| 51 | virtual void device_start(); | |
| 52 | virtual void device_reset(); | |
| 53 | private: | |
| 54 | // internal state | |
| 55 | void *m_token; | |
| 56 | }; | |
| 57 | ||
| 58 | extern const device_type MOS6530; | |
| 59 | ||
| 60 | ||
| 61 | #define MCFG_MOS6530_ADD(_tag, _clock, _config) \ | |
| 62 | MCFG_DEVICE_ADD((_tag), MOS6530, _clock) \ | |
| 63 | MCFG_DEVICE_CONFIG(_config) | |
| 64 | ||
| 65 | #define MOS6530_INTERFACE(name) \ | |
| 66 | const mos6530_interface (name) = | |
| 67 | ||
| 68 | /*************************************************************************** | |
| 69 | TYPE DEFINITIONS | |
| 70 | ***************************************************************************/ | |
| 71 | ||
| 72 | struct mos6530_interface | |
| 73 | { | |
| 74 | devcb_read8 in_pa_func; | |
| 75 | devcb_write8 out_pa_func; | |
| 76 | ||
| 77 | devcb_read8 in_pb_func; | |
| 78 | devcb_write8 out_pb_func; | |
| 79 | }; | |
| 80 | ||
| 81 | /*************************************************************************** | |
| 82 | PROTOTYPES | |
| 83 | ***************************************************************************/ | |
| 84 | ||
| 85 | DECLARE_READ8_DEVICE_HANDLER( mos6530_r ); | |
| 86 | DECLARE_WRITE8_DEVICE_HANDLER( mos6530_w ); | |
| 87 | ||
| 88 | void mos6530_porta_in_set(device_t *device, UINT8 data, UINT8 mask); | |
| 89 | void mos6530_portb_in_set(device_t *device, UINT8 data, UINT8 mask); | |
| 90 | ||
| 91 | UINT8 mos6530_porta_in_get(device_t *device); | |
| 92 | UINT8 mos6530_portb_in_get(device_t *device); | |
| 93 | ||
| 94 | UINT8 mos6530_porta_out_get(device_t *device); | |
| 95 | UINT8 mos6530_portb_out_get(device_t *device); | |
| 96 | ||
| 97 | #endif |
| r21684 | r21685 | |
|---|---|---|
| 1 | /*************************************************************************** | |
| 2 | commodore c64 home computer | |
| 3 | ||
| 4 | peter.trauner@jk.uni-linz.ac.at | |
| 5 | documentation | |
| 6 | www.funet.fi | |
| 7 | ***************************************************************************/ | |
| 8 | ||
| 9 | /* | |
| 10 | 2008-09-06: Tape status for C64 & C128 [FP & RZ] | |
| 11 | - tape loading works | |
| 12 | - tap files are supported | |
| 13 | - tape writing works | |
| 14 | */ | |
| 15 | ||
| 16 | #include "emu.h" | |
| 17 | ||
| 18 | #include "cpu/m6502/m6510.h" | |
| 19 | #include "cpu/z80/z80.h" | |
| 20 | #include "sound/mos6581.h" | |
| 21 | #include "machine/6526cia.h" | |
| 22 | #include "machine/cbmiec.h" | |
| 23 | ||
| 24 | #include "includes/cbm.h" | |
| 25 | #include "includes/c64_legacy.h" | |
| 26 | ||
| 27 | #include "imagedev/cassette.h" | |
| 28 | #include "imagedev/cartslot.h" | |
| 29 | ||
| 30 | #define VERBOSE_LEVEL 0 | |
| 31 | #define DBG_LOG( MACHINE, N, M, A ) \ | |
| 32 | do { \ | |
| 33 | if(VERBOSE_LEVEL >= N) \ | |
| 34 | { \ | |
| 35 | if( M ) \ | |
| 36 | logerror("%11.6f: %-24s", MACHINE.time().as_double(), (char*) M ); \ | |
| 37 | logerror A; \ | |
| 38 | } \ | |
| 39 | } while (0) | |
| 40 | ||
| 41 | #define log_cart 0 | |
| 42 | ||
| 43 | /* Info from http://unusedino.de/ec64/technical/misc/c64/64doc.html */ | |
| 44 | /* | |
| 45 | ||
| 46 | The leftmost column of the table contains addresses in hexadecimal | |
| 47 | notation. The columns aside it introduce all possible memory | |
| 48 | configurations. The default mode is on the left, and the absolutely | |
| 49 | most rarely used Ultimax game console configuration is on the right. | |
| 50 | (Has anybody ever seen any Ultimax games?) Each memory configuration | |
| 51 | column has one or more four-digit binary numbers as a title. The bits, | |
| 52 | from left to right, represent the state of the -LORAM, -HIRAM, -GAME | |
| 53 | and -EXROM lines, respectively. The bits whose state does not matter | |
| 54 | are marked with "x". For instance, when the Ultimax video game | |
| 55 | configuration is active (the -GAME line is shorted to ground), the | |
| 56 | -LORAM and -HIRAM lines have no effect. | |
| 57 | ||
| 58 | default 001x Ultimax | |
| 59 | 1111 101x 1000 011x 00x0 1110 0100 1100 xx01 | |
| 60 | 10000 | |
| 61 | ---------------------------------------------------------------------- | |
| 62 | F000 | |
| 63 | Kernal RAM RAM Kernal RAM Kernal Kernal Kernal ROMH(* | |
| 64 | E000 | |
| 65 | ---------------------------------------------------------------------- | |
| 66 | D000 IO/C IO/C IO/RAM IO/C RAM IO/C IO/C IO/C I/O | |
| 67 | ---------------------------------------------------------------------- | |
| 68 | C000 RAM RAM RAM RAM RAM RAM RAM RAM - | |
| 69 | ---------------------------------------------------------------------- | |
| 70 | B000 | |
| 71 | BASIC RAM RAM RAM RAM BASIC ROMH ROMH - | |
| 72 | A000 | |
| 73 | ---------------------------------------------------------------------- | |
| 74 | 9000 | |
| 75 | RAM RAM RAM RAM RAM ROML RAM ROML ROML(* | |
| 76 | 8000 | |
| 77 | ---------------------------------------------------------------------- | |
| 78 | 7000 | |
| 79 | ||
| 80 | 6000 | |
| 81 | RAM RAM RAM RAM RAM RAM RAM RAM - | |
| 82 | 5000 | |
| 83 | ||
| 84 | 4000 | |
| 85 | ---------------------------------------------------------------------- | |
| 86 | 3000 | |
| 87 | ||
| 88 | 2000 RAM RAM RAM RAM RAM RAM RAM RAM - | |
| 89 | ||
| 90 | 1000 | |
| 91 | ---------------------------------------------------------------------- | |
| 92 | 0000 RAM RAM RAM RAM RAM RAM RAM RAM RAM | |
| 93 | ---------------------------------------------------------------------- | |
| 94 | ||
| 95 | *) Internal memory does not respond to write accesses to these | |
| 96 | areas. | |
| 97 | ||
| 98 | ||
| 99 | Legend: Kernal E000-FFFF Kernal ROM. | |
| 100 | ||
| 101 | IO/C D000-DFFF I/O address space or Character | |
| 102 | generator ROM, selected by | |
| 103 | -CHAREN. If the CHAREN bit is | |
| 104 | clear, the character generator | |
| 105 | ROM will be selected. If it is | |
| 106 | set, the I/O chips are | |
| 107 | accessible. | |
| 108 | ||
| 109 | IO/RAM D000-DFFF I/O address space or RAM, | |
| 110 | selected by -CHAREN. If the | |
| 111 | CHAREN bit is clear, the | |
| 112 | character generator ROM will | |
| 113 | be selected. If it is set, the | |
| 114 | internal RAM is accessible. | |
| 115 | ||
| 116 | I/O D000-DFFF I/O address space. | |
| 117 | The -CHAREN line has no effect. | |
| 118 | ||
| 119 | BASIC A000-BFFF BASIC ROM. | |
| 120 | ||
| 121 | ROMH A000-BFFF or External ROM with the -ROMH line | |
| 122 | E000-FFFF connected to its -CS line. | |
| 123 | ||
| 124 | ROML 8000-9FFF External ROM with the -ROML line | |
| 125 | connected to its -CS line. | |
| 126 | ||
| 127 | RAM various ranges Commodore 64's internal RAM. | |
| 128 | ||
| 129 | - 1000-7FFF and Open address space. | |
| 130 | A000-CFFF The Commodore 64's memory chips | |
| 131 | do not detect any memory accesses | |
| 132 | to this area except the VIC-II's | |
| 133 | DMA and memory refreshes. | |
| 134 | ||
| 135 | NOTE: Whenever the processor tries to write to any ROM area | |
| 136 | (Kernal, BASIC, CHAROM, ROML, ROMH), the data will get | |
| 137 | "through the ROM" to the C64's internal RAM. | |
| 138 | ||
| 139 | For this reason, you can easily copy data from ROM to RAM, | |
| 140 | without any bank switching. But implementing external | |
| 141 | memory expansions without DMA is very hard, as you have to | |
| 142 | use a 256 byte window on the I/O1 or I/O2 area, like | |
| 143 | GEORAM, or the Ultimax memory configuration, if you do not | |
| 144 | want the data to be written both to internal and external | |
| 145 | RAM. | |
| 146 | ||
| 147 | However, this is not true for the Ultimax video game | |
| 148 | configuration. In that mode, the internal RAM ignores all | |
| 149 | memory accesses outside the area $0000-$0FFF, unless they | |
| 150 | are performed by the VIC, and you can write to external | |
| 151 | memory at $1000-$CFFF and $E000-$FFFF, if any, without | |
| 152 | changing the contents of the internal RAM. | |
| 153 | ||
| 154 | */ | |
| 155 | ||
| 156 | static void c64_bankswitch( running_machine &machine, int reset ) | |
| 157 | { | |
| 158 | legacy_c64_state *state = machine.driver_data<legacy_c64_state>(); | |
| 159 | int loram, hiram, charen; | |
| 160 | int ultimax_mode = 0; | |
| 161 | int data = machine.device<m6510_device>("maincpu")->get_port() & 0x07; | |
| 162 | ||
| 163 | /* Are we in Ultimax mode? */ | |
| 164 | if (!state->m_game && state->m_exrom) | |
| 165 | ultimax_mode = 1; | |
| 166 | ||
| 167 | DBG_LOG(machine, 1, "bankswitch", ("%d\n", data & 7)); | |
| 168 | loram = (data & 1) ? 1 : 0; | |
| 169 | hiram = (data & 2) ? 1 : 0; | |
| 170 | charen = (data & 4) ? 1 : 0; | |
| 171 | //logerror("Bankswitch mode || charen, state->m_ultimax\n"); | |
| 172 | //logerror("%d, %d, %d, %d || %d, %d \n", loram, hiram, state->m_game, state->m_exrom, charen, ultimax_mode); | |
| 173 | ||
| 174 | if (ultimax_mode) | |
| 175 | { | |
| 176 | state->m_io_enabled = 1; // charen has no effect in ultimax_mode | |
| 177 | ||
| 178 | state->membank("bank1")->set_base(state->m_roml); | |
| 179 | state->membank("bank3")->set_base(state->m_memory + 0xa000); | |
| 180 | state->membank("bank4")->set_base(state->m_romh); | |
| 181 | machine.device("maincpu")->memory().space(AS_PROGRAM).nop_write(0xe000, 0xffff); | |
| 182 | } | |
| 183 | else | |
| 184 | { | |
| 185 | /* 0x8000-0x9000 */ | |
| 186 | if (loram && hiram && !state->m_exrom) | |
| 187 | { | |
| 188 | state->membank("bank1")->set_base(state->m_roml); | |
| 189 | } | |
| 190 | else | |
| 191 | { | |
| 192 | state->membank("bank1")->set_base(state->m_memory + 0x8000); | |
| 193 | } | |
| 194 | ||
| 195 | /* 0xa000 */ | |
| 196 | if (hiram && !state->m_game && !state->m_exrom) | |
| 197 | state->membank("bank3")->set_base(state->m_romh); | |
| 198 | ||
| 199 | else if (loram && hiram && state->m_game) | |
| 200 | state->membank("bank3")->set_base(state->m_basic); | |
| 201 | ||
| 202 | else | |
| 203 | state->membank("bank3")->set_base(state->m_memory + 0xa000); | |
| 204 | ||
| 205 | /* 0xd000 */ | |
| 206 | // RAM | |
| 207 | if (!loram && !hiram && (state->m_game || !state->m_exrom)) | |
| 208 | { | |
| 209 | state->m_io_enabled = 0; | |
| 210 | state->m_io_ram_r_ptr = state->m_memory + 0xd000; | |
| 211 | state->m_io_ram_w_ptr = state->m_memory + 0xd000; | |
| 212 | } | |
| 213 | // IO/RAM | |
| 214 | else if (loram && !hiram && !state->m_game) // remember we cannot be in ultimax_mode, no need of !state->m_exrom | |
| 215 | { | |
| 216 | state->m_io_enabled = 1; | |
| 217 | state->m_io_ram_r_ptr = (!charen) ? state->m_chargen : state->m_memory + 0xd000; | |
| 218 | state->m_io_ram_w_ptr = state->m_memory + 0xd000; | |
| 219 | } | |
| 220 | // IO/C | |
| 221 | else | |
| 222 | { | |
| 223 | state->m_io_enabled = charen ? 1 : 0; | |
| 224 | ||
| 225 | if (!charen) | |
| 226 | { | |
| 227 | state->m_io_ram_r_ptr = state->m_chargen; | |
| 228 | state->m_io_ram_w_ptr = state->m_memory + 0xd000; | |
| 229 | } | |
| 230 | } | |
| 231 | ||
| 232 | /* 0xe000-0xf000 */ | |
| 233 | state->membank("bank4")->set_base(hiram ? state->m_kernal : state->m_memory + 0xe000); | |
| 234 | state->membank("bank5")->set_base(state->m_memory + 0xe000); | |
| 235 | } | |
| 236 | ||
| 237 | /* make sure the opbase function gets called each time */ | |
| 238 | /* NPW 15-May-2008 - Another hack in the C64 drivers broken! */ | |
| 239 | /* opbase->mem_max = 0xcfff; */ | |
| 240 | ||
| 241 | state->m_old_game = state->m_game; | |
| 242 | state->m_old_exrom = state->m_exrom; | |
| 243 | state->m_old_data = data; | |
| 244 | } | |
| 245 | ||
| 246 | int c64_paddle_read( device_t *device, address_space &space, int which ) | |
| 247 | { | |
| 248 | running_machine &machine = device->machine(); | |
| 249 | int pot1 = 0xff, pot2 = 0xff, pot3 = 0xff, pot4 = 0xff, temp; | |
| 250 | UINT8 cia0porta = mos6526_pa_r(machine.device("cia_0"), space, 0); | |
| 251 | int controller1 = machine.root_device().ioport("CTRLSEL")->read() & 0x07; | |
| 252 | int controller2 = machine.root_device().ioport("CTRLSEL")->read() & 0x70; | |
| 253 | /* Notice that only a single input is defined for Mouse & Lightpen in both ports */ | |
| 254 | switch (controller1) | |
| 255 | { | |
| 256 | case 0x01: | |
| 257 | if (which) | |
| 258 | pot2 = machine.root_device().ioport("PADDLE2")->read(); | |
| 259 | else | |
| 260 | pot1 = machine.root_device().ioport("PADDLE1")->read(); | |
| 261 | break; | |
| 262 | ||
| 263 | case 0x02: | |
| 264 | if (which) | |
| 265 | pot2 = machine.root_device().ioport("TRACKY")->read(); | |
| 266 | else | |
| 267 | pot1 = machine.root_device().ioport("TRACKX")->read(); | |
| 268 | break; | |
| 269 | ||
| 270 | case 0x03: | |
| 271 | if (which && (machine.root_device().ioport("JOY1_2B")->read() & 0x20)) /* Joy1 Button 2 */ | |
| 272 | pot1 = 0x00; | |
| 273 | break; | |
| 274 | ||
| 275 | case 0x04: | |
| 276 | if (which) | |
| 277 | pot2 = machine.root_device().ioport("LIGHTY")->read(); | |
| 278 | else | |
| 279 | pot1 = machine.root_device().ioport("LIGHTX")->read(); | |
| 280 | break; | |
| 281 | ||
| 282 | case 0x06: | |
| 283 | if (which && (machine.root_device().ioport("OTHER")->read() & 0x04)) /* Lightpen Signal */ | |
| 284 | pot2 = 0x00; | |
| 285 | break; | |
| 286 | ||
| 287 | case 0x00: | |
| 288 | case 0x07: | |
| 289 | break; | |
| 290 | ||
| 291 | default: | |
| 292 | logerror("Invalid Controller Setting %d\n", controller1); | |
| 293 | break; | |
| 294 | } | |
| 295 | ||
| 296 | switch (controller2) | |
| 297 | { | |
| 298 | case 0x10: | |
| 299 | if (which) | |
| 300 | pot4 = machine.root_device().ioport("PADDLE4")->read(); | |
| 301 | else | |
| 302 | pot3 = machine.root_device().ioport("PADDLE3")->read(); | |
| 303 | break; | |
| 304 | ||
| 305 | case 0x20: | |
| 306 | if (which) | |
| 307 | pot4 = machine.root_device().ioport("TRACKY")->read(); | |
| 308 | else | |
| 309 | pot3 = machine.root_device().ioport("TRACKX")->read(); | |
| 310 | break; | |
| 311 | ||
| 312 | case 0x30: | |
| 313 | if (which && (machine.root_device().ioport("JOY2_2B")->read() & 0x20)) /* Joy2 Button 2 */ | |
| 314 | pot4 = 0x00; | |
| 315 | break; | |
| 316 | ||
| 317 | case 0x40: | |
| 318 | if (which) | |
| 319 | pot4 = machine.root_device().ioport("LIGHTY")->read(); | |
| 320 | else | |
| 321 | pot3 = machine.root_device().ioport("LIGHTX")->read(); | |
| 322 | break; | |
| 323 | ||
| 324 | case 0x60: | |
| 325 | if (which && (machine.root_device().ioport("OTHER")->read() & 0x04)) /* Lightpen Signal */ | |
| 326 | pot4 = 0x00; | |
| 327 | break; | |
| 328 | ||
| 329 | case 0x00: | |
| 330 | case 0x70: | |
| 331 | break; | |
| 332 | ||
| 333 | default: | |
| 334 | logerror("Invalid Controller Setting %d\n", controller1); | |
| 335 | break; | |
| 336 | } | |
| 337 | ||
| 338 | if (machine.root_device().ioport("CTRLSEL")->read() & 0x80) /* Swap */ | |
| 339 | { | |
| 340 | temp = pot1; pot1 = pot3; pot3 = temp; | |
| 341 | temp = pot2; pot2 = pot4; pot4 = temp; | |
| 342 | } | |
| 343 | ||
| 344 | switch (cia0porta & 0xc0) | |
| 345 | { | |
| 346 | case 0x40: | |
| 347 | return which ? pot2 : pot1; | |
| 348 | ||
| 349 | case 0x80: | |
| 350 | return which ? pot4 : pot3; | |
| 351 | ||
| 352 | case 0xc0: | |
| 353 | return which ? pot2 : pot1; | |
| 354 | ||
| 355 | default: | |
| 356 | return 0; | |
| 357 | } | |
| 358 | } | |
| 359 | ||
| 360 | READ8_HANDLER( c64_colorram_read ) | |
| 361 | { | |
| 362 | legacy_c64_state *state = space.machine().driver_data<legacy_c64_state>(); | |
| 363 | return state->m_colorram[offset & 0x3ff]; | |
| 364 | } | |
| 365 | ||
| 366 | WRITE8_HANDLER( c64_colorram_write ) | |
| 367 | { | |
| 368 | legacy_c64_state *state = space.machine().driver_data<legacy_c64_state>(); | |
| 369 | state->m_colorram[offset & 0x3ff] = data | 0xf0; | |
| 370 | } | |
| 371 | ||
| 372 | /*********************************************** | |
| 373 | ||
| 374 | C64 Cartridges | |
| 375 | ||
| 376 | ***********************************************/ | |
| 377 | ||
| 378 | /* Info based on http://ist.uwaterloo.ca/~schepers/formats/CRT.TXT */ | |
| 379 | /* Please refer to the webpage for the latest version and for a very | |
| 380 | complete listing of various cart types and their bankswitch tricks */ | |
| 381 | /* | |
| 382 | Cartridge files were introduced in the CCS64 emulator, written by Per | |
| 383 | Hakan Sundell, and use the ".CRT" file extension. This format was created | |
| 384 | to handle the various ROM cartridges that exist, such as Action Replay, the | |
| 385 | Power cartridge, and the Final Cartridge. | |
| 386 | ||
| 387 | Normal game cartridges can load into several different memory ranges | |
| 388 | ($8000-9FFF, $A000-BFFF or $E000-FFFF). Newer utility and freezer | |
| 389 | cartridges were less intrusive, hiding themselves until called upon, and | |
| 390 | still others used bank-switching techniques to allow much larger ROM's than | |
| 391 | normal. Because of these "stealthing" and bank-switching methods, a special | |
| 392 | cartridge format was necessary, to let the emulator know where the | |
| 393 | cartridge should reside, the control line states to enable it and any | |
| 394 | special hardware features it uses. | |
| 395 | ||
| 396 | (...) | |
| 397 | ||
| 398 | [ A .CRT file consists of | |
| 399 | ||
| 400 | $0000-0040 : Header of the whole .crt files | |
| 401 | $0040-EOF : Blocks of data | |
| 402 | ||
| 403 | Each block of data, called 'CHIP', can be of variable size. The first | |
| 404 | 0x10 bytes of each CHIP block is the block header, and it contains various | |
| 405 | informations on the block itself, as its size (both with and without the | |
| 406 | header), the loading address and an index to identify which memory bank | |
| 407 | the data must be loaded to. FP ] | |
| 408 | ||
| 409 | .CRT header description | |
| 410 | ----------------------- | |
| 411 | ||
| 412 | Bytes: $0000-000F - 16-byte cartridge signature "C64 CARTRIDGE" (padded | |
| 413 | with space characters) | |
| 414 | 0010-0013 - File header length ($00000040, in high/low format, | |
| 415 | calculated from offset $0000). The default (also the | |
| 416 | minimum) value is $40. Some cartridges exist which | |
| 417 | show a value of $00000020 which is wrong. | |
| 418 | 0014-0015 - Cartridge version (high/low, presently 01.00) | |
| 419 | 0016-0017 - Cartridge hardware type ($0000, high/low) | |
| 420 | 0018 - Cartridge port EXROM line status | |
| 421 | 0 - inactive | |
| 422 | 1 - active | |
| 423 | 0019 - Cartridge port GAME line status | |
| 424 | 0 - inactive | |
| 425 | 1 - active | |
| 426 | 001A-001F - Reserved for future use | |
| 427 | 0020-003F - 32-byte cartridge name "CCSMON" (uppercase, padded | |
| 428 | with null characters) | |
| 429 | 0040-xxxx - Cartridge contents (called CHIP PACKETS, as there can | |
| 430 | be more than one per CRT file). See below for a | |
| 431 | breakdown of the CHIP format. | |
| 432 | ||
| 433 | CHIP content description | |
| 434 | ------------------------ | |
| 435 | ||
| 436 | [ Addresses shifted back to $0000. FP ] | |
| 437 | ||
| 438 | Bytes: $0000-0003 - Contained ROM signature "CHIP" (note there can be more | |
| 439 | than one image in a .CRT file) | |
| 440 | 0004-0007 - Total packet length (ROM image size and | |
| 441 | header combined) (high/low format) | |
| 442 | 0008-0009 - Chip type | |
| 443 | 0 - ROM | |
| 444 | 1 - RAM, no ROM data | |
| 445 | 2 - Flash ROM | |
| 446 | 000A-000B - Bank number | |
| 447 | 000C-000D - Starting load address (high/low format) | |
| 448 | 000E-000F - ROM image size in bytes (high/low format, typically | |
| 449 | $2000 or $4000) | |
| 450 | 0010-xxxx - ROM data | |
| 451 | ||
| 452 | ||
| 453 | */ | |
| 454 | ||
| 455 | ||
| 456 | /* Hardware Types for C64 carts */ | |
| 457 | enum { | |
| 458 | GENERIC_CRT = 0, /* 00 - Normal cartridge */ | |
| 459 | ACTION_REPLAY, /* 01 - Action Replay */ | |
| 460 | KCS_PC, /* 02 - KCS Power Cartridge */ | |
| 461 | FINAL_CART_III, /* 03 - Final Cartridge III */ | |
| 462 | SIMONS_BASIC, /* 04 - Simons Basic */ | |
| 463 | OCEAN_1, /* 05 - Ocean type 1 (1) */ | |
| 464 | EXPERT, /* 06 - Expert Cartridge */ | |
| 465 | FUN_PLAY, /* 07 - Fun Play, Power Play */ | |
| 466 | SUPER_GAMES, /* 08 - Super Games */ | |
| 467 | ATOMIC_POWER, /* 09 - Atomic Power */ | |
| 468 | EPYX_FASTLOAD, /* 10 - Epyx Fastload */ | |
| 469 | WESTERMANN, /* 11 - Westermann Learning */ | |
| 470 | REX, /* 12 - Rex Utility */ | |
| 471 | FINAL_CART_I, /* 13 - Final Cartridge I */ | |
| 472 | MAGIC_FORMEL, /* 14 - Magic Formel */ | |
| 473 | C64GS, /* 15 - C64 Game System, System 3 */ | |
| 474 | WARPSPEED, /* 16 - WarpSpeed */ | |
| 475 | DINAMIC, /* 17 - Dinamic (2) */ | |
| 476 | ZAXXON, /* 18 - Zaxxon, Super Zaxxon (SEGA) */ | |
| 477 | DOMARK, /* 19 - Magic Desk, Domark, HES Australia */ | |
| 478 | SUPER_SNAP_5, /* 20 - Super Snapshot 5 */ | |
| 479 | COMAL_80, /* 21 - Comal-80 */ | |
| 480 | STRUCT_BASIC, /* 22 - Structured Basic */ | |
| 481 | ROSS, /* 23 - Ross */ | |
| 482 | DELA_EP64, /* 24 - Dela EP64 */ | |
| 483 | DELA_EP7X8, /* 25 - Dela EP7x8 */ | |
| 484 | DELA_EP256, /* 26 - Dela EP256 */ | |
| 485 | REX_EP256, /* 27 - Rex EP256 */ | |
| 486 | MIKRO_ASSMBLR, /* 28 - Mikro Assembler */ | |
| 487 | REAL_FC_I, /* 29 - (3) */ | |
| 488 | ACTION_REPLAY_4, /* 30 - Action Replay 4 */ | |
| 489 | STARDOS, /* 31 - StarDOS */ | |
| 490 | /* | |
| 491 | (1) Ocean type 1 includes Navy Seals, Robocop 2 & 3, Shadow of | |
| 492 | the Beast, Toki, Terminator 2 and more. Both 256 and 128 Kb images. | |
| 493 | (2) Dinamic includes Narco Police and more. | |
| 494 | (3) Type 29 is reserved for the real Final Cartridge I, the one | |
| 495 | above (Type 13) will become Final Cartridge II. */ | |
| 496 | /**************************************** | |
| 497 | Vice also defines the following types: | |
| 498 | #define CARTRIDGE_ACTION_REPLAY3 -29 | |
| 499 | #define CARTRIDGE_IEEE488 -11 | |
| 500 | #define CARTRIDGE_IDE64 -7 | |
| 501 | #define CARTRIDGE_RETRO_REPLAY -5 | |
| 502 | #define CARTRIDGE_SUPER_SNAPSHOT -4 | |
| 503 | ||
| 504 | Can we support these as well? | |
| 505 | *****************************************/ | |
| 506 | }; | |
| 507 | ||
| 508 | DEVICE_IMAGE_UNLOAD_MEMBER( legacy_c64_state, c64_cart ) | |
| 509 | { | |
| 510 | int i; | |
| 511 | ||
| 512 | for (i = 0; i < C64_MAX_ROMBANK; i++) | |
| 513 | { | |
| 514 | m_cart.bank[i].size = 0; | |
| 515 | m_cart.bank[i].addr = 0; | |
| 516 | m_cart.bank[i].index = 0; | |
| 517 | m_cart.bank[i].start = 0; | |
| 518 | } | |
| 519 | } | |
| 520 | ||
| 521 | ||
| 522 | void legacy_c64_state::c64_legacy_driver_init() | |
| 523 | { | |
| 524 | /* In the first slot we can load a .crt file. In this case we want | |
| 525 | to use game & exrom values from the header, not the default ones. */ | |
| 526 | m_cart.game = -1; | |
| 527 | m_cart.exrom = -1; | |
| 528 | m_cart.mapper = GENERIC_CRT; | |
| 529 | m_cart.n_banks = 0; | |
| 530 | } | |
| 531 | ||
| 532 | static int c64_crt_load( device_image_interface &image ) | |
| 533 | { | |
| 534 | legacy_c64_state *state = image.device().machine().driver_data<legacy_c64_state>(); | |
| 535 | int size = image.length(), test, i = 0, ii; | |
| 536 | int _80_loaded = 0, _90_loaded = 0, a0_loaded = 0, b0_loaded = 0, e0_loaded = 0, f0_loaded = 0; | |
| 537 | const char *filetype = image.filetype(); | |
| 538 | int address = 0, new_start = 0; | |
| 539 | // int lbank_end_addr = 0, hbank_end_addr = 0; | |
| 540 | UINT8 *cart_cpy = state->memregion("user1")->base(); | |
| 541 | ||
| 542 | /* We support .crt files */ | |
| 543 | if (!mame_stricmp(filetype, "crt")) | |
| 544 | { | |
| 545 | int j; | |
| 546 | unsigned short c64_cart_type; | |
| 547 | ||
| 548 | if (i >= C64_MAX_ROMBANK) | |
| 549 | return IMAGE_INIT_FAIL; | |
| 550 | ||
| 551 | /* Start to parse the .crt header */ | |
| 552 | /* 0x16-0x17 is Hardware type */ | |
| 553 | image.fseek(0x16, SEEK_SET); | |
| 554 | image.fread(&c64_cart_type, 2); | |
| 555 | state->m_cart.mapper = BIG_ENDIANIZE_INT16(c64_cart_type); | |
| 556 | ||
| 557 | /* If it is unsupported cart type, warn the user */ | |
| 558 | switch (state->m_cart.mapper) | |
| 559 | { | |
| 560 | case SIMONS_BASIC: /* Type # 4 */ | |
| 561 | case OCEAN_1: /* Type # 5 */ | |
| 562 | case FUN_PLAY: /* Type # 7 */ | |
| 563 | case SUPER_GAMES: /* Type # 8 */ | |
| 564 | case EPYX_FASTLOAD: /* Type # 10 */ | |
| 565 | case REX: /* Type # 12 */ | |
| 566 | case C64GS: /* Type # 15 */ | |
| 567 | case DINAMIC: /* Type # 17 */ | |
| 568 | case ZAXXON: /* Type # 18 */ | |
| 569 | case DOMARK: /* Type # 19 */ | |
| 570 | case COMAL_80: /* Type # 21 */ | |
| 571 | case GENERIC_CRT: /* Type # 0 */ | |
| 572 | printf("Currently supported cart type (Type %d)\n", state->m_cart.mapper); | |
| 573 | break; | |
| 574 | ||
| 575 | default: | |
| 576 | case ACTION_REPLAY: /* Type # 1 */ | |
| 577 | case KCS_PC: /* Type # 2 */ | |
| 578 | case FINAL_CART_III: /* Type # 3 */ | |
| 579 | case EXPERT: /* Type # 6 */ | |
| 580 | case ATOMIC_POWER: /* Type # 9 */ | |
| 581 | case WESTERMANN: /* Type # 11 */ | |
| 582 | case FINAL_CART_I: /* Type # 13 */ | |
| 583 | case MAGIC_FORMEL: /* Type # 14 */ | |
| 584 | case SUPER_SNAP_5: /* Type # 20 */ | |
| 585 | printf("Currently unsupported cart type (Type %d)\n", state->m_cart.mapper); | |
| 586 | break; | |
| 587 | } | |
| 588 | ||
| 589 | /* 0x18 is EXROM */ | |
| 590 | image.fseek(0x18, SEEK_SET); | |
| 591 | image.fread(&state->m_cart.exrom, 1); | |
| 592 | ||
| 593 | /* 0x19 is GAME */ | |
| 594 | image.fread(&state->m_cart.game, 1); | |
| 595 | ||
| 596 | /* We can pass to the data: it starts from 0x40 */ | |
| 597 | image.fseek(0x40, SEEK_SET); | |
| 598 | j = 0x40; | |
| 599 | ||
| 600 | logerror("Loading cart %s size:%.4x\n", image.filename(), size); | |
| 601 | logerror("Header info: EXROM %d, GAME %d, Cart Type %d \n", state->m_cart.exrom, state->m_cart.game, c64_cart_type); | |
| 602 | ||
| 603 | ||
| 604 | /* Data in a .crt image are organized in blocks called 'CHIP': | |
| 605 | each 'CHIP' consists of a 0x10 header, which contains the | |
| 606 | actual size of the block, the loading address and info on | |
| 607 | the bankswitch, followed by the actual data */ | |
| 608 | while (j < size) | |
| 609 | { | |
| 610 | unsigned short chip_size, chip_bank_index, chip_data_size; | |
| 611 | unsigned char buffer[10]; | |
| 612 | ||
| 613 | /* Start to parse the CHIP header */ | |
| 614 | /* First 4 bytes are the string 'CHIP' */ | |
| 615 | image.fread(buffer, 6); | |
| 616 | ||
| 617 | /* 0x06-0x07 is the size of the CHIP block (header + data) */ | |
| 618 | image.fread(&chip_size, 2); | |
| 619 | chip_size = BIG_ENDIANIZE_INT16(chip_size); | |
| 620 | ||
| 621 | /* 0x08-0x09 chip type (ROM, RAM + no ROM, Flash ROM) */ | |
| 622 | image.fread(buffer + 6, 2); | |
| 623 | ||
| 624 | /* 0x0a-0x0b is the bank number of the CHIP block */ | |
| 625 | image.fread(&chip_bank_index, 2); | |
| 626 | chip_bank_index = BIG_ENDIANIZE_INT16(chip_bank_index); | |
| 627 | ||
| 628 | /* 0x0c-0x0d is the loading address of the CHIP block */ | |
| 629 | image.fread(&address, 2); | |
| 630 | address = BIG_ENDIANIZE_INT16(address); | |
| 631 | ||
| 632 | /* 0x0e-0x0f is the data size of the CHIP block (without header) */ | |
| 633 | image.fread(&chip_data_size, 2); | |
| 634 | chip_data_size = BIG_ENDIANIZE_INT16(chip_data_size); | |
| 635 | ||
| 636 | /* Print out the CHIP header! */ | |
| 637 | logerror("%.4s %.2x %.2x %.4x %.2x %.2x %.4x %.4x:%.4x\n", | |
| 638 | buffer, buffer[4], buffer[5], chip_size, | |
| 639 | buffer[6], buffer[7], chip_bank_index, | |
| 640 | address, chip_data_size); | |
| 641 | logerror("Loading CHIP data at %.4x size:%.4x\n", address, chip_data_size); | |
| 642 | ||
| 643 | /* Store data, address & size of the CHIP block */ | |
| 644 | state->m_cart.bank[i].addr = address; | |
| 645 | state->m_cart.bank[i].index = chip_bank_index; | |
| 646 | state->m_cart.bank[i].size = chip_data_size; | |
| 647 | state->m_cart.bank[i].start = new_start; | |
| 648 | ||
| 649 | test = image.fread(cart_cpy + new_start, state->m_cart.bank[i].size); | |
| 650 | new_start += state->m_cart.bank[i].size; | |
| 651 | ||
| 652 | /* Does CHIP contain any data? */ | |
| 653 | if (test != state->m_cart.bank[i].size) | |
| 654 | return IMAGE_INIT_FAIL; | |
| 655 | ||
| 656 | /* Advance to the next CHIP block */ | |
| 657 | i++; | |
| 658 | j += chip_size; | |
| 659 | } | |
| 660 | } | |
| 661 | else /* We also support .80 files for c64 & .e0/.f0 for max */ | |
| 662 | { | |
| 663 | /* Assign loading address according to extension */ | |
| 664 | if (!mame_stricmp(filetype, "80")) | |
| 665 | address = 0x8000; | |
| 666 | ||
| 667 | if (!mame_stricmp(filetype, "e0")) | |
| 668 | address = 0xe000; | |
| 669 | ||
| 670 | if (!mame_stricmp(filetype, "f0")) | |
| 671 | address = 0xf000; | |
| 672 | ||
| 673 | logerror("loading %s rom at %.4x size:%.4x\n", image.filename(), address, size); | |
| 674 | ||
| 675 | /* Store data, address & size */ | |
| 676 | state->m_cart.bank[0].addr = address; | |
| 677 | state->m_cart.bank[0].size = size; | |
| 678 | state->m_cart.bank[0].start = new_start; | |
| 679 | ||
| 680 | test = image.fread(cart_cpy + new_start, state->m_cart.bank[0].size); | |
| 681 | new_start += state->m_cart.bank[0].size; | |
| 682 | ||
| 683 | /* Does cart contain any data? */ | |
| 684 | if (test != state->m_cart.bank[0].size) | |
| 685 | return IMAGE_INIT_FAIL; | |
| 686 | } | |
| 687 | ||
| 688 | state->m_cart.n_banks = i; // this is also needed so that we only set mappers if a cart is present! | |
| 689 | ||
| 690 | /* If we load a .crt file, use EXROM & GAME from the header! */ | |
| 691 | if ((state->m_cart.exrom != -1) && (state->m_cart.game != -1)) | |
| 692 | { | |
| 693 | state->m_exrom = state->m_cart.exrom; | |
| 694 | state->m_game = state->m_cart.game; | |
| 695 | } | |
| 696 | ||
| 697 | /* Finally load the cart */ | |
| 698 | state->m_roml = state->m_c64_roml; | |
| 699 | state->m_romh = state->m_c64_romh; | |
| 700 | ||
| 701 | memset(state->m_roml, 0, 0x2000); | |
| 702 | memset(state->m_romh, 0, 0x2000); | |
| 703 | ||
| 704 | switch (state->m_cart.mapper) | |
| 705 | { | |
| 706 | default: | |
| 707 | if (!state->m_game && state->m_exrom && (state->m_cart.n_banks == 1)) | |
| 708 | { | |
| 709 | memcpy(state->m_romh, cart_cpy, 0x2000); | |
| 710 | } | |
| 711 | else | |
| 712 | { | |
| 713 | // we first attempt to load the first 'CHIPs' with address 0x8000-0xb000 and 0xe000-0xf000, otherwise we load the first (or first two) 'CHIPs' of the image | |
| 714 | for (ii = 0; ii < state->m_cart.n_banks; ii++) | |
| 715 | { | |
| 716 | if (state->m_cart.bank[ii].addr == 0x8000 && !_80_loaded) | |
| 717 | { | |
| 718 | memcpy(state->m_roml, cart_cpy + state->m_cart.bank[ii].start, state->m_cart.bank[ii].size); | |
| 719 | _80_loaded = 1; | |
| 720 | if (state->m_cart.bank[ii].size > 0x1000) | |
| 721 | _90_loaded = 1; | |
| 722 | if (state->m_cart.bank[ii].size > 0x2000) | |
| 723 | a0_loaded = 1; | |
| 724 | if (state->m_cart.bank[ii].size > 0x3000) | |
| 725 | b0_loaded = 1; | |
| 726 | // printf("addr 0x8000: 80 %d, 90 %d, a0 %d, b0 %d\n", _80_loaded, _90_loaded, a0_loaded, b0_loaded); | |
| 727 | } | |
| 728 | ||
| 729 | if (state->m_cart.bank[ii].addr == 0x9000 && !_90_loaded) | |
| 730 | { | |
| 731 | memcpy(state->m_roml + 0x1000, cart_cpy + state->m_cart.bank[ii].start, state->m_cart.bank[ii].size); | |
| 732 | _90_loaded = 1; | |
| 733 | if (state->m_cart.bank[ii].size > 0x1000) | |
| 734 | a0_loaded = 1; | |
| 735 | if (state->m_cart.bank[ii].size > 0x2000) | |
| 736 | b0_loaded = 1; | |
| 737 | // printf("addr 0x9000: 80 %d, 90 %d, a0 %d, b0 %d\n", _80_loaded, _90_loaded, a0_loaded, b0_loaded); | |
| 738 | } | |
| 739 | ||
| 740 | if (state->m_cart.bank[ii].addr == 0xa000 && !a0_loaded) | |
| 741 | { | |
| 742 | memcpy(state->m_roml + 0x2000, cart_cpy + state->m_cart.bank[ii].start, state->m_cart.bank[ii].size); | |
| 743 | a0_loaded = 1; | |
| 744 | if (state->m_cart.bank[ii].size > 0x1000) | |
| 745 | b0_loaded = 1; | |
| 746 | // printf("addr 0xa000: 80 %d, 90 %d, a0 %d, b0 %d\n", _80_loaded, _90_loaded, a0_loaded, b0_loaded); | |
| 747 | } | |
| 748 | ||
| 749 | if (state->m_cart.bank[ii].addr == 0xb000 && !b0_loaded) | |
| 750 | { | |
| 751 | memcpy(state->m_roml + 0x3000, cart_cpy + state->m_cart.bank[ii].start, state->m_cart.bank[ii].size); | |
| 752 | b0_loaded = 1; | |
| 753 | // printf("addr 0xb000: 80 %d, 90 %d, a0 %d, b0 %d\n", _80_loaded, _90_loaded, a0_loaded, b0_loaded); | |
| 754 | } | |
| 755 | ||
| 756 | if (state->m_cart.bank[ii].addr == 0xe000 && !e0_loaded) | |
| 757 | { | |
| 758 | memcpy(state->m_romh, cart_cpy + state->m_cart.bank[ii].start, state->m_cart.bank[ii].size); | |
| 759 | e0_loaded = 1; | |
| 760 | if (state->m_cart.bank[ii].size > 0x1000) | |
| 761 | f0_loaded = 1; | |
| 762 | // printf("addr 0xe000: e0 %d, f0 %d\n", e0_loaded, f0_loaded); | |
| 763 | } | |
| 764 | ||
| 765 | if (state->m_cart.bank[ii].addr == 0xf000 && !f0_loaded) | |
| 766 | { | |
| 767 | memcpy(state->m_romh + 0x1000, cart_cpy + state->m_cart.bank[ii].start, state->m_cart.bank[ii].size); | |
| 768 | f0_loaded = 1; | |
| 769 | // printf("addr 0xe000: e0 %d, f0 %d\n", e0_loaded, f0_loaded); | |
| 770 | } | |
| 771 | } | |
| 772 | } | |
| 773 | } | |
| 774 | ||
| 775 | return IMAGE_INIT_PASS; | |
| 776 | } | |
| 777 | ||
| 778 | /*************************************************************************** | |
| 779 | SOFTWARE LIST CARTRIDGE HANDLING | |
| 780 | ***************************************************************************/ | |
| 781 | ||
| 782 | #define install_write_handler(_start, _end, _handler) \ | |
| 783 | image.device().machine().firstcpu->space(AS_PROGRAM).install_legacy_write_handler(_start, _end, FUNC(_handler)); | |
| 784 | ||
| 785 | #define install_io1_handler(_handler) \ | |
| 786 | image.device().machine().firstcpu->space(AS_PROGRAM).install_legacy_write_handler(0xde00, 0xde00, 0, 0xff, FUNC(_handler)); | |
| 787 | ||
| 788 | #define install_io2_handler(_handler) \ | |
| 789 | image.device().machine().firstcpu->space(AS_PROGRAM).install_legacy_write_handler(0xdf00, 0xdf00, 0, 0xff, FUNC(_handler)); | |
| 790 | ||
| 791 | #define allocate_cartridge_timer(_period, _func) \ | |
| 792 | legacy_c64_state *state = image.device().machine().driver_data<legacy_c64_state>(); \ | |
| 793 | state->m_cartridge_timer = image.device().machine().scheduler().timer_alloc(FUNC(_func)); \ | |
| 794 | state->m_cartridge_timer->adjust(_period, 0); | |
| 795 | ||
| 796 | #define set_game_line(_machine, _state) \ | |
| 797 | _machine.driver_data<legacy_c64_state>()->m_game = _state; \ | |
| 798 | c64_bankswitch(_machine, 0); | |
| 799 | ||
| 800 | INLINE void load_cartridge_region(device_image_interface &image, const char *name, offs_t offset, size_t size) | |
| 801 | { | |
| 802 | UINT8 *cart = image.device().machine().root_device().memregion("user1")->base(); | |
| 803 | UINT8 *rom = image.get_software_region(name); | |
| 804 | memcpy(cart + offset, rom, size); | |
| 805 | } | |
| 806 | ||
| 807 | INLINE void map_cartridge_roml(running_machine &machine, offs_t offset) | |
| 808 | { | |
| 809 | legacy_c64_state *state = machine.driver_data<legacy_c64_state>(); | |
| 810 | UINT8 *cart = state->memregion("user1")->base(); | |
| 811 | memcpy(state->m_roml, cart + offset, 0x2000); | |
| 812 | } | |
| 813 | ||
| 814 | INLINE void map_cartridge_romh(running_machine &machine, offs_t offset) | |
| 815 | { | |
| 816 | legacy_c64_state *state = machine.driver_data<legacy_c64_state>(); | |
| 817 | UINT8 *cart = state->memregion("user1")->base(); | |
| 818 | memcpy(state->m_romh, cart + offset, 0x2000); | |
| 819 | } | |
| 820 | ||
| 821 | static void load_standard_c64_cartridge(device_image_interface &image) | |
| 822 | { | |
| 823 | legacy_c64_state *state = image.device().machine().driver_data<legacy_c64_state>(); | |
| 824 | UINT32 size; | |
| 825 | ||
| 826 | // is there anything to load at 0x8000? | |
| 827 | size = image.get_software_region_length("roml"); | |
| 828 | ||
| 829 | if (size) | |
| 830 | { | |
| 831 | memcpy(state->m_roml, image.get_software_region("roml"), MIN(0x2000, size)); | |
| 832 | ||
| 833 | if (size == 0x4000) | |
| 834 | { | |
| 835 | // continue loading to ROMH region | |
| 836 | memcpy(state->m_romh, image.get_software_region("roml") + 0x2000, 0x2000); | |
| 837 | } | |
| 838 | } | |
| 839 | ||
| 840 | // is there anything to load at 0xa000? | |
| 841 | size = image.get_software_region_length("romh"); | |
| 842 | if (size) | |
| 843 | memcpy(state->m_romh, image.get_software_region("romh"), size); | |
| 844 | } | |
| 845 | ||
| 846 | static TIMER_CALLBACK( vizawrite_timer ) | |
| 847 | { | |
| 848 | map_cartridge_roml(machine, 0x2000); | |
| 849 | set_game_line(machine, 1); | |
| 850 | } | |
| 851 | ||
| 852 | static void load_vizawrite_cartridge(device_image_interface &image) | |
| 853 | { | |
| 854 | #define VW64_DECRYPT_ADDRESS(_offset) \ | |
| 855 | BITSWAP16(_offset,15,14,13,12,7,8,6,9,5,11,4,3,2,10,1,0) | |
| 856 | ||
| 857 | #define VW64_DECRYPT_DATA(_data) \ | |
| 858 | BITSWAP8(_data,7,6,0,5,1,4,2,3) | |
| 859 | ||
| 860 | UINT8 *roml = image.get_software_region("roml"); | |
| 861 | UINT8 *romh = image.get_software_region("romh"); | |
| 862 | UINT8 *decrypted = image.device().machine().root_device().memregion("user1")->base(); | |
| 863 | ||
| 864 | // decrypt ROMs | |
| 865 | for (offs_t offset = 0; offset < 0x2000; offset++) | |
| 866 | { | |
| 867 | offs_t address = VW64_DECRYPT_ADDRESS(offset); | |
| 868 | decrypted[address] = VW64_DECRYPT_DATA(roml[offset]); | |
| 869 | decrypted[address + 0x2000] = VW64_DECRYPT_DATA(roml[offset + 0x2000]); | |
| 870 | decrypted[address + 0x4000] = VW64_DECRYPT_DATA(romh[offset]); | |
| 871 | } | |
| 872 | ||
| 873 | // map cartridge ROMs | |
| 874 | map_cartridge_roml(image.device().machine(), 0x0000); | |
| 875 | map_cartridge_romh(image.device().machine(), 0x4000); | |
| 876 | ||
| 877 | // allocate GAME changing timer | |
| 878 | allocate_cartridge_timer(attotime::from_msec(1184), vizawrite_timer); | |
| 879 | } | |
| 880 | ||
| 881 | static WRITE8_HANDLER( hugo_bank_w ) | |
| 882 | { | |
| 883 | /* | |
| 884 | ||
| 885 | bit description | |
| 886 | ||
| 887 | 0 | |
| 888 | 1 | |
| 889 | 2 | |
| 890 | 3 | |
| 891 | 4 A14 | |
| 892 | 5 A15 | |
| 893 | 6 A16 | |
| 894 | 7 A13 | |
| 895 | ||
| 896 | */ | |
| 897 | ||
| 898 | int bank = ((data >> 3) & 0x0e) | BIT(data, 7); | |
| 899 | ||
| 900 | map_cartridge_roml(space.machine(), bank * 0x2000); | |
| 901 | } | |
| 902 | ||
| 903 | static void load_hugo_cartridge(device_image_interface &image) | |
| 904 | { | |
| 905 | #define HUGO_DECRYPT_ADDRESS(_offset) \ | |
| 906 | BITSWAP16(_offset,15,14,13,12,7,6,5,4,3,2,1,0,8,9,11,10) | |
| 907 | ||
| 908 | #define HUGO_DECRYPT_DATA(_data) \ | |
| 909 | BITSWAP8(_data,7,6,5,4,0,1,2,3) | |
| 910 | ||
| 911 | UINT8 *roml = image.get_software_region("roml"); | |
| 912 | UINT8 *decrypted = image.device().machine().root_device().memregion("user1")->base(); | |
| 913 | ||
| 914 | // decrypt ROMs | |
| 915 | for (offs_t offset = 0; offset < 0x20000; offset++) | |
| 916 | { | |
| 917 | offs_t address = (offset & 0x10000) | HUGO_DECRYPT_ADDRESS(offset); | |
| 918 | decrypted[address] = HUGO_DECRYPT_DATA(roml[offset]); | |
| 919 | } | |
| 920 | ||
| 921 | // map cartridge ROMs | |
| 922 | map_cartridge_roml(image.device().machine(), 0x0000); | |
| 923 | ||
| 924 | // install bankswitch handler | |
| 925 | install_io1_handler(hugo_bank_w); | |
| 926 | } | |
| 927 | ||
| 928 | static WRITE8_HANDLER( easy_calc_result_bank_w ) | |
| 929 | { | |
| 930 | map_cartridge_romh(space.machine(), 0x2000 + (!offset * 0x2000)); | |
| 931 | } | |
| 932 | ||
| 933 | static void load_easy_calc_result_cartridge(device_image_interface &image) | |
| 934 | { | |
| 935 | load_cartridge_region(image, "roml", 0x0000, 0x2000); | |
| 936 | load_cartridge_region(image, "romh", 0x2000, 0x4000); | |
| 937 | ||
| 938 | map_cartridge_roml(image.device().machine(), 0x0000); | |
| 939 | map_cartridge_romh(image.device().machine(), 0x2000); | |
| 940 | ||
| 941 | install_write_handler(0xde00, 0xde01, easy_calc_result_bank_w); | |
| 942 | } | |
| 943 | ||
| 944 | static WRITE8_HANDLER( pagefox_bank_w ) | |
| 945 | { | |
| 946 | /* | |
| 947 | ||
| 948 | Die 96KB des Moduls belegen in 6 16K-Banken den Modulbereich von $8000- $c000. | |
| 949 | Die Umschaltung erfolgt mit einem Register in $DE80 (-$DEFF, nicht voll decodiert), | |
| 950 | welches nur beschrieben und nicht gelesen werden kann. Durch Schreiben der Werte | |
| 951 | $08 oder $0A selektiert man eine der beiden RAM-Banke, $FF deselektiert das Modul. | |
| 952 | ||
| 953 | Zusatzlich muss Adresse 1 entsprechend belegt werden :$37 fur Lesezugriffe auf das | |
| 954 | Modul, $35 oder $34 fur Lesezugriffe auf das Ram des C64. Schreibzugriffe lenkt | |
| 955 | der C64 grundsatzlich ins eigene RAM, weshalb zum Beschreiben des Modulrams ein | |
| 956 | Trick notwendig ist: Man schaltet das Ram-Modul parallel zum C64-Ram, rettet vor | |
| 957 | dem Schreiben den C64-Ram-Inhalt und stellt ihn nachher wieder her... | |
| 958 | ||
| 959 | Ldy#0 | |
| 960 | Lda#$35 | |
| 961 | Sta 1 | |
| 962 | Loop Lda (Ptr),y | |
| 963 | Pha | |
| 964 | Lda#$08 | |
| 965 | Sta $DE80 | |
| 966 | Lda (Quell),y | |
| 967 | Sta (Ptr),y | |
| 968 | Lda#$FF | |
| 969 | Sta $DE80 | |
| 970 | Pla | |
| 971 | Sta (Ptr),y | |
| 972 | Iny | |
| 973 | Bne Loop | |
| 974 | ||
| 975 | */ | |
| 976 | ||
| 977 | legacy_c64_state *state = space.machine().driver_data<legacy_c64_state>(); | |
| 978 | UINT8 *cart = state->memregion("user1")->base(); | |
| 979 | ||
| 980 | if (data == 0xff) | |
| 981 | { | |
| 982 | // hide cartridge | |
| 983 | state->m_game = 1; | |
| 984 | state->m_exrom = 1; | |
| 985 | } | |
| 986 | else | |
| 987 | { | |
| 988 | if (state->m_game) | |
| 989 | { | |
| 990 | // enable cartridge | |
| 991 | state->m_game = 0; | |
| 992 | state->m_exrom = 0; | |
| 993 | } | |
| 994 | ||
| 995 | int bank = (data >> 1) & 0x07; | |
| 996 | int ram = BIT(data, 3); | |
| 997 | offs_t address = bank * 0x4000; | |
| 998 | ||
| 999 | state->m_roml_writable = ram; | |
| 1000 | ||
| 1001 | if (ram) | |
| 1002 | { | |
| 1003 | state->m_roml = cart + address; | |
| 1004 | } | |
| 1005 | else | |
| 1006 | { | |
| 1007 | state->m_roml = state->m_c64_roml; | |
| 1008 | ||
| 1009 | map_cartridge_roml(space.machine(), address); | |
| 1010 | map_cartridge_romh(space.machine(), address + 0x2000); | |
| 1011 | } | |
| 1012 | } | |
| 1013 | ||
| 1014 | c64_bankswitch(space.machine(), 0); | |
| 1015 | } | |
| 1016 | ||
| 1017 | static void load_pagefox_cartridge(device_image_interface &image) | |
| 1018 | { | |
| 1019 | load_cartridge_region(image, "rom", 0x0000, 0x10000); | |
| 1020 | ||
| 1021 | map_cartridge_roml(image.device().machine(), 0x0000); | |
| 1022 | map_cartridge_romh(image.device().machine(), 0x2000); | |
| 1023 | ||
| 1024 | install_write_handler(0xde80, 0xdeff, pagefox_bank_w); | |
| 1025 | } | |
| 1026 | ||
| 1027 | static WRITE8_HANDLER( multiscreen_bank_w ) | |
| 1028 | { | |
| 1029 | legacy_c64_state *state = space.machine().driver_data<legacy_c64_state>(); | |
| 1030 | UINT8 *cart = state->memregion("user1")->base(); | |
| 1031 | int bank = data & 0x0f; | |
| 1032 | offs_t address = bank * 0x4000; | |
| 1033 | ||
| 1034 | if (bank == 0x0d) | |
| 1035 | { | |
| 1036 | // RAM | |
| 1037 | state->m_roml = cart + address; | |
| 1038 | state->m_roml_writable = 1; | |
| 1039 | ||
| 1040 | map_cartridge_romh(space.machine(), 0x2000); | |
| 1041 | } | |
| 1042 | else | |
| 1043 | { | |
| 1044 | // ROM | |
| 1045 | state->m_roml = state->m_c64_roml; | |
| 1046 | state->m_roml_writable = 0; | |
| 1047 | ||
| 1048 | map_cartridge_roml(space.machine(), address); | |
| 1049 | map_cartridge_romh(space.machine(), address + 0x2000); | |
| 1050 | } | |
| 1051 | ||
| 1052 | c64_bankswitch(space.machine(), 0); | |
| 1053 | } | |
| 1054 | ||
| 1055 | static void load_multiscreen_cartridge(device_image_interface &image) | |
| 1056 | { | |
| 1057 | load_cartridge_region(image, "roml", 0x0000, 0x4000); | |
| 1058 | load_cartridge_region(image, "rom", 0x4000, 0x30000); | |
| 1059 | ||
| 1060 | map_cartridge_roml(image.device().machine(), 0x0000); | |
| 1061 | map_cartridge_romh(image.device().machine(), 0x2000); | |
| 1062 | ||
| 1063 | install_write_handler(0xdfff, 0xdfff, multiscreen_bank_w); | |
| 1064 | } | |
| 1065 | ||
| 1066 | static WRITE8_HANDLER( simons_basic_bank_w ) | |
| 1067 | { | |
| 1068 | set_game_line(space.machine(), !BIT(data, 0)); | |
| 1069 | } | |
| 1070 | ||
| 1071 | static void load_simons_basic_cartridge(device_image_interface &image) | |
| 1072 | { | |
| 1073 | load_cartridge_region(image, "roml", 0x0000, 0x2000); | |
| 1074 | load_cartridge_region(image, "romh", 0x2000, 0x2000); | |
| 1075 | ||
| 1076 | map_cartridge_roml(image.device().machine(), 0x0000); | |
| 1077 | map_cartridge_romh(image.device().machine(), 0x2000); | |
| 1078 | ||
| 1079 | install_io1_handler(simons_basic_bank_w); | |
| 1080 | } | |
| 1081 | ||
| 1082 | static READ8_HANDLER( super_explode_r ) | |
| 1083 | { | |
| 1084 | legacy_c64_state *state = space.machine().driver_data<legacy_c64_state>(); | |
| 1085 | ||
| 1086 | return state->m_roml[0x1f00 | offset]; | |
| 1087 | } | |
| 1088 | ||
| 1089 | static WRITE8_HANDLER( super_explode_bank_w ) | |
| 1090 | { | |
| 1091 | map_cartridge_roml(space.machine(), BIT(data, 7) * 0x2000); | |
| 1092 | } | |
| 1093 | ||
| 1094 | static void load_super_explode_cartridge(device_image_interface &image) | |
| 1095 | { | |
| 1096 | load_cartridge_region(image, "roml", 0x0000, 0x4000); | |
| 1097 | ||
| 1098 | map_cartridge_roml(image.device().machine(), 0x0000); | |
| 1099 | ||
| 1100 | address_space &space = image.device().machine().firstcpu->space(AS_PROGRAM); | |
| 1101 | space.install_legacy_read_handler(0xdf00, 0xdfff, FUNC(super_explode_r)); | |
| 1102 | ||
| 1103 | install_io2_handler(super_explode_bank_w); | |
| 1104 | } | |
| 1105 | ||
| 1106 | static void c64_software_list_cartridge_load(device_image_interface &image) | |
| 1107 | { | |
| 1108 | legacy_c64_state *state = image.device().machine().driver_data<legacy_c64_state>(); | |
| 1109 | ||
| 1110 | // initialize ROML and ROMH pointers | |
| 1111 | state->m_roml = state->m_c64_roml; | |
| 1112 | state->m_romh = state->m_c64_romh; | |
| 1113 | ||
| 1114 | // clear ROML and ROMH areas | |
| 1115 | memset(state->m_roml, 0, 0x2000); | |
| 1116 | memset(state->m_romh, 0, 0x2000); | |
| 1117 | ||
| 1118 | // set GAME and EXROM | |
| 1119 | state->m_game = atol(image.get_feature("game")); | |
| 1120 | state->m_exrom = atol(image.get_feature("exrom")); | |
| 1121 | ||
| 1122 | // determine cartridge type | |
| 1123 | const char *cart_type = image.get_feature("cart_type"); | |
| 1124 | ||
| 1125 | if (cart_type == NULL) | |
| 1126 | { | |
| 1127 | load_standard_c64_cartridge(image); | |
| 1128 | } | |
| 1129 | else | |
| 1130 | { | |
| 1131 | if (!strcmp(cart_type, "vizawrite")) | |
| 1132 | load_vizawrite_cartridge(image); | |
| 1133 | ||
| 1134 | else if (!strcmp(cart_type, "hugo")) | |
| 1135 | load_hugo_cartridge(image); | |
| 1136 | ||
| 1137 | else if (!strcmp(cart_type, "easy_calc_result")) | |
| 1138 | load_easy_calc_result_cartridge(image); | |
| 1139 | ||
| 1140 | else if (!strcmp(cart_type, "pagefox")) | |
| 1141 | load_pagefox_cartridge(image); | |
| 1142 | ||
| 1143 | else if (!strcmp(cart_type, "multiscreen")) | |
| 1144 | /* | |
| 1145 | ||
| 1146 | TODO: crashes on protection check after cartridge RAM test | |
| 1147 | ||
| 1148 | 805A: lda $01 | |
| 1149 | 805C: and #$FE | |
| 1150 | 805E: sta $01 | |
| 1151 | 8060: m6502_brk#$00 <-- BOOM! | |
| 1152 | ||
| 1153 | */ | |
| 1154 | load_multiscreen_cartridge(image); | |
| 1155 | ||
| 1156 | else if (!strcmp(cart_type, "simons_basic")) | |
| 1157 | load_simons_basic_cartridge(image); | |
| 1158 | ||
| 1159 | else if (!strcmp(cart_type, "super_explode")) | |
| 1160 | load_super_explode_cartridge(image); | |
| 1161 | ||
| 1162 | else | |
| 1163 | load_standard_c64_cartridge(image); | |
| 1164 | } | |
| 1165 | } | |
| 1166 | ||
| 1167 | DEVICE_IMAGE_LOAD_MEMBER( legacy_c64_state, c64_cart ) | |
| 1168 | { | |
| 1169 | int result = IMAGE_INIT_PASS; | |
| 1170 | ||
| 1171 | if (image.software_entry() != NULL) | |
| 1172 | { | |
| 1173 | c64_software_list_cartridge_load(image); | |
| 1174 | } | |
| 1175 | else | |
| 1176 | result = c64_crt_load(image); | |
| 1177 | ||
| 1178 | return result; | |
| 1179 | } | |
| 1180 | MACHINE_CONFIG_FRAGMENT( c64_cartslot ) | |
| 1181 | MCFG_CARTSLOT_ADD("cart1") | |
| 1182 | MCFG_CARTSLOT_EXTENSION_LIST("crt,80") | |
| 1183 | MCFG_CARTSLOT_NOT_MANDATORY | |
| 1184 | MCFG_CARTSLOT_INTERFACE("c64_cart") | |
| 1185 | MCFG_CARTSLOT_LOAD(legacy_c64_state,c64_cart) | |
| 1186 | MCFG_CARTSLOT_UNLOAD(legacy_c64_state,c64_cart) | |
| 1187 | ||
| 1188 | MCFG_CARTSLOT_ADD("cart2") | |
| 1189 | MCFG_CARTSLOT_EXTENSION_LIST("crt,80") | |
| 1190 | MCFG_CARTSLOT_NOT_MANDATORY | |
| 1191 | MCFG_CARTSLOT_LOAD(legacy_c64_state,c64_cart) | |
| 1192 | MCFG_CARTSLOT_UNLOAD(legacy_c64_state,c64_cart) | |
| 1193 | ||
| 1194 | MCFG_SOFTWARE_LIST_ADD("cart_list_c64", "c64_cart") | |
| 1195 | MACHINE_CONFIG_END |
| r21684 | r21685 | |
|---|---|---|
| 1 | /********************************************************************** | |
| 2 | ||
| 3 | Copyright (C) Antoine Mine' 2006 | |
| 4 | ||
| 5 | Motorola 6854 emulation. | |
| 6 | ||
| 7 | The MC6854 chip is an Advanced Data-Link Controller (ADLC). | |
| 8 | It provides a high-level network interface that can transimit frames with | |
| 9 | arbitrary data and address length, and is compatible with the following | |
| 10 | standards: | |
| 11 | - ADCCP (Advanced Data Communication Control Procedure) | |
| 12 | - HDLC (High-Level Data-Link Control) | |
| 13 | - SDLC (Synchronous Data-Link Control) | |
| 14 | It is designed to be interfaced with a M6800-family CPU. | |
| 15 | ||
| 16 | It is used in the "Nano-network" extension of the Thomson computers to | |
| 17 | link up to 32 computers at 500 Kbps. | |
| 18 | Many networks involving one PC server and several MO5 or TO7/70 computers | |
| 19 | were build in French schools in the 1980's to teach computer science. | |
| 20 | ||
| 21 | TODO: | |
| 22 | - CRC | |
| 23 | - DMA mode | |
| 24 | - loop mode | |
| 25 | - status prioritization | |
| 26 | - NRZI vs. NRZ coding | |
| 27 | - FD output | |
| 28 | ||
| 29 | **********************************************************************/ | |
| 30 | ||
| 31 | ||
| 32 | #include "emu.h" | |
| 33 | #include "mc6854.h" | |
| 34 | ||
| 35 | ||
| 36 | ||
| 37 | /******************* parameters ******************/ | |
| 38 | ||
| 39 | ||
| 40 | ||
| 41 | #define VERBOSE 0 | |
| 42 | ||
| 43 | ||
| 44 | #define MAX_FRAME_LENGTH 65536 | |
| 45 | /* arbitrary value, you may need to enlarge it if you get truncated frames */ | |
| 46 | ||
| 47 | #define FIFO_SIZE 3 | |
| 48 | /* hardcoded size of the 6854 FIFO (this is a hardware limit) */ | |
| 49 | ||
| 50 | #define FLAG 0x7e | |
| 51 | /* flag value, as defined by HDLC protocol: 01111110 */ | |
| 52 | ||
| 53 | #define BIT_LENGTH attotime::from_hz( 500000 ) | |
| 54 | ||
| 55 | ||
| 56 | ||
| 57 | /******************* internal chip data structure ******************/ | |
| 58 | ||
| 59 | ||
| 60 | struct mc6854_t | |
| 61 | { | |
| 62 | devcb_resolved_write_line out_irq_func; | |
| 63 | devcb_resolved_read_line in_rxd_func; | |
| 64 | devcb_resolved_write_line out_txd_func; | |
| 65 | devcb_resolved_write_line out_rts_func; | |
| 66 | devcb_resolved_write_line out_dtr_func; | |
| 67 | ||
| 68 | /* interface */ | |
| 69 | const mc6854_interface* iface; | |
| 70 | ||
| 71 | /* registers */ | |
| 72 | UINT8 cr1, cr2, cr3, cr4; /* control registers */ | |
| 73 | UINT8 sr1, sr2; /* status registers */ | |
| 74 | ||
| 75 | UINT8 cts, dcd; | |
| 76 | ||
| 77 | /* transmit state */ | |
| 78 | UINT8 tstate; | |
| 79 | UINT16 tfifo[FIFO_SIZE]; /* X x 8-bit FIFO + full & last marker bits */ | |
| 80 | UINT8 tones; /* counter for zero-insertion */ | |
| 81 | emu_timer *ttimer; /* when to ask for more data */ | |
| 82 | ||
| 83 | /* receive state */ | |
| 84 | UINT8 rstate; | |
| 85 | UINT32 rreg; /* shift register */ | |
| 86 | UINT8 rones; /* count '1 bits */ | |
| 87 | UINT8 rsize; /* bits in the shift register */ | |
| 88 | UINT16 rfifo[FIFO_SIZE]; /* X x 8-bit FIFO + full & addr marker bits */ | |
| 89 | ||
| 90 | /* frame-based interface*/ | |
| 91 | UINT8 frame[MAX_FRAME_LENGTH]; | |
| 92 | UINT32 flen, fpos; | |
| 93 | ||
| 94 | }; | |
| 95 | ||
| 96 | /* meaning of tstate / rtate: | |
| 97 | 0 = idle / waiting for frame flag | |
| 98 | 1 = flag sync | |
| 99 | 2 = 8-bit address field(s) | |
| 100 | 3-4 = 8-bit control field(s) | |
| 101 | 5 = 8-bit logical control field(s) | |
| 102 | 6 = variable-length data field(s) | |
| 103 | */ | |
| 104 | ||
| 105 | ||
| 106 | ||
| 107 | /******************* utility function and macros ********************/ | |
| 108 | ||
| 109 | ||
| 110 | ||
| 111 | #define LOG(x) do { if (VERBOSE) logerror x; } while (0) | |
| 112 | ||
| 113 | ||
| 114 | ||
| 115 | /* control register 1 */ | |
| 116 | ||
| 117 | #define AC ( mc6854->cr1 & 1 ) | |
| 118 | #define FCTDRA ( mc6854->cr2 & 8 ) | |
| 119 | /* extra register select bits */ | |
| 120 | ||
| 121 | #define RRESET ( mc6854->cr1 & 0x40 ) | |
| 122 | #define TRESET ( mc6854->cr1 & 0x80 ) | |
| 123 | /* transmit / reset condition */ | |
| 124 | ||
| 125 | #define RIE ( mc6854->cr1 & 2 ) | |
| 126 | #define TIE ( mc6854->cr1 & 4 ) | |
| 127 | /* interrupt enable */ | |
| 128 | ||
| 129 | #define DISCONTINUE ( mc6854->cr1 & 0x20 ) | |
| 130 | /* discontinue received frame */ | |
| 131 | ||
| 132 | ||
| 133 | ||
| 134 | /* control register 2 */ | |
| 135 | ||
| 136 | #define PSE ( mc6854->cr2 & 1 ) | |
| 137 | /* prioritize status bits (TODO) */ | |
| 138 | ||
| 139 | #define TWOBYTES ( mc6854->cr2 & 2 ) | |
| 140 | /* two-bytes mode */ | |
| 141 | ||
| 142 | #define FMIDLE ( mc6854->cr2 & 4 ) | |
| 143 | /* flag time fill (vs. mark idle) */ | |
| 144 | ||
| 145 | #define TLAST ( mc6854->cr2 & 0x10 ) | |
| 146 | /* transmit last byte of frame */ | |
| 147 | ||
| 148 | #define RTS ( mc6854->cr2 & 0x80 ) | |
| 149 | /* request-to-send */ | |
| 150 | ||
| 151 | ||
| 152 | ||
| 153 | /* control register 3 */ | |
| 154 | ||
| 155 | #define LCF ( mc6854->cr3 & 1 ) | |
| 156 | /* logical control field select */ | |
| 157 | ||
| 158 | #define CEX ( mc6854->cr3 & 2 ) | |
| 159 | /* control field is 16 bits instead of 8 */ | |
| 160 | ||
| 161 | #define AEX ( mc6854->cr3 & 4 ) | |
| 162 | /* extended address mode (vs normal 8-bit address mode) */ | |
| 163 | ||
| 164 | #define IDL0 ( mc6854->cr3 & 8 ) | |
| 165 | /* idle condition begins with a '0' instead of a '1" */ | |
| 166 | ||
| 167 | #define FDSE ( mc6854->cr3 & 0x10 ) | |
| 168 | /* enable the flag detect status in SR1 */ | |
| 169 | ||
| 170 | #define LOOP ( mc6854->cr3 & 0x20 ) | |
| 171 | /* loop mode */ | |
| 172 | ||
| 173 | #define TST ( mc6854->cr3 & 0x40 ) | |
| 174 | /* test mode (or go active on poll) */ | |
| 175 | ||
| 176 | #define DTR ( mc6854->cr3 & 0x80 ) | |
| 177 | /* data-transmit-ready (or loop on-line control) */ | |
| 178 | ||
| 179 | ||
| 180 | ||
| 181 | /* control register 4 */ | |
| 182 | ||
| 183 | #define TWOINTER ( mc6854->cr4 & 1 ) | |
| 184 | /* both an openning and a closing inter-frame are sent */ | |
| 185 | ||
| 186 | static const int word_length[4] = { 5, 6, 7, 8 }; | |
| 187 | #define TWL word_length[ ( mc6854->cr4 >> 1 ) & 3 ] | |
| 188 | #define RWL word_length[ ( mc6854->cr4 >> 3 ) & 3 ] | |
| 189 | /* transmit / receive word length */ | |
| 190 | ||
| 191 | #define ABT ( mc6854->cr4 & 0x20 ) | |
| 192 | /* aborts */ | |
| 193 | ||
| 194 | #define ABTEX ( mc6854->cr4 & 0x40 ) | |
| 195 | /* abort generates 16 '1' bits instead of 8 */ | |
| 196 | ||
| 197 | #define NRZ ( mc6854->cr4 & 0x80 ) | |
| 198 | /* zero complement / non-zero complement data format */ | |
| 199 | ||
| 200 | ||
| 201 | ||
| 202 | /* status register 1 */ | |
| 203 | #define RDA 0x01 /* receiver data available */ | |
| 204 | #define S2RQ 0x02 /* status register #2 read request */ | |
| 205 | #define FD 0x04 /* flag detect */ | |
| 206 | #define CTS 0x10 /* clear-to-send */ | |
| 207 | #define TU 0x20 /* transmitter underrun */ | |
| 208 | #define TDRA 0x40 /* transmitter data register available */ | |
| 209 | #define IRQ 0x80 /* interrupt request */ | |
| 210 | ||
| 211 | ||
| 212 | /* status register 2 */ | |
| 213 | #define AP 0x01 /* address present */ | |
| 214 | #define FV 0x02 /* frame valid */ | |
| 215 | #define RIDLE 0x04 /* receiver idle */ | |
| 216 | #define RABT 0x08 /* receiver abort */ | |
| 217 | #define ERR 0x10 /* invalid frame error */ | |
| 218 | #define DCD 0x20 /* data carrier detect (ignored) */ | |
| 219 | #define OVRN 0x40 /* receiver overrun */ | |
| 220 | #define RDA2 0x80 /* copy of RDA */ | |
| 221 | ||
| 222 | ||
| 223 | ||
| 224 | INLINE mc6854_t* get_safe_token( device_t *device ) | |
| 225 | { | |
| 226 | assert( device != NULL ); | |
| 227 | assert( device->type() == MC6854 ); | |
| 228 | return (mc6854_t*) downcast<mc6854_device *>(device)->token(); | |
| 229 | } | |
| 230 | ||
| 231 | ||
| 232 | /*********************** transmit ***********************/ | |
| 233 | ||
| 234 | ||
| 235 | ||
| 236 | /* MC6854 fills bit queue */ | |
| 237 | static void mc6854_send_bits( device_t *device, UINT32 data, int len, int zi ) | |
| 238 | { | |
| 239 | mc6854_t* mc6854 = get_safe_token( device ); | |
| 240 | attotime expire; | |
| 241 | int i; | |
| 242 | if ( zi ) | |
| 243 | { | |
| 244 | /* zero-insertion mode */ | |
| 245 | UINT32 d = 0; | |
| 246 | int l = 0; | |
| 247 | for ( i = 0; i < len; i++, data >>= 1, l++ ) | |
| 248 | { | |
| 249 | if ( data & 1 ) | |
| 250 | { | |
| 251 | d |= 1 << l; | |
| 252 | mc6854->tones++; | |
| 253 | if ( mc6854->tones == 5 ) | |
| 254 | { | |
| 255 | /* insert a '0' after 5 consecutive '1" */ | |
| 256 | mc6854->tones = 0; | |
| 257 | l++; | |
| 258 | } | |
| 259 | } | |
| 260 | else | |
| 261 | mc6854->tones = 0; | |
| 262 | } | |
| 263 | data = d; | |
| 264 | len = l; | |
| 265 | } | |
| 266 | else | |
| 267 | mc6854->tones = 0; | |
| 268 | ||
| 269 | /* send bits */ | |
| 270 | if ( !mc6854->out_txd_func.isnull() ) | |
| 271 | { | |
| 272 | for ( i = 0; i < len; i++, data >>= 1 ) | |
| 273 | mc6854->out_txd_func( data & 1 ); | |
| 274 | } | |
| 275 | ||
| 276 | /* schedule when to ask the MC6854 for more bits */ | |
| 277 | expire = mc6854->ttimer ->remaining( ); | |
| 278 | if ( expire== attotime::never ) | |
| 279 | expire = attotime::zero; | |
| 280 | mc6854->ttimer->reset( expire + (BIT_LENGTH * len)); | |
| 281 | } | |
| 282 | ||
| 283 | ||
| 284 | ||
| 285 | /* CPU push -> tfifo[0] -> ... -> tfifo[FIFO_SIZE-1] -> pop */ | |
| 286 | static void mc6854_tfifo_push( device_t *device, UINT8 data ) | |
| 287 | { | |
| 288 | mc6854_t* mc6854 = get_safe_token( device ); | |
| 289 | int i; | |
| 290 | ||
| 291 | if ( TRESET ) | |
| 292 | return; | |
| 293 | ||
| 294 | /* push towards the rightmost free entry */ | |
| 295 | for ( i = FIFO_SIZE - 1; i >= 0; i-- ) | |
| 296 | { | |
| 297 | if ( ! ( mc6854->tfifo[ i ] & 0x100 ) ) | |
| 298 | break; | |
| 299 | } | |
| 300 | ||
| 301 | if ( i >= 0 ) | |
| 302 | mc6854->tfifo[ i ] = data | 0x100; | |
| 303 | else | |
| 304 | logerror( "%f mc6854_tfifo_push: FIFO overrun\n", device->machine().time().as_double() ); | |
| 305 | ||
| 306 | /* start frame, if needed */ | |
| 307 | if ( ! mc6854->tstate ) | |
| 308 | { | |
| 309 | LOG(( "%f mc6854_tfifo_push: start frame\n", device->machine().time().as_double() )); | |
| 310 | mc6854->tstate = 2; | |
| 311 | mc6854_send_bits( device, FLAG, 8, 0 ); | |
| 312 | } | |
| 313 | } | |
| 314 | ||
| 315 | ||
| 316 | ||
| 317 | /* CPU asks for normal frame termination */ | |
| 318 | static void mc6854_tfifo_terminate( device_t *device ) | |
| 319 | { | |
| 320 | mc6854_t* mc6854 = get_safe_token( device ); | |
| 321 | ||
| 322 | /* mark most recently pushed byte as the last one of the frame */ | |
| 323 | int i; | |
| 324 | for ( i = 0; i < FIFO_SIZE; i++ ) | |
| 325 | { | |
| 326 | if ( mc6854->tfifo[ i ] & 0x100 ) | |
| 327 | { | |
| 328 | mc6854->tfifo[ i ] |= 0x200; | |
| 329 | break; | |
| 330 | } | |
| 331 | } | |
| 332 | } | |
| 333 | ||
| 334 | ||
| 335 | ||
| 336 | /* call-back to refill the bit-stream from the FIFO */ | |
| 337 | static TIMER_CALLBACK(mc6854_tfifo_cb) | |
| 338 | { | |
| 339 | device_t* device = (device_t*) ptr; | |
| 340 | mc6854_t* mc6854 = get_safe_token( device ); | |
| 341 | int i, data = mc6854->tfifo[ FIFO_SIZE - 1 ]; | |
| 342 | ||
| 343 | if ( ! mc6854->tstate ) | |
| 344 | return; | |
| 345 | ||
| 346 | /* shift FIFO to the right */ | |
| 347 | for ( i = FIFO_SIZE - 1; i > 0; i-- ) | |
| 348 | mc6854->tfifo[ i ] = mc6854->tfifo[ i - 1 ]; | |
| 349 | mc6854->tfifo[ 0 ] = 0; | |
| 350 | ||
| 351 | if ( data & 0x100 ) | |
| 352 | { | |
| 353 | /* got data */ | |
| 354 | ||
| 355 | int blen = 8; | |
| 356 | ||
| 357 | switch ( mc6854->tstate ) | |
| 358 | { | |
| 359 | case 2: /* 8-bit address field */ | |
| 360 | if ( ( data & 1 ) || ( ! AEX ) ) | |
| 361 | mc6854->tstate = 3; | |
| 362 | LOG(( "%f mc6854_tfifo_cb: address field $%02X\n", machine.time().as_double(), data & 0xff )); | |
| 363 | break; | |
| 364 | ||
| 365 | case 3: /* 8-bit control field */ | |
| 366 | if ( CEX ) | |
| 367 | mc6854->tstate = 4; | |
| 368 | else if ( LCF ) | |
| 369 | mc6854->tstate = 5; | |
| 370 | else | |
| 371 | mc6854->tstate = 6; | |
| 372 | LOG(( "%f mc6854_tfifo_cb: control field $%02X\n", machine.time().as_double(), data & 0xff )); | |
| 373 | break; | |
| 374 | ||
| 375 | case 4: /* 8-bit extended control field (optional) */ | |
| 376 | if ( LCF ) | |
| 377 | mc6854->tstate = 5; | |
| 378 | else | |
| 379 | mc6854->tstate = 6; | |
| 380 | LOG(( "%f mc6854_tfifo_cb: control field $%02X\n", machine.time().as_double(), data & 0xff )); | |
| 381 | break; | |
| 382 | ||
| 383 | case 5: /* 8-bit logical control (optional) */ | |
| 384 | if ( ! ( data & 0x80 ) ) | |
| 385 | mc6854->tstate = 6; | |
| 386 | LOG(( "%f mc6854_tfifo_cb: logical control field $%02X\n", machine.time().as_double(), data & 0xff )); | |
| 387 | break; | |
| 388 | ||
| 389 | case 6: /* variable-length data */ | |
| 390 | blen = TWL; | |
| 391 | LOG(( "%f mc6854_tfifo_cb: data field $%02X, %i bits\n", machine.time().as_double(), data & 0xff, blen )); | |
| 392 | break; | |
| 393 | ||
| 394 | default: | |
| 395 | LOG(( "%f mc6854_tfifo_cb: state=%i\n", machine.time().as_double(), mc6854->tstate)); | |
| 396 | } | |
| 397 | ||
| 398 | if ( mc6854->flen < MAX_FRAME_LENGTH ) | |
| 399 | mc6854->frame[ mc6854->flen++ ] = data; | |
| 400 | else | |
| 401 | logerror( "mc6854_tfifo_cb: truncated frame, max=%i\n", MAX_FRAME_LENGTH ); | |
| 402 | ||
| 403 | mc6854_send_bits( device, data, blen, 1 ); | |
| 404 | } | |
| 405 | else | |
| 406 | { | |
| 407 | /* data underrun => abort */ | |
| 408 | logerror( "%f mc6854_tfifo_cb: FIFO underrun\n", machine.time().as_double() ); | |
| 409 | mc6854->sr1 |= TU; | |
| 410 | mc6854->tstate = 0; | |
| 411 | mc6854_send_bits( device, 0xffff, ABTEX ? 16 : 8, 0 ); | |
| 412 | mc6854->flen = 0; | |
| 413 | } | |
| 414 | ||
| 415 | /* close frame, if needed */ | |
| 416 | if ( data & 0x200 ) | |
| 417 | { | |
| 418 | int len = mc6854->flen; | |
| 419 | ||
| 420 | LOG(( "%f mc6854_tfifo_cb: end frame\n", machine.time().as_double() )); | |
| 421 | mc6854_send_bits( device, 0xdeadbeef, 16, 1 ); /* send check-sum: TODO */ | |
| 422 | mc6854_send_bits( device, FLAG, 8, 0 ); /* send closing flag */ | |
| 423 | ||
| 424 | if ( mc6854->tfifo[ FIFO_SIZE - 1 ] & 0x100 ) | |
| 425 | { | |
| 426 | /* re-open frame asap */ | |
| 427 | LOG(( "%f mc6854_tfifo_cb: start frame\n", machine.time().as_double() )); | |
| 428 | if ( TWOINTER ) | |
| 429 | mc6854_send_bits( device, FLAG, 8, 0 ); | |
| 430 | } | |
| 431 | else | |
| 432 | mc6854->tstate = 0; | |
| 433 | ||
| 434 | mc6854->flen = 0; | |
| 435 | if ( mc6854->iface->out_frame ) | |
| 436 | mc6854->iface->out_frame( device, mc6854->frame, len ); | |
| 437 | } | |
| 438 | } | |
| 439 | ||
| 440 | ||
| 441 | ||
| 442 | static void mc6854_tfifo_clear( device_t *device ) | |
| 443 | { | |
| 444 | mc6854_t* mc6854 = get_safe_token( device ); | |
| 445 | memset( mc6854->tfifo, 0, sizeof( mc6854->tfifo ) ); | |
| 446 | mc6854->tstate = 0; | |
| 447 | mc6854->flen = 0; | |
| 448 | mc6854->ttimer->reset( ); | |
| 449 | } | |
| 450 | ||
| 451 | ||
| 452 | ||
| 453 | /*********************** receive ***********************/ | |
| 454 | ||
| 455 | ||
| 456 | ||
| 457 | /* MC6854 pushes a field in the FIFO */ | |
| 458 | static void mc6854_rfifo_push( device_t *device, UINT8 d ) | |
| 459 | { | |
| 460 | mc6854_t* mc6854 = get_safe_token( device ); | |
| 461 | int i, blen = 8; | |
| 462 | unsigned data = d; | |
| 463 | ||
| 464 | switch ( mc6854->rstate ) | |
| 465 | { | |
| 466 | case 0: | |
| 467 | case 1: | |
| 468 | case 2: /* 8-bit address field */ | |
| 469 | if ( ( data & 1 ) || ( ! AEX ) ) | |
| 470 | mc6854->rstate = 3; | |
| 471 | else | |
| 472 | mc6854->rstate = 2; | |
| 473 | LOG(( "%f mc6854_rfifo_push: address field $%02X\n", device->machine().time().as_double(), data )); | |
| 474 | data |= 0x400; /* address marker */ | |
| 475 | break; | |
| 476 | ||
| 477 | case 3: /* 8-bit control field */ | |
| 478 | if ( CEX ) | |
| 479 | mc6854->rstate = 4; | |
| 480 | else if ( LCF ) | |
| 481 | mc6854->rstate = 5; | |
| 482 | else | |
| 483 | mc6854->rstate = 6; | |
| 484 | LOG(( "%f mc6854_rfifo_push: control field $%02X\n", device->machine().time().as_double(), data )); | |
| 485 | break; | |
| 486 | ||
| 487 | case 4: /* 8-bit extended control field (optional) */ | |
| 488 | if ( LCF ) | |
| 489 | mc6854->rstate = 5; | |
| 490 | else | |
| 491 | mc6854->rstate = 6; | |
| 492 | LOG(( "%f mc6854_rfifo_push: control field $%02X\n", device->machine().time().as_double(), data )); | |
| 493 | break; | |
| 494 | ||
| 495 | case 5: /* 8-bit logical control (optional) */ | |
| 496 | if ( ! ( data & 0x80 ) ) | |
| 497 | mc6854->rstate = 6; | |
| 498 | LOG(( "%f mc6854_rfifo_push: logical control field $%02X\n", device->machine().time().as_double(), data )); | |
| 499 | break; | |
| 500 | ||
| 501 | case 6: /* variable-length data */ | |
| 502 | blen = RWL; | |
| 503 | data >>= 8 - blen; | |
| 504 | LOG(( "%f mc6854_rfifo_push: data field $%02X, %i bits\n", device->machine().time().as_double(), data, blen )); | |
| 505 | break; | |
| 506 | } | |
| 507 | ||
| 508 | /* no further FIFO fill until FV is cleared! */ | |
| 509 | if ( mc6854->sr2 & FV ) | |
| 510 | { | |
| 511 | LOG(( "%f mc6854_rfifo_push: field not pushed\n", device->machine().time().as_double() )); | |
| 512 | return; | |
| 513 | } | |
| 514 | ||
| 515 | data |= 0x100; /* entry full marker */ | |
| 516 | ||
| 517 | /* push towards the rightmost free entry */ | |
| 518 | for ( i = FIFO_SIZE - 1; i >= 0; i-- ) | |
| 519 | { | |
| 520 | if ( ! ( mc6854->rfifo[ i ] & 0x100 ) ) | |
| 521 | break; | |
| 522 | } | |
| 523 | ||
| 524 | if ( i >= 0 ) | |
| 525 | mc6854->rfifo[ i ] = data | 0x100; | |
| 526 | else | |
| 527 | { | |
| 528 | /* FIFO full */ | |
| 529 | mc6854->sr2 |= OVRN; | |
| 530 | mc6854->rfifo[ 0 ] = data; | |
| 531 | logerror( "%f mc6854_rfifo_push: FIFO overrun\n", device->machine().time().as_double() ); | |
| 532 | } | |
| 533 | ||
| 534 | mc6854->rsize -= blen; | |
| 535 | } | |
| 536 | ||
| 537 | ||
| 538 | ||
| 539 | static void mc6854_rfifo_terminate( device_t *device ) | |
| 540 | { | |
| 541 | mc6854_t* mc6854 = get_safe_token( device ); | |
| 542 | /* mark most recently pushed byte as the last one of the frame */ | |
| 543 | int i; | |
| 544 | for ( i = 0; i < FIFO_SIZE; i++ ) | |
| 545 | { | |
| 546 | if ( mc6854->rfifo[ i ] & 0x100 ) | |
| 547 | { | |
| 548 | mc6854->tfifo[ i ] |= 0x200; | |
| 549 | break; | |
| 550 | } | |
| 551 | ||
| 552 | } | |
| 553 | ||
| 554 | mc6854->flen = 0; | |
| 555 | mc6854->rstate = 1; | |
| 556 | } | |
| 557 | ||
| 558 | ||
| 559 | ||
| 560 | /* CPU pops the FIFO */ | |
| 561 | static UINT8 mc6854_rfifo_pop( device_t *device ) | |
| 562 | { | |
| 563 | mc6854_t* mc6854 = get_safe_token( device ); | |
| 564 | int i, data = mc6854->rfifo[ FIFO_SIZE - 1 ]; | |
| 565 | ||
| 566 | /* shift FIFO to the right */ | |
| 567 | for ( i = FIFO_SIZE - 1; i > 0; i -- ) | |
| 568 | mc6854->rfifo[ i ] = mc6854->rfifo[ i - 1 ]; | |
| 569 | mc6854->rfifo[ 0 ] = 0; | |
| 570 | ||
| 571 | if ( mc6854->rfifo[ FIFO_SIZE - 1 ] & 0x200 ) | |
| 572 | { | |
| 573 | /* last byte in frame */ | |
| 574 | mc6854->sr2 |= FV; /* TODO: check CRC & set ERR instead of FV if error*/ | |
| 575 | } | |
| 576 | ||
| 577 | /* auto-refill in frame mode */ | |
| 578 | if ( mc6854->flen > 0 ) | |
| 579 | { | |
| 580 | mc6854_rfifo_push( device, mc6854->frame[ mc6854->fpos++ ] ); | |
| 581 | if ( mc6854->fpos == mc6854->flen ) | |
| 582 | mc6854_rfifo_terminate( device ); | |
| 583 | } | |
| 584 | ||
| 585 | return data; | |
| 586 | } | |
| 587 | ||
| 588 | ||
| 589 | /* MC6854 makes fields from bits */ | |
| 590 | WRITE_LINE_DEVICE_HANDLER( mc6854_set_rx ) | |
| 591 | { | |
| 592 | mc6854_t* mc6854 = get_safe_token( device ); | |
| 593 | int fieldlen = ( mc6854->rstate < 6 ) ? 8 : RWL; | |
| 594 | ||
| 595 | if ( RRESET || (mc6854->sr2 & DCD) ) | |
| 596 | return; | |
| 597 | ||
| 598 | if ( state ) | |
| 599 | { | |
| 600 | mc6854->rones++; | |
| 601 | mc6854->rreg = (mc6854->rreg >> 1) | 0x80000000; | |
| 602 | if ( mc6854->rones >= 8 ) | |
| 603 | { | |
| 604 | /* abort */ | |
| 605 | mc6854->rstate = 0; | |
| 606 | mc6854->rsize = 0; | |
| 607 | if ( mc6854->rstate > 1 ) | |
| 608 | { | |
| 609 | /* only in-frame abort */ | |
| 610 | mc6854->sr2 |= RABT; | |
| 611 | LOG(( "%f mc6854_receive_bit: abort\n", device->machine().time().as_double() )); | |
| 612 | } | |
| 613 | } | |
| 614 | else | |
| 615 | { | |
| 616 | mc6854->rsize++; | |
| 617 | if ( mc6854->rstate && mc6854->rsize >= fieldlen + 24 ) | |
| 618 | mc6854_rfifo_push( device, mc6854->rreg ); | |
| 619 | } | |
| 620 | } | |
| 621 | else if ( mc6854->rones == 5 ) | |
| 622 | { | |
| 623 | /* discards '0' inserted after 5 '1' */ | |
| 624 | mc6854->rones = 0; | |
| 625 | return; | |
| 626 | } | |
| 627 | else if ( mc6854->rones == 6 ) | |
| 628 | { | |
| 629 | /* flag */ | |
| 630 | if ( FDSE ) | |
| 631 | mc6854->sr1 |= FD; | |
| 632 | ||
| 633 | if ( mc6854->rstate > 1 ) | |
| 634 | { | |
| 635 | /* end of frame */ | |
| 636 | mc6854->rreg >>= 1; | |
| 637 | mc6854->rsize++; | |
| 638 | if ( mc6854->rsize >= fieldlen + 24 ) /* last field */ | |
| 639 | mc6854_rfifo_push( device, mc6854->rreg ); | |
| 640 | mc6854_rfifo_terminate( device ); | |
| 641 | LOG(( "%f mc6854_receive_bit: end of frame\n", device->machine().time().as_double() )); | |
| 642 | } | |
| 643 | mc6854->rones = 0; | |
| 644 | mc6854->rstate = 1; | |
| 645 | mc6854->rsize = 0; | |
| 646 | } else | |
| 647 | { | |
| 648 | mc6854->rones = 0; | |
| 649 | mc6854->rreg >>= 1; | |
| 650 | mc6854->rsize++; | |
| 651 | if ( mc6854->rstate && mc6854->rsize >= fieldlen + 24 ) | |
| 652 | mc6854_rfifo_push( device, mc6854->rreg ); | |
| 653 | } | |
| 654 | } | |
| 655 | ||
| 656 | ||
| 657 | ||
| 658 | static void mc6854_rfifo_clear( device_t *device ) | |
| 659 | { | |
| 660 | mc6854_t* mc6854 = get_safe_token( device ); | |
| 661 | memset( mc6854->rfifo, 0, sizeof( mc6854->rfifo ) ); | |
| 662 | mc6854->rstate = 0; | |
| 663 | mc6854->rreg = 0; | |
| 664 | mc6854->rsize = 0; | |
| 665 | mc6854->rones = 0; | |
| 666 | mc6854->flen = 0; | |
| 667 | } | |
| 668 | ||
| 669 | ||
| 670 | ||
| 671 | int mc6854_send_frame( device_t *device, UINT8* data, int len ) | |
| 672 | { | |
| 673 | mc6854_t* mc6854 = get_safe_token( device ); | |
| 674 | if ( mc6854->rstate > 1 || mc6854->tstate > 1 || RTS ) | |
| 675 | return -1; /* busy */ | |
| 676 | ||
| 677 | if ( len > MAX_FRAME_LENGTH ) | |
| 678 | { | |
| 679 | logerror( "mc6854_send_frame: truncated frame, size=%i, max=%i\n", len, MAX_FRAME_LENGTH ); | |
| 680 | len = MAX_FRAME_LENGTH; | |
| 681 | } | |
| 682 | else if ( len < 2 ) | |
| 683 | { | |
| 684 | logerror( "mc6854_send_frame: frame too short, size=%i, min=2\n", len ); | |
| 685 | len = 2; | |
| 686 | } | |
| 687 | memcpy( mc6854->frame, data, len ); | |
| 688 | if ( FDSE ) | |
| 689 | mc6854->sr1 |= FD; | |
| 690 | mc6854->flen = len; | |
| 691 | mc6854->fpos = 0; | |
| 692 | mc6854_rfifo_push( device, mc6854->frame[ mc6854->fpos++ ] ); | |
| 693 | mc6854_rfifo_push( device, mc6854->frame[ mc6854->fpos++ ] ); | |
| 694 | if ( mc6854->fpos == mc6854->flen ) | |
| 695 | mc6854_rfifo_terminate( device ); | |
| 696 | return 0; | |
| 697 | } | |
| 698 | ||
| 699 | ||
| 700 | ||
| 701 | /************************** CPU interface ****************************/ | |
| 702 | ||
| 703 | ||
| 704 | ||
| 705 | WRITE_LINE_DEVICE_HANDLER( mc6854_set_cts ) | |
| 706 | { | |
| 707 | mc6854_t* mc6854 = get_safe_token( device ); | |
| 708 | if ( ! mc6854->cts && state ) | |
| 709 | mc6854->sr1 |= CTS; | |
| 710 | mc6854->cts = state; | |
| 711 | ||
| 712 | if ( mc6854->cts ) | |
| 713 | mc6854->sr1 |= CTS; | |
| 714 | else | |
| 715 | mc6854->sr1 &= ~CTS; | |
| 716 | } | |
| 717 | ||
| 718 | ||
| 719 | ||
| 720 | WRITE_LINE_DEVICE_HANDLER( mc6854_set_dcd ) | |
| 721 | { | |
| 722 | mc6854_t* mc6854 = get_safe_token( device ); | |
| 723 | if ( ! mc6854->dcd && state ) | |
| 724 | { | |
| 725 | mc6854->sr2 |= DCD; | |
| 726 | /* partial reset */ | |
| 727 | mc6854->rstate = 0; | |
| 728 | mc6854->rreg = 0; | |
| 729 | mc6854->rsize = 0; | |
| 730 | mc6854->rones = 0; | |
| 731 | } | |
| 732 | mc6854->dcd = state; | |
| 733 | } | |
| 734 | ||
| 735 | ||
| 736 | ||
| 737 | static void mc6854_update_sr2( mc6854_t* mc6854 ) | |
| 738 | { | |
| 739 | /* update RDA */ | |
| 740 | mc6854->sr2 |= RDA2; | |
| 741 | if ( ! (mc6854->rfifo[ FIFO_SIZE - 1 ] & 0x100) ) | |
| 742 | mc6854->sr2 &= ~RDA2; | |
| 743 | else if ( TWOBYTES && ! (mc6854->tfifo[ FIFO_SIZE - 2 ] & 0x100) ) | |
| 744 | mc6854->sr2 &= ~RDA2; | |
| 745 | ||
| 746 | /* update AP */ | |
| 747 | if ( mc6854->rfifo[ FIFO_SIZE - 1 ] & 0x400 ) | |
| 748 | mc6854->sr2 |= AP; | |
| 749 | else | |
| 750 | mc6854->sr2 &= ~AP; | |
| 751 | } | |
| 752 | ||
| 753 | ||
| 754 | ||
| 755 | static void mc6854_update_sr1( mc6854_t* mc6854 ) | |
| 756 | { | |
| 757 | mc6854_update_sr2( mc6854 ); | |
| 758 | ||
| 759 | /* update S2RQ */ | |
| 760 | if ( mc6854->sr2 & 0x7f ) | |
| 761 | mc6854->sr1 |= S2RQ; | |
| 762 | else | |
| 763 | mc6854->sr1 &= ~S2RQ; | |
| 764 | ||
| 765 | /* update TRDA (always prioritized by CTS) */ | |
| 766 | if ( TRESET || ( mc6854->sr1 & CTS ) ) | |
| 767 | mc6854->sr1 &= ~TDRA; | |
| 768 | else | |
| 769 | { | |
| 770 | mc6854->sr1 |= TDRA; | |
| 771 | if ( mc6854->tfifo[ 0 ] & 0x100 ) | |
| 772 | mc6854->sr1 &= ~TDRA; | |
| 773 | else if ( TWOBYTES && (mc6854->tfifo[ 1 ] & 0x100) ) | |
| 774 | mc6854->sr1 &= ~TDRA; | |
| 775 | } | |
| 776 | ||
| 777 | /* update RDA */ | |
| 778 | if ( mc6854->sr2 & RDA2 ) | |
| 779 | mc6854->sr1 |= RDA; | |
| 780 | else | |
| 781 | mc6854->sr1 &= ~RDA; | |
| 782 | ||
| 783 | /* update IRQ */ | |
| 784 | mc6854->sr1 &= ~IRQ; | |
| 785 | if ( RIE && (mc6854->sr1 & (TU | TDRA) ) ) | |
| 786 | mc6854->sr1 |= IRQ; | |
| 787 | if ( TIE ) | |
| 788 | { | |
| 789 | if ( mc6854->sr1 & (S2RQ | RDA | CTS) ) | |
| 790 | mc6854->sr1 |= IRQ; | |
| 791 | if ( mc6854->sr2 & (ERR | FV | DCD | OVRN | RABT | RIDLE | AP) ) | |
| 792 | mc6854->sr1 |= IRQ; | |
| 793 | } | |
| 794 | ||
| 795 | mc6854->out_irq_func((mc6854->sr1 & IRQ) ? ASSERT_LINE : CLEAR_LINE); | |
| 796 | } | |
| 797 | ||
| 798 | ||
| 799 | ||
| 800 | READ8_DEVICE_HANDLER ( mc6854_r ) | |
| 801 | { | |
| 802 | mc6854_t* mc6854 = get_safe_token( device ); | |
| 803 | switch ( offset ) | |
| 804 | { | |
| 805 | case 0: /* status register 1 */ | |
| 806 | mc6854_update_sr1( mc6854 ); | |
| 807 | LOG(( "%f $%04x mc6854_r: get SR1=$%02X (rda=%i,s2rq=%i,fd=%i,cts=%i,tu=%i,tdra=%i,irq=%i)\n", | |
| 808 | space.machine().time().as_double(), space.machine().firstcpu->pcbase( ), mc6854->sr1, | |
| 809 | ( mc6854->sr1 & RDA) ? 1 : 0, ( mc6854->sr1 & S2RQ) ? 1 : 0, | |
| 810 | ( mc6854->sr1 & FD ) ? 1 : 0, ( mc6854->sr1 & CTS ) ? 1 : 0, | |
| 811 | ( mc6854->sr1 & TU ) ? 1 : 0, ( mc6854->sr1 & TDRA) ? 1 : 0, | |
| 812 | ( mc6854->sr1 & IRQ) ? 1 : 0 )); | |
| 813 | return mc6854->sr1; | |
| 814 | ||
| 815 | case 1: /* status register 2 */ | |
| 816 | mc6854_update_sr2( mc6854 ); | |
| 817 | LOG(( "%f $%04x mc6854_r: get SR2=$%02X (ap=%i,fv=%i,ridle=%i,rabt=%i,err=%i,dcd=%i,ovrn=%i,rda2=%i)\n", | |
| 818 | space.machine().time().as_double(), space.machine().firstcpu->pcbase( ), mc6854->sr2, | |
| 819 | ( mc6854->sr2 & AP ) ? 1 : 0, ( mc6854->sr2 & FV ) ? 1 : 0, | |
| 820 | ( mc6854->sr2 & RIDLE) ? 1 : 0, ( mc6854->sr2 & RABT) ? 1 : 0, | |
| 821 | ( mc6854->sr2 & ERR ) ? 1 : 0, ( mc6854->sr2 & DCD ) ? 1 : 0, | |
| 822 | ( mc6854->sr2 & OVRN ) ? 1 : 0, ( mc6854->sr2 & RDA2) ? 1 : 0 )); | |
| 823 | return mc6854->sr2; | |
| 824 | ||
| 825 | case 2: /* receiver data register */ | |
| 826 | case 3: | |
| 827 | { | |
| 828 | UINT8 data = mc6854_rfifo_pop( device ); | |
| 829 | LOG(( "%f $%04x mc6854_r: get data $%02X\n", | |
| 830 | space.machine().time().as_double(), space.machine().firstcpu->pcbase( ), data )); | |
| 831 | return data; | |
| 832 | } | |
| 833 | ||
| 834 | default: | |
| 835 | logerror( "$%04x mc6854 invalid read offset %i\n", space.machine().firstcpu->pcbase( ), offset ); | |
| 836 | } | |
| 837 | return 0; | |
| 838 | } | |
| 839 | ||
| 840 | ||
| 841 | ||
| 842 | WRITE8_DEVICE_HANDLER ( mc6854_w ) | |
| 843 | { | |
| 844 | mc6854_t* mc6854 = get_safe_token( device ); | |
| 845 | switch ( offset ) | |
| 846 | { | |
| 847 | case 0: /* control register 1 */ | |
| 848 | mc6854->cr1 = data; | |
| 849 | LOG(( "%f $%04x mc6854_w: set CR1=$%02X (ac=%i,irq=%c%c,%sreset=%c%c)\n", | |
| 850 | space.machine().time().as_double(), space.machine().firstcpu->pcbase( ), mc6854->cr1, | |
| 851 | AC ? 1 : 0, | |
| 852 | RIE ? 'r' : '-', TIE ? 't' : '-', | |
| 853 | DISCONTINUE ? "discontinue," : "", | |
| 854 | RRESET ? 'r' : '-', TRESET ? 't' : '-' | |
| 855 | )); | |
| 856 | if ( mc6854->cr1 & 0xc ) | |
| 857 | logerror( "$%04x mc6854 DMA not handled (CR1=$%02X)\n", | |
| 858 | space.machine().firstcpu->pcbase( ), mc6854->cr1 ); | |
| 859 | if ( DISCONTINUE ) | |
| 860 | { | |
| 861 | /* abort receive FIFO but keeps shift register & synchro */ | |
| 862 | mc6854->rstate = 0; | |
| 863 | memset( mc6854->rfifo, 0, sizeof( mc6854->rfifo ) ); | |
| 864 | } | |
| 865 | if ( RRESET ) | |
| 866 | { | |
| 867 | /* abort FIFO & synchro */ | |
| 868 | mc6854_rfifo_clear( device ); | |
| 869 | mc6854->sr1 &= ~FD; | |
| 870 | mc6854->sr2 &= ~(AP | FV | RIDLE | RABT | ERR | OVRN | DCD); | |
| 871 | if ( mc6854->dcd ) mc6854->sr2 |= DCD; | |
| 872 | } | |
| 873 | if ( TRESET ) | |
| 874 | { | |
| 875 | mc6854_tfifo_clear( device ); | |
| 876 | mc6854->sr1 &= ~(TU | TDRA | CTS); | |
| 877 | if ( mc6854->cts ) mc6854->sr1 |= CTS; | |
| 878 | } | |
| 879 | break; | |
| 880 | ||
| 881 | case 1: | |
| 882 | if ( AC ) | |
| 883 | { | |
| 884 | /* control register 3 */ | |
| 885 | mc6854->cr3 = data; | |
| 886 | LOG(( "%f $%04x mc6854_w: set CR3=$%02X (lcf=%i,aex=%i,idl=%i,fdse=%i,loop=%i,tst=%i,dtr=%i)\n", | |
| 887 | space.machine().time().as_double(), space.machine().firstcpu->pcbase( ), mc6854->cr3, | |
| 888 | LCF ? (CEX ? 16 : 8) : 0, AEX ? 1 : 0, | |
| 889 | IDL0 ? 0 : 1, FDSE ? 1 : 0, LOOP ? 1 : 0, | |
| 890 | TST ? 1 : 0, DTR ? 1 : 0 | |
| 891 | )); | |
| 892 | if ( LOOP ) | |
| 893 | logerror( "$%04x mc6854 loop mode not handled (CR3=$%02X)\n", space.machine().firstcpu->pcbase( ), mc6854->cr3 ); | |
| 894 | if ( TST ) | |
| 895 | logerror( "$%04x mc6854 test mode not handled (CR3=$%02X)\n", space.machine().firstcpu->pcbase( ), mc6854->cr3 ); | |
| 896 | ||
| 897 | mc6854->out_dtr_func( DTR ? 1 : 0 ); | |
| 898 | ||
| 899 | } | |
| 900 | else | |
| 901 | { | |
| 902 | /* control register 2 */ | |
| 903 | mc6854->cr2 = data; | |
| 904 | LOG(( "%f $%04x mc6854_w: set CR2=$%02X (pse=%i,bytes=%i,fmidle=%i,%s,tlast=%i,clr=%c%c,rts=%i)\n", | |
| 905 | space.machine().time().as_double(), space.machine().firstcpu->pcbase( ), mc6854->cr2, | |
| 906 | PSE ? 1 : 0, TWOBYTES ? 2 : 1, FMIDLE ? 1 : 0, | |
| 907 | FCTDRA ? "fc" : "tdra", TLAST ? 1 : 0, | |
| 908 | data & 0x20 ? 'r' : '-', data & 0x40 ? 't' : '-', | |
| 909 | RTS ? 1 : 0 )); | |
| 910 | if ( PSE ) | |
| 911 | logerror( "$%04x mc6854 status prioritization not handled (CR2=$%02X)\n", space.machine().firstcpu->pcbase( ), mc6854->cr2 ); | |
| 912 | if ( TLAST ) | |
| 913 | mc6854_tfifo_terminate( device ); | |
| 914 | if ( data & 0x20 ) | |
| 915 | { | |
| 916 | /* clear receiver status */ | |
| 917 | mc6854->sr1 &= ~FD; | |
| 918 | mc6854->sr2 &= ~(AP | FV | RIDLE | RABT | ERR | OVRN | DCD); | |
| 919 | if ( mc6854->dcd ) | |
| 920 | mc6854->sr2 |= DCD; | |
| 921 | } | |
| 922 | if ( data & 0x40 ) | |
| 923 | { | |
| 924 | /* clear transmitter status */ | |
| 925 | mc6854->sr1 &= ~(TU | TDRA | CTS); | |
| 926 | if ( mc6854->cts ) | |
| 927 | mc6854->sr1 |= CTS; | |
| 928 | } | |
| 929 | ||
| 930 | mc6854->out_rts_func( RTS ? 1 : 0 ); | |
| 931 | } | |
| 932 | break; | |
| 933 | ||
| 934 | case 2: /* transmitter data: continue data */ | |
| 935 | LOG(( "%f $%04xmc6854_w: push data=$%02X\n", space.machine().time().as_double(), space.machine().firstcpu->pcbase( ), data )); | |
| 936 | mc6854_tfifo_push( device, data ); | |
| 937 | break; | |
| 938 | ||
| 939 | case 3: | |
| 940 | if ( AC ) | |
| 941 | { | |
| 942 | /* control register 4 */ | |
| 943 | mc6854->cr4 = data; | |
| 944 | LOG(( "%f $%04x mc6854_w: set CR4=$%02X (interframe=%i,tlen=%i,rlen=%i,%s%s)\n", space.machine().time().as_double(), space.machine().firstcpu->pcbase( ), mc6854->cr4, | |
| 945 | TWOINTER ? 2 : 1, | |
| 946 | TWL, RWL, | |
| 947 | ABT ? ( ABTEX ? "abort-ext," : "abort,") : "", | |
| 948 | NRZ ? "nrz" : "nrzi" )); | |
| 949 | if ( ABT ) | |
| 950 | { | |
| 951 | mc6854->tstate = 0; | |
| 952 | mc6854_send_bits( device, 0xffff, ABTEX ? 16 : 8, 0 ); | |
| 953 | mc6854->flen = 0; | |
| 954 | } | |
| 955 | } | |
| 956 | else | |
| 957 | { | |
| 958 | /* transmitter data: last data */ | |
| 959 | LOG(( "%f $%04x mc6854_w: push last-data=$%02X\n", space.machine().time().as_double(), space.machine().firstcpu->pcbase( ), data )); | |
| 960 | mc6854_tfifo_push( device, data ); | |
| 961 | mc6854_tfifo_terminate( device ); | |
| 962 | } | |
| 963 | break; | |
| 964 | ||
| 965 | default: | |
| 966 | logerror( "$%04x mc6854 invalid write offset %i (data=$%02X)\n", space.machine().firstcpu->pcbase( ), offset, data ); | |
| 967 | } | |
| 968 | } | |
| 969 | ||
| 970 | WRITE_LINE_DEVICE_HANDLER( mc6854_rxc_w ) | |
| 971 | { | |
| 972 | // TODO | |
| 973 | } | |
| 974 | ||
| 975 | WRITE_LINE_DEVICE_HANDLER( mc6854_txc_w ) | |
| 976 | { | |
| 977 | // TODO | |
| 978 | } | |
| 979 | ||
| 980 | /************************ reset *****************************/ | |
| 981 | ||
| 982 | static DEVICE_RESET( mc6854 ) | |
| 983 | { | |
| 984 | mc6854_t* mc6854 = get_safe_token( device ); | |
| 985 | LOG (( "mc6854 reset\n" )); | |
| 986 | mc6854->cr1 = 0xc0; /* reset condition */ | |
| 987 | mc6854->cr2 = 0; | |
| 988 | mc6854->cr3 = 0; | |
| 989 | mc6854->cr4 = 0; | |
| 990 | mc6854->sr1 = 0; | |
| 991 | mc6854->sr2 = 0; | |
| 992 | mc6854->cts = 0; | |
| 993 | mc6854->dcd = 0; | |
| 994 | mc6854_tfifo_clear( device ); | |
| 995 | mc6854_rfifo_clear( device ); | |
| 996 | } | |
| 997 | ||
| 998 | ||
| 999 | ||
| 1000 | /************************ start *****************************/ | |
| 1001 | ||
| 1002 | static DEVICE_START( mc6854 ) | |
| 1003 | { | |
| 1004 | mc6854_t* mc6854 = get_safe_token( device ); | |
| 1005 | ||
| 1006 | mc6854->iface = (const mc6854_interface*)device->static_config(); | |
| 1007 | mc6854->out_irq_func.resolve(mc6854->iface->out_irq_func, *device); | |
| 1008 | mc6854->in_rxd_func.resolve(mc6854->iface->in_rxd_func, *device); | |
| 1009 | mc6854->out_txd_func.resolve(mc6854->iface->out_txd_func, *device); | |
| 1010 | mc6854->out_rts_func.resolve(mc6854->iface->out_rts_func, *device); | |
| 1011 | mc6854->out_dtr_func.resolve(mc6854->iface->out_dtr_func, *device); | |
| 1012 | ||
| 1013 | mc6854->ttimer = device->machine().scheduler().timer_alloc(FUNC(mc6854_tfifo_cb), (void*) device ); | |
| 1014 | ||
| 1015 | state_save_register_item( device->machine(), "mc6854", device->tag(), 0, mc6854->cr1 ); | |
| 1016 | state_save_register_item( device->machine(), "mc6854", device->tag(), 0, mc6854->cr2 ); | |
| 1017 | state_save_register_item( device->machine(), "mc6854", device->tag(), 0, mc6854->cr3 ); | |
| 1018 | state_save_register_item( device->machine(), "mc6854", device->tag(), 0, mc6854->cr4 ); | |
| 1019 | state_save_register_item( device->machine(), "mc6854", device->tag(), 0, mc6854->sr1 ); | |
| 1020 | state_save_register_item( device->machine(), "mc6854", device->tag(), 0, mc6854->sr2 ); | |
| 1021 | state_save_register_item( device->machine(), "mc6854", device->tag(), 0, mc6854->cts ); | |
| 1022 | state_save_register_item( device->machine(), "mc6854", device->tag(), 0, mc6854->dcd ); | |
| 1023 | state_save_register_item( device->machine(), "mc6854", device->tag(), 0, mc6854->tstate ); | |
| 1024 | state_save_register_item_array( device->machine(), "mc6854", device->tag(), 0, mc6854->tfifo ); | |
| 1025 | state_save_register_item( device->machine(), "mc6854", device->tag(), 0, mc6854->tones ); | |
| 1026 | state_save_register_item( device->machine(), "mc6854", device->tag(), 0, mc6854->rstate ); | |
| 1027 | state_save_register_item( device->machine(), "mc6854", device->tag(), 0, mc6854->rreg ); | |
| 1028 | state_save_register_item( device->machine(), "mc6854", device->tag(), 0, mc6854->rones ); | |
| 1029 | state_save_register_item( device->machine(), "mc6854", device->tag(), 0, mc6854->rsize ); | |
| 1030 | state_save_register_item_array( device->machine(), "mc6854", device->tag(), 0, mc6854->rfifo ); | |
| 1031 | state_save_register_item_array( device->machine(), "mc6854", device->tag(), 0, mc6854->frame ); | |
| 1032 | state_save_register_item( device->machine(), "mc6854", device->tag(), 0, mc6854->flen ); | |
| 1033 | state_save_register_item( device->machine(), "mc6854", device->tag(), 0, mc6854->fpos ); | |
| 1034 | } | |
| 1035 | ||
| 1036 | ||
| 1037 | ||
| 1038 | const device_type MC6854 = &device_creator<mc6854_device>; | |
| 1039 | ||
| 1040 | mc6854_device::mc6854_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) | |
| 1041 | : device_t(mconfig, MC6854, "Motorola MC6854 ADLC", tag, owner, clock) | |
| 1042 | { | |
| 1043 | m_token = global_alloc_clear(mc6854_t); | |
| 1044 | } | |
| 1045 | ||
| 1046 | //------------------------------------------------- | |
| 1047 | // device_config_complete - perform any | |
| 1048 | // operations now that the configuration is | |
| 1049 | // complete | |
| 1050 | //------------------------------------------------- | |
| 1051 | ||
| 1052 | void mc6854_device::device_config_complete() | |
| 1053 | { | |
| 1054 | } | |
| 1055 | ||
| 1056 | //------------------------------------------------- | |
| 1057 | // device_start - device-specific startup | |
| 1058 | //------------------------------------------------- | |
| 1059 | ||
| 1060 | void mc6854_device::device_start() | |
| 1061 | { | |
| 1062 | DEVICE_START_NAME( mc6854 )(this); | |
| 1063 | } | |
| 1064 | ||
| 1065 | //------------------------------------------------- | |
| 1066 | // device_reset - device-specific reset | |
| 1067 | //------------------------------------------------- | |
| 1068 | ||
| 1069 | void mc6854_device::device_reset() | |
| 1070 | { | |
| 1071 | DEVICE_RESET_NAME( mc6854 )(this); | |
| 1072 | } |
| r21684 | r21685 | |
|---|---|---|
| 1 | /********************************************************************** | |
| 2 | ||
| 3 | Copyright (C) Antoine Mine' 2006 | |
| 4 | ||
| 5 | Motorola 6854 emulation (network interface). | |
| 6 | ||
| 7 | **********************************************************************/ | |
| 8 | ||
| 9 | #ifndef MC6854_H | |
| 10 | #define MC6854_H | |
| 11 | ||
| 12 | class mc6854_device : public device_t | |
| 13 | { | |
| 14 | public: | |
| 15 | mc6854_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); | |
| 16 | ~mc6854_device() { global_free(m_token); } | |
| 17 | ||
| 18 | // access to legacy token | |
| 19 | void *token() const { assert(m_token != NULL); return m_token; } | |
| 20 | protected: | |
| 21 | // device-level overrides | |
| 22 | virtual void device_config_complete(); | |
| 23 | virtual void device_start(); | |
| 24 | virtual void device_reset(); | |
| 25 | private: | |
| 26 | // internal state | |
| 27 | void *m_token; | |
| 28 | }; | |
| 29 | ||
| 30 | extern const device_type MC6854; | |
| 31 | ||
| 32 | ||
| 33 | /* we provide two interfaces: | |
| 34 | - a bit-based interface: out_tx, set_rx | |
| 35 | - a frame-based interface: out_frame, send_frame | |
| 36 | ||
| 37 | The bit-based interface is low-level and slow. | |
| 38 | Use it to simulate the actual bits sent into the wires, e.g., to connect | |
| 39 | the emulator to another bit-based emulated network device, or an actual | |
| 40 | device. | |
| 41 | ||
| 42 | The frame-based interface is higher-level and faster. | |
| 43 | It passes bytes directly from one end to the other without bothering with | |
| 44 | the actual bit-encoding, synchronization, and CRC. | |
| 45 | Once completed, a frame is sent through out_frame. Aborted frames are not | |
| 46 | transmitted at all. No start flag, stop flag, or crc bits are trasmitted. | |
| 47 | send_frame makes a frame available to the CPU through the 6854 (it may | |
| 48 | fail and return -1 if the 6854 is not ready to accept the frame; even | |
| 49 | if the frame is accepted and 0 is returned, the CPU may abort it). Ony | |
| 50 | full frames are accepted. | |
| 51 | */ | |
| 52 | ||
| 53 | ||
| 54 | /* ---------- configuration ------------ */ | |
| 55 | ||
| 56 | struct mc6854_interface | |
| 57 | { | |
| 58 | devcb_write_line out_irq_func; /* interrupt request */ | |
| 59 | ||
| 60 | /* low-level, bit-based interface */ | |
| 61 | devcb_read_line in_rxd_func; /* receive bit */ | |
| 62 | devcb_write_line out_txd_func; /* transmit bit */ | |
| 63 | ||
| 64 | /* high-level, frame-based interface */ | |
| 65 | void ( * out_frame ) ( device_t *device, UINT8* data, int length ); | |
| 66 | ||
| 67 | /* control lines */ | |
| 68 | devcb_write_line out_rts_func; /* 1 = transmitting, 0 = idle */ | |
| 69 | devcb_write_line out_dtr_func; /* 1 = data transmit ready, 0 = busy */ | |
| 70 | }; | |
| 71 | ||
| 72 | ||
| 73 | #define MCFG_MC6854_ADD(_tag, _intrf) \ | |
| 74 | MCFG_DEVICE_ADD(_tag, MC6854, 0) \ | |
| 75 | MCFG_DEVICE_CONFIG(_intrf) | |
| 76 | ||
| 77 | #define MCFG_MC6854_REMOVE(_tag) \ | |
| 78 | MCFG_DEVICE_REMOVE(_tag) | |
| 79 | ||
| 80 | ||
| 81 | /* ---------- functions ------------ */ | |
| 82 | /* interface to CPU via address/data bus*/ | |
| 83 | extern DECLARE_READ8_DEVICE_HANDLER ( mc6854_r ); | |
| 84 | extern DECLARE_WRITE8_DEVICE_HANDLER ( mc6854_w ); | |
| 85 | ||
| 86 | /* low-level, bit-based interface */ | |
| 87 | WRITE_LINE_DEVICE_HANDLER( mc6854_set_rx ); | |
| 88 | ||
| 89 | /* high-level, frame-based interface */ | |
| 90 | extern int mc6854_send_frame( device_t *device, UINT8* data, int length ); /* ret -1 if busy */ | |
| 91 | ||
| 92 | /* control lines */ | |
| 93 | WRITE_LINE_DEVICE_HANDLER( mc6854_set_cts ); /* 1 = clear-to-send, 0 = busy */ | |
| 94 | WRITE_LINE_DEVICE_HANDLER( mc6854_set_dcd ); /* 1 = carrier, 0 = no carrier */ | |
| 95 | ||
| 96 | /* clock */ | |
| 97 | WRITE_LINE_DEVICE_HANDLER( mc6854_rxc_w ); | |
| 98 | WRITE_LINE_DEVICE_HANDLER( mc6854_txc_w ); | |
| 99 | ||
| 100 | #endif |
| r21684 | r21685 | |
|---|---|---|
| 1 | /********************************************************************** | |
| 2 | ||
| 3 | Copyright (C) Antoine Mine' 2006 | |
| 4 | ||
| 5 | Motorola 6846 emulation. | |
| 6 | ||
| 7 | The MC6846 chip provides ROM (2048 bytes), I/O (8-bit directional data port + | |
| 8 | 2 control lines) and a programmable timer. | |
| 9 | It may be interfaced with a M6809 cpu. | |
| 10 | It is used in some Thomson computers. | |
| 11 | ||
| 12 | Not yet implemented: | |
| 13 | - external clock (CTC) | |
| 14 | - latching of port on CP1 | |
| 15 | - gate input (CTG) | |
| 16 | - timer comparison modes (frequency and pulse width) | |
| 17 | - CP2 acknowledge modes | |
| 18 | ||
| 19 | **********************************************************************/ | |
| 20 | ||
| 21 | #include "emu.h" | |
| 22 | #include "mc6846.h" | |
| 23 | ||
| 24 | #define VERBOSE 0 | |
| 25 | ||
| 26 | ||
| 27 | ||
| 28 | /******************* internal chip data structure ******************/ | |
| 29 | ||
| 30 | ||
| 31 | struct mc6846_t | |
| 32 | { | |
| 33 | const mc6846_interface* iface; | |
| 34 | ||
| 35 | /* registers */ | |
| 36 | UINT8 csr; /* 0,4: combination status register */ | |
| 37 | UINT8 pcr; /* 1: peripheral control register */ | |
| 38 | UINT8 ddr; /* 2: data direction register */ | |
| 39 | UINT8 pdr; /* 3: peripheral data register (last cpu write) */ | |
| 40 | UINT8 tcr; /* 5: timer control register */ | |
| 41 | ||
| 42 | /* lines */ | |
| 43 | UINT8 cp1; /* 1-bit input */ | |
| 44 | UINT8 cp2; /* 1-bit input/output: last external write */ | |
| 45 | UINT8 cp2_cpu; /* last cpu write */ | |
| 46 | UINT8 cto; /* 1-bit timer output (unmasked) */ | |
| 47 | ||
| 48 | /* internal state */ | |
| 49 | UINT8 time_MSB; /* MSB buffer register */ | |
| 50 | UINT8 csr0_to_be_cleared; | |
| 51 | UINT8 csr1_to_be_cleared; | |
| 52 | UINT8 csr2_to_be_cleared; | |
| 53 | UINT16 latch; /* timer latch */ | |
| 54 | UINT16 preset; /* preset value */ | |
| 55 | UINT8 timer_started; | |
| 56 | ||
| 57 | /* timers */ | |
| 58 | emu_timer *interval; /* interval programmable timer */ | |
| 59 | emu_timer *one_shot; /* 1-us x factor one-shot timer */ | |
| 60 | ||
| 61 | /* CPU write to the outside through chip */ | |
| 62 | devcb_resolved_write8 out_port; /* 8-bit output */ | |
| 63 | devcb_resolved_write8 out_cp1; /* 1-bit output */ | |
| 64 | devcb_resolved_write8 out_cp2; /* 1-bit output */ | |
| 65 | ||
| 66 | /* CPU read from the outside through chip */ | |
| 67 | devcb_resolved_read8 in_port; /* 8-bit input */ | |
| 68 | ||
| 69 | /* asynchronous timer output to outside world */ | |
| 70 | devcb_resolved_write8 out_cto; /* 1-bit output */ | |
| 71 | ||
| 72 | /* timer interrupt */ | |
| 73 | devcb_resolved_write_line irq; | |
| 74 | ||
| 75 | int old_cif; | |
| 76 | int old_cto; | |
| 77 | }; | |
| 78 | ||
| 79 | ||
| 80 | ||
| 81 | /******************* utility function and macros ********************/ | |
| 82 | ||
| 83 | #define LOG(x) do { if (VERBOSE) logerror x; } while (0) | |
| 84 | ||
| 85 | #define PORT \ | |
| 86 | ((mc6846->pdr & mc6846->ddr) | \ | |
| 87 | ((!mc6846->in_port.isnull() ? mc6846->in_port( 0 ) : 0) & \ | |
| 88 | ~mc6846->ddr)) | |
| 89 | ||
| 90 | #define CTO \ | |
| 91 | ((MODE == 0x30 || (mc6846->tcr & 0x80)) ? mc6846->cto : 0) | |
| 92 | ||
| 93 | #define MODE (mc6846->tcr & 0x38) | |
| 94 | ||
| 95 | #define FACTOR ((mc6846->tcr & 4) ? 8 : 1) | |
| 96 | ||
| 97 | ||
| 98 | ||
| 99 | INLINE mc6846_t* get_safe_token( device_t *device ) | |
| 100 | { | |
| 101 | assert( device != NULL ); | |
| 102 | assert( device->type() == MC6846 ); | |
| 103 | return (mc6846_t*) downcast<mc6846_device *>(device)->token(); | |
| 104 | } | |
| 105 | ||
| 106 | ||
| 107 | INLINE UINT16 mc6846_counter( device_t *device ) | |
| 108 | { | |
| 109 | mc6846_t* mc6846 = get_safe_token( device ); | |
| 110 | if ( mc6846->timer_started ) | |
| 111 | { | |
| 112 | attotime delay = mc6846->interval ->remaining( ); | |
| 113 | return delay.as_ticks(1000000) / FACTOR; | |
| 114 | } | |
| 115 | else | |
| 116 | return mc6846->preset; | |
| 117 | } | |
| 118 | ||
| 119 | ||
| 120 | ||
| 121 | INLINE void mc6846_update_irq( device_t *device ) | |
| 122 | { | |
| 123 | mc6846_t* mc6846 = get_safe_token( device ); | |
| 124 | int cif = 0; | |
| 125 | /* composite interrupt flag */ | |
| 126 | if ( ( (mc6846->csr & 1) && (mc6846->tcr & 0x40) ) || | |
| 127 | ( (mc6846->csr & 2) && (mc6846->pcr & 1) ) || | |
| 128 | ( (mc6846->csr & 4) && (mc6846->pcr & 8) && ! (mc6846->pcr & 0x20) ) ) | |
| 129 | cif = 1; | |
| 130 | if ( mc6846->old_cif != cif ) | |
| 131 | { | |
| 132 | LOG (( "%f: mc6846 interrupt %i (time=%i cp1=%i cp2=%i)\n", | |
| 133 | device->machine().time().as_double(), cif, | |
| 134 | mc6846->csr & 1, (mc6846->csr >> 1 ) & 1, (mc6846->csr >> 2 ) & 1 )); | |
| 135 | mc6846->old_cif = cif; | |
| 136 | } | |
| 137 | if ( cif ) | |
| 138 | { | |
| 139 | mc6846->csr |= 0x80; | |
| 140 | if ( !mc6846->irq.isnull() ) | |
| 141 | mc6846->irq( 1 ); | |
| 142 | } | |
| 143 | else | |
| 144 | { | |
| 145 | mc6846->csr &= ~0x80; | |
| 146 | if ( !mc6846->irq.isnull() ) | |
| 147 | mc6846->irq( 0 ); | |
| 148 | } | |
| 149 | } | |
| 150 | ||
| 151 | ||
| 152 | ||
| 153 | INLINE void mc6846_update_cto ( device_t *device ) | |
| 154 | { | |
| 155 | mc6846_t* mc6846 = get_safe_token( device ); | |
| 156 | int cto = CTO; | |
| 157 | if ( cto != mc6846->old_cto ) | |
| 158 | { | |
| 159 | LOG (( "%f: mc6846 CTO set to %i\n", device->machine().time().as_double(), cto )); | |
| 160 | mc6846->old_cto = cto; | |
| 161 | } | |
| 162 | if ( !mc6846->out_cto.isnull() ) | |
| 163 | mc6846->out_cto( 0, cto ); | |
| 164 | } | |
| 165 | ||
| 166 | ||
| 167 | ||
| 168 | INLINE void mc6846_timer_launch ( device_t *device ) | |
| 169 | { | |
| 170 | mc6846_t* mc6846 = get_safe_token( device ); | |
| 171 | int delay = FACTOR * (mc6846->preset+1); | |
| 172 | LOG (( "%f: mc6846 timer launch called, mode=%i, preset=%i (x%i)\n", device->machine().time().as_double(), MODE, mc6846->preset, FACTOR )); | |
| 173 | ||
| 174 | if ( ! (mc6846->tcr & 2) ) | |
| 175 | { | |
| 176 | logerror( "mc6846 external clock CTC not implemented\n" ); | |
| 177 | } | |
| 178 | ||
| 179 | switch( MODE ) | |
| 180 | { | |
| 181 | case 0x00: | |
| 182 | case 0x10: /* continuous */ | |
| 183 | mc6846->cto = 0; | |
| 184 | break; | |
| 185 | ||
| 186 | case 0x20: /* single-shot */ | |
| 187 | mc6846->cto = 0; | |
| 188 | mc6846->one_shot->reset( attotime::from_usec(FACTOR) ); | |
| 189 | break; | |
| 190 | ||
| 191 | case 0x30: /* cascaded single-shot */ | |
| 192 | break; | |
| 193 | ||
| 194 | default: | |
| 195 | logerror( "mc6846 timer mode %i not implemented\n", MODE ); | |
| 196 | mc6846->interval->reset( ); | |
| 197 | mc6846->timer_started = 0; | |
| 198 | return; | |
| 199 | } | |
| 200 | ||
| 201 | mc6846->interval->reset( attotime::from_usec(delay) ); | |
| 202 | mc6846->timer_started = 1; | |
| 203 | ||
| 204 | mc6846->csr &= ~1; | |
| 205 | mc6846_update_cto( device ); | |
| 206 | mc6846_update_irq( device ); | |
| 207 | } | |
| 208 | ||
| 209 | ||
| 210 | ||
| 211 | /******************* timer callbacks *********************************/ | |
| 212 | ||
| 213 | static TIMER_CALLBACK( mc6846_timer_expire ) | |
| 214 | { | |
| 215 | device_t* device = (device_t*) ptr; | |
| 216 | mc6846_t* mc6846 = get_safe_token( device ); | |
| 217 | int delay = FACTOR * (mc6846->latch+1); | |
| 218 | ||
| 219 | LOG (( "%f: mc6846 timer expire called, mode=%i, latch=%i (x%i)\n", device->machine().time().as_double(), MODE, mc6846->latch, FACTOR )); | |
| 220 | ||
| 221 | /* latch => counter */ | |
| 222 | mc6846->preset = mc6846->latch; | |
| 223 | ||
| 224 | if ( ! (mc6846->tcr & 2) ) | |
| 225 | logerror( "mc6846 external clock CTC not implemented\n" ); | |
| 226 | ||
| 227 | switch ( MODE ) | |
| 228 | { | |
| 229 | case 0x00: | |
| 230 | case 0x10: /* continuous */ | |
| 231 | mc6846->cto = 1 ^ mc6846->cto; | |
| 232 | break; | |
| 233 | ||
| 234 | case 0x20: /* single-shot */ | |
| 235 | mc6846->cto = 0; | |
| 236 | break; | |
| 237 | ||
| 238 | case 0x30: /* cascaded single-shot */ | |
| 239 | mc6846->cto = ( mc6846->tcr & 0x80 ) ? 1 : 0; | |
| 240 | break; | |
| 241 | ||
| 242 | default: | |
| 243 | logerror( "mc6846 timer mode %i not implemented\n", MODE ); | |
| 244 | mc6846->interval->reset( ); | |
| 245 | mc6846->timer_started = 0; | |
| 246 | return; | |
| 247 | } | |
| 248 | ||
| 249 | mc6846->interval->reset( attotime::from_usec(delay) ); | |
| 250 | ||
| 251 | mc6846->csr |= 1; | |
| 252 | mc6846_update_cto( device ); | |
| 253 | mc6846_update_irq( device ); | |
| 254 | } | |
| 255 | ||
| 256 | ||
| 257 | ||
| 258 | static TIMER_CALLBACK( mc6846_timer_one_shot ) | |
| 259 | { | |
| 260 | device_t* device = (device_t*) ptr; | |
| 261 | mc6846_t* mc6846 = get_safe_token( device ); | |
| 262 | LOG (( "%f: mc6846 timer one shot called\n", device->machine().time().as_double() )); | |
| 263 | ||
| 264 | /* 1 micro second after one-shot launch, we put cto to high */ | |
| 265 | mc6846->cto = 1; | |
| 266 | mc6846_update_cto( device ); | |
| 267 | } | |
| 268 | ||
| 269 | ||
| 270 | ||
| 271 | /************************** CPU interface ****************************/ | |
| 272 | ||
| 273 | ||
| 274 | READ8_DEVICE_HANDLER ( mc6846_r ) | |
| 275 | { | |
| 276 | mc6846_t* mc6846 = get_safe_token( device ); | |
| 277 | switch ( offset ) | |
| 278 | { | |
| 279 | case 0: | |
| 280 | case 4: | |
| 281 | LOG (( "$%04x %f: mc6846 CSR read $%02X intr=%i (timer=%i, cp1=%i, cp2=%i)\n", | |
| 282 | space.machine().firstcpu->pcbase( ), space.machine().time().as_double(), | |
| 283 | mc6846->csr, (mc6846->csr >> 7) & 1, | |
| 284 | mc6846->csr & 1, (mc6846->csr >> 1) & 1, (mc6846->csr >> 2) & 1 )); | |
| 285 | mc6846->csr0_to_be_cleared = mc6846->csr & 1; | |
| 286 | mc6846->csr1_to_be_cleared = mc6846->csr & 2; | |
| 287 | mc6846->csr2_to_be_cleared = mc6846->csr & 4; | |
| 288 | return mc6846->csr; | |
| 289 | ||
| 290 | case 1: | |
| 291 | LOG (( "$%04x %f: mc6846 PCR read $%02X\n", space.machine().firstcpu->pcbase( ), space.machine().time().as_double(), mc6846->pcr )); | |
| 292 | return mc6846->pcr; | |
| 293 | ||
| 294 | case 2: | |
| 295 | LOG (( "$%04x %f: mc6846 DDR read $%02X\n", space.machine().firstcpu->pcbase( ), space.machine().time().as_double(), mc6846->ddr )); | |
| 296 | return mc6846->ddr; | |
| 297 | ||
| 298 | case 3: | |
| 299 | LOG (( "$%04x %f: mc6846 PORT read $%02X\n", space.machine().firstcpu->pcbase( ), space.machine().time().as_double(), PORT )); | |
| 300 | if ( ! (mc6846->pcr & 0x80) ) | |
| 301 | { | |
| 302 | if ( mc6846->csr1_to_be_cleared ) | |
| 303 | mc6846->csr &= ~2; | |
| 304 | if ( mc6846->csr2_to_be_cleared ) | |
| 305 | mc6846->csr &= ~4; | |
| 306 | mc6846_update_irq( device ); | |
| 307 | mc6846->csr1_to_be_cleared = 0; | |
| 308 | mc6846->csr2_to_be_cleared = 0; | |
| 309 | } | |
| 310 | return PORT; | |
| 311 | ||
| 312 | case 5: | |
| 313 | LOG (( "$%04x %f: mc6846 TCR read $%02X\n",space.machine().firstcpu->pcbase( ), space.machine().time().as_double(), mc6846->tcr )); | |
| 314 | return mc6846->tcr; | |
| 315 | ||
| 316 | case 6: | |
| 317 | LOG (( "$%04x %f: mc6846 COUNTER hi read $%02X\n", space.machine().firstcpu->pcbase( ), space.machine().time().as_double(), mc6846_counter( device ) >> 8 )); | |
| 318 | if ( mc6846->csr0_to_be_cleared ) | |
| 319 | { | |
| 320 | mc6846->csr &= ~1; | |
| 321 | mc6846_update_irq( device ); | |
| 322 | } | |
| 323 | mc6846->csr0_to_be_cleared = 0; | |
| 324 | return mc6846_counter( device ) >> 8; | |
| 325 | ||
| 326 | case 7: | |
| 327 | LOG (( "$%04x %f: mc6846 COUNTER low read $%02X\n", space.machine().firstcpu->pcbase( ), space.machine().time().as_double(), mc6846_counter( device ) & 0xff )); | |
| 328 | if ( mc6846->csr0_to_be_cleared ) | |
| 329 | { | |
| 330 | mc6846->csr &= ~1; | |
| 331 | mc6846_update_irq( device ); | |
| 332 | } | |
| 333 | mc6846->csr0_to_be_cleared = 0; | |
| 334 | return mc6846_counter( device ) & 0xff; | |
| 335 | ||
| 336 | default: | |
| 337 | logerror( "$%04x mc6846 invalid read offset %i\n", space.machine().firstcpu->pcbase( ), offset ); | |
| 338 | } | |
| 339 | return 0; | |
| 340 | } | |
| 341 | ||
| 342 | ||
| 343 | ||
| 344 | WRITE8_DEVICE_HANDLER ( mc6846_w ) | |
| 345 | { | |
| 346 | mc6846_t* mc6846 = get_safe_token( device ); | |
| 347 | switch ( offset ) | |
| 348 | { | |
| 349 | case 0: | |
| 350 | case 4: | |
| 351 | /* CSR is read-only */ | |
| 352 | break; | |
| 353 | ||
| 354 | case 1: | |
| 355 | { | |
| 356 | static const char *const cp2[8] = | |
| 357 | { | |
| 358 | "in,neg-edge", "in,neg-edge,intr", "in,pos-edge", "in,pos-edge,intr", | |
| 359 | "out,intr-ack", "out,i/o-ack", "out,0", "out,1" | |
| 360 | }; | |
| 361 | static const char *const cp1[8] = | |
| 362 | { | |
| 363 | "neg-edge", "neg-edge,intr", "pos-edge", "pos-edge,intr", | |
| 364 | "latched,neg-edge", "latched,neg-edge,intr", | |
| 365 | "latcged,pos-edge", "latcged,pos-edge,intr" | |
| 366 | }; | |
| 367 | LOG (( "$%04x %f: mc6846 PCR write $%02X reset=%i cp2=%s cp1=%s\n", | |
| 368 | space.machine().firstcpu->pcbase( ), space.machine().time().as_double(), data, | |
| 369 | (data >> 7) & 1, cp2[ (data >> 3) & 7 ], cp1[ data & 7 ] )); | |
| 370 | ||
| 371 | } | |
| 372 | mc6846->pcr = data; | |
| 373 | if ( data & 0x80 ) | |
| 374 | { /* data reset */ | |
| 375 | mc6846->pdr = 0; | |
| 376 | mc6846->ddr = 0; | |
| 377 | mc6846->csr &= ~6; | |
| 378 | mc6846_update_irq( device ); | |
| 379 | } | |
| 380 | if ( data & 4 ) | |
| 381 | logerror( "$%04x mc6846 CP1 latching not implemented\n", space.machine().firstcpu->pcbase( ) ); | |
| 382 | if (data & 0x20) | |
| 383 | { | |
| 384 | if (data & 0x10) | |
| 385 | { | |
| 386 | mc6846->cp2_cpu = (data >> 3) & 1; | |
| 387 | if ( !mc6846->out_cp2.isnull() ) | |
| 388 | mc6846->out_cp2( 0, mc6846->cp2_cpu ); | |
| 389 | } | |
| 390 | else | |
| 391 | logerror( "$%04x mc6846 acknowledge not implemented\n", space.machine().firstcpu->pcbase( ) ); | |
| 392 | } | |
| 393 | break; | |
| 394 | ||
| 395 | case 2: | |
| 396 | LOG (( "$%04x %f: mc6846 DDR write $%02X\n", space.machine().firstcpu->pcbase( ), space.machine().time().as_double(), data )); | |
| 397 | if ( ! (mc6846->pcr & 0x80) ) | |
| 398 | { | |
| 399 | mc6846->ddr = data; | |
| 400 | if ( !mc6846->out_port.isnull() ) | |
| 401 | mc6846->out_port( 0, mc6846->pdr & mc6846->ddr ); | |
| 402 | } | |
| 403 | break; | |
| 404 | ||
| 405 | case 3: | |
| 406 | LOG (( "$%04x %f: mc6846 PORT write $%02X (mask=$%02X)\n", space.machine().firstcpu->pcbase( ), space.machine().time().as_double(), data,mc6846->ddr )); | |
| 407 | if ( ! (mc6846->pcr & 0x80) ) | |
| 408 | { | |
| 409 | mc6846->pdr = data; | |
| 410 | if ( !mc6846->out_port.isnull() ) | |
| 411 | mc6846->out_port( 0, mc6846->pdr & mc6846->ddr ); | |
| 412 | if ( mc6846->csr1_to_be_cleared && (mc6846->csr & 2) ) | |
| 413 | { | |
| 414 | mc6846->csr &= ~2; | |
| 415 | LOG (( "$%04x %f: mc6846 CP1 intr reset\n", space.machine().firstcpu->pcbase( ), space.machine().time().as_double() )); | |
| 416 | } | |
| 417 | if ( mc6846->csr2_to_be_cleared && (mc6846->csr & 4) ) | |
| 418 | { | |
| 419 | mc6846->csr &= ~4; | |
| 420 | LOG (( "$%04x %f: mc6846 CP2 intr reset\n", space.machine().firstcpu->pcbase( ), space.machine().time().as_double() )); | |
| 421 | } | |
| 422 | mc6846->csr1_to_be_cleared = 0; | |
| 423 | mc6846->csr2_to_be_cleared = 0; | |
| 424 | mc6846_update_irq( device ); | |
| 425 | } | |
| 426 | break; | |
| 427 | ||
| 428 | case 5: | |
| 429 | { | |
| 430 | static const char *const mode[8] = | |
| 431 | { | |
| 432 | "continuous", "cascaded", "continuous", "one-shot", | |
| 433 | "freq-cmp", "freq-cmp", "pulse-cmp", "pulse-cmp" | |
| 434 | }; | |
| 435 | LOG (( "$%04x %f: mc6846 TCR write $%02X reset=%i clock=%s scale=%i mode=%s out=%s\n", | |
| 436 | space.machine().firstcpu->pcbase( ), space.machine().time().as_double(), data, | |
| 437 | (data >> 7) & 1, (data & 0x40) ? "extern" : "sys", | |
| 438 | (data & 0x40) ? 1 : 8, mode[ (data >> 1) & 7 ], | |
| 439 | (data & 1) ? "enabled" : "0" )); | |
| 440 | ||
| 441 | mc6846->tcr = data; | |
| 442 | if ( mc6846->tcr & 1 ) | |
| 443 | { | |
| 444 | /* timer preset = initialization without launch */ | |
| 445 | mc6846->preset = mc6846->latch; | |
| 446 | mc6846->csr &= ~1; | |
| 447 | if ( MODE != 0x30 ) | |
| 448 | mc6846->cto = 0; | |
| 449 | mc6846_update_cto( device ); | |
| 450 | mc6846->interval->reset( ); | |
| 451 | mc6846->one_shot->reset( ); | |
| 452 | mc6846->timer_started = 0; | |
| 453 | } | |
| 454 | else | |
| 455 | { | |
| 456 | /* timer launch */ | |
| 457 | if ( ! mc6846->timer_started ) | |
| 458 | mc6846_timer_launch( device ); | |
| 459 | } | |
| 460 | mc6846_update_irq( device ); | |
| 461 | } | |
| 462 | break; | |
| 463 | ||
| 464 | case 6: | |
| 465 | mc6846->time_MSB = data; | |
| 466 | break; | |
| 467 | ||
| 468 | case 7: | |
| 469 | mc6846->latch = ( ((UINT16) mc6846->time_MSB) << 8 ) + data; | |
| 470 | LOG (( "$%04x %f: mc6846 COUNT write %i\n", space.machine().firstcpu->pcbase( ), space.machine().time().as_double(), mc6846->latch )); | |
| 471 | if (!(mc6846->tcr & 0x38)) | |
| 472 | { | |
| 473 | /* timer initialization */ | |
| 474 | mc6846->preset = mc6846->latch; | |
| 475 | mc6846->csr &= ~1; | |
| 476 | mc6846_update_irq( device ); | |
| 477 | mc6846->cto = 0; | |
| 478 | mc6846_update_cto( device ); | |
| 479 | /* launch only if started */ | |
| 480 | if (!(mc6846->tcr & 1)) | |
| 481 | mc6846_timer_launch( device ); | |
| 482 | } | |
| 483 | break; | |
| 484 | ||
| 485 | default: | |
| 486 | logerror( "$%04x mc6846 invalid write offset %i\n", space.machine().firstcpu->pcbase( ), offset ); | |
| 487 | } | |
| 488 | } | |
| 489 | ||
| 490 | ||
| 491 | ||
| 492 | /******************** outside world interface ************************/ | |
| 493 | ||
| 494 | ||
| 495 | ||
| 496 | void mc6846_set_input_cp1 ( device_t *device, int data ) | |
| 497 | { | |
| 498 | mc6846_t* mc6846 = get_safe_token( device ); | |
| 499 | data = (data != 0 ); | |
| 500 | if ( data == mc6846->cp1 ) | |
| 501 | return; | |
| 502 | mc6846->cp1 = data; | |
| 503 | LOG (( "%f: mc6846 input CP1 set to %i\n", device->machine().time().as_double(), data )); | |
| 504 | if (( data && (mc6846->pcr & 2)) || (!data && !(mc6846->pcr & 2))) | |
| 505 | { | |
| 506 | mc6846->csr |= 2; | |
| 507 | mc6846_update_irq( device ); | |
| 508 | } | |
| 509 | } | |
| 510 | ||
| 511 | void mc6846_set_input_cp2 ( device_t *device, int data ) | |
| 512 | { | |
| 513 | mc6846_t* mc6846 = get_safe_token( device ); | |
| 514 | data = (data != 0 ); | |
| 515 | if ( data == mc6846->cp2 ) | |
| 516 | return; | |
| 517 | mc6846->cp2 = data; | |
| 518 | LOG (( "%f: mc6846 input CP2 set to %i\n", device->machine().time().as_double(), data )); | |
| 519 | if (mc6846->pcr & 0x20) | |
| 520 | { | |
| 521 | if (( data && (mc6846->pcr & 0x10)) || (!data && !(mc6846->pcr & 0x10))) | |
| 522 | { | |
| 523 | mc6846->csr |= 4; | |
| 524 | mc6846_update_irq( device ); | |
| 525 | } | |
| 526 | } | |
| 527 | } | |
| 528 | ||
| 529 | ||
| 530 | ||
| 531 | /************************ accessors **********************************/ | |
| 532 | ||
| 533 | ||
| 534 | ||
| 535 | UINT8 mc6846_get_output_port ( device_t *device ) | |
| 536 | { | |
| 537 | mc6846_t* mc6846 = get_safe_token( device ); | |
| 538 | return PORT; | |
| 539 | } | |
| 540 | ||
| 541 | ||
| 542 | ||
| 543 | UINT8 mc6846_get_output_cto ( device_t *device ) | |
| 544 | { | |
| 545 | mc6846_t* mc6846 = get_safe_token( device ); | |
| 546 | return CTO; | |
| 547 | } | |
| 548 | ||
| 549 | ||
| 550 | ||
| 551 | UINT8 mc6846_get_output_cp2 ( device_t *device ) | |
| 552 | { | |
| 553 | mc6846_t* mc6846 = get_safe_token( device ); | |
| 554 | return mc6846->cp2_cpu; | |
| 555 | } | |
| 556 | ||
| 557 | ||
| 558 | ||
| 559 | UINT16 mc6846_get_preset ( device_t *device ) | |
| 560 | { | |
| 561 | mc6846_t* mc6846 = get_safe_token( device ); | |
| 562 | return mc6846->preset; | |
| 563 | } | |
| 564 | ||
| 565 | ||
| 566 | ||
| 567 | /************************ reset *****************************/ | |
| 568 | ||
| 569 | ||
| 570 | static DEVICE_RESET( mc6846 ) | |
| 571 | { | |
| 572 | mc6846_t* mc6846 = get_safe_token( device ); | |
| 573 | LOG (( "mc6846_reset\n" )); | |
| 574 | mc6846->cto = 0; | |
| 575 | mc6846->csr = 0; | |
| 576 | mc6846->pcr = 0x80; | |
| 577 | mc6846->ddr = 0; | |
| 578 | mc6846->pdr = 0; | |
| 579 | mc6846->tcr = 1; | |
| 580 | mc6846->cp1 = 0; | |
| 581 | mc6846->cp2 = 0; | |
| 582 | mc6846->cp2_cpu = 0; | |
| 583 | mc6846->latch = 0xffff; | |
| 584 | mc6846->preset = 0xffff; | |
| 585 | mc6846->time_MSB = 0; | |
| 586 | mc6846->csr0_to_be_cleared = 0; | |
| 587 | mc6846->csr1_to_be_cleared = 0; | |
| 588 | mc6846->csr2_to_be_cleared = 0; | |
| 589 | mc6846->timer_started = 0; | |
| 590 | mc6846->interval->reset( ); | |
| 591 | mc6846->one_shot->reset( ); | |
| 592 | } | |
| 593 | ||
| 594 | ||
| 595 | /************************ start *****************************/ | |
| 596 | ||
| 597 | static DEVICE_START( mc6846 ) | |
| 598 | { | |
| 599 | mc6846_t* mc6846 = get_safe_token( device ); | |
| 600 | ||
| 601 | mc6846->iface = (const mc6846_interface*)device->static_config(); | |
| 602 | mc6846->interval = device->machine().scheduler().timer_alloc(FUNC(mc6846_timer_expire), (void*) device ); | |
| 603 | mc6846->one_shot = device->machine().scheduler().timer_alloc(FUNC(mc6846_timer_one_shot), (void*) device ); | |
| 604 | ||
| 605 | mc6846->out_port.resolve(mc6846->iface->out_port_func, *device); /* 8-bit output */ | |
| 606 | mc6846->out_cp1.resolve(mc6846->iface->out_cp1_func, *device); /* 1-bit output */ | |
| 607 | mc6846->out_cp2.resolve(mc6846->iface->out_cp2_func, *device); /* 1-bit output */ | |
| 608 | ||
| 609 | /* CPU read from the outside through chip */ | |
| 610 | mc6846->in_port.resolve(mc6846->iface->in_port_func, *device); /* 8-bit input */ | |
| 611 | ||
| 612 | /* asynchronous timer output to outside world */ | |
| 613 | mc6846->out_cto.resolve(mc6846->iface->out_cto_func, *device); /* 1-bit output */ | |
| 614 | ||
| 615 | /* timer interrupt */ | |
| 616 | mc6846->irq.resolve(mc6846->iface->irq_func, *device); | |
| 617 | ||
| 618 | state_save_register_item( device->machine(), "mc6846", device->tag(), 0, mc6846->csr ); | |
| 619 | state_save_register_item( device->machine(), "mc6846", device->tag(), 0, mc6846->pcr ); | |
| 620 | state_save_register_item( device->machine(), "mc6846", device->tag(), 0, mc6846->ddr ); | |
| 621 | state_save_register_item( device->machine(), "mc6846", device->tag(), 0, mc6846->pdr ); | |
| 622 | state_save_register_item( device->machine(), "mc6846", device->tag(), 0, mc6846->tcr ); | |
| 623 | state_save_register_item( device->machine(), "mc6846", device->tag(), 0, mc6846->cp1 ); | |
| 624 | state_save_register_item( device->machine(), "mc6846", device->tag(), 0, mc6846->cp2 ); | |
| 625 | state_save_register_item( device->machine(), "mc6846", device->tag(), 0, mc6846->cp2_cpu ); | |
| 626 | state_save_register_item( device->machine(), "mc6846", device->tag(), 0, mc6846->cto ); | |
| 627 | state_save_register_item( device->machine(), "mc6846", device->tag(), 0, mc6846->time_MSB ); | |
| 628 | state_save_register_item( device->machine(), "mc6846", device->tag(), 0, mc6846->csr0_to_be_cleared ); | |
| 629 | state_save_register_item( device->machine(), "mc6846", device->tag(), 0, mc6846->csr1_to_be_cleared ); | |
| 630 | state_save_register_item( device->machine(), "mc6846", device->tag(), 0, mc6846->csr2_to_be_cleared ); | |
| 631 | state_save_register_item( device->machine(), "mc6846", device->tag(), 0, mc6846->latch ); | |
| 632 | state_save_register_item( device->machine(), "mc6846", device->tag(), 0, mc6846->preset ); | |
| 633 | state_save_register_item( device->machine(), "mc6846", device->tag(), 0, mc6846->timer_started ); | |
| 634 | } | |
| 635 | ||
| 636 | ||
| 637 | const device_type MC6846 = &device_creator<mc6846_device>; | |
| 638 | ||
| 639 | mc6846_device::mc6846_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) | |
| 640 | : device_t(mconfig, MC6846, "Motorola MC6846 programmable timer", tag, owner, clock) | |
| 641 | { | |
| 642 | m_token = global_alloc_clear(mc6846_t); | |
| 643 | } | |
| 644 | ||
| 645 | //------------------------------------------------- | |
| 646 | // device_config_complete - perform any | |
| 647 | // operations now that the configuration is | |
| 648 | // complete | |
| 649 | //------------------------------------------------- | |
| 650 | ||
| 651 | void mc6846_device::device_config_complete() | |
| 652 | { | |
| 653 | } | |
| 654 | ||
| 655 | //------------------------------------------------- | |
| 656 | // device_start - device-specific startup | |
| 657 | //------------------------------------------------- | |
| 658 | ||
| 659 | void mc6846_device::device_start() | |
| 660 | { | |
| 661 | DEVICE_START_NAME( mc6846 )(this); | |
| 662 | } | |
| 663 | ||
| 664 | //------------------------------------------------- | |
| 665 | // device_reset - device-specific reset | |
| 666 | //------------------------------------------------- | |
| 667 | ||
| 668 | void mc6846_device::device_reset() | |
| 669 | { | |
| 670 | DEVICE_RESET_NAME( mc6846 )(this); | |
| 671 | } |
| r21684 | r21685 | |
|---|---|---|
| 1 | /********************************************************************** | |
| 2 | ||
| 3 | Copyright (C) Antoine Mine' 2006 | |
| 4 | ||
| 5 | Motorola 6846 timer emulation. | |
| 6 | ||
| 7 | **********************************************************************/ | |
| 8 | ||
| 9 | #ifndef MC6846_H | |
| 10 | #define MC6846_H | |
| 11 | ||
| 12 | class mc6846_device : public device_t | |
| 13 | { | |
| 14 | public: | |
| 15 | mc6846_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); | |
| 16 | ~mc6846_device() { global_free(m_token); } | |
| 17 | ||
| 18 | // access to legacy token | |
| 19 | void *token() const { assert(m_token != NULL); return m_token; } | |
| 20 | protected: | |
| 21 | // device-level overrides | |
| 22 | virtual void device_config_complete(); | |
| 23 | virtual void device_start(); | |
| 24 | virtual void device_reset(); | |
| 25 | private: | |
| 26 | // internal state | |
| 27 | void *m_token; | |
| 28 | }; | |
| 29 | ||
| 30 | extern const device_type MC6846; | |
| 31 | ||
| 32 | ||
| 33 | /* ---------- configuration ------------ */ | |
| 34 | ||
| 35 | struct mc6846_interface | |
| 36 | { | |
| 37 | /* CPU write to the outside through chip */ | |
| 38 | devcb_write8 out_port_func; /* 8-bit output */ | |
| 39 | devcb_write8 out_cp1_func; /* 1-bit output */ | |
| 40 | devcb_write8 out_cp2_func; /* 1-bit output */ | |
| 41 | ||
| 42 | /* CPU read from the outside through chip */ | |
| 43 | devcb_read8 in_port_func; /* 8-bit input */ | |
| 44 | ||
| 45 | /* asynchronous timer output to outside world */ | |
| 46 | devcb_write8 out_cto_func; /* 1-bit output */ | |
| 47 | ||
| 48 | /* timer interrupt */ | |
| 49 | devcb_write_line irq_func; | |
| 50 | }; | |
| 51 | ||
| 52 | ||
| 53 | #define MCFG_MC6846_ADD(_tag, _intrf) \ | |
| 54 | MCFG_DEVICE_ADD(_tag, MC6846, 0) \ | |
| 55 | MCFG_DEVICE_CONFIG(_intrf) | |
| 56 | ||
| 57 | #define MCFG_MC6846_MODIFY(_tag, _intrf) \ | |
| 58 | MCFG_DEVICE_MODIFY(_tag) \ | |
| 59 | MCFG_DEVICE_CONFIG(_intrf) | |
| 60 | ||
| 61 | #define MCFG_MC6846_REMOVE(_tag) \ | |
| 62 | MCFG_DEVICE_REMOVE(_tag) | |
| 63 | ||
| 64 | ||
| 65 | /* ---------- functions ------------ */ | |
| 66 | /* interface to CPU via address/data bus*/ | |
| 67 | extern DECLARE_READ8_DEVICE_HANDLER ( mc6846_r ); | |
| 68 | extern DECLARE_WRITE8_DEVICE_HANDLER ( mc6846_w ); | |
| 69 | ||
| 70 | /* asynchronous write from outside world into interrupt-generating pins */ | |
| 71 | extern void mc6846_set_input_cp1 ( device_t *device, int data ); | |
| 72 | extern void mc6846_set_input_cp2 ( device_t *device, int data ); | |
| 73 | ||
| 74 | /* polling from outside world */ | |
| 75 | extern UINT8 mc6846_get_output_port ( device_t *device ); | |
| 76 | extern UINT8 mc6846_get_output_cto ( device_t *device ); | |
| 77 | extern UINT8 mc6846_get_output_cp2 ( device_t *device ); | |
| 78 | ||
| 79 | /* partial access to internal state */ | |
| 80 | extern UINT16 mc6846_get_preset ( device_t *device ); /* timer interval - 1 in us */ | |
| 81 | ||
| 82 | #endif |
| r21684 | r21685 | |
|---|---|---|
| 1 | /********************************************************************** | |
| 2 | ||
| 3 | Western Digital WD11C00-17 PC/XT Host Interface Logic Device | |
| 4 | ||
| 5 | Copyright MESS Team. | |
| 6 | Visit http://mamedev.org for licensing and usage restrictions. | |
| 7 | ||
| 8 | **********************************************************************/ | |
| 9 | ||
| 10 | #include "machine/wd11c00_17.h" | |
| 11 | ||
| 12 | ||
| 13 | ||
| 14 | //************************************************************************** | |
| 15 | // MACROS / CONSTANTS | |
| 16 | //************************************************************************** | |
| 17 | ||
| 18 | #define LOG 1 | |
| 19 | ||
| 20 | ||
| 21 | // status register | |
| 22 | #define STATUS_IRQ 0x20 | |
| 23 | #define STATUS_DRQ 0x10 | |
| 24 | #define STATUS_BUSY 0x08 | |
| 25 | #define STATUS_C_D 0x04 | |
| 26 | #define STATUS_I_O 0x02 | |
| 27 | #define STATUS_REQ 0x01 | |
| 28 | ||
| 29 | ||
| 30 | // mask register | |
| 31 | #define MASK_IRQ 0x02 | |
| 32 | #define MASK_DMA 0x01 | |
| 33 | ||
| 34 | ||
| 35 | ||
| 36 | //************************************************************************** | |
| 37 | // DEVICE DEFINITIONS | |
| 38 | //************************************************************************** | |
| 39 | ||
| 40 | const device_type WD11C00_17 = &device_creator<wd11c00_17_device>; | |
| 41 | ||
| 42 | ||
| 43 | //------------------------------------------------- | |
| 44 | // device_config_complete - perform any | |
| 45 | // operations now that the configuration is | |
| 46 | // complete | |
| 47 | //------------------------------------------------- | |
| 48 | ||
| 49 | void wd11c00_17_device::device_config_complete() | |
| 50 | { | |
| 51 | // inherit a copy of the static data | |
| 52 | const wd11c00_17_interface *intf = reinterpret_cast<const wd11c00_17_interface *>(static_config()); | |
| 53 | if (intf != NULL) | |
| 54 | *static_cast<wd11c00_17_interface *>(this) = *intf; | |
| 55 | ||
| 56 | // or initialize to defaults if none provided | |
| 57 | else | |
| 58 | { | |
| 59 | memset(&m_out_irq5_cb, 0, sizeof(m_out_irq5_cb)); | |
| 60 | memset(&m_out_drq3_cb, 0, sizeof(m_out_drq3_cb)); | |
| 61 | memset(&m_out_mr_cb, 0, sizeof(m_out_mr_cb)); | |
| 62 | memset(&m_out_busy_cb, 0, sizeof(m_out_busy_cb)); | |
| 63 | memset(&m_out_req_cb, 0, sizeof(m_out_req_cb)); | |
| 64 | memset(&m_out_ra3_cb, 0, sizeof(m_out_ra3_cb)); | |
| 65 | memset(&m_in_rd322_cb, 0, sizeof(m_in_rd322_cb)); | |
| 66 | memset(&m_in_ramcs_cb, 0, sizeof(m_in_ramcs_cb)); | |
| 67 | memset(&m_out_ramwr_cb, 0, sizeof(m_out_ramwr_cb)); | |
| 68 | memset(&m_in_cs1010_cb, 0, sizeof(m_in_cs1010_cb)); | |
| 69 | memset(&m_out_cs1010_cb, 0, sizeof(m_out_cs1010_cb)); | |
| 70 | } | |
| 71 | } | |
| 72 | ||
| 73 | ||
| 74 | ||
| 75 | //************************************************************************** | |
| 76 | // INLINE HELPERS | |
| 77 | //************************************************************************** | |
| 78 | ||
| 79 | //------------------------------------------------- | |
| 80 | // check_interrupt - | |
| 81 | //------------------------------------------------- | |
| 82 | ||
| 83 | inline void wd11c00_17_device::check_interrupt() | |
| 84 | { | |
| 85 | if (BIT(m_ra, 10)) | |
| 86 | { | |
| 87 | m_status &= ~STATUS_DRQ; | |
| 88 | } | |
| 89 | ||
| 90 | int ra3 = BIT(m_ra, 3); | |
| 91 | ||
| 92 | if (m_ra3 != ra3) | |
| 93 | { | |
| 94 | m_out_ra3_func(ra3 ? ASSERT_LINE : CLEAR_LINE); | |
| 95 | m_ra3 = ra3; | |
| 96 | } | |
| 97 | ||
| 98 | int irq5 = ((m_status & STATUS_IRQ) && (m_mask & MASK_IRQ)) ? ASSERT_LINE : CLEAR_LINE; | |
| 99 | ||
| 100 | if (m_irq5 != irq5) | |
| 101 | { | |
| 102 | m_out_irq5_func(irq5); | |
| 103 | m_irq5 = irq5; | |
| 104 | } | |
| 105 | ||
| 106 | int drq3 = ((m_status & STATUS_DRQ) && (m_mask & MASK_DMA)) ? ASSERT_LINE : CLEAR_LINE; | |
| 107 | ||
| 108 | if (m_drq3 != drq3) | |
| 109 | { | |
| 110 | m_out_drq3_func(drq3); | |
| 111 | m_drq3 = drq3; | |
| 112 | } | |
| 113 | ||
| 114 | int busy = (m_status & STATUS_BUSY) ? 0 : 1; | |
| 115 | ||
| 116 | if (m_busy != busy) | |
| 117 | { | |
| 118 | m_out_busy_func(busy); | |
| 119 | m_busy = busy; | |
| 120 | } | |
| 121 | ||
| 122 | int req = (m_status & STATUS_REQ) ? 1 : 0; | |
| 123 | ||
| 124 | if (m_req != req) | |
| 125 | { | |
| 126 | m_out_req_func(req); | |
| 127 | m_req = req; | |
| 128 | } | |
| 129 | } | |
| 130 | ||
| 131 | ||
| 132 | //------------------------------------------------- | |
| 133 | // increment_address - | |
| 134 | //------------------------------------------------- | |
| 135 | ||
| 136 | inline void wd11c00_17_device::increment_address() | |
| 137 | { | |
| 138 | m_ra++; | |
| 139 | check_interrupt(); | |
| 140 | } | |
| 141 | ||
| 142 | ||
| 143 | //------------------------------------------------- | |
| 144 | // read_data - | |
| 145 | //------------------------------------------------- | |
| 146 | ||
| 147 | inline UINT8 wd11c00_17_device::read_data() | |
| 148 | { | |
| 149 | UINT8 data = 0; | |
| 150 | ||
| 151 | if (m_status & STATUS_BUSY) | |
| 152 | { | |
| 153 | data = m_in_ramcs_func(m_ra & 0x7ff); | |
| 154 | ||
| 155 | increment_address(); | |
| 156 | } | |
| 157 | ||
| 158 | return data; | |
| 159 | } | |
| 160 | ||
| 161 | ||
| 162 | //------------------------------------------------- | |
| 163 | // write_data - | |
| 164 | //------------------------------------------------- | |
| 165 | ||
| 166 | inline void wd11c00_17_device::write_data(UINT8 data) | |
| 167 | { | |
| 168 | if (m_status & STATUS_BUSY) | |
| 169 | { | |
| 170 | m_out_ramwr_func(m_ra & 0x7ff, data); | |
| 171 | ||
| 172 | increment_address(); | |
| 173 | } | |
| 174 | } | |
| 175 | ||
| 176 | ||
| 177 | //------------------------------------------------- | |
| 178 | // software_reset - | |
| 179 | //------------------------------------------------- | |
| 180 | ||
| 181 | inline void wd11c00_17_device::software_reset() | |
| 182 | { | |
| 183 | m_out_mr_func(ASSERT_LINE); | |
| 184 | m_out_mr_func(CLEAR_LINE); | |
| 185 | ||
| 186 | device_reset(); | |
| 187 | } | |
| 188 | ||
| 189 | ||
| 190 | //------------------------------------------------- | |
| 191 | // select - | |
| 192 | //------------------------------------------------- | |
| 193 | ||
| 194 | inline void wd11c00_17_device::select() | |
| 195 | { | |
| 196 | m_status = STATUS_BUSY | STATUS_C_D | STATUS_REQ; | |
| 197 | ||
| 198 | check_interrupt(); | |
| 199 | } | |
| 200 | ||
| 201 | ||
| 202 | ||
| 203 | //************************************************************************** | |
| 204 | // LIVE DEVICE | |
| 205 | //************************************************************************** | |
| 206 | ||
| 207 | //------------------------------------------------- | |
| 208 | // wd11c00_17_device - constructor | |
| 209 | //------------------------------------------------- | |
| 210 | ||
| 211 | wd11c00_17_device::wd11c00_17_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) | |
| 212 | : device_t(mconfig, WD11C00_17, "Western Digital WD11C00-17", tag, owner, clock), | |
| 213 | m_status(0), | |
| 214 | m_ra(0), | |
| 215 | m_irq5(CLEAR_LINE), | |
| 216 | m_drq3(CLEAR_LINE), | |
| 217 | m_busy(1), | |
| 218 | m_req(0), | |
| 219 | m_ra3(0) | |
| 220 | { | |
| 221 | } | |
| 222 | ||
| 223 | ||
| 224 | //------------------------------------------------- | |
| 225 | // device_start - device-specific startup | |
| 226 | //------------------------------------------------- | |
| 227 | ||
| 228 | void wd11c00_17_device::device_start() | |
| 229 | { | |
| 230 | // resolve callbacks | |
| 231 | m_out_irq5_func.resolve(m_out_irq5_cb, *this); | |
| 232 | m_out_drq3_func.resolve(m_out_drq3_cb, *this); | |
| 233 | m_out_mr_func.resolve(m_out_mr_cb, *this); | |
| 234 | m_out_busy_func.resolve(m_out_busy_cb, *this); | |
| 235 | m_out_req_func.resolve(m_out_req_cb, *this); | |
| 236 | m_out_ra3_func.resolve(m_out_ra3_cb, *this); | |
| 237 | m_in_rd322_func.resolve(m_in_rd322_cb, *this); | |
| 238 | m_in_ramcs_func.resolve(m_in_ramcs_cb, *this); | |
| 239 | m_out_ramwr_func.resolve(m_out_ramwr_cb, *this); | |
| 240 | m_in_cs1010_func.resolve(m_in_cs1010_cb, *this); | |
| 241 | m_out_cs1010_func.resolve(m_out_cs1010_cb, *this); | |
| 242 | } | |
| 243 | ||
| 244 | ||
| 245 | //------------------------------------------------- | |
| 246 | // device_reset - device-specific reset | |
| 247 | //------------------------------------------------- | |
| 248 | ||
| 249 | void wd11c00_17_device::device_reset() | |
| 250 | { | |
| 251 | m_status &= ~(STATUS_IRQ | STATUS_DRQ | STATUS_BUSY); | |
| 252 | m_mask = 0; | |
| 253 | m_ra = 0; | |
| 254 | ||
| 255 | check_interrupt(); | |
| 256 | } | |
| 257 | ||
| 258 | ||
| 259 | //------------------------------------------------- | |
| 260 | // io_r - | |
| 261 | //------------------------------------------------- | |
| 262 | ||
| 263 | READ8_MEMBER( wd11c00_17_device::io_r ) | |
| 264 | { | |
| 265 | UINT8 data = 0xff; | |
| 266 | ||
| 267 | switch (offset) | |
| 268 | { | |
| 269 | case 0: // Read Data, Board to Host | |
| 270 | if (LOG) logerror("%s WD11C00-17 '%s' Read Data %03x:", machine().describe_context(), tag(), m_ra); | |
| 271 | data = read_data(); | |
| 272 | if (LOG) logerror("%02x\n", data); | |
| 273 | break; | |
| 274 | ||
| 275 | case 1: // Read Board Hardware Status | |
| 276 | data = m_status; | |
| 277 | check_interrupt(); | |
| 278 | break; | |
| 279 | ||
| 280 | case 2: // Read Drive Configuration Information | |
| 281 | data = m_in_rd322_func(0); | |
| 282 | break; | |
| 283 | ||
| 284 | case 3: // Not Used | |
| 285 | break; | |
| 286 | } | |
| 287 | ||
| 288 | return data; | |
| 289 | } | |
| 290 | ||
| 291 | ||
| 292 | //------------------------------------------------- | |
| 293 | // io_w - | |
| 294 | //------------------------------------------------- | |
| 295 | ||
| 296 | WRITE8_MEMBER( wd11c00_17_device::io_w ) | |
| 297 | { | |
| 298 | switch (offset) | |
| 299 | { | |
| 300 | case 0: // Write Data, Host to Board | |
| 301 | if (LOG) logerror("%s WD11C00-17 '%s' Write Data %03x:%02x\n", machine().describe_context(), tag(), m_ra, data); | |
| 302 | write_data(data); | |
| 303 | break; | |
| 304 | ||
| 305 | case 1: // Board Software Reset | |
| 306 | if (LOG) logerror("%s WD11C00-17 '%s' Software Reset\n", machine().describe_context(), tag()); | |
| 307 | software_reset(); | |
| 308 | break; | |
| 309 | ||
| 310 | case 2: // Board Select | |
| 311 | if (LOG) logerror("%s WD11C00-17 '%s' Select\n", machine().describe_context(), tag()); | |
| 312 | increment_address(); // HACK | |
| 313 | select(); | |
| 314 | break; | |
| 315 | ||
| 316 | case 3: // Set/Reset DMA, IRQ Masks | |
| 317 | if (LOG) logerror("%s WD11C00-17 '%s' Mask IRQ %u DMA %u\n", machine().describe_context(), tag(), BIT(data, 1), BIT(data, 0)); | |
| 318 | m_mask = data; | |
| 319 | check_interrupt(); | |
| 320 | break; | |
| 321 | } | |
| 322 | } | |
| 323 | ||
| 324 | ||
| 325 | //------------------------------------------------- | |
| 326 | // dack_r - | |
| 327 | //------------------------------------------------- | |
| 328 | ||
| 329 | UINT8 wd11c00_17_device::dack_r() | |
| 330 | { | |
| 331 | return read_data(); | |
| 332 | } | |
| 333 | ||
| 334 | ||
| 335 | //------------------------------------------------- | |
| 336 | // dack_w - | |
| 337 | //------------------------------------------------- | |
| 338 | ||
| 339 | void wd11c00_17_device::dack_w(UINT8 data) | |
| 340 | { | |
| 341 | write_data(data); | |
| 342 | } | |
| 343 | ||
| 344 | ||
| 345 | //------------------------------------------------- | |
| 346 | // read - | |
| 347 | //------------------------------------------------- | |
| 348 | ||
| 349 | READ8_MEMBER( wd11c00_17_device::read ) | |
| 350 | { | |
| 351 | UINT8 data = 0; | |
| 352 | ||
| 353 | switch (offset) | |
| 354 | { | |
| 355 | case 0x00: | |
| 356 | if (LOG) logerror("%s WD11C00-17 '%s' Read RAM %03x:", machine().describe_context(), tag(), m_ra); | |
| 357 | data = read_data(); | |
| 358 | if (LOG) logerror("%02x\n", data); | |
| 359 | break; | |
| 360 | ||
| 361 | case 0x20: | |
| 362 | data = m_in_cs1010_func(m_ra >> 8); | |
| 363 | break; | |
| 364 | } | |
| 365 | ||
| 366 | return data; | |
| 367 | } | |
| 368 | ||
| 369 | ||
| 370 | //------------------------------------------------- | |
| 371 | // write - | |
| 372 | //------------------------------------------------- | |
| 373 | ||
| 374 | WRITE8_MEMBER( wd11c00_17_device::write ) | |
| 375 | { | |
| 376 | switch (offset) | |
| 377 | { | |
| 378 | case 0x00: | |
| 379 | if (LOG) logerror("%s WD11C00-17 '%s' Write RAM %03x:%02x\n", machine().describe_context(), tag(), m_ra, data); | |
| 380 | write_data(data); | |
| 381 | if (m_ra > 0x400) m_ecc_not_0 = 0; // HACK | |
| 382 | break; | |
| 383 | ||
| 384 | case 0x20: | |
| 385 | m_out_cs1010_func(m_ra >> 8, data); | |
| 386 | break; | |
| 387 | ||
| 388 | case 0x60: | |
| 389 | m_ra = (data & 0x07) << 8; | |
| 390 | if (LOG) logerror("%s WD11C00-17 '%s' RA %03x\n", machine().describe_context(), tag(), m_ra); | |
| 391 | check_interrupt(); | |
| 392 | break; | |
| 393 | } | |
| 394 | } | |
| 395 | ||
| 396 | ||
| 397 | //------------------------------------------------- | |
| 398 | // ireq_w - | |
| 399 | //------------------------------------------------- | |
| 400 | ||
| 401 | WRITE_LINE_MEMBER( wd11c00_17_device::ireq_w ) | |
| 402 | { | |
| 403 | if (LOG) logerror("%s WD11C00-17 '%s' IREQ %u\n", machine().describe_context(), tag(), state); | |
| 404 | ||
| 405 | if (state) m_status |= STATUS_REQ; else m_status &= ~STATUS_REQ; | |
| 406 | ||
| 407 | if (m_status & STATUS_BUSY) | |
| 408 | { | |
| 409 | if (state) | |
| 410 | { | |
| 411 | m_status |= STATUS_IRQ | STATUS_I_O; | |
| 412 | } | |
| 413 | else | |
| 414 | { | |
| 415 | if (m_status & STATUS_I_O) | |
| 416 | { | |
| 417 | m_status &= ~(STATUS_BUSY | STATUS_I_O); | |
| 418 | } | |
| 419 | } | |
| 420 | } | |
| 421 | ||
| 422 | check_interrupt(); | |
| 423 | } | |
| 424 | ||
| 425 | ||
| 426 | //------------------------------------------------- | |
| 427 | // io_w - | |
| 428 | //------------------------------------------------- | |
| 429 | ||
| 430 | WRITE_LINE_MEMBER( wd11c00_17_device::io_w ) | |
| 431 | { | |
| 432 | if (LOG) logerror("%s WD11C00-17 '%s' I/O %u\n", machine().describe_context(), tag(), state); | |
| 433 | ||
| 434 | if (state) m_status |= STATUS_I_O; else m_status &= ~STATUS_I_O; | |
| 435 | } | |
| 436 | ||
| 437 | ||
| 438 | //------------------------------------------------- | |
| 439 | // cd_w - | |
| 440 | //------------------------------------------------- | |
| 441 | ||
| 442 | WRITE_LINE_MEMBER( wd11c00_17_device::cd_w ) | |
| 443 | { | |
| 444 | if (LOG) logerror("%s WD11C00-17 '%s' C/D %u\n", machine().describe_context(), tag(), state); | |
| 445 | ||
| 446 | if (state) m_status |= STATUS_C_D; else m_status &= ~STATUS_C_D; | |
| 447 | } | |
| 448 | ||
| 449 | ||
| 450 | //------------------------------------------------- | |
| 451 | // clct_w - | |
| 452 | //------------------------------------------------- | |
| 453 | ||
| 454 | WRITE_LINE_MEMBER( wd11c00_17_device::clct_w ) | |
| 455 | { | |
| 456 | if (LOG) logerror("%s WD11C00-17 '%s' CLCT %u\n", machine().describe_context(), tag(), state); | |
| 457 | ||
| 458 | if (state) | |
| 459 | { | |
| 460 | m_ra &= 0xff00; | |
| 461 | check_interrupt(); | |
| 462 | } | |
| 463 | } | |
| 464 | ||
| 465 | ||
| 466 | //------------------------------------------------- | |
| 467 | // mode_w - | |
| 468 | //------------------------------------------------- | |
| 469 | ||
| 470 | WRITE_LINE_MEMBER( wd11c00_17_device::mode_w ) | |
| 471 | { | |
| 472 | if (LOG) logerror("%s WD11C00-17 '%s' MODE %u\n", machine().describe_context(), tag(), state); | |
| 473 | ||
| 474 | m_mode = state; | |
| 475 | m_ecc_not_0 = state; // HACK | |
| 476 | } | |
| 477 | ||
| 478 | ||
| 479 | //------------------------------------------------- | |
| 480 | // busy_r - | |
| 481 | //------------------------------------------------- | |
| 482 | ||
| 483 | READ_LINE_MEMBER( wd11c00_17_device::busy_r ) | |
| 484 | { | |
| 485 | return (m_status & STATUS_BUSY) ? 0 : 1; | |
| 486 | } | |
| 487 | ||
| 488 | ||
| 489 | //------------------------------------------------- | |
| 490 | // ecc_not_0_r - | |
| 491 | //------------------------------------------------- | |
| 492 | ||
| 493 | READ_LINE_MEMBER( wd11c00_17_device::ecc_not_0_r ) | |
| 494 | { | |
| 495 | return m_ecc_not_0; | |
| 496 | } |
| r21684 | r21685 | |
|---|---|---|
| 1 | /********************************************************************** | |
| 2 | ||
| 3 | Western Digital WD11C00-17 PC/XT Host Interface Logic Device | |
| 4 | ||
| 5 | Copyright MESS Team. | |
| 6 | Visit http://mamedev.org for licensing and usage restrictions. | |
| 7 | ||
| 8 | **********************************************************************/ | |
| 9 | ||
| 10 | #pragma once | |
| 11 | ||
| 12 | #ifndef __WD11C00_17__ | |
| 13 | #define __WD11C00_17__ | |
| 14 | ||
| 15 | ||
| 16 | #include "emu.h" | |
| 17 | ||
| 18 | ||
| 19 | ||
| 20 | //************************************************************************** | |
| 21 | // INTERFACE CONFIGURATION MACROS | |
| 22 | //************************************************************************** | |
| 23 | ||
| 24 | #define MCFG_WD11C00_17_ADD(_tag, _clock, _config) \ | |
| 25 | MCFG_DEVICE_ADD(_tag, WD11C00_17, _clock) \ | |
| 26 | MCFG_DEVICE_CONFIG(_config) | |
| 27 | ||
| 28 | ||
| 29 | #define WD11C00_17_INTERFACE(_name) \ | |
| 30 | const wd11c00_17_interface (_name) = | |
| 31 | ||
| 32 | ||
| 33 | ||
| 34 | //************************************************************************** | |
| 35 | // TYPE DEFINITIONS | |
| 36 | //************************************************************************** | |
| 37 | ||
| 38 | // ======================> wd11c00_17_interface | |
| 39 | ||
| 40 | struct wd11c00_17_interface | |
| 41 | { | |
| 42 | devcb_write_line m_out_irq5_cb; | |
| 43 | devcb_write_line m_out_drq3_cb; | |
| 44 | devcb_write_line m_out_mr_cb; | |
| 45 | devcb_write_line m_out_busy_cb; | |
| 46 | devcb_write_line m_out_req_cb; | |
| 47 | devcb_write_line m_out_ra3_cb; | |
| 48 | devcb_read8 m_in_rd322_cb; | |
| 49 | devcb_read8 m_in_ramcs_cb; | |
| 50 | devcb_write8 m_out_ramwr_cb; | |
| 51 | devcb_read8 m_in_cs1010_cb; | |
| 52 | devcb_write8 m_out_cs1010_cb; | |
| 53 | }; | |
| 54 | ||
| 55 | ||
| 56 | // ======================> wd11c00_17_device | |
| 57 | ||
| 58 | class wd11c00_17_device : public device_t, | |
| 59 | public wd11c00_17_interface | |
| 60 | { | |
| 61 | public: | |
| 62 | // construction/destruction | |
| 63 | wd11c00_17_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); | |
| 64 | ||
| 65 | DECLARE_READ8_MEMBER( io_r ); | |
| 66 | DECLARE_WRITE8_MEMBER( io_w ); | |
| 67 | ||
| 68 | UINT8 dack_r(); | |
| 69 | void dack_w(UINT8 data); | |
| 70 | ||
| 71 | DECLARE_READ8_MEMBER( read ); | |
| 72 | DECLARE_WRITE8_MEMBER( write ); | |
| 73 | ||
| 74 | DECLARE_WRITE_LINE_MEMBER( ireq_w ); | |
| 75 | DECLARE_WRITE_LINE_MEMBER( io_w ); | |
| 76 | DECLARE_WRITE_LINE_MEMBER( cd_w ); | |
| 77 | DECLARE_WRITE_LINE_MEMBER( clct_w ); | |
| 78 | DECLARE_WRITE_LINE_MEMBER( mode_w ); | |
| 79 | ||
| 80 | DECLARE_READ_LINE_MEMBER( busy_r ); | |
| 81 | DECLARE_READ_LINE_MEMBER( ecc_not_0_r ); | |
| 82 | ||
| 83 | protected: | |
| 84 | // device-level overrides | |
| 85 | virtual void device_start(); | |
| 86 | virtual void device_reset(); | |
| 87 | virtual void device_config_complete(); | |
| 88 | ||
| 89 | private: | |
| 90 | inline void check_interrupt(); | |
| 91 | inline void increment_address(); | |
| 92 | inline UINT8 read_data(); | |
| 93 | inline void write_data(UINT8 data); | |
| 94 | inline void software_reset(); | |
| 95 | inline void select(); | |
| 96 | ||
| 97 | devcb_resolved_write_line m_out_irq5_func; | |
| 98 | devcb_resolved_write_line m_out_drq3_func; | |
| 99 | devcb_resolved_write_line m_out_mr_func; | |
| 100 | devcb_resolved_write_line m_out_busy_func; | |
| 101 | devcb_resolved_write_line m_out_req_func; | |
| 102 | devcb_resolved_write_line m_out_ra3_func; | |
| 103 | devcb_resolved_read8 m_in_rd322_func; | |
| 104 | devcb_resolved_read8 m_in_ramcs_func; | |
| 105 | devcb_resolved_write8 m_out_ramwr_func; | |
| 106 | devcb_resolved_read8 m_in_cs1010_func; | |
| 107 | devcb_resolved_write8 m_out_cs1010_func; | |
| 108 | ||
| 109 | UINT8 m_status; | |
| 110 | UINT8 m_mask; | |
| 111 | ||
| 112 | offs_t m_ra; | |
| 113 | ||
| 114 | int m_mode; | |
| 115 | int m_ecc_not_0; | |
| 116 | ||
| 117 | int m_irq5; | |
| 118 | int m_drq3; | |
| 119 | int m_busy; | |
| 120 | int m_req; | |
| 121 | int m_ra3; | |
| 122 | }; | |
| 123 | ||
| 124 | ||
| 125 | // device type definition | |
| 126 | extern const device_type WD11C00_17; | |
| 127 | ||
| 128 | #endif |
| r21684 | r21685 | |
|---|---|---|
| 1 | /********************************************************************** | |
| 2 | ||
| 3 | Western Digital WD2010 Winchester Disk Controller | |
| 4 | ||
| 5 | Copyright MESS Team. | |
| 6 | Visit http://mamedev.org for licensing and usage restrictions. | |
| 7 | ||
| 8 | **********************************************************************/ | |
| 9 | ||
| 10 | #include "machine/wd2010.h" | |
| 11 | ||
| 12 | ||
| 13 | ||
| 14 | //************************************************************************** | |
| 15 | // MACROS / CONSTANTS | |
| 16 | //************************************************************************** | |
| 17 | ||
| 18 | #define LOG 1 | |
| 19 | ||
| 20 | ||
| 21 | // task file | |
| 22 | enum | |
| 23 | { | |
| 24 | TASK_FILE_ERROR = 1, | |
| 25 | TASK_FILE_WRITE_PRECOMP_CYLINDER = TASK_FILE_ERROR, | |
| 26 | TASK_FILE_SECTOR_COUNT, | |
| 27 | TASK_FILE_SECTOR_NUMBER, | |
| 28 | TASK_FILE_CYLINDER_LOW, | |
| 29 | TASK_FILE_CYLINDER_HIGH, | |
| 30 | TASK_FILE_SDH_REGISTER, | |
| 31 | TASK_FILE_STATUS, | |
| 32 | TASK_FILE_COMMAND = TASK_FILE_STATUS | |
| 33 | }; | |
| 34 | ||
| 35 | #define WRITE_PRECOMP_CYLINDER \ | |
| 36 | (m_task_file[TASK_FILE_WRITE_PRECOMP_CYLINDER] * 4) | |
| 37 | ||
| 38 | #define SECTOR_COUNT \ | |
| 39 | ((m_task_file[TASK_FILE_SECTOR_COUNT] + 1) * 256) | |
| 40 | ||
| 41 | #define SECTOR_NUMBER \ | |
| 42 | (m_task_file[TASK_FILE_SECTOR_NUMBER]) | |
| 43 | ||
| 44 | #define CYLINDER \ | |
| 45 | (((m_task_file[TASK_FILE_CYLINDER_HIGH] & 0x07) << 8) | m_task_file[TASK_FILE_CYLINDER_LOW]) | |
| 46 | ||
| 47 | #define HEAD \ | |
| 48 | (m_task_file[TASK_FILE_SDH_REGISTER] & 0x07) | |
| 49 | ||
| 50 | #define DRIVE \ | |
| 51 | ((m_task_file[TASK_FILE_SDH_REGISTER] >> 3) & 0x03) | |
| 52 | ||
| 53 | static const int SECTOR_SIZES[4] = { 256, 512, 1024, 128 }; | |
| 54 | ||
| 55 | #define SECTOR_SIZE \ | |
| 56 | SECTOR_SIZES[(m_task_file[TASK_FILE_SDH_REGISTER] >> 5) & 0x03] | |
| 57 | ||
| 58 | ||
| 59 | // status register | |
| 60 | #define STATUS_BSY 0x80 | |
| 61 | #define STATUS_RDY 0x40 | |
| 62 | #define STATUS_WF 0x20 | |
| 63 | #define STATUS_SC 0x10 | |
| 64 | #define STATUS_DRQ 0x08 | |
| 65 | #define STATUS_DWC 0x04 | |
| 66 | #define STATUS_CIP 0x02 | |
| 67 | #define STATUS_ERR 0x01 | |
| 68 | ||
| 69 | ||
| 70 | // error register | |
| 71 | #define ERROR_BB 0x80 | |
| 72 | #define ERROR_CRC_ECC 0x40 | |
| 73 | #define ERROR_ID 0x10 | |
| 74 | #define ERROR_AC 0x04 | |
| 75 | #define ERROR_TK 0x02 | |
| 76 | #define ERROR_DM 0x01 | |
| 77 | ||
| 78 | ||
| 79 | // command register | |
| 80 | #define COMMAND_MASK 0xf0 | |
| 81 | #define COMMAND_RESTORE 0x10 | |
| 82 | #define COMMAND_SEEK 0x70 | |
| 83 | #define COMMAND_READ_SECTOR 0x20 | |
| 84 | #define COMMAND_WRITE_SECTOR 0x30 | |
| 85 | #define COMMAND_SCAN_ID 0x40 | |
| 86 | #define COMMAND_WRITE_FORMAT 0x50 | |
| 87 | #define COMMAND_COMPUTE_CORRECTION 0x08 | |
| 88 | #define COMMAND_SET_PARAMETER_MASK 0xfe | |
| 89 | #define COMMAND_SET_PARAMETER 0x00 | |
| 90 | ||
| 91 | ||
| 92 | ||
| 93 | //************************************************************************** | |
| 94 | // DEVICE DEFINITIONS | |
| 95 | //************************************************************************** | |
| 96 | ||
| 97 | const device_type WD2010 = &device_creator<wd2010_device>; | |
| 98 | ||
| 99 | ||
| 100 | //------------------------------------------------- | |
| 101 | // device_config_complete - perform any | |
| 102 | // operations now that the configuration is | |
| 103 | // complete | |
| 104 | //------------------------------------------------- | |
| 105 | ||
| 106 | void wd2010_device::device_config_complete() | |
| 107 | { | |
| 108 | // inherit a copy of the static data | |
| 109 | const wd2010_interface *intf = reinterpret_cast<const wd2010_interface *>(static_config()); | |
| 110 | if (intf != NULL) | |
| 111 | *static_cast<wd2010_interface *>(this) = *intf; | |
| 112 | ||
| 113 | // or initialize to defaults if none provided | |
| 114 | else | |
| 115 | { | |
| 116 | memset(&m_out_intrq_cb, 0, sizeof(m_out_intrq_cb)); | |
| 117 | memset(&m_out_bdrq_cb, 0, sizeof(m_out_bdrq_cb)); | |
| 118 | memset(&m_out_bcr_cb, 0, sizeof(m_out_bcr_cb)); | |
| 119 | memset(&m_in_bcs_cb, 0, sizeof(m_in_bcs_cb)); | |
| 120 | memset(&m_out_bcs_cb, 0, sizeof(m_out_bcs_cb)); | |
| 121 | memset(&m_out_dirin_cb, 0, sizeof(m_out_dirin_cb)); | |
| 122 | memset(&m_out_step_cb, 0, sizeof(m_out_step_cb)); | |
| 123 | memset(&m_out_rwc_cb, 0, sizeof(m_out_rwc_cb)); | |
| 124 | memset(&m_in_drdy_cb, 0, sizeof(m_in_drdy_cb)); | |
| 125 | memset(&m_in_index_cb, 0, sizeof(m_in_index_cb)); | |
| 126 | memset(&m_in_wf_cb, 0, sizeof(m_in_wf_cb)); | |
| 127 | memset(&m_in_tk000_cb, 0, sizeof(m_in_tk000_cb)); | |
| 128 | memset(&m_in_sc_cb, 0, sizeof(m_in_sc_cb)); | |
| 129 | } | |
| 130 | } | |
| 131 | ||
| 132 | ||
| 133 | ||
| 134 | //************************************************************************** | |
| 135 | // LIVE DEVICE | |
| 136 | //************************************************************************** | |
| 137 | ||
| 138 | //------------------------------------------------- | |
| 139 | // wd2010_device - constructor | |
| 140 | //------------------------------------------------- | |
| 141 | ||
| 142 | wd2010_device::wd2010_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) | |
| 143 | : device_t(mconfig, WD2010, "Western Digital WD2010", tag, owner, clock), | |
| 144 | m_status(0), | |
| 145 | m_error(0) | |
| 146 | { | |
| 147 | } | |
| 148 | ||
| 149 | ||
| 150 | //------------------------------------------------- | |
| 151 | // device_start - device-specific startup | |
| 152 | //------------------------------------------------- | |
| 153 | ||
| 154 | void wd2010_device::device_start() | |
| 155 | { | |
| 156 | // resolve callbacks | |
| 157 | m_out_intrq_func.resolve(m_out_intrq_cb, *this); | |
| 158 | m_out_bdrq_func.resolve(m_out_bdrq_cb, *this); | |
| 159 | m_out_bcr_func.resolve(m_out_bcr_cb, *this); | |
| 160 | m_in_bcs_func.resolve(m_in_bcs_cb, *this); | |
| 161 | m_out_bcs_func.resolve(m_out_bcs_cb, *this); | |
| 162 | m_out_dirin_func.resolve(m_out_dirin_cb, *this); | |
| 163 | m_out_step_func.resolve(m_out_step_cb, *this); | |
| 164 | m_out_rwc_func.resolve(m_out_rwc_cb, *this); | |
| 165 | m_in_drdy_func.resolve(m_in_drdy_cb, *this); | |
| 166 | m_in_index_func.resolve(m_in_index_cb, *this); | |
| 167 | m_in_wf_func.resolve(m_in_wf_cb, *this); | |
| 168 | m_in_tk000_func.resolve(m_in_tk000_cb, *this); | |
| 169 | m_in_sc_func.resolve(m_in_sc_cb, *this); | |
| 170 | } | |
| 171 | ||
| 172 | ||
| 173 | //------------------------------------------------- | |
| 174 | // device_reset - device-specific reset | |
| 175 | //------------------------------------------------- | |
| 176 | ||
| 177 | void wd2010_device::device_reset() | |
| 178 | { | |
| 179 | } | |
| 180 | ||
| 181 | ||
| 182 | //------------------------------------------------- | |
| 183 | // read - | |
| 184 | //------------------------------------------------- | |
| 185 | ||
| 186 | READ8_MEMBER( wd2010_device::read ) | |
| 187 | { | |
| 188 | UINT8 data = 0; | |
| 189 | ||
| 190 | switch (offset) | |
| 191 | { | |
| 192 | case TASK_FILE_ERROR: | |
| 193 | data = m_error; | |
| 194 | break; | |
| 195 | ||
| 196 | case TASK_FILE_STATUS: | |
| 197 | m_out_intrq_func(CLEAR_LINE); | |
| 198 | data = m_status | STATUS_RDY | STATUS_SC; | |
| 199 | break; | |
| 200 | ||
| 201 | default: | |
| 202 | data = m_task_file[offset]; | |
| 203 | break; | |
| 204 | } | |
| 205 | ||
| 206 | return data; | |
| 207 | } | |
| 208 | ||
| 209 | ||
| 210 | //------------------------------------------------- | |
| 211 | // write - | |
| 212 | //------------------------------------------------- | |
| 213 | ||
| 214 | WRITE8_MEMBER( wd2010_device::write ) | |
| 215 | { | |
| 216 | m_task_file[offset] = data; | |
| 217 | ||
| 218 | switch (offset) | |
| 219 | { | |
| 220 | case TASK_FILE_WRITE_PRECOMP_CYLINDER: | |
| 221 | if (LOG) logerror("%s WD2010 '%s' Write Precomp Cylinder: %u\n", machine().describe_context(), tag(), WRITE_PRECOMP_CYLINDER); | |
| 222 | break; | |
| 223 | ||
| 224 | case TASK_FILE_SECTOR_COUNT: | |
| 225 | if (LOG) logerror("%s WD2010 '%s' Sector Count: %u\n", machine().describe_context(), tag(), SECTOR_COUNT); | |
| 226 | break; | |
| 227 | ||
| 228 | case TASK_FILE_SECTOR_NUMBER: | |
| 229 | if (LOG) logerror("%s WD2010 '%s' Sector Number: %u\n", machine().describe_context(), tag(), SECTOR_NUMBER); | |
| 230 | break; | |
| 231 | ||
| 232 | case TASK_FILE_CYLINDER_LOW: | |
| 233 | if (LOG) logerror("%s WD2010 '%s' Cylinder Low: %u\n", machine().describe_context(), tag(), CYLINDER); | |
| 234 | break; | |
| 235 | ||
| 236 | case TASK_FILE_CYLINDER_HIGH: | |
| 237 | if (LOG) logerror("%s WD2010 '%s' Cylinder Low: %u\n", machine().describe_context(), tag(), CYLINDER); | |
| 238 | break; | |
| 239 | ||
| 240 | case TASK_FILE_SDH_REGISTER: | |
| 241 | if (LOG) | |
| 242 | { | |
| 243 | logerror("%s WD2010 '%s' Head: %u\n", machine().describe_context(), tag(), HEAD); | |
| 244 | logerror("%s WD2010 '%s' Drive: %u\n", machine().describe_context(), tag(), DRIVE); | |
| 245 | logerror("%s WD2010 '%s' Sector Size: %u\n", machine().describe_context(), tag(), SECTOR_SIZE); | |
| 246 | } | |
| 247 | break; | |
| 248 | ||
| 249 | case TASK_FILE_COMMAND: | |
| 250 | if (data == COMMAND_COMPUTE_CORRECTION) | |
| 251 | { | |
| 252 | if (LOG) logerror("%s WD2010 '%s' COMPUTE CORRECTION\n", machine().describe_context(), tag()); | |
| 253 | compute_correction(data); | |
| 254 | } | |
| 255 | else if ((data & COMMAND_SET_PARAMETER_MASK) == COMMAND_SET_PARAMETER) | |
| 256 | { | |
| 257 | if (LOG) logerror("%s WD2010 '%s' SET PARAMETER\n", machine().describe_context(), tag()); | |
| 258 | set_parameter(data); | |
| 259 | } | |
| 260 | else | |
| 261 | { | |
| 262 | switch (data & COMMAND_MASK) | |
| 263 | { | |
| 264 | case COMMAND_RESTORE: | |
| 265 | if (LOG) logerror("%s WD2010 '%s' RESTORE\n", machine().describe_context(), tag()); | |
| 266 | restore(data); | |
| 267 | break; | |
| 268 | ||
| 269 | case COMMAND_SEEK: | |
| 270 | if (LOG) logerror("%s WD2010 '%s' SEEK\n", machine().describe_context(), tag()); | |
| 271 | seek(data); | |
| 272 | break; | |
| 273 | ||
| 274 | case COMMAND_READ_SECTOR: | |
| 275 | if (LOG) logerror("%s WD2010 '%s' READ SECTOR\n", machine().describe_context(), tag()); | |
| 276 | read_sector(data); | |
| 277 | break; | |
| 278 | ||
| 279 | case COMMAND_WRITE_SECTOR: | |
| 280 | if (LOG) logerror("%s WD2010 '%s' WRITE SECTOR\n", machine().describe_context(), tag()); | |
| 281 | write_sector(data); | |
| 282 | break; | |
| 283 | ||
| 284 | case COMMAND_SCAN_ID: | |
| 285 | if (LOG) logerror("%s WD2010 '%s' SCAN ID\n", machine().describe_context(), tag()); | |
| 286 | scan_id(data); | |
| 287 | break; | |
| 288 | ||
| 289 | case COMMAND_WRITE_FORMAT: | |
| 290 | if (LOG) logerror("%s WD2010 '%s' WRITE FORMAT\n", machine().describe_context(), tag()); | |
| 291 | format(data); | |
| 292 | break; | |
| 293 | } | |
| 294 | } | |
| 295 | break; | |
| 296 | } | |
| 297 | } | |
| 298 | ||
| 299 | ||
| 300 | //------------------------------------------------- | |
| 301 | // compute_correction - | |
| 302 | //------------------------------------------------- | |
| 303 | ||
| 304 | void wd2010_device::compute_correction(UINT8 data) | |
| 305 | { | |
| 306 | } | |
| 307 | ||
| 308 | ||
| 309 | //------------------------------------------------- | |
| 310 | // set_parameter - | |
| 311 | //------------------------------------------------- | |
| 312 | ||
| 313 | void wd2010_device::set_parameter(UINT8 data) | |
| 314 | { | |
| 315 | } | |
| 316 | ||
| 317 | ||
| 318 | //------------------------------------------------- | |
| 319 | // restore - | |
| 320 | //------------------------------------------------- | |
| 321 | ||
| 322 | void wd2010_device::restore(UINT8 data) | |
| 323 | { | |
| 324 | // reset INTRQ, errors, set BUSY, CIP | |
| 325 | m_out_intrq_func(CLEAR_LINE); | |
| 326 | m_error = 0; | |
| 327 | m_status = STATUS_BSY | STATUS_CIP; | |
| 328 | ||
| 329 | // reset RWC, set direction=OUT, store step rate | |
| 330 | m_out_rwc_func(0); | |
| 331 | m_out_dirin_func(0); | |
| 332 | ||
| 333 | int step_pulses = 0; | |
| 334 | ||
| 335 | while (step_pulses < 2048) | |
| 336 | { | |
| 337 | while (!m_in_sc_func()) | |
| 338 | { | |
| 339 | // drive not ready or write fault? | |
| 340 | if (!m_in_drdy_func() || m_in_wf_func()) | |
| 341 | { | |
| 342 | // pulse BCR, set AC, INTRQ, reset BSY, CIP | |
| 343 | m_out_bcr_func(0); | |
| 344 | m_out_bcr_func(1); | |
| 345 | m_error = ERROR_AC; | |
| 346 | m_status = (m_in_drdy_func() << 6) | (m_in_wf_func() << 5) | STATUS_ERR; | |
| 347 | m_out_intrq_func(ASSERT_LINE); | |
| 348 | return; | |
| 349 | } | |
| 350 | } | |
| 351 | ||
| 352 | if (m_in_tk000_func()) | |
| 353 | { | |
| 354 | // pulse BCR, set INTRQ, reset BSY, CIP | |
| 355 | m_out_bcr_func(0); | |
| 356 | m_out_bcr_func(1); | |
| 357 | m_status &= ~(STATUS_BSY | STATUS_CIP); | |
| 358 | m_out_intrq_func(ASSERT_LINE); | |
| 359 | return; | |
| 360 | } | |
| 361 | ||
| 362 | if (step_pulses == 2047) | |
| 363 | { | |
| 364 | // set TK000 error | |
| 365 | m_error = ERROR_TK; | |
| 366 | m_status |= STATUS_ERR; | |
| 367 | ||
| 368 | // pulse BCR, set INTRQ, reset BSY, CIP | |
| 369 | m_out_bcr_func(0); | |
| 370 | m_out_bcr_func(1); | |
| 371 | m_status &= ~(STATUS_BSY | STATUS_CIP); | |
| 372 | m_out_intrq_func(ASSERT_LINE); | |
| 373 | return; | |
| 374 | } | |
| 375 | ||
| 376 | // issue a step pulse | |
| 377 | m_out_step_func(1); | |
| 378 | m_out_step_func(0); | |
| 379 | step_pulses++; | |
| 380 | } | |
| 381 | } | |
| 382 | ||
| 383 | ||
| 384 | //------------------------------------------------- | |
| 385 | // seek - | |
| 386 | //------------------------------------------------- | |
| 387 | ||
| 388 | void wd2010_device::seek(UINT8 data) | |
| 389 | { | |
| 390 | } | |
| 391 | ||
| 392 | ||
| 393 | //------------------------------------------------- | |
| 394 | // read_sector - | |
| 395 | //------------------------------------------------- | |
| 396 | ||
| 397 | void wd2010_device::read_sector(UINT8 data) | |
| 398 | { | |
| 399 | } | |
| 400 | ||
| 401 | ||
| 402 | //------------------------------------------------- | |
| 403 | // write_sector - | |
| 404 | //------------------------------------------------- | |
| 405 | ||
| 406 | void wd2010_device::write_sector(UINT8 data) | |
| 407 | { | |
| 408 | } | |
| 409 | ||
| 410 | ||
| 411 | //------------------------------------------------- | |
| 412 | // scan_id - | |
| 413 | //------------------------------------------------- | |
| 414 | ||
| 415 | void wd2010_device::scan_id(UINT8 data) | |
| 416 | { | |
| 417 | } | |
| 418 | ||
| 419 | ||
| 420 | //------------------------------------------------- | |
| 421 | // format - | |
| 422 | //------------------------------------------------- | |
| 423 | ||
| 424 | void wd2010_device::format(UINT8 data) | |
| 425 | { | |
| 426 | } |
| r21684 | r21685 | |
|---|---|---|
| 1 | /********************************************************************** | |
| 2 | ||
| 3 | Western Digital WD2010 Winchester Disk Controller | |
| 4 | ||
| 5 | Copyright MESS Team. | |
| 6 | Visit http://mamedev.org for licensing and usage restrictions. | |
| 7 | ||
| 8 | **********************************************************************/ | |
| 9 | ||
| 10 | #pragma once | |
| 11 | ||
| 12 | #ifndef __WD2010__ | |
| 13 | #define __WD2010__ | |
| 14 | ||
| 15 | ||
| 16 | #include "emu.h" | |
| 17 | ||
| 18 | ||
| 19 | ||
| 20 | //************************************************************************** | |
| 21 | // INTERFACE CONFIGURATION MACROS | |
| 22 | //************************************************************************** | |
| 23 | ||
| 24 | #define MCFG_WD2010_ADD(_tag, _clock, _config) \ | |
| 25 | MCFG_DEVICE_ADD(_tag, WD2010, _clock) \ | |
| 26 | MCFG_DEVICE_CONFIG(_config) | |
| 27 | ||
| 28 | ||
| 29 | #define WD2010_INTERFACE(_name) \ | |
| 30 | const wd2010_interface (_name) = | |
| 31 | ||
| 32 | ||
| 33 | ||
| 34 | //************************************************************************** | |
| 35 | // TYPE DEFINITIONS | |
| 36 | //************************************************************************** | |
| 37 | ||
| 38 | // ======================> wd2010_interface | |
| 39 | ||
| 40 | struct wd2010_interface | |
| 41 | { | |
| 42 | devcb_write_line m_out_intrq_cb; | |
| 43 | devcb_write_line m_out_bdrq_cb; | |
| 44 | devcb_write_line m_out_bcr_cb; | |
| 45 | devcb_read8 m_in_bcs_cb; | |
| 46 | devcb_write8 m_out_bcs_cb; | |
| 47 | devcb_write_line m_out_dirin_cb; | |
| 48 | devcb_write_line m_out_step_cb; | |
| 49 | devcb_write_line m_out_rwc_cb; | |
| 50 | devcb_read_line m_in_drdy_cb; | |
| 51 | devcb_read_line m_in_index_cb; | |
| 52 | devcb_read_line m_in_wf_cb; | |
| 53 | devcb_read_line m_in_tk000_cb; | |
| 54 | devcb_read_line m_in_sc_cb; | |
| 55 | }; | |
| 56 | ||
| 57 | ||
| 58 | // ======================> wd2010_device | |
| 59 | ||
| 60 | class wd2010_device : public device_t, | |
| 61 | public wd2010_interface | |
| 62 | { | |
| 63 | public: | |
| 64 | // construction/destruction | |
| 65 | wd2010_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); | |
| 66 | ||
| 67 | DECLARE_READ8_MEMBER( read ); | |
| 68 | DECLARE_WRITE8_MEMBER( write ); | |
| 69 | ||
| 70 | protected: | |
| 71 | // device-level overrides | |
| 72 | virtual void device_start(); | |
| 73 | virtual void device_reset(); | |
| 74 | virtual void device_config_complete(); | |
| 75 | ||
| 76 | private: | |
| 77 | void compute_correction(UINT8 data); | |
| 78 | void set_parameter(UINT8 data); | |
| 79 | void restore(UINT8 data); | |
| 80 | void seek(UINT8 data); | |
| 81 | void read_sector(UINT8 data); | |
| 82 | void write_sector(UINT8 data); | |
| 83 | void scan_id(UINT8 data); | |
| 84 | void format(UINT8 data); | |
| 85 | ||
| 86 | devcb_resolved_write_line m_out_intrq_func; | |
| 87 | devcb_resolved_write_line m_out_bdrq_func; | |
| 88 | devcb_resolved_write_line m_out_bcr_func; | |
| 89 | devcb_resolved_read8 m_in_bcs_func; | |
| 90 | devcb_resolved_write8 m_out_bcs_func; | |
| 91 | devcb_resolved_write_line m_out_dirin_func; | |
| 92 | devcb_resolved_write_line m_out_step_func; | |
| 93 | devcb_resolved_write_line m_out_rwc_func; | |
| 94 | devcb_resolved_read_line m_in_drdy_func; | |
| 95 | devcb_resolved_read_line m_in_index_func; | |
| 96 | devcb_resolved_read_line m_in_wf_func; | |
| 97 | devcb_resolved_read_line m_in_tk000_func; | |
| 98 | devcb_resolved_read_line m_in_sc_func; | |
| 99 | ||
| 100 | UINT8 m_status; | |
| 101 | UINT8 m_error; | |
| 102 | UINT8 m_task_file[8]; | |
| 103 | }; | |
| 104 | ||
| 105 | ||
| 106 | // device type definition | |
| 107 | extern const device_type WD2010; | |
| 108 | ||
| 109 | #endif |
| r21684 | r21685 | |
|---|---|---|
| 9 | 9 | |
| 10 | 10 | #include "includes/cbm.h" |
| 11 | 11 | #include "includes/c65.h" |
| 12 | #include "includes/c64_legacy.h" | |
| 13 | 12 | #include "cpu/m6502/m4510.h" |
| 14 | 13 | #include "sound/mos6581.h" |
| 15 | 14 | #include "machine/6526cia.h" |
| r21684 | r21685 | |
| 994 | 993 | DRIVER_INIT_MEMBER(c65_state,c65) |
| 995 | 994 | { |
| 996 | 995 | m_dma.version = 2; |
| 997 | c64_legacy_driver_init(); | |
| 998 | 996 | c65_common_driver_init(machine()); |
| 999 | 997 | } |
| 1000 | 998 | |
| 1001 | 999 | DRIVER_INIT_MEMBER(c65_state,c65pal) |
| 1002 | 1000 | { |
| 1003 | 1001 | m_dma.version = 1; |
| 1004 | c64_legacy_driver_init(); | |
| 1005 | 1002 | c65_common_driver_init(machine()); |
| 1006 | 1003 | m_pal = 1; |
| 1007 | 1004 | } |
| Previous | 199869 Revisions | Next |