Coverage for MC6809/components/mc6809_stack.py: 74%
75 statements
« prev ^ index » next coverage.py v7.2.1, created at 2023-03-06 19:50 +0100
« prev ^ index » next coverage.py v7.2.1, created at 2023-03-06 19:50 +0100
1#!/usr/bin/env python
3"""
4 MC6809 - 6809 CPU emulator in Python
5 =======================================
7 6809 is Big-Endian
9 Links:
10 http://dragondata.worldofdragon.org/Publications/inside-dragon.htm
11 http://www.burgins.com/m6809.html
12 http://koti.mbnet.fi/~atjs/mc6809/
14 :copyleft: 2013-2015 by the MC6809 team, see AUTHORS for more details.
15 :license: GNU GPL v3 or above, see LICENSE for more details.
17 Based on:
18 * ApplyPy by James Tauber (MIT license)
19 * XRoar emulator by Ciaran Anscomb (GPL license)
20 more info, see README
21"""
24from MC6809.components.cpu_utils.instruction_caller import opcode
25from MC6809.components.MC6809data.MC6809_op_data import REG_A, REG_B, REG_CC, REG_DP, REG_PC, REG_U, REG_X, REG_Y
28class StackMixin:
30 def push_byte(self, stack_pointer, byte):
31 """ pushed a byte onto stack """
32 # FIXME: self.system_stack_pointer -= 1
33 stack_pointer.decrement(1)
34 addr = stack_pointer.value
36# log.info(
37# log.error(
38# "%x|\tpush $%x to %s stack at $%x\t|%s",
39# self.last_op_address, byte, stack_pointer.name, addr,
40# self.cfg.mem_info.get_shortest(self.last_op_address)
41# )
42 self.memory.write_byte(addr, byte)
44 def pull_byte(self, stack_pointer):
45 """ pulled a byte from stack """
46 addr = stack_pointer.value
47 byte = self.memory.read_byte(addr)
48# log.info(
49# log.error(
50# "%x|\tpull $%x from %s stack at $%x\t|%s",
51# self.last_op_address, byte, stack_pointer.name, addr,
52# self.cfg.mem_info.get_shortest(self.last_op_address)
53# )
55 # FIXME: self.system_stack_pointer += 1
56 stack_pointer.increment(1)
58 return byte
60 def push_word(self, stack_pointer, word):
61 # FIXME: self.system_stack_pointer -= 2
62 stack_pointer.decrement(2)
64 addr = stack_pointer.value
65# log.info(
66# log.error(
67# "%x|\tpush word $%x to %s stack at $%x\t|%s",
68# self.last_op_address, word, stack_pointer.name, addr,
69# self.cfg.mem_info.get_shortest(self.last_op_address)
70# )
72 self.memory.write_word(addr, word)
74# hi, lo = divmod(word, 0x100)
75# self.push_byte(hi)
76# self.push_byte(lo)
78 def pull_word(self, stack_pointer):
79 addr = stack_pointer.value
80 word = self.memory.read_word(addr)
81# log.info(
82# log.error(
83# "%x|\tpull word $%x from %s stack at $%x\t|%s",
84# self.last_op_address, word, stack_pointer.name, addr,
85# self.cfg.mem_info.get_shortest(self.last_op_address)
86# )
87 # FIXME: self.system_stack_pointer += 2
88 stack_pointer.increment(2)
89 return word
91 ####
93 @opcode( # Push A, B, CC, DP, D, X, Y, U, or PC onto stack
94 0x36, # PSHU (immediate)
95 0x34, # PSHS (immediate)
96 )
97 def instruction_PSH(self, opcode, m, register):
98 """
99 All, some, or none of the processor registers are pushed onto stack
100 (with the exception of stack pointer itself).
102 A single register may be placed on the stack with the condition codes
103 set by doing an autodecrement store onto the stack (example: STX ,--S).
105 source code forms: b7 b6 b5 b4 b3 b2 b1 b0 PC U Y X DP B A CC push order
106 ->
108 CC bits "HNZVC": -----
109 """
110 assert register in (self.system_stack_pointer, self.user_stack_pointer)
112 def push(register_str, stack_pointer):
113 register_obj = self.register_str2object[register_str]
114 data = register_obj.value
116# log.debug("\tpush %s with data $%x", register_obj.name, data)
118 if register_obj.WIDTH == 8:
119 self.push_byte(register, data)
120 else:
121 assert register_obj.WIDTH == 16
122 self.push_word(register, data)
124# log.debug("$%x PSH%s post byte: $%x", self.program_counter, register.name, m)
126 # m = postbyte
127 if m & 0x80: 127 ↛ 128line 127 didn't jump to line 128, because the condition on line 127 was never true
128 push(REG_PC, register) # 16 bit program counter register
129 if m & 0x40: 129 ↛ 130line 129 didn't jump to line 130, because the condition on line 129 was never true
130 push(REG_U, register) # 16 bit user-stack pointer
131 if m & 0x20: 131 ↛ 132line 131 didn't jump to line 132, because the condition on line 131 was never true
132 push(REG_Y, register) # 16 bit index register
133 if m & 0x10:
134 push(REG_X, register) # 16 bit index register
135 if m & 0x08: 135 ↛ 136line 135 didn't jump to line 136, because the condition on line 135 was never true
136 push(REG_DP, register) # 8 bit direct page register
137 if m & 0x04:
138 push(REG_B, register) # 8 bit accumulator
139 if m & 0x02:
140 push(REG_A, register) # 8 bit accumulator
141 if m & 0x01: 141 ↛ 142line 141 didn't jump to line 142, because the condition on line 141 was never true
142 push(REG_CC, register) # 8 bit condition code register
144 @opcode( # Pull A, B, CC, DP, D, X, Y, U, or PC from stack
145 0x37, # PULU (immediate)
146 0x35, # PULS (immediate)
147 )
148 def instruction_PUL(self, opcode, m, register):
149 """
150 All, some, or none of the processor registers are pulled from stack
151 (with the exception of stack pointer itself).
153 A single register may be pulled from the stack with condition codes set
154 by doing an autoincrement load from the stack (example: LDX ,S++).
156 source code forms: b7 b6 b5 b4 b3 b2 b1 b0 PC U Y X DP B A CC = pull
157 order
159 CC bits "HNZVC": ccccc
160 """
161 assert register in (self.system_stack_pointer, self.user_stack_pointer)
163 def pull(register_str, stack_pointer):
164 reg_obj = self.register_str2object[register_str]
166 reg_width = reg_obj.WIDTH # 8 / 16
167 if reg_width == 8: 167 ↛ 170line 167 didn't jump to line 170, because the condition on line 167 was never false
168 data = self.pull_byte(stack_pointer)
169 else:
170 assert reg_width == 16
171 data = self.pull_word(stack_pointer)
173 reg_obj.set(data)
175# log.debug("$%x PUL%s:", self.program_counter, register.name)
177 # m = postbyte
178 if m & 0x01: 178 ↛ 179line 178 didn't jump to line 179, because the condition on line 178 was never true
179 pull(REG_CC, register) # 8 bit condition code register
180 if m & 0x02:
181 pull(REG_A, register) # 8 bit accumulator
182 if m & 0x04:
183 pull(REG_B, register) # 8 bit accumulator
184 if m & 0x08: 184 ↛ 185line 184 didn't jump to line 185, because the condition on line 184 was never true
185 pull(REG_DP, register) # 8 bit direct page register
186 if m & 0x10: 186 ↛ 187line 186 didn't jump to line 187, because the condition on line 186 was never true
187 pull(REG_X, register) # 16 bit index register
188 if m & 0x20: 188 ↛ 189line 188 didn't jump to line 189, because the condition on line 188 was never true
189 pull(REG_Y, register) # 16 bit index register
190 if m & 0x40: 190 ↛ 191line 190 didn't jump to line 191, because the condition on line 190 was never true
191 pull(REG_U, register) # 16 bit user-stack pointer
192 if m & 0x80: 192 ↛ 193line 192 didn't jump to line 193, because the condition on line 192 was never true
193 pull(REG_PC, register) # 16 bit program counter register