6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Thu Oct 03, 2024 11:13 pm

All times are UTC




Post new topic Reply to topic  [ 56 posts ]  Go to page Previous  1, 2, 3, 4  Next
Author Message
PostPosted: Sat Oct 01, 2016 8:00 am 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10943
Location: England
I never wrote an assembler or a monitor, but I think it's a great way to get your teeth into the machine level, and those who have done it seem to be well set up.

I like the look of dflat!


Top
 Profile  
Reply with quote  
PostPosted: Sat Oct 01, 2016 5:38 pm 
Offline
User avatar

Joined: Sat Dec 07, 2013 4:32 pm
Posts: 246
Location: The Kettle Moraine
I learnt 6502 by writing my first assembler. I learnt how to write the assembler by comparing listings in "Compute!" They would sometimes show a program in both assembly and hexadecimal machine language (or decimal in the form of BASIC "DATA" statements!). That's why for the longest time, I didn't know how to use a few uncommon instructions. I remember figuring out the hard way how BRK takes a parameter.

I wouldn't say I'm particularly well set up. But I wouldn't rather have done it any other way.

I did have prior experience with assembly, though. I would hand-assemble TMS-1000 on paper.


Top
 Profile  
Reply with quote  
PostPosted: Sat Oct 01, 2016 6:06 pm 
Offline

