Let's Design and Build a (mostly) Digital Theremin!

Posted: 6/6/2017 3:28:06 PM

From: 60 Miles North of San Diego, CA

Joined: 10/1/2014

I showed you my path to wealth which could have financed your project but it is gone now, you may have been distracted by the trees. Some day when you are tired the two great walls to climb, in front of you, will be packaging and marketing.

Posted: 6/6/2017 4:09:49 PM

From: Northern NJ, USA

Joined: 2/17/2012

"I showed you my path to wealth which could have financed your project but it is gone now, you may have been distracted by the trees."

I appreciate that, but at this point even a guaranteed get-rich-quick scheme is a distraction.  I'm not rich but I've got enough money.

"Some day when you are tired the two great walls to climb, in front of you, will be packaging and marketing."

Yes, not exactly looking forward to that.  One of the few things I miss about working for a large company is the way other departments would handle physical design, manufacturing, and sales.


Posted: 6/12/2017 8:52:01 PM

From: Northern NJ, USA

Joined: 2/17/2012

Variables and Pointers

At it's most basic and mechanical, programming is assigning data values to memory slots.  Memory slots are consecutively numbered from zero, and this numbering is the address.  Addresses are obviously unique, and an address can hold any data value. Addresses are generally full-width (i.e. 32 bits wide in a 32 bit machine) but the value at the memory address can span one or more address slots, be signed or unsigned, etc.  In other words data is "typed" or needs extra information to properly evaluate it.

Programming languages support names that are convenient aliases for constant and variable data values, which may or may not exist at actual memory addresses.  Opcode (processor instruction) data is inferred from the code.  Data may be used to statically size constructs like arrays, and in this case serve more as a build parameter that gets removed at compile time.  Data may make it through compilation and remain fixed (a constant) or it may be changed during run time (a variable).  Data may exist in memory, or may only "live" for a time in processor registers.  Data values in memory may be indexed by the address, immediate (contained in the opcode), or in-line literals (following the opcode).

The C language is something of an odd man out in that it has pointers and allows limited math to be performed on them.  Pointers are just alias names for address values.  Even though addresses are full-width, pointers are typed - why?  So that it's clear what kind of data is being pointed to, and how to do math on the address.  Pointers can also be the address of a subroutine or function, and in that case are typed according to the return value.

Say we want an integer variable in C named "d":

  int d;  // create int

We can assign it the value 5:

  d = 5;  // assign data

The address at this point is implicit, and we often don't care what it is.

We can create a pointer named "a" with the star:

  int * a;  // create pointer to int

We can assign it the address of d with the ampersand:

  a = &d;  // assign address

If we want the data of the thing pointed to we again use the star:

  * a  // dereference

which is equal to 5.

So we can define a variable name or pointer name without assigning them address nor data, nor even linking them, which is kind of interesting.

Array names are actually pointers, and demonstrate one use of pointer math:

  int b[4];  // create array of 4 ints

Here "b" is a pointer to an int.  We can assign a value to one element via indexing:

  b[2] = 6;  // assign data

Or via pointer math:

  *(b + 2) = 6;  // assign data

When we pass an array to a function we're actually passing it the address of the array, so the array contents can be changed by the function!  Presumably this was done to limit needless copying large structures when calling functions, but it's a coding hazard.

I can see where they came from, and how they might be used, but I've never liked pointers in C and have avoided them as much as possible.  For one thing I find the choice of syntax confusing.  Why didn't they use @ instead of star?  Maybe use the ampersand for declaration?  Having pointers running around uncoupled seems dangerous, and mechanisms such as scoping can cause decoupling.  Indeed, the use of pointers in C++ is discouraged.  One blog comment I read recently stated that modern control structures (if, then, else, while, etc.) have made code more readable and have largely eliminated the need for GOTO and the like, which are too wide open and unstructured.  And the object oriented approach has done the same for data structures, largely eliminating the need for pointers. 

