Exemple #1
0
// buildFunction compiles the given function.
func (a *assembler) buildFunction(f *parser.Function) (err error) {
	nodes := f.Children()
	name := nodes[0].(*parser.Label)

	a.debug.SetFunctionStart(cpu.Word(len(a.code)), f.Line(), name.Data)

	for i := range nodes {
		switch tt := nodes[i].(type) {
		case *parser.Comment:
			/* ignore */

		case *parser.Label:
			a.labels[tt.Data] = cpu.Word(len(a.code))

		case *parser.Instruction:
			err = a.buildInstruction(tt.Children())

		default:
			err = NewBuildError(
				a.ast.Files[tt.File()], tt.Line(), tt.Col(),
				"Unexpected node %T. Want Comment, Label, Instruction.", tt,
			)
		}

		if err != nil {
			return
		}
	}

	a.debug.SetFunctionEnd(cpu.Word(len(a.code)), nodes[len(nodes)-1].Line())
	return
}
Exemple #2
0
// Insert loads media from the given file.
// Data is expected to be stored in Little Endian format.
//
// protected is true when the media is considered read-only.
func (d *Device) Insert(file string, protected bool) error {
	if d.state != StateNoMedia {
		return fmt.Errorf("Media already present.")
	}

	d.setState(StateBusy)
	defer d.setState(StateReady)

	data, err := ioutil.ReadFile(file)
	if err != nil {
		d.setError(ErrBroken)
		return err
	}

	if len(data) != WordCount<<1 {
		d.setError(ErrBroken)
		return fmt.Errorf("Invalid file size. Expected %d bytes.", WordCount<<1)
	}

	for i := range d.data {
		d.data[i] = cpu.Word(data[i*2]) | cpu.Word(data[i*2+1])<<8
	}

	d.protected = protected
	return nil
}
Exemple #3
0
// buildNodes compiles the given ast root nodes
func (a *assembler) buildNodes(nodes []parser.Node) (err error) {
	for i := range nodes {
		switch tt := nodes[i].(type) {
		case *parser.Comment:
			/* ignore */

		case *parser.Label:
			a.labels[tt.Data] = cpu.Word(len(a.code))

		case *parser.Function:
			err = a.buildFunction(tt)

		case *parser.Instruction:
			err = a.buildInstruction(tt.Children())

		default:
			err = NewBuildError(
				a.ast.Files[tt.File()], tt.Line(), tt.Col(),
				"Unexpected node %T. Want Comment, Label, Function or Instruction.", tt,
			)
		}

		if err != nil {
			return
		}
	}

	return
}
Exemple #4
0
func test(t *testing.T, src string, code []cpu.Word) {
	var ast parser.AST

	files, err := path.SourceFiles(src)
	if err != nil {
		t.Fatal(err)
	}

	for i := range files {
		err = ast.Parse(files[i], 0)
		if err != nil {
			t.Fatal(err)
		}
	}

	ar, err := Assemble(&ast, 0)
	if err != nil {
		t.Fatal(err)
	}

	if len(code) != len(ar.Code) {
		t.Fatalf("Code size mismatch. Expected %d, have %d\n%04x\n%04x",
			len(code), len(ar.Code), code, ar.Code)
	}

	for i := range code {
		if code[i] != cpu.Word(ar.Code[i]) {
			t.Fatalf("Code mismatch at instruction %d:\nWant: %04x\nHave: %04x", i, code, ar.Code)
		}
	}
}
Exemple #5
0
// buildData compiles the given data section
func (a *assembler) buildData(nodes []parser.Node) (err error) {
	var r rune
	nodes = nodes[1:] // Skip 'dat' instruction.

	for i := range nodes {
		expr, ok := nodes[i].(*parser.Expression)
		if !ok {
			continue
		}

		switch tt := expr.Children()[0].(type) {
		case *parser.String:
			for _, r = range tt.Data {
				a.debug.Emit(tt)
				a.code = append(a.code, cpu.Word(r))
			}

		case parser.NumericNode:
			num, err := tt.Parse()
			if err != nil {
				return err
			}

			a.debug.Emit(tt)
			a.code = append(a.code, num)
		}
	}

	return
}
Exemple #6
0
// setError changes the current error and optionally triggers an interrupt message.
func (d *Device) setError(err uint32) {
	atomic.StoreUint32(&d.error, err)

	id := cpu.Word(atomic.LoadUint32(&d.id))
	if id != 0 {
		d.int(id)
	}
}
Exemple #7
0
// setState changes the current state and optionally triggers an interrupt message.
func (d *Device) setState(state uint32) {
	atomic.StoreUint32(&d.state, state)

	id := cpu.Word(atomic.LoadUint32(&d.id))
	if id != 0 {
		d.int(id)
	}
}
Exemple #8
0
func (d *DebugInfo) getStartAddr(fileidx int) cpu.Word {
	for i := range d.SourceMapping {
		if d.SourceMapping[i].File == fileidx {
			return cpu.Word(i)
		}
	}

	return 0
}
Exemple #9
0
// Words returns the program code as a sequence of words.
func (a *Archive) Words() []cpu.Word {
	w := make([]cpu.Word, len(a.Code))

	for i, v := range a.Code {
		w[i] = cpu.Word(v)
	}

	return w
}
Exemple #10
0
func (d *Device) Handler(s *cpu.Storage) {
	switch s.A {
	case PollDevice:
		d.Lock()
		s.A = cpu.Word(d.state)
		s.B = cpu.Word(d.error)
		s.C = cpu.Word(len(d.buf))
		d.Unlock()

	case SetInterrupt:
		atomic.StoreUint32(&d.id, uint32(s.X))

	case Connect:
		go d.connect(byte(s.X>>8), byte(s.X), byte(s.Y>>8), byte(s.Y), s.Z)

	case Disconnect:
		go d.disconnect()

	case Send:
		if s.Y == 0 || s.Y > MaxBuffer {
			d.setError(ErrInvalidBufferSize)
			return
		}

		go d.send(s.Mem[s.X : s.X+s.Y])

	case Receive:
		if s.Y == 0 || s.Y > MaxBuffer {
			s.B = 0
			d.setError(ErrInvalidBufferSize)
			return
		}

		s.A = s.Y

		sz := cpu.Word(len(d.buf))
		if s.A > sz {
			s.A = sz
		}

		go d.receive(s.Mem[s.X : s.X+s.A])
	}
}
Exemple #11
0
func (d *Device) Init() error {
	glfw.SetKeyCallback(func(key, state int) {
		var value cpu.Word

		if key >= glfw.KeySpecial {
			switch key {
			case glfw.KeyBackspace:
				value = 0x10
			case glfw.KeyEnter:
				value = 0x11
			case glfw.KeyInsert:
				value = 0x12
			case glfw.KeyDel:
				value = 0x13
			case glfw.KeyUp:
				value = 0x80
			case glfw.KeyDown:
				value = 0x81
			case glfw.KeyLeft:
				value = 0x82
			case glfw.KeyRight:
				value = 0x83
			case glfw.KeyLshift, glfw.KeyRshift:
				value = 0x90
			case glfw.KeyLctrl, glfw.KeyRctrl:
				value = 0x91
			default:
				return // Not supported.
			}
		} else {
			value = cpu.Word(key)
		}

		d.state[value] = cpu.Word(state)
		d.buf = append(d.buf, value)

		// Trigger an interrupt if enabled.
		if d.id != 0 {
			d.int(d.id)
		}
	})
	return nil
}
Exemple #12
0
// Parse attempts to process the node's string data as a number.
func (n *Char) Parse() (cpu.Word, error) {
	r, size := utf8.DecodeRuneInString(n.Data)

	// If the encoding is invalid, utf8.DecodeRune yields (RuneError, 1).
	// This constitutes an impossible result for correct UTF-8.
	if r == utf8.RuneError && size == 1 {
		return 0, errors.New(fmt.Sprintf("Invalid utf8 character literal: %s", n.Data))
	}

	return cpu.Word(r), nil
}
Exemple #13
0
func TestEQU(t *testing.T) {
	doTest(t,
		`equ SomeValue, 16
		 equ AnotherValue, 'A'
		 set a, SomeValue
		 add a, AnotherValue
		`,
		cpu.Encode(cpu.SET, 0, 0x31), // set a, 16
		cpu.Encode(cpu.ADD, 0, 0x1f), // add a, 'A'
		cpu.Word('A'),
	)
}
Exemple #14
0
// Parse attempts to process the node's string data as a number.
func (n *Number) Parse() (cpu.Word, error) {
	var v uint64
	var err error

	if len(n.Data) > 2 && n.Data[0] == '0' && n.Data[1] == 'b' {
		// strconv.ParseUint can't deal with 0b01010101 formatted strings.
		// So handle these manually.
		v, err = strconv.ParseUint(n.Data[2:], 2, 64)
	} else {
		// Otherwise, just let it figure out if we have octal, decimal or hex values.
		v, err = strconv.ParseUint(n.Data, 0, 64)
	}

	return cpu.Word(v), err
}
Exemple #15
0
// buildOperand compiles the given instruction operand.
//
// The `first` parameter determines if we are parsing the A or B parameter
// in something like 'set A, B'. This makes a difference when encoding
// small literal numbers.
func (a *assembler) buildOperand(argv *[]cpu.Word, symbols *[]parser.Node, node parser.Node, first bool) (val cpu.Word, err error) {
	switch tt := node.(type) {
	case *parser.Name:
		if reg, ok := registers[tt.Data]; ok {
			return reg, nil
		}

		if addr, ok := a.labels[tt.Data]; ok {
			if !first && (addr == 0xffff || addr <= 0x1e) {
				return addr + 0x21, nil
			}

			*symbols = append(*symbols, tt)
			*argv = append(*argv, addr)
			return 0x1f, nil
		}

		a.refs[cpu.Word(len(a.code)+1+len(*argv))] = tt
		*symbols = append(*symbols, tt)
		*argv = append(*argv, 0)
		return 0x1f, nil

	case parser.NumericNode:
		num, err := tt.Parse()
		if err != nil {
			return 0, err
		}

		if !first && (num == 0xffff || num <= 0x1e) {
			return num + 0x21, nil
		}

		*symbols = append(*symbols, tt)
		*argv = append(*argv, num)
		return 0x1f, nil

	case *parser.Block:
		return a.buildBlock(argv, symbols, tt)

	default:
		return 0, NewBuildError(
			a.ast.Files[tt.File()], tt.Line(), tt.Col(),
			"Unexpected node %T. Want Name, Number or Block.", tt,
		)
	}

	return
}
Exemple #16
0
// translate retrieves the red component for each pixel in
// the given column. It then constructs an 8 bit value from
// the 8 red components.
func translate(img image.Image, x, y int) cpu.Word {
	var c [8]uint32
	c[0], _, _, _ = img.At(x, y+0).RGBA()
	c[1], _, _, _ = img.At(x, y+1).RGBA()
	c[2], _, _, _ = img.At(x, y+2).RGBA()
	c[3], _, _, _ = img.At(x, y+3).RGBA()
	c[4], _, _, _ = img.At(x, y+4).RGBA()
	c[5], _, _, _ = img.At(x, y+5).RGBA()
	c[6], _, _, _ = img.At(x, y+6).RGBA()
	c[7], _, _, _ = img.At(x, y+7).RGBA()

	return cpu.Word(((c[0]&1)<<0 | (c[1]&1)<<1 |
		(c[2]&1)<<2 | (c[3]&1)<<3 |
		(c[4]&1)<<4 | (c[5]&1)<<5 |
		(c[6]&1)<<6 | (c[7]&1)<<7) & 0xff)
}
Exemple #17
0
func (a *assembler) buildBlockOperand(argv *[]cpu.Word, symbols *[]parser.Node, node parser.Node) (cpu.Word, error) {
	switch tt := node.(type) {
	case *parser.Name:
		if reg, ok := registers[tt.Data]; ok {
			if reg <= 0x7 {
				return reg + 0x10, nil
			}

			if reg == 0x1b {
				return 0x1a, nil
			}

			return 0, NewBuildError(
				a.ast.Files[tt.File()], tt.Line(), tt.Col(),
				"Illegal use of register %q.", tt.Data,
			)
		}

		if addr, ok := a.labels[tt.Data]; ok {
			*symbols = append(*symbols, tt)
			*argv = append(*argv, addr)
			return 0, nil
		}

		a.refs[cpu.Word(len(a.code)+1+len(*argv))] = tt
		*symbols = append(*symbols, tt)
		*argv = append(*argv, 0)
		return 0, nil

	case parser.NumericNode:
		num, err := tt.Parse()
		if err != nil {
			return 0, err
		}

		*symbols = append(*symbols, tt)
		*argv = append(*argv, num)
		return 0, nil
	}

	return 0, NewBuildError(
		a.ast.Files[node.File()], node.Line(), node.Col(),
		"Unexpected node %T. Want Name or Number.", node,
	)
}
Exemple #18
0
func TestWrite(t *testing.T) {
	var fdd HMU1440
	err := fdd.Open("test.fdd")

	if err != nil {
		t.Fatal(err)
	}

	defer fdd.Close()

	var buf [SectorSize]cpu.Word
	for i := range buf {
		buf[i] = cpu.Word(i)
	}

	if err = fdd.Write(2, buf[:]); err != nil {
		t.Errorf("write: %v", err)
		return
	}
}
Exemple #19
0
func (k *Keyboard) Handler(s *cpu.Storage) {
	switch s.A {
	case ClearBuffer:
		k.buf = k.buf[:0]

	case GetNextKey:
		s.C = 0
		if sz := len(k.buf); sz > 0 {
			s.C = k.buf[0]
			copy(k.buf, k.buf[1:])
			k.buf = k.buf[:sz-1]
		}

	case GetKeyState:
		s.C = 0
		if int(s.B) < len(k.keys) {
			s.C = cpu.Word(k.keys[s.B] & 1)
		}

	case SetInterruptId:
		k.id = s.B
	}
}
Exemple #20
0
func (v *Vertex) toWords() (a, b cpu.Word) {
	a = cpu.Word(v.Y)<<8 | cpu.Word(v.X)
	b = cpu.Word(v.Intensity)<<10 | cpu.Word(v.Color)<<8 | cpu.Word(v.Z)
	return
}
Exemple #21
0
// Encode encodes vidmem cell components into a single word.
func Encode(fg, bg, blink, char byte) cpu.Word {
	return cpu.Word(char&127) | cpu.Word(blink&1)<<7 |
		cpu.Word(bg&15)<<8 | cpu.Word(fg&15)<<12
}
Exemple #22
0
// buildBlock builds a block expression.
func (a *assembler) buildBlock(argv *[]cpu.Word, symbols *[]parser.Node, b *parser.Block) (val cpu.Word, err error) {
	nodes := b.Children()

	switch len(nodes) {
	case 1:
		switch tt := nodes[0].(type) {
		case *parser.Name:
			if reg, ok := registers[tt.Data]; ok {
				return reg + 0x08, nil
			}

			if addr, ok := a.labels[tt.Data]; ok {
				*symbols = append(*symbols, tt)
				*argv = append(*argv, addr)
				return 0x1e, nil
			}

			a.refs[cpu.Word(len(a.code)+1+len(*argv))] = tt
			*symbols = append(*symbols, tt)
			*argv = append(*argv, 0)
			return 0x1e, nil

		case parser.NumericNode:
			num, err := tt.Parse()
			if err != nil {
				return 0, err
			}

			*symbols = append(*symbols, tt)
			*argv = append(*argv, num)
			return 0x1e, nil

		default:
			return 0, NewBuildError(
				a.ast.Files[tt.File()], tt.Line(), tt.Col(),
				"Unexpected node %T. Want Name, Number or Block.", tt,
			)
		}

	case 3:
		var va, vb cpu.Word

		if va, err = a.buildBlockOperand(argv, symbols, nodes[0]); err != nil {
			return
		}

		if vb, err = a.buildBlockOperand(argv, symbols, nodes[2]); err != nil {
			return
		}

		if va != 0 {
			return va, nil
		}

		return vb, nil

	default:
		err = NewBuildError(
			a.ast.Files[b.File()], b.Line(), b.Col(),
			"Unexpected node count. Want 1 or 3. Got %d", len(nodes))
	}

	return
}
Exemple #23
0
// Read reads the binary version of a profile into a Profile structure.
//
// See the documentation on prof.Write for details on the file format.
func Read(r io.Reader) (p *Profile, err error) {
	var size uint32
	p = new(Profile)

	// [1]
	if err = binary.Read(r, be, &size); err != nil {
		return
	}

	p.Files = make([]asm.FileInfo, size)

	// [2]
	for i := range p.Files {
		if err = binary.Read(r, be, &p.Files[i].StartAddr); err != nil {
			return
		}

		var size uint16
		if err = binary.Read(r, be, &size); err != nil {
			return
		}

		d := make([]byte, size)
		if _, err = r.Read(d); err != nil {
			return
		}

		p.Files[i].Name = string(d)
	}

	// [3]
	if err = binary.Read(r, be, &size); err != nil {
		return
	}

	p.Functions = make([]asm.FuncInfo, size)

	// [4]
	for i := range p.Functions {
		if err = binary.Read(r, be, &p.Functions[i].StartAddr); err != nil {
			return
		}

		if err = binary.Read(r, be, &p.Functions[i].EndAddr); err != nil {
			return
		}

		var line uint32
		if err = binary.Read(r, be, &line); err != nil {
			return
		}
		p.Functions[i].StartLine = int(line)

		if err = binary.Read(r, be, &line); err != nil {
			return
		}
		p.Functions[i].EndLine = int(line)

		var size uint16
		if err = binary.Read(r, be, &size); err != nil {
			return
		}

		d := make([]byte, size)
		if _, err = r.Read(d); err != nil {
			return
		}

		p.Functions[i].Name = string(d)
	}

	// [5]
	if err = binary.Read(r, be, &size); err != nil {
		return
	}

	p.Data = make([]ProfileData, size)

	// [6]
	var d [30]byte
	for i := range p.Data {
		if _, err = r.Read(d[:]); err != nil {
			return
		}

		var pd ProfileData

		pd.Data = cpu.Word(d[0])<<8 | cpu.Word(d[1])
		pd.File = int(d[2])<<24 | int(d[3])<<16 | int(d[4])<<8 | int(d[5])
		pd.Line = int(d[6])<<24 | int(d[7])<<16 | int(d[8])<<8 | int(d[9])
		pd.Col = int(d[10])<<24 | int(d[11])<<16 | int(d[12])<<8 | int(d[13])

		pd.Count = uint64(d[14])<<56 | uint64(d[15])<<48 | uint64(d[16])<<40 |
			uint64(d[17])<<32 | uint64(d[18])<<24 | uint64(d[19])<<16 |
			uint64(d[20])<<8 | uint64(d[21])

		pd.Penalty = uint64(d[22])<<56 | uint64(d[23])<<48 | uint64(d[24])<<40 |
			uint64(d[25])<<32 | uint64(d[26])<<24 | uint64(d[27])<<16 |
			uint64(d[28])<<8 | uint64(d[29])

		p.Data[i] = pd
	}

	p.setInstructionSizes()
	return
}