Joined: Tue Nov 10, 2015 5:46 am
Posts: 228
Location: Kent, UK
Tor wrote:
I've become so used to modern source code practices that I don't think I could ever do the editing on the target platform anymore.
Back in the 80s I knew a published games programmer who worked on the Commodore 64, under contract from Activision. He used a PC clone for development (editor/assembler) with some kind of hardware interface (attached to the '64 cartridge port) to squirt the entire assembled program over to the '64 in a couple of seconds.

The system cost a few thousand UK pounds. A broke kid, I remember being quiet envious. It was all very slick. Being able to absorb a crash or reset and just keep coding/testing without skipping a beat made assembly programming too easy. Nothing broke my stride on the Atari 800XL like having to reset and reload my source code. I also used the slowest assembler in the world... so that didn't help. My friend pressed an 'F' key and, it seemed, that before his finger had completely lifted off the key, the code was assembled, transferred over and the program was running. It wasn't that fast, of course, but that's how it felt.

From what I've read it seems that programming on the target, with all its constraints and limitations, was for kids in their bedrooms. Professional developers used systems ranging from personal IBM PC clones to PDP-11s, and more. Event the Atari ST, which came out in '85, was a popular low-cost system for the 8-bit machines, with the Atari MADMAC assembler supporting 6502 code generation.

I don't remember source code control being part of my friend's development system. Maybe it was... I wasn't aware of the notion back then. Of course nowadays, like you, everything is under source code control. It's essentially zero-effort.

EDIT: I think this is what my friend used: http://www.cpcwiki.eu/index.php/PDS_development_system


Top
 Profile  
Reply with quote  
PostPosted: Sun Oct 02, 2016 5:55 am 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8521
Location: Southern California
sark02 wrote:
He used a PC clone for development (editor/assembler) with some kind of hardware interface (attached to the '64 cartridge port) to squirt the entire assembled program over to the '64 in a couple of seconds.

The system cost a few thousand UK pounds. A broke kid, I remember being quiet envious. It was all very slick. Being able to absorb a crash or reset and just keep coding/testing without skipping a beat made assembly programming too easy. Nothing broke my stride on the Atari 800XL like having to reset and reload my source code.

I suppose this is a bit O.T., so I'll try to keep it short. Forum veterans have heard part of this already. A way to do what you're saying would be to have a Forth cartridge, so Forth (including an assembler) is in ROM, and put a reset button on it (since the C64 otherwise required turning the unit off and back on to get a reset). I have Forth in ROM on my workbench computer, and I use the DOS PC for development for the professional programmer's text editor, the PC's 132-column monitor (yes, I have that in DOS, and up to 60 lines), big keyboard, and hard disc. As I develop code using the text editor on the PC, I put block markers around a small, new portion I want to try, and "print" it to the RS-232 port (the PC thinks it's sending it to a serial printer), then the workbench computer takes that text, and compiles, assembles, or interprets on the fly, as appropriate.

If I crash the workbench computer, I can press the reset button, and the boot-up routine puts "New/Old/Init-Ap?" in the 16-character LCD, three options which correspond to three particular keys on the keypad. Pressing the key for "Old" keeps everything I already had compiled in its RAM, rather than starting over. This almost always works because crashes don't usually go writing trash all over RAM, but instead are just from loops whose exit condition never gets met. Init-Ap goes further, and executes the initialization routine whose address is in the init-ap variable. This allows resetting, setting up I/O again, re-initializing things, etc., and being totally back to operational in a couple of seconds, with nothing lost. The crash and reset on the workbench computer does not affect the PC. There's no special software on the PC, not TSR's, etc., let alone anything expensive.

_________________
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?


Top
 Profile  
Reply with quote  
PostPosted: Sun Oct 02, 2016 6:55 am 
Offline

Joined: Tue Nov 10, 2015 5:46 am
Posts: 228
Location: Kent, UK
GARTHWILSON wrote:
As I develop code using the text editor on the PC, I put block markers around a small, new portion I want to try, and "print" it to the RS-232 port (the PC thinks it's sending it to a serial printer), then the workbench computer takes that text, and compiles, assembles, or interprets on the fly, as appropriate.
I've read your story about this before. Using the PRINT mechanic to send data to the target is neat.

Quote:
If I crash the workbench computer, I can press the reset button, and the boot-up routine puts "New/Old/Init-Ap?" in the 16-character LCD, three options which correspond to three particular keys on the keypad. Pressing the key for "Old" keeps everything I already had compiled in its RAM, rather than starting over. This almost always works because crashes don't usually go writing trash all over RAM, but instead are just from loops whose exit condition never gets met.
Not as slick as this, but in my 68000 programming days, on the Atari ST, my common startup code would hook the reset vector to issue a PTerm (Process Terminate) OS call. What this meant was that if my program went off into the weeds I could press the Atari's reset button and the OS would essentially see the current process terminate and it would return back to the editor/assembler application that had launched it. Somewhere in details I forget, someone (either my code or the OS pre-hook) would reinitialize I/O, video sync, frame buffer address, palette, etc. The bottom line was that usually a freeze was trivially escapable (as long as the bug hadn't clobbered memory). This was programming and running on the target itself - not with a master/slave system like yours... which I would have killed for.


Top
 Profile  
Reply with quote  
PostPosted: Sun Oct 02, 2016 7:25 am 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10943
Location: England
I think the key is having a second computer for development - even if it's as cheap as the first computer, the target, it's still doubled the cost of setting up! We only get safety during development later on, when our CPUs get memory protection. Back in the day, using a timesharing service would be one way to keep costs down - that's good for the entrepreneur, not so much for the schoolkid. Perhaps using nearby University computers for free would do it!


Top
 Profile  
Reply with quote  
PostPosted: Sat Oct 15, 2016 9:52 am 
Offline

Joined: Mon Oct 19, 2015 7:04 am
Posts: 68
Location: France
My home-made calculator software has approximately 6,500 lines of code. I wrote some 3,700 lines, 750 of them being an extension to C.R. Bond's math library which accounts for the remaining 2,800 lines.

I didn't use sophisticated methods for debugging, it was mostly done with head-and-pencil, and the Kowalski simulator was used for some math routines. I used the oscilloscope to check the correct behaviour of the keyboard scanning ISR and the associated hardware.

The whole development was done on an old laptop (pentium-II), mainly with DOS tools (as65, ...). I didn't use macros ; I suppose I'd use them if I were to start a new project. The code is made of 13 modules included into the main one at assembly time.

All of that was quite a satisfaction : it's been 20 years since my last software development in assembly... it was at work : I didn't write as large assembly code, but I often passed the 10,000-line limit with parts of projects written in C or PL//M -but that was not for the 6502 of course.


Top
 Profile  
Reply with quote  
PostPosted: Sat Oct 15, 2016 6:10 pm 
Offline
User avatar

Joined: Sun Nov 27, 2011 12:03 pm
Posts: 229
Location: Amsterdam, Netherlands
My largest 6502 coded source is a hair under 20.000 lines, producing around 9 KB of (very efficiently coded) binary. It's for a contraption called GoSDC (see http://www.zeridajh.org/hardware/gosdc/index.htm). One of the funky things is that it runs almost entirely on stack space.


Top
 Profile  
Reply with quote  
PostPosted: Sat Oct 15, 2016 7:09 pm 
Offline
User avatar

Joined: Sat Dec 07, 2013 4:32 pm
Posts: 246
Location: The Kettle Moraine
20,000 lines to 9216 bytes of code?

Don't get me wrong, I'm not trying to pick on you, I'm trying to understand. For me, I'd expect to get 9216 bytes of code in about 6000 lines. I guess I'll have to look at some of my code and see how big it really is,


Top
 Profile  
Reply with quote  
PostPosted: Sat Oct 15, 2016 7:37 pm 
Offline
User avatar

Joined: Sun Nov 27, 2011 12:03 pm
Posts: 229
Location: Amsterdam, Netherlands
KC9UDX wrote:
20,000 lines to 9216 bytes of code?

Don't get me wrong, I'm not trying to pick on you, I'm trying to understand. For me, I'd expect to get 9216 bytes of code in about 6000 lines. I guess I'll have to look at some of my code and see how big it really is,

It's actually 20 KB of binary (the source produces more than one binary, duh to self). But some chunks end up in more than one binary, so I guess it's probably nearer to 13 KB of unique object code. And I use plenty of air in my source code to keep it neat and tidy.


Top
 Profile  
Reply with quote  
PostPosted: Sat Oct 15, 2016 11:57 pm 
Offline
User avatar

Joined: Sat Dec 07, 2013 4:32 pm
Posts: 246
Location: The Kettle Moraine
OK thanks. I was starting to think you had paragraphs of comments in your code. :)


Top
 Profile  
Reply with quote  
PostPosted: Sun Oct 16, 2016 1:16 am 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8521
Location: Southern California
KC9UDX wrote:
OK thanks. I was starting to think you had paragraphs of comments in your code. :)

I do explain everything clearly in the source code, because I myself might need it later when it's time to make a change and I can't remember why I did something the way I did; but OTOH, each macro invocation shortens the source code a lot.

_________________
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?


Top
 Profile  
Reply with quote  
PostPosted: Sun Oct 16, 2016 6:08 am 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10943
Location: England
Always think of the next person who will work on the code - it might well be yourself!


Top
 Profile  
Reply with quote  
PostPosted: Sun Oct 16, 2016 10:23 am 
Offline
User avatar

Joined: Sun Nov 27, 2011 12:03 pm
Posts: 229
Location: Amsterdam, Netherlands
KC9UDX wrote:
OK thanks. I was starting to think you had paragraphs of comments in your code. :)

