Neolithic Romless
Re: Neolithic Romless
Yes. I was thinking of what might be needed to drop in something like the cypress 32kB FRAM - FM18W08 or FM28V20 - to give enable a single programming event and then just subsequently run at power up.
I don't think it's much: would need to consider the supply voltage - this is 5v, and some of the FRAM run at 5v - and a different way to wake up the serial chips. Might just be a second button to load...
Programming that MR5A16A could be done with something with a few more I/O legs than an Arduino - a Nucleo of some flavour perhaps (as drives my eeprom programmer at the moment) - but it seems a shame to use only half of it. Not sure how you'd be able to use the top eight bits of the memory word.
Neil
I don't think it's much: would need to consider the supply voltage - this is 5v, and some of the FRAM run at 5v - and a different way to wake up the serial chips. Might just be a second button to load...
Programming that MR5A16A could be done with something with a few more I/O legs than an Arduino - a Nucleo of some flavour perhaps (as drives my eeprom programmer at the moment) - but it seems a shame to use only half of it. Not sure how you'd be able to use the top eight bits of the memory word.
Neil
Re: Neolithic Romless
Got the two ram chips on the board. The dual DIP/SOIC footprint is really handy and I happened to have some soic parts around. This courtesy of a few minutes in a second hand toaster oven and a syringe of solder paste; no template for this one. Just had one short (too much solder) and one open circuit (not enough), both easily fixed with the soldering iron.
Neil
Neil
Re: Neolithic Romless
Now with added sockets. No, I didn't have any 20-pin sockets... never mind. The other SM parts added with a hot air pencil (should have done them in the oven with the ram but I didn't think).
The reset resets and the oscillator oscles. So now it's waiting on me to finish the code to convert an intel hex file into a binary blob.
Neil
The reset resets and the oscillator oscles. So now it's waiting on me to finish the code to convert an intel hex file into a binary blob.
Neil
Re: Neolithic Romless
Some very fragile code that - on visual inspection - produces a binary blob which ought to program the neolithic. It's seriously dodgy code, take with two aspirins and a dose of salt. But it does appear to work with a properly formed intel 8-bit hex file.
Note: it's for Linux. I don't think Windows includes getline() but there are probably versions online if it doesn't. I'll probably just copy the blob to the \dev\ttyUSB0 port directly, but there's a mechanism to send via minicom here: https://www.dannysung.com/articles/linu ... a-minicom/
Don't forget that the comm port speed will need to be 19k2 for the boot load and something rather higher - 115k2 likely - for actual comms.
Neil
Note: it's for Linux. I don't think Windows includes getline() but there are probably versions online if it doesn't. I'll probably just copy the blob to the \dev\ttyUSB0 port directly, but there's a mechanism to send via minicom here: https://www.dannysung.com/articles/linu ... a-minicom/
Don't forget that the comm port speed will need to be 19k2 for the boot load and something rather higher - 115k2 likely - for actual comms.
Neil
Code: Select all
// convert an existing intel 8-bit hex file to a binary blob which can
// be used to load the Neolithic Romless 6502 processor
// three addressable uarts handle the address and data and write strobe,
// a fourth resets the processor after memory is loaded
// - 0x0 data and strobe
// - 0x1 address low byte
// - 0x2 address high byte (page)
// - 0x3 reset
//
// (c) nailed_barnacle 2023
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
void decode_data (uint8_t data)
{
printf ("%02x %01x\t%01x\t%01x\n", data, data >> 4, (data & 0x0e) >> 1, data & 0x01);
}
uint8_t build_txbyte (int8_t val, int8_t target, bool first)
{
// convert a single byte into the first packet value
// bit 0 - always 1
// bit 1-3 - target address
// bit 4-7 - low nibble of val if first is true
// - high nibble of val if first is false
uint8_t res = 1; // bit 0 = 1
res += (target & 7) << 1;
if (first)
{
res += (val & 0x0f) << 4;
}
else
{
res += (val & 0xf0);
}
return res;
}
void output_txpair (int8_t val, int8_t target, FILE * fo)
{
uint8_t first;
uint8_t second;
// output two bytes to fo
first = build_txbyte (val, target, true);
second = build_txbyte (val, target, false);
fprintf (fo, "%c%c", first, second);
decode_data (first);
decode_data (second);
}
void output_page (uint8_t page, FILE * fo)
{
// output a page address to uart 2
// if we only send this when it changes, we increase tranfer speed
// by about fifty percent
output_txpair (page, 2, fo);
}
void output_add_data (uint8_t addr, uint8_t data, FILE * fo)
{
// write a byte at the selected address on the current page
output_txpair (addr, 1, fo);
output_txpair (data, 0, fo); // this writes to the ram
}
int main (int argc, char ** argv)
{
// read an intel hex file and write the data into a binary file
// such that it can be used directly to load the neolithic romless
// processor
FILE * fi;
FILE * fo;
char * line = NULL;
size_t len = 0;
ssize_t nread;
int record_type;
int record_count;
int record_addr;
int record_data;
// sanity check input
if (argc < 3)
{
printf ("Usage: lv8153 <input hex file> <output binary file>\r\n");
return 1;
}
// open input and output files
if (NULL == (fi = fopen (argv[1], "r")))
{
printf ("Can't open input file %s\n", argv[1]);
return 1;
}
if (NULL == (fo = fopen (argv[2], "w")))
{
printf ("Can't open output file %s\n", argv[2]);
fclose (fi);
return 1;
}
// now we can plough through the file one line at a time
// this will only work for a properly formed hex file, not robust!
// - two hex digits for payload count
// - four hex digits for load address (high byte first)
// - two hex digits as record type: 00 for data, 01 for end of file
// - data as two hex digits, repeated count times
// - two hex digits as checksum (we ignore this)
while (-1 != (nread = getline (&line, &len, fi)))
{
sscanf (line, ":%02x%04x%02x", &record_count, &record_addr, &record_type);
if (0 == record_type)
{
// only for types we understand
// send high byte of target
output_page ((record_addr & 0xff00) >> 8, fo);
for (int q = 0; q < record_count; q++)
{
// for each data byte
sscanf (&line[9 + (q * 2)], "%02x", &record_data);
output_add_data (record_addr & 0xff, record_data, fo);
record_addr++;
if (0x00 == record_addr & 0xff)
{
// if the page rolls over in the middle of the line
output_page ((record_addr & 0xff00) >> 8, fo);
}
}
printf ("\n");
}
}
// finally reset the processor
output_txpair (0, 3, fo);
fclose (fi);
fclose (fo);
printf ("Load complete\n");
}
Re: Neolithic Romless
Ok, the board is built up, it looks like code is loading, and the reset and BE go high at the end of the load.
The bad news is that my initial code doesn't look like it's running. It's possible, though, that it's stuck in a loop waiting for something from the UART. It should be running Basic, so the first thing out should be the Cold/Warm start message; even by tickling the reset pin manually I don't see it.
It's also possible that my minicom setup isn't happy: On this linux box I'm setting the parameters for the load and sending it:
But then minicom needs to set the line back to 112,500 baud to talk to the processor instead of the loader hardware. Which takes an amount of time and perhaps Basic is getting bored waiting.
Next step is a tiny code that just emits constant values to the port after configuring it.
Neil
p.s. of course it's entirely possible that my conversion software isn't converting right...
The bad news is that my initial code doesn't look like it's running. It's possible, though, that it's stuck in a loop waiting for something from the UART. It should be running Basic, so the first thing out should be the Cold/Warm start message; even by tickling the reset pin manually I don't see it.
It's also possible that my minicom setup isn't happy: On this linux box I'm setting the parameters for the load and sending it:
Code: Select all
stty -F /dev/ttyUSB0 19200 -parity cs8 -cstopb
cat basic.bin > /dev/ttyUSB0
Next step is a tiny code that just emits constant values to the port after configuring it.
Neil
p.s. of course it's entirely possible that my conversion software isn't converting right...
Re: Neolithic Romless
I've had pretty good mileage using Python for serial comms - its Serial module makes it easy to switch to arbitrary baud rates on the fly, and I used that for a fileserver for the BBC Micro (6850-based) where the initial connection was 9600 baud but it stepped up to 76800 baud after an initial negotiation, and that worked well. The Python server also assembled the 6502 code automatically.
More recently I've been using similar code at a fixed baud rate (that minicom doesn't support) and having it handle the initial bootup negotiation with the 6502 system, load some code, and switch to an interactive serial terminal mode after that to allow human I/O. It's been good for that too.
You could do the same in C of course, the main thing I think is that it can be beneficial to have some custom server code here especially if you need to do things like rate changes.
More recently I've been using similar code at a fixed baud rate (that minicom doesn't support) and having it handle the initial bootup negotiation with the 6502 system, load some code, and switch to an interactive serial terminal mode after that to allow human I/O. It's been good for that too.
You could do the same in C of course, the main thing I think is that it can be beneficial to have some custom server code here especially if you need to do things like rate changes.
Re: Neolithic Romless
Actually, I think I might simplify things if for the time being I initialise the UART for 19k2 as well. There should be no issue with the loader chain receiving data *unless* the write pulse might still be active even with the output disabled - something I haven't thought about. Hmm.
Neil
Neil
Re: Neolithic Romless
Hmm. A simple program to emit lots and lots of ************* (0x2A) produces output which the scope insists is at the expected 115,200 baud and decodes correctly as asterixen. Sadly, minicom produces a long string of identical characters but they're not asterixes, I tend to get % or I. I don't know if the unit is simply sending things out which can be misinterpreted, and my first attempt to output continuous 'hello world's didn't output anything. Need to look at that.
Sadly the datasheet revealed that the only divisors for the serial clock are 1, 16, and 64. Since the clock is 1,843,200 Hz, that gives me the default 115,200 or 28,800, so I can't stick it at 19k2 or 9k6 and leave it there.
It's possible that the change from the medium speed at the control line, to the fast speed in minicom, isn't necessarily working correctly. It might be that for safety, I need to receive data at the 6502 side before starting the main software, to prove the serial is running.
But the basic load and reset does appear to be working.
Neil
Sadly the datasheet revealed that the only divisors for the serial clock are 1, 16, and 64. Since the clock is 1,843,200 Hz, that gives me the default 115,200 or 28,800, so I can't stick it at 19k2 or 9k6 and leave it there.
It's possible that the change from the medium speed at the control line, to the fast speed in minicom, isn't necessarily working correctly. It might be that for safety, I need to receive data at the 6502 side before starting the main software, to prove the serial is running.
But the basic load and reset does appear to be working.
Neil
Re: Neolithic Romless
barnacle wrote:
Hmm. A simple program to emit lots and lots of ************* (0x2A) produces output which the scope insists is at the expected 115,200 baud and decodes correctly as asterixen. Sadly, minicom produces a long string of identical characters but they're not asterixes, I tend to get % or I. I don't know if the unit is simply sending things out which can be misinterpreted, and my first attempt to output continuous 'hello world's didn't output anything. Need to look at that.
Sadly the datasheet revealed that the only divisors for the serial clock are 1, 16, and 64. Since the clock is 1,843,200 Hz, that gives me the default 115,200 or 28,800, so I can't stick it at 19k2 or 9k6 and leave it there.
It's possible that the change from the medium speed at the control line, to the fast speed in minicom, isn't necessarily working correctly. It might be that for safety, I need to receive data at the 6502 side before starting the main software, to prove the serial is running.
But the basic load and reset does appear to be working.
Neil
Sadly the datasheet revealed that the only divisors for the serial clock are 1, 16, and 64. Since the clock is 1,843,200 Hz, that gives me the default 115,200 or 28,800, so I can't stick it at 19k2 or 9k6 and leave it there.
It's possible that the change from the medium speed at the control line, to the fast speed in minicom, isn't necessarily working correctly. It might be that for safety, I need to receive data at the 6502 side before starting the main software, to prove the serial is running.
But the basic load and reset does appear to be working.
Neil
I'm sure you've checked the usual parity shenanigans though. Stars are good - 0x2A, or 0xAA if sent with even parity. Capital U is another - 0x55 so the parity bit ought to be zero there.
Also, serial port permissions - if not root, then you ought to be in the 'dialout' group so you can fully access the serial ports. Minicom gets a bit fussy with storing modes, etc. but I've not had issues just using it directly from the command-line:
Code: Select all
minicom -D /dev/ttyUSB0 -b 115200I'm sure you'll get there in the end though..
Cheers,
-Gordon
--
Gordon Henderson.
See my Ruby 6502 and 65816 SBC projects here: https://projects.drogon.net/ruby/
Gordon Henderson.
See my Ruby 6502 and 65816 SBC projects here: https://projects.drogon.net/ruby/
Re: Neolithic Romless
A thought - send some number of characters (maybe 8) then a space, and repeat. Do you get characters in groups of 8, or something else? If you're getting the right number of characters, I can only imagine something is wrong with, say, stop bits, or parity. Set both sides to 8-N-1 if you can.
Re: Neolithic Romless
I've had this kind of thing too when sending a long string of identical characters, if the receiver tries to start listening in while the data is already being sent - it is possible for the receiver to be out of sync with the start and stop bits, so it sees valid but incorrect data. As Ed said, pausing between characters, at least occasionally, might fix that, and you could chose a character value that's unambiguous, e.g. 255 (just one clear bit, the start bit) or 0 (just one set bit, the stop bit) - with 8N1 at least.
Re: Neolithic Romless
Yeah, that's my next thought but something for tomorrow. The USB adaptor is an FDTI USB-serial SIL connector, so that shouldn't be an issue. It feels like it's missing out on the start bit somehow. But asterixen are usually safe. 0x55 in 8-n-1 can pick up anywhere, so it doesn't tell me a lot...
When I get the 'hello world', over the weekend perhaps, I'll know more.
One concern I have still is that some mischance of incoming data might trigger the address 8513 - the data sheet doesn't mention whether the SOUT pin is still active with the output pins disabled, but if it is, there's a chance for some really subtle bugs: it might need a more sophisticated mixing of the RnW from the processor to actively block the SOUT 'write' pulse.
Neil
p.s. I'm in dialout and tty groups.
When I get the 'hello world', over the weekend perhaps, I'll know more.
One concern I have still is that some mischance of incoming data might trigger the address 8513 - the data sheet doesn't mention whether the SOUT pin is still active with the output pins disabled, but if it is, there's a chance for some really subtle bugs: it might need a more sophisticated mixing of the RnW from the processor to actively block the SOUT 'write' pulse.
Neil
p.s. I'm in dialout and tty groups.
Re: Neolithic Romless
To illustrate, these are all valid interpretations of an 8N1 stream of asterisks, depending which bit you consider to be the start bit:
One way it could get out of sync would be if the transmitter started using the higher baud rate before the receiver did. Once it is in sync there shouldn't be a problem.
Code: Select all
00101010010010101001...
0010101001 = 42 (*)
0101001001 = 37 (%)
0100100101 = 73 (I)
0010010101 = 82 (R)
Re: Neolithic Romless
Yep, the second and the third are the ones I've seen. And yes, it does start transmitting at the higher rate before the receiver changes over, which might be some seconds later.
This is why I think any use of this will require some recognised _received_ character (or character string: +++ perhaps) before it starts transmitting; thereafter everything should be in sync. Everything's running at 8n1.
Neil
This is why I think any use of this will require some recognised _received_ character (or character string: +++ perhaps) before it starts transmitting; thereafter everything should be in sync. Everything's running at 8n1.
Neil
Re: Neolithic Romless
Yes that should be good. Otherwise as I said, bytes 0 and 255 don't have any risk of misinterpretation. You could also send a break, or just leave healthy gaps between bytes during initial connection phase.