Hacker News new | ask | show | jobs
by scott_s 4161 days ago
Advice to the authors: don't stress syntax, but semantics. People here are getting caught up on the notion that "this syntax is not too different from Verilog/VHDL". But that's not the point; it's not what you say, but what that means. You have created a programming model that software people can understand intuitively, but also easily maps to hardware.

People may get hung up on this because the example on your page is so simple. The equivalent VHDL and Verilog is also relatively simple. A simple example is good, and a comparison is good, but just presenting the differences is not enough. Stress what someone coding in Cx does not have to think about. In other words, what are the abstractions in Cx?

Consider what the equivalent page for C versus assembly would look like for a function that computes some simple arithmetic. Some people may say, "Oh, sure, the assembly has a few more lines because you need to push and pop parameters from the stack, but that's no big deal." And it's not - for one function. What's the big deal is that there are entire concepts - saving existing registers, pushing parameters onto the stack, register management - that C programmers don't need to think about. (Most of the time.)

The code you link to elsewhere in this thread hints to me that there are indeed significant abstractions behind Cx, that make it more than just an alternative syntax to Verilog and VHDL. See: https://github.com/synflow/sha-256/blob/master/SHA256/src/co...

1 comments

That's a very good point. In fact the main difference in semantics is that Cx code is structured. Sure in VHDL/Verilog you have functions and if statements and loops. But they can only be used to describe combinational logic. There is a chasm between synchronous logic (everything in a big switch/case) and combinational statements.

Cx supports functions, if and loops for both combinational and synchronous logic. You can have a function that spans over two cycles. You can give parameters to this kind of function just like in software, except that in the end this is all inlined and the state machine is flattened.

The language encourages a higher level of abstraction where you think in terms of blocking reads and data availability rather than "is my signal true". The best is that this can be extended just by changing the port signature, for example to provide rendez-vous style communications (we call it "sync ack" but they're not implemented yet), whereas in HDL you'd have to write a lot of boilerplate code.

Another property is that there is no synthesizable subset in Cx. As far as I know, this is very rare in languages for hardware design, but the language is entirely synthesizable. You never have to think about synthesis versus simulation. Exactly like in software, nobody ever wonders if they can write code that won't run on the processor :-)

And for the example you mention, this is another interesting feature of the language. Because we support sequential loop constructs etc. you can actually write code that works and synthesizes pretty easily, albeit it is slow. And then you can produce a derived version that is optimized :-)

"Another property is that there is no synthesizable subset in Cx. As far as I know, this is very rare in languages for hardware design, but the language is entirely synthesizable. You never have to think about synthesis versus simulation. Exactly like in software, nobody ever wonders if they can write code that won't run on the processor :-)"

This is scary. I want the tool to tell me "I can't synthesize this" because when it does, it might infer characteristics of the design that I might not want.

Do you have some kind of paper or detailed explanation about this part?

Sometimes a bad design is not bad because it's badly written, it's bad because it's not complying with some timing constraints or because the synthesis tool decided to infer some crazy system from the code the designer wrote.

@gothenburg @mng2 I get that you think it's not useful or even it's crazy, especially as both of you seem to be seasoned hardware designers. But as a software guy myself, there's nothing I have found more horrible when learning to write some VHDL than finding out what was allowed in synthesis, what was tolerated but not recommended, and what was legal VHDL but could never synthesize. Things like automatically inferred latches because of local variables, multidimensional arrays supported but not always (vendor-dependent), loops that work for combinatorial logic only, "wait" that are not permitted (or only in vendor-specific ways), etc.

In Cx you can't create latches, loops work for combinatorial logic and synchronous logic alike, and all in all there are no unsynthesizable constructs. Finding out if a piece of code will result in unacceptable performance is a different problem, I hope to have the compiler kind of "guide" you on this kind of things.

Is it any scarier than having wildly inefficient software code? (Think a naive traversal of large matrices that thrashes the cache.)

That's a workflow where optimization requires knowing the internals and how they interact, but you can ignore such things if you just want correctness. At least in software, that model works well, because the performance of most of the code we write doesn't matter - even in applications where performance is a concern.

I wouldn't call it 'scary', myself, but it doesn't strike me as a particularly useful feature. In software, a single slow subroutine can simply take up more cycles. But in hardware, a slow path becomes your critical path, and you have a hard clock cycle requirement. (Sure, you can use multi-cycle paths and/or change clock speed, but those generally have to be adjusted manually/physically, and not all design situations will have that flexibility.)