Hitachi 6309 Description

Alan DeKok's additions

The new features of the 6309 are closely related to the changes in design from the 6809. The 6309 is micro-coded, which allowed the designers to easily add new instrctions and registers. It also has a one byte pre-fetch 'cache', which enables the 6309 to execute instructions like 'lsld' (2-bytes) in one clock cycle. The design of the 6809 series allows them to read one byte per clock cycle MAXIMUM, but there is a catch. Most instructions take more clock cycles to execute than bytes they contain. While the 6309 is performing internal calculations, the 'cache' hardware goes and reads the next instruction byte, leaving only one additional byte to be read to execute the 'lsld'. Reading this byte requires one clock cycle, and then the instruction is executed while the CPU fetches the next instruction.

The 6309 has a true 16-bit internal design.
e.g. the EXG instruction operates as
6809: read op-code
      read inter-register byte (r0,r1)
        r0_high -> temp_high
        r0_low  -> temp_low
        r1_high -> r0_high
        r1_low  -> r0_low
        r0_high -> r1_high
        r0_low  -> r1_low

8 actions, 8 clock cycles.

6809: read op-code
      read inter-register byte (r0,r1)
        r0 -> temp
        r1 -> r0
        r0 -> r1

5 actions, 5 clock cycles.

The 6309 native mode instruction execution clock lengths can be mostly accounted for by accounting for the pre-fetch cache and the internal 16-bit ALU.

TFM has some caveats. TFM r1-,r2- should NOT be used to setup the stack, as it's a POST-decrement instruction, not PRE-decrement.

Watch out for TFM r1,r2+ if you're reading from a peripherial. Why? The TFM uses the 1-byte 'cache' as an internal buffer for the byte that it's currently moving. The TFM instruction is interruptible (the only instruction that is), and code execution during the interrupt will destroy the byte in the cache.

On returning from the interrupt, the TFM will read the FROM address again to get the lost byte, which may be the wrong one. The visible effect of this is that block moves sometimes have a byte missing from the middle, and everything after that byte shifted down one address.

There are a few ways of checking of you're running on a 6309 or a 6809, these include:

:
 tfr 0,d  -> illegal registers are '$FFFF' on a 6809, $0000 on a 6309
 tstb     ->
 beq  Is6309
:

:
 ldb #$ff
 clrd      -> executes as a $10 (ignored) $4F (clra) on a 6809
 tstb
 beq  Is6309
:

It's a bit harder to check if the system is running in native mode or not. Most of the time it won't be necessary, but the only realy method is to do:

:
 pshs cc,d,dp,x,y,u  SAVE ALL REGISTERS AS CHECKING WILL TRASH THEM
 leax Is6309,pc
 pshs  x               save address of 6309 flag code
 leax Is6809,pc
 pshs  x               save address of 6809 flag code
 pshs  cc,d,dp,x,y,u   save registers
 orcc #ENTIRE          set to ALL registers on-stack
 rti                   go to 6309/6809 code

Is6309 clr <Flag   it's a 6309
 bra Continue

Is6809 leas 2,s   account for 6309 PC
  lda #$FF
  sta <Flag

Continue puls cc,d,dp,x,y,u  restore all registers
[etc...]
:

Note that the checks for both 6809/6309 and native/emulation will execute perfectly on both 6809 and 6309 systems, and will give the correct results in all cases.

In order to check for 6309 FIRQ operation (i.e. all registers saved), you'd have to do something like

[ enable FIRQ's ]
:
 leau -3,s       where stack will be if only CC and PC are saved
 stu <test       remember the pointer
loop tst <check  FIRQ happened yet?
  bne loop       no, wait for an FIRQ
[...]

FIRQ cmps <test  only CC, PC saved?
 bne  Is6309F    no, it's 6309 FIRQ mode
 clr <F.Flag     set to 6809 IRQ mode
 bra continue

Is6309F lda #$FF don't bother saving A as 6309 FIRQ mode already saves it
 sta <F.Flag     set the FIRQ flag

continue clr <check         we've done an FIRQ, so we can exit
 rti
:

The W,E, and F registers do not have the full immediate addressing mode capabilities that D,A, and B do. SBC, AND, BIT, EOR, ADC, OR with E,F,W are available only in register-register mode. LSR, ROR, ROL are available for W but not for E,F. ASR, ASL, LSL, NEG do not exist at all for W,E,F.

ASL can sort of be implemented by doing a ADDR R1,R1. (see later)

You can also do things like 'leax u,x' by doing a ADDR u,x.

Sadly, many of the new 6309 instructions are useless in everyday life. The bit manipulation instructions are interesting, but slow and mostly of limited value. Same with much of the DIV/MUL higher math. The AIM, etc. are very useful, though.

Programmer recommendations

Try to stay away from using the W register. It's got another pre-byte (like instructions using 'Y' or 'S'), and is correspondingly larger and slower. E and F are best used mainly instead of pushing loop counters onto the stack when you're running out of registers.

The V register is mostly pointless. If you're doing context switches, it isn't saved across interrupts unless you do so manually. Shuffling data back and forth between other registers and V is a lot of trouble. Any math, etc. involving V is generally done much faster using a real register. After going through 1meg+ of 6309 assembly code which is everything from an OS kernel to serial drivers to graphics drivers, I've never seen a use for the V register.

Of course, you could put '$FFFF' into V, and have registers for reg-reg addressing modes with bits all zero (0), and another with bits all 1 (V).

Pseudo-nops: tfr 0,0; exg 0,0

Extremely small software timing loops with large delays may be generated by performing a 'LDW',and then 'TFM r0,r0+'.

Many programs can be executed in 6309 native mode by patching only the IRQ code, if it accesses the stack. A 'LDMD #$01' may be performed as soon as your program starts executing, and will see an immediate 10-15% speed increase. Software timing loops must be checked!

Opcodes Hitachi left out of the 6309: and some round-about equivalents

E/F/W
-----
ADCr:  ADCR 0,r
ANDr:  ; ANDR V,r
ASLr/LSLr:  ADDR r,r
ASRr
BITr
EORr
NEGr:  COMr INCr
ORr
SBCr:  SBCR Z,r


E/F
---
LSRr
ROLr: ADCR r,r
RORr

Q (Long word =W1:W0)
--------------------
ADDQ: ADDW W0; ADCD W1
SUBQ: SUBW W0; SBCD W1
ASLQ: ASLW   ; ROLD
ROLQ: ROLW   ; ROLD
LSRQ: LSRD   ; RORW
RORQ: RORD   ; RORW
ASRQ: ASRD   ; RORW
COMQ: COMD   ; COMW
NEGQ: COMD   ; COMW ; SBCR 0,D

Please note: I did not write these pages. They were copied from the The Wayback Machine to make them easier to navigate (see top right menu) and to keep them alive a little bit longer, for posterity.