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