I do describe the entry and exit conditions at the top of each routine. I always do that, but it's downright essential in sources this big. The rest of the comments (concise descriptions of, on average, 5 to 10 instructions, no 'INX // This increments X' from me ...) are at line ends, so don't count towards the line total. There's some macros as well. Table generating code. Constants being defined. Etc. So keep in mind that 'weighing' source code can get pretty complicated ... !


Top
 Profile  
Reply with quote  
PostPosted: Sun Oct 16, 2016 7:34 pm 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8411
Location: Midwestern USA
Windfall wrote:
KC9UDX wrote:
OK thanks. I was starting to think you had paragraphs of comments in your code. :)

I do describe the entry and exit conditions at the top of each routine. I always do that, but it's downright essential in sources this big.

Indeed. Every function in my code, unless very trivial, has a comment header that, at minimum, tells what the entry register values must be and what the exit register values will be, such as in this 65C816 assembly language subroutine header:

Code:
;================================================================================
;
;lbopbo: CONVERT LOGICAL BLOCK OFFSET TO PHYSICAL BLOCK OFFSET
;
;   —————————————————————————————————————————————————————————
;   Calling syntax: LONGX                 ;16 bit index
;                   LDX LBOLSW            ;LBO LSW
;                   LDY LBOMSW            ;LBO MSW
;                   JSR LBOPBO            ;convert LBO to PBO
;
;   Exit registers: .A: entry value
;                   .B: entry value
;                   .X: PBO LSW (1,2)
;                   .Y: PBO MSW (1,2)
;                   DB: entry value
;                   DP: entry value
;                   PB: entry value
;                   SR: NVmxDIZC
;                       ||||||||
;                       |||||||+———> 0: okay
;                       |||||||      1: PBO wrapped — error
;                       +++++++————> entry value
;
;   Notes: 1) The returned PBO is zero-based.
;
;          2) Content is undefined if an error occurs.
;   —————————————————————————————————————————————————————————

Depending on the complexity of what the function does, the comment header could be quite wordy, viz:

