EEVblog Electronics Community Forum

Products => Computers => Programming => Topic started by: metertech58761 on December 09, 2022, 06:19:07 am

Title: Another bit of 68xx code
Post by: metertech58761 on December 09, 2022, 06:19:07 am
I recently posted a bit of HC11 assembly code for converting unpacked BCD to binary, and I thank those that took time to look at it and for the replacement code that someone offered.

I figure the code that does the opposite is probably just as inefficient, so here we go.

;      Convert binary data to BCD values
bin2BCD      LDX   f2BCD
      LDAB  f2bytes
      LDAA  #$00
func02_1   STAA  $00,X
      DEX
      DECB
      BNE   func02_1
      INX
      STX   f2BCD
      LDAA  #$80
      STAA  f2bitpos
func02_2   LDX   f2binary
      LDAA  $00,X
      PSHA
      DEX
      STX   f2binary
func02_3   PULA
      PSHA
      ANDA  f2bitpos
      BEQ   func02_5
      LDX   f2BCD
      LDAB  f2bytes
      LDAA  $00,X
      ADDA  #$01
func02_4   DAA
      STAA  $00,X
      DECB
      BEQ   func02_5
      INX
      LDAA  $00,X
      ADCA  #$00
      BRA   func02_4
func02_5   LDAA  f2bits
      CMPA  #$01
      BEQ   func02_7
      LDX   f2BCD
      LDAB  f2bytes
      LDAA  $00,X
      ADDA  $00,X
func02_6   DAA
      STAA  $00,X
      DECB
      BEQ   func02_7
      INX
      LDAA  $00,X
      ADCA  $00,X
      BRA   func02_6
func02_7   DEC   f2bits
      BEQ   func02_8
      LSR   f2bitpos
      BNE   func02_3
      PULA
      LDAA  #$80
      STAA  f2bitpos
      BRA   func02_2
func02_8   PULA
      RTS


As I mentioned in the other thread, this routine has a few prerequisites before being called:

f2binary - 16-bit address of the source binary data
f2BCD - 16-bit address of the packed BCD output (these are stored in the same sequence as the readout as mentioned in the other thread; 7/6, 5/4, 3/2, 1/0)
f2bytes - I assume this is a byte counter (only 2 values are used: 2 or 4)
f2bits - I assume this is a bit counter (only 2 values are used: 8 or 24 - corresponding to above values)

Title: Re: Another bit of 68xx code
Post by: metertech58761 on January 06, 2023, 07:59:12 pm
I'm now actively working to figure out this bit of code... my interest is trying to figure out why it pushes and pulls values on and off the stack versus using an actual variable in RAM.

It seems 6811IDE doesn't work well with PSHA / PULA, and I'm having fits trying to get THR6811 to accept ORG - no matter how I try and format the address, it gets rejected every time.  :wtf:
Title: Re: Another bit of 68xx code
Post by: brucehoult on January 07, 2023, 11:13:06 pm
I'm now actively working to figure out this bit of code... my interest is trying to figure out why it pushes and pulls values on and off the stack versus using an actual variable in RAM.

It's only one thing -- the current byte from f2binary.

Push and pull are normally used for code compactness, at the expense of speed, because they are only 1 byte, vs 2 bytes each for store to direct page and load from direct page. But that is negated when you do "PULA;PSHA" when it could have been just a load, and have to add not one but two gratuitous "PULA" in func02_7 / func02_8 to clean up. You're ending up with 5 bytes of code in total when it could have been just 4 with storing the result of "LDAA  $00,X" to DP and then loading it at the start of func02_3 and that's it.

I suspect the code was hacked on a lot after it was initially "designed".

The whole 68xx "LDX ptr;LDAA $00,X;DEX;STX ptr" dance kind of pisses me off every time I see it. Sooo much easier and faster on 6502 to just do "LDA (ptr),Y;DEY", especially when you know the buffers are no more than 256 bytes, as here ("f2bytes" fits into B). When the size can be greater than 256 on 6502 then you need a little bit of fiddling in an outer loop which more or less equalises the code size. but there's still a fast inner loop.

