Coverage for MC6809/example6809.py: 94%
59 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 Example
5 ~~~~~~~~~~~~~~
7 A small example how to use the emulated 6809 CPU.
9 Here we use a assembler listing to calculate a ZIP 32-bit CRC.
10 The origin code by Johann E. Klasek, j AT klasek at
12 The CRC32 will be compared with binascii.crc32() (written in C), see:
13 https://docs.python.org/library/binascii.html
15 Similar code used in unittests:
16 MC6809/tests/test_6809_program.py
17 ...and is part of the benchmark, too.
19 :created: 2015 by Jens Diemer - www.jensdiemer.de
20 :copyleft: 2015 by the MC6809 team, see AUTHORS for more details.
21 :license: GNU GPL v3 or above, see LICENSE for more details.
22"""
24import binascii
25import string
26import time
28from MC6809.components.cpu6809 import CPU
29from MC6809.components.memory import Memory
30from MC6809.core.configs import BaseConfig
33CFG_DICT = {
34 "verbosity": None,
35 "trace": None,
36}
39class Config(BaseConfig):
40 RAM_START = 0x0000
41 RAM_END = 0x7FFF
43 ROM_START = 0x8000
44 ROM_END = 0xFFFF
47class MC6809Example:
48 def __init__(self):
49 cfg = Config(CFG_DICT)
50 memory = Memory(cfg)
51 self.cpu = CPU(memory, cfg)
53 def cpu_test_run(self, start, end, mem):
54 assert isinstance(mem, bytearray), "given mem is not a bytearray!"
56 print("memory load at $%x: %s", start,
57 ", ".join(f"${i:x}" for i in mem)
58 )
59 self.cpu.memory.load(start, mem)
60 if end is None: 60 ↛ 62line 60 didn't jump to line 62, because the condition on line 60 was never false
61 end = start + len(mem)
62 self.cpu.test_run(start, end)
64 def crc32(self, data):
65 """
66 Calculate a ZIP 32-bit CRC from data in memory.
67 Origin code by Johann E. Klasek, j AT klasek at
68 """
69 data_address = 0x1000 # position of the test data
70 self.cpu.memory.load(data_address, data) # write test data into RAM
71 self.cpu.index_x.set(data_address + len(data)) # end address
72 addr_hi, addr_lo = divmod(data_address, 0x100) # start address
74 self.cpu_test_run(start=0x0100, end=None, mem=bytearray([
75 # 0100| .ORG $100
76 0x10, 0xCE, 0x40, 0x00, # 0100| LDS #$4000
77 # 0104| CRCHH: EQU $ED
78 # 0104| CRCHL: EQU $B8
79 # 0104| CRCLH: EQU $83
80 # 0104| CRCLL: EQU $20
81 # 0104| CRCINITH: EQU $FFFF
82 # 0104| CRCINITL: EQU $FFFF
83 # 0104| ; CRC 32 bit in DP (4 bytes)
84 # 0104| CRC: EQU $80
85 0xCE, addr_hi, addr_lo, # 0104| LDU #.... ; start address in u
86 0x34, 0x10, # 010C| PSHS x ; end address +1 to TOS
87 0xCC, 0xFF, 0xFF, # 010E| LDD #CRCINITL
88 0xDD, 0x82, # 0111| STD crc+2
89 0x8E, 0xFF, 0xFF, # 0113| LDX #CRCINITH
90 0x9F, 0x80, # 0116| STX crc
91 # 0118| ; d/x contains the CRC
92 # 0118| BL:
93 0xE8, 0xC0, # 0118| EORB ,u+ ; XOR with lowest byte
94 0x10, 0x8E, 0x00, 0x08, # 011A| LDY #8 ; bit counter
95 # 011E| RL:
96 0x1E, 0x01, # 011E| EXG d,x
97 # 0120| RL1:
98 0x44, # 0120| LSRA ; shift CRC right, beginning with high word
99 0x56, # 0121| RORB
100 0x1E, 0x01, # 0122| EXG d,x
101 0x46, # 0124| RORA ; low word
102 0x56, # 0125| RORB
103 0x24, 0x12, # 0126| BCC cl
104 # 0128| ; CRC=CRC XOR polynomic
105 0x88, 0x83, # 0128| EORA #CRCLH ; apply CRC polynomic low word
106 0xC8, 0x20, # 012A| EORB #CRCLL
107 0x1E, 0x01, # 012C| EXG d,x
108 0x88, 0xED, # 012E| EORA #CRCHH ; apply CRC polynomic high word
109 0xC8, 0xB8, # 0130| EORB #CRCHL
110 0x31, 0x3F, # 0132| LEAY -1,y ; bit count down
111 0x26, 0xEA, # 0134| BNE rl1
112 0x1E, 0x01, # 0136| EXG d,x ; CRC: restore correct order
113 0x27, 0x04, # 0138| BEQ el ; leave bit loop
114 # 013A| CL:
115 0x31, 0x3F, # 013A| LEAY -1,y ; bit count down
116 0x26, 0xE0, # 013C| BNE rl ; bit loop
117 # 013E| EL:
118 0x11, 0xA3, 0xE4, # 013E| CMPU ,s ; end address reached?
119 0x26, 0xD5, # 0141| BNE bl ; byte loop
120 0xDD, 0x82, # 0143| STD crc+2 ; CRC low word
121 0x9F, 0x80, # 0145| STX crc ; CRC high word
122 ]))
123 d = self.cpu.accu_d.value
124 x = self.cpu.index_x.value
125 crc32 = x * 0x10000 + d
126 return crc32 ^ 0xFFFFFFFF
128 def compare_crc32(self, data):
130 data = bytes(data, encoding="ASCII")
132 print(f"Compare CRC32 with: {data!r}")
134 print("\nCreate CRC32 with binascii:")
135 start_time = time.time()
136 excpected_crc32 = binascii.crc32(data) & 0xffffffff
137 duration = time.time() - start_time
138 print(f"\tbinascii crc32..: ${excpected_crc32:X} calculated in {duration:.6f}sec")
140 print("\nCreate CRC32 with Emulated 6809 CPU:")
141 start_time = time.time()
142 crc32_value = self.crc32(data)
143 duration = time.time() - start_time
144 print(f"\tMC6809 crc32..: ${crc32_value:X} calculated in {duration:.2f}sec")
145 print()
146 if crc32_value == excpected_crc32: 146 ↛ 150line 146 didn't jump to line 150, because the condition on line 146 was never false
147 print(" *** CRC32 values from 6809 and binascii are the same, ok.\n")
148 return True
149 else:
150 print(" *** ERROR: CRC32 are different!\n")
151 return False
154def run_example():
155 mc6809 = MC6809Example()
157 data = string.digits + string.ascii_letters + string.punctuation
158 ok = mc6809.compare_crc32(data)
160 return ok # Used in unittests ;)
163if __name__ == '__main__':
164 run_example()