src/mess/video/hd61830.c
| r9369 | r9370 | |
| 10 | 10 | #include "emu.h" |
| 11 | 11 | #include "hd61830.h" |
| 12 | 12 | |
| 13 | | /*************************************************************************** |
| 14 | | PARAMETERS |
| 15 | | ***************************************************************************/ |
| 16 | 13 | |
| 14 | |
| 15 | //************************************************************************** |
| 16 | // MACROS / CONSTANTS |
| 17 | //************************************************************************** |
| 18 | |
| 17 | 19 | #define LOG 0 |
| 18 | 20 | |
| 19 | 21 | enum |
| 20 | 22 | { |
| 21 | | HD61830_INSTRUCTION_MODE_CONTROL = 0, |
| 22 | | HD61830_INSTRUCTION_CHARACTER_PITCH, |
| 23 | | HD61830_INSTRUCTION_NUMBER_OF_CHARACTERS, |
| 24 | | HD61830_INSTRUCTION_NUMBER_OF_TIME_DIVISIONS, |
| 25 | | HD61830_INSTRUCTION_CURSOR_POSITION, |
| 26 | | HD61830_INSTRUCTION_DISPLAY_START_LOW = 8, |
| 27 | | HD61830_INSTRUCTION_DISPLAY_START_HIGH, |
| 28 | | HD61830_INSTRUCTION_CURSOR_ADDRESS_LOW, |
| 29 | | HD61830_INSTRUCTION_CURSOR_ADDRESS_HIGH, |
| 30 | | HD61830_INSTRUCTION_DISPLAY_DATA_WRITE, |
| 31 | | HD61830_INSTRUCTION_DISPLAY_DATA_READ, |
| 32 | | HD61830_INSTRUCTION_CLEAR_BIT, |
| 33 | | HD61830_INSTRUCTION_SET_BIT |
| 23 | INSTRUCTION_MODE_CONTROL = 0, |
| 24 | INSTRUCTION_CHARACTER_PITCH, |
| 25 | INSTRUCTION_NUMBER_OF_CHARACTERS, |
| 26 | INSTRUCTION_NUMBER_OF_TIME_DIVISIONS, |
| 27 | INSTRUCTION_CURSOR_POSITION, |
| 28 | INSTRUCTION_DISPLAY_START_LOW = 8, |
| 29 | INSTRUCTION_DISPLAY_START_HIGH, |
| 30 | INSTRUCTION_CURSOR_ADDRESS_LOW, |
| 31 | INSTRUCTION_CURSOR_ADDRESS_HIGH, |
| 32 | INSTRUCTION_DISPLAY_DATA_WRITE, |
| 33 | INSTRUCTION_DISPLAY_DATA_READ, |
| 34 | INSTRUCTION_CLEAR_BIT, |
| 35 | INSTRUCTION_SET_BIT |
| 34 | 36 | }; |
| 35 | 37 | |
| 36 | | static const int HD61830_CYCLES[] = { |
| 38 | static const int CYCLES[] = |
| 39 | { |
| 37 | 40 | 4, 4, 4, 4, 4, -1, -1, -1, 4, 4, 4, 4, 6, 6, 36, 36 |
| 38 | 41 | }; |
| 39 | 42 | |
| 40 | | #define HD61830_MODE_EXTERNAL_CG 0x01 |
| 41 | | #define HD61830_MODE_GRAPHIC 0x02 |
| 42 | | #define HD61830_MODE_CURSOR 0x04 |
| 43 | | #define HD61830_MODE_BLINK 0x08 |
| 44 | | #define HD61830_MODE_MASTER 0x10 |
| 45 | | #define HD61830_MODE_DISPLAY_ON 0x20 |
| 43 | const int MODE_EXTERNAL_CG = 0x01; |
| 44 | const int MODE_GRAPHIC = 0x02; |
| 45 | const int MODE_CURSOR = 0x04; |
| 46 | const int MODE_BLINK = 0x08; |
| 47 | const int MODE_MASTER = 0x10; |
| 48 | const int MODE_DISPLAY_ON = 0x20; |
| 46 | 49 | |
| 47 | | /*************************************************************************** |
| 48 | | TYPE DEFINITIONS |
| 49 | | ***************************************************************************/ |
| 50 | 50 | |
| 51 | | typedef struct _hd61830_t hd61830_t; |
| 52 | | struct _hd61830_t |
| 51 | |
| 52 | //************************************************************************** |
| 53 | // GLOBAL VARIABLES |
| 54 | //************************************************************************** |
| 55 | |
| 56 | // devices |
| 57 | const device_type HD61830 = hd61830_device_config::static_alloc_device_config; |
| 58 | |
| 59 | |
| 60 | // default address map |
| 61 | static ADDRESS_MAP_START( hd61830, 0, 8 ) |
| 62 | AM_RANGE(0x0000, 0xffff) AM_RAM |
| 63 | ADDRESS_MAP_END |
| 64 | |
| 65 | |
| 66 | // internal character generator ROM |
| 67 | ROM_START( hd61830 ) |
| 68 | ROM_REGION( 0x5c0, "hd61830", ROMREGION_LOADBYNAME ) // internal 7360-bit chargen ROM |
| 69 | ROM_LOAD( "hd61830.bin", 0x000, 0x5c0, BAD_DUMP CRC(06a934da) SHA1(bf3f074db5dc92e6f530cb18d6c013563099a87d) ) // typed in from manual |
| 70 | ROM_END |
| 71 | |
| 72 | |
| 73 | |
| 74 | //************************************************************************** |
| 75 | // DEVICE CONFIGURATION |
| 76 | //************************************************************************** |
| 77 | |
| 78 | //------------------------------------------------- |
| 79 | // hd61830_device_config - constructor |
| 80 | //------------------------------------------------- |
| 81 | |
| 82 | hd61830_device_config::hd61830_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock) |
| 83 | : device_config(mconfig, static_alloc_device_config, "Hitachi HD61830", tag, owner, clock), |
| 84 | device_config_memory_interface(mconfig, *this), |
| 85 | m_space_config("videoram", ENDIANNESS_LITTLE, 8, 16, 0, NULL, *ADDRESS_MAP_NAME(hd61830)) |
| 53 | 86 | { |
| 54 | | address_space *ram; /* video RAM memory space */ |
| 55 | | hd61830_rd_read rd_r; |
| 87 | } |
| 56 | 88 | |
| 57 | | int bf; /* busy flag */ |
| 58 | 89 | |
| 59 | | UINT8 ir; /* instruction register */ |
| 60 | | UINT8 mcr; /* mode control register */ |
| 61 | | UINT8 dor; /* data output register */ |
| 90 | //------------------------------------------------- |
| 91 | // static_alloc_device_config - allocate a new |
| 92 | // configuration object |
| 93 | //------------------------------------------------- |
| 62 | 94 | |
| 63 | | UINT16 dsa; /* display start address */ |
| 64 | | UINT16 cac; /* cursor address counter */ |
| 95 | device_config *hd61830_device_config::static_alloc_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock) |
| 96 | { |
| 97 | return global_alloc(hd61830_device_config(mconfig, tag, owner, clock)); |
| 98 | } |
| 65 | 99 | |
| 66 | | int vp; /* vertical character pitch */ |
| 67 | | int hp; /* horizontal character pitch */ |
| 68 | | int hn; /* horizontal number of characters */ |
| 69 | | int nx; /* number of time divisions */ |
| 70 | | int cp; /* cursor position */ |
| 71 | 100 | |
| 72 | | int blink; /* blinking */ |
| 73 | | int cursor; |
| 101 | //------------------------------------------------- |
| 102 | // alloc_device - allocate a new device object |
| 103 | //------------------------------------------------- |
| 74 | 104 | |
| 75 | | /* devices */ |
| 76 | | screen_device *screen; |
| 105 | device_t *hd61830_device_config::alloc_device(running_machine &machine) const |
| 106 | { |
| 107 | return auto_alloc(&machine, hd61830_device(machine, *this)); |
| 108 | } |
| 77 | 109 | |
| 78 | | /* timers */ |
| 79 | | emu_timer *busy_timer; |
| 80 | | }; |
| 81 | 110 | |
| 82 | | /*************************************************************************** |
| 83 | | INLINE FUNCTIONS |
| 84 | | ***************************************************************************/ |
| 111 | //------------------------------------------------- |
| 112 | // memory_space_config - return a description of |
| 113 | // any address spaces owned by this device |
| 114 | //------------------------------------------------- |
| 85 | 115 | |
| 86 | | INLINE hd61830_t *get_safe_token(running_device *device) |
| 116 | const address_space_config *hd61830_device_config::memory_space_config(int spacenum) const |
| 87 | 117 | { |
| 88 | | assert(device != NULL); |
| 89 | | assert(device->type() == HD61830); |
| 90 | | return (hd61830_t *)downcast<legacy_device_base *>(device)->token(); |
| 118 | return (spacenum == 0) ? &m_space_config : NULL; |
| 91 | 119 | } |
| 92 | 120 | |
| 93 | | INLINE const hd61830_interface *get_interface(running_device *device) |
| 121 | |
| 122 | //------------------------------------------------- |
| 123 | // rom_region - device-specific ROM region |
| 124 | //------------------------------------------------- |
| 125 | |
| 126 | const rom_entry *hd61830_device_config::rom_region() const |
| 94 | 127 | { |
| 95 | | assert(device != NULL); |
| 96 | | assert(device->type() == HD61830); |
| 97 | | return (const hd61830_interface *) device->baseconfig().static_config(); |
| 128 | return ROM_NAME(hd61830); |
| 98 | 129 | } |
| 99 | 130 | |
| 100 | | /*************************************************************************** |
| 101 | | IMPLEMENTATION |
| 102 | | ***************************************************************************/ |
| 103 | 131 | |
| 104 | | /*------------------------------------------------- |
| 105 | | TIMER_CALLBACK( busy_tick ) |
| 106 | | -------------------------------------------------*/ |
| 132 | //------------------------------------------------- |
| 133 | // device_config_complete - perform any |
| 134 | // operations now that the configuration is |
| 135 | // complete |
| 136 | //------------------------------------------------- |
| 107 | 137 | |
| 108 | | static TIMER_CALLBACK( busy_tick ) |
| 138 | void hd61830_device_config::device_config_complete() |
| 109 | 139 | { |
| 110 | | running_device *device = (running_device *)ptr; |
| 111 | | hd61830_t *hd61830 = get_safe_token(device); |
| 140 | // inherit a copy of the static data |
| 141 | const hd61830_interface *intf = reinterpret_cast<const hd61830_interface *>(static_config()); |
| 142 | if (intf != NULL) |
| 143 | *static_cast<hd61830_interface *>(this) = *intf; |
| 112 | 144 | |
| 113 | | /* clear busy flag */ |
| 114 | | hd61830->bf = 0; |
| 145 | // or initialize to defaults if none provided |
| 146 | else |
| 147 | { |
| 148 | memset(&m_in_rd_func, 0, sizeof(m_in_rd_func)); |
| 149 | } |
| 115 | 150 | } |
| 116 | 151 | |
| 117 | | /*------------------------------------------------- |
| 118 | | set_busy_flag - set busy flag and arm timer |
| 119 | | to clear it later |
| 120 | | -------------------------------------------------*/ |
| 121 | 152 | |
| 122 | | static void set_busy_flag(hd61830_t *hd61830, int period) |
| 153 | |
| 154 | //************************************************************************** |
| 155 | // INLINE HELPERS |
| 156 | //************************************************************************** |
| 157 | |
| 158 | //------------------------------------------------- |
| 159 | // readbyte - read a byte at the given address |
| 160 | //------------------------------------------------- |
| 161 | |
| 162 | inline UINT8 hd61830_device::readbyte(offs_t address) |
| 123 | 163 | { |
| 124 | | /* set busy flag */ |
| 125 | | hd61830->bf = 1; |
| 164 | return space()->read_byte(address); |
| 165 | } |
| 126 | 166 | |
| 127 | | /* adjust busy timer */ |
| 128 | | timer_adjust_oneshot(hd61830->busy_timer, ATTOTIME_IN_USEC(period), 0); |
| 167 | |
| 168 | //------------------------------------------------- |
| 169 | // writebyte - write a byte at the given address |
| 170 | //------------------------------------------------- |
| 171 | |
| 172 | inline void hd61830_device::writebyte(offs_t address, UINT8 data) |
| 173 | { |
| 174 | space()->write_byte(address, data); |
| 129 | 175 | } |
| 130 | 176 | |
| 131 | | /*------------------------------------------------- |
| 132 | | hd61830_status_r - status read |
| 133 | | -------------------------------------------------*/ |
| 134 | 177 | |
| 135 | | READ8_DEVICE_HANDLER( hd61830_status_r ) |
| 178 | |
| 179 | //************************************************************************** |
| 180 | // LIVE DEVICE |
| 181 | //************************************************************************** |
| 182 | |
| 183 | //------------------------------------------------- |
| 184 | // hd61830_device - constructor |
| 185 | //------------------------------------------------- |
| 186 | |
| 187 | hd61830_device::hd61830_device(running_machine &_machine, const hd61830_device_config &config) |
| 188 | : device_t(_machine, config), |
| 189 | device_memory_interface(_machine, config, *this), |
| 190 | m_config(config) |
| 136 | 191 | { |
| 137 | | hd61830_t *hd61830 = get_safe_token(device); |
| 192 | m_bf = false; |
| 193 | } |
| 138 | 194 | |
| 139 | | if (LOG) logerror("HD61380 '%s' Status Read: %s\n", device->tag(), hd61830->bf ? "busy" : "ready"); |
| 140 | 195 | |
| 141 | | return hd61830->bf << 7; |
| 196 | //------------------------------------------------- |
| 197 | // device_start - device-specific startup |
| 198 | //------------------------------------------------- |
| 199 | |
| 200 | void hd61830_device::device_start() |
| 201 | { |
| 202 | // allocate timers |
| 203 | m_busy_timer = device_timer_alloc(*this); |
| 204 | |
| 205 | // resolve callbacks |
| 206 | devcb_resolve_read8(&m_in_rd_func, &m_config.m_in_rd_func, this); |
| 207 | |
| 208 | // register for state saving |
| 209 | state_save_register_device_item(this, 0, m_bf); |
| 210 | state_save_register_device_item(this, 0, m_ir); |
| 211 | state_save_register_device_item(this, 0, m_mcr); |
| 212 | state_save_register_device_item(this, 0, m_dor); |
| 213 | state_save_register_device_item(this, 0, m_cac); |
| 214 | state_save_register_device_item(this, 0, m_dsa); |
| 215 | state_save_register_device_item(this, 0, m_vp); |
| 216 | state_save_register_device_item(this, 0, m_hp); |
| 217 | state_save_register_device_item(this, 0, m_hn); |
| 218 | state_save_register_device_item(this, 0, m_nx); |
| 219 | state_save_register_device_item(this, 0, m_cp); |
| 220 | state_save_register_device_item(this, 0, m_blink); |
| 221 | state_save_register_device_item(this, 0, m_cursor); |
| 142 | 222 | } |
| 143 | 223 | |
| 144 | | /*------------------------------------------------- |
| 145 | | hd61830_control_w - control write |
| 146 | | -------------------------------------------------*/ |
| 147 | 224 | |
| 148 | | WRITE8_DEVICE_HANDLER( hd61830_control_w ) |
| 225 | //------------------------------------------------- |
| 226 | // device_reset - device-specific reset |
| 227 | //------------------------------------------------- |
| 228 | |
| 229 | void hd61830_device::device_reset() |
| 149 | 230 | { |
| 150 | | hd61830_t *hd61830 = get_safe_token(device); |
| 231 | // display off, slave mode |
| 232 | m_mcr &= ~(MODE_MASTER | MODE_DISPLAY_ON); |
| 151 | 233 | |
| 152 | | hd61830->ir = data; |
| 234 | // default horizontal pitch |
| 235 | m_hp = 6; |
| 153 | 236 | } |
| 154 | 237 | |
| 238 | |
| 239 | //------------------------------------------------- |
| 240 | // device_timer - handler timer events |
| 241 | //------------------------------------------------- |
| 242 | |
| 243 | void hd61830_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) |
| 244 | { |
| 245 | // clear busy flag |
| 246 | m_bf = false; |
| 247 | } |
| 248 | |
| 249 | |
| 155 | 250 | /*------------------------------------------------- |
| 156 | | hd61830_data_r - data read |
| 251 | set_busy_flag - set busy flag and arm timer |
| 252 | to clear it later |
| 157 | 253 | -------------------------------------------------*/ |
| 158 | 254 | |
| 159 | | READ8_DEVICE_HANDLER( hd61830_data_r ) |
| 255 | void hd61830_device::set_busy_flag() |
| 160 | 256 | { |
| 161 | | hd61830_t *hd61830 = get_safe_token(device); |
| 162 | | UINT8 data = hd61830->dor; |
| 257 | // set busy flag |
| 258 | m_bf = true; |
| 163 | 259 | |
| 164 | | if (LOG) logerror("HD61380 '%s' Display Data Read %02x\n", device->tag(), hd61830->dor); |
| 260 | // adjust busy timer |
| 261 | timer_adjust_oneshot(m_busy_timer, ATTOTIME_IN_USEC(CYCLES[m_ir]), 0); |
| 262 | } |
| 165 | 263 | |
| 166 | | hd61830->dor = hd61830->ram->read_byte(hd61830->cac); |
| 167 | 264 | |
| 168 | | hd61830->cac++; |
| 265 | //------------------------------------------------- |
| 266 | // status_r - status register read |
| 267 | //------------------------------------------------- |
| 169 | 268 | |
| 269 | READ8_MEMBER( hd61830_device::status_r ) |
| 270 | { |
| 271 | if (LOG) logerror("HD61830 '%s' Status Read: %s\n", tag(), m_bf ? "busy" : "ready"); |
| 272 | |
| 273 | return m_bf ? 0x80 : 0; |
| 274 | } |
| 275 | |
| 276 | |
| 277 | //------------------------------------------------- |
| 278 | // control_w - instruction register write |
| 279 | //------------------------------------------------- |
| 280 | |
| 281 | WRITE8_MEMBER( hd61830_device::control_w ) |
| 282 | { |
| 283 | m_ir = data; |
| 284 | } |
| 285 | |
| 286 | |
| 287 | //------------------------------------------------- |
| 288 | // data_r - data register read |
| 289 | //------------------------------------------------- |
| 290 | |
| 291 | READ8_MEMBER( hd61830_device::data_r ) |
| 292 | { |
| 293 | UINT8 data = m_dor; |
| 294 | |
| 295 | if (LOG) logerror("HD61830 '%s' Display Data Read %02x\n", tag(), m_dor); |
| 296 | |
| 297 | m_dor = readbyte(m_cac); |
| 298 | |
| 299 | m_cac++; |
| 300 | |
| 170 | 301 | return data; |
| 171 | 302 | } |
| 172 | 303 | |
| 173 | | /*------------------------------------------------- |
| 174 | | hd61830_data_w - data write |
| 175 | | -------------------------------------------------*/ |
| 176 | 304 | |
| 177 | | WRITE8_DEVICE_HANDLER( hd61830_data_w ) |
| 305 | //------------------------------------------------- |
| 306 | // data_w - data register write |
| 307 | //------------------------------------------------- |
| 308 | |
| 309 | WRITE8_MEMBER( hd61830_device::data_w ) |
| 178 | 310 | { |
| 179 | | hd61830_t *hd61830 = get_safe_token(device); |
| 311 | if (m_bf) |
| 312 | { |
| 313 | logerror("HD61830 '%s' Ignoring data write %02x due to business\n", tag(), data); |
| 314 | return; |
| 315 | } |
| 180 | 316 | |
| 181 | | switch (hd61830->ir) |
| 317 | switch (m_ir) |
| 182 | 318 | { |
| 183 | | case HD61830_INSTRUCTION_MODE_CONTROL: |
| 184 | | hd61830->mcr = data; |
| 319 | case INSTRUCTION_MODE_CONTROL: |
| 320 | m_mcr = data; |
| 185 | 321 | |
| 186 | 322 | if (LOG) |
| 187 | 323 | { |
| 188 | | logerror("HD61380 '%s' %s CG\n", device->tag(), (data & HD61830_MODE_EXTERNAL_CG) ? "External" : "Internal"); |
| 189 | | logerror("HD61380 '%s' %s Display Mode\n", device->tag(), (data & HD61830_MODE_GRAPHIC) ? "Graphic" : "Character"); |
| 190 | | logerror("HD61380 '%s' %s Mode\n", device->tag(), (data & HD61830_MODE_MASTER) ? "Master" : "Slave"); |
| 191 | | logerror("HD61380 '%s' Cursor %s\n", device->tag(), (data & HD61830_MODE_CURSOR) ? "On" : "Off"); |
| 192 | | logerror("HD61380 '%s' Blink %s\n", device->tag(), (data & HD61830_MODE_BLINK) ? "On" : "Off"); |
| 193 | | logerror("HD61380 '%s' Display %s\n", device->tag(), (data & HD61830_MODE_DISPLAY_ON) ? "On" : "Off"); |
| 324 | logerror("HD61830 '%s' %s CG\n", tag(), (data & MODE_EXTERNAL_CG) ? "External" : "Internal"); |
| 325 | logerror("HD61830 '%s' %s Display Mode\n", tag(), (data & MODE_GRAPHIC) ? "Graphic" : "Character"); |
| 326 | logerror("HD61830 '%s' %s Mode\n", tag(), (data & MODE_MASTER) ? "Master" : "Slave"); |
| 327 | logerror("HD61830 '%s' Cursor %s\n", tag(), (data & MODE_CURSOR) ? "On" : "Off"); |
| 328 | logerror("HD61830 '%s' Blink %s\n", tag(), (data & MODE_BLINK) ? "On" : "Off"); |
| 329 | logerror("HD61830 '%s' Display %s\n", tag(), (data & MODE_DISPLAY_ON) ? "On" : "Off"); |
| 194 | 330 | } |
| 195 | 331 | break; |
| 196 | 332 | |
| 197 | | case HD61830_INSTRUCTION_CHARACTER_PITCH: |
| 198 | | hd61830->hp = (data & 0x07) + 1; |
| 199 | | hd61830->vp = (data >> 4) + 1; |
| 333 | case INSTRUCTION_CHARACTER_PITCH: |
| 334 | m_hp = (data & 0x07) + 1; |
| 335 | m_vp = (data >> 4) + 1; |
| 200 | 336 | |
| 201 | | if (LOG) logerror("HD61380 '%s' Horizontal Character Pitch: %u\n", device->tag(), hd61830->hp); |
| 202 | | if (LOG) logerror("HD61380 '%s' Vertical Character Pitch: %u\n", device->tag(), hd61830->vp); |
| 337 | if (LOG) logerror("HD61830 '%s' Horizontal Character Pitch: %u\n", tag(), m_hp); |
| 338 | if (LOG) logerror("HD61830 '%s' Vertical Character Pitch: %u\n", tag(), m_vp); |
| 203 | 339 | break; |
| 204 | 340 | |
| 205 | | case HD61830_INSTRUCTION_NUMBER_OF_CHARACTERS: |
| 206 | | hd61830->hn = (data & 0x7f) + 1; |
| 341 | case INSTRUCTION_NUMBER_OF_CHARACTERS: |
| 342 | m_hn = (data & 0x7f) + 1; |
| 207 | 343 | |
| 208 | | if (LOG) logerror("HD61380 '%s' Number of Characters: %u\n", device->tag(), hd61830->hn); |
| 344 | if (LOG) logerror("HD61830 '%s' Number of Characters: %u\n", tag(), m_hn); |
| 209 | 345 | break; |
| 210 | 346 | |
| 211 | | case HD61830_INSTRUCTION_NUMBER_OF_TIME_DIVISIONS: |
| 212 | | hd61830->nx = (data & 0x7f) + 1; |
| 347 | case INSTRUCTION_NUMBER_OF_TIME_DIVISIONS: |
| 348 | m_nx = (data & 0x7f) + 1; |
| 213 | 349 | |
| 214 | | if (LOG) logerror("HD61380 '%s' Number of Time Divisions: %u\n", device->tag(), hd61830->nx); |
| 350 | if (LOG) logerror("HD61830 '%s' Number of Time Divisions: %u\n", tag(), m_nx); |
| 215 | 351 | break; |
| 216 | 352 | |
| 217 | | case HD61830_INSTRUCTION_CURSOR_POSITION: |
| 218 | | hd61830->cp = (data & 0x7f) + 1; |
| 353 | case INSTRUCTION_CURSOR_POSITION: |
| 354 | m_cp = (data & 0x7f) + 1; |
| 219 | 355 | |
| 220 | | if (LOG) logerror("HD61380 '%s' Cursor Position: %u\n", device->tag(), hd61830->cp); |
| 356 | if (LOG) logerror("HD61830 '%s' Cursor Position: %u\n", tag(), m_cp); |
| 221 | 357 | break; |
| 222 | 358 | |
| 223 | | case HD61830_INSTRUCTION_DISPLAY_START_LOW: |
| 224 | | hd61830->dsa = (hd61830->dsa & 0xff00) | data; |
| 359 | case INSTRUCTION_DISPLAY_START_LOW: |
| 360 | m_dsa = (m_dsa & 0xff00) | data; |
| 225 | 361 | |
| 226 | | if (LOG) logerror("HD61380 '%s' Display Start Address Low %04x\n", device->tag(), hd61830->dsa); |
| 362 | if (LOG) logerror("HD61830 '%s' Display Start Address Low %04x\n", tag(), m_dsa); |
| 227 | 363 | break; |
| 228 | 364 | |
| 229 | | case HD61830_INSTRUCTION_DISPLAY_START_HIGH: |
| 230 | | hd61830->dsa = (data << 8) | (hd61830->dsa & 0xff); |
| 365 | case INSTRUCTION_DISPLAY_START_HIGH: |
| 366 | m_dsa = (data << 8) | (m_dsa & 0xff); |
| 231 | 367 | |
| 232 | | if (LOG) logerror("HD61380 '%s' Display Start Address High %04x\n", device->tag(), hd61830->dsa); |
| 368 | if (LOG) logerror("HD61830 '%s' Display Start Address High %04x\n", tag(), m_dsa); |
| 233 | 369 | break; |
| 234 | 370 | |
| 235 | | case HD61830_INSTRUCTION_CURSOR_ADDRESS_LOW: |
| 236 | | if (BIT(hd61830->cac, 7) && !BIT(data, 7)) |
| 371 | case INSTRUCTION_CURSOR_ADDRESS_LOW: |
| 372 | if (BIT(m_cac, 7) && !BIT(data, 7)) |
| 237 | 373 | { |
| 238 | | hd61830->cac = (((hd61830->cac >> 8) + 1) << 8) | data; |
| 374 | m_cac = (((m_cac >> 8) + 1) << 8) | data; |
| 239 | 375 | } |
| 240 | 376 | else |
| 241 | 377 | { |
| 242 | | hd61830->cac = (hd61830->cac & 0xff00) | data; |
| 378 | m_cac = (m_cac & 0xff00) | data; |
| 243 | 379 | } |
| 244 | 380 | |
| 245 | | if (LOG) logerror("HD61380 '%s' Cursor Address Low %02x: %04x\n", device->tag(), data, hd61830->cac); |
| 381 | if (LOG) logerror("HD61830 '%s' Cursor Address Low %02x: %04x\n", tag(), data, m_cac); |
| 246 | 382 | break; |
| 247 | 383 | |
| 248 | | case HD61830_INSTRUCTION_CURSOR_ADDRESS_HIGH: |
| 249 | | hd61830->cac = (data << 8) | (hd61830->cac & 0xff); |
| 384 | case INSTRUCTION_CURSOR_ADDRESS_HIGH: |
| 385 | m_cac = (data << 8) | (m_cac & 0xff); |
| 250 | 386 | |
| 251 | | if (LOG) logerror("HD61380 '%s' Cursor Address High %02x: %04x\n", device->tag(), data, hd61830->cac); |
| 387 | if (LOG) logerror("HD61830 '%s' Cursor Address High %02x: %04x\n", tag(), data, m_cac); |
| 252 | 388 | break; |
| 253 | 389 | |
| 254 | | case HD61830_INSTRUCTION_DISPLAY_DATA_WRITE: |
| 255 | | hd61830->ram->write_byte(hd61830->cac, data); |
| 390 | case INSTRUCTION_DISPLAY_DATA_WRITE: |
| 391 | writebyte(m_cac, data); |
| 256 | 392 | |
| 257 | | if (LOG) logerror("HD61380 '%s' Display Data Write %02x -> %04x row %u col %u\n", device->tag(), data, hd61830->cac, hd61830->cac / 40, hd61830->cac % 40); |
| 393 | if (LOG) logerror("HD61830 '%s' Display Data Write %02x -> %04x row %u col %u\n", tag(), data, m_cac, m_cac / 40, m_cac % 40); |
| 258 | 394 | |
| 259 | | hd61830->cac++; |
| 395 | m_cac++; |
| 260 | 396 | break; |
| 261 | 397 | |
| 262 | | case HD61830_INSTRUCTION_CLEAR_BIT: |
| 398 | case INSTRUCTION_CLEAR_BIT: |
| 263 | 399 | { |
| 264 | | int nb = data & 0x07; |
| 265 | | UINT8 data_ = hd61830->ram->read_byte(hd61830->cac); |
| 400 | int bit = data & 0x07; |
| 401 | UINT8 md = readbyte(m_cac); |
| 266 | 402 | |
| 267 | | data_ &= ~(2 << nb); |
| 403 | md &= ~(1 << bit); |
| 268 | 404 | |
| 269 | | if (LOG) logerror("HD61380 '%s' Clear Bit %u at %04x\n", device->tag(), nb + 1, hd61830->cac); |
| 405 | if (LOG) logerror("HD61830 '%s' Clear Bit %u at %04x\n", tag(), bit + 1, m_cac); |
| 270 | 406 | |
| 271 | | hd61830->ram->write_byte(hd61830->cac, data_); |
| 407 | writebyte(m_cac, md); |
| 272 | 408 | |
| 273 | | hd61830->cac++; |
| 409 | m_cac++; |
| 274 | 410 | } |
| 275 | 411 | break; |
| 276 | 412 | |
| 277 | | case HD61830_INSTRUCTION_SET_BIT: |
| 413 | case INSTRUCTION_SET_BIT: |
| 278 | 414 | { |
| 279 | | int nb = data & 0x07; |
| 280 | | UINT8 data_ = hd61830->ram->read_byte(hd61830->cac); |
| 415 | int bit = data & 0x07; |
| 416 | UINT8 md = readbyte(m_cac); |
| 281 | 417 | |
| 282 | | data_ |= 2 << nb; |
| 418 | md |= 1 << bit; |
| 283 | 419 | |
| 284 | | if (LOG) logerror("HD61380 '%s' Set Bit %u at %04x\n", device->tag(), nb + 1, hd61830->cac); |
| 420 | if (LOG) logerror("HD61830 '%s' Set Bit %u at %04x\n", tag(), bit + 1, m_cac); |
| 285 | 421 | |
| 286 | | hd61830->ram->write_byte(hd61830->cac, data_); |
| 422 | writebyte(m_cac, md); |
| 287 | 423 | |
| 288 | | hd61830->cac++; |
| 424 | m_cac++; |
| 289 | 425 | } |
| 290 | 426 | break; |
| 291 | 427 | |
| 292 | 428 | default: |
| 293 | | logerror("HD61830 '%s' Illegal Instruction %02x!\n", device->tag(), hd61830->ir); |
| 429 | logerror("HD61830 '%s' Illegal Instruction %02x!\n", tag(), m_ir); |
| 294 | 430 | return; |
| 295 | 431 | } |
| 296 | 432 | |
| 297 | | /* burn cycles */ |
| 298 | | set_busy_flag(hd61830, HD61830_CYCLES[hd61830->ir]); |
| 433 | // burn cycles |
| 434 | set_busy_flag(); |
| 299 | 435 | } |
| 300 | 436 | |
| 301 | | /*------------------------------------------------- |
| 302 | | draw_scanline - draw one scanline |
| 303 | | -------------------------------------------------*/ |
| 304 | 437 | |
| 305 | | static void draw_scanline(running_device *device, bitmap_t *bitmap, const rectangle *cliprect, int y, UINT16 ra) |
| 438 | //------------------------------------------------- |
| 439 | // draw_scanline - draw one graphics scanline |
| 440 | //------------------------------------------------- |
| 441 | |
| 442 | void hd61830_device::draw_scanline(bitmap_t *bitmap, const rectangle *cliprect, int y, UINT16 ra) |
| 306 | 443 | { |
| 307 | | hd61830_t *hd61830 = get_safe_token(device); |
| 308 | | |
| 309 | | for (int sx = 0; sx < hd61830->hn; sx++) |
| 444 | for (int sx = 0; sx < m_hn; sx++) |
| 310 | 445 | { |
| 311 | | UINT8 data = hd61830->ram->read_byte(ra++); |
| 446 | UINT8 data = readbyte(ra++); |
| 312 | 447 | |
| 313 | | for (int x = 0; x < hd61830->hp; x++) |
| 448 | for (int x = 0; x < m_hp; x++) |
| 314 | 449 | { |
| 315 | | *BITMAP_ADDR16(bitmap, y, (sx * hd61830->hp) + x) = BIT(data, x); |
| 450 | *BITMAP_ADDR16(bitmap, y, (sx * m_hp) + x) = BIT(data, x); |
| 316 | 451 | } |
| 317 | 452 | } |
| 318 | 453 | } |
| 319 | 454 | |
| 320 | | /*------------------------------------------------- |
| 321 | | update_graphics - draw graphics mode screen |
| 322 | | -------------------------------------------------*/ |
| 323 | 455 | |
| 324 | | static void update_graphics(running_device *device, bitmap_t *bitmap, const rectangle *cliprect) |
| 456 | //------------------------------------------------- |
| 457 | // update_graphics - draw graphics mode screen |
| 458 | //------------------------------------------------- |
| 459 | |
| 460 | void hd61830_device::update_graphics(bitmap_t *bitmap, const rectangle *cliprect) |
| 325 | 461 | { |
| 326 | | hd61830_t *hd61830 = get_safe_token(device); |
| 327 | | |
| 328 | | for (int y = 0; y < hd61830->nx; y++) |
| 462 | for (int y = 0; y < m_nx; y++) |
| 329 | 463 | { |
| 330 | | UINT16 rac1 = hd61830->dsa + (y * hd61830->hn); |
| 331 | | UINT16 rac2 = rac1 + (hd61830->nx * hd61830->hn); |
| 464 | UINT16 rac1 = m_dsa + (y * m_hn); |
| 465 | UINT16 rac2 = rac1 + (m_nx * m_hn); |
| 332 | 466 | |
| 333 | 467 | /* draw upper half scanline */ |
| 334 | | draw_scanline(device, bitmap, cliprect, y, rac1); |
| 468 | draw_scanline(bitmap, cliprect, y, rac1); |
| 335 | 469 | |
| 336 | 470 | /* draw lower half scanline */ |
| 337 | | draw_scanline(device, bitmap, cliprect, y + hd61830->nx, rac2); |
| 471 | draw_scanline(bitmap, cliprect, y + m_nx, rac2); |
| 338 | 472 | } |
| 339 | 473 | } |
| 340 | 474 | |
| 341 | | /*------------------------------------------------- |
| 342 | | draw_char - draw a char |
| 343 | | -------------------------------------------------*/ |
| 344 | 475 | |
| 345 | | static void draw_char(running_device *device, bitmap_t *bitmap, const rectangle *cliprect, UINT16 ma, int x, int y, UINT8 md) |
| 476 | //------------------------------------------------- |
| 477 | // draw_char - draw a char |
| 478 | //------------------------------------------------- |
| 479 | |
| 480 | void hd61830_device::draw_char(bitmap_t *bitmap, const rectangle *cliprect, UINT16 ma, int x, int y, UINT8 md) |
| 346 | 481 | { |
| 347 | | hd61830_t *hd61830 = get_safe_token(device); |
| 348 | | |
| 349 | | for (int cl = 0; cl < hd61830->vp; cl++) |
| 482 | for (int cl = 0; cl < m_vp; cl++) |
| 350 | 483 | { |
| 351 | | for (int cr = 0; cr < hd61830->hp; cr++) |
| 484 | for (int cr = 0; cr < m_hp; cr++) |
| 352 | 485 | { |
| 353 | | int sy = y * hd61830->vp + cl; |
| 354 | | int sx = x * hd61830->hp + cr; |
| 486 | int sy = y * m_vp + cl; |
| 487 | int sx = x * m_hp + cr; |
| 355 | 488 | UINT8 data = 0; |
| 356 | 489 | |
| 357 | | if (hd61830->mcr & HD61830_MODE_EXTERNAL_CG) |
| 490 | if (m_mcr & MODE_EXTERNAL_CG) |
| 358 | 491 | { |
| 359 | | data = hd61830->rd_r(device, (cl << 12) | (ma & 0xfff), md); |
| 492 | data = devcb_call_read8(&m_in_rd_func, (cl << 12) | md); |
| 360 | 493 | } |
| 361 | 494 | else |
| 362 | 495 | { |
| r9369 | r9370 | |
| 378 | 511 | addr = 160*7 + (md - 0xe0) * 11 + cl; |
| 379 | 512 | } |
| 380 | 513 | |
| 381 | | data = device->subregion("hd61830")->u8(addr); |
| 514 | data = subregion("hd61830")->u8(addr); |
| 382 | 515 | } |
| 383 | 516 | |
| 384 | | int cursor = hd61830->mcr & HD61830_MODE_CURSOR; |
| 385 | | int blink = hd61830->mcr & HD61830_MODE_BLINK; |
| 517 | int cursor = m_mcr & MODE_CURSOR; |
| 518 | int blink = m_mcr & MODE_BLINK; |
| 386 | 519 | |
| 387 | 520 | // cursor off |
| 388 | 521 | int pixel = BIT(data, cr); |
| 389 | 522 | |
| 390 | | if (blink && (ma == hd61830->cac)) |
| 523 | if (blink && (ma == m_cac)) |
| 391 | 524 | { |
| 392 | 525 | // cursor off, character blink |
| 393 | 526 | if (!cursor) |
| 394 | | pixel = hd61830->cursor ? pixel : 0; |
| 527 | pixel = m_cursor ? pixel : 0; |
| 395 | 528 | |
| 396 | 529 | // cursor blink |
| 397 | | if (cursor && (cl == hd61830->cp)) |
| 398 | | pixel = hd61830->cursor; |
| 530 | if (cursor && (cl == m_cp)) |
| 531 | pixel = m_cursor ? 1 : 0; |
| 399 | 532 | } |
| 400 | 533 | else |
| 401 | 534 | { |
| 402 | 535 | // cursor on |
| 403 | | if (cursor && (cl == hd61830->cp)) |
| 404 | | pixel = hd61830->cursor; |
| 536 | if (cursor && (cl == m_cp)) |
| 537 | pixel = m_cursor ? 1 : 0; |
| 405 | 538 | } |
| 406 | 539 | |
| 407 | 540 | *BITMAP_ADDR16(bitmap, sy, sx) = pixel; |
| r9369 | r9370 | |
| 409 | 542 | } |
| 410 | 543 | } |
| 411 | 544 | |
| 412 | | /*------------------------------------------------- |
| 413 | | update_text - draw text mode screen |
| 414 | | -------------------------------------------------*/ |
| 415 | 545 | |
| 416 | | static void update_text(running_device *device, bitmap_t *bitmap, const rectangle *cliprect) |
| 546 | //------------------------------------------------- |
| 547 | // update_text - draw text mode screen |
| 548 | //------------------------------------------------- |
| 549 | |
| 550 | void hd61830_device::update_text(bitmap_t *bitmap, const rectangle *cliprect) |
| 417 | 551 | { |
| 418 | | hd61830_t *hd61830 = get_safe_token(device); |
| 419 | | |
| 420 | | for (int y = 0; y < (hd61830->nx / hd61830->vp); y++) |
| 552 | for (int y = 0; y < (m_nx / m_vp); y++) |
| 421 | 553 | { |
| 422 | | for (int x = 0; x < hd61830->hn; x++) |
| 554 | for (int x = 0; x < m_hn; x++) |
| 423 | 555 | { |
| 424 | | UINT16 ma = y * hd61830->hn + x; |
| 425 | | UINT8 md = hd61830->ram->read_byte(ma); |
| 556 | UINT16 ma = y * m_hn + x; |
| 557 | UINT8 md = readbyte(ma); |
| 426 | 558 | |
| 427 | | draw_char(device, bitmap, cliprect, ma, x, y, md); |
| 559 | draw_char(bitmap, cliprect, ma, x, y, md); |
| 428 | 560 | } |
| 429 | 561 | } |
| 430 | 562 | } |
| 431 | 563 | |
| 432 | | /*------------------------------------------------- |
| 433 | | hd61830_update - update screen |
| 434 | | -------------------------------------------------*/ |
| 435 | 564 | |
| 436 | | void hd61830_update(running_device *device, bitmap_t *bitmap, const rectangle *cliprect) |
| 565 | //------------------------------------------------- |
| 566 | // update_screen - update screen |
| 567 | //------------------------------------------------- |
| 568 | |
| 569 | void hd61830_device::update_screen(bitmap_t *bitmap, const rectangle *cliprect) |
| 437 | 570 | { |
| 438 | | hd61830_t *hd61830 = get_safe_token(device); |
| 439 | | |
| 440 | | if (hd61830->mcr & HD61830_MODE_DISPLAY_ON) |
| 571 | if (m_mcr & MODE_DISPLAY_ON) |
| 441 | 572 | { |
| 442 | | if (hd61830->mcr & HD61830_MODE_GRAPHIC) |
| 573 | if (m_mcr & MODE_GRAPHIC) |
| 443 | 574 | { |
| 444 | | update_graphics(device, bitmap, cliprect); |
| 575 | update_graphics(bitmap, cliprect); |
| 445 | 576 | } |
| 446 | 577 | else |
| 447 | 578 | { |
| 448 | | update_text(device, bitmap, cliprect); |
| 579 | update_text(bitmap, cliprect); |
| 449 | 580 | } |
| 450 | 581 | } |
| 451 | 582 | else |
| r9369 | r9370 | |
| 453 | 584 | bitmap_fill(bitmap, cliprect, 0); |
| 454 | 585 | } |
| 455 | 586 | |
| 456 | | hd61830->blink++; |
| 587 | m_blink++; |
| 457 | 588 | |
| 458 | | if (hd61830->blink == 0x20) |
| 589 | if (m_blink == 0x20) |
| 459 | 590 | { |
| 460 | | hd61830->blink = 0; |
| 461 | | hd61830->cursor = !hd61830->cursor; |
| 591 | m_blink = 0; |
| 592 | m_cursor = !m_cursor; |
| 462 | 593 | } |
| 463 | 594 | } |
| 464 | | |
| 465 | | /*------------------------------------------------- |
| 466 | | hd61830_r - register read |
| 467 | | -------------------------------------------------*/ |
| 468 | | |
| 469 | | READ8_DEVICE_HANDLER( hd61830_r ) |
| 470 | | { |
| 471 | | return (offset & 0x01) ? hd61830_status_r(device, offset) : hd61830_data_r(device, offset); |
| 472 | | } |
| 473 | | |
| 474 | | /*------------------------------------------------- |
| 475 | | hd61830_w - register write |
| 476 | | -------------------------------------------------*/ |
| 477 | | |
| 478 | | WRITE8_DEVICE_HANDLER( hd61830_w ) |
| 479 | | { |
| 480 | | (offset & 0x01) ? hd61830_control_w(device, offset, data) : hd61830_data_w(device, offset, data); |
| 481 | | } |
| 482 | | |
| 483 | | /*------------------------------------------------- |
| 484 | | ROM( hd61830 ) |
| 485 | | -------------------------------------------------*/ |
| 486 | | |
| 487 | | ROM_START( hd61830 ) |
| 488 | | ROM_REGION( 0x5c0, "hd61830", ROMREGION_LOADBYNAME ) // internal 7360-bit chargen ROM |
| 489 | | ROM_LOAD( "hd61830.bin", 0x000, 0x5c0, BAD_DUMP CRC(06a934da) SHA1(bf3f074db5dc92e6f530cb18d6c013563099a87d) ) // typed in from manual |
| 490 | | ROM_END |
| 491 | | |
| 492 | | /*------------------------------------------------- |
| 493 | | ADDRESS_MAP( hd61830 ) |
| 494 | | -------------------------------------------------*/ |
| 495 | | |
| 496 | | static ADDRESS_MAP_START( hd61380_ram, 0, 8 ) |
| 497 | | AM_RANGE(0x0000, 0xffff) AM_RAM |
| 498 | | ADDRESS_MAP_END |
| 499 | | |
| 500 | | /*------------------------------------------------- |
| 501 | | DEVICE_START( hd61830 ) |
| 502 | | -------------------------------------------------*/ |
| 503 | | |
| 504 | | static DEVICE_START( hd61830 ) |
| 505 | | { |
| 506 | | hd61830_t *hd61830 = get_safe_token(device); |
| 507 | | const hd61830_interface *intf = get_interface(device); |
| 508 | | |
| 509 | | hd61830->rd_r = intf->rd_r; |
| 510 | | |
| 511 | | /* get the screen device */ |
| 512 | | hd61830->screen = device->machine->device<screen_device>(intf->screen_tag); |
| 513 | | assert(hd61830->screen != NULL); |
| 514 | | |
| 515 | | hd61830->ram = device_get_space(device, ADDRESS_SPACE_0); |
| 516 | | |
| 517 | | /* create the busy timer */ |
| 518 | | hd61830->busy_timer = timer_alloc(device->machine, busy_tick, (void *)device); |
| 519 | | |
| 520 | | /* register for state saving */ |
| 521 | | state_save_register_device_item(device, 0, hd61830->bf); |
| 522 | | state_save_register_device_item(device, 0, hd61830->ir); |
| 523 | | state_save_register_device_item(device, 0, hd61830->mcr); |
| 524 | | state_save_register_device_item(device, 0, hd61830->dor); |
| 525 | | state_save_register_device_item(device, 0, hd61830->cac); |
| 526 | | state_save_register_device_item(device, 0, hd61830->dsa); |
| 527 | | state_save_register_device_item(device, 0, hd61830->vp); |
| 528 | | state_save_register_device_item(device, 0, hd61830->hp); |
| 529 | | state_save_register_device_item(device, 0, hd61830->hn); |
| 530 | | state_save_register_device_item(device, 0, hd61830->nx); |
| 531 | | state_save_register_device_item(device, 0, hd61830->cp); |
| 532 | | state_save_register_device_item(device, 0, hd61830->blink); |
| 533 | | state_save_register_device_item(device, 0, hd61830->cursor); |
| 534 | | } |
| 535 | | |
| 536 | | /*------------------------------------------------- |
| 537 | | DEVICE_RESET( hd61830 ) |
| 538 | | -------------------------------------------------*/ |
| 539 | | |
| 540 | | static DEVICE_RESET( hd61830 ) |
| 541 | | { |
| 542 | | hd61830_t *hd61830 = get_safe_token(device); |
| 543 | | |
| 544 | | hd61830->mcr = hd61830->mcr & ~(HD61830_MODE_MASTER | HD61830_MODE_DISPLAY_ON); |
| 545 | | hd61830->hp = 6; |
| 546 | | } |
| 547 | | |
| 548 | | /*------------------------------------------------- |
| 549 | | DEVICE_GET_INFO( hd61830 ) |
| 550 | | -------------------------------------------------*/ |
| 551 | | |
| 552 | | DEVICE_GET_INFO( hd61830 ) |
| 553 | | { |
| 554 | | switch (state) |
| 555 | | { |
| 556 | | /* --- the following bits of info are returned as 64-bit signed integers --- */ |
| 557 | | case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(hd61830_t); break; |
| 558 | | case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = 0; break; |
| 559 | | case DEVINFO_INT_DATABUS_WIDTH_0: info->i = 8; break; |
| 560 | | case DEVINFO_INT_ADDRBUS_WIDTH_0: info->i = 16; break; |
| 561 | | case DEVINFO_INT_ADDRBUS_SHIFT_0: info->i = 0; break; |
| 562 | | |
| 563 | | /* --- the following bits of info are returned as pointers --- */ |
| 564 | | case DEVINFO_PTR_ROM_REGION: info->romregion = ROM_NAME(hd61830); break; |
| 565 | | |
| 566 | | /* --- the following bits of info are returned as pointers to data --- */ |
| 567 | | case DEVINFO_PTR_DEFAULT_MEMORY_MAP_0: info->default_map8 = ADDRESS_MAP_NAME(hd61380_ram); break; |
| 568 | | |
| 569 | | /* --- the following bits of info are returned as pointers to functions --- */ |
| 570 | | case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(hd61830); break; |
| 571 | | case DEVINFO_FCT_STOP: /* Nothing */ break; |
| 572 | | case DEVINFO_FCT_RESET: info->reset = DEVICE_RESET_NAME(hd61830); break; |
| 573 | | |
| 574 | | /* --- the following bits of info are returned as NULL-terminated strings --- */ |
| 575 | | case DEVINFO_STR_NAME: strcpy(info->s, "Hitachi HD61830"); break; |
| 576 | | case DEVINFO_STR_FAMILY: strcpy(info->s, "Hitachi HD61830"); break; |
| 577 | | case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break; |
| 578 | | case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break; |
| 579 | | case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright MESS Team"); break; |
| 580 | | } |
| 581 | | } |
| 582 | | |
| 583 | | DEFINE_LEGACY_MEMORY_DEVICE(HD61830, hd61830); |
src/mess/drivers/portfoli.c
| r9369 | r9370 | |
| 42 | 42 | |
| 43 | 43 | */ |
| 44 | 44 | |
| 45 | #define ADDRESS_MAP_MODERN |
| 46 | |
| 45 | 47 | #include "emu.h" |
| 46 | 48 | #include "includes/portfoli.h" |
| 47 | 49 | #include "cpu/i86/i86.h" |
| r9369 | r9370 | |
| 87 | 89 | // check_interrupt - check interrupt status |
| 88 | 90 | //------------------------------------------------- |
| 89 | 91 | |
| 90 | | static void check_interrupt(running_machine *machine) |
| 92 | void portfolio_state::check_interrupt() |
| 91 | 93 | { |
| 92 | | portfolio_state *state = machine->driver_data<portfolio_state>(); |
| 93 | | |
| 94 | | int level = (state->ip & state->ie) ? ASSERT_LINE : CLEAR_LINE; |
| 94 | int level = (m_ip & m_ie) ? ASSERT_LINE : CLEAR_LINE; |
| 95 | 95 | |
| 96 | | cputag_set_input_line(machine, M80C88A_TAG, INPUT_LINE_INT0, level); |
| 96 | cpu_set_input_line(m_maincpu, INPUT_LINE_INT0, level); |
| 97 | 97 | } |
| 98 | 98 | |
| 99 | 99 | //------------------------------------------------- |
| 100 | 100 | // trigger_interrupt - trigger interrupt request |
| 101 | 101 | //------------------------------------------------- |
| 102 | 102 | |
| 103 | | static void trigger_interrupt(running_machine *machine, int level) |
| 103 | void portfolio_state::trigger_interrupt(int level) |
| 104 | 104 | { |
| 105 | | portfolio_state *state = machine->driver_data<portfolio_state>(); |
| 106 | | |
| 107 | 105 | // set interrupt pending bit |
| 108 | | state->ip |= 1 << level; |
| 106 | m_ip |= 1 << level; |
| 109 | 107 | |
| 110 | | check_interrupt(machine); |
| 108 | check_interrupt(); |
| 111 | 109 | } |
| 112 | 110 | |
| 113 | 111 | //------------------------------------------------- |
| 114 | 112 | // irq_status_r - interrupt status read |
| 115 | 113 | //------------------------------------------------- |
| 116 | 114 | |
| 117 | | static READ8_HANDLER( irq_status_r ) |
| 115 | READ8_MEMBER( portfolio_state::irq_status_r ) |
| 118 | 116 | { |
| 119 | | portfolio_state *state = space->machine->driver_data<portfolio_state>(); |
| 120 | | |
| 121 | | return state->ip; |
| 117 | return m_ip; |
| 122 | 118 | } |
| 123 | 119 | |
| 124 | 120 | //------------------------------------------------- |
| 125 | 121 | // irq_mask_w - interrupt enable mask |
| 126 | 122 | //------------------------------------------------- |
| 127 | 123 | |
| 128 | | static WRITE8_HANDLER( irq_mask_w ) |
| 124 | WRITE8_MEMBER( portfolio_state::irq_mask_w ) |
| 129 | 125 | { |
| 130 | | portfolio_state *state = space->machine->driver_data<portfolio_state>(); |
| 131 | | |
| 132 | | state->ie = data; |
| 126 | m_ie = data; |
| 133 | 127 | //logerror("IE %02x\n", data); |
| 134 | 128 | |
| 135 | | check_interrupt(space->machine); |
| 129 | check_interrupt(); |
| 136 | 130 | } |
| 137 | 131 | |
| 138 | 132 | //------------------------------------------------- |
| 139 | 133 | // sivr_w - serial interrupt vector register |
| 140 | 134 | //------------------------------------------------- |
| 141 | 135 | |
| 142 | | static WRITE8_HANDLER( sivr_w ) |
| 136 | WRITE8_MEMBER( portfolio_state::sivr_w ) |
| 143 | 137 | { |
| 144 | | portfolio_state *state = space->machine->driver_data<portfolio_state>(); |
| 145 | | |
| 146 | | state->sivr = data; |
| 138 | m_sivr = data; |
| 147 | 139 | //logerror("SIVR %02x\n", data); |
| 148 | 140 | } |
| 149 | 141 | |
| r9369 | r9370 | |
| 151 | 143 | // IRQ_CALLBACK( portfolio_int_ack ) |
| 152 | 144 | //------------------------------------------------- |
| 153 | 145 | |
| 154 | | static IRQ_CALLBACK( portfolio_int_ack ) |
| 146 | IRQ_CALLBACK( portfolio_int_ack ) |
| 155 | 147 | { |
| 156 | 148 | portfolio_state *state = device->machine->driver_data<portfolio_state>(); |
| 157 | 149 | |
| 158 | | UINT8 vector = state->sivr; |
| 150 | UINT8 vector = state->m_sivr; |
| 159 | 151 | |
| 160 | 152 | for (int i = 0; i < 4; i++) |
| 161 | 153 | { |
| 162 | | if (BIT(state->ip, i)) |
| 154 | if (BIT(state->m_ip, i)) |
| 163 | 155 | { |
| 164 | 156 | // clear interrupt pending bit |
| 165 | | state->ip &= ~(1 << i); |
| 157 | state->m_ip &= ~(1 << i); |
| 166 | 158 | |
| 167 | 159 | if (i == 3) |
| 168 | | vector = state->sivr; |
| 160 | vector = state->m_sivr; |
| 169 | 161 | else |
| 170 | 162 | vector = INTERRUPT_VECTOR[i]; |
| 171 | 163 | |
| r9369 | r9370 | |
| 173 | 165 | } |
| 174 | 166 | } |
| 175 | 167 | |
| 176 | | check_interrupt(device->machine); |
| 168 | state->check_interrupt(); |
| 177 | 169 | |
| 178 | 170 | return vector; |
| 179 | 171 | } |
| r9369 | r9370 | |
| 186 | 178 | // scan_keyboard - scan keyboard |
| 187 | 179 | //------------------------------------------------- |
| 188 | 180 | |
| 189 | | static void scan_keyboard(running_machine *machine) |
| 181 | void portfolio_state::scan_keyboard() |
| 190 | 182 | { |
| 191 | | portfolio_state *state = machine->driver_data<portfolio_state>(); |
| 192 | | |
| 193 | 183 | UINT8 keycode = 0xff; |
| 194 | 184 | |
| 195 | 185 | static const char *const keynames[] = { "ROW0", "ROW1", "ROW2", "ROW3", "ROW4", "ROW5", "ROW6", "ROW7" }; |
| 196 | 186 | |
| 197 | 187 | for (int row = 0; row < 8; row++) |
| 198 | 188 | { |
| 199 | | UINT8 data = input_port_read(machine, keynames[row]); |
| 189 | UINT8 data = input_port_read(&m_machine, keynames[row]); |
| 200 | 190 | |
| 201 | 191 | if (data != 0xff) |
| 202 | 192 | { |
| r9369 | r9370 | |
| 213 | 203 | if (keycode != 0xff) |
| 214 | 204 | { |
| 215 | 205 | // key pressed |
| 216 | | if (keycode != state->keylatch) |
| 206 | if (keycode != m_keylatch) |
| 217 | 207 | { |
| 218 | | state->keylatch = keycode; |
| 208 | m_keylatch = keycode; |
| 219 | 209 | |
| 220 | | trigger_interrupt(machine, INT_KEYBOARD); |
| 210 | trigger_interrupt(INT_KEYBOARD); |
| 221 | 211 | } |
| 222 | 212 | } |
| 223 | 213 | else |
| 224 | 214 | { |
| 225 | 215 | // key released |
| 226 | | if (state->keylatch != 0xff) |
| 216 | if (m_keylatch != 0xff) |
| 227 | 217 | { |
| 228 | | state->keylatch |= 0x80; |
| 218 | m_keylatch |= 0x80; |
| 229 | 219 | |
| 230 | | trigger_interrupt(machine, INT_KEYBOARD); |
| 220 | trigger_interrupt(INT_KEYBOARD); |
| 231 | 221 | } |
| 232 | 222 | } |
| 233 | 223 | } |
| r9369 | r9370 | |
| 236 | 226 | // TIMER_DEVICE_CALLBACK( keyboard_tick ) |
| 237 | 227 | //------------------------------------------------- |
| 238 | 228 | |
| 239 | | static TIMER_DEVICE_CALLBACK( keyboard_tick ) |
| 229 | TIMER_DEVICE_CALLBACK( keyboard_tick ) |
| 240 | 230 | { |
| 241 | | scan_keyboard(timer.machine); |
| 231 | portfolio_state *state = timer.machine->driver_data<portfolio_state>(); |
| 232 | |
| 233 | state->scan_keyboard(); |
| 242 | 234 | } |
| 243 | 235 | |
| 244 | 236 | //------------------------------------------------- |
| 245 | 237 | // keyboard_r - keyboard scan code register |
| 246 | 238 | //------------------------------------------------- |
| 247 | 239 | |
| 248 | | static READ8_HANDLER( keyboard_r ) |
| 240 | READ8_MEMBER( portfolio_state::keyboard_r ) |
| 249 | 241 | { |
| 250 | | portfolio_state *state = space->machine->driver_data<portfolio_state>(); |
| 251 | | |
| 252 | | return state->keylatch; |
| 242 | return m_keylatch; |
| 253 | 243 | } |
| 254 | 244 | |
| 255 | 245 | //************************************************************************** |
| r9369 | r9370 | |
| 260 | 250 | // speaker_w - internal speaker output |
| 261 | 251 | //------------------------------------------------- |
| 262 | 252 | |
| 263 | | static WRITE8_HANDLER( speaker_w ) |
| 253 | WRITE8_MEMBER( portfolio_state::speaker_w ) |
| 264 | 254 | { |
| 265 | 255 | /* |
| 266 | 256 | |
| r9369 | r9370 | |
| 277 | 267 | |
| 278 | 268 | */ |
| 279 | 269 | |
| 280 | | portfolio_state *state = space->machine->driver_data<portfolio_state>(); |
| 270 | speaker_level_w(m_speaker, !BIT(data, 7)); |
| 281 | 271 | |
| 282 | | speaker_level_w(state->speaker, !BIT(data, 7)); |
| 283 | | |
| 284 | 272 | //logerror("SPEAKER %02x\n", data); |
| 285 | 273 | } |
| 286 | 274 | |
| r9369 | r9370 | |
| 292 | 280 | // power_w - power management |
| 293 | 281 | //------------------------------------------------- |
| 294 | 282 | |
| 295 | | static WRITE8_HANDLER( power_w ) |
| 283 | WRITE8_MEMBER( portfolio_state::power_w ) |
| 296 | 284 | { |
| 297 | 285 | /* |
| 298 | 286 | |
| r9369 | r9370 | |
| 316 | 304 | // battery_r - battery status |
| 317 | 305 | //------------------------------------------------- |
| 318 | 306 | |
| 319 | | static READ8_HANDLER( battery_r ) |
| 307 | READ8_MEMBER( portfolio_state::battery_r ) |
| 320 | 308 | { |
| 321 | 309 | /* |
| 322 | 310 | |
| r9369 | r9370 | |
| 333 | 321 | |
| 334 | 322 | */ |
| 335 | 323 | |
| 336 | | portfolio_state *state = space->machine->driver_data<portfolio_state>(); |
| 337 | | |
| 338 | 324 | UINT8 data = 0; |
| 339 | 325 | |
| 340 | 326 | /* peripheral detect */ |
| 341 | | data |= (state->pid != PID_NONE) << 5; |
| 327 | data |= (m_pid != PID_NONE) << 5; |
| 342 | 328 | |
| 343 | 329 | /* battery status */ |
| 344 | | data |= BIT(input_port_read(space->machine, "BATTERY"), 0) << 6; |
| 330 | data |= BIT(input_port_read(&m_machine, "BATTERY"), 0) << 6; |
| 345 | 331 | |
| 346 | 332 | return data; |
| 347 | 333 | } |
| r9369 | r9370 | |
| 350 | 336 | // unknown_w - ? |
| 351 | 337 | //------------------------------------------------- |
| 352 | 338 | |
| 353 | | static WRITE8_HANDLER( unknown_w ) |
| 339 | WRITE8_MEMBER( portfolio_state::unknown_w ) |
| 354 | 340 | { |
| 355 | 341 | //logerror("UNKNOWN %02x\n", data); |
| 356 | 342 | } |
| r9369 | r9370 | |
| 363 | 349 | // TIMER_DEVICE_CALLBACK( system_tick ) |
| 364 | 350 | //------------------------------------------------- |
| 365 | 351 | |
| 366 | | static TIMER_DEVICE_CALLBACK( system_tick ) |
| 352 | TIMER_DEVICE_CALLBACK( system_tick ) |
| 367 | 353 | { |
| 368 | | trigger_interrupt(timer.machine, INT_TICK); |
| 354 | portfolio_state *state = timer.machine->driver_data<portfolio_state>(); |
| 355 | |
| 356 | state->trigger_interrupt(INT_TICK); |
| 369 | 357 | } |
| 370 | 358 | |
| 371 | 359 | //------------------------------------------------- |
| 372 | 360 | // TIMER_DEVICE_CALLBACK( counter_tick ) |
| 373 | 361 | //------------------------------------------------- |
| 374 | 362 | |
| 375 | | static TIMER_DEVICE_CALLBACK( counter_tick ) |
| 363 | TIMER_DEVICE_CALLBACK( counter_tick ) |
| 376 | 364 | { |
| 377 | 365 | portfolio_state *state = timer.machine->driver_data<portfolio_state>(); |
| 378 | 366 | |
| 379 | | state->counter++; |
| 367 | state->m_counter++; |
| 380 | 368 | } |
| 381 | 369 | |
| 382 | 370 | //------------------------------------------------- |
| 383 | 371 | // counter_r - counter register read |
| 384 | 372 | //------------------------------------------------- |
| 385 | 373 | |
| 386 | | static READ8_HANDLER( counter_r ) |
| 374 | READ8_MEMBER( portfolio_state::counter_r ) |
| 387 | 375 | { |
| 388 | | portfolio_state *state = space->machine->driver_data<portfolio_state>(); |
| 389 | | |
| 390 | 376 | UINT8 data = 0; |
| 391 | 377 | |
| 392 | 378 | switch (offset) |
| 393 | 379 | { |
| 394 | 380 | case 0: |
| 395 | | data = state->counter & 0xff; |
| 381 | data = m_counter & 0xff; |
| 396 | 382 | break; |
| 397 | 383 | |
| 398 | 384 | case 1: |
| 399 | | data = state->counter >> 1; |
| 385 | data = m_counter >> 1; |
| 400 | 386 | break; |
| 401 | 387 | } |
| 402 | 388 | |
| r9369 | r9370 | |
| 407 | 393 | // counter_w - counter register write |
| 408 | 394 | //------------------------------------------------- |
| 409 | 395 | |
| 410 | | static WRITE8_HANDLER( counter_w ) |
| 396 | WRITE8_MEMBER( portfolio_state::counter_w ) |
| 411 | 397 | { |
| 412 | | portfolio_state *state = space->machine->driver_data<portfolio_state>(); |
| 413 | | |
| 414 | 398 | switch (offset) |
| 415 | 399 | { |
| 416 | 400 | case 0: |
| 417 | | state->counter = (state->counter & 0xff00) | data; |
| 401 | m_counter = (m_counter & 0xff00) | data; |
| 418 | 402 | break; |
| 419 | 403 | |
| 420 | 404 | case 1: |
| 421 | | state->counter = (data << 8) | (state->counter & 0xff); |
| 405 | m_counter = (data << 8) | (m_counter & 0xff); |
| 422 | 406 | break; |
| 423 | 407 | } |
| 424 | 408 | } |
| r9369 | r9370 | |
| 431 | 415 | // ncc1_w - credit card memory select |
| 432 | 416 | //------------------------------------------------- |
| 433 | 417 | |
| 434 | | static WRITE8_HANDLER( ncc1_w ) |
| 418 | WRITE8_MEMBER( portfolio_state::ncc1_w ) |
| 435 | 419 | { |
| 436 | | address_space *program = cputag_get_address_space(space->machine, M80C88A_TAG, ADDRESS_SPACE_PROGRAM); |
| 420 | address_space *program = cpu_get_address_space(m_maincpu, ADDRESS_SPACE_PROGRAM); |
| 437 | 421 | |
| 438 | 422 | if (BIT(data, 0)) |
| 439 | 423 | { |
| 440 | 424 | // system ROM |
| 441 | | UINT8 *rom = memory_region(space->machine, M80C88A_TAG); |
| 425 | UINT8 *rom = memory_region(&m_machine, M80C88A_TAG); |
| 442 | 426 | memory_install_rom(program, 0xc0000, 0xdffff, 0, 0, rom); |
| 443 | 427 | } |
| 444 | 428 | else |
| r9369 | r9370 | |
| 454 | 438 | // pid_r - peripheral identification |
| 455 | 439 | //------------------------------------------------- |
| 456 | 440 | |
| 457 | | static READ8_HANDLER( pid_r ) |
| 441 | READ8_MEMBER( portfolio_state::pid_r ) |
| 458 | 442 | { |
| 459 | 443 | /* |
| 460 | 444 | |
| r9369 | r9370 | |
| 472 | 456 | |
| 473 | 457 | */ |
| 474 | 458 | |
| 475 | | portfolio_state *state = space->machine->driver_data<portfolio_state>(); |
| 476 | | |
| 477 | | return state->pid; |
| 459 | return m_pid; |
| 478 | 460 | } |
| 479 | 461 | |
| 480 | 462 | //************************************************************************** |
| r9369 | r9370 | |
| 485 | 467 | // ADDRESS_MAP( portfolio_mem ) |
| 486 | 468 | //------------------------------------------------- |
| 487 | 469 | |
| 488 | | static ADDRESS_MAP_START( portfolio_mem, ADDRESS_SPACE_PROGRAM, 8 ) |
| 470 | static ADDRESS_MAP_START( portfolio_mem, ADDRESS_SPACE_PROGRAM, 8, portfolio_state ) |
| 489 | 471 | AM_RANGE(0x00000, 0x1efff) AM_RAM AM_SHARE("nvram1") |
| 490 | 472 | AM_RANGE(0x1f000, 0x9efff) AM_RAM // expansion |
| 491 | 473 | AM_RANGE(0xb0000, 0xb0fff) AM_MIRROR(0xf000) AM_RAM AM_SHARE("nvram2") // video RAM |
| r9369 | r9370 | |
| 497 | 479 | // ADDRESS_MAP( portfolio_io ) |
| 498 | 480 | //------------------------------------------------- |
| 499 | 481 | |
| 500 | | static ADDRESS_MAP_START( portfolio_io, ADDRESS_SPACE_IO, 8 ) |
| 482 | static ADDRESS_MAP_START( portfolio_io, ADDRESS_SPACE_IO, 8, portfolio_state ) |
| 501 | 483 | AM_RANGE(0x8000, 0x8000) AM_READ(keyboard_r) |
| 502 | | AM_RANGE(0x8010, 0x8010) AM_DEVREADWRITE(HD61830_TAG, hd61830_data_r, hd61830_data_w) |
| 503 | | AM_RANGE(0x8011, 0x8011) AM_DEVREADWRITE(HD61830_TAG, hd61830_status_r, hd61830_control_w) |
| 484 | AM_RANGE(0x8010, 0x8010) AM_DEVREADWRITE(HD61830_TAG, hd61830_device, data_r, data_w) |
| 485 | AM_RANGE(0x8011, 0x8011) AM_DEVREADWRITE(HD61830_TAG, hd61830_device, status_r, control_w) |
| 504 | 486 | AM_RANGE(0x8020, 0x8020) AM_WRITE(speaker_w) |
| 505 | 487 | AM_RANGE(0x8030, 0x8030) AM_WRITE(power_w) |
| 506 | 488 | AM_RANGE(0x8040, 0x8041) AM_READWRITE(counter_r, counter_w) |
| 507 | 489 | AM_RANGE(0x8050, 0x8050) AM_READWRITE(irq_status_r, irq_mask_w) |
| 508 | 490 | AM_RANGE(0x8051, 0x8051) AM_READWRITE(battery_r, unknown_w) |
| 509 | | AM_RANGE(0x8060, 0x8060) AM_RAM AM_BASE_MEMBER(portfolio_state, contrast) |
| 510 | | // AM_RANGE(0x8070, 0x8077) AM_DEVREADWRITE(M82C50A_TAG, ins8250_r, ins8250_w) Serial Interface |
| 511 | | // AM_RANGE(0x8078, 0x807b) AM_DEVREADWRITE(M82C55A_TAG, i8255a_r, i8255a_w) Parallel Interface |
| 491 | AM_RANGE(0x8060, 0x8060) AM_RAM AM_BASE(m_contrast) |
| 492 | // AM_RANGE(0x8070, 0x8077) AM_DEVREADWRITE_LEGACY(M82C50A_TAG, ins8250_r, ins8250_w) // Serial Interface |
| 493 | // AM_RANGE(0x8078, 0x807b) AM_DEVREADWRITE_LEGACY(M82C55A_TAG, i8255a_r, i8255a_w) // Parallel Interface |
| 512 | 494 | AM_RANGE(0x807c, 0x807c) AM_WRITE(ncc1_w) |
| 513 | 495 | AM_RANGE(0x807f, 0x807f) AM_READWRITE(pid_r, sivr_w) |
| 514 | 496 | ADDRESS_MAP_END |
| r9369 | r9370 | |
| 602 | 584 | PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_A) PORT_CHAR('a') PORT_CHAR('A') |
| 603 | 585 | PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Esc") PORT_CODE(KEYCODE_ESC) PORT_CHAR(UCHAR_MAMEKEY(ESC)) |
| 604 | 586 | |
| 587 | PORT_START("PPI-PB") |
| 588 | PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_SPECIAL) PORT_WRITE_LINE_DEVICE(CENTRONICS_TAG, centronics_strobe_w) |
| 589 | PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_SPECIAL) PORT_WRITE_LINE_DEVICE(CENTRONICS_TAG, centronics_autofeed_w) |
| 590 | PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_SPECIAL) PORT_WRITE_LINE_DEVICE(CENTRONICS_TAG, centronics_init_w) |
| 591 | PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_SPECIAL) // PORT_WRITE_LINE_DEVICE(CENTRONICS_TAG, centronics_select_in_w) |
| 592 | PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_UNUSED) |
| 593 | PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_UNUSED) |
| 594 | PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_UNUSED) |
| 595 | PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_UNUSED) |
| 596 | |
| 597 | PORT_START("PPI-PC") |
| 598 | PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_SPECIAL) PORT_READ_LINE_DEVICE(CENTRONICS_TAG, centronics_pe_r) |
| 599 | PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_SPECIAL) PORT_READ_LINE_DEVICE(CENTRONICS_TAG, centronics_vcc_r) |
| 600 | PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_UNUSED) |
| 601 | PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_SPECIAL) PORT_READ_LINE_DEVICE(CENTRONICS_TAG, centronics_fault_r) |
| 602 | PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_SPECIAL) PORT_READ_LINE_DEVICE(CENTRONICS_TAG, centronics_busy_r) |
| 603 | PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_SPECIAL) PORT_READ_LINE_DEVICE(CENTRONICS_TAG, centronics_ack_r) |
| 604 | PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_UNUSED) |
| 605 | PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_UNUSED) |
| 606 | |
| 605 | 607 | PORT_START("BATTERY") |
| 606 | 608 | PORT_CONFNAME( 0x01, 0x01, "Battery Status" ) |
| 607 | 609 | PORT_CONFSETTING( 0x01, DEF_STR( Normal ) ) |
| r9369 | r9370 | |
| 629 | 631 | } |
| 630 | 632 | |
| 631 | 633 | //------------------------------------------------- |
| 632 | | // VIDEO_UPDATE( portfolio ) |
| 633 | | //------------------------------------------------- |
| 634 | | |
| 635 | | static VIDEO_UPDATE( portfolio ) |
| 636 | | { |
| 637 | | portfolio_state *state = screen->machine->driver_data<portfolio_state>(); |
| 638 | | |
| 639 | | hd61830_update(state->hd61830, bitmap, cliprect); |
| 640 | | |
| 641 | | return 0; |
| 642 | | } |
| 643 | | |
| 644 | | //------------------------------------------------- |
| 645 | 634 | // HD61830_INTERFACE( lcdc_intf ) |
| 646 | 635 | //------------------------------------------------- |
| 647 | 636 | |
| 648 | | static HD61830_RD_READ( hd61830_rd_r ) |
| 637 | READ8_DEVICE_HANDLER( hd61830_rd_r ) |
| 649 | 638 | { |
| 650 | | UINT16 address = (md << 3) | ((ma >> 12) & 0x07); |
| 639 | UINT16 address = ((offset & 0xff) << 3) | ((offset >> 12) & 0x07); |
| 651 | 640 | UINT8 data = memory_region(device->machine, HD61830_TAG)[address]; |
| 652 | 641 | |
| 653 | 642 | return data; |
| r9369 | r9370 | |
| 656 | 645 | static HD61830_INTERFACE( lcdc_intf ) |
| 657 | 646 | { |
| 658 | 647 | SCREEN_TAG, |
| 659 | | hd61830_rd_r |
| 648 | DEVCB_HANDLER(hd61830_rd_r) |
| 660 | 649 | }; |
| 661 | 650 | |
| 662 | 651 | //------------------------------------------------- |
| r9369 | r9370 | |
| 670 | 659 | 1, |
| 671 | 660 | { 0 }, |
| 672 | 661 | { 7, 6, 5, 4, 3, 2 }, |
| 673 | | { 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8 }, |
| 662 | { STEP8(0,8) }, |
| 674 | 663 | 8*8 |
| 675 | 664 | }; |
| 676 | 665 | |
| r9369 | r9370 | |
| 690 | 679 | // I8255A_INTERFACE( ppi_intf ) |
| 691 | 680 | //------------------------------------------------- |
| 692 | 681 | |
| 693 | | static WRITE8_DEVICE_HANDLER( ppi_pb_w ) |
| 694 | | { |
| 695 | | /* |
| 696 | | |
| 697 | | bit signal |
| 698 | | |
| 699 | | PB0 strobe |
| 700 | | PB1 autofeed |
| 701 | | PB2 init/reset |
| 702 | | PB3 select in |
| 703 | | PB4 |
| 704 | | PB5 |
| 705 | | PB6 |
| 706 | | PB7 |
| 707 | | |
| 708 | | */ |
| 709 | | |
| 710 | | portfolio_state *state = device->machine->driver_data<portfolio_state>(); |
| 711 | | |
| 712 | | /* strobe */ |
| 713 | | centronics_strobe_w(state->centronics, BIT(data, 0)); |
| 714 | | |
| 715 | | /* autofeed */ |
| 716 | | centronics_autofeed_w(state->centronics, BIT(data, 1)); |
| 717 | | |
| 718 | | /* init/reset */ |
| 719 | | centronics_init_w(state->centronics, BIT(data, 2)); |
| 720 | | |
| 721 | | /* select in */ |
| 722 | | //centronics_select_in_w(state->centronics, BIT(data, 3)); |
| 723 | | } |
| 724 | | |
| 725 | | static READ8_DEVICE_HANDLER( ppi_pc_r ) |
| 726 | | { |
| 727 | | /* |
| 728 | | |
| 729 | | bit signal |
| 730 | | |
| 731 | | PC0 paper |
| 732 | | PC1 select |
| 733 | | PC2 |
| 734 | | PC3 error |
| 735 | | PC4 busy |
| 736 | | PC5 ack |
| 737 | | PC6 |
| 738 | | PC7 |
| 739 | | |
| 740 | | */ |
| 741 | | |
| 742 | | portfolio_state *state = device->machine->driver_data<portfolio_state>(); |
| 743 | | |
| 744 | | UINT8 data = 0; |
| 745 | | |
| 746 | | /* paper end */ |
| 747 | | data |= centronics_pe_r(state->centronics); |
| 748 | | |
| 749 | | /* select */ |
| 750 | | data |= centronics_vcc_r(state->centronics) << 1; |
| 751 | | |
| 752 | | /* error */ |
| 753 | | data |= centronics_fault_r(state->centronics) << 3; |
| 754 | | |
| 755 | | /* busy */ |
| 756 | | data |= centronics_busy_r(state->centronics) << 4; |
| 757 | | |
| 758 | | /* acknowledge */ |
| 759 | | data |= centronics_ack_r(state->centronics) << 5; |
| 760 | | |
| 761 | | return data; |
| 762 | | } |
| 763 | | |
| 764 | 682 | static I8255A_INTERFACE( ppi_intf ) |
| 765 | 683 | { |
| 766 | 684 | DEVCB_NULL, // Port A read |
| 767 | 685 | DEVCB_NULL, // Port B read |
| 768 | | DEVCB_HANDLER(ppi_pc_r), // Port C read |
| 686 | DEVCB_INPUT_PORT("PPI-PC"), // Port C read |
| 769 | 687 | DEVCB_DEVICE_HANDLER(CENTRONICS_TAG, centronics_data_w), // Port A write |
| 770 | | DEVCB_HANDLER(ppi_pb_w), // Port B write |
| 688 | DEVCB_INPUT_PORT("PPI-PB"), // Port B write |
| 771 | 689 | DEVCB_NULL // Port C write |
| 772 | 690 | }; |
| 773 | 691 | |
| r9369 | r9370 | |
| 777 | 695 | |
| 778 | 696 | static INS8250_INTERRUPT( i8250_intrpt_w ) |
| 779 | 697 | { |
| 780 | | // trigger_interrupt(device->machine, INT_EXTERNAL); |
| 698 | portfolio_state *driver_state = device->machine->driver_data<portfolio_state>(); |
| 699 | |
| 700 | driver_state->trigger_interrupt(INT_EXTERNAL); |
| 781 | 701 | } |
| 782 | 702 | |
| 783 | | const ins8250_interface i8250_intf = |
| 703 | static const ins8250_interface i8250_intf = |
| 784 | 704 | { |
| 785 | 705 | XTAL_1_8432MHz, |
| 786 | 706 | i8250_intrpt_w, |
| r9369 | r9370 | |
| 819 | 739 | //************************************************************************** |
| 820 | 740 | |
| 821 | 741 | //------------------------------------------------- |
| 822 | | // MACHINE_START( portfolio ) |
| 742 | // machine_start |
| 823 | 743 | //------------------------------------------------- |
| 824 | 744 | |
| 825 | | static MACHINE_START( portfolio ) |
| 745 | void portfolio_state::machine_start() |
| 826 | 746 | { |
| 827 | | portfolio_state *state = machine->driver_data<portfolio_state>(); |
| 828 | | address_space *program = cputag_get_address_space(machine, M80C88A_TAG, ADDRESS_SPACE_PROGRAM); |
| 747 | address_space *program = cpu_get_address_space(m_maincpu, ADDRESS_SPACE_PROGRAM); |
| 829 | 748 | |
| 830 | 749 | /* set CPU interrupt vector callback */ |
| 831 | | cpu_set_irq_callback(machine->device(M80C88A_TAG), portfolio_int_ack); |
| 750 | cpu_set_irq_callback(m_maincpu, portfolio_int_ack); |
| 832 | 751 | |
| 833 | 752 | /* find devices */ |
| 834 | | state->hd61830 = machine->device(HD61830_TAG); |
| 835 | | state->centronics = machine->device(CENTRONICS_TAG); |
| 836 | | state->speaker = machine->device(SPEAKER_TAG); |
| 837 | | state->timer_tick = machine->device<timer_device>(TIMER_TICK_TAG); |
| 753 | m_timer_tick = machine->device<timer_device>(TIMER_TICK_TAG); |
| 838 | 754 | |
| 839 | 755 | /* memory expansions */ |
| 840 | 756 | switch (messram_get_size(machine->device("messram"))) |
| r9369 | r9370 | |
| 849 | 765 | } |
| 850 | 766 | |
| 851 | 767 | /* set initial values */ |
| 852 | | state->keylatch = 0xff; |
| 853 | | state->sivr = 0x2a; |
| 854 | | state->pid = 0xff; |
| 768 | m_keylatch = 0xff; |
| 769 | m_sivr = 0x2a; |
| 770 | m_pid = 0xff; |
| 855 | 771 | |
| 856 | 772 | /* register for state saving */ |
| 857 | | state_save_register_global(machine, state->ip); |
| 858 | | state_save_register_global(machine, state->ie); |
| 859 | | state_save_register_global(machine, state->sivr); |
| 860 | | state_save_register_global(machine, state->counter); |
| 861 | | state_save_register_global(machine, state->keylatch); |
| 862 | | state_save_register_global(machine, state->contrast); |
| 863 | | state_save_register_global(machine, state->pid); |
| 773 | state_save_register_global(machine, m_ip); |
| 774 | state_save_register_global(machine, m_ie); |
| 775 | state_save_register_global(machine, m_sivr); |
| 776 | state_save_register_global(machine, m_counter); |
| 777 | state_save_register_global(machine, m_keylatch); |
| 778 | state_save_register_global(machine, m_contrast); |
| 779 | state_save_register_global(machine, m_pid); |
| 864 | 780 | } |
| 865 | 781 | |
| 866 | 782 | //------------------------------------------------- |
| 867 | | // MACHINE_RESET( portfolio ) |
| 783 | // machine_reset |
| 868 | 784 | //------------------------------------------------- |
| 869 | 785 | |
| 870 | | static MACHINE_RESET( portfolio ) |
| 786 | void portfolio_state::machine_reset() |
| 871 | 787 | { |
| 872 | | portfolio_state *state = machine->driver_data<portfolio_state>(); |
| 873 | | address_space *io = cputag_get_address_space(machine, M80C88A_TAG, ADDRESS_SPACE_IO); |
| 788 | address_space *io = cpu_get_address_space(m_maincpu, ADDRESS_SPACE_IO); |
| 874 | 789 | |
| 875 | | /* peripheral */ |
| 876 | | state->pid = input_port_read(machine, "PERIPHERAL"); |
| 790 | // peripherals |
| 791 | m_pid = input_port_read(&m_machine, "PERIPHERAL"); |
| 877 | 792 | |
| 878 | | switch (state->pid) |
| 793 | memory_unmap_readwrite(io, 0x8070, 0x807b, 0, 0); |
| 794 | memory_unmap_readwrite(io, 0x807d, 0x807e, 0, 0); |
| 795 | |
| 796 | switch (m_pid) |
| 879 | 797 | { |
| 880 | 798 | case PID_SERIAL: |
| 881 | | memory_install_readwrite8_device_handler(io, machine->device(M82C50A_TAG), 0x8070, 0x8077, 0, 0, ins8250_r, ins8250_w); |
| 799 | memory_install_readwrite8_device_handler(io, m_uart, 0x8070, 0x8077, 0, 0, ins8250_r, ins8250_w); |
| 882 | 800 | break; |
| 883 | 801 | |
| 884 | 802 | case PID_PARALLEL: |
| 885 | | memory_install_readwrite8_device_handler(io, machine->device(M82C55A_TAG), 0x8078, 0x807b, 0, 0, i8255a_r, i8255a_w); |
| 803 | memory_install_readwrite8_device_handler(io, m_ppi, 0x8078, 0x807b, 0, 0, i8255a_r, i8255a_w); |
| 886 | 804 | break; |
| 887 | 805 | } |
| 888 | 806 | } |
| r9369 | r9370 | |
| 901 | 819 | MDRV_CPU_PROGRAM_MAP(portfolio_mem) |
| 902 | 820 | MDRV_CPU_IO_MAP(portfolio_io) |
| 903 | 821 | |
| 904 | | MDRV_MACHINE_START(portfolio) |
| 905 | | MDRV_MACHINE_RESET(portfolio) |
| 906 | | |
| 907 | 822 | /* video hardware */ |
| 908 | 823 | MDRV_SCREEN_ADD(SCREEN_TAG, LCD) |
| 909 | 824 | MDRV_SCREEN_REFRESH_RATE(72) |
| r9369 | r9370 | |
| 916 | 831 | MDRV_PALETTE_LENGTH(2) |
| 917 | 832 | MDRV_PALETTE_INIT(portfolio) |
| 918 | 833 | |
| 919 | | MDRV_VIDEO_UPDATE(portfolio) |
| 920 | 834 | MDRV_GFXDECODE(portfolio) |
| 921 | 835 | |
| 922 | 836 | MDRV_HD61830_ADD(HD61830_TAG, XTAL_4_9152MHz/2/2, lcdc_intf) |