Or 6809, of course, where you have X, Y, and if you need it U.
Title: Re: Another bit of 68xx code
Post by: metertech58761 on January 09, 2023, 09:33:03 pm
So I could just add a dedicated variable (or even use one of the existing 'scratchpad' variables) and just do away with PSHA / PULA?

The code I started with could easily be described as "And it still works?! Really?!" Some sections only needed minor cleanup but two major sections still had to be torn to bits and reassembled in a more logical order (and the result is ALSO a few dozen bytes shorter!)

The bit about the index registers on the 68xx vs. the 6502 IS a pain indeed! It's almost like they flipped the index and base around.
Title: Re: Another bit of 68xx code
Post by: MIS42N on January 10, 2023, 01:46:00 am
I already wrote the bin->dec for you https://www.eevblog.com/forum/programming/cleaning-up-a-bit-of-6800-assembly-code/msg4569265/#msg4569265 (https://www.eevblog.com/forum/programming/cleaning-up-a-bit-of-6800-assembly-code/msg4569265/#msg4569265)

I don't have the hardware to test it using the DAA instruction so it was emulated. Not exactly what you asked for as I didn't have the requirements. I'll look later at your code and resolve any differences.
Title: Re: Another bit of 68xx code
Post by: brucehoult on January 10, 2023, 01:49:52 am
So I could just add a dedicated variable (or even use one of the existing 'scratchpad' variables) and just do away with PSHA / PULA?

Sure looks like it.

But the whole code is pretty whack. Why do binary/BCD conversion 1 bit at a time (with a loop) instead of 4 bits at a time?
Title: Re: Another bit of 68xx code
Post by: MIS42N on January 10, 2023, 04:11:56 am
So I could just add a dedicated variable (or even use one of the existing 'scratchpad' variables) and just do away with PSHA / PULA?
You don't even need to do that. The way it is written, you can get the value into A with
Code: [Select]
    LDX   f2binary ; address of binary to convert
    LDAA  $01,X
because X was decremented. I would prefer to decrement X at the end of the loop so it is LDAA $00,X but that's cosmetic.

It appears the code is generic, convert X bits of binary to Y bytes of BCD. You say X is either 8 or 24 and Y is either 2 or 4, makes sense.
It also does not destroy the binary (which my code does).

Working on it.

Title: Re: Another bit of 68xx code
Post by: MIS42N on January 10, 2023, 06:42:55 am
But the whole code is pretty whack. Why do binary/BCD conversion 1 bit at a time (with a loop) instead of 4 bits at a time?

Do you have an algorithm that does that?

I now have a somewhat bastard child of my code and the OP code. It runs in the HVRSoftware emulator, make sure to put a break at Line 52 or it will just keep going. An oddity, the emulator did not return a Z flag on line 45 when the mask bit got shifted out. I thought it should. So I used BCC instead of BNE (the mask bit gets shifted into C). And I had to emulate DAA.

I couldn't figure out which way the input and output bytes were ordered or addressed, so I made both big endian. That makes it easy to see the result in the emulator 7654321

Code: [Select]
       bra main

binVal .byte $74,$CB,$B1       ; big endian
f2binary .rmb 2

xyz      .rmb 8
decVal   .rmb 8
f2BCD    .rmb 2

f2bytes .byte 4
f2bits  .byte 24
f2bitpos .rmb 1

main LDX #binVal
STX f2binary
LDX #decVal
STX f2BCD

bin2BCD  LDX   f2BCD ; address of output ? couldn't figure what this DEX, INX adjustment of f2BCD was doing
      LDAB  f2bytes ; number of bytes to output
      LDAA  #$00
func021  STAA  $00,X ; clear output to zero
      DEX
      DECB
      BNE   func021
      INX
      STX   f2BCD
func022  LDAA  #$80 ; mask for
      STAA  f2bitpos ; bit position in binary byte
func023  LDX   f2binary ; address of byte in binary to convert
      LDAA  $00,X
      LDX   f2BCD ; set up for loop
      LDAB  f2bytes
      ANDA  f2bitpos ; a bit of A = 1?
      ADDA  #$FF ; will set carry if A has any bit set
func024  LDAA  $00,X ; double the BCD and add in any carry
      ADCA  $00,X
      bsr   EmDAA ; and decimal adjust it
      STAA  $00,X
      DEX ; *** or INX if little endian
      DECB        ; adjusted all output bytes
      BNE   func024 ; no, next byte
