Debugger Complete
This commit is contained in:
parent
54a91e53c7
commit
22dd9915c3
@ -3,6 +3,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -23,6 +24,7 @@ var instructions, lastInst []string
|
|||||||
var curr, cursor int
|
var curr, cursor int
|
||||||
var pause, step, skip bool
|
var pause, step, skip bool
|
||||||
var breakpoints []int
|
var breakpoints []int
|
||||||
|
var eventChan chan termbox.Event
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
var debug bool
|
var debug bool
|
||||||
@ -49,12 +51,13 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
defer termbox.Close()
|
defer termbox.Close()
|
||||||
eventChan := make(chan termbox.Event)
|
eventChan = make(chan termbox.Event)
|
||||||
go readUserInput(eventChan)
|
go readUserInput(eventChan)
|
||||||
go sendNoneEvent(eventChan)
|
go sendNoneEvent(eventChan)
|
||||||
curr = 0
|
curr = 0
|
||||||
var ins []string
|
var ins []string
|
||||||
for curr < len(instructions) || done {
|
for curr < len(instructions) || done {
|
||||||
|
isBreak := isBreakpoint(curr)
|
||||||
if debug {
|
if debug {
|
||||||
lastInst = ins
|
lastInst = ins
|
||||||
}
|
}
|
||||||
@ -62,68 +65,20 @@ func main() {
|
|||||||
if len(ins) == 0 {
|
if len(ins) == 0 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
// Optimize multiplication
|
if isMultOp(curr) {
|
||||||
/*
|
curr = doMultOp(curr)
|
||||||
> cpy b c
|
|
||||||
inc a
|
|
||||||
dec c
|
|
||||||
jnz c -2
|
|
||||||
dec d
|
|
||||||
jnz d -5
|
|
||||||
== add (b * d) to a
|
|
||||||
set c & d to 0
|
|
||||||
curr += 5
|
|
||||||
*/
|
|
||||||
if ins[0] == "cpy" {
|
|
||||||
if len(instructions) >= curr+6 {
|
|
||||||
ins1 := strings.Fields(instructions[curr+1])
|
|
||||||
ins2 := strings.Fields(instructions[curr+2])
|
|
||||||
ins3 := strings.Fields(instructions[curr+3])
|
|
||||||
ins4 := strings.Fields(instructions[curr+4])
|
|
||||||
ins5 := strings.Fields(instructions[curr+5])
|
|
||||||
if ins1[0] == "inc" && ins2[0] == "dec" && ins3[0] == "jnz" && ins4[0] == "dec" && ins5[0] == "jnz" {
|
|
||||||
allGood := true
|
|
||||||
if allGood {
|
|
||||||
// Do the multiplication
|
|
||||||
// ins[1] * ins4[1]
|
|
||||||
// add that value to ins1[1]
|
|
||||||
// set ins[2] to 0
|
|
||||||
// set ins4[1] to 0
|
|
||||||
// Then add 5 to the pc
|
|
||||||
src1 := ins[1]
|
|
||||||
src2 := ins4[1]
|
|
||||||
dst := ins1[1]
|
|
||||||
if _, ok := regs[dst]; !ok {
|
|
||||||
// Invalid destination register
|
|
||||||
allGood = false
|
|
||||||
}
|
|
||||||
if _, ok := regs[src1]; !ok {
|
|
||||||
// Invalid source register
|
|
||||||
allGood = false
|
|
||||||
}
|
|
||||||
if _, ok := regs[src2]; !ok {
|
|
||||||
allGood = false
|
|
||||||
}
|
|
||||||
if allGood {
|
|
||||||
regs[dst] += (regs[src1] * regs[src2])
|
|
||||||
curr += 6
|
|
||||||
skip = true
|
skip = true
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if debug {
|
if debug {
|
||||||
if isBreakpoint(curr + 1) {
|
if isBreak {
|
||||||
pause = true
|
pause = true
|
||||||
step = false
|
step = false
|
||||||
}
|
}
|
||||||
for pause && !step {
|
for pause && !step && !done {
|
||||||
// print state and wait for user to step
|
// print state and wait for user to step
|
||||||
PrintState()
|
PrintState()
|
||||||
fmt.Println("Last Instruction:", lastInst)
|
|
||||||
PrintInstructionState()
|
PrintInstructionState()
|
||||||
fmt.Println("(q): quit (space): pause/unpause (s): step (b): toggle breakpoint")
|
PrintDebugHelp()
|
||||||
ev := <-eventChan
|
ev := <-eventChan
|
||||||
if ev.Type == termbox.EventKey {
|
if ev.Type == termbox.EventKey {
|
||||||
switch {
|
switch {
|
||||||
@ -135,6 +90,8 @@ func main() {
|
|||||||
toggleBreakpoint(cursor)
|
toggleBreakpoint(cursor)
|
||||||
case ev.Ch == 's':
|
case ev.Ch == 's':
|
||||||
step = true
|
step = true
|
||||||
|
case ev.Ch == 'u':
|
||||||
|
updateRegister()
|
||||||
case ev.Key == termbox.KeyArrowUp:
|
case ev.Key == termbox.KeyArrowUp:
|
||||||
if cursor > 0 {
|
if cursor > 0 {
|
||||||
cursor--
|
cursor--
|
||||||
@ -268,6 +225,7 @@ func PrintRegs() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func PrintInstructionState() {
|
func PrintInstructionState() {
|
||||||
|
optim := color.New(color.FgGreen)
|
||||||
for pi := range instructions {
|
for pi := range instructions {
|
||||||
if pi == curr {
|
if pi == curr {
|
||||||
fmt.Print(">")
|
fmt.Print(">")
|
||||||
@ -281,12 +239,28 @@ func PrintInstructionState() {
|
|||||||
}
|
}
|
||||||
if cursor == pi {
|
if cursor == pi {
|
||||||
cursor := color.New(color.FgBlack).Add(color.BgWhite)
|
cursor := color.New(color.FgBlack).Add(color.BgWhite)
|
||||||
|
if isMultOp(pi) {
|
||||||
|
cursor.Println("+ " + instructions[pi] + " == optimized")
|
||||||
|
} else if mo, _ := isInMultOp(pi); mo {
|
||||||
|
cursor.Println("| " + instructions[pi])
|
||||||
|
} else {
|
||||||
cursor.Println(instructions[pi])
|
cursor.Println(instructions[pi])
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if isMultOp(pi) {
|
||||||
|
optim.Println("+ " + instructions[pi] + " == optimized")
|
||||||
|
} else if mo, _ := isInMultOp(pi); mo {
|
||||||
|
optim.Println("| " + instructions[pi])
|
||||||
} else {
|
} else {
|
||||||
fmt.Println(instructions[pi])
|
fmt.Println(instructions[pi])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fmt.Println(instructions[curr])
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func PrintDebugHelp() {
|
||||||
|
fmt.Println("(s): step | (space): pause/unpause | (b): toggle breakpoint")
|
||||||
|
fmt.Println("(u): update register to value | (q): quit")
|
||||||
}
|
}
|
||||||
|
|
||||||
func readUserInput(e chan termbox.Event) {
|
func readUserInput(e chan termbox.Event) {
|
||||||
@ -304,7 +278,111 @@ func sendNoneEvent(e chan termbox.Event) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// isInMultOp returns true and the pc for the
|
||||||
|
// start of the multiplication operation if pos is
|
||||||
|
// located within it
|
||||||
|
func isInMultOp(pos int) (bool, int) {
|
||||||
|
// We need to check instructions[pos +- 5] to see if any
|
||||||
|
// are a multiplication op and return the pos for the (first) one
|
||||||
|
// that is
|
||||||
|
if isMultOp(pos) {
|
||||||
|
return true, pos
|
||||||
|
}
|
||||||
|
for i := 1; i < 6; i++ {
|
||||||
|
if isMultOp(pos - i) {
|
||||||
|
return true, (pos - i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false, pos
|
||||||
|
}
|
||||||
|
|
||||||
|
// isMultOpStart return whether pos is the start of
|
||||||
|
// what can be optimized as multiplication
|
||||||
|
/*
|
||||||
|
> cpy b c
|
||||||
|
inc a
|
||||||
|
dec c
|
||||||
|
jnz c -2
|
||||||
|
dec d
|
||||||
|
jnz d -5
|
||||||
|
== add (b * d) to a
|
||||||
|
set c & d to 0
|
||||||
|
curr += 5
|
||||||
|
*/
|
||||||
|
func isMultOp(pos int) bool {
|
||||||
|
if pos < 0 || pos > len(instructions)-1 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
ins := strings.Fields(instructions[pos])
|
||||||
|
if len(ins) < 3 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if ins[0] == "cpy" {
|
||||||
|
if len(instructions) >= pos+6 {
|
||||||
|
ins1 := strings.Fields(instructions[pos+1])
|
||||||
|
ins2 := strings.Fields(instructions[pos+2])
|
||||||
|
ins3 := strings.Fields(instructions[pos+3])
|
||||||
|
ins4 := strings.Fields(instructions[pos+4])
|
||||||
|
ins5 := strings.Fields(instructions[pos+5])
|
||||||
|
if ins1[0] == "inc" && ins2[0] == "dec" && ins3[0] == "jnz" && ins4[0] == "dec" && ins5[0] == "jnz" {
|
||||||
|
allGood := true
|
||||||
|
if allGood {
|
||||||
|
// Do the multiplication
|
||||||
|
// ins[1] * ins4[1]
|
||||||
|
// add that value to ins1[1]
|
||||||
|
// set ins[2] to 0
|
||||||
|
// set ins4[1] to 0
|
||||||
|
// Then add 5 to the pc
|
||||||
|
src1 := ins[1]
|
||||||
|
src2 := ins4[1]
|
||||||
|
dst := ins1[1]
|
||||||
|
if _, ok := regs[dst]; !ok {
|
||||||
|
// Invalid destination register
|
||||||
|
allGood = false
|
||||||
|
}
|
||||||
|
if _, ok := regs[src1]; !ok {
|
||||||
|
// Invalid source register
|
||||||
|
allGood = false
|
||||||
|
}
|
||||||
|
if _, ok := regs[src2]; !ok {
|
||||||
|
allGood = false
|
||||||
|
}
|
||||||
|
return allGood
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// doMultOp performs a multiplcation operation and returns the new pc
|
||||||
|
func doMultOp(pos int) int {
|
||||||
|
isOp, pos := isInMultOp(pos)
|
||||||
|
if !isOp {
|
||||||
|
// No optimization to do
|
||||||
|
return pos
|
||||||
|
}
|
||||||
|
ins := strings.Fields(instructions[pos])
|
||||||
|
ins1 := strings.Fields(instructions[pos+1])
|
||||||
|
ins4 := strings.Fields(instructions[pos+4])
|
||||||
|
// Do the multiplication
|
||||||
|
// ins[1] * ins4[1]
|
||||||
|
// add that value to ins1[1]
|
||||||
|
// set ins[2] to 0
|
||||||
|
// set ins4[1] to 0
|
||||||
|
// Then add 5 to the pc
|
||||||
|
src1 := ins[1]
|
||||||
|
src2 := ins4[1]
|
||||||
|
dst := ins1[1]
|
||||||
|
regs[dst] += (regs[src1] * regs[src2])
|
||||||
|
regs[ins[2]] = 0
|
||||||
|
regs[ins4[1]] = 0
|
||||||
|
pos += 6
|
||||||
|
return pos
|
||||||
|
}
|
||||||
|
|
||||||
func toggleBreakpoint(pos int) {
|
func toggleBreakpoint(pos int) {
|
||||||
|
_, pos = isInMultOp(pos)
|
||||||
for i := 0; i < len(breakpoints); i++ {
|
for i := 0; i < len(breakpoints); i++ {
|
||||||
if breakpoints[i] == pos {
|
if breakpoints[i] == pos {
|
||||||
breakpoints = append(breakpoints[:i], breakpoints[i+1:]...)
|
breakpoints = append(breakpoints[:i], breakpoints[i+1:]...)
|
||||||
@ -315,6 +393,7 @@ func toggleBreakpoint(pos int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func isBreakpoint(pos int) bool {
|
func isBreakpoint(pos int) bool {
|
||||||
|
_, pos = isInMultOp(pos)
|
||||||
for i := 0; i < len(breakpoints); i++ {
|
for i := 0; i < len(breakpoints); i++ {
|
||||||
if breakpoints[i] == pos {
|
if breakpoints[i] == pos {
|
||||||
return true
|
return true
|
||||||
@ -322,3 +401,48 @@ func isBreakpoint(pos int) bool {
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func updateRegister() {
|
||||||
|
var updReg string
|
||||||
|
fmt.Println("Update which register? (a,b,c,d)")
|
||||||
|
ev := <-eventChan
|
||||||
|
if ev.Type == termbox.EventKey {
|
||||||
|
switch {
|
||||||
|
case ev.Ch == 'a':
|
||||||
|
updReg = "a"
|
||||||
|
case ev.Ch == 'b':
|
||||||
|
updReg = "b"
|
||||||
|
case ev.Ch == 'c':
|
||||||
|
updReg = "c"
|
||||||
|
case ev.Ch == 'd':
|
||||||
|
updReg = "d"
|
||||||
|
default:
|
||||||
|
fmt.Println("Invalid register (" + string(ev.Ch) + ")")
|
||||||
|
fmt.Println("Press any key to continue")
|
||||||
|
ev = <-eventChan
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("Enter new value (must be integer, end with enter)")
|
||||||
|
var newVal string
|
||||||
|
for ev.Key != termbox.KeyEnter {
|
||||||
|
ev = <-eventChan
|
||||||
|
if ev.Ch >= '0' && ev.Ch <= '9' {
|
||||||
|
newVal += string(ev.Ch)
|
||||||
|
fmt.Print(string(ev.Ch))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Println("Setting Register (" + updReg + ") to " + newVal)
|
||||||
|
var v int
|
||||||
|
var e error
|
||||||
|
if v, e = strconv.Atoi(newVal); e != nil {
|
||||||
|
fmt.Println()
|
||||||
|
fmt.Println("Error parsing integer")
|
||||||
|
fmt.Println(e)
|
||||||
|
fmt.Println("Press any key to continue")
|
||||||
|
ev = <-eventChan
|
||||||
|
return
|
||||||
|
}
|
||||||
|
regs[updReg] = v
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user