Skip to content

Commit 3c51c1f

Browse files
committedJul 16, 2024·
Added debug logging feature.
1 parent 1e9e24f commit 3c51c1f

File tree

22 files changed

+887
-571
lines changed

22 files changed

+887
-571
lines changed
 

‎config/debugconfig/debugconfig.go

+140
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
/*
2+
* S370 - Debug options configuration.
3+
*
4+
* Copyright 2024, Richard Cornwell
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in
14+
* all copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
* SOFTWARE.
23+
*
24+
*/
25+
26+
package debugconfig
27+
28+
import (
29+
"errors"
30+
"strconv"
31+
"strings"
32+
33+
config "github.com/rcornwell/S370/config/configparser"
34+
"github.com/rcornwell/S370/emu/cpu"
35+
dev "github.com/rcornwell/S370/emu/device"
36+
ch "github.com/rcornwell/S370/emu/sys_channel"
37+
"github.com/rcornwell/S370/util/tape"
38+
)
39+
40+
// register a device on initialize.
41+
func init() {
42+
config.RegisterModel("DEBUG", config.TypeOptions, setDebug)
43+
}
44+
45+
// Set default port.
46+
func setDebug(devNum uint16, device string, options []config.Option) error {
47+
switch strings.ToUpper(device) {
48+
case "CHANNEL":
49+
// Process Channel debug options
50+
51+
if len(options) < 1 {
52+
return errors.New("debug channel requires a number first")
53+
}
54+
number := uint64(0)
55+
for i, opt := range options {
56+
if i == 0 {
57+
if options[0].EqualOpt != "" || len(options[0].Value) != 0 {
58+
return errors.New("debug channel number can't have equals or values")
59+
}
60+
var err error
61+
number, err = strconv.ParseUint(options[0].Name, 10, 4)
62+
if err != nil {
63+
return errors.New("channel number must be a number: " + options[0].Name)
64+
}
65+
continue
66+
}
67+
err := ch.Debug(int(number), strings.ToUpper(opt.Name))
68+
if err != nil {
69+
return err
70+
}
71+
if len(opt.Value) != 0 {
72+
for _, value := range opt.Value {
73+
err = ch.Debug(int(number), strings.ToUpper(*value))
74+
if err != nil {
75+
return err
76+
}
77+
}
78+
}
79+
}
80+
81+
case "CPU":
82+
// Process CPU debug options
83+
for _, opt := range options {
84+
err := cpu.Debug(strings.ToUpper(opt.Name))
85+
if err != nil {
86+
return err
87+
}
88+
if len(opt.Value) != 0 {
89+
for _, value := range opt.Value {
90+
err = cpu.Debug(strings.ToUpper(*value))
91+
if err != nil {
92+
return err
93+
}
94+
}
95+
}
96+
}
97+
98+
case "TAPE":
99+
// Process tape debug options
100+
for _, opt := range options {
101+
err := tape.Debug(strings.ToUpper(opt.Name))
102+
if err != nil {
103+
return err
104+
}
105+
if len(opt.Value) != 0 {
106+
for _, value := range opt.Value {
107+
err = tape.Debug(strings.ToUpper(*value))
108+
if err != nil {
109+
return err
110+
}
111+
}
112+
}
113+
}
114+
115+
default:
116+
if devNum == dev.NoDev {
117+
return errors.New("debug option invalid: " + device)
118+
}
119+
dev, err := ch.GetDevice(devNum)
120+
if err != nil {
121+
return err
122+
}
123+
124+
for _, opt := range options {
125+
err := dev.Debug(strings.ToUpper(opt.Name))
126+
if err != nil {
127+
return err
128+
}
129+
if len(opt.Value) != 0 {
130+
for _, value := range opt.Value {
131+
err = dev.Debug(strings.ToUpper(*value))
132+
if err != nil {
133+
return err
134+
}
135+
}
136+
}
137+
}
138+
}
139+
return nil
140+
}

‎emu/cpu/cpu.go