func025  DEC   f2bits ; more binary bits to process?
      BEQ   func028 ; no
      LSR   f2bitpos ; yes, adjust the mask
      BCC   func023 ; mask still has a bit
      LDX   f2binary ; no bits, move to the next binary byte
      INX ; *** or DEX if little endian
      STX   f2binary
      BRA   func022 ; and repeat

func028  RTS

; emulate the DAA instruction
EmDAA   pshb
        tab
        tpa
        anda  #$20 ; isolate half carry
        bcs   EmCy
        bne   EmCnHy ; C clear H set
; C clear H clear
        tba
        anda  #$0F
        cmpa  #$0A
        bcs   xxx
EmCnHy  addb  #$06
        bcs   Em60
xxx     cmpb  #$A0
        bcs   EmXCn
Em60    addb  #$60
EmXCy   tba
        pulb
        sec
        rts
EmXCn   tba
        pulb
        clc
        rts
; C set
EmCy    bne   EmCyHy ; C set H set
        tba
        anda  #$0F
        cmpa  #$0A
        bcs   Em60
EmCyHy  addb  #$06
        bra   Em60

     .end
       
Title: Re: Another bit of 68xx code
Post by: metertech58761 on January 10, 2023, 08:30:33 am

I'll check out the code, thanks again.

Also, yes, both the source (f2bin) and destination (f2BCD) ranges are big endian.

It also appears f2bits is the actual number of bits to be converted and f2bytes is the number of bytes to be converted plus one, and that matches the unpacking process for one of the instances after this routine is called.

Oh, and for laughs, I'm attaching a reconstruction of the as-dumped code and the results of my ongoing cleanup.
Title: Re: Another bit of 68xx code
Post by: MIS42N on January 10, 2023, 11:29:56 am
It also appears f2bits is the actual number of bits to be converted and f2bytes is the number of bytes to be converted plus one, and that matches the unpacking process for one of the instances after this routine is called.
I am confused by the destination address passed to Bin2BCD in the variable f2BCD. It looks like it is the address of the last byte, and the destination gets cleared by stepping backward to the first byte. Then when doing the binary to decimal conversion it steps from first to last. Say the destination number is 01234567 it looks to me like it ends up in the bytes as 67|45|23|01 which is not big endian. This seems to be confirmed by dispBCD routine which will unpack it as 0|1|2|3|4|5|6|7 - little endian
Quote
Oh, and for laughs, I'm attaching a reconstruction of the as-dumped code and the results of my ongoing cleanup.
So you had a dump of the memory, disassembled it, and now trying to make sense of it? Arrrrrgh!!
I think it needs a LOT more annotation before doing a cleanup. What the ** are all those tests doing? I'd put a page of notes at the beginning to give some idea of what is going on.
How's your headache? bedtime here, I'm off.
Title: Re: Another bit of 68xx code
Post by: metertech58761 on January 10, 2023, 01:32:31 pm
It may help to know the physical display on the unit is arranged 98 76543210.

Digits 9 and 8 are represented by the variable testOne, hence the backwards representation of the test number.

If you think this is hard to make sense of, the firmware for the LMT-2 is even worse - like trying cram 5K of code into 4K.

