Cleaning up a bit of 6800 assembly code - Page 1
Forum section: electronics / general

author: metertech58761
author_rank: Frequent Contributor
timestamp: November 27, 2022, 06:47:11 pm
content: When going through a bit of 6800 assembly code (actually 6801 / HC11), I came across this section and I know it can be rearranged better, but I cannot get it to work properly. I would like to see if anyone can point out how to properly rearrange these instructions, especially given that the RTS is smack dab in the middle and that a BRA is needed to continue the loop. Now, this is after I already cleaned the 'spaghetti' out of the first half and replaced a loop counter with CPX.What this does is convert a 7-digit BCD value (readout+7 is MSB, readout+1 is LSB, readout+0 is used as a checksum digit elsewhere) into a 3-byte binary value.addrCalc CLCCLR temp6CLR addrLCLR addrMCLR addrHLDX readout+7func01_1 LDAA addrMLDAB addrLADDB $00,XSTAB addrLBCC func01_2ADDA #$01STAA temp6STAA addrMBCC func01_2LDAA addrHADDA #$01STAA addrHLDAA temp6func01_2 CPX readoutBNE func01_5RTSfunc01_5 ASLDSTAB addrLSTAA temp6STAA addrMROL addrHLDAA addrHSTAA temp7LDAA temp6ASLDROL temp7ASLDROL temp7ADDB addrLSTAB addrLADCA addrMSTAA addrMBCC func01_6INC addrHfunc01_6 LDAA temp7ADDA addrHSTAA addrHDEXBRA func01_1

author: Nominal Animal
author_rank: Super Contributor
timestamp: November 27, 2022, 10:08:50 pm
content: Friends don't just throw 68HC11 assembly at friends and ask what's wrong, friends describe the idea of what the code tries to implement (you mostly did, but not fully), and how.Is this packed (two decimal digits per byte) or unpacked BCD (each byte being 0..9 only)?Or is the problem that you use an unpacked algorithm, but the data is really packed?If it is packed BCD, I guess that your input is something likeByteBitsDescriptionB0 0..7Checksum digit, ignoredB0 4..7 D0, least significant BCD digit we're interested inB1 0..3 D1B1 4..7 D2B2 0..3 D3B2 4..7 D4B3 0..3 D5B3 4..7 D6, most significant BCD digit we're interested inbut your description kinda implies unpacked BCD. Which is it?In any case, output is bytesO0,O1,O2, such thatO0 + 256*(O1 + 256*O2) = D0 + 10*(D1 + 10*(D2 + 10*(D3 + 10*(D4 + 10*(D5 + 10*D6)))))i.e.O0 + 256*O1 + 65536*O2 = D0 + 10*D1 + 100*D2 + 1000*D3 + 10000*D4 + 100000*D5 + 1000000*D6right? (If you use MSB, just swap O0 and O2 above, they're just labels anyway. I like to use arithmetic numbering, which starts at zero, and increases as the significance increases, because that matches the math: value = sum digit*radix^n. I'm not a "little-endian zealot".)The core operation here, if I were to implement this from scratch, would beA ← A*10+B = (A << 3) + (A << 1) + Bwhere A is the three-byte register, initialized to zero. For 68HC11, we of course can only shift/rotate one bit at a time, so we need a temporary three-byte area for the shifting, since we need to do that sum. We can do with A, B, D accumulators, if we do it before we extract the new digit B, though.Can I use theNXP M68HC11E manualfor reference, or does your architecture have a different instruction set?

author: metertech58761
author_rank: Frequent Contributor
timestamp: November 28, 2022, 01:29:16 am
content: In this instance, yes, it is unpacked BCD, entered from a keypad before being passed to this routine.The HC11 instruction set will be just fine.If you have a better algorithm in mind, I'd be all ears. If you say you need a third temporary byte, use the mnemonic temp5.Whoever wrote the original code did not know the first thing about 68xx assembly - what I started with wasatrocious!

