summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/sm510/sm530op.cpp
blob: a8a55d89d7b8c2708bf283bc65bf54b0c2712758 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
// license:BSD-3-Clause
// copyright-holders:hap

// SM530 shared opcode handlers

#include "emu.h"
#include "sm530.h"


// internal helpers

void sm530_device::do_branch(u8 pu, u8 pl)
{
	// set new PC(Pu/Pl)
	m_pc = ((pu << 6) | (pl & 0x3f)) & m_prgmask;
}


// instruction set

// RAM address instructions

void sm530_device::op_incb()
{
	// INCB: increment BL, but overflow on 3rd bit!
	sm511_device::op_incb();
	m_skip = ((m_bl & 7) == 0);
}

void sm530_device::op_lb()
{
	// LB x: load BM/BL with 4-bit immediate value (partial)
	m_bl = (m_op << 2 & 8) | (m_op & 1) | 6;
	m_bm = m_op >> 2 & 3;
}

void sm530_device::op_sabl()
{
	// SABL: set BL high bit for next opcode - handled in execute_one()
}


// ROM address instructions

void sm530_device::op_tl()
{
	// TL xy: long jump
	do_branch((m_op << 2) | (m_param >> 6 & 3), m_param & 0x3f);
}

void sm530_device::op_trs()
{
	// TRS x: indirect subroutine call, jump vectors are on page 14
	m_icount--;
	push_stack();
	u8 jump = m_program->read_byte((14 << 6) | (m_op & 0x3f));
	do_branch(bitswap<3>(jump, 5,7,6), jump & 0x1f);
}


// Data transfer instructions

void sm530_device::op_dta()
{
	// DTA: transfer 1/100s counter to ACC
	m_acc = m_count_10ms;
}


// Arithmetic instructions

void sm530_device::op_adx()
{
	// ADX x: add immediate value to ACC, skip next on carry
	m_acc += (m_op & 0xf);
	m_skip = bool(m_acc & 0x10);
	m_acc &= 0xf;
}


// Test instructions

void sm530_device::op_tg()
{
	// TG x: skip next if gamma flag is set, reset it after
	m_skip = bool(m_gamma & bitmask(m_op));
	m_gamma &= ~bitmask(m_op);
}


// I/O instructions

void sm530_device::op_keta()
{
	// KETA: input KE to ACC
	m_acc = m_read_k() >> 4 & 0xf;
}

void sm530_device::op_ats()
{
	// ATS: output ACC to S
	m_write_s(m_acc);
}

void sm530_device::op_atf()
{
	// ATS: output ACC to F
	m_write_f(m_acc);
}

void sm530_device::op_sds()
{
	// SDS: set display enable
	m_ds = true;
}

void sm530_device::op_rds()
{
	// RDS: reset display enable
	m_ds = false;
}


// Special instructions

void sm530_device::op_idiv()
{
	// IDIV: reset divider and 1s counter
	m_div = m_subdiv = 0;
	m_count_1s = 0;
}

void sm530_device::op_inis()
{
	// INIS: reset 1/100s counter
	m_count_10ms = 0;
}