diff --git a/Ghidra/Extensions/SleighDevTools/pcodetest/pcode_defs.py b/Ghidra/Extensions/SleighDevTools/pcodetest/pcode_defs.py index 0e70268d34..44d612a11b 100644 --- a/Ghidra/Extensions/SleighDevTools/pcodetest/pcode_defs.py +++ b/Ghidra/Extensions/SleighDevTools/pcodetest/pcode_defs.py @@ -842,3 +842,19 @@ PCodeTest({ 'language_id': 'Xtensa:BE:32:default', 'ccflags': '-L %(toolchain_dir)s/lib/gcc/xtensa-elf/%(gcc_version)s', }) + + +PCodeTest({ + 'name': 'CPU32', + 'build_all': 1, + 'build_exe': 0, + 'has_float': 0, + 'has_double': 0, + 'toolchain': 'm68k/m68k-linux-gnu', + 'exec_prefix': 'm68k-linux-gnu-', + 'gcc_version': '14', + 'ccflags': '-mcpu=cpu32 -nostdlib -static', + 'cclibs': '-lgcc', + 'gcc_libdir': '/usr/lib/gcc-cross/m68k-linux-gnu/14', + 'language_id': '68000:BE:32:CPU32', +}) diff --git a/Ghidra/Processors/68000/certification.manifest b/Ghidra/Processors/68000/certification.manifest index 55d58490e3..caf51979e7 100644 --- a/Ghidra/Processors/68000/certification.manifest +++ b/Ghidra/Processors/68000/certification.manifest @@ -12,6 +12,7 @@ data/languages/68020.slaspec||GHIDRA||reviewed||END| data/languages/68030.slaspec||GHIDRA||||END| data/languages/68040.slaspec||GHIDRA||||END| data/languages/coldfire.slaspec||GHIDRA||||END| +data/languages/CPU32.slaspec||GHIDRA||||END| data/manuals/68000.idx||GHIDRA||||END| data/patterns/68000_patterns.xml||GHIDRA||||END| data/patterns/patternconstraints.xml||GHIDRA||||END| diff --git a/Ghidra/Processors/68000/data/languages/68000.ldefs b/Ghidra/Processors/68000/data/languages/68000.ldefs index 5115f2d878..7fe13fc6bf 100644 --- a/Ghidra/Processors/68000/data/languages/68000.ldefs +++ b/Ghidra/Processors/68000/data/languages/68000.ldefs @@ -73,4 +73,17 @@ + + Motorola 32-bit CPU32 (MC68340) + + + diff --git a/Ghidra/Processors/68000/data/languages/68000.sinc b/Ghidra/Processors/68000/data/languages/68000.sinc index 674c9d0653..963f0829d3 100644 --- a/Ghidra/Processors/68000/data/languages/68000.sinc +++ b/Ghidra/Processors/68000/data/languages/68000.sinc @@ -59,6 +59,10 @@ define register offset=0x746 size=10 [ FP7 ]; @define DAT_DIR_CTL_ADDR_MODES2 "(mode2=0 | mode2=2 | mode2=5 | mode2=6 | mode=7)" # Data direct and control addressing modes @define CTL_ADDR_MODES2 "(mode2=2 | mode2=5 | mode2=6 | mode2=7)" # Control addressing modes +@ifdef CPU32 +@define TBL_ADDR_MODES "(tbl_mode=2 | tbl_mode=4 | tbl_mode=5 | tbl_mode=6 | tbl_mode=7)" +@endif + # Floating-point condition code bits within FPSR @define N_FP "FPSR[27,1]" @define Z_FP "FPSR[26,1]" @@ -173,9 +177,29 @@ define token extword (16) reg12x = (12,15) reg12xwu = (12,15) reg12xwl = (12,15) -@endif +@endif +@ifdef CPU32 + tbl_dr_size = (6,7) + tbl_dr_round = (10,10) + tbl_dr_sign = (11,11) + tbl_dr_reg = (0,2) +@endif ; +@ifdef CPU32 +define token tbl_instrA(32) + tbl_regan=(16,18) + tbl_mode=(19,21) + tbl_op37=(19,23) + tbl_op67=(22,23) + tbl_opbig=(24,31) + tbl_size=(6,7) + tbl_round=(10,10) + tbl_sign=(11,11) + tbl_regxdn=(12,14) +; +@endif + define token extword2 (16) regda2 = (12,15) ext2_911 = (9,11) @@ -307,12 +331,20 @@ define context contextreg extGUARD = (14,14) # guard for saving off modes before starting instructions ; +@ifdef CPU32 +attach variables [ regdn regxdn reg9dn regdr regdq regsdn regdu regdc regdu2 regdc2 tbl_regxdn tbl_dr_reg ] [ D0 D1 D2 D3 D4 D5 D6 D7 ]; +@else attach variables [ regdn regxdn reg9dn regdr regdq regsdn regdu regdc regdu2 regdc2 ] [ D0 D1 D2 D3 D4 D5 D6 D7 ]; +@endif attach variables [ fldoffreg fldwdreg f_reg fcnt fkfacreg fldynreg ] [ D0 D1 D2 D3 D4 D5 D6 D7 ]; attach variables [ regdnw regxdnw reg9dnw regsdnw regduw regdcw regdu2w regdc2w ] [ D0w D1w D2w D3w D4w D5w D6w D7w ]; attach variables [ regdnb reg9dnb regsdnb regdub regdcb ] [ D0b D1b D2b D3b D4b D5b D6b D7b ]; attach variables [ regda regda2 ] [ D0 D1 D2 D3 D4 D5 D6 D7 A0 A1 A2 A3 A4 A5 A6 SP ]; +@ifdef CPU32 +attach variables [ regan regxan reg9an regfan regsan aregx tbl_regan ] [ A0 A1 A2 A3 A4 A5 A6 SP ]; +@else attach variables [ regan regxan reg9an regfan regsan aregx ] [ A0 A1 A2 A3 A4 A5 A6 SP ]; +@endif attach variables [ reganw regxanw regsanw ] [ A0w A1w A2w A3w A4w A5w A6w A7w ]; attach variables [ reganb regsanb ] [ A0b A1b A2b A3b A4b A5b A6b A7b ]; @@ -1051,6 +1083,7 @@ with : extGUARD=1 { local source = regdn; mask:4 = 1 << (const8 & 31); ZF = (source & mask) == 0; regdn = source & (~mask); } +@ifndef CPU32 bfOffWd: {f_off:f_wd} is f_off & f_wd { } :bfchg e2l^bfOffWd is opbig=0xea & op67=3 & $(DAT_DIR_CTL_ADDR_MODES); bfOffWd & f_off & f_wd; e2l [ savmod2=savmod1; regtsan=regtfan; ] { logflags(); @@ -1144,6 +1177,7 @@ bfOffWd: {f_off:f_wd} is f_off & f_wd { } getbitfield(tmp, f_off, f_wd); resbitflags(tmp, f_wd-1); } +@endif # CPU32 - no bitfield instructions define pcodeop breakpoint; :bkpt "#"op02 is opbig=0x48 & op67=1 & op5=0 & op34=1 & op02 { breakpoint(); } @@ -1205,7 +1239,8 @@ define pcodeop breakpoint; } @endif # COLDFIRE -# TODO: Determine layout of a module descriptor +@ifndef CPU32 +# TODO: Determine layout of a module descriptor define pcodeop callm; :callm const8,e2l is opbig=6 & op67=3 & $(CTL_ADDR_MODES); const8; e2l [ savmod2=savmod1; regtsan=regtfan; ] { PC = callm(const8, e2l); @@ -1283,6 +1318,7 @@ define pcodeop callm; ZF = 1; NF = 0; } +@endif # CPU32 - no CALLM, CAS, CAS2 :chk.w eaw,reg9dnw is (op=4 & reg9dnw & op68=6 & $(DAT_ALTER_ADDR_MODES))... & eaw { build eaw; @@ -2060,6 +2096,7 @@ macro negResFlags(result) { :ori const8,"CCR" is opbig=0 & op37=7 & op02=4; const8 { packflags(SR); SR=SR|zext(const8); unpackflags(SR); } :ori const16,SR is SR; opbig=0x00 & d8base=0x7c; const16 { packflags(SR); SR=SR|const16; unpackflags(SR); } +@ifndef CPU32 :pack Tyw,Txw,const16 is op=8 & op48=20 & Txw & Tyw & rmbit=0; const16 { local value = (Tyw & 0x0F0F) + const16; Txw = (Txw & 0xFF00) | ((value & 0x0F00) >> 4) | (value & 0x000F); @@ -2070,6 +2107,7 @@ macro negResFlags(result) { local result:2 = ((value & 0x0F00) >> 4) | (value & 0x000F); Txb = result:1; } +@endif # CPU32 - no PACK :pea eaptr is (opbig=0x48 & op67=1 & $(CTL_ADDR_MODES))... & eaptr { value:4 = eaptr; SP = SP-4; *SP = value; } @@ -2227,9 +2265,11 @@ ptestLevel: "#"^mregn is mregn { export *[const]:1 mregn; } :rtd const16 is opbig=0x4e & op37=14 & op02=4; const16 { PC = *SP; SP = SP + 4 + zext(const16); return [PC]; } :rte is d16=0x4e73 { tmp:4 = 0; return [tmp]; } +@ifndef CPU32 define pcodeop rtm; :rtm regdn is opbig=0x06 & op37=24 & regdn { PC = rtm(regdn); return [PC]; } :rtm regan is opbig=0x06 & op37=25 & regan { PC = rtm(regan); return [PC];} +@endif # CPU32 - no RTM :rtr is opbig=0x4e & op37=14 & op02=7 { SR = *SP; SP = SP+2; PC = *SP; SP = SP+4; unpackflags(SR); return [PC]; } @@ -2306,6 +2346,7 @@ define pcodeop stop; :unlk regan is opbig=0x4e & op37=11 & regan { SP = regan; regan = *SP; SP = SP+4; } +@ifndef CPU32 :unpk Tyw,Txw,const16 is op=8 & Txw & op48=24 & Tyw & rmbit=0; const16 { Txw = (Txw & 0xF0F0) | ((((Tyw & 0x00F0) << 4) | (Tyw & 0x000F)) + const16); } @@ -2315,7 +2356,9 @@ define pcodeop stop; source = (((source & 0x00F0) << 4) | (source & 0x000F)) + const16; Txw = (Txw & 0xF0F0) | source; } +@endif # CPU32 - no UNPK +@ifndef CPU32 # Floating Point Instructions # 68040 directly implements Floating Point instructions but requires Coprocessor ID be 001 @@ -2883,6 +2926,7 @@ fsubrnd: "d" is fdst & fopmode=0x6c { tmp:4 = float2float(fdst); fdst = float2f :ftwotox.x fsrc, fdst is op=15 & $(FP_COP) & op68=0 & mode=0 & regan=0; frm=0 & f1515=0 & f1313=0 & fsrc & fdst & fopmode=0x11 { fdst = ftwotox(fsrc); } +@endif # CPU32 - no FPU instructions @ifdef COLDFIRE @@ -3151,4 +3195,97 @@ moveaccreg2: ACC3 is ACC3 & op01=3 { export ACC3; } @endif +@ifdef CPU32 + +tbl_eal: (tbl_regan) is tbl_mode=2 & tbl_regan { export *:4 tbl_regan; } +tbl_eal: -(tbl_regan) is tbl_mode=4 & tbl_regan { tbl_regan = tbl_regan - 4; export *:4 tbl_regan; } +tbl_eal: (d16,tbl_regan) is tbl_mode=5 & tbl_regan; d16 { local tmp = tbl_regan + d16; export *:4 tmp; } +tbl_eal: (extw) is tbl_mode=6 & tbl_regan; extw [ regtfan = tbl_regan; pcmode = 0; ] { build extw; export *:4 extw; } +tbl_eal: (d16,PC) is PC & tbl_mode=7 & tbl_regan=2; d16 { tmp:4 = inst_start + 2 + d16; export *:4 tmp; } +tbl_eal: (extw) is tbl_mode=7 & tbl_regan=3; extw [ pcmode=1; ] { build extw; export *:4 extw; } +tbl_eal: (d16)".w" is tbl_mode=7 & tbl_regan=0; d16 { export *:4 d16; } +tbl_eal: (d32)".l" is tbl_mode=7 & tbl_regan=1; d32 { export *:4 d32; } +tbl_eal: "#"^d32 is tbl_mode=7 & tbl_regan=4; d32 { export *[const]:4 d32; } + +tbl_eaw: (tbl_regan) is tbl_mode=2 & tbl_regan { export *:2 tbl_regan; } +tbl_eaw: -(tbl_regan) is tbl_mode=4 & tbl_regan { tbl_regan = tbl_regan - 2; export *:2 tbl_regan; } +tbl_eaw: (d16,tbl_regan) is tbl_mode=5 & tbl_regan; d16 { local tmp = tbl_regan + d16; export *:2 tmp; } +tbl_eaw: (extw) is tbl_mode=6 & tbl_regan; extw [ pcmode=0; regtfan=tbl_regan; ] { build extw; export *:2 extw; } +tbl_eaw: (d16,PC) is PC & tbl_mode=7 & tbl_regan=2; d16 { tmp:4 = inst_start + 2 + d16; export *:2 tmp; } +tbl_eaw: (extw) is tbl_mode=7 & tbl_regan=3; extw [ pcmode=1; ] { build extw; export *:2 extw; } +tbl_eaw: (d16)".w" is tbl_mode=7 & tbl_regan=0; d16 { export *:2 d16; } +tbl_eaw: (d32)".l" is tbl_mode=7 & tbl_regan=1; d32 { export *:2 d32; } +tbl_eaw: "#"^d16 is tbl_mode=7 & tbl_regan=4; d16 { export *[const]:2 d16; } + +tbl_eab: (tbl_regan) is tbl_mode=2 & tbl_regan { export *:1 tbl_regan; } +tbl_eab: -(tbl_regan) is tbl_mode=4 & tbl_regan { tbl_regan = tbl_regan - 1; export *:1 tbl_regan; } +tbl_eab: (d16,tbl_regan) is tbl_mode=5 & tbl_regan; d16 { local tmp = tbl_regan + d16; export *:1 tmp; } +tbl_eab: (extw) is tbl_mode=6 & tbl_regan; extw [ pcmode=0; regtfan=tbl_regan; ] { build extw; export *:1 extw; } +tbl_eab: (d16,PC) is PC & tbl_mode=7 & tbl_regan=2; d16 { tmp:4 = inst_start + 2 + d16; export *:1 tmp; } +tbl_eab: (extw) is tbl_mode=7 & tbl_regan=3; extw [ pcmode=1; ] { build extw; export *:1 extw; } +tbl_eab: (d16)".w" is tbl_mode=7 & tbl_regan=0; d16 { export *:1 d16; } +tbl_eab: (d32)".l" is tbl_mode=7 & tbl_regan=1; d32 { export *:1 d32; } +tbl_eab: "#"^d8 is tbl_mode=7 & tbl_regan=4; d8 { export *[const]:1 d8; } + +tblsign: "u" is tbl_sign=0 { } +tblsign: "s" is tbl_sign=1 { } + +tbldrsign: "u" is tbl_dr_sign=0 { } +tbldrsign: "s" is tbl_dr_sign=1 { } + +define pcodeop tableLookup; + +# Rounded Table Lookup and Interpolate + +:tbl^tblsign^".b" tbl_eab,tbl_regxdn is (tbl_opbig=0xF8 & tbl_op67=0 & $(TBL_ADDR_MODES) & tbl_size=0 & tblsign & tbl_round=0 & tbl_regxdn) ... & tbl_eab + { tbl_regxdn = tableLookup(tbl_regxdn, tbl_eab); } + +:tbl^tblsign^".w" tbl_eaw,tbl_regxdn is (tbl_opbig=0xF8 & tbl_op67=0 & $(TBL_ADDR_MODES) & tbl_size=1 & tblsign & tbl_round=0 & tbl_regxdn) ... & tbl_eaw + { tbl_regxdn = tableLookup(tbl_regxdn, tbl_eaw); } + +:tbl^tblsign^".l" tbl_eal,tbl_regxdn is (tbl_opbig=0xF8 & tbl_op67=0 & $(TBL_ADDR_MODES) & tbl_size=2 & tblsign & tbl_round=0 & tbl_regxdn) ... & tbl_eal + { tbl_regxdn = tableLookup(tbl_regxdn, tbl_eal); } + +# Unrounded Table Lookup and Interpolate + +:tbl^tblsign^"n.b" tbl_eab,tbl_regxdn is (tbl_opbig=0xF8 & tbl_op67=0 & $(TBL_ADDR_MODES) & tbl_size=0 & tblsign & tbl_round=1 & tbl_regxdn) ... & tbl_eab + { tbl_regxdn = tableLookup(tbl_regxdn, tbl_eab); } + +:tbl^tblsign^"n.w" tbl_eaw,tbl_regxdn is (tbl_opbig=0xF8 & tbl_op67=0 & $(TBL_ADDR_MODES) & tbl_size=1 & tblsign & tbl_round=1 & tbl_regxdn) ... & tbl_eaw + { tbl_regxdn = tableLookup(tbl_regxdn, tbl_eaw); } + +:tbl^tblsign^"n.l" tbl_eal,tbl_regxdn is (tbl_opbig=0xF8 & tbl_op67=0 & $(TBL_ADDR_MODES) & tbl_size=2 & tblsign & tbl_round=1 & tbl_regxdn) ... & tbl_eal + { tbl_regxdn = tableLookup(tbl_regxdn, tbl_eal); } + +define pcodeop interpolate; + +# Rounded Data Register Interpolate + +:tbl^tbldrsign^".b" regdn:tbl_dr_reg,regxdn is opbig=0xF8 & op37=0 & mode=0 & regdn ; tbl_dr_size=0 & tbldrsign & tbl_dr_round=0 & tbl_dr_reg & regxdn + { regxdn = interpolate(regdn, tbl_dr_reg); } + +:tbl^tbldrsign^".w" regdn:tbl_dr_reg,regxdn is opbig=0xF8 & op37=0 & mode=0 & regdn ; tbl_dr_size=1 & tbldrsign & tbl_dr_round=0 & tbl_dr_reg & regxdn + { regxdn = interpolate(regdn, tbl_dr_reg); } + +:tbl^tbldrsign^".l" regdn:tbl_dr_reg,regxdn is opbig=0xF8 & op37=0 & mode=0 & regdn ; tbl_dr_size=2 & tbldrsign & tbl_dr_round=0 & tbl_dr_reg & regxdn + { regxdn = interpolate(regdn, tbl_dr_reg); } + +# Unrounded Data Register Interpolate + +:tbl^tbldrsign^"n.b" regdn:tbl_dr_reg,regxdn is opbig=0xF8 & op37=0 & mode=0 & regdn ; tbl_dr_size=0 & tbldrsign & tbl_dr_round=1 & tbl_dr_reg & regxdn + { regxdn = interpolate(regdn, tbl_dr_reg); } + +:tbl^tbldrsign^"n.w" regdn:tbl_dr_reg,regxdn is opbig=0xF8 & op37=0 & mode=0 & regdn ; tbl_dr_size=1 & tbldrsign & tbl_dr_round=1 & tbl_dr_reg & regxdn + { regxdn = interpolate(regdn, tbl_dr_reg); } + +:tbl^tbldrsign^"n.l" regdn:tbl_dr_reg,regxdn is opbig=0xF8 & op37=0 & mode=0 & regdn ; tbl_dr_size=2 & tbldrsign & tbl_dr_round=1 & tbl_dr_reg & regxdn + { regxdn = interpolate(regdn, tbl_dr_reg); } + +define pcodeop low_power_stop; +:lpstop "#"^d16 is opbig=0xf8 & d8base=0x00; opbig=0x01 & d8base=0xC0; d16 { SR = d16; low_power_stop(); } + +define pcodeop background_mode; +:bgnd is opbig=0x4A & d8base=0xFA { background_mode(); } + +@endif # CPU32 } # end with : extGUARD=1 diff --git a/Ghidra/Processors/68000/data/languages/CPU32.slaspec b/Ghidra/Processors/68000/data/languages/CPU32.slaspec new file mode 100644 index 0000000000..dc2c54ab6f --- /dev/null +++ b/Ghidra/Processors/68000/data/languages/CPU32.slaspec @@ -0,0 +1,6 @@ +# Motorola's CPU32 processor + +@define CPU32 "" +@define MC68332 "" + +@include "68000.sinc" diff --git a/Ghidra/Processors/68000/src/test.processors/java/ghidra/test/processors/CPU32_O0_EmulatorTest.java b/Ghidra/Processors/68000/src/test.processors/java/ghidra/test/processors/CPU32_O0_EmulatorTest.java new file mode 100644 index 0000000000..583c7052a9 --- /dev/null +++ b/Ghidra/Processors/68000/src/test.processors/java/ghidra/test/processors/CPU32_O0_EmulatorTest.java @@ -0,0 +1,40 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.test.processors; + +import ghidra.test.processors.support.ProcessorEmulatorTestAdapter; +import junit.framework.Test; + +public class CPU32_O0_EmulatorTest extends ProcessorEmulatorTestAdapter { + + private static final String LANGUAGE_ID = "68000:BE:32:CPU32"; + private static final String COMPILER_SPEC_ID = "default"; + + private static final String[] REG_DUMP_SET = new String[] {}; + + public CPU32_O0_EmulatorTest(String name) throws Exception { + super(name, LANGUAGE_ID, COMPILER_SPEC_ID, REG_DUMP_SET); + } + + @Override + protected String getProcessorDesignator() { + return "CPU32_GCC_O0"; + } + + public static Test suite() { + return ProcessorEmulatorTestAdapter.buildEmulatorTestSuite(CPU32_O0_EmulatorTest.class); + } +} diff --git a/Ghidra/Processors/68000/src/test.processors/java/ghidra/test/processors/CPU32_O3_EmulatorTest.java b/Ghidra/Processors/68000/src/test.processors/java/ghidra/test/processors/CPU32_O3_EmulatorTest.java new file mode 100644 index 0000000000..086c4ab070 --- /dev/null +++ b/Ghidra/Processors/68000/src/test.processors/java/ghidra/test/processors/CPU32_O3_EmulatorTest.java @@ -0,0 +1,40 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.test.processors; + +import ghidra.test.processors.support.ProcessorEmulatorTestAdapter; +import junit.framework.Test; + +public class CPU32_O3_EmulatorTest extends ProcessorEmulatorTestAdapter { + + private static final String LANGUAGE_ID = "68000:BE:32:CPU32"; + private static final String COMPILER_SPEC_ID = "default"; + + private static final String[] REG_DUMP_SET = new String[] {}; + + public CPU32_O3_EmulatorTest(String name) throws Exception { + super(name, LANGUAGE_ID, COMPILER_SPEC_ID, REG_DUMP_SET); + } + + @Override + protected String getProcessorDesignator() { + return "CPU32_GCC_O3"; + } + + public static Test suite() { + return ProcessorEmulatorTestAdapter.buildEmulatorTestSuite(CPU32_O3_EmulatorTest.class); + } +}