author: Nominal Animal
author_rank: Super Contributor
timestamp: November 28, 2022, 03:14:28 am
content: I would implement the following pseudocode:Set addr to 0Set X to address of first digitOptional: jump to FirstLoop:Multiply addr by 2Copy addr to tempMultiply addr by 2Multiply addr by 2Add temp to addrFirst:Load next decimal digit,and add it to addrIncrement XIf we are not past the digit buffer yet,jump to Loopotherwise return from subroutinenoting thattemp=addr*2; addr=temp*2*2+tempis equivalent toaddr=10*addr.I have a nagging feeling we could use the Y register for our advantage here, perhaps via XGDY, which exchanges D and Y, to avoid using temp5, and speed things up.. but me brain isn't working well enough now, captain!I do not have an emulator handy (and can't recall where I could get one quickly for Linux), so consider the following implementation suspect, probably buggy, in need of checking:The conversion starts with clearing addrH:addrM:addrL, and I do assume addrH has the lowest address and addrL the highest address:CLR addrL ; addrL = 0CLR addrM ; addrM = 0CLR addrH ; addrH = 0Use X for the address of incoming digits, in increasing order of importance.LDX readout+1 ; address of least significant digitJMP firstNext, we have a subroutine that multiplies addr by 10, using temp5 as a scratchpad.loop LDD addrM ; A=addrM, B=addrLLSLDSTD addrMLDAA addrHROLASTAA addrH ; addr now multiplied by 2,STAA temp5 ; and temp5=addrHLDAA addrM ; We didn't mangle B above, so reloading addrM sufficesLSLDROL temp5 ; second doubling doneLSLDROL temp5 ; third doubling doneADDD addrM ; A=A+addrM, B=B+addrL, carry set if necessarySTD addrM ; addrL and addrM updatedLDAA temp5ADCA addrHSTAA addrH ; addrH updatedWe then want to load the next digit to B,first LDAB $00,Xand add it to the 24-bit addr:CLRAADDD addrM ; A=addrM, B=addrL+digitSTD addrM ; addrL and addrM updatedLDAA #$0ADCA addrHSTAA addrH ; addrH updatedAdvance to next digit, if any left.INXCPX readout+8 ; past the incoming data?BLO loopRETCan you follow the logic above? Could you test if it works?If it is not fast enough, I'm pretty sure it can be sped up somewhat. I never write fast code on the first run, I strive for correctness.(In fact, if you think about it, it might be useful to call something like this directly from the keypad, using an extra byte to count the number of digits already pressed. Would also save about seven bytes of RAM. Even if the 68HC11 is running off a 32kHz clock or something, the above is faster than even the fastest human pressing digits.)

author: metertech58761
author_rank: Frequent Contributor
timestamp: November 29, 2022, 01:16:05 pm
content: Just want to confirm a few details - the 24-bit address, it is stored as high / mid / low.Given the atrocious code I began with, I don't think speed is terribly important (the clock speed of the MPU was a mere 1.0MHz - about the same as a Commodore 64)Also, there's plenty of space in the ROM - especially after my cleanup / optimization of the overall code, so as long as the code is readable, we should be fine.

author: DiTBho
author_rank: Super Contributor
timestamp: November 29, 2022, 03:46:30 pm
content: I think you can study this kind of routines from the old Motorola BUFALO/11 source.The assembly source is opensource.

author: Nominal Animal
author_rank: Super Contributor
timestamp: November 30, 2022, 07:32:51 am
content: Do you know of any emulation environments for 68HC11? They have existed for sure, but are there any that haven't bit-rotted too much?The instruction set is small enough that a simulator for the symbolic assembly would be easy enough to write, so that functions like the above could be simulated and checked for correctness. Binary simulators are much more work.

author: DiTBho
author_rank: Super Contributor
timestamp: November 30, 2022, 10:34:38 am
content: I have a few good emulators and debuggers for Windows XP(1)None for Linux. Tried a few, all toyish.I prefer real hardware, with "noICE" support.(noICE is a commercial tool, again, for Windows).This stuff is useful for the HC-timers and misc rather than for the HC11 ISA.For GNU/Linux I wrote a downloader tool.Kind of avr-dude for hc11. Nothing special.It supports both bufalo and evb/evbu boards.(1) I specifically bought a second hand laptop for those Windows XP dev tools.There is a nice "talker" written in hc11 assembly, the host control program is written in Delphi Pascal.I'd like to re-write it in C-xmotif. One day

author: DiTBho
author_rank: Super Contributor
timestamp: November 30, 2022, 12:57:54 pm
content: THRSim11 v5.30Proteus v8.0 (comes with an hc11 simulator)

author: Nominal Animal
author_rank: Super Contributor
timestamp: November 30, 2022, 10:42:52 pm
content: Would a symbolic ASM simulator (running on human-readable assembly source, not modeling any peripherals, only the instruction set) be of any use?

author: ozcar
author_rank: Frequent Contributor
timestamp: December 01, 2022, 12:12:51 am
content: Quote from: metertech58761 on November 27, 2022, 06:47:11 pmIn 680x assembly, that would have to beCode:LDX #readout+7to make any sense.Given the whole thing, including sample 'readout', I could probably assemble that for 6809 and see how it behaves.

author: DiTBho
author_rank: Super Contributor
timestamp: December 01, 2022, 12:43:18 am
content: Quote from: Nominal Animal on November 30, 2022, 10:42:52 pmlimited use, hc11 makes sense for its peripheralsummm, there should be sim support in gdb.or, repo likethis(hc11-sim). Never tried.

author: srb1954
author_rank: Super Contributor
timestamp: December 01, 2022, 04:29:47 am
content: Quote from: Nominal Animal on November 30, 2022, 07:32:51 amYou could look around for a 68HC11 evaluation board. Motorola made several different models using the BUFFALO monitor S/W. There were also some third party evaluation boards providing similar features.An evaluation board will generally have a fairly reasonable debugger built into it and should prove adequate for most program testing purposes. An evaluation board is also useful when you come to add extra peripheral devices your system and it allows you to debug on the actual hardware rather than trying to simulate those peripheral devices in a S/W emulator.

