H8 series MCU updates

- Implemented 8-bit timers and free-running counter for H8/3334
- Added bld #imm, @Rd instruction
- Improvements to interrupts and the serial ports
This commit is contained in:
R. Belmont 2009-05-18 03:55:28 +00:00
parent 92c85c173c
commit a59e2337ea
6 changed files with 273 additions and 32 deletions

View File

@ -65,15 +65,32 @@ static CPU_DISASSEMBLE(h8_32)
return h8_disasm(buffer, pc, oprom, opram, 0xffffffff);
}
void h8_3002_InterruptRequest(h83xx_state *h8, UINT8 source)
void h8_3002_InterruptRequest(h83xx_state *h8, UINT8 source, UINT8 state)
{
if(source>31)
// don't allow clear on external interrupts
if ((source <= 17) && (state == 0)) return;
if (state)
{
h8->h8_IRQrequestH |= (1<<(source-32));
if (source>31)
{
h8->h8_IRQrequestH |= (1<<(source-32));
}
else
{
h8->h8_IRQrequestL |= (1<<source);
}
}
else
{
h8->h8_IRQrequestL |= (1<<source);
if (source>31)
{
h8->h8_IRQrequestH &= ~(1<<(source-32));
}
else
{
h8->h8_IRQrequestL &= ~(1<<source);
}
}
}
@ -292,9 +309,23 @@ static int h8_get_priority(h83xx_state *h8, UINT8 bit)
case 17: // IRQ5
if (h8->per_regs[0xF8]&0x10) res = 1; break;
case 53: // SCI0 Rx
if (h8->per_regs[0xB2]&0x40) res = 1; break;
if (!(h8->per_regs[0xB2]&0x40)) res = -2;
else if (h8->per_regs[0xF9]&0x08) res = 1; break;
case 54: // SCI0 Tx Empty
if (!(h8->per_regs[0xB2]&0x80)) res = -2;
else if (h8->per_regs[0xF9]&0x08) res = 1; break;
case 55: // SCI0 Tx End
if (!(h8->per_regs[0xB2]&0x04)) res = -2;
else if (h8->per_regs[0xF9]&0x08) res = 1; break;
case 57: // SCI1 Rx
if (h8->per_regs[0xBA]&0x40) res = 1; break;
if (!(h8->per_regs[0xBA]&0x40)) res = -2;
else if (h8->per_regs[0xF9]&0x04) res = 1; break;
case 58: // SCI1 Tx Empty
if (!(h8->per_regs[0xBA]&0x80)) res = -2;
else if (h8->per_regs[0xF9]&0x04) res = 1; break;
case 59: // SCI1 Tx End
if (!(h8->per_regs[0xBA]&0x04)) res = -2;
else if (h8->per_regs[0xF9]&0x04) res = 1; break;
}
return res;
}
@ -381,17 +412,17 @@ static CPU_SET_INFO( h8 )
case CPUINFO_INT_REGISTER + H8_E6: h8->regs[6] = info->i; break;
case CPUINFO_INT_REGISTER + H8_E7: h8->regs[7] = info->i; break;
case CPUINFO_INT_INPUT_STATE + H8_IRQ0: if (info->i) h8_3002_InterruptRequest(h8, 12); break;
case CPUINFO_INT_INPUT_STATE + H8_IRQ1: if (info->i) h8_3002_InterruptRequest(h8, 13); break;
case CPUINFO_INT_INPUT_STATE + H8_IRQ2: if (info->i) h8_3002_InterruptRequest(h8, 14); break;
case CPUINFO_INT_INPUT_STATE + H8_IRQ3: if (info->i) h8_3002_InterruptRequest(h8, 15); break;
case CPUINFO_INT_INPUT_STATE + H8_IRQ4: if (info->i) h8_3002_InterruptRequest(h8, 16); break;
case CPUINFO_INT_INPUT_STATE + H8_IRQ5: if (info->i) h8_3002_InterruptRequest(h8, 17); break;
case CPUINFO_INT_INPUT_STATE + H8_IRQ0: h8_3002_InterruptRequest(h8, 12, info->i); break;
case CPUINFO_INT_INPUT_STATE + H8_IRQ1: h8_3002_InterruptRequest(h8, 13, info->i); break;
case CPUINFO_INT_INPUT_STATE + H8_IRQ2: h8_3002_InterruptRequest(h8, 14, info->i); break;
case CPUINFO_INT_INPUT_STATE + H8_IRQ3: h8_3002_InterruptRequest(h8, 15, info->i); break;
case CPUINFO_INT_INPUT_STATE + H8_IRQ4: h8_3002_InterruptRequest(h8, 16, info->i); break;
case CPUINFO_INT_INPUT_STATE + H8_IRQ5: h8_3002_InterruptRequest(h8, 17, info->i); break;
case CPUINFO_INT_INPUT_STATE + H8_METRO_TIMER_HACK: if (info->i) h8_3002_InterruptRequest(h8, 24); break;
case CPUINFO_INT_INPUT_STATE + H8_METRO_TIMER_HACK: h8_3002_InterruptRequest(h8, 24, info->i); break;
case CPUINFO_INT_INPUT_STATE + H8_SCI_0_RX: if (info->i) h8_3002_InterruptRequest(h8, 53); break;
case CPUINFO_INT_INPUT_STATE + H8_SCI_1_RX: if (info->i) h8_3002_InterruptRequest(h8, 57); break;
case CPUINFO_INT_INPUT_STATE + H8_SCI_0_RX: h8_3002_InterruptRequest(h8, 53, info->i); break;
case CPUINFO_INT_INPUT_STATE + H8_SCI_1_RX: h8_3002_InterruptRequest(h8, 57, info->i); break;
default:
fatalerror("h8_set_info unknown request %x", state);

