Yuki CPU Mikrocodeassembler

Dies ist ein Nebenprojekt zu meiner Yuki CPU und meinem Zweistufenassembler für diese CPU. Der Mikrocodeassembler verarbeitet Mikroinstruktionen wie diese

in solchen Bytecode

Die Verwendnung dieses Assemblers hat es stark vereinfacht ein Befehlssatz für die Yuki CPU zu entwickeln und macht es möglich den Befehlssatz auf Wunsch komfortable zu modifizieren. Der Quellcode des Assembler lautet wie folgt.

"""
Title:       Yuki CPU microcode assembler
Author:      R.Lux
Last edited: 14.12.2017

microcode format:
bit 0    bit 14
ddddddssssssaaa
sssss = 6 bit source
ddddd = 6 bit destination
aaa   = 3 bit addressmode
addressmodes:
000 = PC
001 = X
010 = Y
011 = direct
100 = SP
101 = SSP
110 = USP

32 microcode steps : A0 - A4
8 bit instruction : A5 - A12
int the first microcode step, the cpu fetches a new instruction and advances the PC or handles an interrupt so the first microinstruction is always ignored
microcode format example:
<0xFF NOP               open microcode segment for instruction 0xFF called NOP
 .A,MEM                  do a move operation (addressmode=0)
 .B,MEM:1         do a move opeariotn (addressmode follows after dot)
 ,INCX:1                 do a special operation (addressmode follows after dot)
                         empty lines as well as comments(# ...) are ignored
 >            close microcode segment(not really mandatory)
"""


# Memory Array
memory = [0] * 8192
memory_index = 0


sources = { "Z"          : 0,
            "R0"         : 1,
        "R1"         : 2,
        "R2"         : 3,
        "R3"         : 4,
        "R4"         : 5,
        "R5"         : 6,
        "R6"         : 7,
        "R7"         : 8,
        "ALUA"       : 9,
        "ALUB"       : 10,
        "ADD"        : 11,
        "SUB"        : 12,
        "MULL"       : 13,
        "MULH"       : 14,
        "OR"         : 15,
        "AND"        : 16,
        "XOR"        : 17,
        "SHL"        : 18,
        "SHR"        : 19,
        "NOTA"       : 20,
        "NOTB"       : 21,
        "PCL"        : 22,
            "PCM"        : 23,
            "PCH"        : 24,
            "XL"         : 25,
            "XM"         : 26,
            "XH"         : 27,
            "YL"         : 28,
            "YM"         : 29,
            "YH"         : 30,
            "USPL"       : 31,
            "USPM"       : 32,
            "USPH"       : 33,
            "MEM"        : 34,
            "INTMEM"     : 35,
            "POP"        : 36}
           
destinations = {"R0"    : 1,
        "R1"    : 2,
        "R2"    : 3,
                "R3"    : 4,
        "R4"    : 5,
        "R5"    : 6,
        "R6"    : 7,
        "R7"    : 8,
        "ALUA"  : 9,
        "ALUB"  : 10,
        "PCL"   : 11,
        "PCM"   : 12,
        "PCH"   : 13,
        "XL"    : 14,
        "XM"    : 15,
        "XH"    : 16,
        "YL"    : 17,
        "YM"    : 18,
        "YH"    : 19,
        "DL"    : 20,
        "DM"    : 21,
        "DH"    : 22,
        "XCMPL" : 23,
        "XCMPM" : 24,
        "XCMPH" : 25,
        "YCMPL" : 26,
        "YCMPM" : 27,
                "YCMPH" : 28,
                "SSPL"  : 29,
                "SSPM"  : 30,
                "SSPH"  : 31,
                "USPL"  : 32,
                "USPM"  : 33,
                "USPH"  : 34,
                "PCBL"  : 35,
                "PCBM"  : 36,
                "PCBH"  : 37,
                "PCBF"  : 38,
                "PCBB"  : 39,
                "MEM"   : 48,
                "PUSH"  : 49,
                "IR"    : 63}
               
               
specials = {"INCD"      : (44, 0),
            "INCX"      : (37, 0),
        "INCY"      : (39, 0),
            "DECD"      : (45, 0),
        "DECX"      : (38, 0),
        "DECY"      : (40, 0),
        "INCPC"     : (43, 0),
        "INTEN"     : (0, 59),
        "INTDIS"    : (0, 58),
            "INTMOFF"   : (0, 61),
        "SUPOFF"    : (0, 60),
            "NOP"       : (0, 0),
            "END"       : (46, 0),
            "JMP"       : (0, 40),
            "JE"        : (0, 41),
            "JZ"        : (0, 42),
            "JN"        : (0, 43),
            "JC"        : (0, 44),
            "JB"        : (0, 45),
            "JXE"       : (0, 46),
            "JYE"       : (0, 47)}
           
infile = open("microcode.masm")
outfile = open("microcode_content.mif", "w") # Quartus Memory initialisation file as output for now
outfile.write("DEPTH = 8192;\n")
outfile.write("WIDTH = 15;\n")
outfile.write("ADDRESS_RADIX = UNS;\n")
outfile.write("DATA_RADIX = UNS;\n")
outfile.write("CONTENT\nBEGIN\n0 : ")


assembled_instructions = 0
for line in infile.readlines():
    line=line.replace("\n", "")
    if line == "":
        # Ignore empty lines
        continue

    if "#" in line:
        # Ignore comments
        continue
   
    if line[0] == "<":
        # A record starts here
        # Goto start address of record
        instruction = int(line[3:5], 16)
        start_address = instruction * 32 + 1
        memory_index = start_address
        print("Instruction " + str(line.split()[1]) + " (" + line[1:5] + ") gets constructed from 0x%0.3x... " % start_address, end="")
        continue

    if line[0] == ">":
        # The record ends here
        print("to 0x%0.3x" % (memory_index), end="")
        print("(size: " + str(memory_index - start_address) + " bytes)")
        if memory_index - start_address > 32:
            raise Exception("Microfunction to BIG!")
        assembled_instructions += 1


    if line[0] == ".":
        # A move happens here
        line = line.replace(".", "")

        # Default address mode is 0(PC)
        addr_int = 0
        if ":" in line:
            # We have got an address mode defintion
            # save it:
            addr_int = int(line.split(":")[1])
            # remove it
            line = line.split(":")[0]

        src = line.split(",")[0]
        dest = line.split(",")[1]
        src_int = sources[src]
        dest_int = destinations[dest]
           
        microinstruction = addr_int * 4096 + src_int * 64 + dest_int # Contruct arguments to control word
        memory[memory_index] = microinstruction               # Save microinstruction
        memory_index += 1
        continue

    if line[0] == ",":
        # We are in special operation mode now!
        line = line.replace(",", "")

        # Default address mode is 0(PC)
        addr_int = 0
        if ":" in line:
            # We have a special address mode!
            addr_int = addr_int = int(line.split(":")[1])
            # remove it
            line = line.split(":")[0]

        src_int, dest_int = specials[line]
        microinstruction = addr_int * 8192 + src_int * 64 + dest_int # Construct arguments to control word
        memory[memory_index] = microinstruction # Save microinstruction
        memory_index += 1
        continue
       



# Now flush memory into output file

for memorycell in memory:
    outfile.write(str(memorycell) + " ")
outfile.write(";\nEND;")

print("Assembled " + str(assembled_instructions) + " instructions")

# Close the files and leave
outfile.close()
infile.close()