add to programmers manual
This commit is contained in:
parent
6e9d234dc0
commit
888ce66f52
|
@ -203,6 +203,102 @@ to use LiteScope to write and read values from the module. For more
|
||||||
information, you can look at
|
information, you can look at
|
||||||
[the boothmul test](https://software.mcgoron.com/peter/boothmul/src/branch/master/arty_test).
|
[the boothmul test](https://software.mcgoron.com/peter/boothmul/src/branch/master/arty_test).
|
||||||
|
|
||||||
|
# Software Programming
|
||||||
|
|
||||||
|
The "software" is the code written in C that runs on the FPGA. This
|
||||||
|
handles access to hardware components, running scripts sent by the
|
||||||
|
controlling computer, and sending information between the hardware and
|
||||||
|
the controlling computer.
|
||||||
|
|
||||||
|
## Crash Course in Multithreaded Programming
|
||||||
|
|
||||||
|
Each script (up to 32 by default, change by redefining a macro) runs in
|
||||||
|
a separate thread. This allows for multiple scripts to execute without
|
||||||
|
having to explicitly hand control from one component to another, but
|
||||||
|
since there is no defined execution path (one thread may execute before
|
||||||
|
or after another thread), the program must handle scripts attempting to
|
||||||
|
access the same component.
|
||||||
|
|
||||||
|
Upsilon handles multiple threads using
|
||||||
|
|
||||||
|
1. Mutexes
|
||||||
|
2. Thread Local Storage
|
||||||
|
|
||||||
|
Mutexes ("mutual exclusion") are objects that only allow for one thread
|
||||||
|
to access them at a time. When one thread locks a mutex, other threads
|
||||||
|
attempting to lock the mutex sleep until the thread unlocks the mutex.
|
||||||
|
After the thread that locked the mutex unlocks it, some other thread gets
|
||||||
|
the mutex.
|
||||||
|
|
||||||
|
Mutex management is important because if multiple threads attempt to
|
||||||
|
read or write to a converter at the same time, the scripts could deadlock,
|
||||||
|
requiring a hard reset of the system. (You could add manual deadlock
|
||||||
|
aborting by adding new commands that call `k_thread_abort`, as long as
|
||||||
|
all threads are not deadlocked. This is a hack but may be necessary.)
|
||||||
|
|
||||||
|
Each thread can lock the mutex as many times as it wants, but it must
|
||||||
|
unlock the mutex the same number of times. Thread local storage (the
|
||||||
|
`__thread` modifier) is used to count the number of times that each mutex
|
||||||
|
is locked by a thread. Since (as the name implies) TLS is thread-local,
|
||||||
|
there is no need to control access to it by mutexes: each thread gets
|
||||||
|
its own local version of the thread local variables.
|
||||||
|
|
||||||
|
The software has to count the number of recursive locks because when
|
||||||
|
the thread finally releases control of the mutex, another thread must
|
||||||
|
be able to access the hardware in a well defined state: it should not
|
||||||
|
attempt to write to hardware while the hardware is running (certain
|
||||||
|
specific exceptions apply). When the unlock routines (see for example
|
||||||
|
`waveform_release()`) reach the final unlock
|
||||||
|
(e.g. `waveform_locked[i] == 1`), the software waits for the hardware
|
||||||
|
to finish what its doing before unlocking.
|
||||||
|
|
||||||
|
## Crash Course in Network Programming
|
||||||
|
|
||||||
|
The kernel communicates with the controlling computer using a TCP/IP
|
||||||
|
connection. You should connect the controller and the computer to a
|
||||||
|
router and assign the kernel a static IP.
|
||||||
|
|
||||||
|
Each script that runs on the kernel is a separate connection. Each
|
||||||
|
connection runs on a separate thread, because each thread runs a Creole
|
||||||
|
interpreter.
|
||||||
|
|
||||||
|
## Logging
|
||||||
|
|
||||||
|
Logging is done via UART. Connect the micro-USB slot to the controlling
|
||||||
|
computer to get debug output.
|
||||||
|
|
||||||
|
# Controlling Computer
|
||||||
|
|
||||||
|
## Creole
|
||||||
|
|
||||||
|
Creole is the bytecode that the kernel runs. It is written using a
|
||||||
|
python library. It looks very similar to assembly, but is custom built
|
||||||
|
to make it easier to write direct assembly code.
|
||||||
|
|
||||||
|
Creole programs are the scripts run by the kernel to communicate with
|
||||||
|
hardware and send messages over Ethernet to the controlling computer.
|
||||||
|
Each creole program should do one thing: i.e. monitor an ADC, run
|
||||||
|
the raster scan, output waveforms, etc.
|
||||||
|
|
||||||
|
Creole programs should reserve the hardware modules (DAC, ADC, CLOOP,
|
||||||
|
waveforms) that they use explicitly. This makes your program faster
|
||||||
|
and less error prone.
|
||||||
|
|
||||||
|
Since the Creole assembler is a python library, you can use things
|
||||||
|
like Python format strings to automate production of Creole code. You
|
||||||
|
can also add virtual instructions (by directly modifying the library)
|
||||||
|
easily.
|
||||||
|
|
||||||
|
Creole has a concept of data blocks, assigned using the `DB` command.
|
||||||
|
These blocks are used for waveforms and for printing sets of data out
|
||||||
|
to the datastream.
|
||||||
|
|
||||||
|
Creole uses a [self-synchronizing code][ssc] to detect encoding and
|
||||||
|
transmission errors. This makes programs bigger, but you should not
|
||||||
|
write big Creole programs.
|
||||||
|
|
||||||
|
[ssc]: https://en.wikipedia.org/wiki/Self-synchronizing_code
|
||||||
|
|
||||||
# Hacks and Pitfalls
|
# Hacks and Pitfalls
|
||||||
|
|
||||||
The open source toolchain that Upsilon uses is novel and unstable.
|
The open source toolchain that Upsilon uses is novel and unstable.
|
||||||
|
|
Loading…
Reference in New Issue