From 9673ad37748ff174861067d0286904da3ecd37cf Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Thu, 6 Jun 2019 13:50:46 +0200 Subject: [PATCH] all: move Register{8,16,32} values into runtime/volatile This avoids duplication of code. None of the smoke tests have changed their output. --- src/machine/machine_atmega.go | 3 +- src/machine/machine_attiny.go | 3 +- src/machine/machine_avr.go | 5 +- src/machine/usb.go | 12 +- src/runtime/volatile/register.go | 162 +++++++++++++++++++++++++++ tools/gen-device-avr.py | 56 +--------- tools/gen-device-svd.py | 184 +++---------------------------- 7 files changed, 189 insertions(+), 236 deletions(-) create mode 100644 src/runtime/volatile/register.go diff --git a/src/machine/machine_atmega.go b/src/machine/machine_atmega.go index f330fc47..323ec9ab 100644 --- a/src/machine/machine_atmega.go +++ b/src/machine/machine_atmega.go @@ -4,6 +4,7 @@ package machine import ( "device/avr" + "runtime/volatile" ) // Configure sets the pin to input or output. @@ -34,7 +35,7 @@ func (p Pin) Get() bool { } } -func (p Pin) getPortMask() (*avr.Register8, uint8) { +func (p Pin) getPortMask() (*volatile.Register8, uint8) { if p < 8 { return avr.PORTD, 1 << uint8(p) } else { diff --git a/src/machine/machine_attiny.go b/src/machine/machine_attiny.go index bf639bcb..dd2444ac 100644 --- a/src/machine/machine_attiny.go +++ b/src/machine/machine_attiny.go @@ -4,6 +4,7 @@ package machine import ( "device/avr" + "runtime/volatile" ) // Configure sets the pin to input or output. @@ -15,7 +16,7 @@ func (p Pin) Configure(config PinConfig) { } } -func (p Pin) getPortMask() (*avr.Register8, uint8) { +func (p Pin) getPortMask() (*volatile.Register8, uint8) { return avr.PORTB, 1 << uint8(p) } diff --git a/src/machine/machine_avr.go b/src/machine/machine_avr.go index e1866e4b..7d63b040 100644 --- a/src/machine/machine_avr.go +++ b/src/machine/machine_avr.go @@ -4,6 +4,7 @@ package machine import ( "device/avr" + "runtime/volatile" ) type PinMode uint8 @@ -30,7 +31,7 @@ func (p Pin) Set(value bool) { // Warning: there are no separate pin set/clear registers on the AVR. The // returned mask is only valid as long as no other pin in the same port has been // changed. -func (p Pin) PortMaskSet() (*avr.Register8, uint8) { +func (p Pin) PortMaskSet() (*volatile.Register8, uint8) { port, mask := p.getPortMask() return port, port.Get() | mask } @@ -41,7 +42,7 @@ func (p Pin) PortMaskSet() (*avr.Register8, uint8) { // Warning: there are no separate pin set/clear registers on the AVR. The // returned mask is only valid as long as no other pin in the same port has been // changed. -func (p Pin) PortMaskClear() (*avr.Register8, uint8) { +func (p Pin) PortMaskClear() (*volatile.Register8, uint8) { port, mask := p.getPortMask() return port, port.Get() &^ mask } diff --git a/src/machine/usb.go b/src/machine/usb.go index e4fd3e1c..be1b3d5c 100644 --- a/src/machine/usb.go +++ b/src/machine/usb.go @@ -4,9 +4,9 @@ package machine import ( "bytes" - "device/sam" "encoding/binary" "errors" + "runtime/volatile" ) const deviceDescriptorSize = 18 @@ -484,11 +484,11 @@ const ( // RoReg8 Reserved1[0x5]; // } UsbDeviceDescBank; type usbDeviceDescBank struct { - ADDR sam.Register32 - PCKSIZE sam.Register32 - EXTREG sam.Register16 - STATUS_BK sam.Register8 - _reserved [5]sam.Register8 + ADDR volatile.Register32 + PCKSIZE volatile.Register32 + EXTREG volatile.Register16 + STATUS_BK volatile.Register8 + _reserved [5]volatile.Register8 } type usbDeviceDescriptor struct { diff --git a/src/runtime/volatile/register.go b/src/runtime/volatile/register.go new file mode 100644 index 00000000..57c0e7d2 --- /dev/null +++ b/src/runtime/volatile/register.go @@ -0,0 +1,162 @@ +package volatile + +// This file defines Register{8,16,32} types, which are convenience types for +// volatile register accesses. + +// Special types that causes loads/stores to be volatile (necessary for +// memory-mapped registers). +type Register8 struct { + Reg uint8 +} + +// Get returns the value in the register. It is the volatile equivalent of: +// +// *r.Reg +// +//go:inline +func (r *Register8) Get() uint8 { + return LoadUint8(&r.Reg) +} + +// Set updates the register value. It is the volatile equivalent of: +// +// *r.Reg = value +// +//go:inline +func (r *Register8) Set(value uint8) { + StoreUint8(&r.Reg, value) +} + +// SetBits reads the register, sets the given bits, and writes it back. It is +// the volatile equivalent of: +// +// r.Reg |= value +// +//go:inline +func (r *Register8) SetBits(value uint8) { + StoreUint8(&r.Reg, LoadUint8(&r.Reg)|value) +} + +// ClearBits reads the register, clears the given bits, and writes it back. It +// is the volatile equivalent of: +// +// r.Reg &^= value +// +//go:inline +func (r *Register8) ClearBits(value uint8) { + StoreUint8(&r.Reg, LoadUint8(&r.Reg)&^value) +} + +// HasBits reads the register and then checks to see if the passed bits are set. It +// is the volatile equivalent of: +// +// (*r.Reg & value) > 0 +// +//go:inline +func (r *Register8) HasBits(value uint8) bool { + return (r.Get() & value) > 0 +} + +type Register16 struct { + Reg uint16 +} + +// Get returns the value in the register. It is the volatile equivalent of: +// +// *r.Reg +// +//go:inline +func (r *Register16) Get() uint16 { + return LoadUint16(&r.Reg) +} + +// Set updates the register value. It is the volatile equivalent of: +// +// *r.Reg = value +// +//go:inline +func (r *Register16) Set(value uint16) { + StoreUint16(&r.Reg, value) +} + +// SetBits reads the register, sets the given bits, and writes it back. It is +// the volatile equivalent of: +// +// r.Reg |= value +// +//go:inline +func (r *Register16) SetBits(value uint16) { + StoreUint16(&r.Reg, LoadUint16(&r.Reg)|value) +} + +// ClearBits reads the register, clears the given bits, and writes it back. It +// is the volatile equivalent of: +// +// r.Reg &^= value +// +//go:inline +func (r *Register16) ClearBits(value uint16) { + StoreUint16(&r.Reg, LoadUint16(&r.Reg)&^value) +} + +// HasBits reads the register and then checks to see if the passed bits are set. It +// is the volatile equivalent of: +// +// (*r.Reg & value) > 0 +// +//go:inline +func (r *Register16) HasBits(value uint16) bool { + return (r.Get() & value) > 0 +} + +type Register32 struct { + Reg uint32 +} + +// Get returns the value in the register. It is the volatile equivalent of: +// +// *r.Reg +// +//go:inline +func (r *Register32) Get() uint32 { + return LoadUint32(&r.Reg) +} + +// Set updates the register value. It is the volatile equivalent of: +// +// *r.Reg = value +// +//go:inline +func (r *Register32) Set(value uint32) { + StoreUint32(&r.Reg, value) +} + +// SetBits reads the register, sets the given bits, and writes it back. It is +// the volatile equivalent of: +// +// r.Reg |= value +// +//go:inline +func (r *Register32) SetBits(value uint32) { + StoreUint32(&r.Reg, LoadUint32(&r.Reg)|value) +} + +// ClearBits reads the register, clears the given bits, and writes it back. It +// is the volatile equivalent of: +// +// r.Reg &^= value +// +//go:inline +func (r *Register32) ClearBits(value uint32) { + StoreUint32(&r.Reg, LoadUint32(&r.Reg)&^value) +} + +// HasBits reads the register and then checks to see if the passed bits are set. It +// is the volatile equivalent of: +// +// (*r.Reg & value) > 0 +// +//go:inline +func (r *Register32) HasBits(value uint32) bool { + return (r.Get() & value) > 0 +} diff --git a/tools/gen-device-avr.py b/tools/gen-device-avr.py index 6656b46f..7e32808a 100755 --- a/tools/gen-device-avr.py +++ b/tools/gen-device-avr.py @@ -156,60 +156,6 @@ import ( "unsafe" ) -// Special type that causes loads/stores to be volatile (necessary for -// memory-mapped registers). -type Register8 struct {{ - Reg uint8 -}} - -// Get returns the value in the register. It is the volatile equivalent of: -// -// *r.Reg -// -//go:inline -func (r *Register8) Get() uint8 {{ - return volatile.LoadUint8(&r.Reg) -}} - -// Set updates the register value. It is the volatile equivalent of: -// -// *r.Reg = value -// -//go:inline -func (r *Register8) Set(value uint8) {{ - volatile.StoreUint8(&r.Reg, value) -}} - -// SetBits reads the register, sets the given bits, and writes it back. It is -// the volatile equivalent of: -// -// r.Reg |= value -// -//go:inline -func (r *Register8) SetBits(value uint8) {{ - volatile.StoreUint8(&r.Reg, volatile.LoadUint8(&r.Reg) | value) -}} - -// ClearBits reads the register, clears the given bits, and writes it back. It -// is the volatile equivalent of: -// -// r.Reg &^= value -// -//go:inline -func (r *Register8) ClearBits(value uint8) {{ - volatile.StoreUint8(&r.Reg, volatile.LoadUint8(&r.Reg) &^ value) -}} - -// HasBits reads the register and then checks to see if the passed bits are set. It -// is the volatile equivalent of: -// -// (*r.Reg & value) > 0 -// -//go:inline -func (r *Register8) HasBits(value uint8) bool {{ - return (r.Get() & value) > 0 -}} - // Some information about this device. const ( DEVICE = "{name}" @@ -231,7 +177,7 @@ const ( out.write('\n\t// {description}\n'.format(**peripheral)) for register in peripheral['registers']: for variant in register['variants']: - out.write('\t{name} = (*Register8)(unsafe.Pointer(uintptr(0x{address:x})))\n'.format(**variant)) + out.write('\t{name} = (*volatile.Register8)(unsafe.Pointer(uintptr(0x{address:x})))\n'.format(**variant)) out.write(')\n') for peripheral in device.peripherals: diff --git a/tools/gen-device-svd.py b/tools/gen-device-svd.py index 5232ce44..44954a03 100755 --- a/tools/gen-device-svd.py +++ b/tools/gen-device-svd.py @@ -305,164 +305,6 @@ import ( "unsafe" ) -// Special types that causes loads/stores to be volatile (necessary for -// memory-mapped registers). -type Register8 struct {{ - Reg uint8 -}} - -// Get returns the value in the register. It is the volatile equivalent of: -// -// *r.Reg -// -//go:inline -func (r *Register8) Get() uint8 {{ - return volatile.LoadUint8(&r.Reg) -}} - -// Set updates the register value. It is the volatile equivalent of: -// -// *r.Reg = value -// -//go:inline -func (r *Register8) Set(value uint8) {{ - volatile.StoreUint8(&r.Reg, value) -}} - -// SetBits reads the register, sets the given bits, and writes it back. It is -// the volatile equivalent of: -// -// r.Reg |= value -// -//go:inline -func (r *Register8) SetBits(value uint8) {{ - volatile.StoreUint8(&r.Reg, volatile.LoadUint8(&r.Reg) | value) -}} - -// ClearBits reads the register, clears the given bits, and writes it back. It -// is the volatile equivalent of: -// -// r.Reg &^= value -// -//go:inline -func (r *Register8) ClearBits(value uint8) {{ - volatile.StoreUint8(&r.Reg, volatile.LoadUint8(&r.Reg) &^ value) -}} - -// HasBits reads the register and then checks to see if the passed bits are set. It -// is the volatile equivalent of: -// -// (*r.Reg & value) > 0 -// -//go:inline -func (r *Register8) HasBits(value uint8) bool {{ - return (r.Get() & value) > 0 -}} - -type Register16 struct {{ - Reg uint16 -}} - -// Get returns the value in the register. It is the volatile equivalent of: -// -// *r.Reg -// -//go:inline -func (r *Register16) Get() uint16 {{ - return volatile.LoadUint16(&r.Reg) -}} - -// Set updates the register value. It is the volatile equivalent of: -// -// *r.Reg = value -// -//go:inline -func (r *Register16) Set(value uint16) {{ - volatile.StoreUint16(&r.Reg, value) -}} - -// SetBits reads the register, sets the given bits, and writes it back. It is -// the volatile equivalent of: -// -// r.Reg |= value -// -//go:inline -func (r *Register16) SetBits(value uint16) {{ - volatile.StoreUint16(&r.Reg, volatile.LoadUint16(&r.Reg) | value) -}} - -// ClearBits reads the register, clears the given bits, and writes it back. It -// is the volatile equivalent of: -// -// r.Reg &^= value -// -//go:inline -func (r *Register16) ClearBits(value uint16) {{ - volatile.StoreUint16(&r.Reg, volatile.LoadUint16(&r.Reg) &^ value) -}} - -// HasBits reads the register and then checks to see if the passed bits are set. It -// is the volatile equivalent of: -// -// (*r.Reg & value) > 0 -// -//go:inline -func (r *Register16) HasBits(value uint16) bool {{ - return (r.Get() & value) > 0 -}} - -type Register32 struct {{ - Reg uint32 -}} - -// Get returns the value in the register. It is the volatile equivalent of: -// -// *r.Reg -// -//go:inline -func (r *Register32) Get() uint32 {{ - return volatile.LoadUint32(&r.Reg) -}} - -// Set updates the register value. It is the volatile equivalent of: -// -// *r.Reg = value -// -//go:inline -func (r *Register32) Set(value uint32) {{ - volatile.StoreUint32(&r.Reg, value) -}} - -// SetBits reads the register, sets the given bits, and writes it back. It is -// the volatile equivalent of: -// -// r.Reg |= value -// -//go:inline -func (r *Register32) SetBits(value uint32) {{ - volatile.StoreUint32(&r.Reg, volatile.LoadUint32(&r.Reg) | value) -}} - -// ClearBits reads the register, clears the given bits, and writes it back. It -// is the volatile equivalent of: -// -// r.Reg &^= value -// -//go:inline -func (r *Register32) ClearBits(value uint32) {{ - volatile.StoreUint32(&r.Reg, volatile.LoadUint32(&r.Reg) &^ value) -}} - -// HasBits reads the register and then checks to see if the passed bits are set. It -// is the volatile equivalent of: -// -// (*r.Reg & value) > 0 -// -//go:inline -func (r *Register32) HasBits(value uint32) bool {{ - return (r.Get() & value) > 0 -}} - // Some information about this device. const ( DEVICE = "{name}" @@ -499,22 +341,22 @@ const ( continue eSize = register['elementsize'] if eSize == 4: - regType = 'Register32' + regType = 'volatile.Register32' elif eSize == 2: - regType = 'Register16' + regType = 'volatile.Register16' elif eSize == 1: - regType = 'Register8' + regType = 'volatile.Register8' else: eSize = 4 - regType = 'Register32' + regType = 'volatile.Register32' # insert padding, if needed if address < register['address']: bytesNeeded = register['address'] - address if bytesNeeded == 1: - out.write('\t_padding{padNumber} {regType}\n'.format(padNumber=padNumber, regType='Register8')) + out.write('\t_padding{padNumber} {regType}\n'.format(padNumber=padNumber, regType='volatile.Register8')) elif bytesNeeded == 2: - out.write('\t_padding{padNumber} {regType}\n'.format(padNumber=padNumber, regType='Register16')) + out.write('\t_padding{padNumber} {regType}\n'.format(padNumber=padNumber, regType='volatile.Register16')) else: numSkip = (register['address'] - address) // eSize if numSkip == 1: @@ -531,28 +373,28 @@ const ( subaddress = register['address'] for subregister in register['registers']: if subregister['elementsize'] == 4: - subregType = 'Register32' + subregType = 'volatile.Register32' elif subregister['elementsize'] == 2: - subregType = 'Register16' + subregType = 'volatile.Register16' else: - subregType = 'Register8' + subregType = 'volatile.Register8' if subregister['array']: subregType = '[{}]{}'.format(subregister['array'], subregType) if subaddress != subregister['address']: bytesNeeded = subregister['address'] - subaddress if bytesNeeded == 1: - regType += '\t\t_padding{padNumber} {subregType}\n'.format(padNumber=padNumber, subregType='Register8') + regType += '\t\t_padding{padNumber} {subregType}\n'.format(padNumber=padNumber, subregType='volatile.Register8') elif bytesNeeded == 2: - regType += '\t\t_padding{padNumber} {subregType}\n'.format(padNumber=padNumber, subregType='Register16') + regType += '\t\t_padding{padNumber} {subregType}\n'.format(padNumber=padNumber, subregType='volatile.Register16') else: numSkip = (subregister['address'] - subaddress) if numSkip < 1: continue elif numSkip == 1: - regType += '\t\t_padding{padNumber} {subregType}\n'.format(padNumber=padNumber, subregType='Register8') + regType += '\t\t_padding{padNumber} {subregType}\n'.format(padNumber=padNumber, subregType='volatile.Register8') else: - regType += '\t\t_padding{padNumber} [{num}]{subregType}\n'.format(padNumber=padNumber, num=numSkip, subregType='Register8') + regType += '\t\t_padding{padNumber} [{num}]{subregType}\n'.format(padNumber=padNumber, num=numSkip, subregType='volatile.Register8') padNumber += 1 subaddress += bytesNeeded if subregister['array'] is not None: