eris2206

Documentation: http://frombelow.net/projects/eris2206/
Clone: git clone https://git.frombelow.net/eris2206.git
Log | Files | Refs | Submodules | README | LICENSE

mc_compiler.py (9852B)


      1 #!/usr/bin/env python3
      2 
      3 # Copyright 2022 Gerd Beuster (gerd@frombelow.net). This is free soft
      4 # under the GNU GPL v3 license or any later version. See COPYING in
      5 # the root directory for details.
      6 
      7 import sys
      8 
      9 pc_set_uncond     = 1 << 0
     10 pc_set_if_zero    = 1 << 1
     11 pc_set_if_nonzero = 1 << 2
     12 pc_inc            = 1 << 3
     13 dp_set            = 1 << 4
     14 dp_get            = 1 << 5
     15 mem_set           = 1 << 6
     16 reg_a_get         = 1 << 7
     17 reg_a_set         = 0b001 << 8
     18 reg_a_inc         = 0b010 << 8
     19 reg_a_dec         = 0b011 << 8
     20 reg_a_rol         = 0b100 << 8
     21 reg_a_ror         = 0b101 << 8
     22 reg_a_inv         = 0b110 << 8
     23 mip_set           = 1 << 11
     24 alu_add           = 0b001 << 12
     25 alu_sub           = 0b010 << 12
     26 # Multiplication and division occpuy too many PLBs
     27 # alu_mul           = 0b011 << 12
     28 # alu_div           = 0b100 << 12
     29 alu_and           = 0b101 << 12
     30 alu_or            = 0b110 << 12
     31 alu_xor           = 0b111 << 12
     32 
     33 # Loading the address bus
     34 #
     35 # In every cycle, the CPU loads the address bus with either
     36 # the value of the program counter or the data pointer.
     37 # Therefore we only need dp_get, a flag indicating if the address bus
     38 # loads the data pointer. If this flag is not set, the address bus
     39 # loads the program counter.
     40 
     41 # Loading the data bus
     42 #
     43 # In every cycle, the CPU loads the data bus with either
     44 # the value from accumulator, the memory, or the alu.
     45 # Accumulator access has priority. If reg_a_get is not set,
     46 # the data bus is loaded from the ALU if alu_... is set and from memory
     47 # otherwise.
     48 
     49 # Summary:
     50 
     51 # - Unless dp_get is set, the address bus is loaded from the PC on every
     52 #   instruction.
     53 # - If neither alu_... nor reg_a_get is set, the data bus is loaded
     54 #   from memory on every instructions
     55 #
     56 # Therefore microcode 0 loads the data bus with the memory location
     57 # given by the PC.
     58 
     59 opcode = [['NOP',
     60            [
     61                # First instruction implicitly loads address bus with PC
     62                # and reads memory at that location. The memory content is loaded on the data bus in the next step,
     63                # and the MIP is set from the data bus.
     64                # The PC is incremented such that the operand of the
     65                # next instruction can be fetched in the next step
     66                0,
     67                pc_inc | mip_set,
     68            ]],
     69 	  ['LDA', 'direct',
     70            [
     71                # We want to load from the memory address pointed to
     72                # by the PC. We read the memory address (i.e. the pointer value) ...
     73                0,
     74                # ... and store it DP.
     75                dp_set,
     76                # Now we transfer this value to the address bus, read this memory
     77                # address ...
     78                dp_get,
     79                # ... and store it in the accumulator. We also increment
     80                # the PC such that we can fetch the next instruction
     81                # and the following step.
     82                dp_get | reg_a_set | pc_inc,
     83                # We are done. Fetch next instruction and increment PC such that
     84                # the next instruction can load its argument.
     85                0,
     86                pc_inc | mip_set,
     87            ]],
     88 	  ['LDA', 'immediate',
     89            [
     90                reg_a_set | pc_inc,
     91                0,
     92                pc_inc | mip_set,
     93            ]],
     94 	  ['LDA', 'indirect',
     95            [
     96                0,
     97                dp_set,
     98                dp_get | dp_set,
     99                dp_get,
    100                dp_get | reg_a_set | pc_inc,
    101                0,
    102                pc_inc | mip_set,
    103            ]],
    104           ['STA', 'direct',
    105            [
    106                0,
    107                dp_set,
    108                dp_get | mem_set | reg_a_get | pc_inc,
    109                0,
    110                pc_inc | mip_set,
    111            ]],
    112           ['STA', 'indirect',
    113            [
    114                0,
    115                dp_set,
    116                dp_get | dp_set,
    117                dp_get | mem_set |reg_a_get | pc_inc,
    118                0,
    119                pc_inc | mip_set,
    120            ]],
    121           ['JMP', 'direct',
    122            [
    123                0,
    124                pc_set_uncond,
    125                0,
    126                pc_inc | mip_set,
    127            ]],
    128           ['JNZ', 'direct',
    129            [
    130                0,
    131                pc_inc | pc_set_if_nonzero,
    132                0,
    133                pc_inc | mip_set,
    134            ]],
    135           ['JZE', 'direct',
    136            [
    137                0,
    138                pc_inc | pc_set_if_zero,
    139                0,
    140                pc_inc | mip_set,
    141            ]],
    142           ['ADD', 'direct',
    143            [
    144                0,
    145                dp_set,
    146                dp_get,
    147                dp_get,
    148                alu_add | pc_inc | reg_a_set,
    149                0,
    150                pc_inc | mip_set,
    151            ]],
    152           ['ADD', 'indirect',
    153            [
    154                0,
    155                dp_set,
    156                dp_get | dp_set,
    157                dp_get,
    158                dp_get,
    159                pc_inc | alu_add | reg_a_set,
    160                0,
    161                pc_inc | mip_set,
    162            ]],
    163           ['ADD', 'immediate',
    164            [
    165                0,
    166                alu_add | pc_inc | reg_a_set,
    167                0,
    168                pc_inc | mip_set,
    169            ]],
    170           ['SUB', 'direct',
    171            [
    172                0,
    173                dp_set,
    174                dp_get,
    175                dp_get,
    176                alu_sub | pc_inc | reg_a_set,
    177                0,
    178                pc_inc | mip_set,
    179            ]],
    180           ['SUB', 'indirect',
    181            [
    182                0,
    183                dp_set,
    184                dp_get | dp_set,
    185                dp_get,
    186                dp_get,
    187                pc_inc | alu_sub | reg_a_set,
    188                0,
    189                pc_inc | mip_set,
    190            ]],
    191           ['SUB', 'immediate',
    192            [
    193                0,
    194                alu_sub | pc_inc | reg_a_set,
    195                0,
    196                pc_inc | mip_set,
    197            ]],
    198           ['AND', 'direct',
    199            [
    200                0,
    201                dp_set,
    202                dp_get,
    203                dp_get,
    204                alu_and | pc_inc | reg_a_set,
    205                0,
    206                pc_inc | mip_set,
    207            ]],
    208           ['AND', 'indirect',
    209            [
    210                0,
    211                dp_set,
    212                dp_get | dp_set,
    213                dp_get,
    214                dp_get,
    215                pc_inc | alu_and | reg_a_set,
    216                0,
    217                pc_inc | mip_set,
    218            ]],
    219           ['AND', 'immediate',
    220            [
    221                0,
    222                alu_and | pc_inc | reg_a_set,
    223                0,
    224                pc_inc | mip_set,
    225            ]],
    226           ['ORA', 'direct',
    227            [
    228                0,
    229                dp_set,
    230                dp_get,
    231                dp_get,
    232                alu_or | pc_inc | reg_a_set,
    233                0,
    234                pc_inc | mip_set,
    235            ]],
    236           ['ORA', 'indirect',
    237            [
    238                0,
    239                dp_set,
    240                dp_get | dp_set,
    241                dp_get,
    242                dp_get,
    243                pc_inc | alu_or | reg_a_set,
    244                0,
    245                pc_inc | mip_set,
    246            ]],
    247           ['ORA', 'immediate',
    248            [
    249                0,
    250                alu_or | pc_inc | reg_a_set,
    251                0,
    252                pc_inc | mip_set,
    253            ]],
    254           ['XOR', 'direct',
    255            [
    256                0,
    257                dp_set,
    258                dp_get,
    259                dp_get,
    260                alu_xor | pc_inc | reg_a_set,
    261                0,
    262                pc_inc | mip_set,
    263            ]],
    264           ['XOR', 'indirect',
    265            [
    266                0,
    267                dp_set,
    268                dp_get | dp_set,
    269                dp_get,
    270                dp_get,
    271                pc_inc | alu_xor | reg_a_set,
    272                0,
    273                pc_inc | mip_set,
    274            ]],
    275           ['XOR', 'immediate',
    276            [
    277                0,
    278                alu_xor | pc_inc | reg_a_set,
    279                0,
    280                pc_inc | mip_set,
    281            ]],
    282           ['INC',
    283            [
    284                reg_a_inc,
    285                pc_inc | mip_set,
    286            ]],
    287           ['DEC',
    288            [
    289                reg_a_dec,
    290                pc_inc | mip_set,
    291            ]],
    292           ['ROL',
    293            [
    294                reg_a_rol,
    295                pc_inc | mip_set,
    296            ]],
    297           ['ROR',
    298            [
    299                reg_a_ror,
    300                pc_inc | mip_set,
    301            ]],
    302           ['INV',
    303            [
    304                reg_a_inv,
    305                pc_inc | mip_set,
    306            ]],
    307 ]
    308 
    309 if len(sys.argv) != 2:
    310     sys.stderr.write("Usage: mc_compiler.py microcode|opcode\n")
    311     sys.exit(-1)
    312 
    313 if sys.argv[1] == 'microcode':
    314     # Since ROM data has a width of 8 bit, we split the microcode into two
    315     # rom files.
    316     with open('microcode_rom_lsb.dat', 'w') as r_lsb:
    317         r_lsb.write('// Microcode - LSB\n')
    318         with open('microcode_rom_msb.dat', 'w') as r_msb:
    319             r_msb.write('// Microcode - MSB\n')
    320             byte_count = 0
    321             for o in opcode:
    322                 r_lsb.write('// {}\n'.format(o[0]))
    323                 r_msb.write('// {}\n'.format(o[0]))
    324                 r_lsb.write("".join(["{:02X} ".format(x & 0xFF) for x in o[-1]]) + "\n")
    325                 r_msb.write("".join(["{:02X} ".format(x >> 8) for x in o[-1]]) + "\n")
    326                 byte_count += len(o[1])
    327             r_lsb.write('// Number of instructions: {}\n'.format(byte_count))
    328             r_msb.write('// Number of instructions: {}\n'.format(byte_count))
    329 
    330 
    331 if sys.argv[1] == 'opcodes':
    332     byte_count = 0
    333     with open('opcodes.pl', 'w') as f:
    334         f.write(':- discontiguous opcode_to_byte/2.\n')
    335         for o in opcode:
    336             if(len(o) == 2):
    337                 # Opcode without addressing mode
    338                 f.write('opcode_to_byte("{}", {}).\n'.format(o[0], byte_count))
    339             else:
    340                 # Opcode with addressing mode
    341                 f.write('opcode_to_byte("{}", {}, {}).\n'.format(o[0], o[1], byte_count))
    342             byte_count += len(o[-1])