From 32db9094a20e1b8090e6842ee6fe659087ad0b10 Mon Sep 17 00:00:00 2001 From: mole99 Date: Sat, 13 Apr 2024 12:40:56 +0200 Subject: [PATCH] Update test and sw --- .gitignore | 2 +- sw/assembler.py | 142 +++++++++++++++++++++++++--------- sw/binary/test1.bit | 2 + sw/binary/test2.bit | 2 + sw/binary/test7.bit | 10 +++ sw/images/test1.png | Bin 114 -> 153 bytes sw/images/test2.png | Bin 139 -> 221 bytes sw/images/test3.png | Bin 103 -> 149 bytes sw/images/test4.png | Bin 184 -> 387 bytes sw/images/test5.png | Bin 100 -> 131 bytes sw/images/test6.png | Bin 104 -> 137 bytes sw/images/test7.png | Bin 0 -> 360 bytes sw/shader/test1.shader | 3 + sw/shader/test2.shader | 3 + sw/shader/test7.shader | 25 ++++++ test/test.py | 172 +++++++++++++++++++++++------------------ 16 files changed, 249 insertions(+), 112 deletions(-) create mode 100644 sw/binary/test7.bit create mode 100644 sw/images/test7.png create mode 100644 sw/shader/test7.shader 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 49ee85537cef5303fa81c0b7c2df4f047efd7471..d351b628101e1d041041fcf38a2c5fa393d9d59f 100644 GIT binary patch literal 153 zcmeAS@N?(olHy`uVBq!ia0vp^4nSFSZ?A6TJ)pqD;5g}| zMi&9_8fcWTdT!ygf@hM;kP;ev%kyCFaOIax_}UjmEXYd@f>qZ Tt@%-Ppj`}}u6{1-oD!Me&8tIjUlpJ4EVx#COiW-ZVV N22WQ%mvv4FO#ld=B^Uqz diff --git a/sw/images/test2.png b/sw/images/test2.png index 2537442795268a81a029bdf8b713b01c4e057d71..380fcbbbb2ae1cf7c4402ab7127c9394ea2a162c 100644 GIT binary patch literal 221 zcmeAS@N?(olHy`uVBq!ia0vp^4nS*uRn2V@&@-4 zfe%=kY@PVHH@u7v;4Ip}ejgdCbh5{1M2ySYwlAc=kYs41ayM`{Rlq(Kb@Y m58qD`TV!Qr!od72nPH9=yVrrbGpRt+89ZJ6T-G@yGywp^?=2?) diff --git a/sw/images/test3.png b/sw/images/test3.png index 8897080db955764df17c9ff4ec77b44634407244..d73b8318ac66c737ff57f9068654b1fd424fd807 100644 GIT binary patch literal 149 zcmeAS@N?(olHy`uVBq!ia0vp^4nSFSZ!d1-JYc}U>?paZ zJnX!HCg0)sg;5{UZ||O){r%?d)wb5Z4%v%d&{`1cu(~0PaV=96>lUsIyaKnrvf4Fk W$n0sqyyy_n9tKZWKbLh*2~7Z6>oYe1 literal 103 zcmeAS@N?(olHy`uVBq!ia0vp^8bB<^!2~2P?myiHr1U&p978JRygh5k%V5BBV1tj; zhEMLM9M-=rPQ4F4du)5As(}O#Tl2vL5cR)$@hicyoc1S8K%ESpu6{1-oD!MNkl570o%jnKSzpjf~6_=E-xEZKz$)bW2BNRCi;2HwN} z`?t3L%_M3*8AD+*xTKKrV zXhH5i>wD`gJWe^@dba!V+b(Af_FKzC*}Rmd&oo55LsZ>6|Z9Y_YGpYL)_Y3WKMspUXO@geCw)nM)`D diff --git a/sw/images/test5.png b/sw/images/test5.png index d640a28190efbf0904d1eafb070f86c68168b9fd..4faa590013eac2d9b9590559a114678294bdaab6 100644 GIT binary patch literal 131 zcmeAS@N?(olHy`uVBq!ia0vp^4nSFSZ!a1$G8hOjFWgsu paV5{R!%W-XvhHHrz_x{W$e$eUeo^F~tO3we22WQ%mvv4FO#ljECz}8O literal 100 zcmeAS@N?(olHy`uVBq!ia0vp^8bB<^!2~2P?myiHq_jO<978JRygkpz$iTpH$lzss zSH_ne@y$!$?iD&-(f3p4v*okmGtXz7H@wf#&aZgEx@mGfP#c4%tDnm{r-UW|n7Se^ diff --git a/sw/images/test6.png b/sw/images/test6.png index bd5d1f2e8c03e3c3fe61e80b7bf35efb03e7822f..1507dc0bc010be031a5fccb646122528c42c25b1 100644 GIT binary patch literal 137 zcmeAS@N?(olHy`uVBq!ia0vp^4nSFSZ_jV!WN;KXvf<(H v_m%s3iWOMT?cII*Ti$-#a}H-ofN$BGcf|kqJ=k#yXf}hVtDnm{r-UW|oCY@5 literal 104 zcmeAS@N?(olHy`uVBq!ia0vp^8bB<^!2~2P?myiHr1U*q978JRygj>6kime5*)aaQ z{HevMEt^_i91LEXJL&I!8CJIDg9!!_JV5F}J#(wQu65|r*SCRM89ZJ6T-G@yGywqC Cks(?D diff --git a/sw/images/test7.png b/sw/images/test7.png new file mode 100644 index 0000000000000000000000000000000000000000..b03305bbb323fb8e071e3d8eb5740efbc321af9c GIT binary patch literal 360 zcmV-u0hj)XP)+^O38o(5KI6+*J*LR80W!w_IU#V z{5-}7_`=`{VL-Ac(C_&JfY0y&B1i&5>tjHoFV|qpTYB^H$B&Z0xcWCBxj_vX7XA2G z@B<|?*rRJE&Rk&R2C$Pb+W z0M&XMyVu*W#;-1~dIE*>1oP