It is currently Thu Nov 14, 2019 7:09 pm

All times are UTC - 7 hours





Post new topic Reply to topic  [ 29 posts ]  Go to page 1, 2  Next
Author Message
PostPosted: Sun Apr 07, 2019 6:35 pm 
Offline

Joined: Sun Jun 30, 2013 7:59 am
Posts: 41
Hi :) hope this is the right sort of subject matter for this forum.

Those of you who had previous programming experience (not necessarily schooling/university) with other, higher-level languages, how do you feel assembly has improved your programming in general? Or, alternatively, if assembly was your first language and you've since learned others, how do you think it has coloured the process and your style in those languages?

Often you find people saying that it gives you a closer intimacy with "the metal" but, a 6502 is in some ways a radically different beast from modern architectures. I feel like if anything you'd have to cultivate a lot of discipline in regards to planning and program flow. With modern, statically-typed languages, you have a compiler watching your back to ensure you don't pass arguments of the wrong type to functions, and there are numerous methods of avoiding things which are practically a given in assembly programming, such as global variables and mutable state. I suppose this does actually tie in with being "closer to the metal" though, because you yourself are taking the role of the compiler/interpreter ;)

Also, do you have anything to say regarding the reverse? Is there anything you took from higher-level languages (that mightn't be so obvious to someone who had assembly expertise only) and applied to your assembly programming which you felt was advantageous? I feel like this could be a more limited possibility, but it's a subject I find very interesting.

I was just curious, would love to hear your thoughts. Forgive any factual inaccuracies or wrong assumptions above. I also don't mean to imply that assembly and higher-level (e.g. oop, functional) languages are opposed, just that they often seem to require vastly different sensibilities and means-of-abstraction at times.

Thanks!


Top
 Profile  
 
PostPosted: Sun Apr 07, 2019 8:54 pm 
Offline

Joined: Wed Nov 30, 2016 4:45 pm
Posts: 147
Location: Southern California
Efficiency, something I'm a bit OCD about. I have taken things from HLLs and applied them to assembly, like my program flow-control structure macros. (There are a couple of extended examples near the end of the page in my multitasking article, and I tell more of how the innards of the macros construct the 6502 code in section 17 of the 6502 stacks treatise. These improve readability, maintainability, and productivity, reduce bugs, and in most cases, they assemble the same thing you would do by hand, meaning there's no penalty in run speed or memory taken. Oh, and BTW, you can do local variables on the 6502 in assembly. See section 14 of my 6502 stacks treatise.

_________________
http://WilsonMinesCo.com/ lots of 6502 resources


Top
 Profile  
 
PostPosted: Mon Apr 08, 2019 2:59 am 
Offline
User avatar

Joined: Fri Jan 24, 2014 9:05 am
Posts: 193
Location: Hungary
I'd had no programming knowledge other than a few classes of "Comenius Logo" or whatever it was called, before I started learning 6502 assembly. I have to say that the first thing people notice in my higher-level code is that it's absolutely filled with comments to the point that almost every line has some sort of an explanation, even if the variable names etc. are descriptive on their own right.

Other than that, I feel that since assembly for these old CPUs is the field where I can have a sense of "everything that's possible to perform as the next step", meaning I know all the instructions, all the addressing modes, I know the target hardware inside and out, I feel I have a kind of fluency that I can't have at a higher level on a modern platform. There is too much that is dependent on knowing 10 million libraries and pre-made tools with high-level languages. I form the bigger picture in my head while working on the intricate details, so to say, and anything more sophisticated than C requires me to think ahead too quickly.

In a way, starting at a low level made it really hard for me to think at a higher level, although as I have put together a working game engine I stopped thinking about the implementation, and started thinking in terms of game objects / entites, etc.
Working on a few development tools in C# really helped me, because I could take some of the basic object-oriented programming principles and apply them to how I treated my in-game entities. But overall, I tend to try to equate a high-level concept to an assembly concept to make sense of it like "switch-case" is the equivalent of an assembly "jump table", and so on. I feel like my knowledge of somehing high-level isn't complete until I know how it was implemented, and I know the performance / size advantages and drawbacks. So if this hobby of mine ever becomes something more, like a job, I will follow people's advice and try to get into programming for embedded systems or writing an operating system, or drivers... basically anything where I can work in C or assembly.


Top
 Profile  
 
PostPosted: Mon Apr 08, 2019 7:54 am 
Offline
User avatar

Joined: Fri Nov 24, 2017 2:40 pm
Posts: 170
It makes me think a lot more about code compactness. I've always been a bit obsessed with runtime performance, and that's already a never ending rabbit hole. Doing assembly for 8 bit again has reminded me how compilers are pretty decent about making fast code, but not always compact code. So that's a new dimension to over-analyze and over optimize when working on projects for fun. ;)


Top
 Profile  
 
PostPosted: Mon Apr 08, 2019 10:51 am 
Offline
User avatar

Joined: Thu Mar 31, 2016 11:15 am
Posts: 532
Some bitwise tricks and a better understanding of two's compliment.


Top
 Profile  
 
PostPosted: Mon Apr 08, 2019 11:16 am 
Offline
User avatar

Joined: Sun Sep 19, 2004 9:28 pm
Posts: 4213
Location: A world gone mad
CrowleyBluegrass wrote:
Those of you who had previous programming experience (not necessarily schooling/university) with other, higher-level languages, how do you feel assembly has improved your programming in general? Or, alternatively, if assembly was your first language and you've since learned others, how do you think it has coloured the process and your style in those languages?

Generally speaking, working in assembly forces me to think in a "minimalist" mindset; the more of it you do, the more this mindset becomes second nature, and then begins to trickle into other works you do (in other PLs, projects, whatever). You could say it's sort of imposes indirectly KISS principle.

I can't say this is a direct result of assembly itself but moreso whatever architecture/platform you're working on, but: use of assembly ends up forcing you to get better with basic bitwise CPU operations like AND, OR, and XOR, and also forces you to understand how pointers (or references) actually work. Likewise, you're forced to understand how data is stored/organised in actual memory (read: not through some obtuse abstraction layer)... and that in turn often forces you to learn about the importance of endian.

CrowleyBluegrass wrote:
Often you find people saying that it gives you a closer intimacy with "the metal" but, a 6502 is in some ways a radically different beast from modern architectures. I feel like if anything you'd have to cultivate a lot of discipline in regards to planning and program flow. With modern, statically-typed languages, you have a compiler watching your back to ensure you don't pass arguments of the wrong type to functions, and there are numerous methods of avoiding things which are practically a given in assembly programming, such as global variables and mutable state. I suppose this does actually tie in with being "closer to the metal" though, because you yourself are taking the role of the compiler/interpreter ;)

