Coverage for MC6809/example6809.py: 94%

59 statements  

« prev     ^ index     » next       coverage.py v7.2.1, created at 2023-03-06 19:50 +0100

1#!/usr/bin/env python 

2 

3""" 

4 MC6809 Example 

5 ~~~~~~~~~~~~~~ 

6 

7 A small example how to use the emulated 6809 CPU. 

8 

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 

11 

12 The CRC32 will be compared with binascii.crc32() (written in C), see: 

13 https://docs.python.org/library/binascii.html 

14 

15 Similar code used in unittests: 

16 MC6809/tests/test_6809_program.py 

17 ...and is part of the benchmark, too. 

18 

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""" 

23 

24import binascii 

25import string 

26import time 

27 

28from MC6809.components.cpu6809 import CPU 

29from MC6809.components.memory import Memory 

30from MC6809.core.configs import BaseConfig 

31 

32 

33CFG_DICT = { 

34 "verbosity": None, 

35 "trace": None, 

36} 

37 

38 

39class Config(BaseConfig): 

40 RAM_START = 0x0000 

41 RAM_END = 0x7FFF 

42 

43 ROM_START = 0x8000 

44 ROM_END = 0xFFFF 

45 

46 

47class MC6809Example: 

48 def __init__(self): 

49 cfg = Config(CFG_DICT) 

50 memory = Memory(cfg) 

51 self.cpu = CPU(memory, cfg) 

52 

53 def cpu_test_run(self, start, end, mem): 

54 assert isinstance(mem, bytearray), "given mem is not a bytearray!" 

55 

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) 

63 

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 

73 

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 

127 

128 def compare_crc32(self, data): 

129 

130 data = bytes(data, encoding="ASCII") 

131 

132 print(f"Compare CRC32 with: {data!r}") 

133 

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") 

139 

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 

152 

153 

154def run_example(): 

155 mc6809 = MC6809Example() 

156 

157 data = string.digits + string.ascii_letters + string.punctuation 

158 ok = mc6809.compare_crc32(data) 

159 

160 return ok # Used in unittests ;) 

161 

162 

163if __name__ == '__main__': 

164 run_example()