File: instructions.cpp

package info (click to toggle)
libretro-bsnes-mercury 094%2Bgit20220807-8
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, forky, sid, trixie
  • size: 9,792 kB
  • sloc: cpp: 109,408; ansic: 3,554; makefile: 991; xml: 115; asm: 55; sh: 1
file content (222 lines) | stat: -rw-r--r-- 7,531 bytes parent folder | download | duplicates (5)
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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
void uPD96050::exec() {
  uint24 opcode = programROM[regs.pc++];
  switch(opcode >> 22) {
  case 0: exec_op(opcode); break;
  case 1: exec_rt(opcode); break;
  case 2: exec_jp(opcode); break;
  case 3: exec_ld(opcode); break;
  }

  int32 result = (int32)regs.k * regs.l;  //sign + 30-bit result
  regs.m = result >> 15;  //store sign + top 15-bits
  regs.n = result <<  1;  //store low 15-bits + zero
}

void uPD96050::exec_op(uint24 opcode) {
  uint2 pselect = opcode >> 20;  //P select
  uint4 alu     = opcode >> 16;  //ALU operation mode
  uint1 asl     = opcode >> 15;  //accumulator select
  uint2 dpl     = opcode >> 13;  //DP low modify
  uint4 dphm    = opcode >>  9;  //DP high XOR modify
  uint1 rpdcr   = opcode >>  8;  //RP decrement
  uint4 src     = opcode >>  4;  //move source
  uint4 dst     = opcode >>  0;  //move destination

  uint16 idb;
  switch(src) {
  case  0: idb = regs.trb; break;
  case  1: idb = regs.a; break;
  case  2: idb = regs.b; break;
  case  3: idb = regs.tr; break;
  case  4: idb = regs.dp; break;
  case  5: idb = regs.rp; break;
  case  6: idb = dataROM[regs.rp]; break;
  case  7: idb = 0x8000 - regs.flaga.s1; break;
  case  8: idb = regs.dr; regs.sr.rqm = 1; break;
  case  9: idb = regs.dr; break;
  case 10: idb = regs.sr; break;
  case 11: idb = regs.si; break;  //MSB
  case 12: idb = regs.si; break;  //LSB
  case 13: idb = regs.k; break;
  case 14: idb = regs.l; break;
  case 15: idb = dataRAM[regs.dp]; break;
  }

  if(alu) {
    uint16 p, q, r;
    Flag flag;
    bool c;

    switch(pselect) {
    case 0: p = dataRAM[regs.dp]; break;
    case 1: p = idb; break;
    case 2: p = regs.m; break;
    case 3: p = regs.n; break;
    }

    switch(asl) {
    case 0: q = regs.a; flag = regs.flaga; c = regs.flagb.c; break;
    case 1: q = regs.b; flag = regs.flagb; c = regs.flaga.c; break;
    }

    switch(alu) {
    case  1: r = q | p; break;                    //OR
    case  2: r = q & p; break;                    //AND
    case  3: r = q ^ p; break;                    //XOR
    case  4: r = q - p; break;                    //SUB
    case  5: r = q + p; break;                    //ADD
    case  6: r = q - p - c; break;                //SBB
    case  7: r = q + p + c; break;                //ADC
    case  8: r = q - 1; p = 1; break;             //DEC
    case  9: r = q + 1; p = 1; break;             //INC
    case 10: r = ~q; break;                       //CMP
    case 11: r = (q >> 1) | (q & 0x8000); break;  //SHR1 (ASR)
    case 12: r = (q << 1) | c; break;             //SHL1 (ROL)
    case 13: r = (q << 2) |  3; break;            //SHL2
    case 14: r = (q << 4) | 15; break;            //SHL4
    case 15: r = (q << 8) | (q >> 8); break;      //XCHG
    }

    flag.s0 = (r & 0x8000);
    flag.z = (r == 0);

    switch(alu) {
    case  1: case  2: case  3: case 10: case 13: case 14: case 15: {
      flag.c = 0;
      flag.ov0 = 0;
      flag.ov1 = 0;
      break;
    }
    case  4: case  5: case  6: case  7: case  8: case  9: {
      if(alu & 1) {
        //addition
        flag.ov0 = (q ^ r) & ~(q ^ p) & 0x8000;
        flag.c = (r < q);
      } else {
        //subtraction
        flag.ov0 = (q ^ r) &  (q ^ p) & 0x8000;
        flag.c = (r > q);
      }
      if(flag.ov0) {
        flag.s1 = flag.ov1 ^ !(r & 0x8000);
        flag.ov1 = !flag.ov1;
      }
      break;
    }
    case 11: {
      flag.c = q & 1;
      flag.ov0 = 0;
      flag.ov1 = 0;
      break;
    }
    case 12: {
      flag.c = q >> 15;
      flag.ov0 = 0;
      flag.ov1 = 0;
      break;
    }
    }

    switch(asl) {
    case 0: regs.a = r; regs.flaga = flag; break;
    case 1: regs.b = r; regs.flagb = flag; break;
    }
  }

  exec_ld((idb << 6) + dst);

  switch(dpl) {
  case 1: regs.dp = (regs.dp & 0xf0) + ((regs.dp + 1) & 0x0f); break;  //DPINC
  case 2: regs.dp = (regs.dp & 0xf0) + ((regs.dp - 1) & 0x0f); break;  //DPDEC
  case 3: regs.dp = (regs.dp & 0xf0); break;  //DPCLR
  }

  regs.dp ^= dphm << 4;

  if(rpdcr) regs.rp--;
}