Code:
;===============================================================================
;
;mktime: CONVERT BROKEN-DOWN TIME TO CALENDAR TIME
;
;   ————————————————————————————————————————————————————————————————————————
;   Calling syntax: per altzone   ;pointer to daylight saving time zone data
;                   per timezone  ;pointer to standard time zone data
;                   per time      ;pointer to calendar time field (2)
;                   per tm        ;pointer to broken-down time structure (1)
;                   jsr mktime
;
;   Exit registers: .A: entry value
;                   .B: entry value
;                   .X: entry value
;                   .Y: entry value
;                   DB: entry value
;                   DP: entry value
;                   PB: entry value
;                   SR: NVmxDIZC
;                       ||||||||
;                       |||||||+———> 0: okay
;                       |||||||      1: conversion error
;                       +++++++————> entry value
;
;   Notes: 1) tm must point to a broken-down date & time structure of type
;             tm, in which fields are as follows:
;
;                 Offset  Field     Description
;                 ——————————————————————————————
;                   $00   tm_sec    seconds
;                   $02   tm_min    minutes
;                   $04   tm_hour   hour
;                   $06   tm_mday   day-of-month
;                   $08   tm_mon    month
;                   $0A   tm_year   year
;                   $0C   tm_wday   day-of-week¹
;                   $0E   tm_yday   day-of-year¹
;                   $10   tm_isdst  DST flag
;                 ——————————————————————————————
;                 ¹Input values are ignored & will be replaced
;                  by data computed from the input date.
;
;             All fields are of size s_int.  Refer to the tm structure def-
;             inition in include/calendrics/tm.asm.
;
;          2) The value returned in time is the number of seconds that have
;             elapsed since the "epoch" (discussed below).  time must be of
;             size s_time_t, which is defined in include/calendrics/tm.asm.
;
;          3) time is assumed to be UTC, not local time.  See below informa-
;             tion for more details.
;
;          4) This function does not verify that the data in tm are valid.
;             An error exit will occur if an intermediate computation causes
;             an over- or underflow, or attempts division by zero.  Nonsens-
;             ical dates, such as Feb 30, or times, such as 61 minutes, may
;             produce unexpected results.
;   —-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-
;   mktime converts the broken-down time in the structure tm into the number
;   of seconds that have elapsed since the "epoch," which is defined as Sun-
;   day, October 1, 00:00:00 UTC, 1752.  The conversion is accurate for all
;   dates from the epoch to December 31, 23:59:59 UTC, 9999.
;
;   This conversion is different than that used in most UNIX-like operating
;   systems, in which the epoch is Thursday, January 1, 1970 & time_t is a
;   signed integer.  UNIX generates a negative result for dates prior to the
;   epoch, with a maximum regression to December 13, 1901 in the case of 32
;   bit time_t definitions.  This implementation of mktime generates an un-
;   signed integer of size s_time_t for any date & time within the accept-
;   able range.
;
;   maktime makes reference to several external variables for time zone &
;   daylight saving time (DST) conversion data:
;
;   § timezone
;
;     This variable of s_int size defines the local time zone as a signed
;     offset to UTC when standard time is in effect.  mktime interprets it
;     as follows:
;
;       x00000xxxxxxxxxx
;       |     ||||||||||
;       |     ++++++++++———> minutes offset from UTC (0-1023)
;       +——————————————————> 0: locale is west of UTC
;                            1: locale is east of UTC
;
;     For example, if timezone is $81E0 the locale is 8 hours east of UTC &
;     28,800 seconds will be subtracted from the computed time value before
;     it is returned.  If timezone is $0168 then the locale is 6 hours west
;     of UTC & 21,600 seconds will be added to the computed time value be-
;     it is returned.  This scheme accommodates time zones that are not ex-
;     act hour multiples east or west of UTC.
;
;   § altzone
;
;     This variable of s_int size defines the local time zone as a signed
;     offset to UTC when daylight saving time is in effect.  mktime inter-
;     prets it as follows:
;
;       x00000xxxxxxxxxx
;       |     ||||||||||
;       |     ++++++++++———> minutes east/west of UTC (0-1023)
;       +——————————————————> 0: locale is west of UTC
;                            1: locale is east of UTC
;
;     If altzone is $0000 then it is ignored by & time zone compensation is
;     based upon timezone.  If timezone & altzone are both $0000 then it is
;     assumed that the locale is in the UTC time zone.
;
;   Daylight saving time will only apply when tm_isdst in the tm structure
;   is $0001.  Otherwise, standard time will be assumed, regardless of the
;   value of altzone.
;
;   Upon a successful conversion, mktime will rewrite all fields in the tm
;   structure, as an internal call will be made to localtim to reverse the
;   conversion to compute the day-of-week (tm_wday) & day-of-year (tm_yday)
;   fields.  A side-effect of this reverse conversion is other fields in tm
;   may also change, usually because a value prior to conversion was nonsen-
;   sical, e.g., a date such as Feb 30.
;   ————————————————————————————————————————————————————————————————————————

The above describes the mktime function I wrote that converts a human-readable form of the local date and time of day into a machine-friendly format. A stack frame has to be set up for the call, and the data structures referred to by the stack frame are populated with new values upon exit. Hence the assembly language equivalent of bloviating. :D

To those just starting out with assembly language, the above sort of thing may seem to be unnecessarily elaborate and a big time-waster. After all, we all have good memories and never forget anything, right? However, a year or two later when you revisit the function, such as to add features, you'll be glad you committed your thoughts at the time to "paper."

The sames applies regardless of the language being used. In years past, I did a lot of development in Thoroughbred Dictionary-IV, which is a complex timesharing form of BASIC. Like almost all BASIC implementations, Thoroughbred has the REM (remark) statement for commenting programs. I tended to use it quite liberally, and when the occasion arose in which I would have to maintain a program I had written long ago I didn't have to rely on memory to figure out why I wrote things the way I did.

_________________
x86?  We ain't got no x86.  We don't NEED no stinking x86!


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 56 posts ]  Go to page Previous  1, 2, 3, 4  Next

All times are UTC


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: