# 6801 assembly: Interrupt code interpretation

#### metermannd

Joined Oct 25, 2020
232
Here's a bit of code I need to get my mind around - understanding it is key to whether I can rewrite it for more modern languages (i.e., C++ or ARM assembly).

What I need help with most is seeing where the received data goes into memory.
The main portion of RAM is between $0080 and$00FF, with an additional range at $0C00 to$0C7F (but only the first 3 bytes are relevant as far as this code goes)

It seems as long as $C9 is NOT set to '1', message reception is basically continuous On the hardware side of this code, the relevant bits of PIA Port A are: bit 0 - Receive signal (serial) bit 1 - Transmit signal (serial) bit 2 - Transmitter enable bit 3 - Transmit / receive relay (In the unit I'm copying, the trace from PA3 is cut, and PA2 drives both the transmitter enable line and the transmit / receive relay) I've noted that part of the code pertaining to PA3, and would like to see how much can safely be cleaned out. It'd be that much less code to work with. What I know about the transmitter side - the process of sending a message: Data string is written into the buffer ($A0 to $B5) Specified values (likely counters) to$B6 and $B8 Let's use the shortest string from the main code as an example for analysis:$A0: AA B8 FF 00 E0 00
$B6: 2B$B8: 01
$0C00: 0006 A 1 is then written to$B7 and $C9 A timer is then set and allowed to run down Meanwhile, the interrupt code moves the output bit stream into PA1, and sets PA2 to put the unit into transmit mode. When the timer ends,$B7 is then read to ensure it is no longer 1 (BLE) - if it is still 1, then a 'no transmit' error flag is set and the main code falls through to the error / abort routine

$C9 is then cleared to tell the interrupt that the transmitter is to be turned off (PA1 and PA2 are eventually cleared within the interrupt code) Coming back to the beginning of the post, the main thing I need to see is where into RAM the received data is written. Code: ;NMI routine (driven by PTM output 2) ; Software shift register: ; Capture data from PIA A bit 0 and save in Present Si byte LDA A$0C
ROR A
ROL $0082 ; Check if transmit flag is set (1) TST$00C9
BNE nmi_01
JMP nmi_31

; Check to see if we have counted off 8 bits
nmi_01
DEC $00D2 LDA A #$07
AND A $D2 BEQ nmi_02 RTI ; We now have 8 bits - Present SI byte is copied to Last Si byte nmi_02 LDA A$82
STA A $83 ; PTM registers are manipulated LDA B #$52
STA B $01 LDA A #$12
TST $00B7 BLE nmi_03 LDA A #$92
nmi_03
STA A $00 LDA B #$53
STA B $01 ; Check to see if 4 'phases' are counted DEC$00D3
LDA A #$03 AND A$D3
BNE nmi_04
JMP nmi_43

; Prepare for I / Q table lookups
nmi_04
LDA A $84 ; Previous Last Si byte LDA B$83    ; Last Si byte
STA B $93 CLR$0094    ; $94 -$97 is scratchpad
CLR $0095 CLR$0096
CLR $0097 LDX #$FD87    ; Lookup table pointer
ROR $0093 ; Roll byte into position ; Evaluate Last / Previous Last Si bytes based on bit 7 (as sign bit) nmi_05 ROL$0093
TAB
EOR B $93 BPL nmi_08 ; we only care about low / high transitions ; Process 'I' value LDA B$00,X
TST A
BPL nmi_06
NEG B
nmi_06
ADD B $94 STA B$94

; Process 'Q' value
LDA B $02,X TST A BPL nmi_07 NEG B nmi_07 ADD B$95
STA B $95 ; Process 'I2' value LDA B$96
ADD B $0A,X STA B$96

; Process 'Q2' value
LDA B $97 ADD B$0B,X
STA B $97 nmi_08 LDA A$93    ; Reload Last Si byte for next pass
DEX
CPX #$FD7F ; Have we reached the last 45 degree interval? BNE nmi_05 BRA nmi08a ; Table: I / Q lookup byte 20 17 00 E9 E0 E9 00 17 20 17 ; Table: I2 / Q2 lookup byte 01 00 FF 00 01 00 FF 00 01 ; save values after table lookup nmi08a STA A$84    ; New Previous Last Si byte value
LDA A $94 STA A$85    ; Ii value
LDA A $95 STA A$86    ; Qi value
LDA A $96 STA A$87    ; I2i value
LDA A $97 STA A$88    ; Q2i value

; Integrator - calculate I2avg, reduce to 15/16 previous
LDA A $89 LDA B$8B
ASR A    ; simulate 'ASR D' operation x 4
ROR B
ASR A
ROR B
ASR A
ROR B
ASR A
ROR B
STA D $93 ; Store 1/16 value LDA A$89    ; Reload I2avg value
LDA B $8B SUB D$93    ; Subtraction
ADD A $87 ; Add I2i value STA A$89    ; Store updated I2avg value
STA B $8B ; Integrator - calculate Q2avg, reduce to 15/16 previous LDA A$8A
LDA B $8C ASR A ; Simulate 'ASR D' operation x 4 ROR B ASR A ROR B ASR A ROR B ASR A ROR B STA D$93    ; Store 1/16 value
LDA A $8A ; Reload Q2avg value LDA B$8C
SUB D $93 ; Subtraction ADD A$88    ; Add Q2i value
STA A $8A ; Store updated Q2avg value STA B$8C

TST $0089 BPL nmi_09 TAB EOR B$8D
BPL nmi_09
COM $0090 nmi_09 STA A$8D
LDA A $89 BPL nmi_10 NEG A nmi_10 LDA B$8A
BPL nmi_11
NEG B
nmi_11
CBA
BPL nmi_12
ASR A
BRA nmi_14
nmi_12
ASR B
nmi_14
ABA
STA A $91 ; value stored for debugging only CMP A #$09    ; has carrier detect threshold been met?
BPL nmi_15
JMP nmi_29
nmi_15
LDA A $89 LDA B$8A
CBA
BPL nmi_16
NEG A
CBA
BMI nmi_17
TST B
BPL nmi_19
BRA nmi_18
nmi_16
NEG B
CBA
BMI nmi_20
STA A $8E NEG B ASR B STA B$8F
BRA nmi_21
nmi_17
ASR A
NEG A
PSH A
ABA
STA A $8E PUL A SBA NEG A STA A$8F
BRA nmi_21
nmi_18
NEG A
NEG B
nmi_19
STA A $8F ASR B STA B$8E
BRA nmi_21
nmi_20
ASR A
PSH A
ABA
STA A $8E PUL A SBA STA A$8F

; Vector calculation
nmi_21
LDA A $85 LDA B$8E
STA A $93 STA B$94
EOR A $94 STA A$94
LDA A $93 BPL nmi_22 NEG A nmi_22 TST B BPL nmi_23 NEG B nmi_23 MUL ASL D ASL D TST$0094
BPL nmi_24
NEG A

nmi_24
STA A $92 ; Vector calculation 2 LDA A$86
LDA B $8F STA A$93
STA B $94 EOR A$94
STA A $94 LDA A$93
BPL nmi_25
NEG A
nmi_25
TST B
BPL nmi_26
NEG B
nmi_26
MUL
ASL D
ASL D
TST $0094 BPL nmi_27 NEG A nmi_27 ADD A$92
TST $0090 BPL nmi_28 COM A nmi_28 STA A$92
INC $00CC BRA nmi_30 nmi_29 CLR$0092
nmi_30
TST $00CC BNE nmi_33 nmi_31 CLR$00CE
LDA A #$05 STA A$D4
CLR $00CB CLR$00DA
LDX #$0008 nmi_32 CLR$97,X
DEX
BNE nmi_32
RTI

nmi_33
LDA A #$00 LDA B$92
ASR B
ABA
STA A $CD ; value stored for debugging only TST$00D4
BEQ nmi_35
nmi_34
TAB
EOR B $92 BPL nmi_35 COM$0090
nmi_35
LDA B #$02 CMP B$CC
BEQ nmi_36
BPL nmi_37
ASR A
nmi_36
ASR A
nmi_37
CLR $00CC LDX$D6
ASR A
STA A $00,X LDA A #$00
LDX #$009B ; reset table pointer nmi_38 ADD A$00,X
DEX
CPX #$0097 ; have we reached the end of the table? BNE nmi_38 STA A$DC
TST A
BPL nmi_39
NEG A
nmi_39
LDX $D6 ASR A ADD A$04,X
STA A $04,X DEX CPX #$0097    ; have we reached the end of the table?
BNE nmi_40
LDX #$009B ; reset table pointer nmi_40 STX$D6
INC $00D5 TST$00CB
BMI nmi_41
CMP A $CB BMI nmi_41 STA A$CB
CLR $00D5 nmi_41 LDA A #$03
AND A $D5 BNE nmi_42 LDA A$DC
STA A $DA nmi_42 RTI nmi_43 DEC$00B7
BEQ nmi_45
BPL nmi_44
JMP nmi_56
nmi_44
RTI

nmi_45
INC $00B7 DEC$00B6
BEQ nmi_54
LDA A $B6 LDA B$BB
CMP B #$01 BEQ nmi_53 CMP A #$34
BNE nmi_47
nmi_46
CLR $0080 nmi_47 CMP A #$06
BNE nmi_48
LDA A $80 ASL A ASL A ADD A$A0
STA A $A0 nmi_48 LDX$0C00
nmi_49
ROL $9F,X DEX BNE nmi_49 ROL A ; BCH checksum ASL$0080
PSH A
BIT A #$01 BEQ nmi_50 LDA A$80
BIT A #$40 BNE nmi_52 BRA nmi_51 nmi_50 LDA A$80
BIT A #$40 BEQ nmi_52 nmi_51 EOR A #$03
nmi_52
AND A #$3F STA A$80
PUL A

; Transmit bit through PIA Port A
AND A #$01 ; clear AccA except bit 0 ASL A ; move bit into place for transmission ADD A #$04    ; set bit 2 (transmit relay 'on')
LDA B $0C ; read PIA Port A AND B #$F9    ; clear bits 1 / 2
ABA            ; add new bits 1 / 2
STA A $0C ; write PIA Port A RTI nmi_53 CMP A #$1E
BNE nmi_47
CLR $0080 JMP nmi_47 nmi_54 DEC$00B8
BEQ nmi_55
LDA A #$34 STA A$B6
BRA nmi_46

; End of transmission cleanup
nmi_55
LDA A $0C ; read PIA Port A AND A #$F9    ; clear bits 1 / 2 (end transmission)
STA A $0C ; write PIA Port A DEC$00B7
INC $0C02 CLR$00CE
LDA A #$05 ; reset data bit counter STA A$D4
RTI

nmi_56
INC $00B7 DEC$00D4
BEQ nmi_60
BMI nmi_57
LDA B #$00 LDA A #$01
CMP A $D4 BNE nmi_59 COM A STA A$CB
BRA nmi_59
nmi_57
INC $00D4 LDA B$DA
TST $00CA BMI nmi_58 COM B nmi_58 LDA A #$FF
STA A $CE ; This section is not needed (PA3 is unused) ; Need to see how much can be cleaned out nmi_59 ROR B ; move bit 7 to bit 3 (not used) ROR B ROR B ROR B AND B #$08
LDA A $0C ; PIA Port A AND A #$F7    ; clear bit 3 (not used)
ABA            ; add in new bit 3
STA A $0C ; write to PIA Port A BRA nmi_61 nmi_60 INC$00D4
LDA A $DA TAB EOR A$DB
BMI nmi_61
STA B $CA DEC$00D4
nmi_61
LDA A $DA STA A$DB
LDA B $CE TST$00CA
BMI nmi_62
COM A
nmi_62
LDX $0C00 TST B BMI nmi_64 CLR$0C02
LDA A $B8 STA A$D1
CLR $0080 CLR$00B6
nmi_63
JMP nmi_04
nmi_64
TST $0C02 BNE nmi_63 ROL A nmi_65 ROL$9F,X
DEX
BNE nmi_65
INC $00B6 LDX$0C00
LDA A $9F,X LDA B$B6

; BCH checksum
ASL $0080 PSH A BIT A #$01
BEQ nmi_66
LDA A $80 BIT A #$40
BNE nmi_68
BRA nmi_67
nmi_66
LDA A $80 BIT A #$40
BEQ nmi_68
nmi_67
EOR A #$03 nmi_68 AND A #$3F
STA A $80 PUL A CMP B #$34
BLT nmi_70
DEC $00D1 BNE nmi_70 LDA B #$01
STA B $0C02 nmi_70 JMP nmi_04 Moderator edit: Code inserted in code box using [code]...text...[/code] #### Attachments • 7 KB Views: 4 #### MrChips Joined Oct 2, 2009 24,610 This is a good example of poor programming style. 1) Do not use absolute hex addresses. Use a labelled name instead, one that the reader can understand. 2) Use comments, not to explain what the line of code does but what is the purpose of a block of code. 3) State code specifications, i.e. what are the inputs, what are the outputs. 4) Address such as nmi_18 conveys no meaning to the reader. It should be something such as "negate_D". 5) Use hex values only for bit masking operations, for example. Use decimal values when referring to a number value, for example, Instead of LDA A #$0A
use
LDA A #10

Why is the code using NMI instead of normal IRQ?

Bottom line: Make your code readable and easy to understand by you and any other person 25 years from now.

#### metermannd

Joined Oct 25, 2020
232
Unfortunately I don't have a proper assembler as I'm on a M1 Mac (I upgraded too soon and don't currently have a viable option for running Windows).

Even this code is better than what I originally copied from the original unit's EPROM - I did a fair bit of cleanup to get it into this state.

I've never had to share code with others, so I don't know the rules of formatting source code.

As for why it's NMI versus IRQ, that's the way it was wired up in the original unit.

Nothing I do is ever good enough it seems.

#### MrChips

Joined Oct 2, 2009
24,610
Unfortunately I don't have a proper assembler as I'm on a M1 Mac (I upgraded too soon and don't currently have a viable option for running Windows).

Even this code is better than what I originally copied from the original unit's EPROM - I did a fair bit of cleanup to get it into this state.

I've never had to share code with others, so I don't know the rules of formatting source code.

As for why it's NMI versus IRQ, that's the way it was wired up in the original unit.

Nothing I do is ever good enough it seems.
Don't take it too hard, just that there's room for improvement.

I am going to assume that this is not your code. I will assume that it was reassembled from code sitting in the EPROM.
It would be worth your while to sit down and try to reverse engineer the code. Try to figure out what each SRAM data location is being used for and give it some reasonable label.
Do the same for subroutines/functions and give it a name.
Then do the same for branch locations and name them too.

If you need help to reverse engineer MC6800 code I could lend a hand, time allowing.
Also if you need to run code through an assembler, whether it be 6800/6805/6809/68000/HC11, we could likely find you an editor/assembler to work with. I have worked with ASM for all of the above.

#### metermannd

Joined Oct 25, 2020
232
Correct that it started as an eprom dump that was run through a disassembler (f9dasm to be precise), cleaned up for formatting, then run through with a fine-tooth comb to clean it up (trust me, the original version is horrid).

I did figure out a good number of these locations (and have them documented in a separate sheet), I just haven't defined suitable 'source' mnemonics for these addresses... yet.

This is the only section of code that I really need help with - most of the remaining code I've figured out (and have optimized already) or at least have a fairly good sense of how it flows. Those sections I don't quite get should start falling into place once I have this straightened out.

For the purposes of analysis, this would be HC11 code (the original MCU was an automotive variant of the 6801).

#### metermannd

Joined Oct 25, 2020
232
So I went through the code and here's an attempt at translating it into C++
I even ran it through an online compiler and fixed all the typos I could find...

#### Attachments

• 9.6 KB Views: 10