author: ozcar
author_rank: Frequent Contributor
timestamp: December 01, 2022, 05:58:59 am
content: Quote from: srb1954 on December 01, 2022, 04:29:47 amI had one made by Axiom, something like 25 years ago!

author: Circlotron
author_rank: Super Contributor
timestamp: December 01, 2022, 06:07:03 am
content: you haveCode:BCC func01_2and thenfunc01_2 CPX readoutBNE func01_5RTSWon't exiting the latter with a RTS after initiallybranchingthere and consequently not pushing the stack eventually cause a stack underflow?

author: MIS42N
author_rank: Frequent Contributor
timestamp: December 05, 2022, 12:57:59 am
content: You say 'readout+0 is used as a checksum digit elsewhere', but it will get added in because your final comparison to exit is with readout, not readout+1Also I don't know how you distinguish between an address as a literal (usually expressed as #address) and an address as a source/destination.I would have thought you'd be using LDX #readout+7 and CPX #readout+1 but I don't know what assembler you are using.The code is a bit messy, possibly could use D register (A+B) to advantage in places and I would not call it addrL/M/H as addr implies address, maybe BinRsL/M/H (Binary result) but that's cosmetic. Some documentation would be good. 'here we multiply by 10' 'here we add in the next digit' etc. It may not help you but it will help the next poor sod that has to look at it. I'd just get it going and walk away - too many people fall into the "if it ain't broke, fix it until it is" mindset. Microsoft updates, I'm looking at you.

author: edavid
author_rank: Super Contributor
timestamp: December 05, 2022, 02:05:12 am
content: Quote from: Nominal Animal on November 30, 2022, 07:32:51 amThere is one here:http://www.hvrsoftware.com/6800emu.htm

author: ozcar
author_rank: Frequent Contributor
timestamp: December 05, 2022, 03:22:00 am
content: Quote from: MIS42N on December 05, 2022, 12:57:59 amI already mentioned that. For the 680x assemblers I encountered, # was used to indicate immediate addressing, where the byte or bytes following the opcode is the information being accessed. So, "LDX readout" would load the contents of readout into the index register. "LDX #readout" would assemble to have the two byte address of readout in the instruction, and it is that value that the instruction puts into the index register.Using a vintage assembler of the era (which allows only UPPERCASE symbols of maximum length 6!):Code:1 0000 ORG 02 0000 31 READO FCC '1234' directly addressable (one byte address)3 0100 ORG $1004 0100 35 READI FCC '5678' extended addressing required (two byte address)56 0104 DE 00 LDX READO loads contents (first two bytes) of READO into X7 0106 FE 01 00 LDX READI loads contents (first two bytes) of READI into X89 0109 CE 00 00 LDX #READO loads two byte address of READO into x10 010C CE 01 00 LDX #READI loads two byte address of READI into x1112 ENDIf the assembler used here is different, how do you load the contents of readout into the register?

author: Nominal Animal
author_rank: Super Contributor
timestamp: December 05, 2022, 03:46:10 am
content: This compiles usingm68hc11-as, the GNU assembler for MC68HC11 from packagebinutils-m68hc1xversion 2.18:Code:; compile using; m68hc11-as example.s -o example.o.datatemp5:.byte 0addr:.byte 0 ; Most significant byte.byte 0.byte 0 ; Least significant bytereadout:.byte 0 ; Checksum byte.byte 0 ; Least significant digit (0-9).byte 0.byte 0.byte 0.byte 0.byte 0.byte 0 ; Most significant digit (0-9)endreadout:.textconvert:clr addr+0clr addr+1clr addr+2ldx #readout+1 ; address of least significant digitjmp .firstloop:ldd addr+1 ; Least significant 16 bits of addrlsldstd addr+1ldaa addr+1rolastaa addr+0 ; addr now multiplied by 2,staa temp5 ; and temp5=most significant 8 bits of addrldaa addr+1 ; We only mangled A above, so reloading addr+1 sufficeslsldrol temp5 ; second doubling donelsldrol temp5 ; third doubling doneaddd addr+1 ; (A:B) = (A:B)+(addr+1:addr+2)std addr+1ldaa temp5adca addr+0staa addr+0 ; addr fully updatedfirst:ldab 0,x ; New digitclraaddd addr+1 ; Add to least significant 16 bits of addrstd addr+1 ; addrL and addrM updatedldaa #0 ; Does not affect carry (clra would)adca addr+0 ; Add carry and most significant 8 bits of addr to Astaa addr+0 ; and addr now fully updatedinxcpx #endreadout ; past the incoming data?blo .looprtsThe operand syntax is#valuefor immediates (8 and 16 bit, stored in the instruction)*zerofor value read from a zero page address.labelfor relative jumps within -128..+127 bytes of the beginning of the next instructionIn other words,addd addr ;adds the contents of [addr:addr+1] to the D register (A:B)addd *addr ;adds the contents of [addr:addr+1] to the D register (A:B), addr being in the zero pageaddd #addr ;adds the constant addr:addr+1 to the D register (A:B)which the MC68HC11 calls extended (EXT), direct (DIR), and immediate (IMM), respectively.The most complex instructions arebrclrandbrset,brclr *addr #mask .labelbrclr addr,x #mask .labelbrclr addr,y #mask .labelthat branch tolabelif bits specified in bytemaskare all clear (brclr) or all set (brset).I'm using Linux, so I don't have an emulator to check if the above code works. I guess I have to write my own, dammit. Fortunately, the opcode coding is extremely straightforward; no bit extraction or such, as it is just a simple bytecode.

