aboutsummaryrefslogtreecommitdiffstats
path: root/atk16_utils/ucode.py
blob: 22a2ce2773e22d0db51a451e81705e378e74ed2f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
#!/usr/bin/env python3
# Generate .bin file with ATK16 CPU microcode

# Addressed by OOOO BUUU
# where O = opcode, B = branch flag, U = microsequencer value

import sys

if len(sys.argv) != 2:
  print("usage: ucode.py <outfile.bin>")
  sys.exit(1)

outfile_path = sys.argv[1]

PC_CO   = 1 << 0
PC_IE   = 1 << 1
PC_OE   = 1 << 2
MAR_IE  = 1 << 3
MEM_IE  = 1 << 4
MEM_OE  = 1 << 5
RW_IE   = 1 << 6
R1_OE   = 1 << 7
R2_OE   = 1 << 8
IR_IE   = 1 << 9
IM_M    = 1 << 10
LI_OE   = 1 << 11
ALU_OE  = 1 << 12
FR_IE   = 1 << 13
HALT    = 1 << 14
US_RS   = 1 << 15
ISRA_OE = 1 << 16
IM_DS   = 1 << 17
IM_EN   = 1 << 18
IPC_IE  = 1 << 19
IPC_OE  = 1 << 20
NOP5    = 1 << 21
NOP6    = 1 << 22
NOP7    = 1 << 23

BRANCH_FLAG_STATES_N = 2
UCODE_N: int = 2**3
CONTROL_WORD_SIZE = 3

def not_branch(bs: list[int]) -> list[list[int]]:
  return BRANCH_FLAG_STATES_N * [bs]

def branch(false_branch: list[int], true_branch: list[int]) -> list[list[int]]:
  return [false_branch, true_branch]

fetch = [PC_OE|MAR_IE, MEM_OE|IR_IE|PC_CO]

def nop():
  return not_branch([*fetch, US_RS, 0, 0, 0, 0, 0])

ucode = [
  # ALR 0000 TTTL LLRR RSSS
  not_branch([*fetch, ALU_OE|FR_IE|RW_IE, US_RS, 0, 0, 0, 0]),
  # ALI 0001 TTTL LLII ISSS
  not_branch([*fetch, IM_M|ALU_OE|FR_IE|RW_IE, US_RS, 0, 0, 0, 0]),
  # LDR 0010 TTTR RRXX XXXX
  not_branch([*fetch, R1_OE|MAR_IE, MEM_OE|RW_IE, US_RS, 0, 0, 0]),
  # STR 0011 XXXL LLRR RXXX
  not_branch([*fetch, R1_OE|MAR_IE, R2_OE|MEM_IE, US_RS, 0, 0, 0]),
  # LDI 0100 TTTI IIII IIII
  not_branch([*fetch, LI_OE|RW_IE, US_RS, 0, 0, 0, 0]),
  # JPR 0101 XXXR RRXX XXXX
  not_branch([*fetch, R1_OE|PC_IE, US_RS, 0, 0, 0, 0]),
  # JPI 0110 XXXI IIII IIII
  not_branch([*fetch, IM_M|LI_OE|PC_IE, US_RS, 0, 0, 0, 0]),
  # BRR  0111 XFFR RRXX XXXX
  branch([*fetch, US_RS, 0, 0, 0, 0, 0],
         [*fetch, R1_OE|PC_IE, US_RS, 0, 0, 0, 0]),
  # BRI 1000 XFFI IIII IIII
  branch([*fetch, US_RS, 0, 0, 0, 0, 0],
         [*fetch, IM_M|LI_OE|PC_IE, US_RS, 0, 0, 0, 0]),
  # LPC 1001 TTTX XXXX XXXX
  not_branch([*fetch, PC_OE|RW_IE, US_RS, 0, 0, 0, 0]),
  # NOP 1010 XXXX XXXX XXXX
  nop(),
  # NOP 1011 XXXX XXXX XXXX
  nop(),
  # ISRP0 1100 XXXX XXXX XXXX
  not_branch([IM_EN|PC_OE|IPC_IE, ISRA_OE|MAR_IE, MEM_OE|PC_IE, US_RS, 0, 0, 0, 0]),
  # ISRP1 1101 XXXX XXXX XXXX
  not_branch([IM_EN|PC_OE|IPC_IE, ISRA_OE|MAR_IE, MEM_OE|PC_IE, US_RS, 0, 0, 0, 0]),
  # RTI 1110 XXXX XXXX XXXX
  not_branch([*fetch, IM_DS|IPC_OE|PC_IE, US_RS, 0, 0, 0, 0]),
  # HLT 1111 XXXX XXXX XXXX
  not_branch([*fetch, HALT, 0, 0, 0, 0, 0]),
]

INST_N = len(ucode)
TOTAL_BYTEARRAY_SIZE = INST_N * BRANCH_FLAG_STATES_N * UCODE_N * CONTROL_WORD_SIZE

res_b = bytearray(TOTAL_BYTEARRAY_SIZE)

for i in range(INST_N):
  for j in range(BRANCH_FLAG_STATES_N):
    for k in range(UCODE_N):
      for l in range(CONTROL_WORD_SIZE):
        idx = l + \
            k * CONTROL_WORD_SIZE + \
            j * CONTROL_WORD_SIZE * UCODE_N + \
            i * CONTROL_WORD_SIZE * UCODE_N * BRANCH_FLAG_STATES_N
        cword = ucode[i][j][k]
        assert len(ucode[i][j]) == 8
        cbyte = (cword >> (8 * (CONTROL_WORD_SIZE - l - 1))) & 0xff
        print(f"inst: {i:>04b}, idx: {idx:>04x}, cbyte: {cbyte:>08b}")
        res_b[idx] = cbyte

with open(outfile_path, "wb") as f:
  f.write(res_b)