Edit: I've attached notes that may help make more sense of the code.
Title: Re: Another bit of 68xx code
Post by: MIS42N on January 17, 2023, 11:02:24 am
I downloaded the files and looked at them. Too much to take in without spending a lot of time (which, if I was being paid big bucks, maybe. Otherwise there's plenty of other things I can be doing). Specific questions are OK. Did the bin->dec code do the job?
Title: Re: Another bit of 68xx code
Post by: metertech58761 on January 18, 2023, 03:17:25 am
I have it saved, but I need to take a step back to make sure I understand how the data is being set up and handled. Perhaps we can trim the overhead requirements.

Also, right now, the code goes from binary -> packed BCD -> unpacked BCD. I'm wondering if that intermediate step is truly necessary.

Title: Re: Another bit of 68xx code
Post by: MIS42N on January 18, 2023, 05:50:29 am
I have it saved, but I need to take a step back to make sure I understand how the data is being set up and handled. Perhaps we can trim the overhead requirements.

Also, right now, the code goes from binary -> packed BCD -> unpacked BCD. I'm wondering if that intermediate step is truly necessary.
It is not necessary but it is advantageous. To convert from binary to decimal the process is to start with a decimal number of zero. then look at the binary number highest bit to lowest bit. Each decimal digit is multiplied by two (adding it to itself does the same thing) and the bit from the binary is added in. It is necessary to check each decimal digit after the add to see if it is > 9 and if it is subtract 10 and carry 1 to the next higher digit. So in your case it would be necessary to look at and possibly adjust every decimal digit for every bit moved in. The DAA instruction helps, but you still end up having to check and adjust every digit for every bit processed.

By using packed decimal, it halves the number of bytes used to store decimal digits, and the DAA instruction does all the heavy lifting of adjusting for carries so it is not necessary to check each digit after each double. The computation time is a lot less and more than makes up for the extra step of unpacking. And if the packed to unpacked was a loop (I don't think your is at the moment) then a bit of code space is saved (although more code than binary->unpacked decimal. So it is a trade off between code and speed.
Title: Re: Another bit of 68xx code
Post by: DiTBho on January 18, 2023, 07:25:09 am
I bought a keyboard and found an HC11 chip as controller
this resumed my interests for HC11 hacking and programming

So, I am porting BUFFALO/HC11 from Motorola-AS/11 to GNU-AS/11.
I can say ... BUFFALO is full of good assembly examples

take a deep look, it's very informative and entertaining :D
Title: Re: Another bit of 68xx code
Post by: MIS42N on January 18, 2023, 09:21:01 am
I bought a keyboard and found an HC11 chip as controller
this resumed my interests for HC11 hacking and programming

So, I am porting BUFFALO/HC11 from Motorola-AS/11 to GNU-AS/11.
I can say ... BUFFALO is full of good assembly examples

take a deep look, it's very informative and entertaining :D
More info? I looked up buffalo hc11 and it described a monitor program. But no good assembly examples. I'm not looking in the right places.

I prefer cross assembly - a good example is MPLAB X, has an emulator. I build some sort of UART capability into the program so when it is in the target, it can be debugged further if needed.
Title: Re: Another bit of 68xx code
Post by: DiTBho on January 18, 2023, 10:25:42 am
More info? I looked up buffalo hc11 and it described a monitor program. But no good assembly examples. I'm not looking in the right places.

yeah, BUFFALO is a monitor. It has several subroutines which are good examples of hc11 assembly programming.
There are even BCD subroutines extensions that you can re-use as kind of "BIOS" for your uploaded programs.

I prefer cross assembly - a good example is MPLAB X, has an emulator. I build some sort of UART capability into the program so when it is in the target, it can be debugged further if needed.

HC11 is early 90's technology, rather abandonware. There is still some copy of PCBUG11 around, written in Delphi. It's Windows-only, but it comes with a "talker" (chip specific, 256byte, 512byte, greater), designed to consume only 200byte of ram, it allows iterative development and debugging via uart at 9600bps.

Nice idea!

I've implemented something similar on GNU/Linux (same "talker", different host-debugger), but if you have enough ROM space, you can also use BUFFALO for that, even writing a gdb-buffalo--bridge so you don't need to write a gdb11-stub.

I think it's better, because ... well, a gdb-stub is ... basically ... the same as the mentioned "talker", just much more powerful  :o :o :o

gcc has been pretty ignoring hc11 for several releases, *there was* a simulator with a very old gdb package.
Title: Re: Another bit of 68xx code
Post by: metertech58761 on January 18, 2023, 11:53:29 am
So, 5 of the calls to the binary to BCD routine take the same parameters, so it's like we could almost just build those parameters into the routine: f2bits (24), f2bytes (4 - but we are actually converting 3 bytes, the existing code counting down to 1), and f2BCD (position 6/7, the code once again stopping one digit shy). The only thing that changes is which three bytes we are converting to decimal.

The other two calls handle one digit apiece... given the firmware ID goes no higher than 95 (0x5F), and the revision is likely a low value number, a simple DAA should suffice for those values, correct?