+39-140
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import (
3737
mem "github.com/rcornwell/S370/emu/memory"
3838
op "github.com/rcornwell/S370/emu/opcodemap"
3939
ch "github.com/rcornwell/S370/emu/sys_channel"
40+
"github.com/rcornwell/S370/util/debug"
4041
)
4142

4243
/*
@@ -179,6 +180,16 @@ func Shutdown() {
179180
ch.Shutdown()
180181
}
181182

183+
// Enable debug options.
184+
func Debug(opt string) error {
185+
flag, ok := debugOption[opt]
186+
if !ok {
187+
return errors.New("CPU debug option invalid: " + opt)
188+
}
189+
debugMsk |= flag
190+
return nil
191+
}
192+
182193
// Return CPU PC.
183194
func PC() uint32 {
184195
return sysCPU.PC
@@ -320,10 +331,10 @@ func (cpu *cpuState) fetch() (int, bool) {
320331
step.R1 = (step.reg >> 4) & 0xf
321332
step.R2 = step.reg & 0xf
322333

323-
// brop := (step.opcode == op.OpBC || step.opcode == op.OpBCR)
324-
// if cpu.iPC == cpu.PC && brop && (step.reg&0xf0) == 0xf0 {
325-
// return memCycle, false
326-
// }
334+
//brop := (step.opcode == op.OpBC || step.opcode == op.OpBCR)
335+
//if cpu.iPC == cpu.PC && brop && (step.reg&0xf0) == 0xf0 {
336+
// return memCycle, false
337+
//}
327338
cpu.perRegMod = 0
328339
cpu.perCode = 0
329340
cpu.perAddr = cpu.PC
@@ -349,22 +360,13 @@ func (cpu *cpuState) fetch() (int, bool) {
349360
return memCycle, true
350361
}
351362
step.address1 = (word >> 16)
352-
inst[2] = byte((word >> 24) & 0xff)
353-
inst[3] = byte((word >> 16) & 0xff)
354363
} else {
355364
step.address1 = word
356-
inst[2] = byte(word >> 8)
357-
inst[3] = byte(word & 0xff)
358365
}
359-
// if cpu.iPC != 0x0002026 {
360-
// fmt.Printf("%02x%02x ", inst[2], inst[3])
361-
// }
362366
step.address1 &= 0xffff
367+
inst[2] = byte(step.address1 >> 8)
368+
inst[3] = byte(step.address1 & 0xff)
363369
cpu.PC += 2
364-
// } else {
365-
// if cpu.iPC != 0x0002026 {
366-
// fmt.Printf(" ")
367-
// }
368370
}
369371

370372
// If SS
@@ -378,29 +380,33 @@ func (cpu *cpuState) fetch() (int, bool) {
378380
return memCycle, true
379381
}
380382
step.address2 = (word >> 16)
381-
inst[4] = byte(word >> 8)
382-
inst[5] = byte(word & 0xff)
383383
} else {
384384
step.address2 = word
385-
inst[4] = byte(word >> 8)
386-
inst[5] = byte(word & 0xff)
387385
}
388-
// if cpu.iPC != 0x0002026 {
389-
// fmt.Printf("%02x%02x ", inst[4], inst[5])
390-
// }
391386
step.address2 &= 0xffff
387+
inst[4] = byte(step.address2 >> 8)
388+
inst[5] = byte(step.address2 & 0xff)
392389
cpu.PC += 2
393-
// } else {
394-
// if cpu.iPC != 0x0002026 {
395-
// fmt.Printf(" ")
396-
// }
397390
}
398391

399392
// if cpu.iPC != 0x0002026 {
400-
symbolic, _ := dis.Disasemble(inst)
401-
symbolic += " "
402-
// fmt.Printf(" %s\n", symbolic)
403-
//}
393+
if (debugMsk & debugInst) != 0 {
394+
str := fmt.Sprintf("%08x %02x %02x ", cpu.iPC, uint32(step.opcode), uint32(step.reg))
395+
if cpu.ilc > 1 {
396+
str += fmt.Sprintf("%02x%02x ", inst[2], inst[3])
397+
} else {
398+
str += " "
399+
}
400+
if cpu.ilc > 2 {
401+
str += fmt.Sprintf("%02x%02x ", inst[4], inst[5])
402+
} else {
403+
str += " "
404+
}
405+
symbolic, _ := dis.Disasemble(inst)
406+
str += symbolic
407+
debug.Debugf("CPU", debugMsk, debugInst, str)
408+
}
409+
404410
err = cpu.execute(&step)
405411
if err != 0 {
406412
cpu.suppress(oPPSW, err)
@@ -624,7 +630,7 @@ func (cpu *cpuState) lpsw(src1, src2 uint32) {
624630
cpu.stKey = uint8((src1 >> 16) & 0xf0)
625631
cpu.flags = uint8((src1 >> 16) & 0x7)
626632
cpu.PC = src2 & AMASK
627-
// fmt.Printf("LPSW %08x: %08x %08x\n", cpu.iPC, src1, src2)
633+
debug.Debugf("CPU", debugMsk, debugDetail, "LPSW %08x: %08x %08x", cpu.iPC, src1, src2)
628634
// sim_debug(DEBUG_INST, &cpu_dev, "PSW=%08x %08x ", src1, src2)
629635
if cpu.ecMode && ((src1&0xb800c0ff) != 0 || (src2&0xff000000) != 0) {
630636
cpu.suppress(oPPSW, ircSpec)
@@ -698,7 +704,7 @@ func (cpu *cpuState) storePSW(vector uint32, irqcode uint16) (irqaddr uint32) {
698704
word1 |= uint32(extEnable) << 24
699705
}
700706

701-
//fmt.Printf("Store PSW: %08x %04x %08x %08x\n", vector, irqcode, word1, word2)
707+
debug.Debugf("CPU", debugMsk, debugDetail, "Store PSW: %08x %04x %08x %08x", vector, irqcode, word1, word2)
702708
memCycle++
703709
mem.SetMemory(vector, word1)
704710
memCycle++
@@ -1166,7 +1172,7 @@ func (cpu *cpuState) writeHalf(virtAddr, data uint32) uint16 {
11661172

11671173
offset := virtAddr & 3
11681174

1169-
// Validate address cy = dec_divstep(l int, s1 int, s2 int, v1 *[32]uint8, v2 *[32]uint8) uint8
1175+
// Validate address
11701176
physAddr, pageErr := cpu.transAddr(virtAddr)
11711177
if pageErr != 0 {
11721178
return pageErr
@@ -1320,110 +1326,3 @@ func setIPLDev(devNum uint16, _ string, _ []config.Option) error {
13201326
IPLDev = devNum
13211327
return nil
13221328
}
1323-
1324-
//
1325-
// /* Reset */
1326-
1327-
// t_stat
1328-
// cpu_reset (DEVICE *dptr)
1329-
// {
1330-
// int i;
1331-
1332-
// /* Make sure devices are mapped correctly */
1333-
// chan_set_devs();
1334-
// sim_vm_fprint_stopped = &cpu_fprint_stopped;
1335-
// /* Create memory array if it does not exist. */%s\n
1336-
// if (M == NULL) { /* first time init? */
1337-
// sim_brk_types = sim_brk_dflt = SWMASK ('E');
1338-
// M = (uint32 *) calloc (((uint32) MEMSIZE) >> 2, sizeof (uint32));
1339-
// if (M == NULL)
1340-
// return SCPE_MEM;
1341-
// }
1342-
// /* Set up channels */
1343-
// chan_set_devs();
1344-
1345-
// sysmsk = irqcode = irqaddr = loading = 0;
1346-
// st_key = cc = pmsk = ec_mode = interval_irq = flags = 0;
1347-
// page_en = irq_en = ext_en = per_en = 0;
1348-
// clk_state = CLOCK_UNSET;
1349-
// for (i = 0; i < 256; i++)
1350-
// tlb[i] = 0;
1351-
// for (i = 0; i < 4096; i++)
1352-
// key[i] = 0;
1353-
// for (i = 0; i < 16; i++)
1354-
// cregs[i] = 0;
1355-
// clk_cmp[0] = clk_cmp[1] = 0xffffffff;
1356-
// if (Q370) {
1357-
// if (clk_state == CLOCK_UNSET) {
1358-
// /* Set TOD to current time */
1359-
// time_t seconds = sim_get_time(NULL);
1360-
// t_uint64 lsec = (t_uint64)seconds;
1361-
// /* IBM measures time from 1900, Unix starts at 1970 */
1362-
// /* Add in number of years from 1900 to 1970 + 17 leap days */
1363-
// lsec += ((70 * 365) + 17) * 86400ULL;
1364-
// lsec *= 1000000ULL;
1365-
// lsec <<= 12;
1366-
// tod_clock[0] = (uint32)(lsec >> 32);
1367-
// tod_clock[1] = (uint32)(lsec & FMASK);
1368-
// clk_state = CLOCK_SET;
1369-
// }
1370-
// cregs[0] = 0x000000e0;
1371-
// cregs[2] = 0xffffffff;
1372-
// cregs[14] = 0xc2000000;
1373-
// cregs[15] = 512;
1374-
// }
1375-
1376-
// if (cpu_unit[0].flags & (FEAT_370|FEAT_TIMER)) {
1377-
// sim_rtcn_init_unit (&cpu_unit[0], 1000, TMR_RTC);
1378-
// sim_activate(&cpu_unit[0], 100);
1379-
// }
1380-
// idle_stop_tm0 = 0;
1381-
// return SCPE_OK;
1382-
// }
1383-
1384-
// /* RSV: Set CPU IDLESTOP=<val>
1385-
// * <val>=number of seconds.
1386-
// *
1387-
// * Sets max time in secounds CPU is IDLE but waiting for interrupt
1388-
// * from device. if <val> not zero, simulated CPU will wait for this wallclock
1389-
// * number of seconds, then stop. This allows to script a BOOT command and the
1390-
// * continue automatically when IPL has finished. Set to zero to disable.
1391-
// */
1392-
1393-
// t_stat cpu_set_idle_stop (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
1394-
// {
1395-
// int32 n;
1396-
// t_stat r;
1397-
1398-
// if (cptr == NULL) {
1399-
// return SCPE_ARG;
1400-
// }
1401-
// n = (int32) get_uint(cptr, 10, 60, &r);
1402-
// if (r != SCPE_OK) return SCPE_ARG;
1403-
// idle_stop_msec = n * 1000;
1404-
// idle_stop_tm0 = 0;
1405-
// return SCPE_OK;
1406-
// }
1407-
1408-
// t_bool
1409-
// cpu_fprint_stopped (FILE *st, t_stat v)
1410-
// {
1411-
// if (ec_mode) {
1412-
// if (Q370)
1413-
// fprintf(st, " PSW=%08x %08x\n",
1414-
// (((uint32)page_en) << 26) | ((per_en) ? 1<<30:0) | ((irq_en) ? 1<<25:0) |
1415-
// ((ext_en) ? 1<<24:0) | 0x80000 | (((uint32)st_key) << 16) |
1416-
// (((uint32)flags) << 16) | (((uint32)cc) << 12) | (((uint32)pmsk) << 8), PC);
1417-
// else
1418-
// fprintf(st, " PSW=%08x %08x\n",
1419-
// (((uint32)page_en) << 26) | ((irq_en) ? 1<<25:0) | ((ext_en) ? 1<<24:0) |
1420-
// (((uint32)st_key) << 16) | (((uint32)flags) << 16) |
1421-
// (((uint32)ilc) << 14) | (((uint32)cc) << 12) | (((uint32)pmsk) << 8), PC);
1422-
// } else {
1423-
// fprintf(st, " PSW=%08x %08x\n",
1424-
// ((uint32)(ext_en) << 24) | (((uint32)sysmsk & 0xfe00) << 16) |
1425-
// (((uint32)st_key) << 16) | (((uint32)flags) << 16) | ((uint32)irqcode),
1426-
// (((uint32)ilc) << 30) | (((uint32)cc) << 28) | (((uint32)pmsk) << 24) | PC);
1427-
// }
1428-
// return FALSE;
1429-
// } */

0 commit comments

Comments
 (0)
Please sign in to comment.