diff --git a/.gitignore b/.gitignore index d8bf585..0ae23f7 100644 --- a/.gitignore +++ b/.gitignore @@ -11,4 +11,4 @@ test/sim_build test/__pycache__/ test/results.xml test/gate_level_netlist.v -frame.png +test/*.png diff --git a/sw/assembler.py b/sw/assembler.py index effe255..e322d18 100644 --- a/sw/assembler.py +++ b/sw/assembler.py @@ -5,42 +5,76 @@ instructions = { - 'SETRGB' : {'format': 'single_operand', 'opcode': '00_0000'}, - 'SETR' : {'format': 'single_operand', 'opcode': '00_0001'}, - 'SETG' : {'format': 'single_operand', 'opcode': '00_0010'}, - 'SETB' : {'format': 'single_operand', 'opcode': '00_0011'}, + 'SETRGB' : {'format': 'single_operand', 'opcode': '00_0000', 'short': 'RGB <= RA', 'description': 'Set the output color to the value of the specified register.', 'category': 'Output'}, + 'SETR' : {'format': 'single_operand', 'opcode': '00_0001', 'short': 'R <= RA[1:0]', 'description': 'Set the red channel of the output color to the lower two bits of the specified register.', 'category': 'Output'}, + 'SETG' : {'format': 'single_operand', 'opcode': '00_0010', 'short': 'G <= RA[1:0]', 'description': 'Set the green channel of the output color to the lower two bits of the specified register.', 'category': 'Output'}, + 'SETB' : {'format': 'single_operand', 'opcode': '00_0011', 'short': 'B <= RA[1:0]', 'description': 'Set the blue channel of the output color to the lower two bits of the specified register.', 'category': 'Output'}, - 'GETX' : {'format': 'single_operand', 'opcode': '00_0100'}, - 'GETY' : {'format': 'single_operand', 'opcode': '00_0101'}, - 'GETTIME' : {'format': 'single_operand', 'opcode': '00_0110'}, - 'GETUSER' : {'format': 'single_operand', 'opcode': '00_0111'}, + 'GETX' : {'format': 'single_operand', 'opcode': '00_0100', 'short': 'RA <= X', 'description': 'Set the specified register to the x position of the current pixel.', 'category': 'Input'}, + 'GETY' : {'format': 'single_operand', 'opcode': '00_0101', 'short': 'RA <= Y', 'description': 'Set the specified register to the y position of the current pixel.', 'category': 'Input'}, + 'GETTIME' : {'format': 'single_operand', 'opcode': '00_0110', 'short': 'RA <= TIME', 'description': 'Set the specified register to the current time value, increases with each frame.', 'category': 'Input'}, + 'GETUSER' : {'format': 'single_operand', 'opcode': '00_0111', 'short': 'RA <= USER', 'description': 'Set the specified register to the user value, can be set via the SPI interface.', 'category': 'Input'}, - 'IFEQ' : {'format': 'single_operand', 'opcode': '00_1000'}, - 'IFNE' : {'format': 'single_operand', 'opcode': '00_1001'}, - 'IFGE' : {'format': 'single_operand', 'opcode': '00_1010'}, - 'IFLT' : {'format': 'single_operand', 'opcode': '00_1011'}, + 'IFEQ' : {'format': 'single_operand', 'opcode': '00_1000', 'short': 'TAKE <= RA == REG0', 'description': 'Execute the next instruction if RA equals REG0.', 'category': 'Branches'}, + 'IFNE' : {'format': 'single_operand', 'opcode': '00_1001', 'short': 'TAKE <= RA != REG0', 'description': 'Execute the next instruction if RA does not equal REG0.', 'category': 'Branches'}, + 'IFGE' : {'format': 'single_operand', 'opcode': '00_1010', 'short': 'TAKE <= RA >= REG0', 'description': 'Execute the next instruction if RA is greater then or equal REG0.', 'category': 'Branches'}, + 'IFLT' : {'format': 'single_operand', 'opcode': '00_1011', 'short': 'TAKE <= RA < REG0', 'description': 'Execute the next instruction if RA is less than REG0.', 'category': 'Branches'}, - 'TODO0' : {'format': 'single_operand', 'opcode': '00_1100'}, - 'TODO1' : {'format': 'single_operand', 'opcode': '00_1101'}, - 'TODO2' : {'format': 'single_operand', 'opcode': '00_1110'}, - 'SINE' : {'format': 'single_operand', 'opcode': '00_1111'}, + 'DOUBLE' : {'format': 'single_operand', 'opcode': '00_1100', 'short': 'RA <= RA * 2', 'description': 'Double the value of RA.', 'category': 'Arithmetic'}, + 'HALF' : {'format': 'single_operand', 'opcode': '00_1101', 'short': 'RA <= RA / 2', 'description': 'Half the value of RA.', 'category': 'Arithmetic'}, + 'CLEAR' : {'format': 'single_operand', 'opcode': '00_1110', 'short': 'RA <= 0', 'description': 'Clear RA by writing 0.', 'category': 'Load'}, + 'SINE' : {'format': 'single_operand', 'opcode': '00_1111', 'short': 'RA <= SINE[REG0[5:2]] TODO', 'description': 'Get the sine value for REG0 and write into RA.', 'category': 'Special'}, - # Logical operations - 'AND' : {'format': 'dual_operand', 'opcode': '01_00'}, - 'OR' : {'format': 'dual_operand', 'opcode': '01_01'}, - 'NOT' : {'format': 'dual_operand', 'opcode': '01_10'}, - 'XOR' : {'format': 'dual_operand', 'opcode': '01_11'}, + # Boolean operations + 'AND' : {'format': 'dual_operand', 'opcode': '01_00', 'short': 'RA <= RA & RB', 'description': 'Boolean AND of RA and RB, result written into RA.', 'category': 'Boolean'}, + 'OR' : {'format': 'dual_operand', 'opcode': '01_01', 'short': 'RA <= RA | RB', 'description': 'Boolean OR of RA and RB, result written into RA.', 'category': 'Boolean'}, + 'NOT' : {'format': 'dual_operand', 'opcode': '01_10', 'short': 'RA <= ~RB', 'description': 'Boolean NOT of RB, result written into RA.', 'category': 'Boolean'}, + 'XOR' : {'format': 'dual_operand', 'opcode': '01_11', 'short': 'RA <= RA ^ RB', 'description': 'Boolean XOR of RA and RB, result written into RA.', 'category': 'Boolean'}, # Various - 'MOV' : {'format': 'dual_operand', 'opcode': '10_00'}, - 'ADD' : {'format': 'dual_operand', 'opcode': '10_01'}, - 'SHIFTL' : {'format': 'dual_operand', 'opcode': '10_10'}, - 'SHIFTR' : {'format': 'dual_operand', 'opcode': '10_11'}, - + 'MOV' : {'format': 'dual_operand', 'opcode': '10_00', 'short': 'RA <= RB', 'description': 'Move value of RB into RA.', 'category': 'Move'}, + 'ADD' : {'format': 'dual_operand', 'opcode': '10_01', 'short': 'RA <= RA + RB', 'description': 'Add RA and RB, result written into RA.', 'category': 'Arithmetic'}, + 'SHIFTL' : {'format': 'dual_operand', 'opcode': '10_10', 'short': 'RA <= RA << RB', 'description': 'Shift RA with RB to the left, result written into RA.', 'category': 'Shift'}, + 'SHIFTR' : {'format': 'dual_operand', 'opcode': '10_11', 'short': 'RA <= RA >> RB', 'description': 'Shift RA with RB to the right, result written into RA.', 'category': 'Shift'}, + # Load immediate - 'LDI' : {'format': 'immediate', 'opcode': '11'} + 'LDI' : {'format': 'immediate', 'opcode': '11', 'short': 'RA <= IMMEDIATE', 'description': 'Load an immediate value into RA.', 'category': 'Load'}, + + # No operation + 'NOP' : {'format': 'pseudo', 'opcode': '01_00_00_00', 'short': 'R0 <= R0 & R0', 'description': 'No operation.', 'category': 'Pseudo'} } + +def get_syntax(fmt): + + if fmt == 'immediate': + return 'IMMEDIATE' + elif fmt == 'single_operand': + return 'RA' + elif fmt == 'dual_operand': + return 'RA RB' + else: + return 'UNKNOWN' + +def summary(): + categories = {} + + for name, instruction in instructions.items(): + if not instruction['category'] in categories: + categories[instruction['category']] = {} + + categories[instruction['category']][name] = instruction + + for name, category in categories.items(): + print(f'### {name}') + + print(f'|Instruction|Operation|Description|') + print(f'|-----------|---------|-----------|') + + for name, instruction in category.items(): + + print(f'|{name} {get_syntax(instruction["format"])}|{instruction["short"]}|{instruction["description"]}|') + def get_register(string): if string[0] != 'R': print('Register operand must start with "R"') @@ -67,13 +101,16 @@ def assemble(program, verbose=False): if token[0] in instructions: instr = instructions[token[0]] - if instr['format'] == 'immediate': + if instr['format'] == 'pseudo': + assembled += f'{instr["opcode"]} // {line}\n' + + elif instr['format'] == 'immediate': if (len(token) != 2): print(f'Instruction {token[0]} expects one immediate') imm = int(token[1]) assembled += f'{instr["opcode"]}_{imm:06b} // {line}\n' - if instr['format'] == 'dual_operand': + elif instr['format'] == 'dual_operand': if (len(token) != 3): print(f'Instruction {token[0]} expects two operand') @@ -82,13 +119,16 @@ def assemble(program, verbose=False): assembled += f'{instr["opcode"]}_{op1:02b}_{op0:02b} // {line}\n' - if instr['format'] == 'single_operand': + elif instr['format'] == 'single_operand': if (len(token) != 2): print(f'Instruction {token[0]} expects one operand') op0 = get_register(token[1]) assembled += f'{instr["opcode"]}_{op0:02b} // {line}\n' + + else: + print(f'Instruction format unknown: {instr["format"]}') else: print(f'Unknown instruction: {token[0]}') sys.exit() @@ -194,11 +234,21 @@ def simulate(program, x_pos=0, y_pos=0, cur_time=0, user=0, verbose=False): if token[0] == 'IFLT': skip = not (register[op0] < register[0]) + if token[0] == 'DOUBLE': + register[op0] = register[op0] << 1 & 0x3F + if token[0] == 'HALF': + register[op0] = register[op0] >> 1 & 0x3F + if token[0] == 'CLEAR': + register[op0] = 0 + if token[0] == 'SINE': + if register[0] & (1<<4): + register[op0] = sine_lut[15 - (register[0] & 0xF)] + else: + register[op0] = sine_lut[register[0] & 0xF] if verbose: print(f'register[0] {register[0]}') - print(f'sine_lut[register[0] >> 2] {sine_lut[register[0] >> 2]}') - register[op0] = sine_lut[register[0] >> 2] + if verbose: print(f'Current state:') @@ -211,14 +261,19 @@ def simulate(program, x_pos=0, y_pos=0, cur_time=0, user=0, verbose=False): return rgb -if __name__ == "__main__": +def main(): parser = argparse.ArgumentParser() parser.add_argument('-i', '--input', help='.shader file to assemble', type=str, required=False) parser.add_argument('-o', '--output', help='output name of the result', type=str, required=False, default='shader.bit') parser.add_argument('--image', help='simulate the shader and save an image of the result', type=str, required=False) parser.add_argument('-v', '--verbose', help='verbose output', action='store_true') + parser.add_argument('-s', '--summary', help='summary about all instructions', action='store_true') args = parser.parse_args() + if args.summary: + summary() + return + if not args.input: shader = """ # Example Shader @@ -244,8 +299,8 @@ def simulate(program, x_pos=0, y_pos=0, cur_time=0, user=0, verbose=False): shader = f.read() if args.image: - WIDTH = 40 - HEIGHT = 30 + WIDTH = 640//10 + HEIGHT = 480//10 from PIL import Image @@ -260,7 +315,19 @@ def simulate(program, x_pos=0, y_pos=0, cur_time=0, user=0, verbose=False): #print(rgb) pass - pixels[x_pos,y_pos] = (rgb[2]<<6, rgb[1]<<6, rgb[0]<<6) + red = (rgb[2]&0x3)<<6 + if rgb[2] & 0x1: + red |= 63 + + green = (rgb[1]&0x3)<<6 + if rgb[1] & 0x1: + green |= 63 + + blue = (rgb[0]&0x3)<<6 + if rgb[0] & 0x1: + blue |= 63 + + pixels[x_pos,y_pos] = (red, green, blue) #img.show() img.save(args.image) @@ -272,3 +339,6 @@ def simulate(program, x_pos=0, y_pos=0, cur_time=0, user=0, verbose=False): with open(args.output, 'w') as f: f.write(assembled) + +if __name__ == "__main__": + main() diff --git a/sw/binary/test1.bit b/sw/binary/test1.bit index 6a38741..dcc2e38 100644 --- a/sw/binary/test1.bit +++ b/sw/binary/test1.bit @@ -6,3 +6,5 @@ 00_0000_01 // SETRGB R1 00_1000_10 // IFEQ R2 00_0000_10 // SETRGB R2 +01_00_00_00 // NOP +01_00_00_00 // NOP diff --git a/sw/binary/test2.bit b/sw/binary/test2.bit index 281e2b4..badf176 100644 --- a/sw/binary/test2.bit +++ b/sw/binary/test2.bit @@ -6,3 +6,5 @@ 00_0010_01 // SETG R1 01_11_00_00 // XOR R0 R0 01_11_00_00 // XOR R0 R0 +01_00_00_00 // NOP +01_00_00_00 // NOP diff --git a/sw/binary/test7.bit b/sw/binary/test7.bit new file mode 100644 index 0000000..bbe6dc3 --- /dev/null +++ b/sw/binary/test7.bit @@ -0,0 +1,10 @@ +11_111111 // LDI 63 +10_00_00_11 // MOV R3 R0 +00_0100_00 // GETX R0 +00_0000_00 // SETRGB R0 +00_1111_00 // SINE R0 +00_1101_00 // HALF R0 +00_0101_01 // GETY R1 +00_1010_01 // IFGE R1 +00_0000_11 // SETRGB R3 +01_00_00_00 // NOP diff --git a/sw/images/test1.png b/sw/images/test1.png index 49ee855..d351b62 100644 Binary files a/sw/images/test1.png and b/sw/images/test1.png differ diff --git a/sw/images/test2.png b/sw/images/test2.png index 2537442..380fcbb 100644 Binary files a/sw/images/test2.png and b/sw/images/test2.png differ diff --git a/sw/images/test3.png b/sw/images/test3.png index 8897080..d73b831 100644 Binary files a/sw/images/test3.png and b/sw/images/test3.png differ diff --git a/sw/images/test4.png b/sw/images/test4.png index 8785561..91f4c75 100644 Binary files a/sw/images/test4.png and b/sw/images/test4.png differ diff --git a/sw/images/test5.png b/sw/images/test5.png index d640a28..4faa590 100644 Binary files a/sw/images/test5.png and b/sw/images/test5.png differ diff --git a/sw/images/test6.png b/sw/images/test6.png index bd5d1f2..1507dc0 100644 Binary files a/sw/images/test6.png and b/sw/images/test6.png differ diff --git a/sw/images/test7.png b/sw/images/test7.png new file mode 100644 index 0000000..b03305b Binary files /dev/null and b/sw/images/test7.png differ diff --git a/sw/shader/test1.shader b/sw/shader/test1.shader index 4a2a653..18faa95 100644 --- a/sw/shader/test1.shader +++ b/sw/shader/test1.shader @@ -14,3 +14,6 @@ SETRGB R1 IFEQ R2 SETRGB R2 + +NOP +NOP diff --git a/sw/shader/test2.shader b/sw/shader/test2.shader index 4d6406c..863aeaf 100644 --- a/sw/shader/test2.shader +++ b/sw/shader/test2.shader @@ -8,3 +8,6 @@ SETG R1 XOR R0 R0 XOR R0 R0 + +NOP +NOP diff --git a/sw/shader/test7.shader b/sw/shader/test7.shader new file mode 100644 index 0000000..ba31f7e --- /dev/null +++ b/sw/shader/test7.shader @@ -0,0 +1,25 @@ +# Sine + +# Load color white +LDI 63 +MOV R3 R0 + +# Get sine value depending on x +GETX R0 + +# Set color to x +SETRGB R0 + +# Get sine value and half it +SINE R0 +HALF R0 + +# Get y +GETY R1 + +# If sine value is greater than y +# set color to white +IFGE R1 +SETRGB R3 + +NOP diff --git a/test/test.py b/test/test.py index 0a22779..73a243b 100644 --- a/test/test.py +++ b/test/test.py @@ -8,11 +8,12 @@ from cocotb.clock import Clock from cocotb.triggers import ClockCycles from cocotb.triggers import Timer, RisingEdge, FallingEdge +from cocotb.regression import TestFactory from cocotbext.spi import SpiBus, SpiConfig, SpiMaster # Tiny Shader Settings -NUM_INSTR = 12 +NUM_INSTR = 10 # VGA Parameters WIDTH = 640 @@ -82,15 +83,9 @@ async def draw_frame(dut): else: screen_x += 1 -# Send cmd and payload over SPI -async def spi_send_cmd(dut, spi_master, cmd, data, burst=False): - print(f'CMD: {cmd} DATA: {data}') - await spi_master.write(cmd) - await spi_master.write(data, burst=burst) - -@cocotb.test() +#@cocotb.test() async def test_vga_default(dut): - dut._log.info("Starting test_vga") + """Draw one frame with the default shader""" # Start the clock c = Clock(dut.clk, 10, 'ns') @@ -110,16 +105,83 @@ async def test_vga_default(dut): # Start thread to draw frame taks_draw_frame = await cocotb.start(draw_frame(dut)) - # Set the input values, wait one clock cycle, and check the output - dut._log.info("Test") - image = await taks_draw_frame.join() image.save(f"default.png") await ClockCycles(dut.clk, 10) +def load_shader(shader_name): + """Load a shader from a binary text file""" + shader = [] + + with open(f'../sw/binary/{shader_name}.bit') as f: + for line in f.readlines(): + line = line.replace('_', '') + if '//' in line: + line = line.split('//')[0] + if line: + shader.append(int(line, 2)) + + return shader + +# TestFactory +async def test_vga_load(dut, shader_name='test7'): + """Load a shader and draw one frame""" + + # Start the clock + c = Clock(dut.clk, 10, 'ns') + await cocotb.start(c.start()) + + # SPI + spi_bus = SpiBus.from_prefix(dut, "spi") + + spi_config = SpiConfig( + word_width = 8, + sclk_freq = 2e6, + cpol = False, + cpha = True, + msb_first = True, + frame_spacing_ns = 500 + ) + + spi_master = SpiMaster(spi_bus, spi_config) + + # Assign default values + dut.ena.value = 1 + dut.mode.value = 0 # cmd mode + + # Reset + await reset_dut(dut.rst_n, 50) + dut._log.info("Reset done") + + # Set to data mode + dut.mode.value = 1 # data mode + + # Get shader + shader = load_shader(shader_name) + assert(len(shader) == NUM_INSTR) + + # Send new shader instructions + await spi_master.write(shader, burst=True) + + await FallingEdge(dut.vsync) + await FallingEdge(dut.hsync) + + # Start thread to draw frame + taks_draw_frame = await cocotb.start(draw_frame(dut)) + + image = await taks_draw_frame.join() + image.save(f"{shader_name}.png") + + await ClockCycles(dut.clk, 10) + +tf = TestFactory(test_function=test_vga_load) +tf.add_option(name='shader_name', optionlist=['test1', 'test2', 'test7']) +tf.generate_tests() + @cocotb.test(skip=os.environ.get('GL_TEST', None) != None) async def test_spi_regs(dut): + """Access the user register""" # Start the clock c = Clock(dut.clk, 10, 'ns') @@ -146,35 +208,26 @@ async def test_spi_regs(dut): await reset_dut(dut.rst_n, 50) dut._log.info("Reset done") - assert(dut.tt_um_tiny_shader_mole99_inst.tiny_shader_top_inst.reg0.value == 0x00) - assert(dut.tt_um_tiny_shader_mole99_inst.tiny_shader_top_inst.reg1.value == 0x00) - assert(dut.tt_um_tiny_shader_mole99_inst.tiny_shader_top_inst.reg2.value == 0x00) - assert(dut.tt_um_tiny_shader_mole99_inst.tiny_shader_top_inst.reg3.value == 0x00) + assert(dut.tt_um_tiny_shader_mole99_inst.tiny_shader_top_inst.user.value == 42) - # Set reg0 - await spi_send_cmd(dut, spi_master, [0x0], [0x03]) - assert(dut.tt_um_tiny_shader_mole99_inst.tiny_shader_top_inst.reg0.value == 0x03) + # Set user register + await spi_master.write([0x03]) + assert(dut.tt_um_tiny_shader_mole99_inst.tiny_shader_top_inst.user.value == 0x03) - # Set reg1 - await spi_send_cmd(dut, spi_master, [0x1], [0x70]) - assert(dut.tt_um_tiny_shader_mole99_inst.tiny_shader_top_inst.reg1.value == 0x70) + await spi_master.write([0x14]) + assert(dut.tt_um_tiny_shader_mole99_inst.tiny_shader_top_inst.user.value == 0x14) - # Set reg2 - await spi_send_cmd(dut, spi_master, [0x2], [0xEA]) - assert(dut.tt_um_tiny_shader_mole99_inst.tiny_shader_top_inst.reg2.value == 0xEA) + await spi_master.write([0xFF]) + assert(dut.tt_um_tiny_shader_mole99_inst.tiny_shader_top_inst.user.value == 0x3F) - # Set reg3 - await spi_send_cmd(dut, spi_master, [0x3], [0xF3]) - assert(dut.tt_um_tiny_shader_mole99_inst.tiny_shader_top_inst.reg3.value == 0xF3) - - # Set reg0 - await spi_send_cmd(dut, spi_master, [0x0], [0x42]) - assert(dut.tt_um_tiny_shader_mole99_inst.tiny_shader_top_inst.reg0.value == 0x42) + await spi_master.write([0x00]) + assert(dut.tt_um_tiny_shader_mole99_inst.tiny_shader_top_inst.user.value == 0x00) await ClockCycles(dut.clk, 10) @cocotb.test(skip=os.environ.get('GL_TEST', None) != None) async def test_spi_shader(dut): + """Write random data into the shader memory""" # Start the clock c = Clock(dut.clk, 10, 'ns') @@ -212,7 +265,8 @@ async def test_spi_shader(dut): await ClockCycles(dut.clk, 10) @cocotb.test(skip=os.environ.get('GL_TEST', None) != None) -async def test_spi_regs_shader_regs_random(dut): +async def test_spi_random(dut): + """Write random data into register and shader and read back""" # Start the clock c = Clock(dut.clk, 10, 'ns') @@ -239,35 +293,17 @@ async def test_spi_regs_shader_regs_random(dut): await reset_dut(dut.rst_n, 50) dut._log.info("Reset done") - assert(dut.tt_um_tiny_shader_mole99_inst.tiny_shader_top_inst.reg0.value == 0x00) - assert(dut.tt_um_tiny_shader_mole99_inst.tiny_shader_top_inst.reg1.value == 0x00) - assert(dut.tt_um_tiny_shader_mole99_inst.tiny_shader_top_inst.reg2.value == 0x00) - assert(dut.tt_um_tiny_shader_mole99_inst.tiny_shader_top_inst.reg3.value == 0x00) + assert(dut.tt_um_tiny_shader_mole99_inst.tiny_shader_top_inst.user.value == 42) # Set reg0 data = random.randint(0, 255) - await spi_send_cmd(dut, spi_master, [0x0], [data]) - assert(dut.tt_um_tiny_shader_mole99_inst.tiny_shader_top_inst.reg0.value == data) - - # Set reg1 - data = random.randint(0, 255) - await spi_send_cmd(dut, spi_master, [0x1], [data]) - assert(dut.tt_um_tiny_shader_mole99_inst.tiny_shader_top_inst.reg1.value == data) - - # Set reg2 - data = random.randint(0, 255) - await spi_send_cmd(dut, spi_master, [0x2], [data]) - assert(dut.tt_um_tiny_shader_mole99_inst.tiny_shader_top_inst.reg2.value == data) - - # Set reg3 - data = random.randint(0, 255) - await spi_send_cmd(dut, spi_master, [0x3], [data]) - assert(dut.tt_um_tiny_shader_mole99_inst.tiny_shader_top_inst.reg3.value == data) + await spi_master.write([data]) + assert(dut.tt_um_tiny_shader_mole99_inst.tiny_shader_top_inst.user.value == data & 0x3F) # Set reg0 data = random.randint(0, 255) - await spi_send_cmd(dut, spi_master, [0x0], [data]) - assert(dut.tt_um_tiny_shader_mole99_inst.tiny_shader_top_inst.reg0.value == data) + await spi_master.write([data]) + assert(dut.tt_um_tiny_shader_mole99_inst.tiny_shader_top_inst.user.value == data & 0x3F) dut.mode.value = 1 # data mode @@ -285,25 +321,11 @@ async def test_spi_regs_shader_regs_random(dut): # Set reg0 data = random.randint(0, 255) - await spi_send_cmd(dut, spi_master, [0x0], [data]) - assert(dut.tt_um_tiny_shader_mole99_inst.tiny_shader_top_inst.reg0.value == data) - - # Set reg1 - data = random.randint(0, 255) - await spi_send_cmd(dut, spi_master, [0x1], [data]) - assert(dut.tt_um_tiny_shader_mole99_inst.tiny_shader_top_inst.reg1.value == data) - - # Set reg2 - data = random.randint(0, 255) - await spi_send_cmd(dut, spi_master, [0x2], [data]) - assert(dut.tt_um_tiny_shader_mole99_inst.tiny_shader_top_inst.reg2.value == data) - - # Set reg3 - data = random.randint(0, 255) - await spi_send_cmd(dut, spi_master, [0x3], [data]) - assert(dut.tt_um_tiny_shader_mole99_inst.tiny_shader_top_inst.reg3.value == data) + await spi_master.write([data]) + assert(dut.tt_um_tiny_shader_mole99_inst.tiny_shader_top_inst.user.value == data & 0x3F) # Set reg0 data = random.randint(0, 255) - await spi_send_cmd(dut, spi_master, [0x0], [data]) - assert(dut.tt_um_tiny_shader_mole99_inst.tiny_shader_top_inst.reg0.value == data) + await spi_master.write([data]) + assert(dut.tt_um_tiny_shader_mole99_inst.tiny_shader_top_inst.user.value == data & 0x3F) +