You should ignore these people, as 99% of the time they have no idea what they're talking about. If they're comparing against present-day x86 architecture, you should ask them to explain what "closer to the metal" means exactly -- you'll find most don't have any idea what that means, because they've never actually gone outside their little happy PL world of Rust and Ruby. When they mention how assembly is "as close as it gets", point out that x86 CPUs (for quite some time now) have consisted of microcode that "interpretes" x86 bytecode, rather than on older CPUs (65xx, 68K, older x86, etc.) where all of this was done purely at the transistor level, involving painstaking creation of photomasks and the like.

CrowleyBluegrass wrote:
Also, do you have anything to say regarding the reverse? Is there anything you took from higher-level languages (that mightn't be so obvious to someone who had assembly expertise only) and applied to your assembly programming which you felt was advantageous? I feel like this could be a more limited possibility, but it's a subject I find very interesting.

Not really. I will say that being around in the early 90s when there was a more commonplace "symbiotic relationship" between assembly language and the-next-highest-up-PL (ex. Pascal or C) helped in comprehending how something in a higher-level language can potentially get turned into assembly, or the relationship between those two. I'll give an example to make my point a bit more clear:

When it comes to strings in Pascal, which in memory happen to be in the format of a length byte/word/whatever followed by the actual content itself (ex. 0x0012, "Hello World!"), a string-copy function can be implemented quickly by sticking the length byte into cx and then using lodsb + rep stosb to copy it from es:si to es:di via pointers. In contrast, C-based strings which are of unknown length but 0x00/NULL-terminated, use a different model (given that the CPU itself has to examine every read/loaded byte to see if it's 0x00 or not, to end the loop).

Having an assembly background also on occasion has forced me to go and look at how higher-level PLs implement something (and if that implementation trickles down into optimal code). For example, I've looked at different implementations of commonplace libc functions over the years -- not something I do regularly, mind you -- just to see how they were implemented, combined with the assembly generated. A more recent example for me was examining a recent change in the dd utility in FreeBSD, provoking me to compare the assembly results of that code to that of the classic XOR-based method of swapping two bytes (without use of a third register/variable): turns out clang generates better code from that C code than if p[0] ^= p[1]; p[1] ^= p[0]; p[0] ^= p[1]; was used, much to my surprise (IIRC, gcc generated better code using the latter). https://godbolt.org/ was invaluable here.

CrowleyBluegrass wrote:
I was just curious, would love to hear your thoughts. Forgive any factual inaccuracies or wrong assumptions above. I also don't mean to imply that assembly and higher-level (e.g. oop, functional) languages are opposed, just that they often seem to require vastly different sensibilities and means-of-abstraction at times.

Understood. And on a slight divergence: the less abstraction there is, the better.


Top
 Profile  
 
PostPosted: Mon Apr 08, 2019 3:05 pm 
Offline

Joined: Sun Jun 30, 2013 7:59 am
Posts: 41
koitsu wrote:
You should ignore these people, as 99% of the time they have no idea what they're talking about. If they're comparing against present-day x86 architecture, you should ask them to explain what "closer to the metal" means exactly -- you'll find most don't have any idea what that means, because they've never actually gone outside their little happy PL world of Rust and Ruby. When they mention how assembly is "as close as it gets", point out that x86 CPUs (for quite some time now) have consisted of microcode that "interpretes" x86 bytecode, rather than on older CPUs (65xx, 68K, older x86, etc.) where all of this was done purely at the transistor level, involving painstaking creation of photomasks and the like.

I remember first reading about Lisp machines, and that really made me reconsider what "close to the metal" means/can mean. Lisp -- I think the majority of people would agree -- is a high-level language. However, as those Lisp machines were designed specifically to run Lisp code efficiently at the hardware level (I'm no hardware expert, feel free to correct me on how possible/efficient this actually was) you're essentially coding in a high-level language, with the benefit that it is actually working together with the machine. For example, the memory itself is list structured.

I also remember reading this article: https://queue.acm.org/detail.cfm?id=3212479
Admittedly, the majority of it went over my head. However, I remember it basically saying that the machines C was designed to run efficiently on, are quite different from the machines we use today. The compilers are doing crazy feats in order to get around that. Hope this isn't too off-topic, but I'd be very interested to hear your and other's thoughts on this too. I made a post on here some time ago of a similar nature, but in regards to the 6502; a few replies were made regarding how C doesn't provide certain things such as efficiently-sized data types for compiling to 6502.

Again, please forgive any errors in this post. I know a little about a lot as opposed to the reverse :lol:


Top
 Profile  
 
PostPosted: Mon Apr 08, 2019 3:19 pm 
Offline
User avatar

Joined: Sun Sep 19, 2004 9:28 pm
Posts: 4213
Location: A world gone mad
Your understanding about Lisp machines (read: hardware that was explicitly designed to run Lisp code optimally) is correct.

If you'd like someone familiar with this -- and the general questions you've asked, plus posed in the above post (the reply to me) -- I can ask someone to do a short write-up. I have more than a few colleagues (including one who owned an actual Lisp machine -- yes, the "huge and heavy box on casters" kind) familiar with this type of thing, and they code in a myriad of languages, assembly being one.


Top
 Profile  
 
PostPosted: Mon Apr 08, 2019 3:41 pm 
Offline

Joined: Sun Jun 30, 2013 7:59 am
Posts: 41
koitsu wrote:
Your understanding about Lisp machines (read: hardware that was explicitly designed to run Lisp code optimally) is correct.

If you'd like someone familiar with this -- and the general questions you've asked, plus posed in the above post (the reply to me) -- I can ask someone to do a short write-up. I have more than a few colleagues (including one who owned an actual Lisp machine -- yes, the "huge and heavy box on casters" kind) familiar with this type of thing, and they code in a myriad of languages, assembly being one.

That would be very much appreciated Koitsu! My biggest interest is how different paradigms and languages interrelate and influence each-other (hoping to focus on that at university), so that would be very much relevant to my interests.


Top
 Profile  
 
PostPosted: Mon Apr 08, 2019 6:00 pm 
Offline

Joined: Sun Mar 27, 2016 7:56 pm
Posts: 218
koitsu wrote:
because they've never actually gone outside their little happy PL world of Rust and Ruby
Okay... I get Ruby, but I'm surprised that Rust is mentioned in the same breath, since that's a compiled programming language with pointers, inline assembly, lack of garbage collection, and so on.

Sure, there's memory safety in the form of static checks at compile-time, but it's not like garbage collection where you don't have to care (and indeed have no idea) how memory is managed. Instead you manage memory yourself (with the help of RAII and destructors, so it's not quite as painful as malloc/free), with the key difference being that the compiler yells at you if you fuck it up.


Top
 Profile  
 
PostPosted: Mon Apr 08, 2019 6:09 pm 
Offline
User avatar

Joined: Sun Sep 19, 2004 9:28 pm
Posts: 4213
Location: A world gone mad
Nicole wrote:
koitsu wrote:
because they've never actually gone outside their little happy PL world of Rust and Ruby
Okay... I get Ruby, but I'm surprised that Rust is mentioned in the same breath, since that's a compiled programming language with pointers, inline assembly, lack of garbage collection, and so on.

Sure, there's memory safety in the form of static checks at compile-time, but it's not like garbage collection where you don't have to care (and indeed have no idea) how memory is managed. Instead you manage memory yourself (with the help of RAII and destructors, so it's not quite as painful as malloc/free), with the key difference being that the compiler yells at you if you fuck it up.

And how does any of what you said make anything "closer to the metal?", which is what my quoted paragraph (of which the context you removed) was about? RAII, destructors, manual memory management -- none of these things get you "closer to the metal". So your above words may pertain to my comment about minimising abstraction (I agree there), but it's irrelevant to the "closer to the metal" phrase thrown around by high-level PL fanatics.


Top
 Profile  
 
PostPosted: Mon Apr 08, 2019 6:43 pm 
Offline

Joined: Sun Mar 27, 2016 7:56 pm
Posts: 218
koitsu wrote:
And how does any of what you said make anything "closer to the metal?", which is what my quoted paragraph (of which the context you removed) was about? RAII, destructors, manual memory management -- none of these things get you "closer to the metal". So your above words may pertain to my comment about minimising abstraction (I agree there), but it's irrelevant to the "closer to the metal" phrase thrown around by high-level PL fanatics.
I'm not sure I understand what other meaningful distinction you could make with regards to whether something is "closer to the metal" or not, unless you're saying that nothing short of pulling out a soldering iron is "close to the metal", and that's just pointless pedantry in my eyes.

To me, whether a programming language is "close to the metal" or not is a spectrum between "this programming language assumes a machine with infinite memory, and theoretically the Hello World example will return a result in the next seven billion years" and "this programming language has blink_led as a built-in keyword". The more the physical reality of the machine in question is exposed, the closer to the metal it is, in my eyes.


Top
 Profile  
 
PostPosted: Mon Apr 08, 2019 7:22 pm 
Offline
Formerly 43110

Joined: Wed Feb 05, 2014 7:01 am
Posts: 386
Location: us-east
My very first exposure to assembly was with single stepping instructions of a hello world program in the debugger of CodeWarrior on Mac OS 8 (Pre OSX). I decided that 68k was easier to read then PowerPC and went on to more exciting (to me at the time) things like viewing the resource fork of files. I must of been about 14 years old at that time

Sometime around 2002 I had downloaded 6502.txt from NESdev (which at the time I thought was only dedicated to ripping NSF files). That document shaped my thinking of how CPU instructions should look like (especially about the carry flag). Before I rediscovered NESdev in 2013 I already had the concept of pointers (which I hear is becoming a lost art nowadays?) and some brief AVR embedded experience on hand. So by the time I posted my first post here 6502 was the easiest part.

The hard part was my impossible goal of fitting something like Metroid into NROM. I had no feel for how much space game data takes.

Along the way I learned Euler's Method and what Calculus is. How I graduated college without this knowledge is beyond me.
I also can reckon with 2's complement numbers with ease, and I also generally improved at adding positive with negative numbers in my head (helpful for balancing your accounts).

And lately I feel like I've unlocked the true purpose of statistics; A tool to engineer machines and not just a thing to make a point in Social science.


Top
 Profile  
 
PostPosted: Mon Apr 08, 2019 10:26 pm 
Offline

Joined: Fri Apr 05, 2019 9:47 pm
Posts: 3
CrowleyBluegrass wrote:
I remember first reading about Lisp machines, and that really made me reconsider what "close to the metal" means/can mean. Lisp -- I think the majority of people would agree -- is a high-level language. However, as those Lisp machines were designed specifically to run Lisp code efficiently at the hardware level (I'm no hardware expert, feel free to correct me on how possible/efficient this actually was) you're essentially coding in a high-level language, with the benefit that it is actually working together with the machine. For example, the memory itself is list structured.

Having written macrocode and microcode level emulation for the TI Explorer Lisp Machine, I can say that the situation was a bit more complicated than that. The machines were largely general-purpose processors with specific extensions for things like reduced-width operation of the ALU. There were a few clevernesses in the MMU design to support the garbage collector, and a wonderfully efficient indexed jump operation, but beyond that the underlying architecture was basically designed to run a bytecode interpreter.

The memory system was a bag of words, and any further semantic above that was added by the microcode (bytecode interpreter). The whole "list structured memory" thing (CDR-coding) is basically using a couple of bits in each "boxed" memory word (so, not code storage or most kinds of array) that, if treated as the CAR of a list reference (the first half of a two-word linked-list structure) told the system where the CDR (the second half) was stored (the CDR would either be stored in the next memory word, would be the address of the next memory word, would be the known value NIL, or that's not a list reference in the first place and what are you trying to pull here?).

One of the main aspects of the Lisp Machine, classically, is that it doesn't require all that much in the way of compiler smarts. The microarchitecture is optimized for creating what we now consider to be bytecode interpreters, but really amount to an implementation of a semantically denser instruction set (known as macrocode) and related memory model. The macroarchitecture, as presented to the compiler and the users more resembles a "managed runtime", to borrow a recent-ish term. It's presented in terms of a given programming language or set of programming languages. The macroinstruction set (bytecode) is designed to be easy to compile to, without requiring a complicated optimizer in order to get tolerable performance. The ability to customize your instruction set to make your compiler simpler and faster is a demonstration of a holistic design philosophy that can cut out a lot of development and maintenance effort.

Leaving Lisp behind, another example of this kind of holistic "design your instruction set to suit your problem space" approach would be Jeff Laughton's KimKlone 65c02-based computer with 16-megabyte linear address space and hardware acceleration for a Forth interpreter. Yet another case would be the MIPS architecture, where the processor was designed to support C semantics, and to shift the complexity of effective address calculations from the CPU to the compiler, so that the hardware could be simpler and therefore could be run reliably at a faster clock speed. And the same idea was done again with the ALPHA architecture, but to an even greater extent: Simplify the instruction set and memory architecture, pushing complexity to the compiler, so that the underlying hardware can be run at a far higher base speed.

There have been various other designs for dedicated hardware specific to one programming language or another, or optimized for some particular application area, including hardware Prolog processors, Forth processors, 3D graphics processors of various types, Digital Signal Processors, the list goes on.

I first learned assembly language more than a quarter century ago (8086 or 6502, I forget which). I most recently learned assembly language last year (8051). I will probably learn assembly language this year (AVR). Off the top of my head, I can say at least fifteen assembly languages that I have worked with (not counting things like the intel-vs-at&t syntax as separate languages for x86, but counting 32-bit and 64-bit MIPS as separate, even though 32-bit MIPS userland code can run unmodified on a 64-bit processor). It has been so long since I first learned assembly that I really can't say what I learned most from it. Or even what I learned from it vs. what I learned from other sources.


Top
 Profile  
 
PostPosted: Tue Apr 09, 2019 3:37 am 
Offline

Joined: Thu Aug 20, 2015 3:09 am
Posts: 471
That I don't have the patience to program in assembly. :lol:

More seriously, I started on my programming journey when I read a book that described how all the components of a CPU - like the address bus, data bus, control lines, flags, ALU etcetera - all worked, at the level of ones and zeros. Before that it all seemed a bit mystical, but after, I had a concrete mental image to work with. Sure, it was a bunch of tiny robots on Tron bikes, but it was something 'real' and physical that I could understand and manipulate.

(There was even a pinout of a Zilog Z80 in the back! Remember when user-level computer books/manuals had actual pinouts in them? Imagine trying to do that now.)

Assembly was the natural step up from there - all I was really missing was the instruction set, plus an actual assembler. I bumbled my way through BASIC and Turbo C before I finally found one, but when I did, I dived right in. I continued working my way up, coding a simple Forth compiler and evolving it into a bare-metal OS (cooperative multitasking!) before I finally realized I'd spent a decade of my life on this voyage of discovery and had nothing of any practical value to show for it. None of my many assembly language projects ever got past the tech demo stage, because the sheer complexity involved inevitably exceeded my ability to reason about.

So in that sense, assembly taught me that compilers are awesome, and when they fail to be awesome it's usually because the job they do is really freaking hard. (Though the latter probably comes more from having written a couple myself, rudimentary as they were.) It also taught me that complexity is the root of all evil, and that managing it - by minimizing it, structuring it and documenting it - is the key to success as a programmer.

Probably not the kind of answer you were looking for, but that's the perspective I got going from low to high instead of high to low.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 29 posts ]  Go to page 1, 2  Next

All times are UTC - 7 hours


Who is online

Users browsing this forum: No registered users and 8 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group