author: DiTBho
author_rank: Super Contributor
timestamp: December 05, 2022, 12:27:41 pm
content: GAS syntax is not compatible with Motorola ssrmbly syntax.

author: DiTBho
author_rank: Super Contributor
timestamp: December 05, 2022, 12:29:06 pm
content: You cannot recompile BUFFALO with GAS.You need to adjust the code.Edit:Just checked, BUFFALO has interesting routines, bcd conversation etc

author: metertech58761
author_rank: Frequent Contributor
timestamp: December 06, 2022, 01:59:31 am
content: As far as testing environments, I have a small W7 box I picked up after finding that neither Parallels or VMWare Fusion would work on a M1 Mac.(things may have changed since then, but this small PC was VERY reasonable in price and was probably a better choice for my remaining Windows needs in the end)I have both THRSim11 and 6811IDE (former for full compile, latter for quick routine testing)MIS42N, ozcar: Yes, well spotted. That was a typo - yes, the LDX and CPX opcodes should be immediate-mode (in other words, #readout+7 and #readout)Circlotron: I'm not sure, but that code is as fragile as it is atrocious. Any attempts to make it flow better visually causes the code to fall apart in a multitude of brainfarts, hence my question to see if it could be rewritten a bit better.Oh, and there are other parts of the code that areeven worse, but that's another thread.The reason I use 'addr' for the 24-bit binary result is that is exactly what it is - the address of the unit to be tested (this is part of some code for a piece of test equipment I reverse engineered a while back)And regarding the arrangement of the readout bytes - that was dictated by the requirements of the Intel 8279 display / keyboard controller IC.If I ever finish optimizing the code, I can probably redo it to work on something juuuust a bit more modern.Anyway, the data readout portion of the display is 8 digits, the MSB being on the left (readout+7), going right towards readout+1, then the LSB (readout+0) contains the checksum digit (for example - if 64738 is entered as the address, the sum of the digits is 28, which is lopped off to leave just the 8. When the enter key is pressed, the code checks to ensure 8 was entered as the checksum before passing the data down to this routine).Nominal Animal: Your code didn't work.The X register address just kept drifting upwards and never exited.

author: Nominal Animal
author_rank: Super Contributor
timestamp: December 06, 2022, 03:19:18 am
content: Quote from: metertech58761 on December 06, 2022, 01:59:31 amDammit. TheINX;CPX #endreadout;BLO .loopshould have worked. The loop order is correct, it progresses from least significant digit to most significant digit.Oh well, time to create a simulator –– in Python, I think, for maximal OS portability and user modifiability without a toolchain –– to lick this.

author: MIS42N
author_rank: Frequent Contributor
timestamp: December 06, 2022, 03:22:20 am
content: Can't resist trying this.I downloaded what is supposed to be a 6811IDE emulator fromhttp://www.hvrsoftware.com/download.htm. Unpack the program is SDK6811.exe and run it - doesn't need installing.When I used the ADDD instruction, it did not seem to deal with the C carry flag properly, setting it when it shouldn't. So I replaced it with ADDB and ADCA. I'm assuming this is a bug in the emulator and ADDD will work properly in firmware. LDD and STD seemed to work OK.This code appears to work OK in the emulator - just save it as a text file, load it into the emulator with the LOAD button and RUN. The value 7654321 is hard coded, and converts to 0x74CBB1 (location 0003-5)Code:braconverttemp5.byte 0binV0.byte 0 ; big endianbinV1.byte 0binV2.byte 0read0 .byte 0 ; Checksum byte.byte 1 ; Little endian value.byte 2 ; 7,654,321.byte 3.byte 4.byte 5.byte 6read7 .byte 7 ; first digitconvert clr binV0 ; result = 0clr binV1clr binV2ldx #read7 ; point to first digitjmp firstloop ldaa binV0 ; Multiply binary value by 10staa temp5ldd binV1 ; 2 shifts = multiply by 4aslbrolarol temp5aslbrolarol temp5addb binV2 ; add the original = multiply by 5adca binV1std binV1ldaa temp5adca binV0staa binV0asl binV2 ; 1 shift = multiply by 10rol binV1rol binV0first ldaa 0,x ; add in next digitadda binV2staa binV2bcc nextinc binV1bne nextinc binV0next dexcpx #read0 ; all done?bne looprts

author: metertech58761
author_rank: Frequent Contributor
timestamp: December 06, 2022, 05:23:36 am
content: I have that downloaded and it is a handy app to test 68xx code fragments once you understand how it expects the code to be formatted.Just tried it and seems to work like a champ. Thank you!

author: ozcar
author_rank: Frequent Contributor
timestamp: December 06, 2022, 05:55:55 am
content: So, I did what I thought of before - assembled it for 6809 and lo, it worked. I had to adjust the source to keep the assembler used happy, but the instructions are unchanged. At least, unchanged by me, the assembler did its usual thing of converting the DEX instruction (which 6809 does not have) into LEAX -1,X .Code:0000 20 0C BRA CONVERT0002 00 TEMP5 FCB 00003 00 BINV0 FCB 0 ; BIG ENDIAN0004 00 BINV1 FCB 00005 00 BINV2 FCB 00006 00 READ0 FCB 0 ; CHECKSUM BYTE0007 01 FCB 1 ; LITTLE ENDIAN VALUE0008 02 FCB 2 ; 7,654,3210009 03 FCB 3000A 04 FCB 4000B 05 FCB 5000C 06 FCB 6000D 07 READ7 FCB 7 ; FIRST DIGIT000E 0F 03 CONVERT CLR BINV0 ; RESULT = 00010 0F 04 CLR BINV10012 0F 05 CLR BINV20014 8E 000D LDX #READ7 ; POINT TO FIRST DIGIT>0017 7E 003A JMP FIRST001A 96 03 LOOP LDAA BINV0 ; MULTIPLY BINARY VALUE BY 10001C 97 02 STAA TEMP5001E DC 04 LDD BINV1 ; 2 SHIFTS = MULTIPLY BY 40020 58 ASLB0021 49 ROLA0022 09 02 ROL TEMP50024 58 ASLB0025 49 ROLA0026 09 02 ROL TEMP50028 DB 05 ADDB BINV2 ; ADD THE ORIGINAL = MULTIPLY BY 5002A 99 04 ADCA BINV1002C DD 04 STD BINV1002E 96 02 LDAA TEMP50030 99 03 ADCA BINV00032 97 03 STAA BINV00034 08 05 ASL BINV2 ; 1 SHIFT = MULTIPLY BY 100036 09 04 ROL BINV10038 09 03 ROL BINV0003A A6 84 FIRST LDAA 0,X ; ADD IN NEXT DIGIT003C 9B 05 ADDA BINV2003E 97 05 STAA BINV20040 24 06 BCC NEXT0042 0C 04 INC BINV10044 26 02 BNE NEXT0046 0C 03 INC BINV00048 30 1F NEXT DEX004A 8C 0006 CPX #READ0 ; ALL DONE?004D 26 CB BNE LOOP004F 39 RTS0 ERROR(S) DETECTEDSYMBOL TABLE:BINV0 0003 BINV1 0004 BINV2 0005 CONVER 000E FIRST 003A LOOP 001A NEXT 0048READ0 0006 READ7 000D TEMP5 0002+++GET EETEST.BIN.1+++MON- SP=C073 US=C073 DP=00 IX=CC9C IY=C847- PC=D379 A=4E B=00 CC: E F - I - Z - ->E 0000-004F- 0000 200C0000 00000001 02030405 06070F03 ...............- 0010 0F040F05 8E000D7E 003A9603 9702DC04 .......~.:......- 0020 58490902 58490902 DB059904 DD049602 XI..XI..........- 0030 99039703 08050904 0903A684 9B059705 ................- 0040 24060C04 26020C03 301F8C00 0626CB39 $...&...0....&.9>^P PC=D379 0000>B 004F>G- SP=C073 US=C073 DP=00 IX=0006 IY=C847- PC=004F A=B1 B=D8 CC: E F - I - Z - ->E 0000-004F- 0000 200C2E74 CBB10001 02030405 06070F03 ..t............- 0010 0F040F05 8E000D7E 003A9603 9702DC04 .......~.:......- 0020 58490902 58490902 DB059904 DD049602 XI..XI..........- 0030 99039703 08050904 0903A684 9B059705 ................- 0040 24060C04 26020C03 301F8C00 0626CB39 $...&...0....&.9>Another view of it running at the bottom, so yes not run on a real 6809, but I even have a real one that I could probably get to run it.

author: MIS42N
author_rank: Frequent Contributor
timestamp: December 06, 2022, 07:12:12 am
content: Quote from: metertech58761 on December 06, 2022, 05:23:36 amYou are welcome. I didn't thoroughly test it. The add 1 byte to 3 bytes (label 'first') needs thrashing. I think it's OK, but this is the first bit of code I've written for 680x.

author: brucehoult
author_rank: Super Contributor
timestamp: December 06, 2022, 08:40:32 am
content: Quote from: ozcar on December 06, 2022, 05:55:55 amAs I'm sure you are aware, they went to some trouble to make the 6809 source code compatible with the 6800, but the binary encodings are completely different.As another example, the LDAA 0,X was implemented as LDA ,X with no offset at all. The 6809 can do 0, 5, 8 or 16 bit offsets from X, Y, S, or U. The 6800 can only do 8 bit offsets from X.

author: DiTBho
author_rank: Super Contributor
timestamp: December 06, 2022, 10:28:23 am
content: THRSim11 is the best one for meI have a couple of hc11 boards, I could attach to the internet, but I don't have the technology to redirect the serial monitor to a browser.I have developed a downloader that resets the board before downloading a program, so it could also be possible to interface it to a browser in order to download a binary-file (s19) to the target.

author: ozcar
author_rank: Frequent Contributor
timestamp: December 06, 2022, 11:08:47 am
content: Quote from: brucehoult on December 06, 2022, 08:40:32 am6809 opcodes are different, but I wouldn't call them completely different. Here is the same code assembled for 6800:Code:1 0000 20 0C BRA CONVERT23 0002 00 TEMP5 FCB 045 0003 00 BINV0 FCB 0 ; BIG ENDIAN6 0004 00 BINV1 FCB 07 0005 00 BINV2 FCB 089 0006 00 READ0 FCB 0 ; CHECKSUM BYTE10 0007 01 FCB 1 ; LITTLE ENDIAN VALUE11 0008 02 FCB 2 ; 7,654,32112 0009 03 FCB 313 000A 04 FCB 414 000B 05 FCB 515 000C 06 FCB 616 000D 07 READ7 FCB 7 ; FIRST DIGIT1718 000E 7F 00 03 CONVERT CLR BINV0 ; RESULT = 019 0011 7F 00 04 CLR BINV120 0014 7F 00 05 CLR BINV221 0017 CE 00 0D LDX #READ7 ; POINT TO FIRST DIGIT22 001A 7E 00 44 JMP FIRST2324 001D 96 03 LOOP LDA A BINV0 ; MULTIPLY BINARY VALUE BY 1025 001F 97 02 STA A TEMP526 0021 01 01 01 LDD BINV1 ; 2 SHIFTS = MULTIPLY BY 4** UNRECOGNIZABLE MNEMONIC27 0024 58 ASL B28 0025 49 ROL A29 0026 79 00 02 ROL TEMP530 0029 58 ASL B31 002A 49 ROL A32 002B 79 00 02 ROL TEMP533 002E DB 05 ADD B BINV2 ; ADD THE ORIGINAL = MULTIPLY BY 534 0030 99 04 ADC A BINV135 0032 01 01 01 STD BINV1** UNRECOGNIZABLE MNEMONIC36 0035 96 02 LDA A TEMP537 0037 99 03 ADC A BINV038 0039 97 03 STA A BINV039 003B 78 00 05 ASL BINV2 ; 1 SHIFT = MULTIPLY BY 1040 003E 79 00 04 ROL BINV141 0041 79 00 03 ROL BINV04243 0044 A6 00 FIRST LDA A 0,X ; ADD IN NEXT DIGIT44 0046 9B 05 ADD A BINV245 0048 97 05 STA A BINV246 004A 24 08 BCC NEXT47 004C 7C 00 04 INC BINV148 004F 26 03 BNE NEXT49 0051 7C 00 03 INC BINV050 0054 09 NEXT DEX51 0055 8C 00 06 CPX #READ0 ; ALL DONE?52 0058 26 C3 BNE LOOP53 005A 39 RTSAssembled strictly for 6800, LDD and STD have quite rightly been rejected, but many of the assembled instructions, BRA, JMP, ASLA , ROLA, and more are identical. Other instructions like CLR BINV0 are only different because 6800 does not have a Direct addressing mode variant, while 6809 does have, and the 6809 opcode for CLR Extended is the same as for CLR Extended on 6800. But yes, there are many differences too.6809 indexed addressing is very different to 6800. Besides the 0, 5, 8 and 16 bit offsets from X, Y, S or U, it also has register offset (A, B, or D) from X, Y, S or U, 0 offset from X, Y, S, or U with auto post-increment or pre-decrement by 1 or 2, 8 and 16 bit offsets from PC, and then a whole bunch of indirect indexed modes.

author: DiTBho
author_rank: Super Contributor
timestamp: December 06, 2022, 11:32:56 am
content: Hc11 should have special x and y opcodes not implemented in 6800.I remember something from an old project

author: metertech58761
author_rank: Frequent Contributor
timestamp: December 06, 2022, 01:06:25 pm
content: The main reason the 6801 / HC11 instruction set was called for is that other parts of this code uses the D (combined A / B) register for certain bit-shift operations and the MUL opcode for one math section.The code also has a routine that goes the other way, from binary to packed BCD (as well as a separate routine that unpacks BCD), but I want to get a better understanding of the arguments passed to the routine first before I ask for help picking apart that bit of code.

author: ozcar
author_rank: Frequent Contributor
timestamp: December 06, 2022, 11:17:12 pm
content: Quote from: metertech58761 on December 06, 2022, 01:06:25 pmI note that the code in the original post for some reason used ASLD but not LDD/STD, while the code as proposed by MIS42N that I tried on 6809 uses LDD and STD, but not ASLD. So, using ASLD as well and I now have this (also rearranged a bit as I saw no reason for FIRST to be last):Code:98 438A 7F 43 7C CONVERT CLR BINV0 ; RESULT = 099 438D 7F 43 7D CLR BINV1100 4390 7F 43 7E CLR BINV2101 4393 CE 43 86 LDX #READ7 ; SETUP FOR FIRST DIGIT102103 4396 A6 00 LOOP LDA A 0,X ; NEXT DIGIT TO ADD IN104 4398 BB 43 7E ADD A BINV2105 439B B7 43 7E STA A BINV2106 439E 24 08 BCC NEXT107 43A0 7C 43 7D INC BINV1108 43A3 26 03 BNE NEXT109 43A5 7C 43 7C INC BINV0110 43A8 09 NEXT DEX111 43A9 8C 43 7F CPX #READ0 ; ALL DONE?112 43AC 27 2B BEQ DONE ; YES113114 43AE B6 43 7C LDA A BINV0 ; MULTIPLY BINARY VALUE BY 10115 43B1 B7 43 7B STA A TEMP5116 43B4 FC 43 7D LDD BINV1 ; 2 SHIFTS = MULTIPLY BY 4117 43B7 05 ASL D118 43B8 79 43 7B ROL TEMP5119 43BB 05 ASL D120 43BC 79 43 7B ROL TEMP5121 43BF F3 43 7D ADD D BINV1 ; ADD THE ORIGINAL = MULTIPLY BY 5122 43C2 FD 43 7D STD BINV1123 43C5 B6 43 7B LDA A TEMP5124 43C8 B9 43 7C ADC A BINV0125 43CB B7 43 7C STA A BINV0126 43CE 78 43 7E ASL BINV2 ; 1 SHIFT = MULTIPLY BY 10127 43D1 79 43 7D ROL BINV1128 43D4 79 43 7C ROL BINV0129 43D7 20 BD BRA LOOP130131 43D9 DONE EQU *For something a bit different, that was assembled for 6803, and tested on the pretend 6803 that I had to hand, which explains the somewhat weird address that was assembled for.

author: MIS42N
author_rank: Frequent Contributor
timestamp: December 07, 2022, 08:26:40 am
content: Quote from: ozcar on December 06, 2022, 11:17:12 pmI had not encountered the 6800 before. So I just did what worked in the emulator. No attempt to optimise further. I tried writing ASLD but what I wrote wasn't accepted. At the time I remember thinking there probably wasn't one, but it it is more likely a typo on my part. Mea culpa.

author: MIS42N
author_rank: Frequent Contributor
timestamp: December 08, 2022, 12:18:21 pm
content: To get more familiarity with the 6800, I wrote a binary to packed decimal routine. Normally one would use the DAA instruction, but the emulator doesn't implement it. So in the emulator, the DAA instruction is emulated by a subroutine EmDAA. Two levels of emulation!The subroutine EmDAA is a bit obscure, it was based on a table in the Motorola_M6800_Programming_Reference_Manual_M68PRM(D)_Nov76.pdf which I found online.Code:braconvertPdec0 .byte 0 ; resultPdec1 .byte 1 ; big endianPdec2 .byte 2 ; packed decimalPdec3 .byte 3binV0.byte $74 ; big endianbinV1.byte $CBbinV2.byte $B1count .byte 0convert clr Pdec0 ; result = 0clr Pdec1clr Pdec2clr Pdec3ldaa #24 ; bits to shiftstaa countloop1 asl binV2 ; get hi bit of binaryrol binV1rol binV0ldx #binV0loop2 dexldaa 0,Xadca 0,Xbsr EmDAA ; emulated DAAstaa 0,Xcpx #Pdec0bne loop2dec countbne loop1rts; emulate the DAA instructionEmDAA tabtpaanda #$20 ; isolate half carrybcs EmCybne EmCnHy ; C clear H set; C clear H cleartbaanda #$0Fcmpa #$0Abcs xxxEmCnHy addb #$06xxx cmpb #$A0bcs EmXCnEm60 addb #$60EmXCy tbasecrtsEmXCn clctbarts; C setEmCy bne EmCyHy ; C set H settbaanda #$0Fcmpa #$0Abcs Em60EmCyHy addb #$06bra Em60

author: ozcar
author_rank: Frequent Contributor
timestamp: December 09, 2022, 07:37:45 am
content: Quote from: MIS42N on December 08, 2022, 12:18:21 pmWhat sort of strange emulator implements the half-carry flag but not the DAA instruction?Having discovered myself some three decades ago (!) that the DAA instruction is a bit tricky to emulate, I grabbed your EmDAA routine and subjected it to the DAA testing from Wolfgang Schwotzer's CPUTEST program. That is really for testing 6809 emulation (and I think I found it bundled with a 6809 emulator, but I'm not sure now exactly where it was now). However, I think the 6800 DAA and 6809 DAA should be the same. Edit, found it here:https://github.com/aladur/flexemu/blob/master/src/tools/cputest.txt.That is not a total torture test, but it does test DAA for 16 different accumulator A values for all four combinations of H and C flags, so a total of 256 tests. It found a problem on the final test for H=0, C=0, with A=$FF (should result in A=$65, but instead got A=$05). It stops at that point, so maybe it would find other problems too.But then maybe you don't need a completely accurate DAA emulation there - I did not get a chance to see how you use the DAA there, and maybe any differences don't matter for your purposes. One way to to give it a good thorough test would be to combine the binary->decimal and decimal->binary conversions, and check that you get the same value you started with. You could start at zero and just add one each time - could be a good speed test for the emulator too.