View File

@ -26,6 +26,11 @@
#define H8_WORD_TIMING(x, adr) if (address24 >= 0xff90) h8->cyccnt -= (x) * 3; else h8->cyccnt -= (x) * 4;
#define H8_IOP_TIMING(x) h8->cyccnt -= (x);
static TIMER_CALLBACK( h8_timer_0_cb );
static TIMER_CALLBACK( h8_timer_1_cb );
static TIMER_CALLBACK( h8_timer_2_cb );
static TIMER_CALLBACK( h8_timer_3_cb );
INLINE UINT16 h8_mem_read16(h83xx_state *h8, offs_t address)
{
UINT16 result = memory_read_byte(h8->program, address)<<8;
@ -239,6 +244,11 @@ static CPU_INIT(h8bit)
h8->program = memory_find_address_space(device, ADDRESS_SPACE_PROGRAM);
h8->io = memory_find_address_space(device, ADDRESS_SPACE_IO);
h8->timer[0] = timer_alloc(h8->device->machine, h8_timer_0_cb, h8);
h8->timer[1] = timer_alloc(h8->device->machine, h8_timer_1_cb, h8);
h8->timer[2] = timer_alloc(h8->device->machine, h8_timer_2_cb, h8);
h8->timer[3] = timer_alloc(h8->device->machine, h8_timer_3_cb, h8);
state_save_register_device_item(device, 0, h8->h8err);
state_save_register_device_item_array(device, 0, h8->regs);
state_save_register_device_item(device, 0, h8->pc);
@ -264,6 +274,12 @@ static CPU_RESET(h8bit)
// disable timers
h8->h8TSTR = 0;
h8->FRC = 0;
h8->STCR = 0;
h8->TCR[0] = h8->TCR[1] = 0;
h8->TCORA[0] = h8->TCORB[0] = 0;
h8->TCORA[1] = h8->TCORB[1] = 0;
h8->TCNT[0] = h8->TCNT[1] = 0;
}
static void h8_GenException(h83xx_state *h8, UINT8 vectornr)
@ -280,7 +296,7 @@ static void h8_GenException(h83xx_state *h8, UINT8 vectornr)
if (h8->h8uiflag == 0)
h8_set_ccr(h8, h8_get_ccr(h8) | 0x40);
h8->pc = h8_mem_read16(h8, vectornr * 2) & 0xffff;
// these timings are still approximations but much better than before
H8_IFETCH_TIMING(8); // 24 cycles
H8_STACK_TIMING(3); // 12 cycles
@ -309,6 +325,14 @@ static int h8_get_priority(h83xx_state *h8, UINT8 bit)
if (h8->per_regs[0xc7]&0x40) res = 1; break;
case 11: // IRQ7
if (h8->per_regs[0xc7]&0x80) res = 1; break;
case 19: // 8-bit timer 0 match A
if (h8->TCR[0] & 0x40) res = 1; break;
case 20: // 8-bit timer 0 match B
if (h8->TCR[0] & 0x80) res = 1; break;
case 22: // 8-bit timer 1 match A
if (h8->TCR[1] & 0x40) res = 1; break;
case 23: // 8-bit timer 1 match B
if (h8->TCR[1] & 0x80) res = 1; break;
case 28: // SCI0 Rx
if (h8->per_regs[0xda]&0x40) res = 1; break;
case 32: // SCI1 Rx
@ -371,6 +395,79 @@ static void h8_check_irqs(h83xx_state *h8)
#define H8_ADDR_MASK 0xffff
#include "h8ops.h"
// peripherals
static void recalc_8bit_timer(h83xx_state *h8, int t)
{
static INT32 dividers[8] = { 0, 0, 8, 2, 64, 32, 1024, 256 };
int div;
INT32 time;
div = (h8->STCR & 1) | ((h8->TCR[t] & 3)<<1);
// if "no clock source", stop
if (div < 2)
{
timer_adjust_oneshot(h8->timer[(t*2)], attotime_never, 0);
timer_adjust_oneshot(h8->timer[(t*2)+1], attotime_never, 0);
return;
}
if (h8->TCORA[t])
{
time = (cpu_get_clock(h8->device) / dividers[div]) / (h8->TCORA[t] - h8->TCNT[t]);
timer_adjust_oneshot(h8->timer[(t*2)], ATTOTIME_IN_HZ(time), 0);
}
if (h8->TCORB[t])
{
time = (cpu_get_clock(h8->device) / dividers[div]) / (h8->TCORB[t] - h8->TCNT[t]);
timer_adjust_oneshot(h8->timer[(t*2)+1], ATTOTIME_IN_HZ(time), 0);
}
}
// IRQs: timer 0: 19 A 20 B 21 OV timer1: 22 A 23 B 24 OV
static void timer_8bit_expire(h83xx_state *h8, int t, int sel)
{
static int irqbase[2] = { 19, 22 };
timer_adjust_oneshot(h8->timer[(t*2)+sel], attotime_never, 0);
h8->TCSR[t] |= ((0x40)<<sel);
// check for interrupts
if (h8->TCR[t] & (0x40<<sel))
{
h8->h8_IRQrequestL |= (1 << (irqbase[t] + sel));
}
switch ((h8->TCR[t]>>3) & 3)
{
case 0: // no clear
break;
case 1: // clear on match A
if (!sel)
{
h8->TCNT[t] = 0;
recalc_8bit_timer(h8, t);
}
break;
case 2: // clear on match B
if (sel)
{
h8->TCNT[t] = 0;
recalc_8bit_timer(h8, t);
}
break;
case 3: // clear on external reset input signal (not implemented)
logerror("H8: external reset not implemented for 8-bit timers\n");
break;
}
}
// MAME interface stuff
static CPU_SET_INFO( h8 )
@ -414,6 +511,8 @@ static READ8_HANDLER( h8330_itu_r )
{
UINT8 val;
UINT8 reg;
UINT64 frc;
static UINT64 divider[4] = { 2, 8, 32, 1 };
h83xx_state *h8 = (h83xx_state *)space->cpu->token;
reg = (offset + 0x88) & 0xff;
@ -423,6 +522,16 @@ static READ8_HANDLER( h8330_itu_r )
case 0x8d: // serial Rx 1
val = memory_read_byte(h8->io, H8_SERIAL_1);
break;
case 0x92: // FRC H
frc = cpu_get_total_cycles(h8->device) / divider[h8->per_regs[0x96]];
frc %= 65536;
return frc>>8;
break;
case 0x93: // FRC L
frc = cpu_get_total_cycles(h8->device) / divider[h8->per_regs[0x96]];
frc %= 65536;
return frc&0xff;
break;
case 0xb2: // port 1 data
val = memory_read_byte(h8->io, H8_PORT_1);
break;
@ -473,6 +582,9 @@ static WRITE8_HANDLER( h8330_itu_w )
switch (reg)
{
case 0x80:
printf("%02x to flash control or external\n", data);
break;
case 0x8b: // serial Tx 1
memory_write_byte(h8->io, H8_SERIAL_1, data);
break;
@ -519,16 +631,91 @@ static WRITE8_HANDLER( h8330_itu_w )
case 0x89:
break;
case 0xc3:
case 0xc7:
break;
case 0xc7:
case 0xc8:
h8->TCR[0] = data;
recalc_8bit_timer(h8, 0);
break;
case 0xc9:
h8->TCSR[0] = data;
h8->h8_IRQrequestL &= ~(1 << 19);
h8->h8_IRQrequestL &= ~(1 << 20);
h8->h8_IRQrequestL &= ~(1 << 21);
recalc_8bit_timer(h8, 0);
break;
case 0xca:
h8->TCORA[0] = data;
recalc_8bit_timer(h8, 0);
break;
case 0xcb:
h8->TCORB[0] = data;
recalc_8bit_timer(h8, 0);
break;
case 0xcc:
h8->TCNT[0] = data;
recalc_8bit_timer(h8, 0);
break;
case 0xc3:
h8->STCR = data;
recalc_8bit_timer(h8, 0);
recalc_8bit_timer(h8, 1);
break;
case 0xd0:
h8->TCR[1] = data;
recalc_8bit_timer(h8, 1);
break;
case 0xd1:
h8->TCSR[1] = data;
h8->h8_IRQrequestL &= ~(1 << 22);
h8->h8_IRQrequestL &= ~(1 << 23);
h8->h8_IRQrequestL &= ~(1 << 24);
recalc_8bit_timer(h8, 1);
break;
case 0xd2:
h8->TCORA[1] = data;
recalc_8bit_timer(h8, 1);
break;
case 0xd3:
h8->TCORB[1] = data;
recalc_8bit_timer(h8, 1);
break;
case 0xd4:
h8->TCNT[1] = data;
recalc_8bit_timer(h8, 1);
break;
}
h8->per_regs[reg] = data;
}
static TIMER_CALLBACK( h8_timer_0_cb )
{
h83xx_state *h8 = (h83xx_state *)ptr;
timer_8bit_expire(h8, 0, 0);
}
static TIMER_CALLBACK( h8_timer_1_cb )
{
h83xx_state *h8 = (h83xx_state *)ptr;
timer_8bit_expire(h8, 0, 1);
}
static TIMER_CALLBACK( h8_timer_2_cb )
{
h83xx_state *h8 = (h83xx_state *)ptr;
timer_8bit_expire(h8, 1, 0);
}
static TIMER_CALLBACK( h8_timer_3_cb )
{
h83xx_state *h8 = (h83xx_state *)ptr;
timer_8bit_expire(h8, 1, 1);
}
static ADDRESS_MAP_START( h8_3334_internal_map, ADDRESS_SPACE_PROGRAM, 8 )
// 512B RAM
AM_RANGE(0xfb80, 0xff7f) AM_RAM