I discuss the above because I'm still grappling with how to deal with pointer syntax in my HAL assembly language.  Really I just need a way to reserve, initialize, and link to a section of memory, and I already have this, but I'm looking to better integrate it into the assembly process.  Looking at other assembly languages doesn't help much because they tend to be clunky and super low-level, with really arcane syntax.

Posted: 6/15/2017 1:10:11 PM

From: Northern NJ, USA

Joined: 2/17/2012

Pointer Syntax

There's a lot of shorthand going on in the syntax of programming languages.  Terse languages make for easier typing, but this can kind of obscure what is going on.  Some shorthand going on with C arrays is that reference to the naked array name is to the base pointer, or address of the first element of the array.  Reference to the indexed array name is to the data in the array:

  int a[3];  // array of ints

  a = 0xf5;  // set value of base address

  a[2] = 7;  // set value of data at location 2

This is kind of odd because you might think that putting braces on a pointer would give you an array of pointers, rather than an array of data with a pointer to the first element.

I've decided to adopt this type of array / pointer syntax for HAL labels, with an '@' at the head to aid parsing, and sizing via the assignment statement rather than via typing:

  @thd_0 := 0xd56a  // declare label and assign address

  @thd_0[4] :b= {1, 0}  // reserve 4 bytes, initialize to 1, 0, 0, 0

The first step above isn't necessary, if it's omitted then the label address is implicit.  Here is an example of the style in a subroutine:

This provides for handy descriptive naming of subroutine labels, as well as very welcomed ad-hoc "scoping" of the label name space within.  My previous labels took the form "LBL[#]" with unique numbering, and I found myself wasting a lot of time micromanaging the global assignment / sequencing of those numbers.  I plan on using the C++ "unordered_map" to handle label value lookup during assembly.

Posted: 6/22/2017 11:38:12 PM

From: Northern NJ, USA

Joined: 2/17/2012

Went through and really cleaned up the assembly language interpreter C++ code.  What I've been calling the "tokenizer" is generally known in the parlance as a "lexer".  Played around with alternate methods to recognize multi-character operators but fell back to what I was doing in the first place, which is to put spaces around symbols, tokenize (based on spaces), and then re-clump recognized sequences of operators back to single tokens.  So the assembly:

  @sin P3:=1<<24

gets "puffed up" (and lower cased) to:

  @  sin  p3  :  =  1  <  <  24

Next the two sequences ":   =" and "<  <" are recognized and reclumped back together:

  @ sin p3 := 1 << 24

It bothers me a little that this kind of operator spacing is thus allowed in the language itself, but it's so brain dead simple to puff and clump that it's hard not to do it this way.  (Clumping is done with the longest sequences recognized and reclumped first, then the next longest, etc. so as not to confuse subsets of similar longer sequences for the shorter ones.  And the minus symbol in front of number is somewhat problematic regardless - is it an operator or a sign?)

I'm using a standard library <vector> of strings to hold the tokens, and a stringstream type to do the tokenizing, which works really well.  Using the unordered_map to do the label processing is also working like a champ, now my labels are much more descriptive and useful, and much less fiddly in terms of assignment naming.

At the point now where the rest of the simulator code could use a good rogering.  I'm thinking of pulling out all the features I'm not using in order to make it easier to maintain.  With an assembly language I'm not going to write code in the sim anymore, so I can get rid of all the editing functions including the undo system.  The core sim logic is based on object oriented modules, a situation which is rather cumbersome and confusing to clock.  Thinking of going with a two phase clock to each module, with the "lo" clock evaluating the async logic, and the "hi" clock updating the synchronous (flop) values.  If I made all module inputs async and all outputs sync, this would remove all possible race conditions when hooking it all together, and things could be clocked in any order, even multiple times (lo or hi) without harm.  Like the cha-cha of a clock escapement.

You must be logged in to post a reply. Please log in or register for a new account.