author: MIS42N
author_rank: Frequent Contributor
timestamp: December 09, 2022, 10:48:49 am
content: Quote from: ozcar on December 09, 2022, 07:37:45 amAn oversight on my part. It is caused when there is a half carry when $06 is added to B, and the high nibble of B was $Fx. You are right, it would not be encountered the way it is being used. The A values are (packed decimal value)*2 + carry from previous (if there is one). So the high nibble of B will be even, and a half carry will make it odd.Can be fixed by changingCode:EmCnHy addb #$06xxx cmpb #$A0toCode:EmCnHy addb #$06bcs Em60xxx cmpb #$A0So even if I had done the binary->decimal->binary it wouldn't have shown an error. It needs something like $77+$88 (both legit packed decimal numbers) which after DAA should be $65 + C. So it does need fixing if someone is relying on it.

author: Nominal Animal
author_rank: Super Contributor
timestamp: December 09, 2022, 12:00:38 pm
content: Is there a reference that describes the individual operations exactly?For example, I thought half carry (H) was defined asR := (val1& 0x0F)OP(val2& 0x0F)H := (R < 0) OR (R > 9)whereval1andval2are the operands, andOPis the arithmetic operation done on them.Is there an exact reference for these? Actually, the only ones I'm missing are the condition codes' exact rules, and the division and multiplication instructions.

