MyHDL

Natural method for expressing horizontal microcode?

Second noob question: is there a natural way, in python or myhdl, to represent a horizontal microcode ROM?

For example, is there a simple/natural way to concatenate enums for representation in each line of the the ROM (e.g. as an intbv) and then, when a line is read, to extract the individual enum fields as separate micro-opcodes for different functional elements?

I had to look that up :slight_smile: (Microprogramming)
I have done only a few simple sequencers until now.
Can you elaborate a bit more?

Regards,
Josy

Here’s a link to the wikipedia article, which covers horizontal and vertical microcode. In horizontal microcode the control word is a set of (usually) fixed-width fields, each of which controls a different functional block in a processor, e.g. ALU operations, status flag control, operand selection and so on. For design and debugging it’s preferable to express these operations in a human readable form (see below), which can then be compiled into the memory contents. If each field is specified using an enumerated type this should help detect errors.

However, once the control word is read from the memory, it would then be helpful to unpack the enumerations for use in each separate block.

Perhaps I’m arguing myself into modelling each line of the ROM as a list of enums, or as an object with particular enum elements, and then maybe using something else to generate a binary output for synthesis.

@block
def microcode(addr, dout):
    data = (
            ...
            mc(ABUS_REG_A, BBUS_MDR, ALU_OP_ADD, Z_FLAG_ALU...)
            ...
            )

    @always_comb
    def read_logic():
        dout.next = data[int(addr)]

    return read_logic

I have used IntEnum to represent that kind:

class FpOpcode(IntEnum):
    ''' a very simple-opcode machine '''
    # load immediate 8-bit value
    LDC = 0  # clears upper 24 bits
    LDI = 1  # shifts right 8 bits, then adds the 8-bit value in upper 8bits
    # register file access
    LDR = 2
    STR = 3
    # input/output
    LDO = 4
    STO = 5
    # feeding/reading the ALU
    STA = 6
    LDA = 7
    # branching, 10 bit address
    BRA = 8
    CALL = 9
    RET = 10
    # Avalon MM bus access
    LDM = 11
    STM = 12


class FpConditionCode(IntEnum):
    ''' as used in Xilinx FP IP '''
    EQ = 0x01
    Lt = 0x02
    LE = 0x03
    Gt = 0x04
    GE = 0x05
    Ne = 0x06
    NAN = 0x08
    # our extensions
    Zr = 0x0b
    NZ = 0x0c
    Always = 0x0f

...
        opcode = Signal(intbv(0)[4:])
        conditioncode = Signal(intbv(0)[4:])

...
            opcode.next = rom.RomBus.ReadData[18:14]
            conditioncode.next = rom.RomBus.ReadData[14:10]

...

                elif opcode == FpOpcode.BRA:
                    if conditioncode == FpConditionCode.Zr:
                        if accu == 0:
                            smn.next = fpsequencer_states.BRANCH
                            pcbranch.next = 1
                        else:
                            pcinc.next = 1

I (re-)wrote a small assembler to generate the rom-code

Thanks josyb. I don’t know much about IntEnum. I’ll take a look.