mirror of
https://github.com/hsoft/collapseos.git
synced 2024-11-23 19:28:06 +11:00
rc2014: complete the EEPROM recipe
This commit is contained in:
parent
d0545d555f
commit
b536d3bfd6
10
drv/at28.fs
10
drv/at28.fs
@ -2,12 +2,12 @@
|
|||||||
operation while doing the right thing. Checks data integrity
|
operation while doing the right thing. Checks data integrity
|
||||||
and ABORT on mismatch.
|
and ABORT on mismatch.
|
||||||
)
|
)
|
||||||
( a n -- )
|
( n a -- )
|
||||||
: AT28!
|
: AT28!
|
||||||
2DUP C! SWAP
|
2DUP C!
|
||||||
( as long as writing operation is running, IO/6 will toggle at each
|
( as long as writing operation is running, IO/6 will toggle at each
|
||||||
read attempt. We know that write is finished when we read the same
|
read attempt. We know that write is finished when we read the same
|
||||||
value twice. )
|
value twice. )
|
||||||
BEGIN ( n1 a )
|
BEGIN ( n1 a )
|
||||||
DUP C@ ( n1 a n2 )
|
DUP C@ ( n1 a n2 )
|
||||||
OVER C@ ( n1 a n2 n3 )
|
OVER C@ ( n1 a n2 n3 )
|
||||||
|
@ -7,7 +7,8 @@ itself.
|
|||||||
|
|
||||||
## Gathering parts
|
## Gathering parts
|
||||||
|
|
||||||
* A RC2014 Classic that could install the base recipe
|
* A RC2014 Classic
|
||||||
|
* `stage3.bin` from the base recipe
|
||||||
* An extra AT28C64B
|
* An extra AT28C64B
|
||||||
* 1x 40106 inverter gates
|
* 1x 40106 inverter gates
|
||||||
* Proto board, RC2014 header pins, wires, IC sockets, etc.
|
* Proto board, RC2014 header pins, wires, IC sockets, etc.
|
||||||
@ -32,52 +33,33 @@ in write protection mode, but I preferred building my own module.
|
|||||||
|
|
||||||
I don't think you need a schematic. It's really simple.
|
I don't think you need a schematic. It's really simple.
|
||||||
|
|
||||||
## Building the kernel
|
## Using the at28 driver
|
||||||
|
|
||||||
For this recipe to work, we need a block device for the `at28w` program to read
|
The AT28 driver is at `drv/at28.fs` and is a pure forth source file so it's
|
||||||
from. The easiest way to go around would be to use a SD card, but maybe you
|
rather easy to set up from the base Stage 3 binary:
|
||||||
haven't built a SPI relay yet and it's quite a challenge to do so.
|
|
||||||
|
|
||||||
Therefore, for this recipe, we'll have `at28w` read from a memory map and we'll
|
cat ../stage3.bin ../pre.fs ../../../drv/at28.fs ../run.fs > os.bin
|
||||||
upload contents to write to memory through our serial link.
|
../../../emul/hw/rc2014/classic os.bin
|
||||||
|
|
||||||
`at28w` is designed to be ran as a "user application", but in this case, because
|
|
||||||
we run from a kernel without a filesystem and that `pgm` can't run without it,
|
|
||||||
we'll integrate `at28w` directly in our kernel and expose it as an extra shell
|
|
||||||
command (renaming it to `a28w` to fit the 4 chars limit).
|
|
||||||
|
|
||||||
For all this to work, you'll need [glue code that looks like this](glue.asm).
|
|
||||||
Running `make` in this directory will produce a `os.bin` with that glue code
|
|
||||||
that you can install in the same way you did with the basic RC2014 recipe.
|
|
||||||
|
|
||||||
If your range is different than `0x2000-0x3fff`, you'll have to modify
|
|
||||||
`AT28W_MEMSTART` before you build.
|
|
||||||
|
|
||||||
## Writing contents to the AT28
|
## Writing contents to the AT28
|
||||||
|
|
||||||
The memory map is configured to start at `0xd000`. The first step is to upload
|
The driver provides `AT28!` which can be plugged in adev's `A!*`.
|
||||||
contents at that address as documented in ["Load code in RAM and run it"][load].
|
|
||||||
|
|
||||||
You have to know the size of the contents you've loaded because you'll pass it
|
It's not in the Stage 3 binary, but because it's a small piece of Forth code,
|
||||||
as at argument to `a28w`. You can run:
|
let's just run its definition code:
|
||||||
|
|
||||||
Collapse OS
|
cat ../../../drv/at28.fs | ./stripfc | ./exec <tty device>
|
||||||
> bsel 0
|
|
||||||
> seek 00 0000
|
|
||||||
> a28w <size-of-contents>
|
|
||||||
|
|
||||||
It takes a little while to write. About 1 second per 0x100 bytes (soon, I'll
|
Then, upload your binary to some place in memory, for example `a000`. To do so,
|
||||||
implement page writing which should make it much faster).
|
run this from your modern computer:
|
||||||
|
|
||||||
If the program doesn't report an error, you're all good! The program takes care
|
./upload <tty device> a000 <filename>
|
||||||
of verifying each byte, so everything should be in place. You can verify
|
|
||||||
yourself by `peek`-ing around the `0x2000-0x3fff` range.
|
|
||||||
|
|
||||||
Note that to write a single byte to the AT28 eeprom, you don't need a special
|
Then, activate `AT28!` with `' AT28! A!* !` and then run
|
||||||
program. You can, while you're in the `0x2000-0x3fff` range, run `poke 1` and
|
`0xa000 0x2000 <size-of-bin> AMOVE`. `AT28!` checks every myte for integrity,
|
||||||
send an arbitrary char. It will work. The problem is with writing multiple
|
so it there's no error, you should be fine. Your content is now on the EEPROM!
|
||||||
bytes: you have to wait until the eeprom is finished writing before writing to
|
|
||||||
a new address, something a regular `poke` doesn't do but `at28w` does.
|
|
||||||
|
|
||||||
[load]: ../../../doc/load-run-code.md
|
|
||||||
|
|
||||||
|
Why not upload content directly to `0x2000` after having activated `AT28!`?
|
||||||
|
Technically, you could. It was my first idea too. However, at the time of this
|
||||||
|
writing, I always get weird mismatch errors about halfway through. Maybe that
|
||||||
|
the ACIA interrupt does something wrong...
|
||||||
|
@ -8,7 +8,9 @@
|
|||||||
void mread(int fd, char *s, int count)
|
void mread(int fd, char *s, int count)
|
||||||
{
|
{
|
||||||
while (count) {
|
while (count) {
|
||||||
while (read(fd, s, 1) == 0);
|
while (read(fd, s, 1) == 0) {
|
||||||
|
usleep(1000);
|
||||||
|
}
|
||||||
s++;
|
s++;
|
||||||
count--;
|
count--;
|
||||||
}
|
}
|
||||||
|
@ -65,6 +65,7 @@ int main(int argc, char **argv)
|
|||||||
// we don't exit now because we need to "consume" our whole program.
|
// we don't exit now because we need to "consume" our whole program.
|
||||||
returncode = 1;
|
returncode = 1;
|
||||||
}
|
}
|
||||||
|
usleep(1000); // let it breathe
|
||||||
}
|
}
|
||||||
mread(fd, s, 2); // "> " prompt
|
mread(fd, s, 2); // "> " prompt
|
||||||
sendcmdp(fd, "FORGET _");
|
sendcmdp(fd, "FORGET _");
|
||||||
|
Loading…
Reference in New Issue
Block a user