author: ozcar
author_rank: Frequent Contributor
timestamp: December 09, 2022, 07:06:56 pm
content: Quote from: MIS42N on December 09, 2022, 10:48:49 amI added the extra instruction, and now it sails through all the tests without complaining.I just noticed my dodgy arithmetic above, it does a total of 64 DAA tests, not 256. 64 DAA tests should be enough for anybody?

author: ozcar
author_rank: Frequent Contributor
timestamp: December 09, 2022, 07:12:08 pm
content: Quote from: Nominal Animal on December 09, 2022, 12:00:38 pmI never did much with HC11, and don't remember much about it other than it had MUL, FDIV and IDIV instructions. For 6800, 6803 and 6809 at least I think the half-carry was only meant for addition. I happen to have a real, printed on paper, version of the 6809 reference manual lying here and from that it looks like H is set in a useful way only for 8-bit ADD and ADC instructions. For other instructions including 16-bit ADD, 8-bit or 16-bit SUB, and MUL, H is either "not affected" or "undefined".My first 6809 emulation was written in 68000 assembly language. 68000 not having half-carry, for the 6809 add instructions that needed valid H, I just added the low nybbles separately and used bit 4 (0x10 position) of the result as H.

author: Nominal Animal
author_rank: Super Contributor
timestamp: December 10, 2022, 07:44:33 am
content: Quote from: ozcar on December 09, 2022, 07:12:08 pmD'oh! You're right; that also applies to 68HC11 as well.

