1 // license:BSD-3-Clause
2 // copyright-holders:hap, Jonathan Gevaryahu
3 
4 // SM590 opcode handlers
5 
6 #include "emu.h"
7 #include "sm590.h"
8 
9 
10 // internal helpers
11 
do_branch(u8 pu,u8 pm,u8 pl)12 void sm590_device::do_branch(u8 pu, u8 pm, u8 pl)
13 {
14 	// set new PC(Pu/Pm/Pl)
15 	m_pc = (((u16)pu << 9 & 0x200) | ((u16)pm << 7 & 0x180) | (pl & 0x07f)) & m_prgmask;
16 }
17 
18 // instruction set
19 
op_adx()20 void sm590_device::op_adx()
21 {
22 	// ADX x: add immediate value to ACC, skip next on carry
23 	m_acc += (m_op & 0xf);
24 	m_skip = bool(m_acc & 0x10);
25 	m_acc &= 0xf;
26 }
27 
op_tax()28 void sm590_device::op_tax()
29 {
30 	// TAX: skip next if ACC equals 4-bit immediate value
31 	m_skip = (m_acc == (m_op & 0xf));
32 }
33 
op_lblx()34 void sm590_device::op_lblx()
35 {
36 	// LBL x: load BL with 4-bit immediate value
37 	m_bl = (m_op & 0xf);
38 }
39 
op_lda()40 void sm590_device::op_lda()
41 {
42 	// LDA: load ACC with RAM
43 	m_acc = ram_r();
44 }
45 
op_exc()46 void sm590_device::op_exc()
47 {
48 	// EXC: exchange ACC with RAM
49 	u8 a = m_acc;
50 	m_acc = ram_r();
51 	ram_w(a);
52 }
53 
op_atr()54 void sm590_device::op_atr()
55 {
56 	// ATR: output ACC to R(BL)
57 	m_rports[m_bl & 0x3] = m_acc; // is the mask for BL correct here? if BL is >= 4, do the writes just go nowhere?
58 }
59 
op_mtr()60 void sm590_device::op_mtr()
61 {
62 	// MTR: output RAM to R(BL)
63 	m_rports[m_bl & 0x3] = ram_r(); // is the mask for BL correct here? if BL is >= 4, do the writes just go nowhere?
64 }
65 
op_str()66 void sm590_device::op_str()
67 {
68 	// STR: output ACC to RAM
69 	ram_w(m_acc);
70 }
71 
op_inbm()72 void sm590_device::op_inbm()
73 {
74 	// INBM: increment BM
75 	m_bm = (m_bm + 1) & 0x3; // is this mask correct?
76 }
77 
op_debm()78 void sm590_device::op_debm()
79 {
80 	// DEBM: decrement BM
81 	m_bm = (m_bm - 1) & 0x3; // is this mask correct?
82 }
83 
op_tc()84 void sm590_device::op_tc()
85 {
86 	// TC: skip next if carry
87 	m_skip = bool(m_c);
88 }
89 
op_rta()90 void sm590_device::op_rta()
91 {
92 	// RTA: load ACC with R(BL)
93 	m_acc = m_rports[m_bl & 0x3]; // TODO: need a read function for this; is the mask for BL correct here? if BL is >= 4, do we always read 0 or F?
94 }
95 
op_blta()96 void sm590_device::op_blta()
97 {
98 	// BLTA: load ACC with BL
99 	m_acc = m_bl;
100 }
101 
op_exax()102 void sm590_device::op_exax()
103 {
104 	// EXAX: exchange X with ACC
105 	u8 a = m_acc;
106 	m_acc = m_x;
107 	m_x = a;
108 }
109 
op_tba()110 void sm590_device::op_tba()
111 {
112 	// TBA x: skip next if ACC bit is set
113 	m_skip = ((m_acc & bitmask(m_op)) != 0);
114 }
115 
op_ads()116 void sm590_device::op_ads()
117 {
118 	// ADS: add RAM to ACC, skip next on carry
119 	m_acc += ram_r();
120 	m_skip = bool(m_acc & 0x10);
121 	m_acc &= 0xf;
122 }
123 
op_adc()124 void sm590_device::op_adc()
125 {
126 	// ADC: add RAM and carry to ACC and carry
127 	m_acc += ram_r() + m_c;
128 	m_c = m_acc >> 4 & 1;
129 	m_acc &= 0xf;
130 }
131 
op_lbmx()132 void sm590_device::op_lbmx()
133 {
134 	// LBM x: load BM with 2-bit immediate value
135 	m_bm = (m_op & 0x3);
136 }
137 
op_tl()138 void sm590_device::op_tl()
139 {
140 	// TL xyz: long jump (same as sm510 TL except m_op and m_param masks)
141 	do_branch((m_op & 2)>>1, (((m_op & 1)<<1)|((m_param&0x80)?1:0)), m_param & 0x7f);
142 }
143 
op_tml()144 void sm590_device::op_tml() // aka TLS
145 {
146 	// TLS xyz: long call (same as sm510 TML except m_param mask)
147 	push_stack();
148 	do_branch((m_op & 2)>>1, (((m_op & 1)<<1)|((m_param&0x80)?1:0)), m_param & 0x7f);
149 }
150 
op_t()151 void sm590_device::op_t()
152 {
153 	// TR xy: jump(transfer) within current page (same as sm510 T except m_op/m_pc mask)
154 	m_pc = (m_pc & ~0x7f) | (m_op & 0x7f);
155 }
156