void uPD96050::exec_rt(uint24 opcode) {
  exec_op(opcode);
  regs.pc = regs.stack[--regs.sp];
}

void uPD96050::exec_jp(uint24 opcode) {
  uint9 brch = opcode >> 13;  //branch
  uint11 na  = opcode >>  2;  //next address
  uint2 bank = opcode >>  0;  //bank address

  uint14 jp = (regs.pc & 0x2000) | (bank << 11) | (na << 0);

  switch(brch) {
  case 0x000: regs.pc = regs.so; return;  //JMPSO

  case 0x080: if(regs.flaga.c == 0) regs.pc = jp; return;  //JNCA
  case 0x082: if(regs.flaga.c == 1) regs.pc = jp; return;  //JCA
  case 0x084: if(regs.flagb.c == 0) regs.pc = jp; return;  //JNCB
  case 0x086: if(regs.flagb.c == 1) regs.pc = jp; return;  //JCB

  case 0x088: if(regs.flaga.z == 0) regs.pc = jp; return;  //JNZA
  case 0x08a: if(regs.flaga.z == 1) regs.pc = jp; return;  //JZA
  case 0x08c: if(regs.flagb.z == 0) regs.pc = jp; return;  //JNZB
  case 0x08e: if(regs.flagb.z == 1) regs.pc = jp; return;  //JZB

  case 0x090: if(regs.flaga.ov0 == 0) regs.pc = jp; return;  //JNOVA0
  case 0x092: if(regs.flaga.ov0 == 1) regs.pc = jp; return;  //JOVA0
  case 0x094: if(regs.flagb.ov0 == 0) regs.pc = jp; return;  //JNOVB0
  case 0x096: if(regs.flagb.ov0 == 1) regs.pc = jp; return;  //JOVB0

  case 0x098: if(regs.flaga.ov1 == 0) regs.pc = jp; return;  //JNOVA1
  case 0x09a: if(regs.flaga.ov1 == 1) regs.pc = jp; return;  //JOVA1
  case 0x09c: if(regs.flagb.ov1 == 0) regs.pc = jp; return;  //JNOVB1
  case 0x09e: if(regs.flagb.ov1 == 1) regs.pc = jp; return;  //JOVB1

  case 0x0a0: if(regs.flaga.s0 == 0) regs.pc = jp; return;  //JNSA0
  case 0x0a2: if(regs.flaga.s0 == 1) regs.pc = jp; return;  //JSA0
  case 0x0a4: if(regs.flagb.s0 == 0) regs.pc = jp; return;  //JNSB0
  case 0x0a6: if(regs.flagb.s0 == 1) regs.pc = jp; return;  //JSB0

  case 0x0a8: if(regs.flaga.s1 == 0) regs.pc = jp; return;  //JNSA1
  case 0x0aa: if(regs.flaga.s1 == 1) regs.pc = jp; return;  //JSA1
  case 0x0ac: if(regs.flagb.s1 == 0) regs.pc = jp; return;  //JNSB1
  case 0x0ae: if(regs.flagb.s1 == 1) regs.pc = jp; return;  //JSB1

  case 0x0b0: if((regs.dp & 0x0f) == 0x00) regs.pc = jp; return;  //JDPL0
  case 0x0b1: if((regs.dp & 0x0f) != 0x00) regs.pc = jp; return;  //JDPLN0
  case 0x0b2: if((regs.dp & 0x0f) == 0x0f) regs.pc = jp; return;  //JDPLF
  case 0x0b3: if((regs.dp & 0x0f) != 0x0f) regs.pc = jp; return;  //JDPLNF

  case 0x0bc: if(regs.sr.rqm == 0) regs.pc = jp; return;  //JNRQM
  case 0x0be: if(regs.sr.rqm == 1) regs.pc = jp; return;  //JRQM

  case 0x100: regs.pc = jp & ~0x2000; return;  //LJMP
  case 0x101: regs.pc = jp |  0x2000; return;  //HJMP

  case 0x140: regs.stack[regs.sp++] = regs.pc; regs.pc = jp & ~0x2000; return;  //LCALL
  case 0x141: regs.stack[regs.sp++] = regs.pc; regs.pc = jp |  0x2000; return;  //HCALL
  }
}

void uPD96050::exec_ld(uint24 opcode) {
  uint16 id = opcode >> 6;  //immediate data
  uint4 dst = opcode >> 0;  //destination

  switch(dst) {
  case  0: break;
  case  1: regs.a = id; break;
  case  2: regs.b = id; break;
  case  3: regs.tr = id; break;
  case  4: regs.dp = id; break;
  case  5: regs.rp = id; break;
  case  6: regs.dr = id; regs.sr.rqm = 1; break;
  case  7: regs.sr = (regs.sr & 0x907c) | (id & ~0x907c); break;
  case  8: regs.so = id; break;  //LSB
  case  9: regs.so = id; break;  //MSB
  case 10: regs.k = id; break;
  case 11: regs.k = id; regs.l = dataROM[regs.rp]; break;
  case 12: regs.l = id; regs.k = dataRAM[regs.dp | 0x40]; break;
  case 13: regs.l = id; break;
  case 14: regs.trb = id; break;
  case 15: dataRAM[regs.dp] = id; break;
  }
}