author: MIS42N
author_rank: Frequent Contributor
timestamp: December 13, 2022, 12:42:39 am
content: I was thinking I had used the Half Carry for something in the past, finally found it. It was an AtMega328P project, I was holding 12 * 16 bit values in register pairs. The 16 bits was split 4/12 and I needed to compare the 12 bit values with one in the register pair ZH/ZL. Usually that would mean ANDing off the high 4 bits. Fortunately the processor set the H bit on compares as well as arithmetic operations so this works:Code:cp r0,ZLcpc r1,ZHbrhs n2insR0This would be really useful in the code for the emulated DAA instead of having to transfer the value to another register and AND $0F to get rid of the high bits. Why does the 6800 not do this on compares? Compares are usually implemented in the processor as an arithmetic operation, discarding the result and keeping the status. One would think more circuitry would be needed to set the H flag only on addition and not otherwise.

author: ozcar
author_rank: Frequent Contributor
timestamp: December 13, 2022, 03:35:30 am
content: Quote from: MIS42N on December 13, 2022, 12:42:39 amThe 6800 reference manual says that H is "not affected" by compare and subtract instructions. As for why, maybe because subtract and compare were implemented by negating the second operand and then adding, and they couldn't be bothered to sort out the half-borrow, but did not want it to be "undefined"?Somewhat strangely, the 6809 reference manual that I have ("Original issue, March 1, 1981"), says that H is "undefined" for both 8-bit compare and 8-bit subtracts. That would make source code compatibility with 6800 a bit tricky, so I did a test, this time on a real 6809, and for the few values that I tested, H was actually "not affected", so as stated for 6800. Now if I tested with another 6809, or perhaps even the same 6809 tomorrow, maybe the results would be different, but I don't think that is very likely. But your guess is better than mine as to why they would say "undefined" in the fine manual if you could rely on it being "not affected".