View File

@ -1247,6 +1247,10 @@ static UINT32 h8disasm_7(UINT32 address, UINT32 opcode, char *buffer, const UINT
}
sprintf(buffer, "%4.4x %s.b #%1.1x, @%s", opcode, bit_instr[(data16>>8)&7], (data16>>4)&7, reg_names32[(opcode>>4) & 0x7]);
break;
case 0x77: // bld #xx:3, @rd
sprintf(buffer, "%4.4x bld #%d, @%s", opcode, (data16>>4)&7, reg_names32[(opcode>>4) & 0x7]);
break;
}
break;
// bxx.b #imm, @aa:8

View File

@ -222,8 +222,7 @@ static CPU_EXECUTE(h8)
if (h8->h8err)
{
fatalerror("H8/3xx: Unknown opcode (PC=%x) %x", h8->ppc, opcode);
fatalerror("H8/3xx: Unknown opcode (PC=%x) %x", h8->ppc, opcode);
}
return cycles - h8->cyccnt;
@ -1233,7 +1232,7 @@ static void h8_group5(h83xx_state *h8, UINT16 opcode)
udata32 = h8_mem_read32(h8, h8_getreg32(h8, H8_SP));
h8_setreg32(h8, H8_SP, h8_getreg32(h8, H8_SP)+4);
// extended mode
h8->pc = udata32;
h8->pc = udata32 & 0xffffff;
H8_IFETCH_TIMING(2);
H8_STACK_TIMING(2);
H8_IOP_TIMING(2);
@ -1695,7 +1694,7 @@ static void h8_group7(h83xx_state *h8, UINT16 opcode)
if(((opcode>>4)&0x8) == 0)
{
switch((opcode>>8)&7)
switch((opcode>>8)&0x7)
{
case 0: udata8 = h8_bset8(h8, bitnr, udata8); h8_setreg8(h8, dstreg, udata8); H8_IFETCH_TIMING(1); break;
case 2: udata8 = h8_bclr8(h8, bitnr, udata8); h8_setreg8(h8, dstreg, udata8);H8_IFETCH_TIMING(1);break;
@ -1924,6 +1923,19 @@ static void h8_group7(h83xx_state *h8, UINT16 opcode)
bitnr = (ext16>>4)&7;
h8_btst8(h8, bitnr, udata8);
break;
// bld.b #imm, @Rn
case 0x77:
udata16 = h8_mem_read16(h8, h8->pc);
h8->pc += 2;
dstreg = (opcode>>4) & 7;
h8_bld8(h8, (udata16>>4) & 7, h8_mem_read8(h8_getreg16(h8, dstreg)));
H8_IFETCH_TIMING(1);
H8_WORD_TIMING(1, h8_getreg16(h8, dstreg));
break;
default:
h8->h8err=1;
}

View File

@ -38,7 +38,7 @@ static const UINT8 tier[5] = { TIER0, TIER1, TIER2, TIER3, TIER4 };
static const UINT8 tcr[5] = { TCR0, TCR1, TCR2, TCR3, TCR4 };
static const int tscales[4] = { 1, 2, 4, 8 };
extern void h8_3002_InterruptRequest(h83xx_state *h8, UINT8 source);
extern void h8_3002_InterruptRequest(h83xx_state *h8, UINT8 source, UINT8 state);
extern void *h8_token;
static void h8itu_timer_expire(h83xx_state *h8, int which)
@ -49,7 +49,7 @@ static void h8itu_timer_expire(h83xx_state *h8, int which)
// interrupt on overflow ?
if(h8->per_regs[tier[which]] & 4)
{
h8_3002_InterruptRequest(h8, 26 + 4*which);
h8_3002_InterruptRequest(h8, 26 + 4*which, 1);
}
}
@ -414,11 +414,15 @@ void h8_register_write8(h83xx_state *h8, UINT32 address, UINT8 val)
switch (reg)
{
case 0xb3:
case 0xb3: // serial 0 send
memory_write_byte(h8->io, H8_SERIAL_0, val);
h8_3002_InterruptRequest(h8, 54, 1);
h8_3002_InterruptRequest(h8, 55, 1);
break;
case 0xbb:
case 0xbb: // serial 1 send
memory_write_byte(h8->io, H8_SERIAL_1, val);
h8_3002_InterruptRequest(h8, 58, 1);
h8_3002_InterruptRequest(h8, 59, 1);
break;
case 0xc7:
memory_write_byte(h8->io, H8_PORT_4, val);
@ -493,7 +497,7 @@ static void h8itu_3007_timer_expire(h83xx_state *h8, int tnum)
if(h8->per_regs[0x64] & (4<<tnum)) // interrupt enable
{
//logerror("h8/3007 timer %d GRA INTERRUPT\n",tnum);
h8_3002_InterruptRequest(h8, 24+tnum*4);
h8_3002_InterruptRequest(h8, 24+tnum*4, 1);
}
}
// GRB match
@ -515,7 +519,7 @@ static void h8itu_3007_timer_expire(h83xx_state *h8, int tnum)
if(h8->per_regs[0x65] & (4<<tnum)) // interrupt enable
{
//logerror("h8/3007 timer %d GRB INTERRUPT\n",tnum);
h8_3002_InterruptRequest(h8, 25+tnum*4);
h8_3002_InterruptRequest(h8, 25+tnum*4, 1);
}
}
// Overflow
@ -526,7 +530,7 @@ static void h8itu_3007_timer_expire(h83xx_state *h8, int tnum)
if(h8->per_regs[0x66] & (4<<tnum)) // interrupt enable
{
//logerror("h8/3007 timer %d OVF INTERRUPT\n",tnum);
h8_3002_InterruptRequest(h8, 26+tnum*4);
h8_3002_InterruptRequest(h8, 26+tnum*4, 1);
}
}
@ -574,7 +578,7 @@ UINT8 h8_3007_itu_read8(h83xx_state *h8, UINT8 reg)
void h8_3007_itu_write8(h83xx_state *h8, UINT8 reg, UINT8 val)
{
//logerror("%06x: h8/3007 reg %02x = %02x\n",h8->pc,reg,val);
logerror("%06x: h8/3007 reg %02x = %02x\n",h8->pc,reg,val);
h8->per_regs[reg] = val;
switch(reg)
{

View File

@ -30,14 +30,17 @@ struct _h83xx_state
const address_space *program;
const address_space *io;
// H8/3002 onboard peripherals stuff
// onboard peripherals stuff
UINT8 per_regs[256];
UINT16 h8TCNT[5];
UINT8 h8TSTR;
UINT8 STCR, TCR[2], TCSR[2], TCORA[2], TCORB[2], TCNT[2];
UINT16 FRC;
emu_timer *timer[5];
emu_timer *frctimer;
int mode_8bit;
};