Mercurial > repos > blastem
comparison cpu_dsl.py @ 2577:5f725429d08f
WIP changes to new CPU core for rotate instructions and to get interrupts more functional
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Fri, 07 Feb 2025 08:57:24 -0800 |
parents | 595719fe69f2 |
children | 9b01541cbd60 |
comparison
equal
deleted
inserted
replaced
2576:c9bfed9156dc | 2577:5f725429d08f |
---|---|
480 elif prog.dispatch == 'goto': | 480 elif prog.dispatch == 'goto': |
481 return '\n\tgoto *impl_{tbl}[{op}];'.format(tbl = table, op = params[0]) | 481 return '\n\tgoto *impl_{tbl}[{op}];'.format(tbl = table, op = params[0]) |
482 else: | 482 else: |
483 raise Exception('Unsupported dispatch type ' + prog.dispatch) | 483 raise Exception('Unsupported dispatch type ' + prog.dispatch) |
484 | 484 |
485 def _addExplicitFlagSet(prog, output, flag, flagval): | |
486 location = prog.flags.getStorage(flag) | |
487 if type(location) is tuple: | |
488 reg,bit = location | |
489 reg = prog.resolveReg(reg, None, {}) | |
490 value = str(1 << bit) | |
491 if flagval: | |
492 operator = '|=' | |
493 else: | |
494 operator = '&=' | |
495 value = '~' + value | |
496 output.append('\n\t{reg} {op} {val};'.format(reg=reg, op=operator, val=value)) | |
497 else: | |
498 reg = prog.resolveReg(location, None, {}) | |
499 output.append('\n\t{reg} = {val};'.format(reg=reg, val=flagval)) | |
500 | |
485 def _updateFlagsCImpl(prog, params, rawParams): | 501 def _updateFlagsCImpl(prog, params, rawParams): |
486 autoUpdate, explicit = prog.flags.parseFlagUpdate(params[0]) | 502 autoUpdate, explicit = prog.flags.parseFlagUpdate(params[0]) |
487 output = [] | 503 output = [] |
488 parity = None | 504 parity = None |
489 directFlags = {} | 505 directFlags = {} |
495 else: | 511 else: |
496 lastDst = prog.resolveParam(prog.lastDst, prog.currentScope, {}) | 512 lastDst = prog.resolveParam(prog.lastDst, prog.currentScope, {}) |
497 storage = prog.flags.getStorage(flag) | 513 storage = prog.flags.getStorage(flag) |
498 if calc == 'bit' or calc == 'sign' or calc == 'carry' or calc == 'half' or calc == 'overflow': | 514 if calc == 'bit' or calc == 'sign' or calc == 'carry' or calc == 'half' or calc == 'overflow': |
499 myRes = lastDst | 515 myRes = lastDst |
516 after = '' | |
500 if calc == 'sign': | 517 if calc == 'sign': |
501 resultBit = prog.getLastSize() - 1 | 518 resultBit = prog.getLastSize() - 1 |
502 elif calc == 'carry': | 519 elif calc == 'carry': |
503 if prog.lastOp.op in ('asr', 'lsr'): | 520 if prog.lastOp.op in ('asr', 'lsr', 'rrc'): |
504 if type(prog.lastB) is int: | 521 if type(prog.lastB) is int: |
505 resultBit = prog.lastB - 1 | 522 if prog.lastB == 0: |
523 explicit[flag] = 0 | |
524 continue | |
525 else: | |
526 resultBit = prog.lastB - 1 | |
506 else: | 527 else: |
528 output.append(f'\n\tif (!{prog.lastB}) {{') | |
529 _addExplicitFlagSet(prog, output, flag, 0) | |
530 output.append('\n\t} else {') | |
531 after = '\n\t}' | |
507 resultBit = f'({prog.lastB} - 1)' | 532 resultBit = f'({prog.lastB} - 1)' |
508 myRes = prog.lastA | 533 myRes = prog.lastA |
534 elif prog.lastOp.op == 'rlc': | |
535 if type(prog.lastB) is int: | |
536 if prog.lastB == 0: | |
537 explicit[flag] = 0 | |
538 continue | |
539 else: | |
540 resultBit = prog.getLastSize() - prog.lastB | |
541 else: | |
542 output.append(f'\n\tif (!{prog.lastB}) {{') | |
543 _addExplicitFlagSet(prog, output, flag, 0) | |
544 output.append('\n\t} else {') | |
545 after = '\n\t}' | |
546 resultBit = f'({prog.getLastSize()} - {prog.lastB})' | |
547 myRes = prog.lastA | |
548 elif prog.lastOp.op == 'rol': | |
549 if type(prog.lastB) is int: | |
550 if prog.lastB == 0: | |
551 explicit[flag] = 0 | |
552 continue | |
553 else: | |
554 output.append(f'\n\tif (!{prog.lastB}) {{') | |
555 _addExplicitFlagSet(prog, output, flag, 0) | |
556 output.append('\n\t} else {') | |
557 after = '\n\t}' | |
558 resultBit = 0 | |
559 elif prog.lastOp.op == 'ror': | |
560 if type(prog.lastB) is int: | |
561 if prog.lastB == 0: | |
562 explicit[flag] = 0 | |
563 continue | |
564 else: | |
565 output.append(f'\n\tif (!{prog.lastB}) {{') | |
566 _addExplicitFlagSet(prog, output, flag, 0) | |
567 output.append('\n\t} else {') | |
568 after = '\n\t}' | |
569 resultBit = prog.getLastSize() - 1 | |
509 elif prog.lastOp.op == 'neg': | 570 elif prog.lastOp.op == 'neg': |
510 if prog.carryFlowDst: | 571 if prog.carryFlowDst: |
511 realSize = prog.getLastSize() | 572 realSize = prog.getLastSize() |
512 if realSize != prog.paramSize(prog.carryFlowDst): | 573 if realSize != prog.paramSize(prog.carryFlowDst): |
513 lastDst = '({res} & {mask})'.format(res=lastDst, mask = (1 << realSize) - 1) | 574 lastDst = '({res} & {mask})'.format(res=lastDst, mask = (1 << realSize) - 1) |
523 reg = reg, res = lastDst | 584 reg = reg, res = lastDst |
524 )) | 585 )) |
525 continue | 586 continue |
526 else: | 587 else: |
527 resultBit = prog.getLastSize() | 588 resultBit = prog.getLastSize() |
528 if prog.lastOp.op == 'ror': | |
529 resultBit -= 1 | |
530 elif calc == 'half': | 589 elif calc == 'half': |
531 resultBit = prog.getLastSize() - 4 | 590 resultBit = prog.getLastSize() - 4 |
532 myRes = '({a} ^ {b} ^ {res})'.format(a = prog.lastA, b = prog.lastB, res = lastDst) | 591 myRes = '({a} ^ {b} ^ {res})'.format(a = prog.lastA, b = prog.lastB, res = lastDst) |
533 elif calc == 'overflow': | 592 elif calc == 'overflow': |
534 resultBit = prog.getLastSize() - 1 | 593 resultBit = prog.getLastSize() - 1 |
564 elif resultBit > maxBit: | 623 elif resultBit > maxBit: |
565 mask = f'{1 << maxBit}U' | 624 mask = f'{1 << maxBit}U' |
566 output.append('\n\t{reg} = {res} >> {shift} & {mask};'.format(reg=reg, res=myRes, shift = resultBit - maxBit, mask = mask)) | 625 output.append('\n\t{reg} = {res} >> {shift} & {mask};'.format(reg=reg, res=myRes, shift = resultBit - maxBit, mask = mask)) |
567 else: | 626 else: |
568 output.append('\n\t{reg} = {res} & {mask};'.format(reg=reg, res=myRes, mask = mask)) | 627 output.append('\n\t{reg} = {res} & {mask};'.format(reg=reg, res=myRes, mask = mask)) |
628 if after: | |
629 output.append(after) | |
569 elif calc == 'zero': | 630 elif calc == 'zero': |
570 if prog.carryFlowDst: | 631 if prog.carryFlowDst: |
571 realSize = prog.getLastSize() | 632 realSize = prog.getLastSize() |
572 if realSize != prog.paramSize(prog.carryFlowDst): | 633 if realSize != prog.paramSize(prog.carryFlowDst): |
573 lastDst = '({res} & {mask})'.format(res=lastDst, mask = (1 << realSize) - 1) | 634 lastDst = '({res} & {mask})'.format(res=lastDst, mask = (1 << realSize) - 1) |
634 reg = prog.resolveParam(parity, None, {}) | 695 reg = prog.resolveParam(parity, None, {}) |
635 output.append('\n\t{flag} = 0x9669 >> {parity} & 1;'.format(flag=reg, parity=parityDst)) | 696 output.append('\n\t{flag} = 0x9669 >> {parity} & 1;'.format(flag=reg, parity=parityDst)) |
636 | 697 |
637 #TODO: combine explicit flags targeting the same storage location | 698 #TODO: combine explicit flags targeting the same storage location |
638 for flag in explicit: | 699 for flag in explicit: |
639 location = prog.flags.getStorage(flag) | 700 _addExplicitFlagSet(prog, output, flag, explicit[flag]) |
640 if type(location) is tuple: | |
641 reg,bit = location | |
642 reg = prog.resolveReg(reg, None, {}) | |
643 value = str(1 << bit) | |
644 if explicit[flag]: | |
645 operator = '|=' | |
646 else: | |
647 operator = '&=' | |
648 value = '~' + value | |
649 output.append('\n\t{reg} {op} {val};'.format(reg=reg, op=operator, val=value)) | |
650 else: | |
651 reg = prog.resolveReg(location, None, {}) | |
652 output.append('\n\t{reg} = {val};'.format(reg=reg, val=explicit[flag])) | |
653 return ''.join(output) | 701 return ''.join(output) |
654 | 702 |
655 def _cmpCImpl(prog, params, rawParams, flagUpdates): | 703 def _cmpCImpl(prog, params, rawParams, flagUpdates): |
656 b_size = size = prog.paramSize(rawParams[1]) | 704 b_size = size = prog.paramSize(rawParams[1]) |
657 needsCarry = False | 705 needsCarry = False |
927 for flag in flagUpdates: | 975 for flag in flagUpdates: |
928 calc = prog.flags.flagCalc[flag] | 976 calc = prog.flags.flagCalc[flag] |
929 if calc == 'carry': | 977 if calc == 'carry': |
930 needsCarry = True | 978 needsCarry = True |
931 decl = '' | 979 decl = '' |
932 size = prog.paramSize(rawParams[2]) | 980 destSize = prog.paramSize(rawParams[2]) |
933 if needsCarry: | 981 needsSizeAdjust = False |
934 decl,name = prog.getTemp(size * 2) | 982 if len(params) > 3: |
983 size = params[3] | |
984 if size == 0: | |
985 size = 8 | |
986 elif size == 1: | |
987 size = 16 | |
988 else: | |
989 size = 32 | |
990 prog.lastSize = size | |
991 if destSize > size: | |
992 needsSizeAdjust = True | |
993 if needsCarry: | |
994 prog.sizeAdjust = size | |
995 else: | |
996 size = destSize | |
997 | |
998 prog.lastB = params[1] | |
999 if needsSizeAdjust: | |
1000 decl,name = prog.getTemp(size) | |
935 dst = prog.carryFlowDst = name | 1001 dst = prog.carryFlowDst = name |
936 else: | 1002 else: |
937 dst = params[2] | 1003 dst = params[2] |
938 return decl + '\n\t{dst} = {a} << {b} | {a} >> ({size} - {b});'.format(dst = dst, | 1004 ret = decl + '\n\t{dst} = {a} << {b} | {a} >> ({size} - {b});'.format(dst = dst, |
939 a = params[0], b = params[1], size=size | 1005 a = params[0], b = params[1], size=size |
940 ) | 1006 ) |
1007 if needsSizeAdjust and not needsCarry: | |
1008 mask = (1 << size) - 1 | |
1009 ret += f'\n\t{params[2]} = ({params[2]} & ~{mask}) | ({dst} & {mask});' | |
1010 return ret | |
941 | 1011 |
942 def _rlcCImpl(prog, params, rawParams, flagUpdates): | 1012 def _rlcCImpl(prog, params, rawParams, flagUpdates): |
943 needsCarry = False | 1013 needsCarry = False |
944 if flagUpdates: | 1014 if flagUpdates: |
945 for flag in flagUpdates: | 1015 for flag in flagUpdates: |
946 calc = prog.flags.flagCalc[flag] | 1016 calc = prog.flags.flagCalc[flag] |
947 if calc == 'carry': | 1017 if calc == 'carry': |
948 needsCarry = True | 1018 needsCarry = True |
949 decl = '' | 1019 decl = '' |
1020 destSize = prog.paramSize(rawParams[2]) | |
1021 needsSizeAdjust = False | |
1022 if len(params) > 3: | |
1023 size = params[3] | |
1024 if size == 0: | |
1025 size = 8 | |
1026 elif size == 1: | |
1027 size = 16 | |
1028 else: | |
1029 size = 32 | |
1030 prog.lastSize = size | |
1031 if destSize > size: | |
1032 needsSizeAdjust = True | |
1033 if needsCarry: | |
1034 prog.sizeAdjust = size | |
1035 else: | |
1036 size = destSize | |
950 carryCheck = _getCarryCheck(prog) | 1037 carryCheck = _getCarryCheck(prog) |
951 size = prog.paramSize(rawParams[2]) | 1038 size = prog.paramSize(rawParams[2]) |
952 if needsCarry: | 1039 if needsCarry or needsSizeAdjust: |
953 decl,name = prog.getTemp(size * 2) | 1040 decl,name = prog.getTemp(size) |
954 dst = prog.carryFlowDst = name | 1041 dst = prog.carryFlowDst = name |
1042 prog.lastA = params[0] | |
1043 prog.lastB = params[1] | |
955 else: | 1044 else: |
956 dst = params[2] | 1045 dst = params[2] |
957 return decl + '\n\t{dst} = {a} << {b} | {a} >> ({size} + 1 - {b}) | ({check} ? 1 : 0) << ({b} - 1);'.format(dst = dst, | 1046 if size == 32 and (not type(params[1]) is int) or params[1] <= 1: |
958 a = params[0], b = params[1], size=size, check=carryCheck | 1047 # we may need to shift by 32-bits which is too much for a normal int |
1048 a = f'((uint64_t){params[0]})' | |
1049 else: | |
1050 a = params[0] | |
1051 ret = decl + '\n\t{dst} = {a} << {b} | {a} >> ({size} + 1 - {b}) | ({check} ? 1 : 0) << ({b} - 1);'.format(dst = dst, | |
1052 a = a, b = params[1], size=size, check=carryCheck | |
959 ) | 1053 ) |
1054 if needsSizeAdjust and not needsCarry: | |
1055 mask = (1 << size) - 1 | |
1056 ret += f'\n\t{params[2]} = ({params[2]} & ~{mask}) | ({dst} & {mask});' | |
1057 return ret | |
960 | 1058 |
961 def _rorCImpl(prog, params, rawParams, flagUpdates): | 1059 def _rorCImpl(prog, params, rawParams, flagUpdates): |
962 size = prog.paramSize(rawParams[2]) | 1060 needsCarry = False |
963 return '\n\t{dst} = {a} >> {b} | {a} << ({size} - {b});'.format(dst = params[2], | 1061 if flagUpdates: |
1062 for flag in flagUpdates: | |
1063 calc = prog.flags.flagCalc[flag] | |
1064 if calc == 'carry': | |
1065 needsCarry = True | |
1066 decl = '' | |
1067 destSize = prog.paramSize(rawParams[2]) | |
1068 needsSizeAdjust = False | |
1069 if len(params) > 3: | |
1070 size = params[3] | |
1071 if size == 0: | |
1072 size = 8 | |
1073 elif size == 1: | |
1074 size = 16 | |
1075 else: | |
1076 size = 32 | |
1077 prog.lastSize = size | |
1078 if destSize > size: | |
1079 needsSizeAdjust = True | |
1080 if needsCarry: | |
1081 prog.sizeAdjust = size | |
1082 else: | |
1083 size = destSize | |
1084 prog.lastB = params[1] | |
1085 if needsSizeAdjust: | |
1086 decl,name = prog.getTemp(size) | |
1087 dst = prog.carryFlowDst = name | |
1088 else: | |
1089 dst = params[2] | |
1090 ret = decl + '\n\t{dst} = {a} >> {b} | {a} << ({size} - {b});'.format(dst = dst, | |
964 a = params[0], b = params[1], size=size | 1091 a = params[0], b = params[1], size=size |
965 ) | 1092 ) |
1093 if needsSizeAdjust and not needsCarry: | |
1094 mask = (1 << size) - 1 | |
1095 ret += f'\n\t{params[2]} = ({params[2]} & ~{mask}) | ({dst} & {mask});' | |
1096 return ret | |
966 | 1097 |
967 def _rrcCImpl(prog, params, rawParams, flagUpdates): | 1098 def _rrcCImpl(prog, params, rawParams, flagUpdates): |
968 needsCarry = False | 1099 needsCarry = False |
969 if flagUpdates: | 1100 if flagUpdates: |
970 for flag in flagUpdates: | 1101 for flag in flagUpdates: |
971 calc = prog.flags.flagCalc[flag] | 1102 calc = prog.flags.flagCalc[flag] |
972 if calc == 'carry': | 1103 if calc == 'carry': |
973 needsCarry = True | 1104 needsCarry = True |
974 decl = '' | 1105 decl = '' |
1106 destSize = prog.paramSize(rawParams[2]) | |
1107 needsSizeAdjust = False | |
1108 if len(params) > 3: | |
1109 size = params[3] | |
1110 if size == 0: | |
1111 size = 8 | |
1112 elif size == 1: | |
1113 size = 16 | |
1114 else: | |
1115 size = 32 | |
1116 prog.lastSize = size | |
1117 if destSize > size: | |
1118 needsSizeAdjust = True | |
1119 if needsCarry: | |
1120 prog.sizeAdjust = size | |
1121 else: | |
1122 size = destSize | |
975 carryCheck = _getCarryCheck(prog) | 1123 carryCheck = _getCarryCheck(prog) |
976 size = prog.paramSize(rawParams[2]) | 1124 size = prog.paramSize(rawParams[2]) |
977 if needsCarry: | 1125 if needsCarry or needsSizeAdjust: |
978 decl,name = prog.getTemp(size * 2) | 1126 decl,name = prog.getTemp(size) |
979 dst = prog.carryFlowDst = name | 1127 dst = prog.carryFlowDst = name |
1128 prog.lastA = params[0] | |
1129 prog.lastB = params[1] | |
980 else: | 1130 else: |
981 dst = params[2] | 1131 dst = params[2] |
982 return decl + '\n\t{dst} = {a} >> {b} | {a} << ({size} + 1 - {b}) | ({check} ? 1 : 0) << ({size}-{b});'.format(dst = dst, | 1132 if size == 32 and (not type(params[1]) is int) or params[1] <= 1: |
983 a = params[0], b = params[1], size=size, check=carryCheck | 1133 # we may need to shift by 32-bits which is too much for a normal int |
1134 a = f'((uint64_t){params[0]})' | |
1135 else: | |
1136 a = params[0] | |
1137 ret = decl + '\n\t{dst} = {a} >> {b} | {a} << ({size} + 1 - {b}) | ({check} ? 1 : 0) << ({size}-{b});'.format(dst = dst, | |
1138 a = a, b = params[1], size=size, check=carryCheck | |
984 ) | 1139 ) |
1140 if needsSizeAdjust and not needsCarry: | |
1141 mask = (1 << size) - 1 | |
1142 ret += f'\n\t{params[2]} = ({params[2]} & ~{mask}) | ({dst} & {mask});' | |
1143 return ret | |
985 | 1144 |
986 def _updateSyncCImpl(prog, params): | 1145 def _updateSyncCImpl(prog, params): |
987 return '\n\t{sync}(context, target_cycle);'.format(sync=prog.sync_cycle) | 1146 return '\n\t{sync}(context, target_cycle);'.format(sync=prog.sync_cycle) |
988 | 1147 |
989 _opMap = { | 1148 _opMap = { |
1681 macro = header.upper().replace('.', '_') | 1840 macro = header.upper().replace('.', '_') |
1682 hFile.write('#ifndef {0}_'.format(macro)) | 1841 hFile.write('#ifndef {0}_'.format(macro)) |
1683 hFile.write('\n#define {0}_'.format(macro)) | 1842 hFile.write('\n#define {0}_'.format(macro)) |
1684 hFile.write('\n#include <stdio.h>') | 1843 hFile.write('\n#include <stdio.h>') |
1685 hFile.write('\n#include "backend.h"') | 1844 hFile.write('\n#include "backend.h"') |
1686 hFile.write('\n\ntypedef struct {') | 1845 hFile.write(f'\n\ntypedef struct {self.prefix}options {self.prefix}options;') |
1687 hFile.write('\n\tcpu_options gen;') | 1846 hFile.write(f'\n\ntypedef struct {self.prefix}context {self.prefix}context;') |
1688 hFile.write('\n\tFILE* address_log;') | |
1689 hFile.write('\n}} {0}options;'.format(self.prefix)) | |
1690 hFile.write('\n\ntypedef struct {') | |
1691 hFile.write('\n\t{0}options *opts;'.format(self.prefix)) | |
1692 self.regs.writeHeader(otype, hFile) | |
1693 hFile.write('\n}} {0}context;'.format(self.prefix)) | |
1694 hFile.write('\n') | |
1695 hFile.write('\nvoid {pre}execute({type} *context, uint32_t target_cycle);'.format(pre = self.prefix, type = self.context_type)) | |
1696 for decl in self.declares: | 1847 for decl in self.declares: |
1697 if decl.startswith('define '): | 1848 if decl.startswith('define '): |
1698 decl = '#' + decl | 1849 decl = '#' + decl |
1699 hFile.write('\n' + decl) | 1850 hFile.write('\n' + decl) |
1851 hFile.write(f'\n\nstruct {self.prefix}options {{') | |
1852 hFile.write('\n\tcpu_options gen;') | |
1853 hFile.write('\n\tFILE* address_log;') | |
1854 hFile.write('\n};') | |
1855 hFile.write(f'\n\nstruct {self.prefix}context {{') | |
1856 hFile.write(f'\n\t{self.prefix}options *opts;') | |
1857 self.regs.writeHeader(otype, hFile) | |
1858 hFile.write('\n};') | |
1859 hFile.write('\n') | |
1860 hFile.write('\nvoid {pre}execute({type} *context, uint32_t target_cycle);'.format(pre = self.prefix, type = self.context_type)) | |
1700 hFile.write('\n#endif //{0}_'.format(macro)) | 1861 hFile.write('\n#endif //{0}_'.format(macro)) |
1701 hFile.write('\n') | 1862 hFile.write('\n') |
1702 hFile.close() | 1863 hFile.close() |
1703 | 1864 |
1704 def _buildTable(self, otype, table, body, lateBody): | 1865 def _buildTable(self, otype, table, body, lateBody): |