166e63ce3Schristos /* m6811_cpu.c -- 68HC11&68HC12 CPU Emulation
2*1424dfb3Schristos    Copyright 1999-2020 Free Software Foundation, Inc.
366e63ce3Schristos    Written by Stephane Carrez (stcarrez@nerim.fr)
466e63ce3Schristos 
566e63ce3Schristos This file is part of GDB, GAS, and the GNU binutils.
666e63ce3Schristos 
766e63ce3Schristos This program is free software; you can redistribute it and/or modify
866e63ce3Schristos it under the terms of the GNU General Public License as published by
966e63ce3Schristos the Free Software Foundation; either version 3 of the License, or
1066e63ce3Schristos (at your option) any later version.
1166e63ce3Schristos 
1266e63ce3Schristos This program is distributed in the hope that it will be useful,
1366e63ce3Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of
1466e63ce3Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1566e63ce3Schristos GNU General Public License for more details.
1666e63ce3Schristos 
1766e63ce3Schristos You should have received a copy of the GNU General Public License
1866e63ce3Schristos along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
1966e63ce3Schristos 
2066e63ce3Schristos #include "sim-main.h"
2166e63ce3Schristos #include "sim-assert.h"
2266e63ce3Schristos #include "sim-module.h"
2366e63ce3Schristos #include "sim-options.h"
2466e63ce3Schristos 
2566e63ce3Schristos enum {
2666e63ce3Schristos   OPTION_CPU_RESET = OPTION_START,
2766e63ce3Schristos   OPTION_EMUL_OS,
2866e63ce3Schristos   OPTION_CPU_CONFIG,
2966e63ce3Schristos   OPTION_CPU_BOOTSTRAP,
3066e63ce3Schristos   OPTION_CPU_MODE
3166e63ce3Schristos };
3266e63ce3Schristos 
3366e63ce3Schristos static DECLARE_OPTION_HANDLER (cpu_option_handler);
3466e63ce3Schristos 
3566e63ce3Schristos static const OPTION cpu_options[] =
3666e63ce3Schristos {
3766e63ce3Schristos   { {"cpu-reset", no_argument, NULL, OPTION_CPU_RESET },
3866e63ce3Schristos       '\0', NULL, "Reset the CPU",
3966e63ce3Schristos       cpu_option_handler },
4066e63ce3Schristos 
4166e63ce3Schristos   { {"emulos",    no_argument, NULL, OPTION_EMUL_OS },
4266e63ce3Schristos       '\0', NULL, "Emulate some OS system calls (read, write, ...)",
4366e63ce3Schristos       cpu_option_handler },
4466e63ce3Schristos 
4566e63ce3Schristos   { {"cpu-config", required_argument, NULL, OPTION_CPU_CONFIG },
4666e63ce3Schristos       '\0', NULL, "Specify the initial CPU configuration register",
4766e63ce3Schristos       cpu_option_handler },
4866e63ce3Schristos 
4966e63ce3Schristos   { {"bootstrap", no_argument, NULL, OPTION_CPU_BOOTSTRAP },
5066e63ce3Schristos       '\0', NULL, "Start the processing in bootstrap mode",
5166e63ce3Schristos       cpu_option_handler },
5266e63ce3Schristos 
5366e63ce3Schristos   { {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL }
5466e63ce3Schristos };
5566e63ce3Schristos 
5666e63ce3Schristos 
5766e63ce3Schristos static SIM_RC
cpu_option_handler(SIM_DESC sd,sim_cpu * cpu,int opt,char * arg,int is_command)5866e63ce3Schristos cpu_option_handler (SIM_DESC sd, sim_cpu *cpu,
5966e63ce3Schristos                     int opt, char *arg, int is_command)
6066e63ce3Schristos {
6166e63ce3Schristos   int val;
6266e63ce3Schristos 
6366e63ce3Schristos   cpu = STATE_CPU (sd, 0);
6466e63ce3Schristos   switch (opt)
6566e63ce3Schristos     {
6666e63ce3Schristos     case OPTION_CPU_RESET:
6766e63ce3Schristos       sim_board_reset (sd);
6866e63ce3Schristos       break;
6966e63ce3Schristos 
7066e63ce3Schristos     case OPTION_EMUL_OS:
7166e63ce3Schristos       cpu->cpu_emul_syscall = 1;
7266e63ce3Schristos       break;
7366e63ce3Schristos 
7466e63ce3Schristos     case OPTION_CPU_CONFIG:
7566e63ce3Schristos       if (sscanf(arg, "0x%x", &val) == 1
7666e63ce3Schristos           || sscanf(arg, "%d", &val) == 1)
7766e63ce3Schristos         {
7866e63ce3Schristos           cpu->cpu_config = val;
7966e63ce3Schristos           cpu->cpu_use_local_config = 1;
8066e63ce3Schristos         }
8166e63ce3Schristos       else
8266e63ce3Schristos         cpu->cpu_use_local_config = 0;
8366e63ce3Schristos       break;
8466e63ce3Schristos 
8566e63ce3Schristos     case OPTION_CPU_BOOTSTRAP:
8666e63ce3Schristos        cpu->cpu_start_mode = "bootstrap";
8766e63ce3Schristos        break;
8866e63ce3Schristos 
8966e63ce3Schristos     case OPTION_CPU_MODE:
9066e63ce3Schristos       break;
9166e63ce3Schristos     }
9266e63ce3Schristos 
9366e63ce3Schristos   return SIM_RC_OK;
9466e63ce3Schristos }
9566e63ce3Schristos 
9666e63ce3Schristos 
9766e63ce3Schristos void
cpu_call(sim_cpu * cpu,uint16 addr)9866e63ce3Schristos cpu_call (sim_cpu *cpu, uint16 addr)
9966e63ce3Schristos {
10066e63ce3Schristos 
10166e63ce3Schristos   cpu_set_pc (cpu, addr);
10266e63ce3Schristos }
10366e63ce3Schristos 
10466e63ce3Schristos void
cpu_return(sim_cpu * cpu)10566e63ce3Schristos cpu_return (sim_cpu *cpu)
10666e63ce3Schristos {
10766e63ce3Schristos }
10866e63ce3Schristos 
10966e63ce3Schristos /* Set the stack pointer and re-compute the current frame.  */
11066e63ce3Schristos void
cpu_set_sp(sim_cpu * cpu,uint16 val)11166e63ce3Schristos cpu_set_sp (sim_cpu *cpu, uint16 val)
11266e63ce3Schristos {
11366e63ce3Schristos   cpu->cpu_regs.sp = val;
11466e63ce3Schristos }
11566e63ce3Schristos 
11666e63ce3Schristos uint16
cpu_get_reg(sim_cpu * cpu,uint8 reg)11766e63ce3Schristos cpu_get_reg (sim_cpu *cpu, uint8 reg)
11866e63ce3Schristos {
11966e63ce3Schristos   switch (reg)
12066e63ce3Schristos     {
12166e63ce3Schristos     case 0:
12266e63ce3Schristos       return cpu_get_x (cpu);
12366e63ce3Schristos 
12466e63ce3Schristos     case 1:
12566e63ce3Schristos       return cpu_get_y (cpu);
12666e63ce3Schristos 
12766e63ce3Schristos     case 2:
12866e63ce3Schristos       return cpu_get_sp (cpu);
12966e63ce3Schristos 
13066e63ce3Schristos     case 3:
13166e63ce3Schristos       return cpu_get_pc (cpu);
13266e63ce3Schristos 
13366e63ce3Schristos     default:
13466e63ce3Schristos       return 0;
13566e63ce3Schristos     }
13666e63ce3Schristos }
13766e63ce3Schristos 
13866e63ce3Schristos uint16
cpu_get_src_reg(sim_cpu * cpu,uint8 reg)13966e63ce3Schristos cpu_get_src_reg (sim_cpu *cpu, uint8 reg)
14066e63ce3Schristos {
14166e63ce3Schristos   switch (reg)
14266e63ce3Schristos     {
14366e63ce3Schristos     case 0:
14466e63ce3Schristos       return cpu_get_a (cpu);
14566e63ce3Schristos 
14666e63ce3Schristos     case 1:
14766e63ce3Schristos       return cpu_get_b (cpu);
14866e63ce3Schristos 
14966e63ce3Schristos     case 2:
15066e63ce3Schristos       return cpu_get_ccr (cpu);
15166e63ce3Schristos 
15266e63ce3Schristos     case 3:
15366e63ce3Schristos       return cpu_get_tmp3 (cpu);
15466e63ce3Schristos 
15566e63ce3Schristos     case 4:
15666e63ce3Schristos       return cpu_get_d (cpu);
15766e63ce3Schristos 
15866e63ce3Schristos     case 5:
15966e63ce3Schristos       return cpu_get_x (cpu);
16066e63ce3Schristos 
16166e63ce3Schristos     case 6:
16266e63ce3Schristos       return cpu_get_y (cpu);
16366e63ce3Schristos 
16466e63ce3Schristos     case 7:
16566e63ce3Schristos       return cpu_get_sp (cpu);
16666e63ce3Schristos 
16766e63ce3Schristos     default:
16866e63ce3Schristos       return 0;
16966e63ce3Schristos     }
17066e63ce3Schristos }
17166e63ce3Schristos 
17266e63ce3Schristos void
cpu_set_dst_reg(sim_cpu * cpu,uint8 reg,uint16 val)17366e63ce3Schristos cpu_set_dst_reg (sim_cpu *cpu, uint8 reg, uint16 val)
17466e63ce3Schristos {
17566e63ce3Schristos   switch (reg)
17666e63ce3Schristos     {
17766e63ce3Schristos     case 0:
17866e63ce3Schristos       cpu_set_a (cpu, val);
17966e63ce3Schristos       break;
18066e63ce3Schristos 
18166e63ce3Schristos     case 1:
18266e63ce3Schristos       cpu_set_b (cpu, val);
18366e63ce3Schristos       break;
18466e63ce3Schristos 
18566e63ce3Schristos     case 2:
18666e63ce3Schristos       cpu_set_ccr (cpu, val);
18766e63ce3Schristos       break;
18866e63ce3Schristos 
18966e63ce3Schristos     case 3:
19066e63ce3Schristos       cpu_set_tmp2 (cpu, val);
19166e63ce3Schristos       break;
19266e63ce3Schristos 
19366e63ce3Schristos     case 4:
19466e63ce3Schristos       cpu_set_d (cpu, val);
19566e63ce3Schristos       break;
19666e63ce3Schristos 
19766e63ce3Schristos     case 5:
19866e63ce3Schristos       cpu_set_x (cpu, val);
19966e63ce3Schristos       break;
20066e63ce3Schristos 
20166e63ce3Schristos     case 6:
20266e63ce3Schristos       cpu_set_y (cpu, val);
20366e63ce3Schristos       break;
20466e63ce3Schristos 
20566e63ce3Schristos     case 7:
20666e63ce3Schristos       cpu_set_sp (cpu, val);
20766e63ce3Schristos       break;
20866e63ce3Schristos 
20966e63ce3Schristos     default:
21066e63ce3Schristos       break;
21166e63ce3Schristos     }
21266e63ce3Schristos }
21366e63ce3Schristos 
21466e63ce3Schristos void
cpu_set_reg(sim_cpu * cpu,uint8 reg,uint16 val)21566e63ce3Schristos cpu_set_reg (sim_cpu *cpu, uint8 reg, uint16 val)
21666e63ce3Schristos {
21766e63ce3Schristos   switch (reg)
21866e63ce3Schristos     {
21966e63ce3Schristos     case 0:
22066e63ce3Schristos       cpu_set_x (cpu, val);
22166e63ce3Schristos       break;
22266e63ce3Schristos 
22366e63ce3Schristos     case 1:
22466e63ce3Schristos       cpu_set_y (cpu, val);
22566e63ce3Schristos       break;
22666e63ce3Schristos 
22766e63ce3Schristos     case 2:
22866e63ce3Schristos       cpu_set_sp (cpu, val);
22966e63ce3Schristos       break;
23066e63ce3Schristos 
23166e63ce3Schristos     case 3:
23266e63ce3Schristos       cpu_set_pc (cpu, val);
23366e63ce3Schristos       break;
23466e63ce3Schristos 
23566e63ce3Schristos     default:
23666e63ce3Schristos       break;
23766e63ce3Schristos     }
23866e63ce3Schristos }
23966e63ce3Schristos 
24066e63ce3Schristos /* Returns the address of a 68HC12 indexed operand.
24166e63ce3Schristos    Pre and post modifications are handled on the source register.  */
24266e63ce3Schristos uint16
cpu_get_indexed_operand_addr(sim_cpu * cpu,int restricted)243ed6a76a9Schristos cpu_get_indexed_operand_addr (sim_cpu *cpu, int restricted)
24466e63ce3Schristos {
24566e63ce3Schristos   uint8 reg;
24666e63ce3Schristos   uint16 sval;
24766e63ce3Schristos   uint16 addr;
24866e63ce3Schristos   uint8 code;
24966e63ce3Schristos 
25066e63ce3Schristos   code = cpu_fetch8 (cpu);
25166e63ce3Schristos 
25266e63ce3Schristos   /* n,r with 5-bit signed constant.  */
25366e63ce3Schristos   if ((code & 0x20) == 0)
25466e63ce3Schristos     {
25566e63ce3Schristos       reg = (code >> 6) & 3;
25666e63ce3Schristos       sval = (code & 0x1f);
25766e63ce3Schristos       if (code & 0x10)
25866e63ce3Schristos 	sval |= 0xfff0;
25966e63ce3Schristos 
26066e63ce3Schristos       addr = cpu_get_reg (cpu, reg);
26166e63ce3Schristos       addr += sval;
26266e63ce3Schristos     }
26366e63ce3Schristos 
26466e63ce3Schristos   /* Auto pre/post increment/decrement.  */
26566e63ce3Schristos   else if ((code & 0xc0) != 0xc0)
26666e63ce3Schristos     {
26766e63ce3Schristos       reg = (code >> 6) & 3;
26866e63ce3Schristos       sval = (code & 0x0f);
26966e63ce3Schristos       if (sval & 0x8)
27066e63ce3Schristos 	{
27166e63ce3Schristos 	  sval |= 0xfff0;
27266e63ce3Schristos 	}
27366e63ce3Schristos       else
27466e63ce3Schristos 	{
27566e63ce3Schristos 	  sval = sval + 1;
27666e63ce3Schristos 	}
27766e63ce3Schristos       addr = cpu_get_reg (cpu, reg);
27866e63ce3Schristos       cpu_set_reg (cpu, reg, addr + sval);
27966e63ce3Schristos       if ((code & 0x10) == 0)
28066e63ce3Schristos 	{
28166e63ce3Schristos 	  addr += sval;
28266e63ce3Schristos 	}
28366e63ce3Schristos     }
28466e63ce3Schristos 
28566e63ce3Schristos   /* [n,r] 16-bits offset indexed indirect.  */
28666e63ce3Schristos   else if ((code & 0x07) == 3)
28766e63ce3Schristos     {
288ed6a76a9Schristos       if (restricted)
28966e63ce3Schristos 	{
29066e63ce3Schristos 	  return 0;
29166e63ce3Schristos 	}
29266e63ce3Schristos       reg = (code >> 3) & 0x03;
29366e63ce3Schristos       addr = cpu_get_reg (cpu, reg);
29466e63ce3Schristos       addr += cpu_fetch16 (cpu);
29566e63ce3Schristos       addr = memory_read16 (cpu, addr);
29666e63ce3Schristos       cpu_add_cycles (cpu, 1);
29766e63ce3Schristos     }
29866e63ce3Schristos   else if ((code & 0x4) == 0)
29966e63ce3Schristos     {
300ed6a76a9Schristos       if (restricted)
30166e63ce3Schristos 	{
30266e63ce3Schristos 	  return 0;
30366e63ce3Schristos 	}
30466e63ce3Schristos       reg = (code >> 3) & 0x03;
30566e63ce3Schristos       addr = cpu_get_reg (cpu, reg);
30666e63ce3Schristos       if (code & 0x2)
30766e63ce3Schristos 	{
30866e63ce3Schristos 	  sval = cpu_fetch16 (cpu);
30966e63ce3Schristos 	  cpu_add_cycles (cpu, 1);
31066e63ce3Schristos 	}
31166e63ce3Schristos       else
31266e63ce3Schristos 	{
31366e63ce3Schristos 	  sval = cpu_fetch8 (cpu);
31466e63ce3Schristos 	  if (code & 0x1)
31566e63ce3Schristos 	    sval |= 0xff00;
31666e63ce3Schristos 	  cpu_add_cycles (cpu, 1);
31766e63ce3Schristos 	}
31866e63ce3Schristos       addr += sval;
31966e63ce3Schristos     }
32066e63ce3Schristos   else
32166e63ce3Schristos     {
32266e63ce3Schristos       reg = (code >> 3) & 0x03;
32366e63ce3Schristos       addr = cpu_get_reg (cpu, reg);
32466e63ce3Schristos       switch (code & 3)
32566e63ce3Schristos 	{
32666e63ce3Schristos 	case 0:
32766e63ce3Schristos 	  addr += cpu_get_a (cpu);
32866e63ce3Schristos 	  break;
32966e63ce3Schristos 	case 1:
33066e63ce3Schristos 	  addr += cpu_get_b (cpu);
33166e63ce3Schristos 	  break;
33266e63ce3Schristos 	case 2:
33366e63ce3Schristos 	  addr += cpu_get_d (cpu);
33466e63ce3Schristos 	  break;
33566e63ce3Schristos 	case 3:
33666e63ce3Schristos 	default:
33766e63ce3Schristos 	  addr += cpu_get_d (cpu);
33866e63ce3Schristos 	  addr = memory_read16 (cpu, addr);
33966e63ce3Schristos 	  cpu_add_cycles (cpu, 1);
34066e63ce3Schristos 	  break;
34166e63ce3Schristos 	}
34266e63ce3Schristos     }
34366e63ce3Schristos 
34466e63ce3Schristos   return addr;
34566e63ce3Schristos }
34666e63ce3Schristos 
34766e63ce3Schristos uint8
cpu_get_indexed_operand8(sim_cpu * cpu,int restricted)348ed6a76a9Schristos cpu_get_indexed_operand8 (sim_cpu *cpu, int restricted)
34966e63ce3Schristos {
35066e63ce3Schristos   uint16 addr;
35166e63ce3Schristos 
352ed6a76a9Schristos   addr = cpu_get_indexed_operand_addr (cpu, restricted);
35366e63ce3Schristos   return memory_read8 (cpu, addr);
35466e63ce3Schristos }
35566e63ce3Schristos 
35666e63ce3Schristos uint16
cpu_get_indexed_operand16(sim_cpu * cpu,int restricted)357ed6a76a9Schristos cpu_get_indexed_operand16 (sim_cpu *cpu, int restricted)
35866e63ce3Schristos {
35966e63ce3Schristos   uint16 addr;
36066e63ce3Schristos 
361ed6a76a9Schristos   addr = cpu_get_indexed_operand_addr (cpu, restricted);
36266e63ce3Schristos   return memory_read16 (cpu, addr);
36366e63ce3Schristos }
36466e63ce3Schristos 
36566e63ce3Schristos void
cpu_move8(sim_cpu * cpu,uint8 code)36666e63ce3Schristos cpu_move8 (sim_cpu *cpu, uint8 code)
36766e63ce3Schristos {
36866e63ce3Schristos   uint8 src;
36966e63ce3Schristos   uint16 addr;
37066e63ce3Schristos 
37166e63ce3Schristos   switch (code)
37266e63ce3Schristos     {
37366e63ce3Schristos     case 0x0b:
37466e63ce3Schristos       src = cpu_fetch8 (cpu);
37566e63ce3Schristos       addr = cpu_fetch16 (cpu);
37666e63ce3Schristos       break;
37766e63ce3Schristos 
37866e63ce3Schristos     case 0x08:
37966e63ce3Schristos       addr = cpu_get_indexed_operand_addr (cpu, 1);
38066e63ce3Schristos       src = cpu_fetch8 (cpu);
38166e63ce3Schristos       break;
38266e63ce3Schristos 
38366e63ce3Schristos     case 0x0c:
38466e63ce3Schristos       addr = cpu_fetch16 (cpu);
38566e63ce3Schristos       src = memory_read8 (cpu, addr);
38666e63ce3Schristos       addr = cpu_fetch16 (cpu);
38766e63ce3Schristos       break;
38866e63ce3Schristos 
38966e63ce3Schristos     case 0x09:
39066e63ce3Schristos       addr = cpu_get_indexed_operand_addr (cpu, 1);
39166e63ce3Schristos       src = memory_read8 (cpu, cpu_fetch16 (cpu));
39266e63ce3Schristos       break;
39366e63ce3Schristos 
39466e63ce3Schristos     case 0x0d:
39566e63ce3Schristos       src = cpu_get_indexed_operand8 (cpu, 1);
39666e63ce3Schristos       addr = cpu_fetch16 (cpu);
39766e63ce3Schristos       break;
39866e63ce3Schristos 
39966e63ce3Schristos     case 0x0a:
40066e63ce3Schristos       src = cpu_get_indexed_operand8 (cpu, 1);
40166e63ce3Schristos       addr = cpu_get_indexed_operand_addr (cpu, 1);
40266e63ce3Schristos       break;
40366e63ce3Schristos 
40466e63ce3Schristos     default:
40566e63ce3Schristos       sim_engine_abort (CPU_STATE (cpu), cpu, 0,
40666e63ce3Schristos 			"Invalid code 0x%0x -- internal error?", code);
40766e63ce3Schristos       return;
40866e63ce3Schristos     }
40966e63ce3Schristos   memory_write8 (cpu, addr, src);
41066e63ce3Schristos }
41166e63ce3Schristos 
41266e63ce3Schristos void
cpu_move16(sim_cpu * cpu,uint8 code)41366e63ce3Schristos cpu_move16 (sim_cpu *cpu, uint8 code)
41466e63ce3Schristos {
41566e63ce3Schristos   uint16 src;
41666e63ce3Schristos   uint16 addr;
41766e63ce3Schristos 
41866e63ce3Schristos   switch (code)
41966e63ce3Schristos     {
42066e63ce3Schristos     case 0x03:
42166e63ce3Schristos       src = cpu_fetch16 (cpu);
42266e63ce3Schristos       addr = cpu_fetch16 (cpu);
42366e63ce3Schristos       break;
42466e63ce3Schristos 
42566e63ce3Schristos     case 0x00:
42666e63ce3Schristos       addr = cpu_get_indexed_operand_addr (cpu, 1);
42766e63ce3Schristos       src = cpu_fetch16 (cpu);
42866e63ce3Schristos       break;
42966e63ce3Schristos 
43066e63ce3Schristos     case 0x04:
43166e63ce3Schristos       addr = cpu_fetch16 (cpu);
43266e63ce3Schristos       src = memory_read16 (cpu, addr);
43366e63ce3Schristos       addr = cpu_fetch16 (cpu);
43466e63ce3Schristos       break;
43566e63ce3Schristos 
43666e63ce3Schristos     case 0x01:
43766e63ce3Schristos       addr = cpu_get_indexed_operand_addr (cpu, 1);
43866e63ce3Schristos       src = memory_read16 (cpu, cpu_fetch16 (cpu));
43966e63ce3Schristos       break;
44066e63ce3Schristos 
44166e63ce3Schristos     case 0x05:
44266e63ce3Schristos       src = cpu_get_indexed_operand16 (cpu, 1);
44366e63ce3Schristos       addr = cpu_fetch16 (cpu);
44466e63ce3Schristos       break;
44566e63ce3Schristos 
44666e63ce3Schristos     case 0x02:
44766e63ce3Schristos       src = cpu_get_indexed_operand16 (cpu, 1);
44866e63ce3Schristos       addr = cpu_get_indexed_operand_addr (cpu, 1);
44966e63ce3Schristos       break;
45066e63ce3Schristos 
45166e63ce3Schristos     default:
45266e63ce3Schristos       sim_engine_abort (CPU_STATE (cpu), cpu, 0,
45366e63ce3Schristos 			"Invalid code 0x%0x -- internal error?", code);
45466e63ce3Schristos       return;
45566e63ce3Schristos     }
45666e63ce3Schristos   memory_write16 (cpu, addr, src);
45766e63ce3Schristos }
45866e63ce3Schristos 
45966e63ce3Schristos int
cpu_initialize(SIM_DESC sd,sim_cpu * cpu)46066e63ce3Schristos cpu_initialize (SIM_DESC sd, sim_cpu *cpu)
46166e63ce3Schristos {
46266e63ce3Schristos   sim_add_option_table (sd, 0, cpu_options);
46366e63ce3Schristos 
46466e63ce3Schristos   memset (&cpu->cpu_regs, 0, sizeof(cpu->cpu_regs));
46566e63ce3Schristos 
46666e63ce3Schristos   cpu->cpu_absolute_cycle = 0;
46766e63ce3Schristos   cpu->cpu_current_cycle  = 0;
46866e63ce3Schristos   cpu->cpu_emul_syscall   = 1;
46966e63ce3Schristos   cpu->cpu_running        = 1;
47066e63ce3Schristos   cpu->cpu_stop_on_interrupt = 0;
47166e63ce3Schristos   cpu->cpu_frequency = 8 * 1000 * 1000;
47266e63ce3Schristos   cpu->cpu_use_elf_start = 0;
47366e63ce3Schristos   cpu->cpu_elf_start     = 0;
47466e63ce3Schristos   cpu->cpu_use_local_config = 0;
47566e63ce3Schristos   cpu->bank_start = 0;
47666e63ce3Schristos   cpu->bank_end   = 0;
47766e63ce3Schristos   cpu->bank_shift = 0;
47866e63ce3Schristos   cpu->cpu_config        = M6811_NOSEC | M6811_NOCOP | M6811_ROMON |
47966e63ce3Schristos     M6811_EEON;
48066e63ce3Schristos   interrupts_initialize (sd, cpu);
48166e63ce3Schristos 
48266e63ce3Schristos   cpu->cpu_is_initialized = 1;
48366e63ce3Schristos   return 0;
48466e63ce3Schristos }
48566e63ce3Schristos 
48666e63ce3Schristos 
48766e63ce3Schristos /* Reinitialize the processor after a reset.  */
48866e63ce3Schristos int
cpu_reset(sim_cpu * cpu)48966e63ce3Schristos cpu_reset (sim_cpu *cpu)
49066e63ce3Schristos {
49166e63ce3Schristos   /* Initialize the config register.
49266e63ce3Schristos      It is only initialized at reset time.  */
49366e63ce3Schristos   memset (cpu->ios, 0, sizeof (cpu->ios));
49466e63ce3Schristos   if (cpu->cpu_configured_arch->arch == bfd_arch_m68hc11)
49566e63ce3Schristos     cpu->ios[M6811_INIT] = 0x1;
49666e63ce3Schristos   else
49766e63ce3Schristos     cpu->ios[M6811_INIT] = 0;
49866e63ce3Schristos 
49966e63ce3Schristos   /* Output compare registers set to 0xFFFF.  */
50066e63ce3Schristos   cpu->ios[M6811_TOC1_H] = 0xFF;
50166e63ce3Schristos   cpu->ios[M6811_TOC1_L] = 0xFF;
50266e63ce3Schristos   cpu->ios[M6811_TOC2_H] = 0xFF;
50366e63ce3Schristos   cpu->ios[M6811_TOC2_L] = 0xFF;
50466e63ce3Schristos   cpu->ios[M6811_TOC3_H] = 0xFF;
50566e63ce3Schristos   cpu->ios[M6811_TOC4_L] = 0xFF;
50666e63ce3Schristos   cpu->ios[M6811_TOC5_H] = 0xFF;
50766e63ce3Schristos   cpu->ios[M6811_TOC5_L] = 0xFF;
50866e63ce3Schristos 
50966e63ce3Schristos   /* Setup the processor registers.  */
51066e63ce3Schristos   memset (&cpu->cpu_regs, 0, sizeof(cpu->cpu_regs));
51166e63ce3Schristos   cpu->cpu_absolute_cycle = 0;
51266e63ce3Schristos   cpu->cpu_current_cycle  = 0;
51366e63ce3Schristos   cpu->cpu_is_initialized = 0;
51466e63ce3Schristos 
51566e63ce3Schristos   /* Reset interrupts.  */
51666e63ce3Schristos   interrupts_reset (&cpu->cpu_interrupts);
51766e63ce3Schristos 
51866e63ce3Schristos   /* Reinitialize the CPU operating mode.  */
51966e63ce3Schristos   cpu->ios[M6811_HPRIO] = cpu->cpu_mode;
52066e63ce3Schristos   return 0;
52166e63ce3Schristos }
52266e63ce3Schristos 
52366e63ce3Schristos /* Reinitialize the processor after a reset.  */
52466e63ce3Schristos int
cpu_restart(sim_cpu * cpu)52566e63ce3Schristos cpu_restart (sim_cpu *cpu)
52666e63ce3Schristos {
52766e63ce3Schristos   uint16 addr;
52866e63ce3Schristos 
52966e63ce3Schristos   /* Get CPU starting address depending on the CPU mode.  */
53066e63ce3Schristos   if (cpu->cpu_use_elf_start == 0)
53166e63ce3Schristos     {
53266e63ce3Schristos       switch ((cpu->ios[M6811_HPRIO]) & (M6811_SMOD | M6811_MDA))
53366e63ce3Schristos         {
53466e63ce3Schristos           /* Single Chip  */
53566e63ce3Schristos         default:
53666e63ce3Schristos         case 0 :
53766e63ce3Schristos           addr = memory_read16 (cpu, 0xFFFE);
53866e63ce3Schristos           break;
53966e63ce3Schristos 
54066e63ce3Schristos           /* Expanded Multiplexed  */
54166e63ce3Schristos         case M6811_MDA:
54266e63ce3Schristos           addr = memory_read16 (cpu, 0xFFFE);
54366e63ce3Schristos           break;
54466e63ce3Schristos 
54566e63ce3Schristos           /* Special Bootstrap  */
54666e63ce3Schristos         case M6811_SMOD:
54766e63ce3Schristos           addr = 0;
54866e63ce3Schristos           break;
54966e63ce3Schristos 
55066e63ce3Schristos           /* Factory Test  */
55166e63ce3Schristos         case M6811_MDA | M6811_SMOD:
55266e63ce3Schristos           addr = memory_read16 (cpu, 0xFFFE);
55366e63ce3Schristos           break;
55466e63ce3Schristos         }
55566e63ce3Schristos     }
55666e63ce3Schristos   else
55766e63ce3Schristos     {
55866e63ce3Schristos       addr = cpu->cpu_elf_start;
55966e63ce3Schristos     }
56066e63ce3Schristos 
56166e63ce3Schristos   /* Setup the processor registers.  */
56266e63ce3Schristos   cpu->cpu_insn_pc  = addr;
56366e63ce3Schristos   cpu->cpu_regs.pc  = addr;
56466e63ce3Schristos   cpu->cpu_regs.ccr = M6811_X_BIT | M6811_I_BIT | M6811_S_BIT;
56566e63ce3Schristos   cpu->cpu_absolute_cycle = 0;
56666e63ce3Schristos   cpu->cpu_is_initialized = 1;
56766e63ce3Schristos   cpu->cpu_current_cycle  = 0;
56866e63ce3Schristos 
56966e63ce3Schristos   cpu_call (cpu, addr);
57066e63ce3Schristos 
57166e63ce3Schristos   return 0;
57266e63ce3Schristos }
57366e63ce3Schristos 
57466e63ce3Schristos void
print_io_reg_desc(SIM_DESC sd,io_reg_desc * desc,int val,int mode)57566e63ce3Schristos print_io_reg_desc (SIM_DESC sd, io_reg_desc *desc, int val, int mode)
57666e63ce3Schristos {
57766e63ce3Schristos   while (desc->mask)
57866e63ce3Schristos     {
57966e63ce3Schristos       if (val & desc->mask)
58066e63ce3Schristos 	sim_io_printf (sd, "%s",
58166e63ce3Schristos 		       mode == 0 ? desc->short_name : desc->long_name);
58266e63ce3Schristos       desc++;
58366e63ce3Schristos     }
58466e63ce3Schristos }
58566e63ce3Schristos 
58666e63ce3Schristos void
print_io_byte(SIM_DESC sd,const char * name,io_reg_desc * desc,uint8 val,uint16 addr)58766e63ce3Schristos print_io_byte (SIM_DESC sd, const char *name, io_reg_desc *desc,
58866e63ce3Schristos 	       uint8 val, uint16 addr)
58966e63ce3Schristos {
59066e63ce3Schristos   sim_io_printf (sd, "  %-9.9s @ 0x%04x 0x%02x ", name, addr, val);
59166e63ce3Schristos   if (desc)
59266e63ce3Schristos     print_io_reg_desc (sd, desc, val, 0);
59366e63ce3Schristos }
59466e63ce3Schristos 
59566e63ce3Schristos void
print_io_word(SIM_DESC sd,const char * name,io_reg_desc * desc,uint16 val,uint16 addr)59666e63ce3Schristos print_io_word (SIM_DESC sd, const char *name, io_reg_desc *desc,
59766e63ce3Schristos 	       uint16 val, uint16 addr)
59866e63ce3Schristos {
59966e63ce3Schristos   sim_io_printf (sd, "  %-9.9s @ 0x%04x 0x%04x ", name, addr, val);
60066e63ce3Schristos   if (desc)
60166e63ce3Schristos     print_io_reg_desc (sd, desc, val, 0);
60266e63ce3Schristos }
60366e63ce3Schristos 
60466e63ce3Schristos void
cpu_ccr_update_tst8(sim_cpu * cpu,uint8 val)6051c468f90Schristos cpu_ccr_update_tst8 (sim_cpu *cpu, uint8 val)
60666e63ce3Schristos {
6071c468f90Schristos   cpu_set_ccr_V (cpu, 0);
6081c468f90Schristos   cpu_set_ccr_N (cpu, val & 0x80 ? 1 : 0);
6091c468f90Schristos   cpu_set_ccr_Z (cpu, val == 0 ? 1 : 0);
61066e63ce3Schristos }
61166e63ce3Schristos 
61266e63ce3Schristos 
61366e63ce3Schristos uint16
cpu_fetch_relbranch(sim_cpu * cpu)61466e63ce3Schristos cpu_fetch_relbranch (sim_cpu *cpu)
61566e63ce3Schristos {
61666e63ce3Schristos   uint16 addr = (uint16) cpu_fetch8 (cpu);
61766e63ce3Schristos 
61866e63ce3Schristos   if (addr & 0x0080)
61966e63ce3Schristos     {
62066e63ce3Schristos       addr |= 0xFF00;
62166e63ce3Schristos     }
62266e63ce3Schristos   addr += cpu->cpu_regs.pc;
62366e63ce3Schristos   return addr;
62466e63ce3Schristos }
62566e63ce3Schristos 
62666e63ce3Schristos uint16
cpu_fetch_relbranch16(sim_cpu * cpu)62766e63ce3Schristos cpu_fetch_relbranch16 (sim_cpu *cpu)
62866e63ce3Schristos {
62966e63ce3Schristos   uint16 addr = cpu_fetch16 (cpu);
63066e63ce3Schristos 
63166e63ce3Schristos   addr += cpu->cpu_regs.pc;
63266e63ce3Schristos   return addr;
63366e63ce3Schristos }
63466e63ce3Schristos 
63566e63ce3Schristos /* Push all the CPU registers (when an interruption occurs).  */
63666e63ce3Schristos void
cpu_push_all(sim_cpu * cpu)63766e63ce3Schristos cpu_push_all (sim_cpu *cpu)
63866e63ce3Schristos {
63966e63ce3Schristos   if (cpu->cpu_configured_arch->arch == bfd_arch_m68hc11)
64066e63ce3Schristos     {
64166e63ce3Schristos       cpu_m68hc11_push_uint16 (cpu, cpu->cpu_regs.pc);
64266e63ce3Schristos       cpu_m68hc11_push_uint16 (cpu, cpu->cpu_regs.iy);
64366e63ce3Schristos       cpu_m68hc11_push_uint16 (cpu, cpu->cpu_regs.ix);
64466e63ce3Schristos       cpu_m68hc11_push_uint16 (cpu, cpu->cpu_regs.d);
64566e63ce3Schristos       cpu_m68hc11_push_uint8 (cpu, cpu->cpu_regs.ccr);
64666e63ce3Schristos     }
64766e63ce3Schristos   else
64866e63ce3Schristos     {
64966e63ce3Schristos       cpu_m68hc12_push_uint16 (cpu, cpu->cpu_regs.pc);
65066e63ce3Schristos       cpu_m68hc12_push_uint16 (cpu, cpu->cpu_regs.iy);
65166e63ce3Schristos       cpu_m68hc12_push_uint16 (cpu, cpu->cpu_regs.ix);
65266e63ce3Schristos       cpu_m68hc12_push_uint16 (cpu, cpu->cpu_regs.d);
65366e63ce3Schristos       cpu_m68hc12_push_uint8 (cpu, cpu->cpu_regs.ccr);
65466e63ce3Schristos     }
65566e63ce3Schristos }
65666e63ce3Schristos 
65766e63ce3Schristos /* Simulation of the dbcc/ibcc/tbcc 68HC12 conditional branch operations.  */
65866e63ce3Schristos void
cpu_dbcc(sim_cpu * cpu)65966e63ce3Schristos cpu_dbcc (sim_cpu *cpu)
66066e63ce3Schristos {
66166e63ce3Schristos   uint8 code;
66266e63ce3Schristos   uint16 addr;
66366e63ce3Schristos   uint16 inc;
66466e63ce3Schristos   uint16 reg;
66566e63ce3Schristos 
66666e63ce3Schristos   code = cpu_fetch8 (cpu);
66766e63ce3Schristos   switch (code & 0xc0)
66866e63ce3Schristos     {
66966e63ce3Schristos     case 0x80: /* ibcc */
67066e63ce3Schristos       inc = 1;
67166e63ce3Schristos       break;
67266e63ce3Schristos     case 0x40: /* tbcc */
67366e63ce3Schristos       inc = 0;
67466e63ce3Schristos       break;
67566e63ce3Schristos     case 0:    /* dbcc */
67666e63ce3Schristos       inc = -1;
67766e63ce3Schristos       break;
67866e63ce3Schristos     default:
67966e63ce3Schristos       abort ();
68066e63ce3Schristos       break;
68166e63ce3Schristos     }
68266e63ce3Schristos 
68366e63ce3Schristos   addr = cpu_fetch8 (cpu);
68466e63ce3Schristos   if (code & 0x10)
68566e63ce3Schristos     addr |= 0xff00;
68666e63ce3Schristos 
68766e63ce3Schristos   addr += cpu_get_pc (cpu);
68866e63ce3Schristos   reg = cpu_get_src_reg (cpu, code & 0x07);
68966e63ce3Schristos   reg += inc;
69066e63ce3Schristos 
69166e63ce3Schristos   /* Branch according to register value.  */
69266e63ce3Schristos   if ((reg != 0 && (code & 0x20)) || (reg == 0 && !(code & 0x20)))
69366e63ce3Schristos     {
69466e63ce3Schristos       cpu_set_pc (cpu, addr);
69566e63ce3Schristos     }
69666e63ce3Schristos   cpu_set_dst_reg (cpu, code & 0x07, reg);
69766e63ce3Schristos }
69866e63ce3Schristos 
69966e63ce3Schristos void
cpu_exg(sim_cpu * cpu,uint8 code)70066e63ce3Schristos cpu_exg (sim_cpu *cpu, uint8 code)
70166e63ce3Schristos {
70266e63ce3Schristos   uint8 r1, r2;
70366e63ce3Schristos   uint16 src1;
70466e63ce3Schristos   uint16 src2;
70566e63ce3Schristos 
70666e63ce3Schristos   r1 = (code >> 4) & 0x07;
70766e63ce3Schristos   r2 = code & 0x07;
70866e63ce3Schristos   if (code & 0x80)
70966e63ce3Schristos     {
71066e63ce3Schristos       src1 = cpu_get_src_reg (cpu, r1);
71166e63ce3Schristos       src2 = cpu_get_src_reg (cpu, r2);
71266e63ce3Schristos       if (r2 == 1 || r2 == 2)
71366e63ce3Schristos         src2 |= 0xff00;
71466e63ce3Schristos 
71566e63ce3Schristos       cpu_set_dst_reg (cpu, r2, src1);
71666e63ce3Schristos       cpu_set_dst_reg (cpu, r1, src2);
71766e63ce3Schristos     }
71866e63ce3Schristos   else
71966e63ce3Schristos     {
72066e63ce3Schristos       src1 = cpu_get_src_reg (cpu, r1);
72166e63ce3Schristos 
72266e63ce3Schristos       /* Sign extend the 8-bit registers (A, B, CCR).  */
72366e63ce3Schristos       if ((r1 == 0 || r1 == 1 || r1 == 2) && (src1 & 0x80))
72466e63ce3Schristos         src1 |= 0xff00;
72566e63ce3Schristos 
72666e63ce3Schristos       cpu_set_dst_reg (cpu, r2, src1);
72766e63ce3Schristos     }
72866e63ce3Schristos }
72966e63ce3Schristos 
73066e63ce3Schristos /* Handle special instructions.  */
73166e63ce3Schristos void
cpu_special(sim_cpu * cpu,enum M6811_Special special)73266e63ce3Schristos cpu_special (sim_cpu *cpu, enum M6811_Special special)
73366e63ce3Schristos {
73466e63ce3Schristos   switch (special)
73566e63ce3Schristos     {
73666e63ce3Schristos     case M6811_RTI:
73766e63ce3Schristos       {
73866e63ce3Schristos         uint8 ccr;
73966e63ce3Schristos 
74066e63ce3Schristos         ccr = cpu_m68hc11_pop_uint8 (cpu);
74166e63ce3Schristos         cpu_set_ccr (cpu, ccr);
74266e63ce3Schristos         cpu_set_d (cpu, cpu_m68hc11_pop_uint16 (cpu));
74366e63ce3Schristos         cpu_set_x (cpu, cpu_m68hc11_pop_uint16 (cpu));
74466e63ce3Schristos         cpu_set_y (cpu, cpu_m68hc11_pop_uint16 (cpu));
74566e63ce3Schristos         cpu_set_pc (cpu, cpu_m68hc11_pop_uint16 (cpu));
74666e63ce3Schristos 	cpu_return (cpu);
74766e63ce3Schristos         break;
74866e63ce3Schristos       }
74966e63ce3Schristos 
75066e63ce3Schristos     case M6812_RTI:
75166e63ce3Schristos       {
75266e63ce3Schristos         uint8 ccr;
75366e63ce3Schristos 
75466e63ce3Schristos         ccr = cpu_m68hc12_pop_uint8 (cpu);
75566e63ce3Schristos         cpu_set_ccr (cpu, ccr);
75666e63ce3Schristos         cpu_set_d (cpu, cpu_m68hc12_pop_uint16 (cpu));
75766e63ce3Schristos         cpu_set_x (cpu, cpu_m68hc12_pop_uint16 (cpu));
75866e63ce3Schristos         cpu_set_y (cpu, cpu_m68hc12_pop_uint16 (cpu));
75966e63ce3Schristos         cpu_set_pc (cpu, cpu_m68hc12_pop_uint16 (cpu));
76066e63ce3Schristos 	cpu_return (cpu);
76166e63ce3Schristos         break;
76266e63ce3Schristos       }
76366e63ce3Schristos 
76466e63ce3Schristos     case M6811_WAI:
76566e63ce3Schristos       /* In the ELF-start mode, we are in a special mode where
76666e63ce3Schristos 	 the WAI corresponds to an exit.  */
76766e63ce3Schristos       if (cpu->cpu_use_elf_start)
76866e63ce3Schristos         {
76966e63ce3Schristos           cpu_set_pc (cpu, cpu->cpu_insn_pc);
77066e63ce3Schristos           sim_engine_halt (CPU_STATE (cpu), cpu,
77166e63ce3Schristos                            NULL, NULL_CIA, sim_exited,
77266e63ce3Schristos                            cpu_get_d (cpu));
77366e63ce3Schristos           return;
77466e63ce3Schristos         }
77566e63ce3Schristos       /* SCz: not correct... */
77666e63ce3Schristos       cpu_push_all (cpu);
77766e63ce3Schristos       break;
77866e63ce3Schristos 
77966e63ce3Schristos     case M6811_SWI:
78066e63ce3Schristos       interrupts_raise (&cpu->cpu_interrupts, M6811_INT_SWI);
78166e63ce3Schristos       interrupts_process (&cpu->cpu_interrupts);
78266e63ce3Schristos       break;
78366e63ce3Schristos 
78466e63ce3Schristos     case M6811_EMUL_SYSCALL:
78566e63ce3Schristos     case M6811_ILLEGAL:
78666e63ce3Schristos       if (cpu->cpu_emul_syscall)
78766e63ce3Schristos         {
78866e63ce3Schristos           uint8 op = memory_read8 (cpu,
78966e63ce3Schristos                                    cpu_get_pc (cpu) - 1);
79066e63ce3Schristos           if (op == 0x41)
79166e63ce3Schristos             {
79266e63ce3Schristos 	      cpu_set_pc (cpu, cpu->cpu_insn_pc);
79366e63ce3Schristos 	      sim_engine_halt (CPU_STATE (cpu), cpu,
79466e63ce3Schristos 			       NULL, NULL_CIA, sim_exited,
79566e63ce3Schristos 			       cpu_get_d (cpu));
79666e63ce3Schristos 	      return;
79766e63ce3Schristos             }
79866e63ce3Schristos           else
79966e63ce3Schristos             {
80066e63ce3Schristos               emul_os (op, cpu);
80166e63ce3Schristos             }
80266e63ce3Schristos           return;
80366e63ce3Schristos         }
80466e63ce3Schristos 
80566e63ce3Schristos       interrupts_raise (&cpu->cpu_interrupts, M6811_INT_ILLEGAL);
80666e63ce3Schristos       interrupts_process (&cpu->cpu_interrupts);
80766e63ce3Schristos       break;
80866e63ce3Schristos 
80966e63ce3Schristos     case M6811_TEST:
81066e63ce3Schristos     case M6812_BGND:
81166e63ce3Schristos       {
81266e63ce3Schristos         SIM_DESC sd;
81366e63ce3Schristos 
81466e63ce3Schristos         sd = CPU_STATE (cpu);
81566e63ce3Schristos 
81666e63ce3Schristos         /* Breakpoint instruction if we are under gdb.  */
81766e63ce3Schristos         if (STATE_OPEN_KIND (sd) == SIM_OPEN_DEBUG)
81866e63ce3Schristos           {
81966e63ce3Schristos             cpu->cpu_regs.pc --;
82066e63ce3Schristos             sim_engine_halt (CPU_STATE (cpu), cpu,
82166e63ce3Schristos                              0, cpu_get_pc (cpu), sim_stopped,
82266e63ce3Schristos                              SIM_SIGTRAP);
82366e63ce3Schristos           }
82466e63ce3Schristos         /* else this is a nop but not in test factory mode.  */
82566e63ce3Schristos         break;
82666e63ce3Schristos       }
82766e63ce3Schristos 
82866e63ce3Schristos     case M6812_IDIVS:
82966e63ce3Schristos       {
83066e63ce3Schristos         int32 src1 = (int16) cpu_get_d (cpu);
83166e63ce3Schristos         int32 src2 = (int16) cpu_get_x (cpu);
83266e63ce3Schristos 
83366e63ce3Schristos         if (src2 == 0)
83466e63ce3Schristos           {
83566e63ce3Schristos             cpu_set_ccr_C (cpu, 1);
83666e63ce3Schristos           }
83766e63ce3Schristos         else
83866e63ce3Schristos           {
83966e63ce3Schristos             cpu_set_d (cpu, src1 % src2);
84066e63ce3Schristos             src1 = src1 / src2;
84166e63ce3Schristos             cpu_set_x (cpu, src1);
84266e63ce3Schristos             cpu_set_ccr_C (cpu, 0);
84366e63ce3Schristos             cpu_set_ccr_Z (cpu, src1 == 0);
84466e63ce3Schristos             cpu_set_ccr_N (cpu, src1 & 0x8000);
84566e63ce3Schristos             cpu_set_ccr_V (cpu, src1 >= 32768 || src1 < -32768);
84666e63ce3Schristos           }
84766e63ce3Schristos       }
84866e63ce3Schristos       break;
84966e63ce3Schristos 
85066e63ce3Schristos     case M6812_EDIV:
85166e63ce3Schristos       {
85266e63ce3Schristos         uint32 src1 = (uint32) cpu_get_x (cpu);
85366e63ce3Schristos         uint32 src2 = (uint32) (cpu_get_y (cpu) << 16)
85466e63ce3Schristos           | (uint32) (cpu_get_d (cpu));
85566e63ce3Schristos 
85666e63ce3Schristos         if (src1 == 0)
85766e63ce3Schristos           {
85866e63ce3Schristos             cpu_set_ccr_C (cpu, 1);
85966e63ce3Schristos           }
86066e63ce3Schristos         else
86166e63ce3Schristos           {
86266e63ce3Schristos             cpu_set_ccr_C (cpu, 0);
86366e63ce3Schristos             cpu_set_d (cpu, src2 % src1);
86466e63ce3Schristos             src2 = src2 / src1;
86566e63ce3Schristos             cpu_set_y (cpu, src2);
86666e63ce3Schristos             cpu_set_ccr_Z (cpu, src2 == 0);
86766e63ce3Schristos             cpu_set_ccr_N (cpu, (src2 & 0x8000) != 0);
86866e63ce3Schristos             cpu_set_ccr_V (cpu, (src2 & 0xffff0000) != 0);
86966e63ce3Schristos           }
87066e63ce3Schristos       }
87166e63ce3Schristos       break;
87266e63ce3Schristos 
87366e63ce3Schristos     case M6812_EDIVS:
87466e63ce3Schristos       {
87566e63ce3Schristos         int32 src1 = (int16) cpu_get_x (cpu);
87666e63ce3Schristos         int32 src2 = (uint32) (cpu_get_y (cpu) << 16)
87766e63ce3Schristos           | (uint32) (cpu_get_d (cpu));
87866e63ce3Schristos 
87966e63ce3Schristos         if (src1 == 0)
88066e63ce3Schristos           {
88166e63ce3Schristos             cpu_set_ccr_C (cpu, 1);
88266e63ce3Schristos           }
88366e63ce3Schristos         else
88466e63ce3Schristos           {
88566e63ce3Schristos             cpu_set_ccr_C (cpu, 0);
88666e63ce3Schristos             cpu_set_d (cpu, src2 % src1);
88766e63ce3Schristos             src2 = src2 / src1;
88866e63ce3Schristos             cpu_set_y (cpu, src2);
88966e63ce3Schristos             cpu_set_ccr_Z (cpu, src2 == 0);
89066e63ce3Schristos             cpu_set_ccr_N (cpu, (src2 & 0x8000) != 0);
89166e63ce3Schristos             cpu_set_ccr_V (cpu, src2 > 32767 || src2 < -32768);
89266e63ce3Schristos           }
89366e63ce3Schristos       }
89466e63ce3Schristos       break;
89566e63ce3Schristos 
89666e63ce3Schristos     case M6812_EMULS:
89766e63ce3Schristos       {
89866e63ce3Schristos         int32 src1, src2;
89966e63ce3Schristos 
90066e63ce3Schristos         src1 = (int16) cpu_get_d (cpu);
90166e63ce3Schristos         src2 = (int16) cpu_get_y (cpu);
90266e63ce3Schristos         src1 = src1 * src2;
90366e63ce3Schristos         cpu_set_d (cpu, src1 & 0x0ffff);
90466e63ce3Schristos         cpu_set_y (cpu, src1 >> 16);
90566e63ce3Schristos         cpu_set_ccr_Z (cpu, src1 == 0);
90666e63ce3Schristos         cpu_set_ccr_N (cpu, (src1 & 0x80000000) != 0);
90766e63ce3Schristos         cpu_set_ccr_C (cpu, (src1 & 0x00008000) != 0);
90866e63ce3Schristos       }
90966e63ce3Schristos       break;
91066e63ce3Schristos 
91166e63ce3Schristos     case M6812_EMACS:
91266e63ce3Schristos       {
91366e63ce3Schristos         int32 src1, src2;
91466e63ce3Schristos         uint16 addr;
91566e63ce3Schristos 
91666e63ce3Schristos         addr = cpu_fetch16 (cpu);
91766e63ce3Schristos         src1 = (int16) memory_read16 (cpu, cpu_get_x (cpu));
91866e63ce3Schristos         src2 = (int16) memory_read16 (cpu, cpu_get_y (cpu));
91966e63ce3Schristos         src1 = src1 * src2;
92066e63ce3Schristos         src2 = (((uint32) memory_read16 (cpu, addr)) << 16)
92166e63ce3Schristos           | (uint32) memory_read16 (cpu, addr + 2);
92266e63ce3Schristos 
92366e63ce3Schristos         memory_write16 (cpu, addr, (src1 + src2) >> 16);
92466e63ce3Schristos         memory_write16 (cpu, addr + 2, (src1 + src2));
92566e63ce3Schristos 
92666e63ce3Schristos 
92766e63ce3Schristos       }
92866e63ce3Schristos       break;
92966e63ce3Schristos 
93066e63ce3Schristos     case M6812_CALL:
93166e63ce3Schristos       {
93266e63ce3Schristos         uint8 page;
93366e63ce3Schristos         uint16 addr;
93466e63ce3Schristos 
93566e63ce3Schristos         addr = cpu_fetch16 (cpu);
93666e63ce3Schristos         page = cpu_fetch8 (cpu);
93766e63ce3Schristos 
93866e63ce3Schristos         cpu_m68hc12_push_uint16 (cpu, cpu_get_pc (cpu));
93966e63ce3Schristos         cpu_m68hc12_push_uint8 (cpu, cpu_get_page (cpu));
94066e63ce3Schristos 
94166e63ce3Schristos         cpu_set_page (cpu, page);
94266e63ce3Schristos         cpu_set_pc (cpu, addr);
94366e63ce3Schristos       }
94466e63ce3Schristos       break;
94566e63ce3Schristos 
94666e63ce3Schristos     case M6812_CALL_INDIRECT:
94766e63ce3Schristos       {
94866e63ce3Schristos         uint8 code;
94966e63ce3Schristos         uint16 addr;
95066e63ce3Schristos         uint8 page;
95166e63ce3Schristos 
95266e63ce3Schristos         code = memory_read8 (cpu, cpu_get_pc (cpu));
95366e63ce3Schristos         /* Indirect addressing call has the page specified in the
95466e63ce3Schristos            memory location pointed to by the address.  */
95566e63ce3Schristos         if ((code & 0xE3) == 0xE3)
95666e63ce3Schristos           {
95766e63ce3Schristos             addr = cpu_get_indexed_operand_addr (cpu, 0);
95866e63ce3Schristos             page = memory_read8 (cpu, addr + 2);
95966e63ce3Schristos             addr = memory_read16 (cpu, addr);
96066e63ce3Schristos           }
96166e63ce3Schristos         else
96266e63ce3Schristos           {
96366e63ce3Schristos             /* Otherwise, page is in the opcode.  */
96466e63ce3Schristos             addr = cpu_get_indexed_operand16 (cpu, 0);
96566e63ce3Schristos             page = cpu_fetch8 (cpu);
96666e63ce3Schristos           }
96766e63ce3Schristos         cpu_m68hc12_push_uint16 (cpu, cpu_get_pc (cpu));
96866e63ce3Schristos         cpu_m68hc12_push_uint8 (cpu, cpu_get_page (cpu));
96966e63ce3Schristos         cpu_set_page (cpu, page);
97066e63ce3Schristos         cpu_set_pc (cpu, addr);
97166e63ce3Schristos       }
97266e63ce3Schristos       break;
97366e63ce3Schristos 
97466e63ce3Schristos     case M6812_RTC:
97566e63ce3Schristos       {
97666e63ce3Schristos         uint8 page = cpu_m68hc12_pop_uint8 (cpu);
97766e63ce3Schristos         uint16 addr = cpu_m68hc12_pop_uint16 (cpu);
97866e63ce3Schristos 
97966e63ce3Schristos         cpu_set_page (cpu, page);
98066e63ce3Schristos         cpu_set_pc (cpu, addr);
98166e63ce3Schristos       }
98266e63ce3Schristos       break;
98366e63ce3Schristos 
98466e63ce3Schristos     case M6812_ETBL:
98566e63ce3Schristos     default:
98666e63ce3Schristos       sim_engine_halt (CPU_STATE (cpu), cpu, NULL,
98766e63ce3Schristos                        cpu_get_pc (cpu), sim_stopped,
98866e63ce3Schristos                        SIM_SIGILL);
98966e63ce3Schristos       break;
99066e63ce3Schristos     }
99166e63ce3Schristos }
99266e63ce3Schristos 
99366e63ce3Schristos 
99466e63ce3Schristos void
cpu_single_step(sim_cpu * cpu)99566e63ce3Schristos cpu_single_step (sim_cpu *cpu)
99666e63ce3Schristos {
99766e63ce3Schristos   cpu->cpu_current_cycle = 0;
99866e63ce3Schristos   cpu->cpu_insn_pc = cpu_get_pc (cpu);
99966e63ce3Schristos 
100066e63ce3Schristos   /* Handle the pending interrupts.  If an interrupt is handled,
100166e63ce3Schristos      treat this as an single step.  */
100266e63ce3Schristos   if (interrupts_process (&cpu->cpu_interrupts))
100366e63ce3Schristos     {
100466e63ce3Schristos       cpu->cpu_absolute_cycle += cpu->cpu_current_cycle;
100566e63ce3Schristos       return;
100666e63ce3Schristos     }
100766e63ce3Schristos 
100866e63ce3Schristos   /*  printf("PC = 0x%04x\n", cpu_get_pc (cpu));*/
100966e63ce3Schristos   cpu->cpu_interpretor (cpu);
101066e63ce3Schristos   cpu->cpu_absolute_cycle += cpu->cpu_current_cycle;
101166e63ce3Schristos }
101266e63ce3Schristos 
101366e63ce3Schristos /* VARARGS */
101466e63ce3Schristos void
sim_memory_error(sim_cpu * cpu,SIM_SIGNAL excep,uint16 addr,const char * message,...)101566e63ce3Schristos sim_memory_error (sim_cpu *cpu, SIM_SIGNAL excep,
101666e63ce3Schristos 		  uint16 addr, const char *message, ...)
101766e63ce3Schristos {
101866e63ce3Schristos   char buf[1024];
101966e63ce3Schristos   va_list args;
102066e63ce3Schristos 
102166e63ce3Schristos   va_start (args, message);
102266e63ce3Schristos   vsprintf (buf, message, args);
102366e63ce3Schristos   va_end (args);
102466e63ce3Schristos 
102566e63ce3Schristos   sim_io_printf (CPU_STATE (cpu), "%s\n", buf);
102666e63ce3Schristos   cpu_memory_exception (cpu, excep, addr, buf);
102766e63ce3Schristos }
102866e63ce3Schristos 
102966e63ce3Schristos 
103066e63ce3Schristos void
cpu_memory_exception(sim_cpu * cpu,SIM_SIGNAL excep,uint16 addr,const char * message)103166e63ce3Schristos cpu_memory_exception (sim_cpu *cpu, SIM_SIGNAL excep,
103266e63ce3Schristos                       uint16 addr, const char *message)
103366e63ce3Schristos {
103466e63ce3Schristos   if (cpu->cpu_running == 0)
103566e63ce3Schristos     return;
103666e63ce3Schristos 
103766e63ce3Schristos   cpu_set_pc (cpu, cpu->cpu_insn_pc);
103866e63ce3Schristos   sim_engine_halt (CPU_STATE (cpu), cpu, NULL,
103966e63ce3Schristos                    cpu_get_pc (cpu), sim_stopped, excep);
104066e63ce3Schristos 
104166e63ce3Schristos #if 0
104266e63ce3Schristos   cpu->mem_exception = excep;
104366e63ce3Schristos   cpu->fault_addr    = addr;
104466e63ce3Schristos   cpu->fault_msg     = strdup (message);
104566e63ce3Schristos 
104666e63ce3Schristos   if (cpu->cpu_use_handler)
104766e63ce3Schristos     {
104866e63ce3Schristos       longjmp (&cpu->cpu_exception_handler, 1);
104966e63ce3Schristos     }
105066e63ce3Schristos   (* cpu->callback->printf_filtered)
105166e63ce3Schristos     (cpu->callback, "Fault at 0x%04x: %s\n", addr, message);
105266e63ce3Schristos #endif
105366e63ce3Schristos }
105466e63ce3Schristos 
105566e63ce3Schristos void
cpu_info(SIM_DESC sd,sim_cpu * cpu)105666e63ce3Schristos cpu_info (SIM_DESC sd, sim_cpu *cpu)
105766e63ce3Schristos {
105866e63ce3Schristos   sim_io_printf (sd, "CPU info:\n");
105966e63ce3Schristos   sim_io_printf (sd, "  Absolute cycle: %s\n",
106066e63ce3Schristos                  cycle_to_string (cpu, cpu->cpu_absolute_cycle,
106166e63ce3Schristos                                   PRINT_TIME | PRINT_CYCLE));
106266e63ce3Schristos 
106366e63ce3Schristos   sim_io_printf (sd, "  Syscall emulation: %s\n",
106466e63ce3Schristos                  cpu->cpu_emul_syscall ? "yes, via 0xcd <n>" : "no");
106566e63ce3Schristos   sim_io_printf (sd, "  Memory errors detection: %s\n",
106666e63ce3Schristos                  cpu->cpu_check_memory ? "yes" : "no");
106766e63ce3Schristos   sim_io_printf (sd, "  Stop on interrupt: %s\n",
106866e63ce3Schristos                  cpu->cpu_stop_on_interrupt ? "yes" : "no");
106966e63ce3Schristos }
107066e63ce3Schristos 
1071