add to programmers manual

This commit is contained in:
Peter McGoron 2023-04-03 04:39:16 +00:00
parent 6e9d234dc0
commit 888ce66f52
1 changed files with 96 additions and 0 deletions

View File

@ -203,6 +203,102 @@ to use LiteScope to write and read values from the module. For more
information, you can look at
[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
The open source toolchain that Upsilon uses is novel and unstable.