from amaranth import * from amaranth.sim import Simulator, Settle, Delay from enum import Enum, unique from hdl.utils import * from hdl.lib.in_out_buff import InOutBuff # used for timing analysis from hdl.core.alu import AluOpCodes from hdl.core.jump_ctl import JumpOpCodes from hdl.config import MACHINE_CODE_CSV import csv MAX_INSTR = 2**8 # do not change this, this is not configurable CL_NAMES = ['mode'] class Control_LUT(Elaboratable): def __init__(self, csv_file, cl_names, **kargs): # cl_names is a list of control line in order of msb to lsb self.csv_file = csv_file self.cl_names = cl_names self.sim = kargs.get("sim", False) def create_lut(self): self.csv_raw = self._read_csv(self.csv_file) self.csv_parsed = self._parse_csv(self.csv_raw) self.mem_init = self._create_mem_init(self.csv_parsed) self.mem = Memory(width=len(self.cl_names) + 1, depth=MAX_INSTR, init=self.mem_init, simulate=self.sim) # one extra bit for valid opcode # read csv file and return a list of dictionaries def _read_csv(self, csv_file): csv_raw = [] with open(csv_file, 'r') as f: reader = csv.DictReader(f) return list(reader) def _list_to_one_hot(self, lst): tmp = 0 for i in range(len(lst)): tmp |= (lst[i] << i) return tmp def _parse_csv(self, csv_raw): csv_parsed = [] for row in csv_raw: tmp = {} tmp['opcode'] = int(row['opcode']) tmp['data'] = [] for cl in self.cl_names: tmp['data'].append(bool(int(row[cl]))) # needs to be converted to int first because boolof a string is true csv_parsed.append(tmp) return csv_parsed def _create_mem_init(self, csv_parsed): mem_init = [] for i in range(MAX_INSTR): mem_init.append(0) # init to 0, this sets all op codes to invalid for row in csv_parsed: assert(0 <= row['opcode'] < MAX_INSTR), "opcode out of range" assert((mem_init[row['opcode']] & 0x1) != 1), 'duplicate opcode, check the .csv file' for cl in row['data']: mem_init[row['opcode']] = cl mem_init[row['opcode']] = (mem_init[row['opcode']] << 1) | 0x1 # set the valid opcode bit return mem_init class Control(Elaboratable): def __init__(self, **kargs): self.instr_op = Signal(4, reset_less=True) # out opcodes self.alu_op = Signal(e2s(AluOpCodes)) self.jump_ctl_op = Signal(e2s(JumpOpCodes)) # register control out self.wr_en = Signal(1) self.stall = Signal(1) self.int_sig = Signal(1) self.iret = Signal(1) self.call = Signal(1) self.jump = Signal(1) # register control in self.int_en = Signal(1) self.user_mode = Signal(1) ports_in = [self.instr_op, self.alu_op, self.jump_ctl_op, self.wr_en, self.stall, self.int_sig, self.iret, self.call, self.jump] ports_out = [] self.ports = {'in': ports_in, 'out': ports_out} self.sim = kargs.get("sim", False) def elaborate(self, platform=None): m = Module() # dummy sync for simulation only needed if there is no other sequential logic if self.sim == True: dummy = Signal() m.d.sync += dummy.eq(~dummy) ... return m # test addition # def test_hdl(): # dut = Control(sim=True) # def proc(): # yield from step #step clock # yield Settle() #needed if for combinatorial logic # yield dut.something #read value # sim(dut, proc) def test_control_mem_init(): lut = Control_LUT(MACHINE_CODE_CSV, CL_NAMES, sim=True) lut.create_lut() print(lut.mem_init) if __name__ == '__main__': test_control_mem_init() # hdl = InOutBuff(Control()) # cmd(hdl)